@leonxin/meetgames 0.1.13 → 0.1.15

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 (49) hide show
  1. package/config/meetsdk-ios.json +1 -1
  2. package/dist/android/manifest.d.ts.map +1 -1
  3. package/dist/android/manifest.js +9 -0
  4. package/dist/android/manifest.js.map +1 -1
  5. package/dist/android/meetSdkRemoteGradle.d.ts.map +1 -1
  6. package/dist/android/meetSdkRemoteGradle.js +126 -6
  7. package/dist/android/meetSdkRemoteGradle.js.map +1 -1
  8. package/dist/config/meetSdkRemoteConfig.d.ts +2 -0
  9. package/dist/config/meetSdkRemoteConfig.d.ts.map +1 -1
  10. package/dist/config/meetSdkRemoteConfig.js +14 -1
  11. package/dist/config/meetSdkRemoteConfig.js.map +1 -1
  12. package/dist/ios/channelConfig.d.ts.map +1 -1
  13. package/dist/ios/channelConfig.js +18 -1
  14. package/dist/ios/channelConfig.js.map +1 -1
  15. package/dist/ios/infoPlist.d.ts +0 -1
  16. package/dist/ios/infoPlist.d.ts.map +1 -1
  17. package/dist/ios/infoPlist.js +0 -5
  18. package/dist/ios/infoPlist.js.map +1 -1
  19. package/dist/ios/integrate.d.ts.map +1 -1
  20. package/dist/ios/integrate.js +172 -97
  21. package/dist/ios/integrate.js.map +1 -1
  22. package/dist/ios/pbxprojEditor.d.ts +1 -1
  23. package/dist/ios/pbxprojEditor.d.ts.map +1 -1
  24. package/dist/ios/pbxprojEditor.js +88 -15
  25. package/dist/ios/pbxprojEditor.js.map +1 -1
  26. package/dist/ops/fileStore.d.ts.map +1 -1
  27. package/dist/ops/fileStore.js +6 -5
  28. package/dist/ops/fileStore.js.map +1 -1
  29. package/dist/ops/handlers.d.ts.map +1 -1
  30. package/dist/ops/handlers.js +35 -3
  31. package/dist/ops/handlers.js.map +1 -1
  32. package/docs/API.md +1 -1
  33. package/docs/INTEGRATION.md +30 -2
  34. package/package.json +1 -1
  35. package/src/android/manifest.ts +11 -0
  36. package/src/android/meetSdkRemoteGradle.ts +125 -7
  37. package/src/config/meetSdkRemoteConfig.ts +13 -1
  38. package/src/ios/channelConfig.ts +18 -1
  39. package/src/ios/infoPlist.ts +0 -7
  40. package/src/ios/integrate.ts +177 -96
  41. package/src/ios/pbxprojEditor.ts +98 -16
  42. package/src/ops/fileStore.ts +7 -6
  43. package/src/ops/handlers.ts +38 -3
  44. package/tests/doctor.test.ts +43 -3
  45. package/tests/meetSdkRemoteConfig.test.ts +3 -2
  46. package/tests/meetSdkRemoteGradle.test.ts +2 -2
  47. package/tests/pipeline.android.test.ts +64 -10
  48. package/tests/pipeline.ios.test.ts +134 -43
  49. package/tests/platformSelection.test.ts +4 -4
@@ -64,7 +64,8 @@ export function escapeGroovyDoubleQuotedInner(value: string): string {
64
64
  return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
65
65
  }
66
66
 
