@leonxin/meetgames 0.1.8 → 0.1.12
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/.agents/skills/meet-sdk-regression/SKILL.md +93 -0
- package/.cursor/mcp.example.json +16 -0
- package/.cursor/mcp.json +11 -0
- package/.cursor/skills/meetgames-mcp/SKILL.md +48 -0
- package/.vite/vitest/results.json +1 -0
- package/README.md +36 -13
- package/{meetsdk-android.json → config/meetsdk-android.json} +2 -1
- package/config/meetsdk-ios.json +15 -0
- package/dist/android/adapter.d.ts.map +1 -1
- package/dist/android/adapter.js +2 -2
- package/dist/android/adapter.js.map +1 -1
- package/dist/android/detect.d.ts +2 -2
- package/dist/android/detect.d.ts.map +1 -1
- package/dist/android/detect.js +36 -8
- package/dist/android/detect.js.map +1 -1
- package/dist/cache.d.ts +44 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +101 -0
- package/dist/cache.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +181 -49
- package/dist/cli.js.map +1 -1
- package/dist/config/meetSdkDefaultConfig.d.ts +19 -2
- package/dist/config/meetSdkDefaultConfig.d.ts.map +1 -1
- package/dist/config/meetSdkDefaultConfig.js +69 -6
- package/dist/config/meetSdkDefaultConfig.js.map +1 -1
- package/dist/config/meetSdkIosConfig.d.ts +21 -0
- package/dist/config/meetSdkIosConfig.d.ts.map +1 -0
- package/dist/config/meetSdkIosConfig.js +68 -0
- package/dist/config/meetSdkIosConfig.js.map +1 -0
- package/dist/config/meetSdkRemoteConfig.d.ts +19 -1
- package/dist/config/meetSdkRemoteConfig.d.ts.map +1 -1
- package/dist/config/meetSdkRemoteConfig.js +64 -25
- package/dist/config/meetSdkRemoteConfig.js.map +1 -1
- package/dist/contracts/types.d.ts +27 -6
- package/dist/contracts/types.d.ts.map +1 -1
- package/dist/core/doctor.d.ts +17 -0
- package/dist/core/doctor.d.ts.map +1 -0
- package/dist/core/doctor.js +444 -0
- package/dist/core/doctor.js.map +1 -0
- package/dist/core/pipeline.d.ts.map +1 -1
- package/dist/core/pipeline.js +0 -15
- package/dist/core/pipeline.js.map +1 -1
- package/dist/core/platform.d.ts +12 -0
- package/dist/core/platform.d.ts.map +1 -0
- package/dist/core/platform.js +40 -0
- package/dist/core/platform.js.map +1 -0
- package/dist/core/previewPatches.d.ts +1 -1
- package/dist/core/previewPatches.js +2 -2
- package/dist/core/previewPatches.js.map +1 -1
- package/dist/core/reporter.js +1 -1
- package/dist/core/reporter.js.map +1 -1
- package/dist/core/workspace.d.ts +2 -2
- package/dist/core/workspace.d.ts.map +1 -1
- package/dist/core/workspace.js +6 -5
- package/dist/core/workspace.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/ios/channelConfig.d.ts +1 -0
- package/dist/ios/channelConfig.d.ts.map +1 -1
- package/dist/ios/channelConfig.js +82 -0
- package/dist/ios/channelConfig.js.map +1 -1
- package/dist/ios/codeUtils.d.ts +1 -0
- package/dist/ios/codeUtils.d.ts.map +1 -1
- package/dist/ios/codeUtils.js +11 -2
- package/dist/ios/codeUtils.js.map +1 -1
- package/dist/ios/detect.d.ts +2 -2
- package/dist/ios/detect.d.ts.map +1 -1
- package/dist/ios/detect.js +49 -10
- package/dist/ios/detect.js.map +1 -1
- package/dist/ios/entitlements.d.ts +4 -0
- package/dist/ios/entitlements.d.ts.map +1 -0
- package/dist/ios/entitlements.js +53 -0
- package/dist/ios/entitlements.js.map +1 -0
- package/dist/ios/fileManager.d.ts.map +1 -1
- package/dist/ios/fileManager.js +3 -2
- package/dist/ios/fileManager.js.map +1 -1
- package/dist/ios/infoPlist.d.ts +1 -1
- package/dist/ios/infoPlist.d.ts.map +1 -1
- package/dist/ios/infoPlist.js.map +1 -1
- package/dist/ios/integrate.d.ts.map +1 -1
- package/dist/ios/integrate.js +214 -39
- package/dist/ios/integrate.js.map +1 -1
- package/dist/ios/pbxprojEditor.d.ts +2 -0
- package/dist/ios/pbxprojEditor.d.ts.map +1 -1
- package/dist/ios/pbxprojEditor.js +250 -6
- package/dist/ios/pbxprojEditor.js.map +1 -1
- package/dist/ios/pluginConfig.d.ts +1 -0
- package/dist/ios/pluginConfig.d.ts.map +1 -1
- package/dist/ios/pluginConfig.js +36 -4
- package/dist/ios/pluginConfig.js.map +1 -1
- package/dist/ios/sdkBundle.d.ts +1 -6
- package/dist/ios/sdkBundle.d.ts.map +1 -1
- package/dist/ios/sdkBundle.js +47 -17
- package/dist/ios/sdkBundle.js.map +1 -1
- package/dist/ios/template.d.ts +1 -0
- package/dist/ios/template.d.ts.map +1 -1
- package/dist/ios/template.js +14 -1
- package/dist/ios/template.js.map +1 -1
- package/dist/ios/types.d.ts +2 -2
- package/dist/ios/types.d.ts.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +22 -15
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/service.d.ts +11 -6
- package/dist/mcp/service.d.ts.map +1 -1
- package/dist/mcp/service.js +61 -18
- package/dist/mcp/service.js.map +1 -1
- package/dist/ops/handlers.d.ts.map +1 -1
- package/dist/ops/handlers.js +34 -23
- package/dist/ops/handlers.js.map +1 -1
- package/dist/remote/sdkHomeDownload.d.ts +65 -0
- package/dist/remote/sdkHomeDownload.d.ts.map +1 -0
- package/dist/remote/sdkHomeDownload.js +229 -0
- package/dist/remote/sdkHomeDownload.js.map +1 -0
- package/dist/remote/topsdkDownloadSdkConfig.d.ts.map +1 -1
- package/dist/remote/topsdkDownloadSdkConfig.js +11 -1
- package/dist/remote/topsdkDownloadSdkConfig.js.map +1 -1
- package/dist/shared/errors.d.ts +7 -0
- package/dist/shared/errors.d.ts.map +1 -0
- package/dist/shared/errors.js +16 -0
- package/dist/shared/errors.js.map +1 -0
- package/docs/API.md +246 -32
- package/docs/CLI.md +291 -0
- package/docs/INTEGRATION.md +116 -0
- package/docs/MCP.md +86 -0
- package/docs/README.md +18 -10
- package/docs/{api → archive/api}/downloadSDKConfig.md +9 -7
- package/docs/{api → archive/api}/getChannelConfig-meetgames.md +2 -2
- package/docs/archive/ios-migration.md +2139 -0
- package/docs/{ → archive/product/}/346/212/200/346/234/257/346/226/271/346/241/210/350/260/203/347/240/224.md +7 -7
- package/docs/{ → archive/product/}/351/234/200/346/261/202/346/226/207/346/241/243.md +16 -15
- package/package.json +7 -36
- package/recipes/android-default.yaml +0 -5
- package/recipes/integrate-default.yaml +0 -5
- package/src/android/adapter.ts +9 -0
- package/src/android/assembleIntegrationJson.ts +33 -0
- package/src/android/detect.ts +132 -0
- package/src/android/downloadGoogleServicesJson.ts +56 -0
- package/src/android/gradle.ts +116 -0
- package/src/android/manifest.ts +50 -0
- package/src/android/meetSdkRemoteGradle.ts +837 -0
- package/src/cache.ts +164 -0
- package/src/cli.ts +496 -0
- package/src/config/fetchConfigWrite.ts +30 -0
- package/src/config/loadAndroidIntegration.ts +41 -0
- package/src/config/loadManifest.ts +40 -0
- package/src/config/meetSdkDefaultConfig.ts +100 -0
- package/src/config/meetSdkIosConfig.ts +89 -0
- package/src/config/meetSdkRemoteConfig.ts +1215 -0
- package/src/config/topsdkFeatureModules.ts +92 -0
- package/src/contracts/types.ts +129 -0
- package/src/core/doctor.ts +485 -0
- package/src/core/patch.ts +64 -0
- package/src/core/pipeline.ts +107 -0
- package/src/core/platform.ts +47 -0
- package/src/core/previewPatches.ts +23 -0
- package/src/core/reporter.ts +24 -0
- package/src/core/workspace.ts +31 -0
- package/src/entry.ts +7 -0
- package/src/index.ts +140 -0
- package/src/ios/channelConfig.ts +128 -0
- package/src/ios/codeUtils.ts +160 -0
- package/src/ios/detect.ts +105 -0
- package/src/ios/entitlements.ts +61 -0
- package/src/ios/fileManager.ts +48 -0
- package/src/ios/infoPlist.ts +55 -0
- package/src/ios/integrate.ts +517 -0
- package/src/ios/pbxprojEditor.ts +450 -0
- package/src/ios/pluginConfig.ts +97 -0
- package/src/ios/reserved.ts +8 -0
- package/src/ios/sdkBundle.ts +59 -0
- package/src/ios/template.ts +36 -0
- package/src/ios/types.ts +65 -0
- package/src/mcp/server.ts +176 -0
- package/src/mcp/service.ts +253 -0
- package/src/mcp-entry.ts +7 -0
- package/src/ops/fileStore.ts +56 -0
- package/src/ops/handlers.ts +308 -0
- package/src/remote/fetchJson.ts +22 -0
- package/src/remote/sdkHomeDownload.ts +295 -0
- package/src/remote/topsdkDownloadSdkConfig.ts +93 -0
- package/src/remote/topsdkGetSdkConfig.ts +122 -0
- package/src/remote/topsdkSign.ts +10 -0
- package/src/shared/errors.ts +16 -0
- package/tests/assemble.test.ts +12 -0
- package/tests/doctor.test.ts +91 -0
- package/tests/downloadGoogleServicesJson.test.ts +47 -0
- package/tests/fetch-remote.test.ts +23 -0
- package/tests/fetchConfigOverrides.test.ts +28 -0
- package/tests/fetchConfigWrite.test.ts +54 -0
- package/tests/fixtures-hosts.test.ts +78 -0
- package/tests/gradle.test.ts +33 -0
- package/tests/integration-json.test.ts +29 -0
- package/tests/ios.codeUtils.test.ts +23 -0
- package/tests/ios.sdkBundle.test.ts +21 -0
- package/tests/loadManifest.test.ts +15 -0
- package/tests/manifest-xml.test.ts +30 -0
- package/tests/mcp.e2e.ts +214 -0
- package/tests/mcp.service.test.ts +53 -0
- package/tests/meetSdkRemoteConfig.test.ts +481 -0
- package/tests/meetSdkRemoteGradle.test.ts +414 -0
- package/tests/pipeline.android.test.ts +95 -0
- package/tests/pipeline.integration-json.test.ts +58 -0
- package/tests/pipeline.ios.test.ts +392 -0
- package/tests/pipeline.preview.patch.test.ts +85 -0
- package/tests/platformSelection.test.ts +77 -0
- package/tests/sdkHomeDownload.test.ts +124 -0
- package/tests/sdkVersionConfig.test.ts +131 -0
- package/tests/topsdk.test.ts +53 -0
- package/tests/topsdkDownloadSdkConfig.test.ts +81 -0
- package/tests/topsdkFeatureModules.test.ts +116 -0
- package/tsconfig.json +19 -0
- package/vitest.config.ts +9 -0
- package/vitest.mcp.config.ts +11 -0
- package/bundled/android/sample.txt +0 -1
- package/docs/ANDROID.md +0 -133
- package/docs/CURSOR-MCP-SETUP.md +0 -72
- package/docs/MCP-SKILL.md +0 -63
- package/fixtures/api-samples/getChannelConfig-meetgames.sample.json +0 -123
- package/fixtures/meetsdk-remote-config.download-shape.json +0 -20
- package/fixtures/meetsdk-remote-config.mock.json +0 -69
- package/fixtures/recipes/android-default.fixture.yaml +0 -15
- package/fixtures/recipes/android-integration.fixture.json +0 -29
- package/fixtures/topsdk-config-reference.json +0 -39
- /package/docs/{api → archive/api}/getSDKConfig.md +0 -0
package/src/cache.ts
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { MEETSDK_REMOTE_CONFIG_FILENAME } from "./config/meetSdkRemoteConfig.js";
|
|
6
|
+
|
|
7
|
+
export const MEET_SDK_TOOL_CACHE_ROOT = path.join(os.homedir(), ".cache", "meet-sdk-tool");
|
|
8
|
+
|
|
9
|
+
function iosSdkZipFileName(version: string): string {
|
|
10
|
+
return `topSDK-ios--V${version}.zip`;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function safeSegment(value: string): string {
|
|
14
|
+
const cleaned = value.trim().replace(/[^a-zA-Z0-9._-]+/g, "_").replace(/^_+|_+$/g, "");
|
|
15
|
+
return cleaned || "unknown";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function sha256Hex(value: string, length = 16): string {
|
|
19
|
+
return crypto.createHash("sha256").update(value).digest("hex").slice(0, length);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function writeFileAtomic(absPath: string, content: string | Buffer): void {
|
|
23
|
+
ensureCacheRoot();
|
|
24
|
+
fs.mkdirSync(path.dirname(absPath), { recursive: true });
|
|
25
|
+
const tmp = path.join(path.dirname(absPath), `.${path.basename(absPath)}.${process.pid}.${Date.now()}.tmp`);
|
|
26
|
+
fs.writeFileSync(tmp, content);
|
|
27
|
+
fs.renameSync(tmp, absPath);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function ensureCacheRoot(): string {
|
|
31
|
+
fs.mkdirSync(MEET_SDK_TOOL_CACHE_ROOT, { recursive: true, mode: 0o700 });
|
|
32
|
+
try {
|
|
33
|
+
fs.chmodSync(MEET_SDK_TOOL_CACHE_ROOT, 0o700);
|
|
34
|
+
} catch {
|
|
35
|
+
// Best-effort on filesystems that do not support POSIX modes.
|
|
36
|
+
}
|
|
37
|
+
return MEET_SDK_TOOL_CACHE_ROOT;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function resolveRemoteConfigCachePath(params: {
|
|
41
|
+
env: string;
|
|
42
|
+
appId: string;
|
|
43
|
+
channelType: string;
|
|
44
|
+
}): string {
|
|
45
|
+
return path.join(
|
|
46
|
+
MEET_SDK_TOOL_CACHE_ROOT,
|
|
47
|
+
"configs",
|
|
48
|
+
safeSegment(params.env),
|
|
49
|
+
safeSegment(params.appId),
|
|
50
|
+
safeSegment(params.channelType),
|
|
51
|
+
MEETSDK_REMOTE_CONFIG_FILENAME
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function writeRemoteConfigCache(params: {
|
|
56
|
+
env: string;
|
|
57
|
+
appId: string;
|
|
58
|
+
channelType: string;
|
|
59
|
+
requestUrl: string;
|
|
60
|
+
rawText: string;
|
|
61
|
+
warnings?: readonly string[];
|
|
62
|
+
}): { configPath: string; metadataPath: string } {
|
|
63
|
+
const fetchedAt = new Date().toISOString();
|
|
64
|
+
const metadata = `${JSON.stringify(
|
|
65
|
+
{
|
|
66
|
+
fetchedAt,
|
|
67
|
+
env: params.env,
|
|
68
|
+
appId: params.appId,
|
|
69
|
+
channelType: params.channelType,
|
|
70
|
+
requestUrl: params.requestUrl,
|
|
71
|
+
sha256: crypto.createHash("sha256").update(params.rawText).digest("hex"),
|
|
72
|
+
warnings: params.warnings ?? [],
|
|
73
|
+
},
|
|
74
|
+
null,
|
|
75
|
+
2
|
|
76
|
+
)}\n`;
|
|
77
|
+
const configPath = resolveRemoteConfigCachePath(params);
|
|
78
|
+
const metadataPath = path.join(path.dirname(configPath), "metadata.json");
|
|
79
|
+
|
|
80
|
+
writeFileAtomic(configPath, params.rawText);
|
|
81
|
+
writeFileAtomic(metadataPath, metadata);
|
|
82
|
+
|
|
83
|
+
return { configPath, metadataPath };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function pluginsHash(plugins: readonly string[]): string {
|
|
87
|
+
return sha256Hex(plugins.join(","), 12);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function resolveIosSdkCacheLayout(params: {
|
|
91
|
+
version: string;
|
|
92
|
+
packageType: string;
|
|
93
|
+
plugins: readonly string[];
|
|
94
|
+
}): { baseDir: string; zipPath: string; extractDir: string; metadataPath: string; lockDir: string } {
|
|
95
|
+
const baseDir = path.join(
|
|
96
|
+
MEET_SDK_TOOL_CACHE_ROOT,
|
|
97
|
+
"sdk",
|
|
98
|
+
"ios",
|
|
99
|
+
safeSegment(params.packageType),
|
|
100
|
+
safeSegment(params.version),
|
|
101
|
+
pluginsHash(params.plugins)
|
|
102
|
+
);
|
|
103
|
+
return {
|
|
104
|
+
baseDir,
|
|
105
|
+
zipPath: path.join(baseDir, iosSdkZipFileName(params.version)),
|
|
106
|
+
extractDir: path.join(baseDir, "extracted"),
|
|
107
|
+
metadataPath: path.join(baseDir, "metadata.json"),
|
|
108
|
+
lockDir: path.join(baseDir, ".lock"),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function writeIosSdkCacheMetadata(params: {
|
|
113
|
+
metadataPath: string;
|
|
114
|
+
version: string;
|
|
115
|
+
date?: string;
|
|
116
|
+
packageType: string;
|
|
117
|
+
plugins: readonly string[];
|
|
118
|
+
versionUrl: string;
|
|
119
|
+
downloadApiUrl: string;
|
|
120
|
+
sdkZipUrl: string;
|
|
121
|
+
zipPath: string;
|
|
122
|
+
extractDir: string;
|
|
123
|
+
resolvedSdkRoot: string;
|
|
124
|
+
}): void {
|
|
125
|
+
const zipSha256 = fs.existsSync(params.zipPath)
|
|
126
|
+
? crypto.createHash("sha256").update(fs.readFileSync(params.zipPath)).digest("hex")
|
|
127
|
+
: "";
|
|
128
|
+
writeFileAtomic(
|
|
129
|
+
params.metadataPath,
|
|
130
|
+
`${JSON.stringify(
|
|
131
|
+
{
|
|
132
|
+
fetchedAt: new Date().toISOString(),
|
|
133
|
+
version: params.version,
|
|
134
|
+
date: params.date,
|
|
135
|
+
packageType: params.packageType,
|
|
136
|
+
plugins: params.plugins,
|
|
137
|
+
versionUrl: params.versionUrl,
|
|
138
|
+
downloadApiUrl: params.downloadApiUrl,
|
|
139
|
+
sdkZipUrl: params.sdkZipUrl,
|
|
140
|
+
zipPath: params.zipPath,
|
|
141
|
+
extractDir: params.extractDir,
|
|
142
|
+
resolvedSdkRoot: params.resolvedSdkRoot,
|
|
143
|
+
zipSha256,
|
|
144
|
+
},
|
|
145
|
+
null,
|
|
146
|
+
2
|
|
147
|
+
)}\n`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function withCacheLock<T>(lockDir: string, fn: () => Promise<T>): Promise<T> {
|
|
152
|
+
fs.mkdirSync(path.dirname(lockDir), { recursive: true });
|
|
153
|
+
try {
|
|
154
|
+
fs.mkdirSync(lockDir);
|
|
155
|
+
} catch (e) {
|
|
156
|
+
if ((e as NodeJS.ErrnoException).code === "EEXIST") {
|
|
157
|
+
throw new Error(`cache path is locked by another meet-sdk-tool process: ${lockDir}`);
|
|
158
|
+
}
|
|
159
|
+
throw e;
|
|
160
|
+
}
|
|
161
|
+
return fn().finally(() => {
|
|
162
|
+
fs.rmSync(lockDir, { recursive: true, force: true });
|
|
163
|
+
});
|
|
164
|
+
}
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { loadManifestFile } from "./config/loadManifest.js";
|
|
4
|
+
import { buildWorkspaceContext, resolvePackageRoot } from "./core/workspace.js";
|
|
5
|
+
import { runPipeline } from "./core/pipeline.js";
|
|
6
|
+
import {
|
|
7
|
+
detectSinglePlatform,
|
|
8
|
+
manifestForPlatform,
|
|
9
|
+
platformContext,
|
|
10
|
+
} from "./core/platform.js";
|
|
11
|
+
import { runDoctor } from "./core/doctor.js";
|
|
12
|
+
import { clearPreviewPatchFilesIfTargetInside } from "./core/previewPatches.js";
|
|
13
|
+
import { printReport } from "./core/reporter.js";
|
|
14
|
+
import { defaultTopSdkBaseUrl, fetchTopSdkDownloadSdkConfig, type TopSdkApiEnv } from "./remote/topsdkDownloadSdkConfig.js";
|
|
15
|
+
import {
|
|
16
|
+
defaultSdkHomeApiBaseUrl,
|
|
17
|
+
downloadIosSdkToBundled,
|
|
18
|
+
DEFAULT_IOS_SDK_PACKAGE_TYPE,
|
|
19
|
+
} from "./remote/sdkHomeDownload.js";
|
|
20
|
+
import type { Manifest } from "./contracts/types.js";
|
|
21
|
+
import {
|
|
22
|
+
validateDownloadSdkConfigForWrite,
|
|
23
|
+
} from "./config/fetchConfigWrite.js";
|
|
24
|
+
import {
|
|
25
|
+
MEETSDK_REMOTE_CONFIG_FILENAME,
|
|
26
|
+
readMeetSdkRemoteChannel,
|
|
27
|
+
tryParseAsMeetSdkRemoteConfig,
|
|
28
|
+
type MeetSdkRemoteConfig,
|
|
29
|
+
} from "./config/meetSdkRemoteConfig.js";
|
|
30
|
+
import {
|
|
31
|
+
MEET_SDK_TOOL_CACHE_ROOT,
|
|
32
|
+
resolveRemoteConfigCachePath,
|
|
33
|
+
writeRemoteConfigCache,
|
|
34
|
+
} from "./cache.js";
|
|
35
|
+
|
|
36
|
+
const EXIT = {
|
|
37
|
+
OK: 0,
|
|
38
|
+
INVALID_ARGS: 2,
|
|
39
|
+
PROJECT_ERROR: 3,
|
|
40
|
+
CONFIG_ERROR: 4,
|
|
41
|
+
PIPELINE_ERROR: 5,
|
|
42
|
+
NETWORK_ERROR: 6,
|
|
43
|
+
} as const;
|
|
44
|
+
|
|
45
|
+
function fail(message: string, code: number): never {
|
|
46
|
+
console.error(`[meetgames] ERROR: ${message}`);
|
|
47
|
+
process.exit(code);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface Parsed {
|
|
51
|
+
command: string;
|
|
52
|
+
projectRoot: string;
|
|
53
|
+
projectRootProvided: boolean;
|
|
54
|
+
dryRun: boolean;
|
|
55
|
+
verbose: boolean;
|
|
56
|
+
reportFile: string;
|
|
57
|
+
patchFile: string;
|
|
58
|
+
help: boolean;
|
|
59
|
+
topsdkEnv: TopSdkApiEnv;
|
|
60
|
+
topsdkAppId: string;
|
|
61
|
+
topsdkAppSecret: string;
|
|
62
|
+
topsdkChannelType: string;
|
|
63
|
+
topsdkPackageName: string;
|
|
64
|
+
appTarget: string;
|
|
65
|
+
sdkHomeApiBaseUrl: string;
|
|
66
|
+
iosSdkVersion: string;
|
|
67
|
+
iosSdkPlugins: string;
|
|
68
|
+
iosSdkPackageType: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function printHelp(): void {
|
|
72
|
+
console.log(`
|
|
73
|
+
meetgames — Android-first integration CLI (TypeScript)
|
|
74
|
+
|
|
75
|
+
Usage:
|
|
76
|
+
meetgames integrate [--project-root <path>] [--app-id ID] [--channel-type TYPE] [--env prod|pre|test] [--app-target <target>] [--dry-run] [--verbose] [--patch-file <path>]
|
|
77
|
+
meetgames fetch-config [--app-id ID] [--app-secret SECRET] [--channel-type TYPE] [--env prod|pre|test] [--project-root <path>] [--verbose]
|
|
78
|
+
meetgames download-ios-sdk [--version VERSION] [--plugins csv] [--package-type native|unity|cocos] [--sdk-api-base-url URL] [--verbose]
|
|
79
|
+
meetgames setup [--app-id ID] [--app-secret SECRET] [--channel-type TYPE] [--env prod|pre|test] [--project-root <path>] [--app-target <target>] [--dry-run] [--verbose] [--patch-file <path>]
|
|
80
|
+
meetgames doctor [--app-id ID] [--app-secret SECRET] [--channel-type TYPE] [--env prod|pre|test] --project-root <path> [--app-target <target>] [--verbose]
|
|
81
|
+
|
|
82
|
+
Notes:
|
|
83
|
+
- Source code is TypeScript only; published bin runs compiled output under dist/.
|
|
84
|
+
- iOS: copies frameworks to topSDK/, edits project.pbxproj & Info.plist, injects AppDelegate (.m/.mm) when present (topsdk-tool-ios parity).
|
|
85
|
+
- fetch-config calls TOPSDK downloadSDKConfig and writes the response body unchanged under ${MEET_SDK_TOOL_CACHE_ROOT}.
|
|
86
|
+
- setup runs fetch-config, then download-ios-sdk for iOS projects, then integrate in one process.
|
|
87
|
+
- doctor / setup / integrate require --project-root and auto-select exactly one platform from that root.
|
|
88
|
+
- doctor first fetches downloadSDKConfig to the cache, then validates the detected platform integration.
|
|
89
|
+
- integrate uses recipes/integrate-default.yaml, filtered to the detected platform before execution.
|
|
90
|
+
- iOS SDK is read from ${MEET_SDK_TOOL_CACHE_ROOT}/sdk/ios/.
|
|
91
|
+
- Android integrate/doctor reads the latest SDK version from sdk-home and stores it in config/meetsdk-android.json.
|
|
92
|
+
- download-ios-sdk calls sdk-home getDownLoadUrl, saves and extracts the iOS SDK under ${MEET_SDK_TOOL_CACHE_ROOT}/sdk/ios/.
|
|
93
|
+
- fetch-config requires --app-secret (or TOPSDK_APP_SECRET) to sign downloadSDKConfig; appSecret is never read from meetsdk-remote-config.json.
|
|
94
|
+
- 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.
|
|
95
|
+
- fetch-config writes to ${MEET_SDK_TOOL_CACHE_ROOT}/configs/<env>/<appId>/<channelType>/meetsdk-remote-config.json.
|
|
96
|
+
- integrate/doctor read the cache entry selected by --env, --app-id, and --channel-type; without those flags they only read an existing project-root meetsdk-remote-config.json for compatibility.
|
|
97
|
+
- Recipe op gradle.applyMeetSdkRemoteConfig reads cached meetsdk-remote-config.json and writes TOPSDK marker blocks to root + app build.gradle (same idea as sdk-integration-agent gradleEditor).
|
|
98
|
+
|
|
99
|
+
Options (global where noted):
|
|
100
|
+
--project-root Host project directory (default: cwd); for iOS it may point to the project root or directly to a .xcodeproj directory
|
|
101
|
+
--app-target App target to integrate/check: Android application Gradle module (e.g. :app or launcher) or iOS App target name
|
|
102
|
+
--app-id fetch-config/integrate/doctor cache selector; default TOPSDK_APP_ID
|
|
103
|
+
--app-secret fetch-config: required appSecret for downloadSDKConfig sign (or env TOPSDK_APP_SECRET)
|
|
104
|
+
--channel-type fetch-config/integrate/doctor cache selector; default TOPSDK_CHANNEL_TYPE
|
|
105
|
+
--env fetch-config: prod(正式服,默认)| pre | test(开发调试)
|
|
106
|
+
TOPSDK_API_BASE_URL fetch-config: 覆盖 API 根地址(如 http://localhost:18080/ 联调本机 console)
|
|
107
|
+
MEETGAMES_SDK_HOME_API_BASE_URL 覆盖 sdk-home API 根地址(默认 https://business-api.meetgames.com);用于 Android 最新版本查询和 iOS SDK 下载
|
|
108
|
+
--sdk-api-base-url sdk-home API 根地址;用于 Android 最新版本查询和 iOS SDK 下载
|
|
109
|
+
--version download-ios-sdk: 指定 iOS SDK 版本;不传时从 /sdk/home/version 读取最新 iOS 版本
|
|
110
|
+
--plugins download-ios-sdk: 逗号分隔插件列表;默认与下载页 iOS 默认选择一致
|
|
111
|
+
--package-type download-ios-sdk: native(默认)| unity | cocos
|
|
112
|
+
--dry-run integrate: compute changes and patch preview without writing host project files (default is write to disk)
|
|
113
|
+
--report-file Write JSON report to path
|
|
114
|
+
--patch-file integrate: write unified diff to this path (works with --dry-run). If under <pkg>/preview-patches/, all existing files in that dir are removed first so only the latest patch remains.
|
|
115
|
+
--verbose Verbose logs and full patch preview
|
|
116
|
+
|
|
117
|
+
Subcommand notes:
|
|
118
|
+
- integrate defaults to writing files; use --dry-run for CI preview / diff-only.
|
|
119
|
+
- setup: step 1 always writes meetsdk-remote-config.json; step 2 honors --dry-run / --patch-file / --report-file.
|
|
120
|
+
- fetch-config ignores --dry-run, --report-file, --patch-file (shared parser only).
|
|
121
|
+
`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function parseArgv(argv: string[]): Parsed {
|
|
125
|
+
const out: Parsed = {
|
|
126
|
+
command: "",
|
|
127
|
+
projectRoot: process.cwd(),
|
|
128
|
+
projectRootProvided: false,
|
|
129
|
+
dryRun: false,
|
|
130
|
+
verbose: false,
|
|
131
|
+
reportFile: "",
|
|
132
|
+
patchFile: "",
|
|
133
|
+
help: false,
|
|
134
|
+
topsdkEnv: "prod",
|
|
135
|
+
topsdkAppId: "",
|
|
136
|
+
topsdkAppSecret: "",
|
|
137
|
+
topsdkChannelType: "",
|
|
138
|
+
topsdkPackageName: "",
|
|
139
|
+
appTarget: "",
|
|
140
|
+
sdkHomeApiBaseUrl: "",
|
|
141
|
+
iosSdkVersion: "",
|
|
142
|
+
iosSdkPlugins: "",
|
|
143
|
+
iosSdkPackageType: "",
|
|
144
|
+
};
|
|
145
|
+
const rest = argv.slice(2);
|
|
146
|
+
if (!rest.length || (rest[0]?.startsWith("-") ?? false)) {
|
|
147
|
+
out.help = true;
|
|
148
|
+
return out;
|
|
149
|
+
}
|
|
150
|
+
out.command = rest[0] ?? "";
|
|
151
|
+
for (let i = 1; i < rest.length; i += 1) {
|
|
152
|
+
const t = rest[i];
|
|
153
|
+
if (t === "--help" || t === "-h") {
|
|
154
|
+
out.help = true;
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
157
|
+
if (t === "--verbose") {
|
|
158
|
+
out.verbose = true;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (t === "--dry-run") {
|
|
162
|
+
out.dryRun = true;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if (t === "--project-root") {
|
|
166
|
+
out.projectRoot = path.resolve(rest[i + 1] ?? "");
|
|
167
|
+
out.projectRootProvided = true;
|
|
168
|
+
i += 1;
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
if (t === "--app-target") {
|
|
172
|
+
out.appTarget = rest[i + 1] ?? "";
|
|
173
|
+
if (!out.appTarget || out.appTarget.startsWith("-")) fail("--app-target requires a target name", EXIT.INVALID_ARGS);
|
|
174
|
+
i += 1;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (t === "--sdk-api-base-url") {
|
|
178
|
+
out.sdkHomeApiBaseUrl = rest[i + 1] ?? "";
|
|
179
|
+
if (!out.sdkHomeApiBaseUrl || out.sdkHomeApiBaseUrl.startsWith("-")) {
|
|
180
|
+
fail("--sdk-api-base-url requires a URL", EXIT.INVALID_ARGS);
|
|
181
|
+
}
|
|
182
|
+
i += 1;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (t === "--version") {
|
|
186
|
+
out.iosSdkVersion = rest[i + 1] ?? "";
|
|
187
|
+
if (!out.iosSdkVersion || out.iosSdkVersion.startsWith("-")) fail("--version requires a version", EXIT.INVALID_ARGS);
|
|
188
|
+
i += 1;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (t === "--plugins") {
|
|
192
|
+
out.iosSdkPlugins = rest[i + 1] ?? "";
|
|
193
|
+
if (!out.iosSdkPlugins || out.iosSdkPlugins.startsWith("-")) fail("--plugins requires a comma-separated list", EXIT.INVALID_ARGS);
|
|
194
|
+
i += 1;
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
if (t === "--package-type") {
|
|
198
|
+
out.iosSdkPackageType = rest[i + 1] ?? "";
|
|
199
|
+
if (!out.iosSdkPackageType || out.iosSdkPackageType.startsWith("-")) {
|
|
200
|
+
fail("--package-type requires native, unity, or cocos", EXIT.INVALID_ARGS);
|
|
201
|
+
}
|
|
202
|
+
i += 1;
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
if (t === "--env") {
|
|
206
|
+
const v = (rest[i + 1] ?? "").toLowerCase();
|
|
207
|
+
i += 1;
|
|
208
|
+
if (v === "prod" || v === "pre" || v === "test") out.topsdkEnv = v;
|
|
209
|
+
else fail(`invalid --env (use prod, pre, or test): ${v}`, EXIT.INVALID_ARGS);
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
if (t === "--app-id") {
|
|
213
|
+
out.topsdkAppId = rest[i + 1] ?? "";
|
|
214
|
+
i += 1;
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
if (t === "--app-secret") {
|
|
218
|
+
out.topsdkAppSecret = rest[i + 1] ?? "";
|
|
219
|
+
i += 1;
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
if (t === "--channel-type") {
|
|
223
|
+
out.topsdkChannelType = rest[i + 1] ?? "";
|
|
224
|
+
i += 1;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
if (t === "--report-file") {
|
|
228
|
+
out.reportFile = path.resolve(rest[i + 1] ?? "");
|
|
229
|
+
i += 1;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
if (t === "--patch-file") {
|
|
233
|
+
out.patchFile = path.resolve(rest[i + 1] ?? "");
|
|
234
|
+
i += 1;
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
fail(`unsupported argument: ${t}`, EXIT.INVALID_ARGS);
|
|
238
|
+
}
|
|
239
|
+
return out;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const DEFAULT_MANIFEST = "recipes/integrate-default.yaml";
|
|
243
|
+
|
|
244
|
+
function requiresProjectRoot(command: string): boolean {
|
|
245
|
+
return command === "doctor" || command === "setup" || command === "integrate";
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function resolvedAppTarget(parsed: Parsed): string {
|
|
249
|
+
return parsed.appTarget;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function cachedRemoteConfigPathFromArgs(parsed: Parsed): string {
|
|
253
|
+
const appId = parsed.topsdkAppId || process.env.TOPSDK_APP_ID || "";
|
|
254
|
+
const channelType = parsed.topsdkChannelType || process.env.TOPSDK_CHANNEL_TYPE || "";
|
|
255
|
+
if (!appId || !channelType) return "";
|
|
256
|
+
return resolveRemoteConfigCachePath({ env: parsed.topsdkEnv, appId, channelType });
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function selectedPlatformContext(parsed: Parsed): {
|
|
260
|
+
platform: "android" | "ios";
|
|
261
|
+
ctx: ReturnType<typeof buildWorkspaceContext>;
|
|
262
|
+
selectedCtx: ReturnType<typeof buildWorkspaceContext>;
|
|
263
|
+
} {
|
|
264
|
+
const ctx = buildWorkspaceContext(parsed.projectRoot, resolvePackageRoot(), {
|
|
265
|
+
appTarget: resolvedAppTarget(parsed),
|
|
266
|
+
sdkHomeApiBaseUrl: parsed.sdkHomeApiBaseUrl || undefined,
|
|
267
|
+
remoteConfigPath: cachedRemoteConfigPathFromArgs(parsed) || undefined,
|
|
268
|
+
});
|
|
269
|
+
const detected = detectSinglePlatform(ctx);
|
|
270
|
+
if (!detected.ok) fail(detected.error, EXIT.PROJECT_ERROR);
|
|
271
|
+
return {
|
|
272
|
+
platform: detected.platform,
|
|
273
|
+
ctx,
|
|
274
|
+
selectedCtx: platformContext(ctx, detected.platform),
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
async function cmdDoctor(parsed: Parsed): Promise<void> {
|
|
279
|
+
const { platform, selectedCtx } = selectedPlatformContext(parsed);
|
|
280
|
+
console.log("[meetgames] doctor: fetching remote config…");
|
|
281
|
+
await cmdFetchConfig(parsed);
|
|
282
|
+
console.log("[meetgames] doctor: checking project integration…");
|
|
283
|
+
const report = await runDoctor(selectedCtx, platform);
|
|
284
|
+
console.log(JSON.stringify(report, null, 2));
|
|
285
|
+
if (!report.ok) process.exit(EXIT.CONFIG_ERROR);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function readLocalMeetSdkRemoteConfig(configPath: string): MeetSdkRemoteConfig | null {
|
|
289
|
+
if (!fs.existsSync(configPath)) return null;
|
|
290
|
+
try {
|
|
291
|
+
return tryParseAsMeetSdkRemoteConfig(JSON.parse(fs.readFileSync(configPath, "utf8")) as unknown);
|
|
292
|
+
} catch {
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
async function cmdFetchConfig(parsed: Parsed): Promise<void> {
|
|
298
|
+
const selectedConfigPath = cachedRemoteConfigPathFromArgs(parsed);
|
|
299
|
+
const localConfig = selectedConfigPath ? readLocalMeetSdkRemoteConfig(selectedConfigPath) : null;
|
|
300
|
+
|
|
301
|
+
const appId = parsed.topsdkAppId || localConfig?.topsdk.appId || process.env.TOPSDK_APP_ID || "";
|
|
302
|
+
const appSecret = parsed.topsdkAppSecret || process.env.TOPSDK_APP_SECRET || "";
|
|
303
|
+
const channelType =
|
|
304
|
+
parsed.topsdkChannelType ||
|
|
305
|
+
(localConfig ? readMeetSdkRemoteChannel(localConfig) : "") ||
|
|
306
|
+
process.env.TOPSDK_CHANNEL_TYPE ||
|
|
307
|
+
"";
|
|
308
|
+
|
|
309
|
+
if (!appId || !channelType || !appSecret) {
|
|
310
|
+
fail(
|
|
311
|
+
`fetch-config requires --app-id, --app-secret, and --channel-type (or TOPSDK_APP_ID / TOPSDK_APP_SECRET / TOPSDK_CHANNEL_TYPE; appSecret is not read from ${MEETSDK_REMOTE_CONFIG_FILENAME}).`,
|
|
312
|
+
EXIT.INVALID_ARGS
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const baseUrl = process.env.TOPSDK_API_BASE_URL?.trim() || defaultTopSdkBaseUrl(parsed.topsdkEnv);
|
|
317
|
+
|
|
318
|
+
let body: unknown;
|
|
319
|
+
let requestUrl: string;
|
|
320
|
+
let rawText: string;
|
|
321
|
+
try {
|
|
322
|
+
const res = await fetchTopSdkDownloadSdkConfig({
|
|
323
|
+
baseUrl,
|
|
324
|
+
appId,
|
|
325
|
+
appSecret,
|
|
326
|
+
channelType,
|
|
327
|
+
});
|
|
328
|
+
body = res.body;
|
|
329
|
+
requestUrl = res.url;
|
|
330
|
+
rawText = res.text;
|
|
331
|
+
} catch (e) {
|
|
332
|
+
fail(e instanceof Error ? e.message : String(e), EXIT.NETWORK_ERROR);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const validation = validateDownloadSdkConfigForWrite(body);
|
|
336
|
+
if (!validation) {
|
|
337
|
+
fail(
|
|
338
|
+
`downloadSDKConfig response is not a valid ${MEETSDK_REMOTE_CONFIG_FILENAME} document (GET ${requestUrl})`,
|
|
339
|
+
EXIT.CONFIG_ERROR
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
for (const warning of validation.warnings) {
|
|
344
|
+
console.warn(`[meetgames] warning: ${warning}`);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const written = writeRemoteConfigCache({
|
|
348
|
+
env: parsed.topsdkEnv,
|
|
349
|
+
appId,
|
|
350
|
+
channelType,
|
|
351
|
+
requestUrl,
|
|
352
|
+
rawText,
|
|
353
|
+
warnings: validation.warnings,
|
|
354
|
+
});
|
|
355
|
+
console.log(`[meetgames] wrote ${MEETSDK_REMOTE_CONFIG_FILENAME} (downloadSDKConfig response, unmodified): ${written.configPath}`);
|
|
356
|
+
if (parsed.verbose) {
|
|
357
|
+
console.log(`[meetgames] GET ${requestUrl}`);
|
|
358
|
+
console.log(`[meetgames] metadata: ${written.metadataPath}`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
async function cmdIntegrate(parsed: Parsed): Promise<void> {
|
|
363
|
+
const manifestPath = path.join(resolvePackageRoot(), DEFAULT_MANIFEST);
|
|
364
|
+
if (!fs.existsSync(manifestPath)) {
|
|
365
|
+
fail(`config file not found: ${manifestPath}`, EXIT.PROJECT_ERROR);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
let manifest: Manifest;
|
|
369
|
+
try {
|
|
370
|
+
manifest = loadManifestFile(manifestPath);
|
|
371
|
+
} catch (e) {
|
|
372
|
+
fail(e instanceof Error ? e.message : String(e), EXIT.CONFIG_ERROR);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const { platform, ctx, selectedCtx } = selectedPlatformContext(parsed);
|
|
376
|
+
const selectedManifest = manifestForPlatform(manifest, platform);
|
|
377
|
+
const { report, patch, binaryCopies } = await runPipeline(selectedCtx, selectedManifest, { dryRun: parsed.dryRun });
|
|
378
|
+
printReport(report, patch, parsed.verbose);
|
|
379
|
+
if (binaryCopies.length) {
|
|
380
|
+
console.log("[meetgames] planned binary copies:");
|
|
381
|
+
for (const c of binaryCopies) {
|
|
382
|
+
console.log(` ${c.fromAbs} -> ${path.join(ctx.projectRoot, c.relTo)}`);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (parsed.reportFile) {
|
|
387
|
+
fs.mkdirSync(path.dirname(parsed.reportFile), { recursive: true });
|
|
388
|
+
fs.writeFileSync(parsed.reportFile, JSON.stringify({ ...report, binaryCopies }, null, 2), "utf8");
|
|
389
|
+
}
|
|
390
|
+
if (parsed.patchFile) {
|
|
391
|
+
const patchAbs = path.resolve(parsed.patchFile);
|
|
392
|
+
clearPreviewPatchFilesIfTargetInside(resolvePackageRoot(), patchAbs);
|
|
393
|
+
fs.mkdirSync(path.dirname(patchAbs), { recursive: true });
|
|
394
|
+
fs.writeFileSync(patchAbs, patch || "# no text changes\n", "utf8");
|
|
395
|
+
console.log(`[meetgames] wrote patch file: ${patchAbs}`);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (report.errors.length) {
|
|
399
|
+
process.exit(EXIT.PIPELINE_ERROR);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
async function cmdSetup(parsed: Parsed): Promise<void> {
|
|
404
|
+
const { platform } = selectedPlatformContext(parsed);
|
|
405
|
+
console.log("[meetgames] setup: fetching remote config…");
|
|
406
|
+
await cmdFetchConfig(parsed);
|
|
407
|
+
if (platform === "ios") {
|
|
408
|
+
console.log("[meetgames] setup: downloading iOS SDK…");
|
|
409
|
+
await cmdDownloadIosSdk(parsed);
|
|
410
|
+
}
|
|
411
|
+
console.log("[meetgames] setup: integrating project…");
|
|
412
|
+
await cmdIntegrate(parsed);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
async function cmdDownloadIosSdk(parsed: Parsed): Promise<void> {
|
|
416
|
+
const baseUrl =
|
|
417
|
+
parsed.sdkHomeApiBaseUrl || process.env.MEETGAMES_SDK_HOME_API_BASE_URL?.trim() || defaultSdkHomeApiBaseUrl;
|
|
418
|
+
const packageType = parsed.iosSdkPackageType || DEFAULT_IOS_SDK_PACKAGE_TYPE;
|
|
419
|
+
if (!["native", "unity", "cocos"].includes(packageType)) {
|
|
420
|
+
fail(`invalid --package-type (use native, unity, or cocos): ${packageType}`, EXIT.INVALID_ARGS);
|
|
421
|
+
}
|
|
422
|
+
const plugins = parsed.iosSdkPlugins
|
|
423
|
+
? parsed.iosSdkPlugins
|
|
424
|
+
.split(",")
|
|
425
|
+
.map((s) => s.trim())
|
|
426
|
+
.filter(Boolean)
|
|
427
|
+
: undefined;
|
|
428
|
+
if (parsed.iosSdkPlugins && !plugins?.length) {
|
|
429
|
+
fail("--plugins must contain at least one plugin", EXIT.INVALID_ARGS);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
console.log("[meetgames] download-ios-sdk: resolving sdk-home iOS SDK…");
|
|
433
|
+
let result;
|
|
434
|
+
try {
|
|
435
|
+
result = await downloadIosSdkToBundled(resolvePackageRoot(), {
|
|
436
|
+
baseUrl,
|
|
437
|
+
version: parsed.iosSdkVersion || undefined,
|
|
438
|
+
plugins,
|
|
439
|
+
packageType,
|
|
440
|
+
});
|
|
441
|
+
} catch (e) {
|
|
442
|
+
fail(e instanceof Error ? e.message : String(e), EXIT.NETWORK_ERROR);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
console.log(`[meetgames] downloaded iOS SDK ${result.version} zip: ${result.zipPath}`);
|
|
446
|
+
console.log(`[meetgames] extracted iOS SDK to: ${result.extractDir}`);
|
|
447
|
+
console.log(`[meetgames] resolved iOS SDK root: ${result.resolvedSdkRoot}`);
|
|
448
|
+
console.log(`[meetgames] wrote iOS SDK metadata: ${result.cacheMetadataPath}`);
|
|
449
|
+
if (parsed.verbose) {
|
|
450
|
+
console.log(`[meetgames] GET ${result.versionUrl}`);
|
|
451
|
+
console.log(`[meetgames] GET ${result.downloadApiUrl}`);
|
|
452
|
+
console.log(`[meetgames] SDK zip URL: ${result.sdkZipUrl}`);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
export async function main(): Promise<void> {
|
|
457
|
+
const parsed = parseArgv(process.argv);
|
|
458
|
+
if (parsed.help) {
|
|
459
|
+
printHelp();
|
|
460
|
+
process.exit(EXIT.OK);
|
|
461
|
+
}
|
|
462
|
+
if (!parsed.command) {
|
|
463
|
+
printHelp();
|
|
464
|
+
process.exit(EXIT.INVALID_ARGS);
|
|
465
|
+
}
|
|
466
|
+
if (requiresProjectRoot(parsed.command) && !parsed.projectRootProvided) {
|
|
467
|
+
fail(`${parsed.command} requires --project-root`, EXIT.INVALID_ARGS);
|
|
468
|
+
}
|
|
469
|
+
if (!fs.existsSync(parsed.projectRoot) || !fs.statSync(parsed.projectRoot).isDirectory()) {
|
|
470
|
+
fail("project root does not exist or is not a directory", EXIT.INVALID_ARGS);
|
|
471
|
+
}
|
|
472
|
+
if (parsed.appTarget && !["doctor", "setup", "integrate"].includes(parsed.command)) {
|
|
473
|
+
fail("--app-target is only supported by doctor, setup, and integrate", EXIT.INVALID_ARGS);
|
|
474
|
+
}
|
|
475
|
+
resolvedAppTarget(parsed);
|
|
476
|
+
|
|
477
|
+
switch (parsed.command) {
|
|
478
|
+
case "doctor":
|
|
479
|
+
await cmdDoctor(parsed);
|
|
480
|
+
break;
|
|
481
|
+
case "integrate":
|
|
482
|
+
await cmdIntegrate(parsed);
|
|
483
|
+
break;
|
|
484
|
+
case "fetch-config":
|
|
485
|
+
await cmdFetchConfig(parsed);
|
|
486
|
+
break;
|
|
487
|
+
case "download-ios-sdk":
|
|
488
|
+
await cmdDownloadIosSdk(parsed);
|
|
489
|
+
break;
|
|
490
|
+
case "setup":
|
|
491
|
+
await cmdSetup(parsed);
|
|
492
|
+
break;
|
|
493
|
+
default:
|
|
494
|
+
fail(`unknown command: ${parsed.command}`, EXIT.INVALID_ARGS);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
tryParseAsMeetSdkRemoteConfig,
|
|
5
|
+
validateMeetSdkRemoteConfig,
|
|
6
|
+
type MeetSdkRemoteConfig,
|
|
7
|
+
} from "./meetSdkRemoteConfig.js";
|
|
8
|
+
|
|
9
|
+
export interface FetchConfigWriteValidation {
|
|
10
|
+
parsed: MeetSdkRemoteConfig;
|
|
11
|
+
warnings: string[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Shape check only; does not normalize or merge meetsdk-android.json. */
|
|
15
|
+
export function validateDownloadSdkConfigForWrite(body: unknown): FetchConfigWriteValidation | null {
|
|
16
|
+
const parsed = tryParseAsMeetSdkRemoteConfig(body);
|
|
17
|
+
if (!parsed) return null;
|
|
18
|
+
const warnings: string[] = [];
|
|
19
|
+
const validation = validateMeetSdkRemoteConfig(parsed);
|
|
20
|
+
if (!validation.ok) {
|
|
21
|
+
warnings.push(`remote-config missing or empty fields: ${validation.missing.join(", ")}`);
|
|
22
|
+
}
|
|
23
|
+
return { parsed, warnings };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Write gp-sdk response bytes as-is (no normalize / no meetsdk-android merge). */
|
|
27
|
+
export function writeDownloadSdkConfigRaw(outPath: string, rawText: string): void {
|
|
28
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
29
|
+
fs.writeFileSync(outPath, rawText, "utf8");
|
|
30
|
+
}
|