peachsim 0.1.1625 → 0.1.1640

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 (169) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +15 -2
  3. package/cli/app-config.ts +18 -6
  4. package/cli/app-fonts.ts +37 -17
  5. package/cli/app-stubs.ts +284 -20
  6. package/cli/bridge-flow-runner.ts +66 -45
  7. package/cli/cloud-client.ts +60 -40
  8. package/cli/command-registry.ts +1 -0
  9. package/cli/commands/control.ts +283 -49
  10. package/cli/commands/doctor.ts +30 -189
  11. package/cli/commands/flow.ts +79 -11
  12. package/cli/commands/inspect/core.ts +10 -5
  13. package/cli/commands/inspect/settling.ts +14 -2
  14. package/cli/commands/inspect/shared.ts +9 -4
  15. package/cli/commands/inspect/wait-ready.ts +12 -0
  16. package/cli/commands/inspect.ts +91 -50
  17. package/cli/commands/install-desktop.ts +1 -0
  18. package/cli/commands/maestro-compare.ts +97 -38
  19. package/cli/commands/maestro.ts +9 -1
  20. package/cli/commands/preview.ts +1 -1
  21. package/cli/commands/record.ts +118 -48
  22. package/cli/commands/screenshot.ts +23 -1
  23. package/cli/commands/serve.ts +7 -2
  24. package/cli/commands/setup.ts +19 -42
  25. package/cli/commands/swift.ts +14 -3
  26. package/cli/commands/upload.ts +93 -48
  27. package/cli/desktop-companion.ts +102 -17
  28. package/cli/drivers/desktop.ts +14 -1
  29. package/cli/drivers/playwright-sim-host.ts +103 -45
  30. package/cli/drivers/playwright.ts +9 -8
  31. package/cli/drivers/types.ts +5 -0
  32. package/cli/maestro-accessibility.ts +1 -1
  33. package/cli/maestro-compare.ts +84 -12
  34. package/cli/main.ts +3 -2
  35. package/cli/outbound-endpoints.ts +20 -6
  36. package/cli/pause-aware-timeout.ts +106 -0
  37. package/cli/scene-video.ts +89 -0
  38. package/cli/ws-bridge.ts +37 -19
  39. package/detox/attempt-events.cjs +66 -5
  40. package/detox/attempt-events.d.cts +7 -0
  41. package/detox/expectations.ts +7 -3
  42. package/detox/index.ts +269 -170
  43. package/detox/motion-change.cjs +206 -21
  44. package/detox/motion-change.d.cts +39 -2
  45. package/detox/navigation-lifecycle.ts +35 -3
  46. package/dist-lib/agent-daemon-client.cjs +1 -1
  47. package/dist-lib/agent-events.cjs +1 -1
  48. package/dist-lib/attached-projects.cjs +1 -1
  49. package/dist-lib/auth/shared-session.cjs +1 -1
  50. package/dist-lib/backend-origin.cjs +8 -7
  51. package/dist-lib/beta.cjs +1 -1
  52. package/dist-lib/beta.mjs +1 -1
  53. package/dist-lib/bridge-constants.cjs +13 -1
  54. package/dist-lib/bridge-contract-input.cjs +1 -1
  55. package/dist-lib/bridge-contract-input.mjs +1 -1
  56. package/dist-lib/bridge-contract.cjs +14 -8
  57. package/dist-lib/bridge-contract.mjs +13 -7
  58. package/dist-lib/bundle-channel.cjs +11887 -7900
  59. package/dist-lib/capture-contract.cjs +1 -1
  60. package/dist-lib/capture-contract.mjs +1 -1
  61. package/dist-lib/cloud-contract.cjs +1 -1
  62. package/dist-lib/cloud-contract.mjs +1 -1
  63. package/dist-lib/cloud-test-args.cjs +1 -1
  64. package/dist-lib/cloud-test-args.mjs +1 -1
  65. package/dist-lib/cloud.cjs +1 -1
  66. package/dist-lib/cloud.mjs +1 -1
  67. package/dist-lib/config.cjs +6 -3
  68. package/dist-lib/config.mjs +6 -3
  69. package/dist-lib/detox/index.cjs +1379 -725
  70. package/dist-lib/dev-bundle-resolution.cjs +14 -2
  71. package/dist-lib/expo-swift-bundle.cjs +9341 -5462
  72. package/dist-lib/expo-swift-metadata.cjs +11 -7
  73. package/dist-lib/expo-swift-metadata.mjs +11 -7
  74. package/dist-lib/home-paths.cjs +32 -3
  75. package/dist-lib/host/bridge-host.cjs +50204 -7258
  76. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  77. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  78. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  79. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  80. package/dist-lib/host/websocket-proxy.cjs +1 -1
  81. package/dist-lib/index.cjs +3541 -448
  82. package/dist-lib/jump-to-source-babel.cjs +1 -1
  83. package/dist-lib/jump-to-source-native.cjs +1 -1
  84. package/dist-lib/kotlin-host.cjs +1 -1
  85. package/dist-lib/menu.cjs +1 -1
  86. package/dist-lib/menu.mjs +1 -1
  87. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  88. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  89. package/dist-lib/metro-production-bundle.cjs +1 -1
  90. package/dist-lib/metro-production-bundle.mjs +1 -1
  91. package/dist-lib/metro.cjs +2931 -104
  92. package/dist-lib/native-app-identity-project.cjs +289 -49
  93. package/dist-lib/native-app-identity-project.mjs +289 -49
  94. package/dist-lib/native-app-identity.cjs +77 -26
  95. package/dist-lib/native-app-identity.mjs +76 -26
  96. package/dist-lib/native-firebase-metadata.cjs +1 -1
  97. package/dist-lib/native-firebase-metadata.mjs +1 -1
  98. package/dist-lib/plist.cjs +1 -1
  99. package/dist-lib/plist.mjs +1 -1
  100. package/dist-lib/profiles.cjs +1 -1
  101. package/dist-lib/public-brand.cjs +1 -1
  102. package/dist-lib/react-native-host-modules.cjs +6 -2
  103. package/dist-lib/react-native-host-modules.mjs +6 -2
  104. package/dist-lib/scripts/dev-server-scanner.cjs +22 -8
  105. package/dist-lib/sdk.cjs +27 -11
  106. package/dist-lib/sdk.mjs +27 -10
  107. package/dist-lib/skills.cjs +72201 -26208
  108. package/dist-lib/swift-compile.cjs +1007 -140
  109. package/dist-lib/swift-compile.mjs +1049 -174
  110. package/dist-lib/swift-package.cjs +12 -3
  111. package/dist-lib/swift-package.mjs +12 -3
  112. package/dist-lib/swift-submit.cjs +13 -5
  113. package/dist-lib/swift-submit.mjs +11 -5
  114. package/dist-lib/swift-toolchain.cjs +423 -33
  115. package/dist-lib/swift.cjs +1 -1
  116. package/dist-lib/vite-swift.cjs +8628 -5268
  117. package/dist-lib/vite.cjs +2859 -12
  118. package/dist-lib/worklet-executable.cjs +14 -2
  119. package/dist-lib/worklet-executable.mjs +14 -2
  120. package/kotlin/AppSources/dev/peach/app/PeachDrawable.kt +21 -14
  121. package/kotlin/Sources/androidx/annotation/DrawableRes.kt +14 -0
  122. package/package.json +1 -1
  123. package/scripts/dev-server-scanner.ts +2 -1
  124. package/skills/peach-perf/SKILL.md +11 -5
  125. package/skills/peach-setup/SKILL.md +16 -19
  126. package/src/backend-origin.ts +13 -6
  127. package/src/bridge-constants.ts +11 -0
  128. package/src/bridge-contract.ts +22 -34
  129. package/src/config.ts +15 -0
  130. package/src/desktop-host-delivery.ts +5 -1
  131. package/src/dev-bundle-resolution.ts +2 -1
  132. package/src/expo-manifest-body.ts +13 -0
  133. package/src/expo-swift-host.ts +196 -49
  134. package/src/expo-swift-ready.ts +78 -0
  135. package/src/expoKotlinContract.ts +4 -7
  136. package/src/expoSwiftContract.ts +17 -6
  137. package/src/home-paths.ts +48 -2
  138. package/src/host/bridge-host.ts +5 -2
  139. package/src/host/staged-host-files.ts +9 -0
  140. package/src/native-app-identity-project.ts +27 -6
  141. package/src/native-app-identity.ts +91 -4
  142. package/src/native-firebase-config.ts +209 -13
  143. package/src/nativeAppIconContract.ts +1 -4
  144. package/src/output-lock-stdio.ts +36 -0
  145. package/src/process-group.ts +25 -2
  146. package/src/react-native-bridge-modules.ts +431 -0
  147. package/src/react-native-host-modules.ts +8 -1
  148. package/src/settings-bundle.ts +1 -4
  149. package/src/swift-binary-modules.ts +2 -2
  150. package/src/swift-compile.ts +918 -109
  151. package/src/swift-compiler-digest.ts +14 -0
  152. package/src/swift-distribution.lock.json +24 -12
  153. package/src/swift-distribution.ts +103 -4
  154. package/src/swift-host.ts +180 -55
  155. package/src/swift-icu.ts +27 -13
  156. package/src/swift-objc-compile.ts +355 -0
  157. package/src/swift-objc-sdk.ts +821 -27
  158. package/src/swift-objc-standin.ts +148 -14
  159. package/src/swift-package-manifest.ts +60 -7
  160. package/src/swift-package.ts +15 -1
  161. package/src/swift-packages.ts +154 -81
  162. package/src/swift-standin-emit.ts +96 -15
  163. package/src/swift-standins.ts +530 -116
  164. package/src/swift-submit.ts +13 -5
  165. package/src/swift-toolchain.ts +500 -42
  166. package/src/vite-plugin.ts +12 -1
  167. package/src/worker-system-chunks.ts +11 -12
  168. package/src/worklet-executable.ts +19 -1
  169. package/src/xcode-project.ts +270 -30
