@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.
Files changed (228) hide show
  1. package/.agents/skills/meet-sdk-regression/SKILL.md +93 -0
  2. package/.cursor/mcp.example.json +16 -0
  3. package/.cursor/mcp.json +11 -0
  4. package/.cursor/skills/meetgames-mcp/SKILL.md +48 -0
  5. package/.vite/vitest/results.json +1 -0
  6. package/README.md +36 -13
  7. package/{meetsdk-android.json → config/meetsdk-android.json} +2 -1
  8. package/config/meetsdk-ios.json +15 -0
  9. package/dist/android/adapter.d.ts.map +1 -1
  10. package/dist/android/adapter.js +2 -2
  11. package/dist/android/adapter.js.map +1 -1
  12. package/dist/android/detect.d.ts +2 -2
  13. package/dist/android/detect.d.ts.map +1 -1
  14. package/dist/android/detect.js +36 -8
  15. package/dist/android/detect.js.map +1 -1
  16. package/dist/cache.d.ts +44 -0
  17. package/dist/cache.d.ts.map +1 -0
  18. package/dist/cache.js +101 -0
  19. package/dist/cache.js.map +1 -0
  20. package/dist/cli.d.ts.map +1 -1
  21. package/dist/cli.js +181 -49
  22. package/dist/cli.js.map +1 -1
  23. package/dist/config/meetSdkDefaultConfig.d.ts +19 -2
  24. package/dist/config/meetSdkDefaultConfig.d.ts.map +1 -1
  25. package/dist/config/meetSdkDefaultConfig.js +69 -6
  26. package/dist/config/meetSdkDefaultConfig.js.map +1 -1
  27. package/dist/config/meetSdkIosConfig.d.ts +21 -0
  28. package/dist/config/meetSdkIosConfig.d.ts.map +1 -0
  29. package/dist/config/meetSdkIosConfig.js +68 -0
  30. package/dist/config/meetSdkIosConfig.js.map +1 -0
  31. package/dist/config/meetSdkRemoteConfig.d.ts +19 -1
  32. package/dist/config/meetSdkRemoteConfig.d.ts.map +1 -1
  33. package/dist/config/meetSdkRemoteConfig.js +64 -25
  34. package/dist/config/meetSdkRemoteConfig.js.map +1 -1
  35. package/dist/contracts/types.d.ts +27 -6
  36. package/dist/contracts/types.d.ts.map +1 -1
  37. package/dist/core/doctor.d.ts +17 -0
  38. package/dist/core/doctor.d.ts.map +1 -0
  39. package/dist/core/doctor.js +444 -0
  40. package/dist/core/doctor.js.map +1 -0
  41. package/dist/core/pipeline.d.ts.map +1 -1
  42. package/dist/core/pipeline.js +0 -15
  43. package/dist/core/pipeline.js.map +1 -1
  44. package/dist/core/platform.d.ts +12 -0
  45. package/dist/core/platform.d.ts.map +1 -0
  46. package/dist/core/platform.js +40 -0
  47. package/dist/core/platform.js.map +1 -0
  48. package/dist/core/previewPatches.d.ts +1 -1
  49. package/dist/core/previewPatches.js +2 -2
  50. package/dist/core/previewPatches.js.map +1 -1
  51. package/dist/core/reporter.js +1 -1
  52. package/dist/core/reporter.js.map +1 -1
  53. package/dist/core/workspace.d.ts +2 -2
  54. package/dist/core/workspace.d.ts.map +1 -1
  55. package/dist/core/workspace.js +6 -5
  56. package/dist/core/workspace.js.map +1 -1
  57. package/dist/index.d.ts +4 -1
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +4 -1
  60. package/dist/index.js.map +1 -1
  61. package/dist/ios/channelConfig.d.ts +1 -0
  62. package/dist/ios/channelConfig.d.ts.map +1 -1
  63. package/dist/ios/channelConfig.js +82 -0
  64. package/dist/ios/channelConfig.js.map +1 -1
  65. package/dist/ios/codeUtils.d.ts +1 -0
  66. package/dist/ios/codeUtils.d.ts.map +1 -1
  67. package/dist/ios/codeUtils.js +11 -2
  68. package/dist/ios/codeUtils.js.map +1 -1
  69. package/dist/ios/detect.d.ts +2 -2
  70. package/dist/ios/detect.d.ts.map +1 -1
  71. package/dist/ios/detect.js +49 -10
  72. package/dist/ios/detect.js.map +1 -1
  73. package/dist/ios/entitlements.d.ts +4 -0
  74. package/dist/ios/entitlements.d.ts.map +1 -0
  75. package/dist/ios/entitlements.js +53 -0
  76. package/dist/ios/entitlements.js.map +1 -0
  77. package/dist/ios/fileManager.d.ts.map +1 -1
  78. package/dist/ios/fileManager.js +3 -2
  79. package/dist/ios/fileManager.js.map +1 -1
  80. package/dist/ios/infoPlist.d.ts +1 -1
  81. package/dist/ios/infoPlist.d.ts.map +1 -1
  82. package/dist/ios/infoPlist.js.map +1 -1
  83. package/dist/ios/integrate.d.ts.map +1 -1
  84. package/dist/ios/integrate.js +214 -39
  85. package/dist/ios/integrate.js.map +1 -1
  86. package/dist/ios/pbxprojEditor.d.ts +2 -0
  87. package/dist/ios/pbxprojEditor.d.ts.map +1 -1
  88. package/dist/ios/pbxprojEditor.js +250 -6
  89. package/dist/ios/pbxprojEditor.js.map +1 -1
  90. package/dist/ios/pluginConfig.d.ts +1 -0
  91. package/dist/ios/pluginConfig.d.ts.map +1 -1
  92. package/dist/ios/pluginConfig.js +36 -4
  93. package/dist/ios/pluginConfig.js.map +1 -1
  94. package/dist/ios/sdkBundle.d.ts +1 -6
  95. package/dist/ios/sdkBundle.d.ts.map +1 -1
  96. package/dist/ios/sdkBundle.js +47 -17
  97. package/dist/ios/sdkBundle.js.map +1 -1
  98. package/dist/ios/template.d.ts +1 -0
  99. package/dist/ios/template.d.ts.map +1 -1
  100. package/dist/ios/template.js +14 -1
  101. package/dist/ios/template.js.map +1 -1
  102. package/dist/ios/types.d.ts +2 -2
  103. package/dist/ios/types.d.ts.map +1 -1
  104. package/dist/mcp/server.d.ts.map +1 -1
  105. package/dist/mcp/server.js +22 -15
  106. package/dist/mcp/server.js.map +1 -1
  107. package/dist/mcp/service.d.ts +11 -6
  108. package/dist/mcp/service.d.ts.map +1 -1
  109. package/dist/mcp/service.js +61 -18
  110. package/dist/mcp/service.js.map +1 -1
  111. package/dist/ops/handlers.d.ts.map +1 -1
  112. package/dist/ops/handlers.js +34 -23
  113. package/dist/ops/handlers.js.map +1 -1
  114. package/dist/remote/sdkHomeDownload.d.ts +65 -0
  115. package/dist/remote/sdkHomeDownload.d.ts.map +1 -0
  116. package/dist/remote/sdkHomeDownload.js +229 -0
  117. package/dist/remote/sdkHomeDownload.js.map +1 -0
  118. package/dist/remote/topsdkDownloadSdkConfig.d.ts.map +1 -1
  119. package/dist/remote/topsdkDownloadSdkConfig.js +11 -1
  120. package/dist/remote/topsdkDownloadSdkConfig.js.map +1 -1
  121. package/dist/shared/errors.d.ts +7 -0
  122. package/dist/shared/errors.d.ts.map +1 -0
  123. package/dist/shared/errors.js +16 -0
  124. package/dist/shared/errors.js.map +1 -0
  125. package/docs/API.md +246 -32
  126. package/docs/CLI.md +291 -0
  127. package/docs/INTEGRATION.md +116 -0
  128. package/docs/MCP.md +86 -0
  129. package/docs/README.md +18 -10
  130. package/docs/{api → archive/api}/downloadSDKConfig.md +9 -7
  131. package/docs/{api → archive/api}/getChannelConfig-meetgames.md +2 -2
  132. package/docs/archive/ios-migration.md +2139 -0
  133. 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
  134. package/docs/{ → archive/product/}/351/234/200/346/261/202/346/226/207/346/241/243.md +16 -15
  135. package/package.json +7 -36
  136. package/recipes/android-default.yaml +0 -5
  137. package/recipes/integrate-default.yaml +0 -5
  138. package/src/android/adapter.ts +9 -0
  139. package/src/android/assembleIntegrationJson.ts +33 -0
  140. package/src/android/detect.ts +132 -0
  141. package/src/android/downloadGoogleServicesJson.ts +56 -0
  142. package/src/android/gradle.ts +116 -0
  143. package/src/android/manifest.ts +50 -0
  144. package/src/android/meetSdkRemoteGradle.ts +837 -0
  145. package/src/cache.ts +164 -0
  146. package/src/cli.ts +496 -0
  147. package/src/config/fetchConfigWrite.ts +30 -0
  148. package/src/config/loadAndroidIntegration.ts +41 -0
  149. package/src/config/loadManifest.ts +40 -0
  150. package/src/config/meetSdkDefaultConfig.ts +100 -0
  151. package/src/config/meetSdkIosConfig.ts +89 -0
  152. package/src/config/meetSdkRemoteConfig.ts +1215 -0
  153. package/src/config/topsdkFeatureModules.ts +92 -0
  154. package/src/contracts/types.ts +129 -0
  155. package/src/core/doctor.ts +485 -0
  156. package/src/core/patch.ts +64 -0
  157. package/src/core/pipeline.ts +107 -0
  158. package/src/core/platform.ts +47 -0
  159. package/src/core/previewPatches.ts +23 -0
  160. package/src/core/reporter.ts +24 -0
  161. package/src/core/workspace.ts +31 -0
  162. package/src/entry.ts +7 -0
  163. package/src/index.ts +140 -0
  164. package/src/ios/channelConfig.ts +128 -0
  165. package/src/ios/codeUtils.ts +160 -0
  166. package/src/ios/detect.ts +105 -0
  167. package/src/ios/entitlements.ts +61 -0
  168. package/src/ios/fileManager.ts +48 -0
  169. package/src/ios/infoPlist.ts +55 -0
  170. package/src/ios/integrate.ts +517 -0
  171. package/src/ios/pbxprojEditor.ts +450 -0
  172. package/src/ios/pluginConfig.ts +97 -0
  173. package/src/ios/reserved.ts +8 -0
  174. package/src/ios/sdkBundle.ts +59 -0
  175. package/src/ios/template.ts +36 -0
  176. package/src/ios/types.ts +65 -0
  177. package/src/mcp/server.ts +176 -0
  178. package/src/mcp/service.ts +253 -0
  179. package/src/mcp-entry.ts +7 -0
  180. package/src/ops/fileStore.ts +56 -0
  181. package/src/ops/handlers.ts +308 -0
  182. package/src/remote/fetchJson.ts +22 -0
  183. package/src/remote/sdkHomeDownload.ts +295 -0
  184. package/src/remote/topsdkDownloadSdkConfig.ts +93 -0
  185. package/src/remote/topsdkGetSdkConfig.ts +122 -0
  186. package/src/remote/topsdkSign.ts +10 -0
  187. package/src/shared/errors.ts +16 -0
  188. package/tests/assemble.test.ts +12 -0
  189. package/tests/doctor.test.ts +91 -0
  190. package/tests/downloadGoogleServicesJson.test.ts +47 -0
  191. package/tests/fetch-remote.test.ts +23 -0
  192. package/tests/fetchConfigOverrides.test.ts +28 -0
  193. package/tests/fetchConfigWrite.test.ts +54 -0
  194. package/tests/fixtures-hosts.test.ts +78 -0
  195. package/tests/gradle.test.ts +33 -0
  196. package/tests/integration-json.test.ts +29 -0
  197. package/tests/ios.codeUtils.test.ts +23 -0
  198. package/tests/ios.sdkBundle.test.ts +21 -0
  199. package/tests/loadManifest.test.ts +15 -0
  200. package/tests/manifest-xml.test.ts +30 -0
  201. package/tests/mcp.e2e.ts +214 -0
  202. package/tests/mcp.service.test.ts +53 -0
  203. package/tests/meetSdkRemoteConfig.test.ts +481 -0
  204. package/tests/meetSdkRemoteGradle.test.ts +414 -0
  205. package/tests/pipeline.android.test.ts +95 -0
  206. package/tests/pipeline.integration-json.test.ts +58 -0
  207. package/tests/pipeline.ios.test.ts +392 -0
  208. package/tests/pipeline.preview.patch.test.ts +85 -0
  209. package/tests/platformSelection.test.ts +77 -0
  210. package/tests/sdkHomeDownload.test.ts +124 -0
  211. package/tests/sdkVersionConfig.test.ts +131 -0
  212. package/tests/topsdk.test.ts +53 -0
  213. package/tests/topsdkDownloadSdkConfig.test.ts +81 -0
  214. package/tests/topsdkFeatureModules.test.ts +116 -0
  215. package/tsconfig.json +19 -0
  216. package/vitest.config.ts +9 -0
  217. package/vitest.mcp.config.ts +11 -0
  218. package/bundled/android/sample.txt +0 -1
  219. package/docs/ANDROID.md +0 -133
  220. package/docs/CURSOR-MCP-SETUP.md +0 -72
  221. package/docs/MCP-SKILL.md +0 -63
  222. package/fixtures/api-samples/getChannelConfig-meetgames.sample.json +0 -123
  223. package/fixtures/meetsdk-remote-config.download-shape.json +0 -20
  224. package/fixtures/meetsdk-remote-config.mock.json +0 -69
  225. package/fixtures/recipes/android-default.fixture.yaml +0 -15
  226. package/fixtures/recipes/android-integration.fixture.json +0 -29
  227. package/fixtures/topsdk-config-reference.json +0 -39
  228. /package/docs/{api → archive/api}/getSDKConfig.md +0 -0
