@leonxin/meetgames 0.1.8 → 0.1.11

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 (285) 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 +31 -8
  7. package/dist/aab-converter/aab-entry.d.ts +3 -0
  8. package/dist/aab-converter/aab-entry.d.ts.map +1 -0
  9. package/dist/aab-converter/aab-entry.js +49 -0
  10. package/dist/aab-converter/aab-entry.js.map +1 -0
  11. package/dist/aab-converter/apksExtractor.d.ts +2 -0
  12. package/dist/aab-converter/apksExtractor.d.ts.map +1 -0
  13. package/dist/aab-converter/apksExtractor.js +108 -0
  14. package/dist/aab-converter/apksExtractor.js.map +1 -0
  15. package/dist/aab-converter/bundletoolRunner.d.ts +15 -0
  16. package/dist/aab-converter/bundletoolRunner.d.ts.map +1 -0
  17. package/dist/aab-converter/bundletoolRunner.js +46 -0
  18. package/dist/aab-converter/bundletoolRunner.js.map +1 -0
  19. package/dist/aab-converter/cliArgs.d.ts +27 -0
  20. package/dist/aab-converter/cliArgs.d.ts.map +1 -0
  21. package/dist/aab-converter/cliArgs.js +170 -0
  22. package/dist/aab-converter/cliArgs.js.map +1 -0
  23. package/dist/aab-converter/convertAabToApk.d.ts +7 -0
  24. package/dist/aab-converter/convertAabToApk.d.ts.map +1 -0
  25. package/dist/aab-converter/convertAabToApk.js +69 -0
  26. package/dist/aab-converter/convertAabToApk.js.map +1 -0
  27. package/dist/aab-converter/resourcePaths.d.ts +4 -0
  28. package/dist/aab-converter/resourcePaths.d.ts.map +1 -0
  29. package/dist/aab-converter/resourcePaths.js +42 -0
  30. package/dist/aab-converter/resourcePaths.js.map +1 -0
  31. package/dist/aab-converter/signingOptions.d.ts +9 -0
  32. package/dist/aab-converter/signingOptions.d.ts.map +1 -0
  33. package/dist/aab-converter/signingOptions.js +21 -0
  34. package/dist/aab-converter/signingOptions.js.map +1 -0
  35. package/dist/aab-converter/types.d.ts +24 -0
  36. package/dist/aab-converter/types.d.ts.map +1 -0
  37. package/dist/aab-converter/types.js +2 -0
  38. package/dist/aab-converter/types.js.map +1 -0
  39. package/dist/android/adapter.d.ts.map +1 -1
  40. package/dist/android/adapter.js +2 -2
  41. package/dist/android/adapter.js.map +1 -1
  42. package/dist/android/detect.d.ts +2 -2
  43. package/dist/android/detect.d.ts.map +1 -1
  44. package/dist/android/detect.js +36 -8
  45. package/dist/android/detect.js.map +1 -1
  46. package/dist/cli.d.ts.map +1 -1
  47. package/dist/cli.js +157 -31
  48. package/dist/cli.js.map +1 -1
  49. package/dist/config/meetSdkDefaultConfig.d.ts +19 -2
  50. package/dist/config/meetSdkDefaultConfig.d.ts.map +1 -1
  51. package/dist/config/meetSdkDefaultConfig.js +67 -5
  52. package/dist/config/meetSdkDefaultConfig.js.map +1 -1
  53. package/dist/config/meetSdkIosConfig.d.ts +21 -0
  54. package/dist/config/meetSdkIosConfig.d.ts.map +1 -0
  55. package/dist/config/meetSdkIosConfig.js +66 -0
  56. package/dist/config/meetSdkIosConfig.js.map +1 -0
  57. package/dist/config/meetSdkRemoteConfig.d.ts +18 -1
  58. package/dist/config/meetSdkRemoteConfig.d.ts.map +1 -1
  59. package/dist/config/meetSdkRemoteConfig.js +61 -25
  60. package/dist/config/meetSdkRemoteConfig.js.map +1 -1
  61. package/dist/contracts/types.d.ts +19 -6
  62. package/dist/contracts/types.d.ts.map +1 -1
  63. package/dist/core/doctor.d.ts +17 -0
  64. package/dist/core/doctor.d.ts.map +1 -0
  65. package/dist/core/doctor.js +444 -0
  66. package/dist/core/doctor.js.map +1 -0
  67. package/dist/core/pipeline.d.ts.map +1 -1
  68. package/dist/core/pipeline.js +0 -15
  69. package/dist/core/pipeline.js.map +1 -1
  70. package/dist/core/platform.d.ts +12 -0
  71. package/dist/core/platform.d.ts.map +1 -0
  72. package/dist/core/platform.js +40 -0
  73. package/dist/core/platform.js.map +1 -0
  74. package/dist/core/reporter.js +1 -1
  75. package/dist/core/reporter.js.map +1 -1
  76. package/dist/core/workspace.d.ts +2 -2
  77. package/dist/core/workspace.d.ts.map +1 -1
  78. package/dist/core/workspace.js +4 -5
  79. package/dist/core/workspace.js.map +1 -1
  80. package/dist/index.d.ts +3 -1
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +3 -1
  83. package/dist/index.js.map +1 -1
  84. package/dist/ios/channelConfig.d.ts +1 -0
  85. package/dist/ios/channelConfig.d.ts.map +1 -1
  86. package/dist/ios/channelConfig.js +82 -0
  87. package/dist/ios/channelConfig.js.map +1 -1
  88. package/dist/ios/codeUtils.d.ts +1 -0
  89. package/dist/ios/codeUtils.d.ts.map +1 -1
  90. package/dist/ios/codeUtils.js +11 -2
  91. package/dist/ios/codeUtils.js.map +1 -1
  92. package/dist/ios/detect.d.ts +2 -2
  93. package/dist/ios/detect.d.ts.map +1 -1
  94. package/dist/ios/detect.js +49 -10
  95. package/dist/ios/detect.js.map +1 -1
  96. package/dist/ios/entitlements.d.ts +4 -0
  97. package/dist/ios/entitlements.d.ts.map +1 -0
  98. package/dist/ios/entitlements.js +53 -0
  99. package/dist/ios/entitlements.js.map +1 -0
  100. package/dist/ios/fileManager.d.ts.map +1 -1
  101. package/dist/ios/fileManager.js +3 -2
  102. package/dist/ios/fileManager.js.map +1 -1
  103. package/dist/ios/infoPlist.d.ts +1 -1
  104. package/dist/ios/infoPlist.d.ts.map +1 -1
  105. package/dist/ios/infoPlist.js.map +1 -1
  106. package/dist/ios/integrate.d.ts.map +1 -1
  107. package/dist/ios/integrate.js +211 -36
  108. package/dist/ios/integrate.js.map +1 -1
  109. package/dist/ios/pbxprojEditor.d.ts +2 -0
  110. package/dist/ios/pbxprojEditor.d.ts.map +1 -1
  111. package/dist/ios/pbxprojEditor.js +179 -1
  112. package/dist/ios/pbxprojEditor.js.map +1 -1
  113. package/dist/ios/pluginConfig.d.ts +1 -0
  114. package/dist/ios/pluginConfig.d.ts.map +1 -1
  115. package/dist/ios/pluginConfig.js +36 -4
  116. package/dist/ios/pluginConfig.js.map +1 -1
  117. package/dist/ios/sdkBundle.d.ts +1 -1
  118. package/dist/ios/sdkBundle.d.ts.map +1 -1
  119. package/dist/ios/sdkBundle.js +7 -5
  120. package/dist/ios/sdkBundle.js.map +1 -1
  121. package/dist/ios/template.d.ts +1 -0
  122. package/dist/ios/template.d.ts.map +1 -1
  123. package/dist/ios/template.js +14 -1
  124. package/dist/ios/template.js.map +1 -1
  125. package/dist/ios/types.d.ts +2 -2
  126. package/dist/ios/types.d.ts.map +1 -1
  127. package/dist/mcp/server.d.ts.map +1 -1
  128. package/dist/mcp/server.js +14 -13
  129. package/dist/mcp/server.js.map +1 -1
  130. package/dist/mcp/service.d.ts +8 -6
  131. package/dist/mcp/service.d.ts.map +1 -1
  132. package/dist/mcp/service.js +34 -14
  133. package/dist/mcp/service.js.map +1 -1
  134. package/dist/ops/handlers.d.ts.map +1 -1
  135. package/dist/ops/handlers.js +10 -4
  136. package/dist/ops/handlers.js.map +1 -1
  137. package/dist/remote/sdkHomeDownload.d.ts +65 -0
  138. package/dist/remote/sdkHomeDownload.d.ts.map +1 -0
  139. package/dist/remote/sdkHomeDownload.js +208 -0
  140. package/dist/remote/sdkHomeDownload.js.map +1 -0
  141. package/dist/remote/topsdkDownloadSdkConfig.d.ts.map +1 -1
  142. package/dist/remote/topsdkDownloadSdkConfig.js +11 -1
  143. package/dist/remote/topsdkDownloadSdkConfig.js.map +1 -1
  144. package/dist/shared/errors.d.ts +7 -0
  145. package/dist/shared/errors.d.ts.map +1 -0
  146. package/dist/shared/errors.js +16 -0
  147. package/dist/shared/errors.js.map +1 -0
  148. package/dist/shared/fileUtils.d.ts +5 -0
  149. package/dist/shared/fileUtils.d.ts.map +1 -0
  150. package/dist/shared/fileUtils.js +35 -0
  151. package/dist/shared/fileUtils.js.map +1 -0
  152. package/dist/shared/logger.d.ts +10 -0
  153. package/dist/shared/logger.d.ts.map +1 -0
  154. package/dist/shared/logger.js +37 -0
  155. package/dist/shared/logger.js.map +1 -0
  156. package/dist/shared/pathUtils.d.ts +4 -0
  157. package/dist/shared/pathUtils.d.ts.map +1 -0
  158. package/dist/shared/pathUtils.js +22 -0
  159. package/dist/shared/pathUtils.js.map +1 -0
  160. package/dist/shared/processRunner.d.ts +12 -0
  161. package/dist/shared/processRunner.d.ts.map +1 -0
  162. package/dist/shared/processRunner.js +31 -0
  163. package/dist/shared/processRunner.js.map +1 -0
  164. package/docs/AAB_CONVERTER_CLI_PLAN.md +392 -0
  165. package/docs/API.md +246 -32
  166. package/docs/CLI.md +292 -0
  167. package/docs/INTEGRATION.md +116 -0
  168. package/docs/MCP.md +86 -0
  169. package/docs/README.md +19 -10
  170. package/docs/{api → archive/api}/downloadSDKConfig.md +8 -6
  171. package/docs/{api → archive/api}/getChannelConfig-meetgames.md +1 -1
  172. package/docs/archive/ios-migration.md +2139 -0
  173. 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
  174. package/docs/{ → archive/product/}/351/234/200/346/261/202/346/226/207/346/241/243.md +15 -14
  175. package/logs/convert-20260622-155037.log +5 -0
  176. package/logs/convert-20260622-155226.log +6 -0
  177. package/meetsdk-android.json +2 -1
  178. package/meetsdk-ios.json +15 -0
  179. package/package.json +10 -36
  180. package/scripts/package-aab-cli-win.mjs +193 -0
  181. package/src/aab-converter/aab-entry.ts +48 -0
  182. package/src/aab-converter/apksExtractor.ts +119 -0
  183. package/src/aab-converter/bundletoolRunner.ts +63 -0
  184. package/src/aab-converter/cliArgs.ts +194 -0
  185. package/src/aab-converter/convertAabToApk.ts +81 -0
  186. package/src/aab-converter/resourcePaths.ts +43 -0
  187. package/src/aab-converter/signingOptions.ts +29 -0
  188. package/src/aab-converter/types.ts +26 -0
  189. package/src/android/adapter.ts +9 -0
  190. package/src/android/assembleIntegrationJson.ts +33 -0
  191. package/src/android/detect.ts +132 -0
  192. package/src/android/downloadGoogleServicesJson.ts +56 -0
  193. package/src/android/gradle.ts +116 -0
  194. package/src/android/manifest.ts +50 -0
  195. package/src/android/meetSdkRemoteGradle.ts +837 -0
  196. package/src/cli.ts +488 -0
  197. package/src/config/fetchConfigWrite.ts +30 -0
  198. package/src/config/loadAndroidIntegration.ts +41 -0
  199. package/src/config/loadManifest.ts +40 -0
  200. package/src/config/meetSdkDefaultConfig.ts +99 -0
  201. package/src/config/meetSdkIosConfig.ts +87 -0
  202. package/src/config/meetSdkRemoteConfig.ts +1211 -0
  203. package/src/config/topsdkFeatureModules.ts +92 -0
  204. package/src/contracts/types.ts +121 -0
  205. package/src/core/doctor.ts +485 -0
  206. package/src/core/patch.ts +64 -0
  207. package/src/core/pipeline.ts +107 -0
  208. package/src/core/platform.ts +47 -0
  209. package/src/core/previewPatches.ts +23 -0
  210. package/src/core/reporter.ts +24 -0
  211. package/src/core/workspace.ts +29 -0
  212. package/src/entry.ts +7 -0
  213. package/src/index.ts +133 -0
  214. package/src/ios/channelConfig.ts +128 -0
  215. package/src/ios/codeUtils.ts +160 -0
  216. package/src/ios/detect.ts +105 -0
  217. package/src/ios/entitlements.ts +61 -0
  218. package/src/ios/fileManager.ts +48 -0
  219. package/src/ios/infoPlist.ts +55 -0
  220. package/src/ios/integrate.ts +516 -0
  221. package/src/ios/pbxprojEditor.ts +383 -0
  222. package/src/ios/pluginConfig.ts +97 -0
  223. package/src/ios/reserved.ts +8 -0
  224. package/src/ios/sdkBundle.ts +36 -0
  225. package/src/ios/template.ts +36 -0
  226. package/src/ios/types.ts +65 -0
  227. package/src/mcp/server.ts +170 -0
  228. package/src/mcp/service.ts +222 -0
  229. package/src/mcp-entry.ts +7 -0
  230. package/src/ops/fileStore.ts +56 -0
  231. package/src/ops/handlers.ts +304 -0
  232. package/src/remote/fetchJson.ts +22 -0
  233. package/src/remote/sdkHomeDownload.ts +274 -0
  234. package/src/remote/topsdkDownloadSdkConfig.ts +93 -0
  235. package/src/remote/topsdkGetSdkConfig.ts +122 -0
  236. package/src/remote/topsdkSign.ts +10 -0
  237. package/src/shared/errors.ts +16 -0
  238. package/src/shared/fileUtils.ts +41 -0
  239. package/src/shared/logger.ts +49 -0
  240. package/src/shared/pathUtils.ts +24 -0
  241. package/src/shared/processRunner.ts +43 -0
  242. package/test-projects/README.md +51 -0
  243. package/test-projects/_preview/pipeline.patch +281 -0
  244. package/tests/aab-converter.test.ts +213 -0
  245. package/tests/assemble.test.ts +12 -0
  246. package/tests/doctor.test.ts +89 -0
  247. package/tests/downloadGoogleServicesJson.test.ts +47 -0
  248. package/tests/fetch-remote.test.ts +23 -0
  249. package/tests/fetchConfigOverrides.test.ts +28 -0
  250. package/tests/fetchConfigWrite.test.ts +54 -0
  251. package/tests/gradle.test.ts +33 -0
  252. package/tests/integration-json.test.ts +29 -0
  253. package/tests/ios.codeUtils.test.ts +23 -0
  254. package/tests/ios.sdkBundle.test.ts +16 -0
  255. package/tests/loadManifest.test.ts +15 -0
  256. package/tests/manifest-xml.test.ts +30 -0
  257. package/tests/mcp.e2e.ts +217 -0
  258. package/tests/mcp.service.test.ts +53 -0
  259. package/tests/meetSdkRemoteConfig.test.ts +456 -0
  260. package/tests/meetSdkRemoteGradle.test.ts +414 -0
  261. package/tests/pipeline.android.test.ts +96 -0
  262. package/tests/pipeline.integration-json.test.ts +58 -0
  263. package/tests/pipeline.ios.test.ts +385 -0
  264. package/tests/pipeline.preview.patch.test.ts +85 -0
  265. package/tests/platformSelection.test.ts +77 -0
  266. package/tests/sdkHomeDownload.test.ts +124 -0
  267. package/tests/sdkVersionConfig.test.ts +130 -0
  268. package/tests/test-projects-hosts.test.ts +78 -0
  269. package/tests/topsdk.test.ts +53 -0
  270. package/tests/topsdkDownloadSdkConfig.test.ts +81 -0
  271. package/tests/topsdkFeatureModules.test.ts +116 -0
  272. package/tsconfig.json +19 -0
  273. package/vitest.config.ts +9 -0
  274. package/vitest.mcp.config.ts +11 -0
  275. package/bundled/android/sample.txt +0 -1
  276. package/docs/ANDROID.md +0 -133
  277. package/docs/CURSOR-MCP-SETUP.md +0 -72
  278. package/docs/MCP-SKILL.md +0 -63
  279. package/fixtures/api-samples/getChannelConfig-meetgames.sample.json +0 -123
  280. package/fixtures/meetsdk-remote-config.download-shape.json +0 -20
  281. package/fixtures/meetsdk-remote-config.mock.json +0 -69
  282. package/fixtures/recipes/android-default.fixture.yaml +0 -15
  283. package/fixtures/recipes/android-integration.fixture.json +0 -29
  284. package/fixtures/topsdk-config-reference.json +0 -39
  285. /package/docs/{api → archive/api}/getSDKConfig.md +0 -0