@@ -1,4 +1,4 @@
1
- /*! peach v0.1.1625 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
1
+ /*! peach v0.1.1640 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
 
3
3
  // src/native-app-identity-project.ts
4
4
  import fs2 from "node:fs";
@@ -187,10 +187,12 @@ function androidMergedResourceValuesDirectory(manifestFile) {
187
187
  return `${intermediates}incremental/${variant}/merge${taskVariant}Resources/merged.dir`;
188
188
  }
189
189
 
190
- // src/nativeAppIconContract.ts
190
+ // src/is-record.ts
191
191
  function isRecord(value) {
192
192
  return typeof value === "object" && value !== null && !Array.isArray(value);
193
193
  }
194
+
195
+ // src/nativeAppIconContract.ts
194
196
  function resolveNativeAppIconArtwork(resources, readText, resourceUri, icons, primaryName, alternateNames, resolveReference) {
195
197
  const members = new Set(resources);
196
198
  const dictionary = isRecord(icons) ? icons : {};
@@ -444,12 +446,30 @@ function visitXcodeTargetMembers(objects, targetId, resolvePath, filesUnder, joi
444
446
  }
445
447
 
446
448
  // src/native-app-identity.ts
447
- function isRecord2(value) {
448
- return typeof value === "object" && value !== null && !Array.isArray(value);
449
- }
450
449
  function nonEmptyString(value) {
451
450
  return typeof value === "string" && value.length > 0 ? value : null;
452
451
  }
452
+ function readGoogleSignInConfiguration(plist3, resources) {
453
+ const clientIds = {};
454
+ for (const [file, value] of Object.entries(resources)) {
455
+ if (isRecord(value) && typeof value.CLIENT_ID === "string")
456
+ clientIds[file.split("/").pop()?.replace(/\.plist$/, "") ?? file] = value.CLIENT_ID;
457
+ }
458
+ const urlSchemes = [];
459
+ for (const entry of Array.isArray(plist3.CFBundleURLTypes) ? plist3.CFBundleURLTypes : []) {
460
+ if (!isRecord(entry) || !Array.isArray(entry.CFBundleURLSchemes)) continue;
461
+ for (const scheme of entry.CFBundleURLSchemes)
462
+ if (typeof scheme === "string") urlSchemes.push(scheme);
463
+ }
464
+ return {
465
+ clientId: plist3.GIDClientID,
466
+ serverClientId: plist3.GIDServerClientID,
467
+ hostedDomain: plist3.GIDHostedDomain,
468
+ openIDRealm: plist3.GIDOpenIDRealm,
469
+ urlSchemes,
470
+ clientIds
471
+ };
472
+ }
453
473
  function plistString(plist3, key) {
454
474
  const match = plist3.match(new RegExp(`<key>${key}</key>\\s*<string>([^<]*)</string>`));
455
475
  return match ? match[1].trim() : null;
@@ -545,14 +565,14 @@ function nativeAppIdentityFromIos(files, parseInfoPlist, iosTarget, resourceUri)
545
565
  let objects = {};
546
566
  try {
547
567
  const parsed = parseOpenStepPlist(pbxproj);
548
- if (isRecord2(parsed)) {
549
- objects = isRecord2(parsed.objects) ? parsed.objects : parsed;
568
+ if (isRecord(parsed)) {
569
+ objects = isRecord(parsed.objects) ? parsed.objects : parsed;
550
570
  }
551
571
  } catch {
552
572
  }
553
573
  const targets = [];
554
574
  for (const [id, obj] of Object.entries(objects)) {
555
- if (isRecord2(obj) && obj.isa === "PBXNativeTarget" && typeof obj.name === "string") {
575
+ if (isRecord(obj) && obj.isa === "PBXNativeTarget" && typeof obj.name === "string") {
556
576
  targets.push({
557
577
  id,
558
578
  name: obj.name,
@@ -598,13 +618,13 @@ function nativeAppIdentityFromIos(files, parseInfoPlist, iosTarget, resourceUri)
598
618
  PRODUCT_NAME: targetName
599
619
  };
600
620
  for (const obj of Object.values(objects)) {
601
- if (isRecord2(obj) && obj.isa === "PBXProject" && typeof obj.buildConfigurationList === "string") {
621
+ if (isRecord(obj) && obj.isa === "PBXProject" && typeof obj.buildConfigurationList === "string") {
602
622
  const listObj = objects[obj.buildConfigurationList];
603
- if (isRecord2(listObj) && Array.isArray(listObj.buildConfigurations)) {
623
+ if (isRecord(listObj) && Array.isArray(listObj.buildConfigurations)) {
604
624
  for (const configId of listObj.buildConfigurations) {
605
625
  if (typeof configId === "string") {
606
626
  const configObj = objects[configId];
607
- if (isRecord2(configObj) && configObj.name === "Release" && isRecord2(configObj.buildSettings)) {
627
+ if (isRecord(configObj) && configObj.name === "Release" && isRecord(configObj.buildSettings)) {
608
628
  for (const [k, v] of Object.entries(configObj.buildSettings)) {
609
629
  if (typeof v === "string") settings[k] = v;
610
630
  }
@@ -616,11 +636,11 @@ function nativeAppIdentityFromIos(files, parseInfoPlist, iosTarget, resourceUri)
616
636
  }
617
637
  if (selectedTarget?.buildConfigurationList) {
618
638
  const listObj = objects[selectedTarget.buildConfigurationList];
619
- if (isRecord2(listObj) && Array.isArray(listObj.buildConfigurations)) {
639
+ if (isRecord(listObj) && Array.isArray(listObj.buildConfigurations)) {
620
640
  for (const configId of listObj.buildConfigurations) {
621
641
  if (typeof configId === "string") {
622
642
  const configObj = objects[configId];
623
- if (isRecord2(configObj) && configObj.name === "Release" && isRecord2(configObj.buildSettings)) {
643
+ if (isRecord(configObj) && configObj.name === "Release" && isRecord(configObj.buildSettings)) {
624
644
  for (const [k, v] of Object.entries(configObj.buildSettings)) {
625
645
  if (typeof v === "string") settings[k] = v;
626
646
  }
@@ -671,7 +691,7 @@ function nativeAppIdentityFromIos(files, parseInfoPlist, iosTarget, resourceUri)
671
691
  if (!bundleName) return null;
672
692
  const applicationName = identityFieldFrom(settings, plistString(plist3, "CFBundleDisplayName"), void 0) ?? bundleName;
673
693
  const dictionary = parseInfoPlist(plist3);
674
- if (!isRecord2(dictionary)) throw new Error("native app Info.plist is not a dictionary");
694
+ if (!isRecord(dictionary)) throw new Error("native app Info.plist is not a dictionary");
675
695
  const declaredDisplayName = dictionary.CFBundleDisplayName;
676
696
  const applicationDisplayName = typeof declaredDisplayName === "string" ? resolveBuildSetting(declaredDisplayName, settings) : void 0;
677
697
  if (applicationDisplayName === null)
@@ -684,9 +704,9 @@ function nativeAppIdentityFromIos(files, parseInfoPlist, iosTarget, resourceUri)
684
704
  if (dtPlatformVersion === null)
685
705
  throw new Error("native app Info.plist DTPlatformVersion is unresolved");
686
706
  const icons = dictionary.CFBundleIcons;
687
- const alternates = isRecord2(icons) ? icons.CFBundleAlternateIcons : void 0;
707
+ const alternates = isRecord(icons) ? icons.CFBundleAlternateIcons : void 0;
688
708
  const alternateIconNames = /* @__PURE__ */ new Set();
