@leonxin/meetgames 0.1.11 → 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/README.md +9 -9
- 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 +43 -37
- package/dist/cli.js.map +1 -1
- package/dist/config/meetSdkDefaultConfig.d.ts +1 -1
- package/dist/config/meetSdkDefaultConfig.d.ts.map +1 -1
- package/dist/config/meetSdkDefaultConfig.js +4 -3
- package/dist/config/meetSdkDefaultConfig.js.map +1 -1
- package/dist/config/meetSdkIosConfig.d.ts.map +1 -1
- package/dist/config/meetSdkIosConfig.js +3 -1
- package/dist/config/meetSdkIosConfig.js.map +1 -1
- package/dist/config/meetSdkRemoteConfig.d.ts +1 -0
- package/dist/config/meetSdkRemoteConfig.d.ts.map +1 -1
- package/dist/config/meetSdkRemoteConfig.js +4 -1
- package/dist/config/meetSdkRemoteConfig.js.map +1 -1
- package/dist/contracts/types.d.ts +8 -0
- package/dist/contracts/types.d.ts.map +1 -1
- package/dist/core/doctor.js +7 -7
- package/dist/core/doctor.js.map +1 -1
- 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/workspace.d.ts.map +1 -1
- package/dist/core/workspace.js +2 -0
- package/dist/core/workspace.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/ios/integrate.d.ts.map +1 -1
- package/dist/ios/integrate.js +3 -3
- package/dist/ios/integrate.js.map +1 -1
- package/dist/ios/pbxprojEditor.d.ts.map +1 -1
- package/dist/ios/pbxprojEditor.js +71 -5
- package/dist/ios/pbxprojEditor.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 +44 -16
- package/dist/ios/sdkBundle.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +12 -6
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/service.d.ts +3 -0
- package/dist/mcp/service.d.ts.map +1 -1
- package/dist/mcp/service.js +31 -8
- package/dist/mcp/service.js.map +1 -1
- package/dist/ops/handlers.d.ts.map +1 -1
- package/dist/ops/handlers.js +24 -19
- package/dist/ops/handlers.js.map +1 -1
- package/dist/remote/sdkHomeDownload.d.ts +1 -1
- package/dist/remote/sdkHomeDownload.d.ts.map +1 -1
- package/dist/remote/sdkHomeDownload.js +27 -6
- package/dist/remote/sdkHomeDownload.js.map +1 -1
- package/docs/API.md +16 -16
- package/docs/CLI.md +21 -22
- package/docs/INTEGRATION.md +11 -11
- package/docs/MCP.md +1 -1
- package/docs/README.md +0 -1
- package/docs/archive/api/downloadSDKConfig.md +2 -2
- package/docs/archive/api/getChannelConfig-meetgames.md +1 -1
- package/docs/archive/product//351/234/200/346/261/202/346/226/207/346/241/243.md +1 -1
- package/package.json +2 -5
- package/recipes/android-default.yaml +0 -5
- package/recipes/integrate-default.yaml +0 -5
- package/src/cache.ts +164 -0
- package/src/cli.ts +46 -38
- package/src/config/meetSdkDefaultConfig.ts +4 -3
- package/src/config/meetSdkIosConfig.ts +3 -1
- package/src/config/meetSdkRemoteConfig.ts +5 -1
- package/src/contracts/types.ts +8 -0
- package/src/core/doctor.ts +7 -7
- package/src/core/previewPatches.ts +2 -2
- package/src/core/workspace.ts +2 -0
- package/src/index.ts +7 -0
- package/src/ios/integrate.ts +4 -3
- package/src/ios/pbxprojEditor.ts +70 -3
- package/src/ios/sdkBundle.ts +41 -18
- package/src/mcp/server.ts +12 -6
- package/src/mcp/service.ts +39 -8
- package/src/ops/handlers.ts +23 -19
- package/src/remote/sdkHomeDownload.ts +28 -7
- package/tests/doctor.test.ts +4 -2
- package/tests/{test-projects-hosts.test.ts → fixtures-hosts.test.ts} +2 -2
- package/tests/ios.sdkBundle.test.ts +10 -5
- package/tests/mcp.e2e.ts +2 -5
- package/tests/meetSdkRemoteConfig.test.ts +25 -0
- package/tests/pipeline.android.test.ts +1 -2
- package/tests/pipeline.ios.test.ts +26 -19
- package/tests/pipeline.preview.patch.test.ts +2 -2
- package/tests/sdkVersionConfig.test.ts +3 -2
- package/dist/aab-converter/aab-entry.d.ts +0 -3
- package/dist/aab-converter/aab-entry.d.ts.map +0 -1
- package/dist/aab-converter/aab-entry.js +0 -49
- package/dist/aab-converter/aab-entry.js.map +0 -1
- package/dist/aab-converter/apksExtractor.d.ts +0 -2
- package/dist/aab-converter/apksExtractor.d.ts.map +0 -1
- package/dist/aab-converter/apksExtractor.js +0 -108
- package/dist/aab-converter/apksExtractor.js.map +0 -1
- package/dist/aab-converter/bundletoolRunner.d.ts +0 -15
- package/dist/aab-converter/bundletoolRunner.d.ts.map +0 -1
- package/dist/aab-converter/bundletoolRunner.js +0 -46
- package/dist/aab-converter/bundletoolRunner.js.map +0 -1
- package/dist/aab-converter/cliArgs.d.ts +0 -27
- package/dist/aab-converter/cliArgs.d.ts.map +0 -1
- package/dist/aab-converter/cliArgs.js +0 -170
- package/dist/aab-converter/cliArgs.js.map +0 -1
- package/dist/aab-converter/convertAabToApk.d.ts +0 -7
- package/dist/aab-converter/convertAabToApk.d.ts.map +0 -1
- package/dist/aab-converter/convertAabToApk.js +0 -69
- package/dist/aab-converter/convertAabToApk.js.map +0 -1
- package/dist/aab-converter/resourcePaths.d.ts +0 -4
- package/dist/aab-converter/resourcePaths.d.ts.map +0 -1
- package/dist/aab-converter/resourcePaths.js +0 -42
- package/dist/aab-converter/resourcePaths.js.map +0 -1
- package/dist/aab-converter/signingOptions.d.ts +0 -9
- package/dist/aab-converter/signingOptions.d.ts.map +0 -1
- package/dist/aab-converter/signingOptions.js +0 -21
- package/dist/aab-converter/signingOptions.js.map +0 -1
- package/dist/aab-converter/types.d.ts +0 -24
- package/dist/aab-converter/types.d.ts.map +0 -1
- package/dist/aab-converter/types.js +0 -2
- package/dist/aab-converter/types.js.map +0 -1
- package/dist/shared/fileUtils.d.ts +0 -5
- package/dist/shared/fileUtils.d.ts.map +0 -1
- package/dist/shared/fileUtils.js +0 -35
- package/dist/shared/fileUtils.js.map +0 -1
- package/dist/shared/logger.d.ts +0 -10
- package/dist/shared/logger.d.ts.map +0 -1
- package/dist/shared/logger.js +0 -37
- package/dist/shared/logger.js.map +0 -1
- package/dist/shared/pathUtils.d.ts +0 -4
- package/dist/shared/pathUtils.d.ts.map +0 -1
- package/dist/shared/pathUtils.js +0 -22
- package/dist/shared/pathUtils.js.map +0 -1
- package/dist/shared/processRunner.d.ts +0 -12
- package/dist/shared/processRunner.d.ts.map +0 -1
- package/dist/shared/processRunner.js +0 -31
- package/dist/shared/processRunner.js.map +0 -1
- package/docs/AAB_CONVERTER_CLI_PLAN.md +0 -392
- package/logs/convert-20260622-155037.log +0 -5
- package/logs/convert-20260622-155226.log +0 -6
- package/scripts/package-aab-cli-win.mjs +0 -193
- package/src/aab-converter/aab-entry.ts +0 -48
- package/src/aab-converter/apksExtractor.ts +0 -119
- package/src/aab-converter/bundletoolRunner.ts +0 -63
- package/src/aab-converter/cliArgs.ts +0 -194
- package/src/aab-converter/convertAabToApk.ts +0 -81
- package/src/aab-converter/resourcePaths.ts +0 -43
- package/src/aab-converter/signingOptions.ts +0 -29
- package/src/aab-converter/types.ts +0 -26
- package/src/shared/fileUtils.ts +0 -41
- package/src/shared/logger.ts +0 -49
- package/src/shared/pathUtils.ts +0 -24
- package/src/shared/processRunner.ts +0 -43
- package/test-projects/README.md +0 -51
- package/test-projects/_preview/pipeline.patch +0 -281
- package/tests/aab-converter.test.ts +0 -213
- /package/{meetsdk-android.json → config/meetsdk-android.json} +0 -0
- /package/{meetsdk-ios.json → config/meetsdk-ios.json} +0 -0
package/src/ios/integrate.ts
CHANGED
|
@@ -333,9 +333,9 @@ export async function runIosIntegrateTopSdk(
|
|
|
333
333
|
const warnings: string[] = [];
|
|
334
334
|
const changed = new Set<string>();
|
|
335
335
|
|
|
336
|
-
const configPath = path.join(ctx.projectRoot, MEETSDK_REMOTE_CONFIG_FILENAME);
|
|
336
|
+
const configPath = ctx.remoteConfigPath ?? path.join(ctx.projectRoot, MEETSDK_REMOTE_CONFIG_FILENAME);
|
|
337
337
|
if (!fs.existsSync(configPath)) {
|
|
338
|
-
return fail([`${MEETSDK_REMOTE_CONFIG_FILENAME} not found; run fetch-config or setup first`]);
|
|
338
|
+
return fail([`${MEETSDK_REMOTE_CONFIG_FILENAME} not found at ${configPath}; run fetch-config or setup first`]);
|
|
339
339
|
}
|
|
340
340
|
let remote: ReturnType<typeof tryParseAsMeetSdkRemoteConfig>;
|
|
341
341
|
try {
|
|
@@ -353,7 +353,7 @@ export async function runIosIntegrateTopSdk(
|
|
|
353
353
|
|
|
354
354
|
let sdkRoot: string;
|
|
355
355
|
try {
|
|
356
|
-
sdkRoot = resolveIosSdkRoot(ctx.packageRoot);
|
|
356
|
+
sdkRoot = ctx.iosSdkRoot ?? resolveIosSdkRoot(ctx.packageRoot);
|
|
357
357
|
} catch (e) {
|
|
358
358
|
return fail([e instanceof Error ? e.message : String(e)]);
|
|
359
359
|
}
|
|
@@ -375,6 +375,7 @@ export async function runIosIntegrateTopSdk(
|
|
|
375
375
|
if (p) pluginConfigs.push(p);
|
|
376
376
|
else warnings.push(`iOS plugin folder not in SDK package: plugins/${folder}`);
|
|
377
377
|
}
|
|
378
|
+
|
|
378
379
|
const xcodeprojPath = ctx.ios.xcodeprojPath!;
|
|
379
380
|
const pbx = await loadPbxFromStore(store, ctx.projectRoot, xcodeprojPath, targetName);
|
|
380
381
|
const fm = new TopSdkFileManager(pbx.srcRoot);
|
package/src/ios/pbxprojEditor.ts
CHANGED
|
@@ -69,9 +69,70 @@ export async function loadPbxFromStore(
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
export function savePbxToStore(store: TextFileStore, ctx: PbxContext): void {
|
|
72
|
+
stripUndefinedValues(ctx.proj.hash?.project?.objects);
|
|
73
|
+
sanitizePbxBuildSettings(ctx.proj);
|
|
72
74
|
store.write(ctx.rel, ctx.proj.writeSync());
|
|
73
75
|
}
|
|
74
76
|
|
|
77
|
+
function stripUndefinedValues(value: unknown): void {
|
|
78
|
+
if (Array.isArray(value)) {
|
|
79
|
+
for (const item of value) stripUndefinedValues(item);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (!value || typeof value !== "object") return;
|
|
83
|
+
|
|
84
|
+
const record = value as Record<string, unknown>;
|
|
85
|
+
for (const [key, nested] of Object.entries(record)) {
|
|
86
|
+
if (nested === undefined || nested === "undefined") {
|
|
87
|
+
delete record[key];
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
stripUndefinedValues(nested);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function sanitizePbxBuildSettings(proj: XcodeProject): void {
|
|
95
|
+
const buildConfigs = proj.pbxXCBuildConfigurationSection?.() ?? {};
|
|
96
|
+
for (const [uuid, cfg] of Object.entries(buildConfigs)) {
|
|
97
|
+
if (uuid.endsWith("_comment") || !cfg || typeof cfg !== "object") continue;
|
|
98
|
+
const settings = (cfg as { buildSettings?: Record<string, unknown> }).buildSettings;
|
|
99
|
+
if (!settings) continue;
|
|
100
|
+
for (const [key, raw] of Object.entries(settings)) {
|
|
101
|
+
if (typeof raw === "string") {
|
|
102
|
+
settings[key] = quotePbxStringIfNeeded(raw);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (Array.isArray(raw)) {
|
|
106
|
+
settings[key] = raw.map((value) => (typeof value === "string" ? quotePbxStringIfNeeded(value) : value));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function isPbxQuotedString(value: string): boolean {
|
|
113
|
+
return value.length >= 2 && value.startsWith('"') && value.endsWith('"');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function unquotePbxString(value: string): string {
|
|
117
|
+
if (!isPbxQuotedString(value)) return value;
|
|
118
|
+
return value.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function quotePbxStringIfNeeded(value: string): string {
|
|
122
|
+
if (isPbxQuotedString(value)) return value;
|
|
123
|
+
if (!pbxStringNeedsQuotes(value)) return value;
|
|
124
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function pbxStringNeedsQuotes(value: string): boolean {
|
|
128
|
+
if (value.length === 0 || value.startsWith("-")) return true;
|
|
129
|
+
return /[^A-Za-z0-9_.$/{}()+-]/.test(value);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function samePbxStringValue(a: unknown, b: string): boolean {
|
|
133
|
+
return typeof a === "string" && unquotePbxString(a) === unquotePbxString(b);
|
|
134
|
+
}
|
|
135
|
+
|
|
75
136
|
function targetUuid(proj: XcodeProject, targetName: string): string | undefined {
|
|
76
137
|
const targets = proj.pbxNativeTargetSection?.() ?? {};
|
|
77
138
|
for (const [uuid, t] of Object.entries(targets)) {
|
|
@@ -317,12 +378,18 @@ export function addOtherLinkerFlag(ctx: PbxContext, flag: string): void {
|
|
|
317
378
|
if (!cfg || typeof cfg !== "object") continue;
|
|
318
379
|
const settings = (cfg as { buildSettings?: Record<string, unknown> }).buildSettings ?? {};
|
|
319
380
|
const cur = settings.OTHER_LDFLAGS;
|
|
381
|
+
const normalizedFlag = unquotePbxString(flag);
|
|
382
|
+
const nextFlag = quotePbxStringIfNeeded(normalizedFlag);
|
|
320
383
|
if (typeof cur === "string") {
|
|
321
|
-
if (!cur.includes(
|
|
384
|
+
if (!unquotePbxString(cur).split(/\s+/).includes(normalizedFlag)) {
|
|
385
|
+
settings.OTHER_LDFLAGS = [quotePbxStringIfNeeded(cur), nextFlag];
|
|
386
|
+
}
|
|
322
387
|
} else if (Array.isArray(cur)) {
|
|
323
|
-
|
|
388
|
+
const values = cur.map((value) => (typeof value === "string" ? quotePbxStringIfNeeded(value) : value));
|
|
389
|
+
if (!values.some((value) => samePbxStringValue(value, normalizedFlag))) values.push(nextFlag);
|
|
390
|
+
settings.OTHER_LDFLAGS = values;
|
|
324
391
|
} else {
|
|
325
|
-
settings.OTHER_LDFLAGS = [
|
|
392
|
+
settings.OTHER_LDFLAGS = [nextFlag];
|
|
326
393
|
}
|
|
327
394
|
(cfg as { buildSettings: Record<string, unknown> }).buildSettings = settings;
|
|
328
395
|
}
|
package/src/ios/sdkBundle.ts
CHANGED
|
@@ -1,25 +1,17 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
|
|
4
|
-
const BUNDLED_IOS_REL = path.join("bundled", "ios-sdk");
|
|
5
|
-
|
|
6
|
-
export function defaultBundledIosSdkRoot(packageRoot: string): string {
|
|
7
|
-
return path.join(packageRoot, BUNDLED_IOS_REL);
|
|
8
|
-
}
|
|
3
|
+
import { MEET_SDK_TOOL_CACHE_ROOT } from "../cache.js";
|
|
9
4
|
|
|
10
5
|
/**
|
|
11
|
-
* TopSDK iOS package root
|
|
12
|
-
* Native iOS only
|
|
6
|
+
* TopSDK iOS package root from cache.
|
|
7
|
+
* Native iOS only.
|
|
13
8
|
*/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (!fs.existsSync(bundled)) {
|
|
17
|
-
throw new Error(`iOS SDK not found at ${BUNDLED_IOS_REL} (expected sdk/ and plugins/ inside).`);
|
|
18
|
-
}
|
|
9
|
+
function findIosSdkRoot(container: string): string | null {
|
|
10
|
+
if (!fs.existsSync(container)) return null;
|
|
19
11
|
const children = fs
|
|
20
|
-
.readdirSync(
|
|
12
|
+
.readdirSync(container, { withFileTypes: true })
|
|
21
13
|
.filter((d) => d.isDirectory() && !d.name.startsWith("."))
|
|
22
|
-
.map((d) => path.join(
|
|
14
|
+
.map((d) => path.join(container, d.name))
|
|
23
15
|
.sort()
|
|
24
16
|
.reverse();
|
|
25
17
|
for (const dir of children) {
|
|
@@ -27,10 +19,41 @@ export function resolveIosSdkRoot(packageRoot: string): string {
|
|
|
27
19
|
return dir;
|
|
28
20
|
}
|
|
29
21
|
}
|
|
30
|
-
if (fs.existsSync(path.join(
|
|
31
|
-
return
|
|
22
|
+
if (fs.existsSync(path.join(container, "sdk")) && fs.existsSync(path.join(container, "plugins"))) {
|
|
23
|
+
return container;
|
|
32
24
|
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function findLatestCachedIosSdkRoot(): string | null {
|
|
29
|
+
const iosCache = path.join(MEET_SDK_TOOL_CACHE_ROOT, "sdk", "ios");
|
|
30
|
+
if (!fs.existsSync(iosCache)) return null;
|
|
31
|
+
const candidates: string[] = [];
|
|
32
|
+
const walk = (dir: string): void => {
|
|
33
|
+
for (const ent of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
34
|
+
if (!ent.isDirectory() || ent.name.startsWith(".")) continue;
|
|
35
|
+
const abs = path.join(dir, ent.name);
|
|
36
|
+
if (ent.name === "extracted") {
|
|
37
|
+
candidates.push(abs);
|
|
38
|
+
} else {
|
|
39
|
+
walk(abs);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
walk(iosCache);
|
|
44
|
+
candidates.sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs);
|
|
45
|
+
for (const candidate of candidates) {
|
|
46
|
+
const found = findIosSdkRoot(candidate);
|
|
47
|
+
if (found) return found;
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function resolveIosSdkRoot(_packageRoot: string): string {
|
|
53
|
+
const cached = findLatestCachedIosSdkRoot();
|
|
54
|
+
if (cached) return cached;
|
|
55
|
+
|
|
33
56
|
throw new Error(
|
|
34
|
-
`iOS SDK
|
|
57
|
+
`iOS SDK not found in ${path.join(MEET_SDK_TOOL_CACHE_ROOT, "sdk", "ios")}; run download-ios-sdk or setup first.`
|
|
35
58
|
);
|
|
36
59
|
}
|
package/src/mcp/server.ts
CHANGED
|
@@ -46,7 +46,7 @@ export function createMeetgamesMcpServer(): McpServer {
|
|
|
46
46
|
"meetgames_fetch_config",
|
|
47
47
|
{
|
|
48
48
|
description:
|
|
49
|
-
"Download TOPSDK meetsdk-remote-config.json via downloadSDKConfig and write it into
|
|
49
|
+
"Download TOPSDK meetsdk-remote-config.json via downloadSDKConfig and write it into ~/.cache/meet-sdk-tool.",
|
|
50
50
|
inputSchema: {
|
|
51
51
|
projectRoot: z.string().optional().describe("Absolute or relative project root; default is current working directory."),
|
|
52
52
|
env: z.enum(["prod", "pre", "test"]).optional().describe("TOPSDK API environment."),
|
|
@@ -78,11 +78,14 @@ export function createMeetgamesMcpServer(): McpServer {
|
|
|
78
78
|
inputSchema: {
|
|
79
79
|
projectRoot: z.string().optional().describe("Absolute or relative project root; default is current working directory."),
|
|
80
80
|
appTarget: z.string().optional().describe("App target to integrate/check: Android application Gradle module or iOS App target name."),
|
|
81
|
+
env: z.enum(["prod", "pre", "test"]).optional().describe("TOPSDK API environment for selecting cached config."),
|
|
82
|
+
appId: z.string().optional().describe("Application id for selecting cached config."),
|
|
83
|
+
channelType: z.string().optional().describe("Channel type for selecting cached config."),
|
|
81
84
|
},
|
|
82
85
|
},
|
|
83
|
-
async ({ projectRoot, appTarget }) => {
|
|
86
|
+
async ({ projectRoot, appTarget, env, appId, channelType }) => {
|
|
84
87
|
try {
|
|
85
|
-
const result = await meetgamesIntegrate({ projectRoot, appTarget, dryRun: true });
|
|
88
|
+
const result = await meetgamesIntegrate({ projectRoot, appTarget, env, appId, channelType, dryRun: true });
|
|
86
89
|
if (result.hasErrors) {
|
|
87
90
|
return {
|
|
88
91
|
...toSuccessResult(result),
|
|
@@ -103,11 +106,14 @@ export function createMeetgamesMcpServer(): McpServer {
|
|
|
103
106
|
inputSchema: {
|
|
104
107
|
projectRoot: z.string().optional().describe("Absolute or relative project root; default is current working directory."),
|
|
105
108
|
appTarget: z.string().optional().describe("App target to integrate/check: Android application Gradle module or iOS App target name."),
|
|
109
|
+
env: z.enum(["prod", "pre", "test"]).optional().describe("TOPSDK API environment for selecting cached config."),
|
|
110
|
+
appId: z.string().optional().describe("Application id for selecting cached config."),
|
|
111
|
+
channelType: z.string().optional().describe("Channel type for selecting cached config."),
|
|
106
112
|
},
|
|
107
113
|
},
|
|
108
|
-
async ({ projectRoot, appTarget }) => {
|
|
114
|
+
async ({ projectRoot, appTarget, env, appId, channelType }) => {
|
|
109
115
|
try {
|
|
110
|
-
const result = await meetgamesIntegrate({ projectRoot, appTarget, dryRun: false });
|
|
116
|
+
const result = await meetgamesIntegrate({ projectRoot, appTarget, env, appId, channelType, dryRun: false });
|
|
111
117
|
if (result.hasErrors) {
|
|
112
118
|
return {
|
|
113
119
|
...toSuccessResult(result),
|
|
@@ -125,7 +131,7 @@ export function createMeetgamesMcpServer(): McpServer {
|
|
|
125
131
|
"meetgames_setup",
|
|
126
132
|
{
|
|
127
133
|
description:
|
|
128
|
-
"Download meetsdk-remote-config.json then run default integrate recipe
|
|
134
|
+
"Download meetsdk-remote-config.json into ~/.cache/meet-sdk-tool, ensure iOS SDK cache when needed, then run the default integrate recipe.",
|
|
129
135
|
inputSchema: {
|
|
130
136
|
projectRoot: z.string().optional().describe("Absolute or relative project root; default is current working directory."),
|
|
131
137
|
env: z.enum(["prod", "pre", "test"]).optional().describe("TOPSDK API environment."),
|
package/src/mcp/service.ts
CHANGED
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
} from "../config/meetSdkRemoteConfig.js";
|
|
10
10
|
import {
|
|
11
11
|
validateDownloadSdkConfigForWrite,
|
|
12
|
-
writeDownloadSdkConfigRaw,
|
|
13
12
|
} from "../config/fetchConfigWrite.js";
|
|
14
13
|
import type { PipelineReport } from "../contracts/types.js";
|
|
15
14
|
import type { BinaryCopy } from "../ops/handlers.js";
|
|
@@ -22,6 +21,8 @@ import {
|
|
|
22
21
|
} from "../core/platform.js";
|
|
23
22
|
import { buildWorkspaceContext, resolvePackageRoot } from "../core/workspace.js";
|
|
24
23
|
import { defaultTopSdkBaseUrl, fetchTopSdkDownloadSdkConfig, type TopSdkApiEnv } from "../remote/topsdkDownloadSdkConfig.js";
|
|
24
|
+
import { downloadIosSdkToBundled, defaultSdkHomeApiBaseUrl } from "../remote/sdkHomeDownload.js";
|
|
25
|
+
import { resolveRemoteConfigCachePath, writeRemoteConfigCache } from "../cache.js";
|
|
25
26
|
|
|
26
27
|
const DEFAULT_MANIFEST_REL = "recipes/integrate-default.yaml";
|
|
27
28
|
|
|
@@ -43,6 +44,17 @@ function readLocalMeetSdkRemoteConfig(projectRoot: string): MeetSdkRemoteConfig
|
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
function resolveCachedRemoteConfigPath(params: {
|
|
48
|
+
env?: TopSdkApiEnv;
|
|
49
|
+
appId?: string;
|
|
50
|
+
channelType?: string;
|
|
51
|
+
}): string | undefined {
|
|
52
|
+
const appId = params.appId || process.env.TOPSDK_APP_ID || "";
|
|
53
|
+
const channelType = params.channelType || process.env.TOPSDK_CHANNEL_TYPE || "";
|
|
54
|
+
if (!appId || !channelType) return undefined;
|
|
55
|
+
return resolveRemoteConfigCachePath({ env: params.env ?? "prod", appId, channelType });
|
|
56
|
+
}
|
|
57
|
+
|
|
46
58
|
function ensureDefaultManifestPath(packageRoot: string): string {
|
|
47
59
|
const manifestPath = path.join(packageRoot, DEFAULT_MANIFEST_REL);
|
|
48
60
|
if (!fs.existsSync(manifestPath)) {
|
|
@@ -54,12 +66,13 @@ function ensureDefaultManifestPath(packageRoot: string): string {
|
|
|
54
66
|
function ensureSinglePlatformContext(
|
|
55
67
|
projectRoot: string,
|
|
56
68
|
packageRoot: string,
|
|
57
|
-
appTarget?: string
|
|
69
|
+
appTarget?: string,
|
|
70
|
+
remoteConfigPath?: string
|
|
58
71
|
): {
|
|
59
72
|
platform: DetectedPlatform;
|
|
60
73
|
ctx: ReturnType<typeof buildWorkspaceContext>;
|
|
61
74
|
} {
|
|
62
|
-
const detectedCtx = buildWorkspaceContext(projectRoot, packageRoot, { appTarget });
|
|
75
|
+
const detectedCtx = buildWorkspaceContext(projectRoot, packageRoot, { appTarget, remoteConfigPath });
|
|
63
76
|
const detected = detectSinglePlatform(detectedCtx);
|
|
64
77
|
if (!detected.ok) throw new Error(detected.error);
|
|
65
78
|
const platformCtx = platformContext(detectedCtx, detected.platform);
|
|
@@ -121,7 +134,6 @@ export async function meetgamesFetchConfig(params: {
|
|
|
121
134
|
warnings: string[];
|
|
122
135
|
}> {
|
|
123
136
|
const projectRoot = ensureProjectRoot(params.projectRoot);
|
|
124
|
-
const out = path.join(projectRoot, MEETSDK_REMOTE_CONFIG_FILENAME);
|
|
125
137
|
const localConfig = readLocalMeetSdkRemoteConfig(projectRoot);
|
|
126
138
|
|
|
127
139
|
const appId = params.appId || localConfig?.topsdk.appId || process.env.TOPSDK_APP_ID || "";
|
|
@@ -153,13 +165,23 @@ export async function meetgamesFetchConfig(params: {
|
|
|
153
165
|
}
|
|
154
166
|
warnings.push(...validation.warnings);
|
|
155
167
|
|
|
156
|
-
|
|
157
|
-
|
|
168
|
+
const written = writeRemoteConfigCache({
|
|
169
|
+
env,
|
|
170
|
+
appId,
|
|
171
|
+
channelType,
|
|
172
|
+
requestUrl: res.url,
|
|
173
|
+
rawText: res.text,
|
|
174
|
+
warnings,
|
|
175
|
+
});
|
|
176
|
+
return { outputPath: written.configPath, requestUrl: res.url, env, warnings };
|
|
158
177
|
}
|
|
159
178
|
|
|
160
179
|
export async function meetgamesIntegrate(params: {
|
|
161
180
|
projectRoot?: string;
|
|
162
181
|
appTarget?: string;
|
|
182
|
+
env?: TopSdkApiEnv;
|
|
183
|
+
appId?: string;
|
|
184
|
+
channelType?: string;
|
|
163
185
|
dryRun: boolean;
|
|
164
186
|
}): Promise<{
|
|
165
187
|
dryRun: boolean;
|
|
@@ -176,7 +198,8 @@ export async function meetgamesIntegrate(params: {
|
|
|
176
198
|
const { platform, ctx } = ensureSinglePlatformContext(
|
|
177
199
|
projectRoot,
|
|
178
200
|
packageRoot,
|
|
179
|
-
resolveAppTarget(params)
|
|
201
|
+
resolveAppTarget(params),
|
|
202
|
+
resolveCachedRemoteConfigPath(params)
|
|
180
203
|
);
|
|
181
204
|
const { report, patch, binaryCopies } = await runPipeline(ctx, manifestForPlatform(manifest, platform), { dryRun: params.dryRun });
|
|
182
205
|
return {
|
|
@@ -205,7 +228,7 @@ export async function meetgamesSetup(params: {
|
|
|
205
228
|
const projectRoot = ensureProjectRoot(params.projectRoot);
|
|
206
229
|
const packageRoot = resolvePackageRoot();
|
|
207
230
|
const appTarget = resolveAppTarget(params);
|
|
208
|
-
ensureSinglePlatformContext(projectRoot, packageRoot, appTarget);
|
|
231
|
+
const { platform } = ensureSinglePlatformContext(projectRoot, packageRoot, appTarget);
|
|
209
232
|
const fetch = await meetgamesFetchConfig({
|
|
210
233
|
projectRoot,
|
|
211
234
|
env: params.env,
|
|
@@ -213,9 +236,17 @@ export async function meetgamesSetup(params: {
|
|
|
213
236
|
appSecret: params.appSecret,
|
|
214
237
|
channelType: params.channelType,
|
|
215
238
|
});
|
|
239
|
+
if (platform === "ios") {
|
|
240
|
+
await downloadIosSdkToBundled(packageRoot, {
|
|
241
|
+
baseUrl: process.env.MEETGAMES_SDK_HOME_API_BASE_URL?.trim() || defaultSdkHomeApiBaseUrl,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
216
244
|
const integrate = await meetgamesIntegrate({
|
|
217
245
|
projectRoot,
|
|
218
246
|
appTarget,
|
|
247
|
+
env: params.env,
|
|
248
|
+
appId: params.appId,
|
|
249
|
+
channelType: params.channelType,
|
|
219
250
|
dryRun: params.dryRun,
|
|
220
251
|
});
|
|
221
252
|
return { fetch, integrate };
|
package/src/ops/handlers.ts
CHANGED
|
@@ -59,6 +59,18 @@ function moduleGradleRel(ctx: WorkspaceContext): string | null {
|
|
|
59
59
|
return null;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
function resolveRemoteConfigInput(ctx: WorkspaceContext, configFile: unknown): { abs: string; label: string } {
|
|
63
|
+
if (typeof configFile === "string" && configFile.trim()) {
|
|
64
|
+
const normalized = configFile.trim().replace(/\\/g, "/");
|
|
65
|
+
return {
|
|
66
|
+
abs: path.isAbsolute(normalized) ? normalized : path.join(ctx.projectRoot, normalized),
|
|
67
|
+
label: normalized,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const abs = ctx.remoteConfigPath ?? path.join(ctx.projectRoot, MEETSDK_REMOTE_CONFIG_FILENAME);
|
|
71
|
+
return { abs, label: abs };
|
|
72
|
+
}
|
|
73
|
+
|
|
62
74
|
export interface BinaryCopy {
|
|
63
75
|
fromAbs: string;
|
|
64
76
|
relTo: string;
|
|
@@ -80,23 +92,19 @@ export const opHandlers: Record<string, OpHandler> = {
|
|
|
80
92
|
*/
|
|
81
93
|
"gradle.applyMeetSdkRemoteConfig": async (ctx, store, args, _dry, _bc) => {
|
|
82
94
|
if (!ctx.android?.ok) return fail(["android application module not detected"]);
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
? args.configFile.trim().replace(/\\/g, "/")
|
|
86
|
-
: MEETSDK_REMOTE_CONFIG_FILENAME;
|
|
87
|
-
const abs = path.join(ctx.projectRoot, configRel);
|
|
88
|
-
if (!fs.existsSync(abs)) return fail([`meet sdk remote config not found: ${configRel}`]);
|
|
95
|
+
const config = resolveRemoteConfigInput(ctx, args.configFile);
|
|
96
|
+
if (!fs.existsSync(config.abs)) return fail([`meet sdk remote config not found: ${config.label}`]);
|
|
89
97
|
let raw: unknown;
|
|
90
98
|
try {
|
|
91
|
-
raw = JSON.parse(fs.readFileSync(abs, "utf8")) as unknown;
|
|
99
|
+
raw = JSON.parse(fs.readFileSync(config.abs, "utf8")) as unknown;
|
|
92
100
|
} catch {
|
|
93
|
-
return fail([`failed to parse JSON: ${
|
|
101
|
+
return fail([`failed to parse JSON: ${config.label}`]);
|
|
94
102
|
}
|
|
95
103
|
const parsed = tryParseAsMeetSdkRemoteConfig(raw);
|
|
96
|
-
if (!parsed) return fail([`not a meetsdk-remote-config document: ${
|
|
104
|
+
if (!parsed) return fail([`not a meetsdk-remote-config document: ${config.label}`]);
|
|
97
105
|
const v = validateMeetSdkRemoteConfig(parsed);
|
|
98
106
|
if (!v.ok) {
|
|
99
|
-
return fail([`meetsdk-remote-config validation failed (${
|
|
107
|
+
return fail([`meetsdk-remote-config validation failed (${config.label}): ${v.missing.join(", ")}`]);
|
|
100
108
|
}
|
|
101
109
|
const resolved = applyMeetSdkDefaultConfig(
|
|
102
110
|
parsed,
|
|
@@ -244,20 +252,16 @@ export const opHandlers: Record<string, OpHandler> = {
|
|
|
244
252
|
|
|
245
253
|
"files.downloadGoogleServicesJson": async (ctx, _store, args, dryRun, _bc) => {
|
|
246
254
|
if (!ctx.android?.ok) return fail(["android application module not detected"]);
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
? args.configFile.trim().replace(/\\/g, "/")
|
|
250
|
-
: MEETSDK_REMOTE_CONFIG_FILENAME;
|
|
251
|
-
const abs = path.join(ctx.projectRoot, configRel);
|
|
252
|
-
if (!fs.existsSync(abs)) return fail([`meet sdk remote config not found: ${configRel}`]);
|
|
255
|
+
const config = resolveRemoteConfigInput(ctx, args.configFile);
|
|
256
|
+
if (!fs.existsSync(config.abs)) return fail([`meet sdk remote config not found: ${config.label}`]);
|
|
253
257
|
let raw: unknown;
|
|
254
258
|
try {
|
|
255
|
-
raw = JSON.parse(fs.readFileSync(abs, "utf8")) as unknown;
|
|
259
|
+
raw = JSON.parse(fs.readFileSync(config.abs, "utf8")) as unknown;
|
|
256
260
|
} catch {
|
|
257
|
-
return fail([`failed to parse JSON: ${
|
|
261
|
+
return fail([`failed to parse JSON: ${config.label}`]);
|
|
258
262
|
}
|
|
259
263
|
const parsed = tryParseAsMeetSdkRemoteConfig(raw);
|
|
260
|
-
if (!parsed) return fail([`not a meetsdk-remote-config document: ${
|
|
264
|
+
if (!parsed) return fail([`not a meetsdk-remote-config document: ${config.label}`]);
|
|
261
265
|
const resolved = applyMeetSdkDefaultConfig(
|
|
262
266
|
parsed,
|
|
263
267
|
await loadMeetSdkDefaultConfigWithLatestAndroidVersion({
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { defaultBundledIosSdkRoot } from "../ios/sdkBundle.js";
|
|
5
4
|
import { syncMeetSdkIosVersionToConfig } from "../config/meetSdkIosConfig.js";
|
|
5
|
+
import { resolveIosSdkCacheLayout, withCacheLock, writeIosSdkCacheMetadata } from "../cache.js";
|
|
6
6
|
|
|
7
7
|
export const defaultSdkHomeApiBaseUrl = "https://business-api.meetgames.com";
|
|
8
8
|
export const DEFAULT_IOS_SDK_PLUGINS = ["guest", "facebook", "google", "apple", "apple_pay", "dataAppsFlyer"] as const;
|
|
@@ -36,7 +36,6 @@ export interface DownloadIosSdkOptions {
|
|
|
36
36
|
version?: string;
|
|
37
37
|
plugins?: readonly string[] | string;
|
|
38
38
|
packageType?: string;
|
|
39
|
-
outputDir?: string;
|
|
40
39
|
signal?: AbortSignal;
|
|
41
40
|
}
|
|
42
41
|
|
|
@@ -50,6 +49,7 @@ export interface DownloadIosSdkResult {
|
|
|
50
49
|
extractDir: string;
|
|
51
50
|
resolvedSdkRoot: string;
|
|
52
51
|
iosConfigPath: string;
|
|
52
|
+
cacheMetadataPath: string;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
function isRecord(value: unknown): value is JsonRecord {
|
|
@@ -247,11 +247,16 @@ export async function downloadIosSdkToBundled(
|
|
|
247
247
|
packageType,
|
|
248
248
|
signal: options.signal,
|
|
249
249
|
});
|
|
250
|
-
const
|
|
251
|
-
const
|
|
250
|
+
const cacheLayout = resolveIosSdkCacheLayout({ version, packageType, plugins });
|
|
251
|
+
const extractDir = cacheLayout.extractDir;
|
|
252
|
+
const zipPath = cacheLayout.zipPath;
|
|
252
253
|
|
|
253
|
-
|
|
254
|
-
|
|
254
|
+
const downloadAndExtract = async (): Promise<void> => {
|
|
255
|
+
await downloadBinaryFile(downloadResult.sdkZipUrl, zipPath, options.signal);
|
|
256
|
+
fs.rmSync(extractDir, { recursive: true, force: true });
|
|
257
|
+
await extractZip(zipPath, extractDir);
|
|
258
|
+
};
|
|
259
|
+
await withCacheLock(cacheLayout.lockDir, downloadAndExtract);
|
|
255
260
|
const iosConfigPath = syncMeetSdkIosVersionToConfig({
|
|
256
261
|
packageRoot,
|
|
257
262
|
version,
|
|
@@ -259,6 +264,21 @@ export async function downloadIosSdkToBundled(
|
|
|
259
264
|
packageType,
|
|
260
265
|
plugins,
|
|
261
266
|
});
|
|
267
|
+
const resolvedSdkRoot = resolveIosSdkRootFromDirectory(extractDir);
|
|
268
|
+
const cacheMetadataPath = cacheLayout.metadataPath;
|
|
269
|
+
writeIosSdkCacheMetadata({
|
|
270
|
+
metadataPath: cacheMetadataPath,
|
|
271
|
+
version,
|
|
272
|
+
date: versionResult.ios.date,
|
|
273
|
+
packageType,
|
|
274
|
+
plugins,
|
|
275
|
+
versionUrl: versionResult.url,
|
|
276
|
+
downloadApiUrl: downloadResult.url,
|
|
277
|
+
sdkZipUrl: downloadResult.sdkZipUrl,
|
|
278
|
+
zipPath,
|
|
279
|
+
extractDir,
|
|
280
|
+
resolvedSdkRoot,
|
|
281
|
+
});
|
|
262
282
|
|
|
263
283
|
return {
|
|
264
284
|
version,
|
|
@@ -268,7 +288,8 @@ export async function downloadIosSdkToBundled(
|
|
|
268
288
|
sdkZipUrl: downloadResult.sdkZipUrl,
|
|
269
289
|
zipPath,
|
|
270
290
|
extractDir,
|
|
271
|
-
resolvedSdkRoot
|
|
291
|
+
resolvedSdkRoot,
|
|
272
292
|
iosConfigPath,
|
|
293
|
+
cacheMetadataPath,
|
|
273
294
|
};
|
|
274
295
|
}
|
package/tests/doctor.test.ts
CHANGED
|
@@ -7,12 +7,14 @@ import { runDoctor } from "../src/core/doctor.js";
|
|
|
7
7
|
import { detectSinglePlatform, platformContext } from "../src/core/platform.js";
|
|
8
8
|
import { runPipeline } from "../src/core/pipeline.js";
|
|
9
9
|
import { buildWorkspaceContext } from "../src/core/workspace.js";
|
|
10
|
+
import { resolveIosSdkRootFromDirectory } from "../src/remote/sdkHomeDownload.js";
|
|
10
11
|
|
|
11
12
|
const pkgRoot = path.resolve(__dirname, "..");
|
|
12
13
|
const androidLatestRoot = path.join(pkgRoot, "fixtures", "android-test-project", "android-latest-project");
|
|
13
14
|
const iosProjectRoot = path.join(pkgRoot, "fixtures", "ios-test-project", "tooltest");
|
|
14
15
|
const iosRemoteConfigFixture = path.join(pkgRoot, "fixtures", "meetsdk-remote-config.ios-tooltest.json");
|
|
15
16
|
const hasIosProjectFixture = fs.existsSync(iosProjectRoot);
|
|
17
|
+
const fixtureIosSdkRoot = resolveIosSdkRootFromDirectory(path.join(pkgRoot, "fixtures", "ios-sdk", "topSDK-ios--V1.6.0.5"));
|
|
16
18
|
|
|
17
19
|
function copyIosProjectToTemp(): string {
|
|
18
20
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "meet-ios-doctor-"));
|
|
@@ -67,11 +69,11 @@ describe("doctor", () => {
|
|
|
67
69
|
const tmp = copyIosProjectToTemp();
|
|
68
70
|
try {
|
|
69
71
|
const manifest = loadManifestFile(path.join(pkgRoot, "recipes", "ios-default.yaml"));
|
|
70
|
-
const applyCtx = buildWorkspaceContext(tmp, pkgRoot);
|
|
72
|
+
const applyCtx = buildWorkspaceContext(tmp, pkgRoot, { iosSdkRoot: fixtureIosSdkRoot });
|
|
71
73
|
const { report: applyReport } = await runPipeline(applyCtx, manifest, { dryRun: false });
|
|
72
74
|
expect(applyReport.errors).toEqual([]);
|
|
73
75
|
|
|
74
|
-
const ctx = buildWorkspaceContext(tmp, pkgRoot);
|
|
76
|
+
const ctx = buildWorkspaceContext(tmp, pkgRoot, { iosSdkRoot: fixtureIosSdkRoot });
|
|
75
77
|
const detected = detectSinglePlatform(ctx);
|
|
76
78
|
expect(detected.ok && detected.platform).toBe("ios");
|
|
77
79
|
|
|
@@ -9,7 +9,7 @@ const here = path.dirname(fileURLToPath(import.meta.url));
|
|
|
9
9
|
const pkgRoot = path.resolve(here, "..");
|
|
10
10
|
const androidFixtureRoot = path.join(pkgRoot, "fixtures", "android-test-project");
|
|
11
11
|
|
|
12
|
-
function
|
|
12
|
+
function fixtureProjectRoot(...names: string[]): string {
|
|
13
13
|
for (const name of names) {
|
|
14
14
|
const candidate = path.join(androidFixtureRoot, name);
|
|
15
15
|
if (fs.existsSync(candidate)) return candidate;
|
|
@@ -39,7 +39,7 @@ function createAndroidAppModule(root: string, name: string, applicationId: strin
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
describe("fixture host trees", () => {
|
|
42
|
-
const powerRaidRoot =
|
|
42
|
+
const powerRaidRoot = fixtureProjectRoot("power-raid");
|
|
43
43
|
|
|
44
44
|
it("android-latest-project (plugins DSL) resolves application module :app", () => {
|
|
45
45
|
const root = path.join(androidFixtureRoot, "android-latest-project");
|
|
@@ -3,14 +3,19 @@ import path from "node:path";
|
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { describe, expect, it } from "vitest";
|
|
5
5
|
import { resolveIosSdkRoot } from "../src/ios/sdkBundle.js";
|
|
6
|
+
import { MEET_SDK_TOOL_CACHE_ROOT } from "../src/cache.js";
|
|
6
7
|
|
|
7
8
|
const pkgRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
8
9
|
|
|
9
10
|
describe("resolveIosSdkRoot", () => {
|
|
10
|
-
it("
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
it("uses only the iOS SDK cache", () => {
|
|
12
|
+
try {
|
|
13
|
+
const root = resolveIosSdkRoot(pkgRoot);
|
|
14
|
+
expect(root).toContain(`${path.sep}.cache${path.sep}meet-sdk-tool${path.sep}sdk${path.sep}ios`);
|
|
15
|
+
expect(fs.existsSync(path.join(root, "sdk", "topsdkConfig.t.json"))).toBe(true);
|
|
16
|
+
expect(fs.existsSync(path.join(root, "plugins"))).toBe(true);
|
|
17
|
+
} catch (e) {
|
|
18
|
+
expect(e instanceof Error ? e.message : String(e)).toContain(path.join(MEET_SDK_TOOL_CACHE_ROOT, "sdk", "ios"));
|
|
19
|
+
}
|
|
15
20
|
});
|
|
16
21
|
});
|
package/tests/mcp.e2e.ts
CHANGED
|
@@ -153,7 +153,6 @@ describe("meetgames MCP stdio server", () => {
|
|
|
153
153
|
expect(dryRun.dryRun).toBe(true);
|
|
154
154
|
expect(dryRun.hasErrors).toBe(false);
|
|
155
155
|
expect(String(dryRun.patch)).toContain("TOPSDK AUTO");
|
|
156
|
-
expect(fs.existsSync(path.join(projectRoot, "vendor", "meet-integrate", "sample.txt"))).toBe(false);
|
|
157
156
|
});
|
|
158
157
|
|
|
159
158
|
it("runs fetch-config and setup dry-run through stdio", async () => {
|
|
@@ -175,9 +174,8 @@ describe("meetgames MCP stdio server", () => {
|
|
|
175
174
|
);
|
|
176
175
|
expect(fetched.env).toBe("test");
|
|
177
176
|
expect(String(fetched.requestUrl)).toContain("/console/openSDK/downloadSDKConfig");
|
|
178
|
-
expect(fs.
|
|
179
|
-
|
|
180
|
-
);
|
|
177
|
+
expect(fs.existsSync(path.join(projectRoot, "meetsdk-remote-config.json"))).toBe(false);
|
|
178
|
+
expect(fs.readFileSync(String(fetched.outputPath), "utf8")).toBe(fs.readFileSync(remoteConfigFixture, "utf8"));
|
|
181
179
|
|
|
182
180
|
const setup = structured(
|
|
183
181
|
await client.callTool({
|
|
@@ -211,7 +209,6 @@ describe("meetgames MCP stdio server", () => {
|
|
|
211
209
|
expect(applied.dryRun).toBe(false);
|
|
212
210
|
expect((applied.report as { errors?: string[] }).errors).toEqual([]);
|
|
213
211
|
expect(applied.hasErrors).toBe(false);
|
|
214
|
-
expect(fs.existsSync(path.join(projectRoot, "vendor", "meet-integrate", "sample.txt"))).toBe(true);
|
|
215
212
|
expect(fs.readFileSync(path.join(projectRoot, "app", "build.gradle"), "utf8")).toContain("TOPSDK AUTO");
|
|
216
213
|
});
|
|
217
214
|
});
|
|
@@ -236,6 +236,31 @@ describe("meetSdkRemoteConfig", () => {
|
|
|
236
236
|
});
|
|
237
237
|
});
|
|
238
238
|
|
|
239
|
+
it("parses Adjust eventUrl under analytics.adjust", () => {
|
|
240
|
+
const parsed = tryParseAsMeetSdkRemoteConfig({
|
|
241
|
+
packageName: "com.example",
|
|
242
|
+
channel: "APPLE",
|
|
243
|
+
devicePlatform: "ios",
|
|
244
|
+
topsdk: { appId: "1", appSecret: "s" },
|
|
245
|
+
sdkModules: {
|
|
246
|
+
login: {},
|
|
247
|
+
payment: {},
|
|
248
|
+
analytics: {
|
|
249
|
+
adjust: {
|
|
250
|
+
appCode: "adjust-app-code",
|
|
251
|
+
eventUrl: "https://example.invalid/events.json",
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
expect(parsed?.sdkModules.analytics.adjust).toMatchObject({
|
|
258
|
+
appId: "adjust-app-code",
|
|
259
|
+
eventUrl: "https://example.invalid/events.json",
|
|
260
|
+
enableSandbox: false,
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
239
264
|
it("maps TWITTER / LINE / KAKAO from channelAuthConfig", () => {
|
|
240
265
|
const body = {
|
|
241
266
|
code: 200,
|