@@ -0,0 +1,41 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { createRequire } from "node:module";
4
+ import { fileURLToPath } from "node:url";
5
+ import type { ErrorObject } from "ajv";
6
+ import type { AndroidIntegrationDocument } from "../contracts/types.js";
7
+
8
+ const require = createRequire(import.meta.url);
9
+ const Ajv: typeof import("ajv").default = require("ajv") as typeof import("ajv").default;
10
+ const addFormats = require("ajv-formats") as (ajv: import("ajv").default) => import("ajv").default;
11
+
12
+ const ajv = new Ajv({ allErrors: true, strict: true });
13
+ addFormats(ajv);
14
+
15
+ let validateCached: ReturnType<typeof ajv.compile<AndroidIntegrationDocument>> | undefined;
16
+
17
+ function getValidator() {
18
+ if (validateCached) return validateCached;
19
+ const here = path.dirname(fileURLToPath(import.meta.url));
20
+ const schemaPath = path.join(here, "..", "..", "schema", "android-integration.schema.json");
21
+ const raw = JSON.parse(fs.readFileSync(schemaPath, "utf8")) as object;
22
+ validateCached = ajv.compile<AndroidIntegrationDocument>(raw);
23
+ return validateCached;
24
+ }
25
+
26
+ export function parseAndroidIntegrationJson(data: unknown): AndroidIntegrationDocument {
27
+ const validate = getValidator();
28
+ if (!validate(data)) {
29
+ const msg =
30
+ validate.errors?.map((e: ErrorObject) => `${e.instancePath} ${e.message}`).join("; ") ||
31
+ "invalid android integration json";
32
+ throw new Error(`Android integration validation failed: ${msg}`);
33
+ }
34
+ return data as AndroidIntegrationDocument;
35
+ }
36
+
37
+ export function loadAndroidIntegrationFile(filePath: string): AndroidIntegrationDocument {
38
+ const text = fs.readFileSync(filePath, "utf8");
39
+ const data: unknown = JSON.parse(text);
40
+ return parseAndroidIntegrationJson(data);
41
+ }
@@ -0,0 +1,40 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { createRequire } from "node:module";
4
+ import { fileURLToPath } from "node:url";
5
+ import type { ErrorObject } from "ajv";
6
+ import yaml from "js-yaml";
7
+ import type { Manifest } from "../contracts/types.js";
8
+
9
+ const require = createRequire(import.meta.url);
10
+ const Ajv: typeof import("ajv").default = require("ajv") as typeof import("ajv").default;
11
+ const addFormats = require("ajv-formats") as (ajv: import("ajv").default) => import("ajv").default;
12
+
13
+ const ajv = new Ajv({ allErrors: true, strict: true });
14
+ addFormats(ajv);
15
+
16
+ let validateCached: ReturnType<typeof ajv.compile<Manifest>> | undefined;
17
+
18
+ function getValidator() {
19
+ if (validateCached) return validateCached;
20
+ const here = path.dirname(fileURLToPath(import.meta.url));
21
+ const schemaPath = path.join(here, "..", "..", "schema", "manifest.schema.json");
22
+ const raw = JSON.parse(fs.readFileSync(schemaPath, "utf8")) as object;
23
+ validateCached = ajv.compile<Manifest>(raw);
24
+ return validateCached;
25
+ }
26
+
27
+ export function loadManifestFile(filePath: string): Manifest {
28
+ const text = fs.readFileSync(filePath, "utf8");
29
+ const ext = path.extname(filePath).toLowerCase();
30
+ const data: unknown =
31
+ ext === ".yaml" || ext === ".yml" ? yaml.load(text) : JSON.parse(text);
32
+ const validate = getValidator();
33
+ if (!validate(data)) {
34
+ const msg =
35
+ validate.errors?.map((e: ErrorObject) => `${e.instancePath} ${e.message}`).join("; ") ||
36
+ "invalid manifest";
37
+ throw new Error(`Manifest validation failed: ${msg}`);
38
+ }
39
+ return data as Manifest;
40
+ }
@@ -0,0 +1,100 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { tryParseAsMeetSdkDefaultConfig, type MeetSdkDefaultConfig } from "./meetSdkRemoteConfig.js";
5
+ import { defaultSdkHomeApiBaseUrl, fetchSdkHomeVersions, type SdkHomePlatformVersion } from "../remote/sdkHomeDownload.js";
6
+
7
+ /** Built-in Android SDK defaults (repos and per-plugin dependencies). */
8
+ export const MEETSDK_ANDROID_DEFAULTS_FILENAME = "meetsdk-android.json";
9
+ const MEETSDK_CONFIG_DIR = "config";
10
+
11
+ const defaultConfigPath = fileURLToPath(
12
+ new URL(`../../${MEETSDK_CONFIG_DIR}/${MEETSDK_ANDROID_DEFAULTS_FILENAME}`, import.meta.url)
13
+ );
14
+
15
+ export function resolveMeetSdkAndroidConfigPath(packageRoot?: string): string {
16
+ return packageRoot ? path.join(packageRoot, MEETSDK_CONFIG_DIR, MEETSDK_ANDROID_DEFAULTS_FILENAME) : defaultConfigPath;
17
+ }
18
+
19
+ export function loadBuiltInMeetSdkDefaultConfig(options: { packageRoot?: string } = {}): MeetSdkDefaultConfig {
20
+ const configPath = resolveMeetSdkAndroidConfigPath(options.packageRoot);
21
+ if (!fs.existsSync(configPath)) {
22
+ throw new Error(
23
+ `built-in ${MEETSDK_ANDROID_DEFAULTS_FILENAME} not found at ${configPath}; reinstall @leonxin/meetgames or run from a complete package install`
24
+ );
25
+ }
26
+ const raw = JSON.parse(fs.readFileSync(configPath, "utf8")) as unknown;
27
+ const parsed = tryParseAsMeetSdkDefaultConfig(raw);
28
+ if (!parsed) {
29
+ throw new Error(`built-in ${MEETSDK_ANDROID_DEFAULTS_FILENAME} is not a valid MeetSdk default config`);
30
+ }
31
+ return parsed;
32
+ }
33
+
34
+ function cloneDefaultConfig(value: MeetSdkDefaultConfig): MeetSdkDefaultConfig {
35
+ return JSON.parse(JSON.stringify(value)) as MeetSdkDefaultConfig;
36
+ }
37
+
38
+ function resolveSdkHomeApiBaseUrl(baseUrl?: string): string {
39
+ return baseUrl || process.env.MEETGAMES_SDK_HOME_API_BASE_URL?.trim() || defaultSdkHomeApiBaseUrl;
40
+ }
41
+
42
+ const latestAndroidVersionCache = new Map<string, Promise<SdkHomePlatformVersion>>();
43
+
44
+ async function fetchLatestAndroidSdkVersion(baseUrl?: string): Promise<SdkHomePlatformVersion> {
45
+ const resolvedBaseUrl = resolveSdkHomeApiBaseUrl(baseUrl);
46
+ let cached = latestAndroidVersionCache.get(resolvedBaseUrl);
47
+ if (!cached) {
48
+ cached = fetchSdkHomeVersions({ baseUrl: resolvedBaseUrl }).then(({ versions }) => versions.android);
49
+ latestAndroidVersionCache.set(resolvedBaseUrl, cached);
50
+ }
51
+ return cached;
52
+ }
53
+
54
+ export function syncMeetSdkAndroidVersionToConfig(params: {
55
+ version: string;
56
+ date?: string;
57
+ packageRoot?: string;
58
+ }): string {
59
+ const version = params.version.trim();
60
+ if (!version) throw new Error("Android SDK version is empty");
61
+
62
+ const configPath = resolveMeetSdkAndroidConfigPath(params.packageRoot);
63
+ if (!fs.existsSync(configPath)) {
64
+ throw new Error(`built-in ${MEETSDK_ANDROID_DEFAULTS_FILENAME} not found at ${configPath}`);
65
+ }
66
+ const raw = JSON.parse(fs.readFileSync(configPath, "utf8")) as unknown;
67
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
68
+ throw new Error(`built-in ${MEETSDK_ANDROID_DEFAULTS_FILENAME} is not a JSON object`);
69
+ }
70
+ const record = raw as Record<string, unknown>;
71
+ if (typeof record.topsdk !== "object" || record.topsdk === null || Array.isArray(record.topsdk)) {
72
+ throw new Error(`built-in ${MEETSDK_ANDROID_DEFAULTS_FILENAME} does not contain topsdk object`);
73
+ }
74
+ const topsdk = record.topsdk as Record<string, unknown>;
75
+ topsdk.version = version;
76
+ if (params.date?.trim()) topsdk.date = params.date.trim();
77
+ fs.writeFileSync(configPath, `${JSON.stringify(record, null, 2)}\n`, "utf8");
78
+ return configPath;
79
+ }
80
+
81
+ /**
82
+ * Built-in Android SDK defaults with the SDK version resolved at runtime from sdk-home.
83
+ * The version is also persisted to `config/meetsdk-android.json` so the package config
84
+ * reflects the latest SDK version discovered from the download center.
85
+ */
86
+ export async function loadMeetSdkDefaultConfigWithLatestAndroidVersion(options: {
87
+ sdkHomeApiBaseUrl?: string;
88
+ packageRoot?: string;
89
+ } = {}): Promise<MeetSdkDefaultConfig> {
90
+ const defaults = cloneDefaultConfig(loadBuiltInMeetSdkDefaultConfig({ packageRoot: options.packageRoot }));
91
+ const latest = await fetchLatestAndroidSdkVersion(options.sdkHomeApiBaseUrl);
92
+ syncMeetSdkAndroidVersionToConfig({
93
+ version: latest.ver,
94
+ date: latest.date,
95
+ packageRoot: options.packageRoot,
96
+ });
97
+ defaults.topsdk.version = latest.ver;
98
+ defaults.topsdk.date = latest.date;
99
+ return defaults;
100
+ }
@@ -0,0 +1,89 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ export const MEETSDK_IOS_CONFIG_FILENAME = "meetsdk-ios.json";
5
+ const MEETSDK_CONFIG_DIR = "config";
6
+
7
+ export interface MeetSdkIosConfig {
8
+ topsdk: {
9
+ version: string;
10
+ date?: string;
11
+ packageType?: string;
12
+ plugins?: string[];
13
+ };
14
+ }
15
+
16
+ function isRecord(value: unknown): value is Record<string, unknown> {
17
+ return typeof value === "object" && value !== null && !Array.isArray(value);
18
+ }
19
+
20
+ function str(value: unknown): string {
21
+ return typeof value === "string" ? value.trim() : "";
22
+ }
23
+
24
+ function normalizePlugins(value: unknown): string[] | undefined {
25
+ if (!Array.isArray(value)) return undefined;
26
+ const plugins = value.map((x) => String(x).trim()).filter(Boolean);
27
+ return plugins.length ? plugins : undefined;
28
+ }
29
+
30
+ export function resolveMeetSdkIosConfigPath(packageRoot: string): string {
31
+ return path.join(packageRoot, MEETSDK_CONFIG_DIR, MEETSDK_IOS_CONFIG_FILENAME);
32
+ }
33
+
34
+ export function tryParseAsMeetSdkIosConfig(raw: unknown): MeetSdkIosConfig | null {
35
+ if (!isRecord(raw)) return null;
36
+ const topsdk = isRecord(raw.topsdk) ? raw.topsdk : {};
37
+ return {
38
+ topsdk: {
39
+ version: str(topsdk.version),
40
+ date: str(topsdk.date) || undefined,
41
+ packageType: str(topsdk.packageType) || undefined,
42
+ plugins: normalizePlugins(topsdk.plugins),
43
+ },
44
+ };
45
+ }
46
+
47
+ export function loadMeetSdkIosConfig(packageRoot: string): MeetSdkIosConfig {
48
+ const configPath = resolveMeetSdkIosConfigPath(packageRoot);
49
+ if (!fs.existsSync(configPath)) {
50
+ return { topsdk: { version: "" } };
51
+ }
52
+ const parsed = tryParseAsMeetSdkIosConfig(JSON.parse(fs.readFileSync(configPath, "utf8")) as unknown);
53
+ if (!parsed) {
54
+ throw new Error(`${MEETSDK_IOS_CONFIG_FILENAME} is not a valid MeetSdk iOS config`);
55
+ }
56
+ return parsed;
57
+ }
58
+
59
+ export function writeMeetSdkIosConfig(packageRoot: string, config: MeetSdkIosConfig): string {
60
+ const configPath = resolveMeetSdkIosConfigPath(packageRoot);
61
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
62
+ fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf8");
63
+ return configPath;
64
+ }
65
+
66
+ export function syncMeetSdkIosVersionToConfig(params: {
67
+ packageRoot: string;
68
+ version: string;
69
+ date?: string;
70
+ packageType?: string;
71
+ plugins?: readonly string[];
72
+ }): string {
73
+ const version = params.version.trim();
74
+ if (!version) throw new Error("iOS SDK version is empty");
75
+
76
+ const current = loadMeetSdkIosConfig(params.packageRoot);
77
+ const nextDate = params.date === undefined ? current.topsdk.date : params.date.trim() || undefined;
78
+ const next: MeetSdkIosConfig = {
79
+ ...current,
80
+ topsdk: {
81
+ ...current.topsdk,
82
+ version,
83
+ date: nextDate,
84
+ packageType: params.packageType?.trim() || current.topsdk.packageType,
85
+ plugins: params.plugins?.map((x) => x.trim()).filter(Boolean) || current.topsdk.plugins,
86
+ },
87
+ };
88
+ return writeMeetSdkIosConfig(params.packageRoot, next);
89
+ }