689
- for (const name of isRecord2(alternates) ? Object.keys(alternates) : []) {
709
+ for (const name of isRecord(alternates) ? Object.keys(alternates) : []) {
690
710
  const resolved = resolveBuildSetting(name, settings);
691
711
  if (resolved === null) throw new Error("native alternate icon name is unresolved");
692
712
  alternateIconNames.add(resolved);
@@ -759,6 +779,12 @@ function nativeAppIdentityFromIos(files, parseInfoPlist, iosTarget, resourceUri)
759
779
  if (resolved === null) throw new Error(`native app Info.plist ${key} is unresolved`);
760
780
  permissionUsageDescriptions[key] = resolved;
761
781
  }
782
+ const infoPlistStrings = {};
783
+ for (const [key, value] of Object.entries(dictionary)) {
784
+ if (typeof value !== "string") continue;
785
+ const resolved = resolveBuildSetting(value, settings);
786
+ if (resolved !== null) infoPlistStrings[key] = resolved;
787
+ }
762
788
  if (settings.GENERATE_INFOPLIST_FILE === "YES") {
763
789
  for (const [setting, value] of Object.entries(settings)) {
764
790
  if (!/^INFOPLIST_KEY_NS.*UsageDescription$/.test(setting)) continue;
@@ -784,11 +810,11 @@ function nativeAppIdentityFromIos(files, parseInfoPlist, iosTarget, resourceUri)
784
810
  return `${base.startsWith("/") ? "/" : ""}${segments.join("/")}`;
785
811
  };
786
812
  const project = Object.values(objects).find(
787
- (object) => isRecord2(object) && object.isa === "PBXProject"
813
+ (object) => isRecord(object) && object.isa === "PBXProject"
788
814
  );
789
815
  const projectDir = join(
790
816
  pbxprojPath.replace(/(?:^|\/)[^/]+\.xcodeproj\/project\.pbxproj$/, ""),
791
- isRecord2(project) && typeof project.projectDirPath === "string" ? project.projectDirPath : ""
817
+ isRecord(project) && typeof project.projectDirPath === "string" ? project.projectDirPath : ""
792
818
  );
793
819
  const paths = Object.keys(files);
794
820
  visitXcodeTargetMembers(
@@ -819,12 +845,22 @@ function nativeAppIdentityFromIos(files, parseInfoPlist, iosTarget, resourceUri)
819
845
  ...rootModuleName === void 0 ? {} : { rootModuleName },
820
846
  ...rootViewBackgroundColor === void 0 ? {} : { rootViewBackgroundColor },
821
847
  ...designRequiresCompatibility ? { designRequiresCompatibility } : {},
848
+ ...typeof dictionary.UIStatusBarHidden === "boolean" ? { statusBarHidden: dictionary.UIStatusBarHidden } : {},
849
+ ...typeof dictionary.UIViewControllerBasedStatusBarAppearance === "boolean" ? {
850
+ viewControllerBasedStatusBarAppearance: dictionary.UIViewControllerBasedStatusBarAppearance
851
+ } : {},
822
852
  ...dtPlatformVersion === void 0 ? {} : { dtPlatformVersion },
823
853
  bundleName,
824
854
  appVersion,
825
855
  buildVersion,
826
856
  bundleIdentifier,
827
857
  platform: "ios",
858
+ googleSignIn: readGoogleSignInConfiguration(
859
+ dictionary,
860
+ Object.fromEntries(
861
+ [...resources].filter((file) => file.endsWith(".plist") && files[file]).map((file) => [file, parseInfoPlist(files[file])])
862
+ )
863
+ ),
828
864
  supportedInterfaceOrientations,
829
865
  ipadSupportedInterfaceOrientations,
830
866
  ...defaultScreenOrientationMask === void 0 ? {} : { defaultScreenOrientationMask },
@@ -846,6 +882,7 @@ function nativeAppIdentityFromIos(files, parseInfoPlist, iosTarget, resourceUri)
846
882
  )
847
883
  } : {},
848
884
  permissionUsageDescriptions,
885
+ infoPlistStrings,
849
886
  urlQuerySchemes,
850
887
  ...shareIntoAppGroupId === void 0 ? {} : { shareIntoAppGroupId },
851
888
  ...rtcAppGroupIdentifier === void 0 ? {} : { rtcAppGroupIdentifier },
@@ -890,6 +927,8 @@ function parsePlistSource(source) {
890
927
  }
891
928
 
892
929
  // src/xcode-project.ts
930
+ import { execFileSync } from "node:child_process";
931
+ import { createHash } from "node:crypto";
893
932
  import fs from "node:fs";
894
933
  import path2 from "node:path";
895
934
  import plist2 from "plist";
@@ -1497,33 +1536,131 @@ function expand(value, lookup) {
1497
1536
  }
1498
1537
  );