@@ -0,0 +1,47 @@
1
+ import type { Manifest, WorkspaceContext } from "../contracts/types.js";
2
+
3
+ export type DetectedPlatform = "android" | "ios";
4
+
5
+ export function detectSinglePlatform(ctx: WorkspaceContext): {
6
+ ok: true;
7
+ platform: DetectedPlatform;
8
+ } | {
9
+ ok: false;
10
+ error: string;
11
+ } {
12
+ const androidOk = ctx.android?.ok === true;
13
+ const iosOk = ctx.ios?.ok === true;
14
+ if (androidOk && !iosOk) return { ok: true, platform: "android" };
15
+ if (iosOk && !androidOk) return { ok: true, platform: "ios" };
16
+ if (androidOk && iosOk) {
17
+ return {
18
+ ok: false,
19
+ error: "project root matches both Android and iOS projects; pass a narrower --project-root so exactly one platform is detected",
20
+ };
21
+ }
22
+ const androidError = ctx.android && !ctx.android.ok ? ctx.android.error : "not detected";
23
+ const iosError = ctx.ios && !ctx.ios.ok ? ctx.ios.error : "not detected";
24
+ const androidLooksLikeProject = Boolean(ctx.android && !ctx.android.ok && !androidError.includes("settings.gradle"));
25
+ const iosLooksLikeProject = Boolean(ctx.ios && !ctx.ios.ok && !iosError.includes("no .xcodeproj"));
26
+ if (androidLooksLikeProject && !iosLooksLikeProject) return { ok: false, error: androidError };
27
+ if (iosLooksLikeProject && !androidLooksLikeProject) return { ok: false, error: iosError };
28
+ return {
29
+ ok: false,
30
+ error: `project root is neither a supported Android nor iOS project (android: ${androidError}; ios: ${iosError})`,
31
+ };
32
+ }
33
+
34
+ export function platformContext(ctx: WorkspaceContext, platform: DetectedPlatform): WorkspaceContext {
35
+ if (platform === "android") {
36
+ return { ...ctx, ios: undefined, iosReserved: undefined };
37
+ }
38
+ return { ...ctx, android: undefined };
39
+ }
40
+
41
+ export function manifestForPlatform(manifest: Manifest, platform: DetectedPlatform): Manifest {
42
+ return {
43
+ ...manifest,
44
+ targets: manifest.targets?.filter((target) => target.platform === platform || target.platform === "all"),
45
+ steps: manifest.steps.filter((step) => !step.platform || step.platform === platform || step.platform === "all"),
46
+ };
47
+ }
@@ -0,0 +1,23 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ /** Default directory for `pipeline.patch` / `cli-preview.patch` (gitignored). */
5
+ export function resolveDefaultPreviewPatchDir(packageRoot: string): string {
6
+ return path.join(packageRoot, "test-projects", "_preview");
7
+ }
8
+
9
+ /**
10
+ * Before writing a new patch under `test-projects/_preview/`, remove all existing files there
11
+ * so only the latest command output remains.
12
+ */
13
+ export function clearPreviewPatchFilesIfTargetInside(packageRoot: string, patchFileAbs: string): void {
14
+ const previewDir = resolveDefaultPreviewPatchDir(packageRoot);
15
+ const target = path.resolve(patchFileAbs);
16
+ const prev = path.resolve(previewDir);
17
+ if (target !== prev && !target.startsWith(prev + path.sep)) return;
18
+ if (!fs.existsSync(prev)) return;
19
+ for (const ent of fs.readdirSync(prev, { withFileTypes: true })) {
20
+ const p = path.join(prev, ent.name);
21
+ if (ent.isFile()) fs.unlinkSync(p);
22
+ }
23
+ }
@@ -0,0 +1,24 @@
1
+ import type { PipelineReport } from "../contracts/types.js";
2
+
3
+ export function printReport(report: PipelineReport, patch: string, verbose: boolean): void {
4
+ console.log(`[meetgames] dryRun=${report.dryRun}`);
5
+ console.log(`[meetgames] steps run: ${report.stepsRun}, skipped: ${report.stepsSkipped}`);
6
+ if (report.warnings.length) {
7
+ for (const w of report.warnings) console.log(`[meetgames] warning: ${w}`);
8
+ }
9
+ if (report.errors.length) {
10
+ for (const e of report.errors) console.error(`[meetgames] error: ${e}`);
11
+ }
12
+
13
+ if (!patch.trim()) {
14
+ console.log("[meetgames] patch preview: no text file changes");
15
+ return;
16
+ }
17
+ const lines = patch.split("\n");
18
+ const max = verbose ? lines.length : Math.min(lines.length, 120);
19
+ console.log("[meetgames] patch preview:");
20
+ console.log(lines.slice(0, max).join("\n"));
21
+ if (!verbose && lines.length > max) {
22
+ console.log(`[meetgames] ... truncated ${lines.length - max} lines (use --verbose)`);
23
+ }
24
+ }
@@ -0,0 +1,29 @@
1
+ import path from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import type { WorkspaceContext, WorkspaceContextOptions } from "../contracts/types.js";
4
+ import { detectAndroid } from "../android/detect.js";
5
+ import { detectIOS } from "../ios/detect.js";
6
+ import { iosToolingReserved } from "../ios/reserved.js";
7
+
8
+ /** Package root: parent of dist/ when running compiled cli */
9
+ export function resolvePackageRoot(): string {
10
+ const here = path.dirname(fileURLToPath(import.meta.url));
11
+ return path.resolve(here, "..", "..");
12
+ }
13
+
14
+ export function buildWorkspaceContext(
15
+ projectRoot: string,
16
+ packageRoot?: string,
17
+ options: WorkspaceContextOptions = {}
18
+ ): WorkspaceContext {
19
+ const root = path.resolve(projectRoot);
20
+ const pkg = packageRoot ?? resolvePackageRoot();
21
+ return {
22
+ projectRoot: root,
23
+ packageRoot: pkg,
24
+ sdkHomeApiBaseUrl: options.sdkHomeApiBaseUrl,
25
+ android: detectAndroid(root, { appTarget: options.appTarget }),
26
+ ios: detectIOS(root, { appTarget: options.appTarget }),
27
+ iosReserved: iosToolingReserved,
28
+ };
29
+ }
package/src/entry.ts ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { main } from "./cli.js";
3
+
4
+ main().catch((err: unknown) => {
5
+ console.error(err);
6
+ process.exit(1);
7
+ });
package/src/index.ts ADDED
@@ -0,0 +1,133 @@
1
+ export type * from "./contracts/types.js";
2
+ export { loadManifestFile } from "./config/loadManifest.js";
3
+ export { loadAndroidIntegrationFile, parseAndroidIntegrationJson } from "./config/loadAndroidIntegration.js";
4
+ export {
5
+ type MeetSdkAnalyticsAdjustCredentials,
6
+ type MeetSdkAnalyticsAdjustModule,
7
+ type MeetSdkAnalyticsAppsflyerCredentials,
8
+ type MeetSdkAnalyticsAppsflyerModule,
9
+ type MeetSdkAnalyticsFirebaseCredentials,
10
+ type MeetSdkAnalyticsFirebaseModule,
11
+ type MeetSdkAnalyticsModules,
12
+ type MeetSdkDefaultConfig,
13
+ type MeetSdkFeatureScope,
14
+ type MeetSdkGradleDependency,
15
+ type MeetSdkLoginFacebookCredentials,
16
+ type MeetSdkLoginFacebookModule,
17
+ type MeetSdkLoginGoogleCredentials,
18
+ type MeetSdkLoginGoogleModule,
19
+ type MeetSdkLoginKakaoCredentials,
20
+ type MeetSdkLoginKakaoModule,
21
+ type MeetSdkLoginLineCredentials,
22
+ type MeetSdkLoginLineModule,
23
+ type MeetSdkLoginModules,
24
+ type MeetSdkLoginNaverCredentials,
25
+ type MeetSdkLoginNaverModule,
26
+ type MeetSdkLoginSnapchatCredentials,
27
+ type MeetSdkLoginSnapchatModule,
28
+ type MeetSdkLoginTiktokCredentials,
29
+ type MeetSdkLoginTiktokModule,
30
+ type MeetSdkLoginTwitterCredentials,
31
+ type MeetSdkLoginTwitterModule,
32
+ type MeetSdkModuleToggles,
33
+ type MeetSdkPaymentModules,
34
+ type MeetSdkRemoteConfig,
35
+ type MeetSdkRemoteTopsdkBlock,
36
+ type MeetSdkSimpleModule,
37
+ type MeetSdkSimplePluginConfig,
38
+ DEFAULT_TOPSDK_PLUGIN_DEPENDENCIES,
39
+ MEETSDK_REMOTE_CONFIG_FILENAME,
40
+ applyMeetSdkDefaultConfig,
41
+ applyFetchConfigCliOverrides,
42
+ collectMeetSdkRemoteApplyPlugins,
43
+ collectMeetSdkRemoteBuildscriptClasspaths,
44
+ collectMeetSdkRemoteBuildscriptRepositories,
45
+ collectMeetSdkRemotePluginsDslForModule,
46
+ collectMeetSdkRemotePluginsDslForRoot,
47
+ collectMeetSdkRemoteRepositories,
48
+ type MeetSdkGradlePluginDslSpec,
49
+ defaultSdkModules,
50
+ emptySdkModules,
51
+ hasSdkModuleKey,
52
+ isSdkModuleToggleOn,
53
+ mapTopSdkGetSdkConfigToMeetSdkRemoteConfig,
54
+ readMeetSdkRemoteChannel,
55
+ normalizeSdkModulesFromUnknown,
56
+ tryParseAsMeetSdkDefaultConfig,
57
+ tryParseAsMeetSdkRemoteConfig,
58
+ validateMeetSdkRemoteConfig,
59
+ } from "./config/meetSdkRemoteConfig.js";
60
+ export {
61
+ loadBuiltInMeetSdkDefaultConfig,
62
+ loadMeetSdkDefaultConfigWithLatestAndroidVersion,
63
+ resolveMeetSdkAndroidConfigPath,
64
+ syncMeetSdkAndroidVersionToConfig,
65
+ } from "./config/meetSdkDefaultConfig.js";
66
+ export {
67
+ MEETSDK_IOS_CONFIG_FILENAME,
68
+ loadMeetSdkIosConfig,
69
+ resolveMeetSdkIosConfigPath,
70
+ syncMeetSdkIosVersionToConfig,
71
+ tryParseAsMeetSdkIosConfig,
72
+ writeMeetSdkIosConfig,
73
+ type MeetSdkIosConfig,
74
+ } from "./config/meetSdkIosConfig.js";
75
+ export {
76
+ type MeetSdkFeatureCategory,
77
+ type TopSdkFeatureModule,
78
+ TOPSDK_FEATURE_MODULES,
79
+ buildTopSdkFeatureImplementationLines,
80
+ isTopSdkFeatureModuleEnabled,
81
+ } from "./config/topsdkFeatureModules.js";
82
+ export { clearPreviewPatchFilesIfTargetInside, resolveDefaultPreviewPatchDir } from "./core/previewPatches.js";
83
+ export { buildWorkspaceContext, resolvePackageRoot } from "./core/workspace.js";
84
+ export { runPipeline } from "./core/pipeline.js";
85
+ export { generatePatchForFile } from "./core/patch.js";
86
+ export { androidPlatformAdapter } from "./android/adapter.js";
87
+ export { fetchJsonGet } from "./remote/fetchJson.js";
88
+ export { topsdkMd5Base64Sign } from "./remote/topsdkSign.js";
89
+ export {
90
+ TOPSDK_GET_SDK_CONFIG_DISCOVERY_AUTH_TYPES,
91
+ defaultTopSdkBaseUrl,
92
+ fetchTopSdkGetSdkConfig,
93
+ filterTopSdkAuthTypesForRequest,
94
+ resolveAuthTypesForGetSdkConfigRequest,
95
+ buildTopSdkGetSdkConfigUrl,
96
+ } from "./remote/topsdkGetSdkConfig.js";
97
+ export {
98
+ buildTopSdkDownloadSdkConfigUrl,
99
+ fetchTopSdkDownloadSdkConfig,
100
+ parseTopSdkApiErrorBody,
101
+ } from "./remote/topsdkDownloadSdkConfig.js";
102
+ export {
103
+ DEFAULT_IOS_SDK_PACKAGE_TYPE,
104
+ DEFAULT_IOS_SDK_PLUGINS,
105
+ buildSdkHomeDownloadUrl,
106
+ buildSdkHomeVersionUrl,
107
+ defaultSdkHomeApiBaseUrl,
108
+ downloadBinaryFile,
109
+ downloadIosSdkToBundled,
110
+ extractZip,
111
+ fetchSdkHomeIosDownloadUrl,
112
+ fetchSdkHomeIosVersion,
113
+ fetchSdkHomeVersions,
114
+ resolveIosSdkRootFromDirectory,
115
+ resolveIosSdkZipFileName,
116
+ type DownloadIosSdkOptions,
117
+ type DownloadIosSdkResult,
118
+ type SdkHomeDownloadUrlRequest,
119
+ type SdkHomePlatformVersion,
120
+ type SdkHomeVersions,
121
+ } from "./remote/sdkHomeDownload.js";
122
+ export { unwrapRemoteIntegrationPayload, attachIntegrationMeta } from "./android/assembleIntegrationJson.js";
123
+ export { iosToolingReserved, detectIOSPlaceholder } from "./ios/reserved.js";
124
+ export { detectIOS } from "./ios/detect.js";
125
+ export { runIosIntegrateTopSdk } from "./ios/integrate.js";
126
+ export { resolveIosSdkRoot } from "./ios/sdkBundle.js";
127
+ export { createMeetgamesMcpServer, startMeetgamesMcpServer } from "./mcp/server.js";
128
+ export {
129
+ meetgamesDoctor,
130
+ meetgamesFetchConfig,
131
+ meetgamesIntegrate,
132
+ meetgamesSetup,
133
+ } from "./mcp/service.js";
@@ -0,0 +1,128 @@
1
+ import type { MeetSdkRemoteConfig } from "../config/meetSdkRemoteConfig.js";
2
+ import { hasSdkModuleKey } from "../config/meetSdkRemoteConfig.js";
3
+
4
+ /** Flat map for `{topsdk.appId}` style templates in plugin config. */
5
+ export function buildChannelConfigMap(config: MeetSdkRemoteConfig): Record<string, unknown> {
6
+ const out: Record<string, unknown> = {
7
+ packageName: config.packageName,
8
+ channel: config.channel,
9
+ devicePlatform: config.devicePlatform,
10
+ topsdk: { ...config.topsdk },
11
+ sdkModules: config.sdkModules,
12
+ };
13
+ for (const [scope, bucket] of Object.entries(config.sdkModules)) {
14
+ if (!bucket || typeof bucket !== "object") continue;
15
+ const scopeRecord = bucket as Record<string, unknown>;
16
+ for (const [key, val] of Object.entries(scopeRecord)) {
17
+ if (!hasSdkModuleKey(scopeRecord, key)) continue;
18
+ if (typeof val === "object" && val !== null) {
19
+ const normalized = normalizeIosChannelConfig(key, val as Record<string, unknown>);
20
+ out[`${scope}.${key}`] = val;
21
+ out[key] = val;
22
+ out[key.toUpperCase()] = normalized;
23
+ if (key === "facebookdata" && !out.FACEBOOK) {
24
+ out.FACEBOOK = normalized;
25
+ }
26
+ }
27
+ }
28
+ }
29
+ return out;
30
+ }
31
+
32
+ function normalizeIosChannelConfig(subKey: string, value: Record<string, unknown>): Record<string, unknown> {
33
+ const normalized: Record<string, unknown> = { ...value };
34
+ if (subKey === "facebook") {
35
+ normalized.clientId = normalized.clientId ?? normalized.facebookAppId ?? normalized.appId;
36
+ normalized.name = normalized.name ?? normalized.facebookDisplayName ?? normalized.displayName;
37
+ normalized.scheme = normalized.scheme ?? normalized.fbLoginProtocolScheme;
38
+ normalized.secret = normalized.secret ?? normalized.facebookClientToken ?? normalized.clientToken;
39
+ normalized.openMessenger = normalized.openMessenger ?? "0";
40
+ }
41
+ if (subKey === "facebookdata") {
42
+ normalized.clientId = normalized.clientId ?? normalized.facebookAppId ?? normalized.appId;
43
+ normalized.name = normalized.name ?? normalized.facebookDisplayName ?? normalized.displayName;
44
+ normalized.scheme = normalized.scheme ?? normalized.fbLoginProtocolScheme;
45
+ normalized.secret = normalized.secret ?? normalized.facebookClientToken ?? normalized.clientToken;
46
+ }
47
+ if (subKey === "google") {
48
+ normalized.clientId = normalized.clientId ?? normalized.googleClientId;
49
+ normalized.scheme = normalized.scheme ?? normalized.reversedClientId ?? normalized.reversed_client_id;
50
+ }
51
+ if (subKey === "appsflyer") {
52
+ normalized.clientId = normalized.clientId ?? normalized.appleAppId ?? normalized.appId;
53
+ normalized.secret = normalized.secret ?? normalized.devKey;
54
+ }
55
+ if (subKey === "adjust") {
56
+ normalized.clientId = normalized.clientId ?? normalized.appId ?? normalized.appToken;
57
+ }
58
+ if (subKey === "firebase") {
59
+ normalized.clientId = normalized.clientId ?? normalized.firebase_file_url ?? normalized.googleServicesUrl;
60
+ }
61
+ if (subKey === "snapchat") {
62
+ normalized.scheme = normalized.scheme ?? schemeFromNonHttpUrl(normalized.redirect);
63
+ }
64
+ if (subKey === "line" || subKey === "naver") {
65
+ normalized.scheme = normalized.scheme ?? schemeFromNonHttpUrl(normalized.redirect);
66
+ }
67
+ return normalized;
68
+ }
69
+
70
+ function schemeFromNonHttpUrl(value: unknown): string | undefined {
71
+ if (typeof value !== "string" || !value.trim()) return undefined;
72
+ try {
73
+ const u = new URL(value);
74
+ const scheme = u.protocol.replace(/:$/, "");
75
+ if (!scheme || scheme === "http" || scheme === "https") return undefined;
76
+ return scheme;
77
+ } catch {
78
+ const match = value.match(/^([A-Za-z][A-Za-z0-9+.-]*):\/\//);
79
+ return match?.[1];
80
+ }
81
+ }
82
+
83
+ /** `meetsdk-remote-config` subKey → TopSDK iOS `plugins/<folder>/` name (native iOS package). */
84
+ export const IOS_PLUGIN_FOLDER_BY_SUBKEY: Record<string, string> = {
85
+ guest: "GuestSignin",
86
+ email: "EmailSignin",
87
+ facebook: "FacebookSignin",
88
+ google: "GoogleSignin",
89
+ snapchat: "SnapchatSignin",
90
+ discord: "DiscordSignin",
91
+ line: "LineSignin",
92
+ naver: "NaverSignin",
93
+ kakao: "KakaoSignin",
94
+ tiktok: "TiktokSignin",
95
+ googleIap: "IAPPay",
96
+ apple: "AppleSignin",
97
+ appsflyer: "AppsFlyerManager",
98
+ firebase: "FirebaseManager",
99
+ adjust: "AdjustManager",
100
+ facebookdata: "FacebookManager",
101
+ };
102
+
103
+ export function enabledIosPluginFolders(config: MeetSdkRemoteConfig): string[] {
104
+ const folders: string[] = [];
105
+ for (const [scope, bucket] of Object.entries(config.sdkModules)) {
106
+ if (!bucket || typeof bucket !== "object") continue;
107
+ const scopeRecord = bucket as Record<string, unknown>;
108
+ for (const [subKey, val] of Object.entries(scopeRecord)) {
109
+ if (!hasSdkModuleKey(scopeRecord, subKey)) continue;
110
+ const folder = IOS_PLUGIN_FOLDER_BY_SUBKEY[subKey];
111
+ if (folder) folders.push(folder);
112
+ }
113
+ }
114
+ return [...new Set(folders)];
115
+ }
116
+
117
+ export function unsupportedIosModuleKeys(config: MeetSdkRemoteConfig): string[] {
118
+ const keys: string[] = [];
119
+ for (const [scope, bucket] of Object.entries(config.sdkModules)) {
120
+ if (!bucket || typeof bucket !== "object") continue;
121
+ const scopeRecord = bucket as Record<string, unknown>;
122
+ for (const [subKey] of Object.entries(scopeRecord)) {
123
+ if (!hasSdkModuleKey(scopeRecord, subKey)) continue;
124
+ if (!IOS_PLUGIN_FOLDER_BY_SUBKEY[subKey]) keys.push(`${scope}.${subKey}`);
125
+ }
126
+ }
127
+ return keys;
128
+ }
@@ -0,0 +1,160 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ /** Objective-C AppDelegate injection (topsdk-tool-ios CodeUtils). */
5
+ export class CodeUtils {
6
+ constructor(private filePath: string, private content: string) {}
7
+
8
+ static fromFile(filePath: string): CodeUtils {
9
+ if (!fs.existsSync(filePath)) throw new Error(`code file not found: ${filePath}`);
10
+ return new CodeUtils(filePath, fs.readFileSync(filePath, "utf8"));
11
+ }
12
+
13
+ get text(): string {
14
+ return this.content;
15
+ }
16
+
17
+ private checkExisted(code: string): boolean {
18
+ const norm = (s: string) => s.replace(/\s/g, "");
19
+ return norm(this.content).includes(norm(code));
20
+ }
21
+
22
+ addHeader(code: string): boolean {
23
+ if (this.checkExisted(code)) return true;
24
+ this.content = `${code}\n${this.content}`;
25
+ return true;
26
+ }
27
+
28
+ addCodeToMethod(method: string, code: string, addToReturn = false): boolean {
29
+ if (this.checkExisted(code)) return true;
30
+ const bodyCode = code.replace(/;/g, "");
31
+ const methodSig = method.replace(/[{}\s]/g, "");
32
+
33
+ if (this.checkExisted(methodSig)) {
34
+ const lines = this.content.split("\n");
35
+ const out: string[] = [];
36
+ let methodStart = false;
37
+ let added = false;
38
+ for (const line of lines) {
39
+ if (!addToReturn) {
40
+ out.push(line);
41
+ const temp = line.replace(/\s/g, "");
42
+ if (temp.includes(methodSig)) methodStart = true;
43
+ if (line.includes("{") && methodStart && !added) {
44
+ out.push(`\t${bodyCode};\n`);
45
+ added = true;
46
+ }
47
+ } else {
48
+ const temp = line.replace(/\s/g, "");
49
+ if (temp.includes(methodSig)) {
50
+ methodStart = true;
51
+ out.push(line);
52
+ } else if (line.includes("return") && methodStart && !added) {
53
+ if (line.includes("return YES;") || line.includes("return NO;")) {
54
+ out.push(`\treturn ${bodyCode};\n`);
55
+ } else {
56
+ const returnIndex = line.indexOf("return ");
57
+ const semi = line.indexOf(";");
58
+ const current = line.slice(returnIndex + 7, semi);
59
+ out.push(`\treturn (${current} && ${bodyCode});\n`);
60
+ }
61
+ added = true;
62
+ } else {
63
+ out.push(line);
64
+ }
65
+ }
66
+ }
67
+ if (added) {
68
+ this.content = out.join("\n");
69
+ return true;
70
+ }
71
+ return false;
72
+ }
73
+
74
+ const lines = this.content.split("\n");
75
+ const out: string[] = [];
76
+ let blockStart = false;
77
+ let added = false;
78
+ for (const line of lines) {
79
+ if (line.includes("@implementation")) {
80
+ out.push(line);
81
+ blockStart = true;
82
+ } else if (line.includes("@end") && blockStart && !added) {
83
+ out.push(`${method} {`);
84
+ if (addToReturn) out.push(`\treturn ${bodyCode};\n`);
85
+ else out.push(`\t${bodyCode};\n`);
86
+ out.push("}\n");
87
+ out.push("@end\n");
88
+ added = true;
89
+ } else {
90
+ out.push(line);
91
+ }
92
+ }
93
+ if (added) {
94
+ this.content = out.join("\n");
95
+ return true;
96
+ }
97
+ return false;
98
+ }
99
+
100
+ writeIfChanged(): boolean {
101
+ const before = fs.readFileSync(this.filePath, "utf8");
102
+ if (before === this.content) return false;
103
+ fs.writeFileSync(this.filePath, this.content, "utf8");
104
+ return true;
105
+ }
106
+
107
+ applyToStore(write: (content: string) => void): boolean {
108
+ write(this.content);
109
+ return true;
110
+ }
111
+ }
112
+
113
+ function findObjectiveCDelegateFiles(srcRoot: string, marker: string): string[] {
114
+ const paths: string[] = [];
115
+ const walk = (dir: string): void => {
116
+ let entries: fs.Dirent[];
117
+ try {
118
+ entries = fs.readdirSync(dir, { withFileTypes: true });
119
+ } catch {
120
+ return;
121
+ }
122
+ for (const e of entries) {
123
+ if (e.name.startsWith(".")) continue;
124
+ const full = path.join(dir, e.name);
125
+ if (e.isDirectory()) {
126
+ if (!["Pods", "build", "DerivedData", "topSDK"].includes(e.name)) walk(full);
127
+ continue;
128
+ }
129
+ if (!/\.(m|mm|h)$/.test(e.name)) continue;
130
+ let text: string;
131
+ try {
132
+ text = fs.readFileSync(full, "utf8");
133
+ } catch {
134
+ continue;
135
+ }
136
+ if (!text.includes(marker)) continue;
137
+ if (e.name.endsWith(".h")) {
138
+ const m = full.replace(/\.h$/, ".m");
139
+ const mm = full.replace(/\.h$/, ".mm");
140
+ if (fs.existsSync(m)) paths.push(m);
141
+ if (fs.existsSync(mm)) paths.push(mm);
142
+ } else {
143
+ paths.push(full);
144
+ }
145
+ }
146
+ };
147
+ walk(srcRoot);
148
+ return [...new Set(paths)];
149
+ }
150
+
151
+ export function findDelegateFiles(srcRoot: string): string[] {
152
+ return findObjectiveCDelegateFiles(srcRoot, "UIApplicationDelegate").filter((p) => {
153
+ const name = path.basename(p);
154
+ return name !== "Unity_iPhone_Tests.m" && name !== "UnityAppController+ViewHandling.mm";
155
+ });
156
+ }
157
+
158
+ export function findSceneDelegateFiles(srcRoot: string): string[] {
159
+ return findObjectiveCDelegateFiles(srcRoot, "UIWindowSceneDelegate");
160
+ }
@@ -0,0 +1,105 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import type { IOSDetectOptions, IOSDetectResult } from "../contracts/types.js";
4
+
5
+ function findXcodeprojDirs(root: string, maxDepth: number): string[] {
6
+ const found: string[] = [];
7
+ const walk = (dir: string, depth: number): void => {
8
+ if (depth > maxDepth) return;
9
+ let entries: fs.Dirent[];
10
+ try {
11
+ entries = fs.readdirSync(dir, { withFileTypes: true });
12
+ } catch {
13
+ return;
14
+ }
15
+ for (const e of entries) {
16
+ if (e.name.startsWith(".")) continue;
17
+ const full = path.join(dir, e.name);
18
+ if (e.isDirectory() && e.name.endsWith(".xcodeproj")) {
19
+ found.push(full);
20
+ continue;
21
+ }
22
+ if (e.isDirectory() && !["node_modules", "Pods", "build", "DerivedData"].includes(e.name)) {
23
+ walk(full, depth + 1);
24
+ }
25
+ }
26
+ };
27
+ walk(root, 0);
28
+ return found.sort();
29
+ }
30
+
31
+ function readPrimaryTargetName(pbxprojContent: string): string | null {
32
+ return readApplicationTargetNames(pbxprojContent)[0] ?? null;
33
+ }
34
+
35
+ function unquotePbxValue(value: string): string {
36
+ return value.trim().replace(/^"|"$/g, "");
37
+ }
38
+
39
+ function readApplicationTargetNames(pbxprojContent: string): string[] {
40
+ const names: string[] = [];
41
+ const targetBlock = /^[ \t]*[A-Za-z0-9]+ \/\*[^*]*\*\/ = \{\s*isa = PBXNativeTarget;[\s\S]*?^[ \t]*\};/gm;
42
+ let match = targetBlock.exec(pbxprojContent);
43
+ while (match) {
44
+ const block = match[0];
45
+ if (/\bproductType\s*=\s*"com\.apple\.product-type\.application"\s*;/.test(block)) {
46
+ const name = block.match(/\bname\s*=\s*([^;]+);/);
47
+ if (name) names.push(unquotePbxValue(name[1]));
48
+ }
49
+ match = targetBlock.exec(pbxprojContent);
50
+ }
51
+ return names;
52
+ }
53
+
54
+ function targetList(targetNames: string[]): string {
55
+ return targetNames.join(", ");
56
+ }
57
+
58
+ export function detectIOS(projectRoot: string, options: IOSDetectOptions = {}): IOSDetectResult {
59
+ const root = path.resolve(projectRoot);
60
+ let xcodeprojPath: string;
61
+ if (root.endsWith(".xcodeproj")) {
62
+ if (!fs.existsSync(root) || !fs.statSync(root).isDirectory()) {
63
+ return { ok: false, error: `xcodeproj path does not exist or is not a directory: ${root}` };
64
+ }
65
+ xcodeprojPath = root;
66
+ } else {
67
+ const xcodeprojs = findXcodeprojDirs(root, 4);
68
+ if (!xcodeprojs.length) {
69
+ return { ok: false, error: "no .xcodeproj found under project root" };
70
+ }
71
+ xcodeprojPath = xcodeprojs[0];
72
+ }
73
+ const iosRoot = path.dirname(xcodeprojPath);
74
+ const pbxprojPath = path.join(xcodeprojPath, "project.pbxproj");
75
+ if (!fs.existsSync(pbxprojPath)) {
76
+ return { ok: false, error: `missing project.pbxproj: ${pbxprojPath}` };
77
+ }
78
+ const pbx = fs.readFileSync(pbxprojPath, "utf8");
79
+ const targetNames = readApplicationTargetNames(pbx);
80
+ if (!targetNames.length) {
81
+ return { ok: false, error: "NO_IOS_APP_TARGET_FOUND" };
82
+ }
83
+ const requestedTarget = options.appTarget?.trim() ?? "";
84
+ if (requestedTarget && !targetNames.includes(requestedTarget)) {
85
+ return {
86
+ ok: false,
87
+ error: `IOS_APP_TARGET_NOT_FOUND: ${requestedTarget}; available app targets: ${targetList(targetNames)}`,
88
+ };
89
+ }
90
+ const targetName = requestedTarget || readPrimaryTargetName(pbx) || path.basename(xcodeprojPath, ".xcodeproj");
91
+ const podfilePath = path.join(iosRoot, "Podfile");
92
+ const workspaceCandidates = fs
93
+ .readdirSync(iosRoot)
94
+ .filter((n) => n.endsWith(".xcworkspace"))
95
+ .map((n) => path.join(iosRoot, n));
96
+ return {
97
+ ok: true,
98
+ iosRoot,
99
+ xcodeprojPath,
100
+ workspacePath: workspaceCandidates[0],
101
+ podfilePath: fs.existsSync(podfilePath) ? podfilePath : undefined,
102
+ targetName,
103
+ targetNames,
104
+ };
105
+ }