67
- const RES_VALUE_KEY_RE = /resValue\s*\(\s*'[^']+'\s*,\s*'([^']+)'/;
67
+ const RES_VALUE_KEY_RE = /resValue\s*\(\s*['"][^'"]+['"]\s*,\s*['"]([^'"]+)['"]/;
68
+ const RES_VALUE_RE = /resValue\s*\(\s*(['"])([^'"]+)\1\s*,\s*(['"])([^'"]+)\3\s*,\s*(['"])(.*?)\5\s*\)/;
68
69
  const IMPLEMENTATION_COORD_RE = /implementation\s+["']([^"']+)["']/;
69
70
  const APPLY_PLUGIN_ID_RE = /apply\s+plugin:\s*['"]([^'"]+)['"]/;
70
71
  const PLUGINS_DSL_ID_RE = /^\s*id\s+(?:\(\s*)?['"]([^'"]+)['"](?:\s*\))?/;
@@ -99,6 +100,12 @@ export function extractResValueKey(line: string): string | null {
99
100
  return m?.[1] ?? null;
100
101
  }
101
102
 
103
+ function parseResValueLine(line: string): { type: string; key: string; value: string } | null {
104
+ const m = line.trim().match(RES_VALUE_RE);
105
+ if (!m) return null;
106
+ return { type: m[2], key: m[4], value: m[6] };
107
+ }
108
+
102
109
  /** Maven coordinate key for upsert: `group:artifact` (version ignored). */
103
110
  export function mavenGroupArtifactKey(coordinate: string): string {
104
111
  const parts = coordinate.split(":");
@@ -251,6 +258,9 @@ function repositoryToGradleLine(repo: string): string {
251
258
  }
252
259
 
253
260
  export function mergeRepositoriesInBlock(blockText: string, repositories: readonly string[]): string {
261
+ if (repositories.length && repositories.every((repo) => blockText.split("\n").some((line) => lineDeclaresRepository(line, repo)))) {
262
+ return blockText;
263
+ }
254
264
  let cleaned = removeRepositoryLinesByKeys(blockText, repositories);
255
265
  cleaned = stripManagedBlocks(cleaned, TOPSDK_REPO_AUTO_START, TOPSDK_REPO_AUTO_END);
256
266
  if (!repositories.length) return cleaned;
@@ -266,6 +276,16 @@ export function mergeRepositoriesInBlock(blockText: string, repositories: readon
266
276
  * Upsert buildscript classpaths: drop existing lines with same coordinate, then write TOPSDK AUTO block.
267
277
  */
268
278
  export function mergeClasspathsInBlock(blockText: string, classpaths: readonly string[]): string {
279
+ if (
280
+ classpaths.length &&
281
+ classpaths.every((classpath) =>
282
+ blockText
283
+ .split("\n")
284
+ .some((line) => extractClasspathCoordinate(line) === classpath)
285
+ )
286
+ ) {
287
+ return blockText;
288
+ }
269
289
  const coords = new Set(classpaths);
270
290
  let cleaned = removeClasspathLinesByCoordinates(blockText, coords);
271
291
  cleaned = stripManagedBlocks(cleaned, TOPSDK_AUTO_START, TOPSDK_AUTO_END);
@@ -312,6 +332,9 @@ function insertAfterLeadingApplyPlugins(content: string, snippet: string): strin
312
332
  */
313
333
  export function mergeApplyPluginsInContent(content: string, applyPlugins: readonly string[]): string {
314
334
  if (!applyPlugins.length) return content;
335
+ if (applyPlugins.every((plugin) => content.split("\n").some((line) => extractApplyPluginId(line) === plugin))) {
336
+ return content;
337
+ }
315
338
  const ids = new Set(applyPlugins);
316
339
  let cleaned = removeApplyPluginLinesByIds(content, ids);
317
340
  cleaned = stripManagedBlocks(cleaned, TOPSDK_PLUGIN_AUTO_START, TOPSDK_PLUGIN_AUTO_END);
@@ -342,25 +365,77 @@ export function mergeResValuesInDefaultConfigBlock(blockText: string, managedSni
342
365
  .split("\n")
343
366
  .map((l) => l.trimEnd())
344
367
  .filter((l) => l.includes("resValue("));
345
- const keys = new Set(
346
- [...desiredLines.map((l) => extractResValueKey(l)).filter((k): k is string => Boolean(k)), ...TOPSDK_MANAGED_RESVALUE_KEYS]
368
+ const desiredByKey = new Map(
369
+ desiredLines
370
+ .map((line) => {
371
+ const spec = parseResValueLine(line);
372
+ return spec ? ([spec.key, { ...spec, line }] as const) : null;
373
+ })
374
+ .filter((entry): entry is readonly [string, { type: string; key: string; value: string; line: string }] =>
375
+ Boolean(entry)
376
+ )
347
377
  );
348
- let cleaned = removeResValueLinesByKeys(blockText, keys);
378
+ if (resValuesAlreadyMatch(blockText, desiredByKey)) return blockText;
379
+ const keys = new Set([...desiredByKey.keys(), ...TOPSDK_MANAGED_RESVALUE_KEYS]);
380
+ const seen = new Set<string>();
381
+ let cleaned = blockText
382
+ .split("\n")
383
+ .filter((line) => {
384
+ if (line.includes(TOPSDK_AUTO_START) || line.includes(TOPSDK_AUTO_END)) return false;
385
+ const current = parseResValueLine(line);
386
+ if (!current || !keys.has(current.key)) return true;
387
+ const desired = desiredByKey.get(current.key);
388
+ if (!desired) return false;
389
+ if (current.type === desired.type && current.value === desired.value && !seen.has(current.key)) {
390
+ seen.add(current.key);
391
+ return true;
392
+ }
393
+ return false;
394
+ })
395
+ .join("\n");
349
396
  cleaned = stripManagedBlocks(cleaned, TOPSDK_AUTO_START, TOPSDK_AUTO_END);
397
+ const missingLines = desiredLines.filter((line) => {
398
+ const spec = parseResValueLine(line);
399
+ return spec ? !seen.has(spec.key) : false;
400
+ });
401
+ if (missingLines.length === 0) return cleaned;
402
+ const missingSnippet = [TOPSDK_AUTO_START, ...missingLines, TOPSDK_AUTO_END].join("\n");
350
403
  return replaceOrInsertManaged(
351
404
  cleaned,
352
405
  { start: 0, openBrace: 0, end: cleaned.length },
353
406
  TOPSDK_AUTO_START,
354
407
  TOPSDK_AUTO_END,
355
- managedSnippet
408
+ missingSnippet
356
409
  );
357
410
  }
358
411
 
412
+ function resValuesAlreadyMatch(
413
+ blockText: string,
414
+ desiredByKey: ReadonlyMap<string, { type: string; key: string; value: string; line: string }>
415
+ ): boolean {
416
+ const lines = blockText.split("\n");
417
+ const seen = new Set<string>();
418
+ for (const line of lines) {
419
+ const current = parseResValueLine(line);
420
+ if (!current) continue;
421
+ const desired = desiredByKey.get(current.key);
422
+ if (!desired) {
423
+ if ((TOPSDK_MANAGED_RESVALUE_KEYS as readonly string[]).includes(current.key)) return false;
424
+ continue;
425
+ }
426
+ if (seen.has(current.key)) return false;
427
+ if (current.type !== desired.type || current.value !== desired.value) return false;
428
+ seen.add(current.key);
429
+ }
430
+ return [...desiredByKey.keys()].every((key) => seen.has(key));
431
+ }
432
+
359
433
  function mergeDependenciesInBlock(
360
434
  blockText: string,
361
435
  managedSnippet: string,
362
436
  fallbackGroupId: string
363
437
  ): string {
438
+ if (dependenciesAlreadyMatch(blockText, managedSnippet, fallbackGroupId)) return blockText;
364
439
  const lookupText = `${blockText}\n${managedSnippet}`;
365
440
  const desiredLines = managedSnippet
366
441
  .split("\n")
@@ -388,6 +463,32 @@ function mergeDependenciesInBlock(
388
463
  );
389
464
  }
390
465
 
466
+ function dependenciesAlreadyMatch(blockText: string, managedSnippet: string, fallbackGroupId: string): boolean {
467
+ const lookupText = `${blockText}\n${managedSnippet}`;
468
+ const desiredLines = managedSnippet
469
+ .split("\n")
470
+ .map((l) => l.trimEnd())
471
+ .filter((l) => l.includes("implementation "));
472
+ const desiredKeys = desiredLines
473
+ .map((l) => extractImplementationKey(l, lookupText, fallbackGroupId))
474
+ .filter((k): k is string => Boolean(k));
475
+ const existingKeys = blockText
476
+ .split("\n")
477
+ .map((line) => extractImplementationKey(line, blockText, fallbackGroupId))
478
+ .filter((k): k is string => Boolean(k));
479
+ const existingKeySet = new Set(existingKeys);
480
+ if (!desiredKeys.every((key) => existingKeySet.has(key))) return false;
481
+ const versionMatch = managedSnippet.match(/def\s+topsdk_version\s*=\s*["']([^"']+)["']/);
482
+ const groupMatch = managedSnippet.match(/def\s+groupId\s*=\s*["']([^"']+)["']/);
483
+ if (versionMatch && !new RegExp(`def\\s+topsdk_version\\s*=\\s*["']${escapeRegExp(versionMatch[1])}["']`).test(blockText)) return false;
484
+ if (groupMatch && !new RegExp(`def\\s+groupId\\s*=\\s*["']${escapeRegExp(groupMatch[1])}["']`).test(blockText)) return false;
485
+ return true;
486
+ }
487
+
488
+ function escapeRegExp(value: string): string {
489
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
490
+ }
491
+
391
492
  function stripManagedBlocks(text: string, startMarker: string, endMarker: string): string {
392
493
  const start = text.indexOf(startMarker);
393
494
  const end = text.indexOf(endMarker);
@@ -576,6 +677,7 @@ function mergePluginsDslInBlock(blockText: string, specs: readonly MeetSdkGradle
576
677
  */
577
678
  export function mergePluginsDslInContent(content: string, specs: readonly MeetSdkGradlePluginDslSpec[]): string {
578
679
  if (!specs.length) return content;
680
+ if (pluginsDslAlreadyMatch(content, specs)) return content;
579
681
  const ids = new Set(specs.map((s) => s.id));
580
682
  let cleaned = removePluginsDslLinesByIds(content, ids);
581
683
  cleaned = removeApplyPluginLinesByIds(cleaned, ids);
@@ -589,6 +691,20 @@ export function mergePluginsDslInContent(content: string, specs: readonly MeetSd
589
691
  return cleaned.slice(0, pluginsBlock.openBrace + 1) + merged + cleaned.slice(pluginsBlock.end);
590
692
  }
591
693
 
694
+ function pluginsDslAlreadyMatch(content: string, specs: readonly MeetSdkGradlePluginDslSpec[]): boolean {
695
+ const lines = content.split("\n");
696
+ return specs.every((spec) =>
697
+ lines.some((line) => {
698
+ if (extractPluginsDslId(line) !== spec.id) return false;
699
+ if (spec.version && !line.includes(`version '${spec.version}'`) && !line.includes(`version "${spec.version}"`)) {
700
+ return false;
701
+ }
702
+ if (spec.applyFalse && !/\bapply\s+false\b/.test(line)) return false;
703
+ return true;
704
+ })
705
+ );
706
+ }
707
+
592
708
  function stripBuildscriptClasspaths(content: string, classpaths: readonly string[]): string {
593
709
  if (!classpaths.length) return content;
594
710
  const buildscript = findBlockRange(content, "buildscript");
@@ -746,8 +862,10 @@ function buildRemoteDependenciesSnippet(config: MeetSdkRemoteConfig): string {
746
862
  function updateDefaultConfigApplicationId(content: string, defaultConfigBlock: { openBrace: number; end: number }, applicationId: string): string {
747
863
  const escaped = escapeGroovyDoubleQuotedInner(applicationId);
748
864
  const blockText = content.slice(defaultConfigBlock.openBrace + 1, defaultConfigBlock.end);
749
- const existing = /(^[ \t]*)applicationId\s+(?:=+\s*)?["'][^"']*["']/m;
750
- if (existing.test(blockText)) {
865
+ const existing = /(^[ \t]*)applicationId\s+(?:=+\s*)?(["'])([^"']*)\2/m;
866
+ const match = blockText.match(existing);
867
+ if (match) {
868
+ if (match[3] === applicationId) return content;
751
869
  const updatedBlockText = blockText.replace(existing, `$1applicationId "${escaped}"`);
752
870
  return content.slice(0, defaultConfigBlock.openBrace + 1) + updatedBlockText + content.slice(defaultConfigBlock.end);
753
871
  }
@@ -189,6 +189,7 @@ export interface MeetSdkLoginModules {
189
189
 
190
190
  export interface MeetSdkPaymentModules {
191
191
  googleIap: MeetSdkSimpleModule;
192
+ appleIap: MeetSdkSimpleModule;
192
193
  onestoreIap: MeetSdkSimpleModule;
193
194
  huaweiIap: MeetSdkSimpleModule;
194
195
  xiaomiIap: MeetSdkSimpleModule;
@@ -271,7 +272,7 @@ export function defaultSdkModules(): MeetSdkModuleToggles {
271
272
  tiktok: false,
272
273
  discord: false,
273
274
  },
274
- payment: { googleIap: false, onestoreIap: false, huaweiIap: false, xiaomiIap: false },
275
+ payment: { googleIap: false, appleIap: false, onestoreIap: false, huaweiIap: false, xiaomiIap: false },
275
276
  analytics: { appsflyer: false, facebookdata: false, firebase: false, adjust: false },
276
277
  };
277
278
  }
@@ -333,6 +334,7 @@ export const DEFAULT_TOPSDK_PLUGIN_DEPENDENCIES = {
333
334
  },
334
335
  payment: {
335
336
  googleIap: dependency("google-iap"),
337
+ appleIap: [],
336
338
  onestoreIap: dependency("onestore-iap"),
337
339
  huaweiIap: dependency("huawei-iap"),
338
340
  xiaomiIap: dependency("xiaomi-iap"),
@@ -663,6 +665,12 @@ export function normalizeSdkModulesFromUnknown(raw: unknown): MeetSdkModuleToggl
663
665
  if (x === null || x === false) return null;
664
666
  d.payment.googleIap = x;
665
667
  }
668
+ if ("appleIap" in P) {
669
+ if (!isSdkModuleJsonObject(P.appleIap)) return null;
670
+ const x = parseSimpleModule(P.appleIap, DEFAULT_TOPSDK_PLUGIN_DEPENDENCIES.payment.appleIap);
671
+ if (x === null || x === false) return null;
672
+ d.payment.appleIap = x;
673
+ }
666
674
  if ("onestoreIap" in P) {
667
675
  if (!isSdkModuleJsonObject(P.onestoreIap)) return null;
668
676
  const x = parseSimpleModule(P.onestoreIap, DEFAULT_TOPSDK_PLUGIN_DEPENDENCIES.payment.onestoreIap);
@@ -883,6 +891,10 @@ export function mapTopSdkGetSdkConfigToMeetSdkRemoteConfig(
883
891
  case "GOOGLE_IAP":
884
892
  out.sdkModules.payment.googleIap = {};
885
893
  break;
894
+ case "APPLEIAP":
895
+ case "APPLE_IAP":
896
+ out.sdkModules.payment.appleIap = {};
897
+ break;
886
898
  case "ONESTOREIAP":
887
899
  case "ONESTORE_IAP":
888
900
  out.sdkModules.payment.onestoreIap = {};
@@ -93,6 +93,7 @@ export const IOS_PLUGIN_FOLDER_BY_SUBKEY: Record<string, string> = {
93
93
  kakao: "KakaoSignin",
94
94
  tiktok: "TiktokSignin",
95
95
  googleIap: "IAPPay",
96
+ appleIap: "IAPPay",
96
97
  apple: "AppleSignin",
97
98
  appsflyer: "AppsFlyerManager",
98
99
  firebase: "FirebaseManager",
@@ -100,6 +101,16 @@ export const IOS_PLUGIN_FOLDER_BY_SUBKEY: Record<string, string> = {
100
101
  facebookdata: "FacebookManager",
101
102
  };
102
103
 
104
+ const IOS_PLUGIN_ORDER = [
105
+ "GuestSignin",
106
+ "UI",
107
+ "IAPPay",
108
+ "AppsFlyerManager",
109
+ "FacebookSignin",
110
+ "GoogleSignin",
111
+ "AppleSignin",
112
+ ] as const;
113
+
103
114
  export function enabledIosPluginFolders(config: MeetSdkRemoteConfig): string[] {
104
115
  const folders: string[] = ["UI"];
105
116
  for (const [scope, bucket] of Object.entries(config.sdkModules)) {
@@ -111,7 +122,13 @@ export function enabledIosPluginFolders(config: MeetSdkRemoteConfig): string[] {
111
122
  if (folder) folders.push(folder);
112
123
  }
113
124
  }
114
- return [...new Set(folders)];
125
+ const unique = [...new Set(folders)];
126
+ return unique.sort((a, b) => {
127
+ const ai = IOS_PLUGIN_ORDER.indexOf(a as (typeof IOS_PLUGIN_ORDER)[number]);
128
+ const bi = IOS_PLUGIN_ORDER.indexOf(b as (typeof IOS_PLUGIN_ORDER)[number]);
129
+ if (ai !== -1 || bi !== -1) return (ai === -1 ? Number.MAX_SAFE_INTEGER : ai) - (bi === -1 ? Number.MAX_SAFE_INTEGER : bi);
130
+ return unique.indexOf(a) - unique.indexOf(b);
131
+ });
115
132
  }
116
133
 
117
134
  export function unsupportedIosModuleKeys(config: MeetSdkRemoteConfig): string[] {
@@ -21,13 +21,6 @@ export function addPlistParam(data: Record<string, unknown>, key: string, value:
21
21
  data[key] = value;
22
22
  }
23
23
 
24
- export function setAppTransportSecurity(data: Record<string, unknown>, open: boolean): void {
25
- const security =
26
- (data.NSAppTransportSecurity as Record<string, unknown> | undefined) ?? {};
27
- security.NSAllowsArbitraryLoads = open;
28
- data.NSAppTransportSecurity = security;
29
- }
30
-
31
24
  export function addQueriesScheme(data: Record<string, unknown>, scheme: string): void {
32
25
  if (!scheme) return;
33
26
  const schemes = Array.isArray(data.LSApplicationQueriesSchemes)