1499
1538
  }
1500
- function targetMembers(ref, settings, options = {}) {
1539
+ var preparedSourcePhases = /* @__PURE__ */ new Map();
1540
+ function targetMembers(ref, settings, options, settingKeys, projectInputs) {
1501
1541
  const { project, target, id: targetId } = ref;
1502
1542
  const targetName = str(target.name) ?? targetId;
1503
1543
  const sources = /* @__PURE__ */ new Set();
1504
1544
  const allSources = /* @__PURE__ */ new Set();
1505
1545
  const resources = /* @__PURE__ */ new Set();
1506
1546
  const scriptForOutput = /* @__PURE__ */ new Map();
1507
- const noteScriptOutput = (raw, script) => {
1508
- const expanded = expand(raw, settings);
1509
- if (!expanded.endsWith(".swift")) return;
1510
- const absolute = path2.isAbsolute(expanded) ? path2.normalize(expanded) : path2.resolve(project.projectDir, expanded);
1511
- if (!scriptForOutput.has(absolute)) scriptForOutput.set(absolute, script);
1512
- };
1513
1547
  for (const phaseId of list(target.buildPhases)) {
1514
1548
  const phase = project.object(phaseId);
1515
1549
  if (phase?.isa !== "PBXShellScriptBuildPhase") continue;
1516
1550
  const script = str(phase.name) ?? phaseId;
1517
- for (const raw of list(phase.outputPaths)) noteScriptOutput(raw, script);
1518
- for (const listPath of list(phase.outputFileListPaths)) {
1519
- const expandedList = expand(listPath, settings);
1520
- const absoluteList = path2.isAbsolute(expandedList) ? expandedList : path2.resolve(project.projectDir, expandedList);
1521
- if (!fs.existsSync(absoluteList)) continue;
1522
- for (const line of fs.readFileSync(absoluteList, "utf8").split("\n")) {
1523
- const trimmed = line.trim();
1524
- if (trimmed === "" || trimmed.startsWith("#")) continue;
1525
- noteScriptOutput(trimmed, script);
1551
+ const absolute = (raw) => path2.resolve(project.projectDir, expand(raw, settings));
1552
+ const inputs = list(phase.inputPaths).map(absolute);
1553
+ const outputs = list(phase.outputPaths).map(absolute);
1554
+ const fileLists = /* @__PURE__ */ new Map();
1555
+ for (const kind of ["INPUT", "OUTPUT"]) {
1556
+ const lists = list(
1557
+ kind === "INPUT" ? phase.inputFileListPaths : phase.outputFileListPaths
1558
+ ).map((raw) => {
1559
+ const file = absolute(raw);
1560
+ if (!fs.existsSync(file)) {
1561
+ return { file, entries: [] };
1562
+ }
1563
+ const entries = fs.readFileSync(file, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line !== "" && !line.startsWith("#")).map(absolute);
1564
+ return { file, entries };
1565
+ });
1566
+ fileLists.set(kind, lists);
1567
+ }
1568
+ const allOutputs = [
1569
+ ...outputs,
1570
+ ...fileLists.get("OUTPUT").flatMap((item) => item.entries)
1571
+ ];
1572
+ for (const output of allOutputs)
1573
+ if (output.endsWith(".swift") && !scriptForOutput.has(output))
1574
+ scriptForOutput.set(output, script);
1575
+ const inputFiles = [
1576
+ ...inputs,
1577
+ ...fileLists.get("INPUT").flatMap((item) => [item.file, ...item.entries]),
1578
+ ...fileLists.get("OUTPUT").map((item) => item.file)
1579
+ ];
1580
+ if (allOutputs.some((file) => file.endsWith(".swift"))) {
1581
+ for (const file of inputFiles) if (fs.existsSync(file)) projectInputs.add(file);
1582
+ }
1583
+ if (options.prepareGeneratedSources && options.requireSources !== false && allOutputs.some((file) => file.endsWith(".swift"))) {
1584
+ const phaseDir = path2.join(settings("TARGET_TEMP_DIR"), `Script-${phaseId}`);
1585
+ for (const lists of fileLists.values())
1586
+ for (const { file } of lists)
1587
+ if (!fs.existsSync(file))
1588
+ throw new Error(
1589
+ `${targetName}: Run Script "${script}" missing file list ${file}`
1590
+ );
1591
+ const env = {
1592
+ ...process.env,
1593
+ ...Object.fromEntries(
1594
+ [...settingKeys].filter((key2) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(key2)).map((key2) => [key2, settings(key2)])
1595
+ )
1596
+ };
1597
+ const declared = { INPUT: inputs, OUTPUT: outputs };
1598
+ for (const kind of ["INPUT", "OUTPUT"]) {
1599
+ env[`SCRIPT_${kind}_FILE_COUNT`] = String(declared[kind].length);
1600
+ declared[kind].forEach((file, index) => {
1601
+ env[`SCRIPT_${kind}_FILE_${index}`] = file;
1602
+ });
1603
+ const lists = fileLists.get(kind);
1604
+ env[`SCRIPT_${kind}_FILE_LIST_COUNT`] = String(lists.length);
1605
+ lists.forEach((_item, index) => {
1606
+ env[`SCRIPT_${kind}_FILE_LIST_${index}`] = path2.join(
1607
+ phaseDir,
1608
+ `${kind}-${index}.xcfilelist`
1609
+ );
1610
+ });
1611
+ }
1612
+ const signature = createHash("sha256").update(
1613
+ JSON.stringify([phase, [...settingKeys].map((key2) => [key2, settings(key2)])])
1614
+ );
1615
+ for (const file of inputFiles) {
1616
+ signature.update(file);
1617
+ if (fs.existsSync(file)) {
1618
+ const stat = fs.statSync(file);
1619
+ signature.update(`${stat.mtimeMs}:${stat.ctimeMs}:${stat.size}`);
1620
+ } else signature.update("missing");
1526
1621
  }
1622
+ const stamp = signature.digest("hex");
1623
+ const key = `${project.projectFile}:${targetId}:${phaseId}:${settings("CONFIGURATION")}`;
1624
+ if (preparedSourcePhases.get(key) === stamp && allOutputs.every((file) => fs.existsSync(file)))
1625
+ continue;
1626
+ fs.mkdirSync(phaseDir, { recursive: true });
1627
+ fs.mkdirSync(settings("BUILT_PRODUCTS_DIR"), { recursive: true });
1628
+ fs.mkdirSync(settings("DERIVED_FILE_DIR"), { recursive: true });
1629
+ for (const [kind, lists] of fileLists)
1630
+ lists.forEach((item, index) => {
1631
+ fs.writeFileSync(
1632
+ env[`SCRIPT_${kind}_FILE_LIST_${index}`],
1633
+ `${item.entries.join("\n")}
1634
+ `
1635
+ );
1636
+ });
1637
+ try {
1638
+ execFileSync(
1639
+ str(phase.shellPath) ?? "/bin/sh",
1640
+ ["-c", str(phase.shellScript) ?? ""],
1641
+ {
1642
+ cwd: project.projectDir,
1643
+ env,
1644
+ stdio: ["ignore", "pipe", "pipe"],
1645
+ timeout: 12e4
1646
+ }
1647
+ );
1648
+ } catch (error) {
1649
+ const output = error instanceof Error ? `${error.message}
1650
+ ${"stdout" in error ? String(error.stdout) : ""}${"stderr" in error ? String(error.stderr) : ""}` : String(error);
1651
+ throw new Error(
1652
+ `${targetName}: Run Script "${script}" failed preparing generated Swift sources:
1653
+ ${output}`
1654
+ );
1655
+ }
1656
+ const missing = allOutputs.filter(
1657
+ (file) => file.endsWith(".swift") && !fs.existsSync(file)
1658
+ );
1659
+ if (missing.length > 0)
1660
+ throw new Error(
1661
+ `${targetName}: Run Script "${script}" did not produce ${missing.join(", ")}`
1662
+ );
1663
+ preparedSourcePhases.set(key, stamp);
1527
1664
  }
1528
1665
  }
1529
1666
  visitXcodeTargetMembers(
@@ -1713,22 +1850,95 @@ function readXcodeAppTarget(input, targetName, configurationName, options = {})
1713
1850
  SRCROOT: ref.project.projectDir,
1714
1851
  SOURCE_ROOT: ref.project.projectDir,
1715
1852
  PROJECT_DIR: ref.project.projectDir,
1853
+ SYMROOT: path2.join(ref.project.projectDir, ".build/peach-xcode/Build/Products"),
1854
+ BUILD_DIR: "$(SYMROOT)",
1855
+ OBJROOT: path2.join(
1856
+ ref.project.projectDir,
1857
+ ".build/peach-xcode/Build/Intermediates.noindex"
1858
+ ),
1859
+ CONFIGURATION_BUILD_DIR: "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)",
1860
+ BUILT_PRODUCTS_DIR: "$(CONFIGURATION_BUILD_DIR)",
1861
+ TARGET_BUILD_DIR: "$(CONFIGURATION_BUILD_DIR)",
1862
+ PROJECT_TEMP_DIR: "$(OBJROOT)/$(PROJECT_NAME).build",
1863
+ CONFIGURATION_TEMP_DIR: "$(PROJECT_TEMP_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)",
1864
+ TARGET_TEMP_DIR: "$(CONFIGURATION_TEMP_DIR)/$(TARGET_NAME).build",
1865
+ DERIVED_FILE_DIR: "$(TARGET_TEMP_DIR)/DerivedSources",
1866
+ DERIVED_FILES_DIR: "$(DERIVED_FILE_DIR)",
1867
+ PLATFORM_NAME: "iphonesimulator",
1868
+ EFFECTIVE_PLATFORM_NAME: "-iphonesimulator",
1869
+ CURRENT_ARCH: "arm64",
1870
+ ARCHS: "arm64",
1871
+ ACTION: "build",
1716
1872
  DEVELOPMENT_LANGUAGE: str(ref.project.project.developmentRegion) ?? "en"
1717
1873
  },
1718
1874
  options
1719
1875
  );
1720
1876
  for (const file of read) xcconfigs.add(file);
1721
1877
  const swiftVersion = Number.parseFloat(settings2("SWIFT_VERSION") || "5");
1878
+ const members = targetMembers(ref, settings2, options, keys, xcconfigs);
1879
+ const implementations = members.allSources.filter(
1880
+ (file) => /\.(c|cc|cpp|cxx|m|mm)$/.test(file)
1881
+ );
1882
+ const absolute = (file) => path2.resolve(ref.project.projectDir, file);
1883
+ const fileFlags = {};
1884
+ for (const phaseId of list(ref.target.buildPhases)) {
1885
+ const phase = ref.project.object(phaseId);
1886
+ if (phase?.isa !== "PBXSourcesBuildPhase") continue;
1887
+ for (const id of list(phase.files)) {
1888
+ const file = ref.project.object(id);
1889
+ const resolved = ref.project.resolvePath(str(file?.fileRef) ?? "");
1890
+ if (resolved && implementations.includes(resolved))
1891
+ fileFlags[resolved] = settingList(
1892
+ expand(
1893
+ str(isDict(file?.settings) ? file.settings.COMPILER_FLAGS : void 0) ?? "",
1894
+ settings2
1895
+ )
1896
+ );
1897
+ }
1898
+ }
1722
1899
  return {
1723
1900
  settings: settings2,
1724
1901
  keys,
1725
1902
  module: {
1726
1903
  name,
1727
1904
  moduleName: applyOperator(settings2("PRODUCT_MODULE_NAME"), "c99extidentifier"),
1728
- ...targetMembers(ref, settings2, options),
1905
+ ...members,
1729
1906
  languageMode: swiftVersion >= 6 ? 6 : 5,
1730
1907
  mainActorIsolation: settings2("SWIFT_DEFAULT_ACTOR_ISOLATION") === "MainActor",
1731
- defines: compilationConditions(settings2)
1908
+ defines: compilationConditions(settings2),
1909
+ iosDeploymentTarget: settings2("IPHONEOS_DEPLOYMENT_TARGET") || null,
1910
+ ...implementations.some((file) => /\.mm?$/.test(file)) ? {
1911
+ objc: {
1912
+ headers: Object.keys(ref.project.objects).flatMap((id) => {
1913
+ const file = ref.project.resolvePath(id);
1914
+ return file && /\.(h|hh|hpp|hxx|pch)$/.test(file) && fs.existsSync(file) ? [file] : [];
1915
+ }),
1916
+ prefixHeader: settings2("GCC_PREFIX_HEADER") ? absolute(settings2("GCC_PREFIX_HEADER")) : null,
1917
+ bridgingHeader: settings2("SWIFT_OBJC_BRIDGING_HEADER") ? absolute(settings2("SWIFT_OBJC_BRIDGING_HEADER")) : null,
1918
+ headerSearchPaths: [
1919
+ ...settingList(settings2("HEADER_SEARCH_PATHS")),
1920
+ ...settingList(settings2("USER_HEADER_SEARCH_PATHS"))
1921
+ ].map(absolute),
1922
+ frameworkSearchPaths: settingList(settings2("FRAMEWORK_SEARCH_PATHS")).map(
1923
+ absolute
1924
+ ),
1925
+ flags: [
1926
+ ...settings2("CLANG_ENABLE_OBJC_ARC") === "YES" ? ["-fobjc-arc"] : [],
1927
+ ...settings2("CLANG_ENABLE_OBJC_WEAK") === "YES" ? ["-fobjc-weak"] : [],
1928
+ ...settings2("CLANG_ENABLE_MODULES") === "YES" ? ["-fmodules"] : [],
1929
+ ...settings2("GCC_C_LANGUAGE_STANDARD") ? [`-std=${settings2("GCC_C_LANGUAGE_STANDARD")}`] : [],
1930
+ ...settingList(settings2("GCC_PREPROCESSOR_DEFINITIONS")).map(
1931
+ (value) => `-D${value}`
1932
+ ),
1933
+ ...settingList(settings2("OTHER_CFLAGS"))
1934
+ ],
1935
+ cxxFlags: [
1936
+ ...settings2("CLANG_CXX_LANGUAGE_STANDARD") ? [`-std=${settings2("CLANG_CXX_LANGUAGE_STANDARD")}`] : [],
1937
+ ...settingList(settings2("OTHER_CPLUSPLUSFLAGS"))
1938
+ ],
1939
+ fileFlags
1940
+ }
1941
+ } : {}
1732
1942
  }
1733
1943
  };
1734
1944
  };
@@ -1777,6 +1987,23 @@ function readXcodeAppTarget(input, targetName, configurationName, options = {})
1777
1987
  ...projects.flatMap(
1778
1988
  (project) => Object.entries(project.objects).flatMap(([id, entry]) => {
1779
1989
  if (!isDict(entry)) return [];
1990
+ if (entry.isa === "PBXFileSystemSynchronizedRootGroup") {
1991
+ const folder = project.resolvePath(id);
1992
+ const pending = folder ? [folder] : [];
1993
+ const packages = [];
1994
+ while (pending.length > 0) {
1995
+ const dir = pending.pop();
1996
+ if (fs.existsSync(path2.join(dir, "Package.swift"))) {
1997
+ packages.push(dir);
1998
+ continue;
1999
+ }
2000
+ if (!isDirectory(dir)) continue;
2001
+ for (const child of fs.readdirSync(dir, { withFileTypes: true }))
2002
+ if (child.isDirectory() && !child.name.startsWith("."))
2003
+ pending.push(path2.join(dir, child.name));
2004
+ }
2005
+ return packages;
2006
+ }
1780
2007
  const candidate = entry.isa === "XCLocalSwiftPackageReference" ? path2.resolve(project.projectDir, str(entry.relativePath) ?? "") : entry.isa === "PBXFileReference" ? project.resolvePath(id) : null;
1781
2008
  return candidate && fs.existsSync(path2.join(candidate, "Package.swift")) ? [candidate] : [];
1782
2009
  })
@@ -1831,6 +2058,7 @@ function readXcodeAppTarget(input, targetName, configurationName, options = {})
1831
2058
  "swiftpm",
1832
2059
  "Package.resolved"
1833
2060
  );
2061
+ const packageResolved = fs.existsSync(resolvedFile) ? [fs.realpathSync(resolvedFile)] : [...new Set(localPackageDirs.map((dir) => path2.join(dir, "Package.resolved")))].filter((file) => fs.existsSync(file)).map((file) => fs.realpathSync(file)).sort();
1834
2062
  const used = order.map((ref) => ref.project);
1835
2063
  return {
1836
2064
  ...module,
@@ -1856,7 +2084,7 @@ function readXcodeAppTarget(input, targetName, configurationName, options = {})
1856
2084
  ...new Set(localPackageDirs.map((dir) => fs.realpathSync(dir)))
1857
2085
  ].sort(),
1858
2086
  binaryFrameworks: [...binaryFrameworks].map(([name, file]) => ({ name, path: file })).sort((left, right) => left.name.localeCompare(right.name)),
1859
- packageResolved: fs.existsSync(resolvedFile) ? resolvedFile : null,
2087
+ packageResolved,
1860
2088
  appTargets: appTargetNames,
1861
2089
  configuration,
1862
2090
  settings
@@ -1864,15 +2092,12 @@ function readXcodeAppTarget(input, targetName, configurationName, options = {})
1864
2092
  }
1865
2093
 
1866
2094
  // src/native-app-identity-project.ts
1867
- function isRecord3(value) {
1868
- return typeof value === "object" && value !== null && !Array.isArray(value);
1869
- }
1870
2095
  function nonEmptyString2(value) {
1871
2096
  return typeof value === "string" && value.length > 0 ? value : void 0;
1872
2097
  }
1873
2098
  function readNativeAppIdentityFromXcodeTarget(app, parseInfoPlist = parsePlistSource) {
1874
2099
  const dictionary = parseInfoPlist(app.infoPlist);
1875
- if (!isRecord3(dictionary)) throw new Error("native app Info.plist is not a dictionary");
2100
+ if (!isRecord(dictionary)) throw new Error("native app Info.plist is not a dictionary");
1876
2101
  const settings = app.settings;
1877
2102
  const bundleIdentifier = nonEmptyString2(dictionary.CFBundleIdentifier) ?? nonEmptyString2(settings?.("PRODUCT_BUNDLE_IDENTIFIER"));
1878
2103
  if (!bundleIdentifier) throw new Error("native app has no bundle identifier");
@@ -1889,8 +2114,8 @@ function readNativeAppIdentityFromXcodeTarget(app, parseInfoPlist = parsePlistSo
1889
2114
  const designRequiresCompatibility = dictionary.UIDesignRequiresCompatibility === true;
1890
2115
  const alternateIconNames = /* @__PURE__ */ new Set();
1891
2116
  const icons = dictionary.CFBundleIcons;
1892
- const alternates = isRecord3(icons) ? icons.CFBundleAlternateIcons : void 0;
1893
- if (isRecord3(alternates)) {
2117
+ const alternates = isRecord(icons) ? icons.CFBundleAlternateIcons : void 0;
2118
+ if (isRecord(alternates)) {
1894
2119
  for (const name of Object.keys(alternates)) {
1895
2120
  if (name) alternateIconNames.add(name);
1896
2121
  }
@@ -1907,6 +2132,10 @@ function readNativeAppIdentityFromXcodeTarget(app, parseInfoPlist = parsePlistSo
1907
2132
  }
1908
2133
  permissionUsageDescriptions[key] = value;
1909
2134
  }
2135
+ const infoPlistStrings = {};
2136
+ for (const [key, value] of Object.entries(dictionary)) {
2137
+ if (typeof value === "string") infoPlistStrings[key] = value;
2138
+ }
1910
2139
  const querySchemes = dictionary.LSApplicationQueriesSchemes;
1911
2140
  const urlQuerySchemes = Array.isArray(querySchemes) ? querySchemes : [];
1912
2141
  const intentIds = dictionary.OneAppIntentIdentifiers;
@@ -1934,12 +2163,22 @@ function readNativeAppIdentityFromXcodeTarget(app, parseInfoPlist = parsePlistSo
1934
2163
  ...rootModuleName ? { rootModuleName } : {},
1935
2164
  ...rootViewBackgroundColor !== void 0 ? { rootViewBackgroundColor } : {},
1936
2165
  ...designRequiresCompatibility ? { designRequiresCompatibility } : {},
2166
+ ...typeof dictionary.UIStatusBarHidden === "boolean" ? { statusBarHidden: dictionary.UIStatusBarHidden } : {},
2167
+ ...typeof dictionary.UIViewControllerBasedStatusBarAppearance === "boolean" ? {
2168
+ viewControllerBasedStatusBarAppearance: dictionary.UIViewControllerBasedStatusBarAppearance
2169
+ } : {},
1937
2170
  ...typeof dictionary.DTPlatformVersion === "string" ? { dtPlatformVersion: dictionary.DTPlatformVersion } : {},
1938
2171
  bundleName,
1939
2172
  appVersion,
1940
2173
  buildVersion,
1941
2174
  bundleIdentifier,
1942
2175
  platform: "ios",
2176
+ googleSignIn: readGoogleSignInConfiguration(
2177
+ dictionary,
2178
+ Object.fromEntries(
2179
+ app.resources.filter((file) => file.endsWith(".plist")).map((file) => [file, parseInfoPlist(fs2.readFileSync(file, "utf8"))])
2180
+ )
2181
+ ),
1943
2182
  supportedInterfaceOrientations,
1944
2183
  ipadSupportedInterfaceOrientations,
1945
2184
  ...defaultScreenOrientationMask ? { defaultScreenOrientationMask } : {},
@@ -1958,6 +2197,7 @@ function readNativeAppIdentityFromXcodeTarget(app, parseInfoPlist = parsePlistSo
1958
2197
  (value) => value
1959
2198
  ),
1960
2199
  permissionUsageDescriptions,
2200
+ infoPlistStrings,
1961
2201
  urlQuerySchemes,
1962
2202
  ...shareIntoAppGroupId ? { shareIntoAppGroupId } : {},
1963
2203
  ...rtcAppGroupIdentifier ? { rtcAppGroupIdentifier } : {},
@@ -2107,9 +2347,9 @@ function readIosNativeAppIdentity(projectRoot, parseInfoPlist, iosTarget) {
2107
2347
  const installedManifest = JSON.parse(
2108
2348
  fs2.readFileSync(reanimatedManifestPath, "utf8")
2109
2349
  );
2110
- const installedVersion = isRecord3(installedManifest) ? nonEmptyString2(installedManifest.version) : void 0;
2350
+ const installedVersion = isRecord(installedManifest) ? nonEmptyString2(installedManifest.version) : void 0;
2111
2351
  if (!installedVersion) throw new Error("Reanimated package version is malformed");
2112
- if (installedVersion.startsWith("3.")) return identity;
2352
+ if (Number.parseInt(installedVersion, 10) < 4) return identity;
2113
2353
  const defaults = JSON.parse(
2114
2354
  fs2.readFileSync(
2115
2355
  path3.join(
@@ -2119,11 +2359,11 @@ function readIosNativeAppIdentity(projectRoot, parseInfoPlist, iosTarget) {
2119
2359
  "utf8"
2120
2360
  )
2121
2361
  );
2122
- if (!isRecord3(defaults)) throw new Error("Reanimated static flags are malformed");
2362
+ if (!isRecord(defaults)) throw new Error("Reanimated static flags are malformed");
2123
2363
  const manifest = JSON.parse(fs2.readFileSync(projectManifestPath, "utf8"));
2124
- const reanimated = isRecord3(manifest) ? manifest.reanimated : void 0;
2125
- const overrides = isRecord3(reanimated) ? reanimated.staticFeatureFlags : void 0;
2126
- if (overrides !== void 0 && !isRecord3(overrides)) {
2364
+ const reanimated = isRecord(manifest) ? manifest.reanimated : void 0;
2365
+ const overrides = isRecord(reanimated) ? reanimated.staticFeatureFlags : void 0;
2366
+ if (overrides !== void 0 && !isRecord(overrides)) {
2127
2367
  throw new Error("Reanimated static flag overrides are malformed");
2128
2368
  }
2129
2369
  const flags = {};