peachsim 0.1.940 → 0.1.1399

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 (396) hide show
  1. package/README.md +28 -22
  2. package/cli/app-catalog.ts +29 -14
  3. package/cli/app-fonts.ts +5 -3
  4. package/cli/bridge-flow-runner.ts +40 -29
  5. package/cli/cloud-client.ts +57 -21
  6. package/cli/cloud-test-tunnel.ts +12 -18
  7. package/cli/commands/agent.ts +1 -1
  8. package/cli/commands/app-fonts.ts +3 -3
  9. package/cli/commands/assert.ts +8 -8
  10. package/cli/commands/auth.ts +8 -3
  11. package/cli/commands/box/bundle-plane.ts +13 -1
  12. package/cli/commands/box.ts +16 -5
  13. package/cli/commands/compat.ts +1 -1
  14. package/cli/commands/config.ts +2 -2
  15. package/cli/commands/control.ts +125 -71
  16. package/cli/commands/cpu-profile.ts +45 -1
  17. package/cli/commands/daemon.ts +131 -33
  18. package/cli/commands/debug.ts +24 -17
  19. package/cli/commands/desktop.ts +7 -1
  20. package/cli/commands/detect.ts +101 -0
  21. package/cli/commands/detox.ts +6 -6
  22. package/cli/commands/device.ts +12 -12
  23. package/cli/commands/electron.ts +32 -14
  24. package/cli/commands/flow.ts +49 -41
  25. package/cli/commands/guest-host.ts +39 -1
  26. package/cli/commands/inspect/core.ts +14 -8
  27. package/cli/commands/inspect/list.ts +1 -1
  28. package/cli/commands/inspect/settle.ts +5 -3
  29. package/cli/commands/inspect/settling.ts +229 -44
  30. package/cli/commands/inspect/wait-idle.ts +3 -2
  31. package/cli/commands/inspect.ts +105 -93
  32. package/cli/commands/install-cli.ts +36 -15
  33. package/cli/commands/install-desktop.ts +68 -195
  34. package/cli/commands/kotlin.ts +6 -5
  35. package/cli/commands/login.ts +5 -5
  36. package/cli/commands/maestro-compare.ts +554 -0
  37. package/cli/commands/maestro-generate.ts +6 -3
  38. package/cli/commands/maestro.ts +22 -0
  39. package/cli/commands/mode.ts +2 -2
  40. package/cli/commands/no-bridge-hint.ts +6 -2
  41. package/cli/commands/platform.ts +35 -6
  42. package/cli/commands/preview.ts +6 -0
  43. package/cli/commands/project-report.ts +10 -12
  44. package/cli/commands/record.ts +37 -37
  45. package/cli/commands/runtime.ts +9 -9
  46. package/cli/commands/screenshot-layers.ts +4 -4
  47. package/cli/commands/screenshot-mode.ts +2 -2
  48. package/cli/commands/screenshot.ts +8 -8
  49. package/cli/commands/screenshots-capture.ts +2 -2
  50. package/cli/commands/serve.ts +9 -12
  51. package/cli/commands/setup.ts +29 -14
  52. package/cli/commands/shell-boolean-mode.ts +2 -2
  53. package/cli/commands/show-touches-mode.ts +2 -2
  54. package/cli/commands/skills.ts +11 -11
  55. package/cli/commands/swift.ts +29 -11
  56. package/cli/commands/telemetry.ts +2 -2
  57. package/cli/commands/test.ts +5 -0
  58. package/cli/commands/three-mode.ts +3 -3
  59. package/cli/commands/timeline.ts +4 -4
  60. package/cli/commands/upgrade.ts +2 -2
  61. package/cli/commands/upload.ts +15 -15
  62. package/cli/commands/what-happened.ts +2 -2
  63. package/cli/current-sim.ts +6 -3
  64. package/cli/desktop-companion.ts +55 -149
  65. package/cli/dev-build-freshness.ts +2 -2
  66. package/cli/drivers/desktop.ts +17 -9
  67. package/cli/drivers/electron.ts +1 -2
  68. package/cli/drivers/playwright-sim-host.ts +11 -2
  69. package/cli/drivers/playwright.ts +35 -2
  70. package/cli/drivers/types.ts +8 -0
  71. package/cli/maestro-compare.ts +670 -0
  72. package/cli/outbound-endpoints.ts +46 -8
  73. package/cli/recording-access.ts +6 -6
  74. package/cli/run-registry.ts +1 -1
  75. package/cli/runtime-compat.ts +5 -1
  76. package/cli/send-to-box.ts +3 -3
  77. package/cli/shell-init.ts +2 -1
  78. package/cli/ws-bridge.ts +9 -5
  79. package/detox/element-types.ts +1 -0
  80. package/detox/gestures.ts +3 -3
  81. package/detox/index.ts +67 -38
  82. package/detox/navigation-lifecycle.ts +9 -6
  83. package/detox/proof-frame.cjs +6 -4
  84. package/dist-lib/agent-daemon-client.cjs +1 -1
  85. package/dist-lib/agent-events.cjs +1 -1
  86. package/dist-lib/attached-projects.cjs +1 -1
  87. package/dist-lib/auth/shared-session.cjs +1 -1
  88. package/dist-lib/backend-origin.cjs +1 -1
  89. package/dist-lib/beta.cjs +1 -1
  90. package/dist-lib/beta.mjs +1 -1
  91. package/dist-lib/bridge-constants.cjs +1 -1
  92. package/dist-lib/bridge-contract-input.cjs +42 -17
  93. package/dist-lib/bridge-contract-input.mjs +41 -16
  94. package/dist-lib/bridge-contract.cjs +1 -4
  95. package/dist-lib/bridge-contract.mjs +1 -3
  96. package/dist-lib/bundle-channel.cjs +2918 -550
  97. package/dist-lib/capture-contract.cjs +65 -24
  98. package/dist-lib/capture-contract.mjs +63 -24
  99. package/dist-lib/cloud-contract.cjs +2 -2
  100. package/dist-lib/cloud-contract.mjs +2 -2
  101. package/dist-lib/cloud-test-args.cjs +1 -1
  102. package/dist-lib/cloud-test-args.mjs +1 -1
  103. package/dist-lib/cloud.cjs +3 -3
  104. package/dist-lib/cloud.mjs +3 -3
  105. package/dist-lib/config.cjs +15 -5
  106. package/dist-lib/config.mjs +154 -0
  107. package/dist-lib/detox/index.cjs +495 -139
  108. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  109. package/dist-lib/expo-swift-bundle.cjs +1168 -238
  110. package/dist-lib/expo-swift-metadata.cjs +34 -23
  111. package/dist-lib/expo-swift-metadata.mjs +32 -23
  112. package/dist-lib/home-paths.cjs +2 -2
  113. package/dist-lib/host/bridge-host.cjs +2938 -654
  114. package/dist-lib/host/fetch-proxy-handler.cjs +14 -1
  115. package/dist-lib/host/fetch-proxy-overrides.cjs +7 -1
  116. package/dist-lib/host/fetch-proxy-overrides.mjs +5 -1
  117. package/dist-lib/host/replacement-module-handler.cjs +2 -2
  118. package/dist-lib/host/websocket-proxy.cjs +1 -1
  119. package/dist-lib/index.cjs +981 -353
  120. package/dist-lib/jump-to-source-babel.cjs +1 -1
  121. package/dist-lib/jump-to-source-native.cjs +1 -1
  122. package/dist-lib/kotlin-host.cjs +332 -19
  123. package/dist-lib/menu.cjs +1 -1
  124. package/dist-lib/menu.mjs +1 -1
  125. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  126. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  127. package/dist-lib/metro-production-bundle.cjs +7 -7
  128. package/dist-lib/metro-production-bundle.mjs +5 -5
  129. package/dist-lib/metro.cjs +670 -250
  130. package/dist-lib/native-app-identity-project.cjs +2647 -0
  131. package/dist-lib/native-app-identity-project.mjs +1257 -0
  132. package/dist-lib/native-app-identity.cjs +304 -25
  133. package/dist-lib/native-app-identity.mjs +302 -25
  134. package/dist-lib/native-firebase-metadata.cjs +1 -1
  135. package/dist-lib/native-firebase-metadata.mjs +1 -1
  136. package/dist-lib/plist.cjs +1 -1
  137. package/dist-lib/plist.mjs +1 -1
  138. package/dist-lib/profiles.cjs +1 -1
  139. package/dist-lib/public-brand.cjs +1 -1
  140. package/dist-lib/react-native-host-modules.cjs +5 -1
  141. package/dist-lib/react-native-host-modules.mjs +5 -1
  142. package/dist-lib/scripts/dev-server-scanner.cjs +57 -32
  143. package/dist-lib/sdk.cjs +231 -51
  144. package/dist-lib/sdk.mjs +231 -51
  145. package/dist-lib/skills.cjs +4107 -1374
  146. package/dist-lib/swift-compile.cjs +290 -30
  147. package/dist-lib/swift-compile.mjs +290 -30
  148. package/dist-lib/swift-package.cjs +143 -12
  149. package/dist-lib/swift-package.mjs +137 -11
  150. package/dist-lib/swift-submit.cjs +47 -5
  151. package/dist-lib/swift-submit.mjs +42 -5
  152. package/dist-lib/swift-toolchain.cjs +7 -2
  153. package/dist-lib/swift.cjs +1 -1
  154. package/dist-lib/vite-swift.cjs +1392 -458
  155. package/dist-lib/vite.cjs +13 -17
  156. package/dist-lib/worklet-executable.cjs +248 -33
  157. package/dist-lib/worklet-executable.mjs +248 -33
  158. package/install.sh +10 -1
  159. package/kotlin/{AppSources → AndroidViewSources}/android/content/res/Resources.kt +9 -9
  160. package/kotlin/AndroidViewSources/android/graphics/Canvas.kt +20 -0
  161. package/kotlin/AndroidViewSources/android/view/View.kt +211 -0
  162. package/kotlin/AndroidViewSources/android/widget/FrameLayout.kt +61 -0
  163. package/kotlin/AndroidViewSources/android/widget/LinearLayout.kt +49 -0
  164. package/kotlin/AppSources/android/view/Window.kt +36 -0
  165. package/kotlin/AppSources/android/view/WindowInsets.kt +9 -0
  166. package/kotlin/AppSources/android/view/WindowInsetsController.kt +5 -0
  167. package/kotlin/AppSources/android/window/OnBackInvokedDispatcher.kt +48 -0
  168. package/kotlin/AppSources/androidx/activity/OnBackPressedDispatcher.kt +20 -5
  169. package/kotlin/AppSources/androidx/compose/foundation/layout/WindowInsets.kt +15 -0
  170. package/kotlin/AppSources/androidx/compose/ui/platform/ComposeView.kt +2 -1
  171. package/kotlin/AppSources/dev/peach/app/PeachApp.kt +42 -50
  172. package/kotlin/ComposeSources/PeachComposeHost.kt +200 -84
  173. package/kotlin/ExpoComposeSources/PeachAndroidView.kt +87 -0
  174. package/kotlin/ExpoComposeSources/PeachExpoViewMount.kt +24 -0
  175. package/kotlin/ExpoComposeSources/dev/peach/expo/PeachExpoCompose.kt +28 -0
  176. package/kotlin/ExpoComposeSources/expo/modules/kotlin/views/ExpoComposeView.kt +70 -0
  177. package/kotlin/ExpoSources/dev/peach/expo/PeachExpoRuntime.kt +513 -0
  178. package/kotlin/ExpoSources/dev/peach/expo/PeachExpoTypes.kt +173 -0
  179. package/kotlin/ExpoSources/expo/modules/kotlin/AppContext.kt +20 -0
  180. package/kotlin/ExpoSources/expo/modules/kotlin/Promise.kt +19 -0
  181. package/kotlin/ExpoSources/expo/modules/kotlin/classcomponent/ClassComponentBuilder.kt +198 -0
  182. package/kotlin/ExpoSources/expo/modules/kotlin/exception/CodedException.kt +126 -0
  183. package/kotlin/ExpoSources/expo/modules/kotlin/functions/Functions.kt +132 -0
  184. package/kotlin/ExpoSources/expo/modules/kotlin/jni/JavaScriptTypedArray.kt +81 -0
  185. package/kotlin/ExpoSources/expo/modules/kotlin/modules/Module.kt +98 -0
  186. package/kotlin/ExpoSources/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +236 -0
  187. package/kotlin/ExpoSources/expo/modules/kotlin/records/Record.kt +12 -0
  188. package/kotlin/ExpoSources/expo/modules/kotlin/runtime/Runtime.kt +9 -0
  189. package/kotlin/ExpoSources/expo/modules/kotlin/sharedobjects/SharedObject.kt +50 -0
  190. package/kotlin/ExpoSources/expo/modules/kotlin/sharedobjects/SharedObjectRegistry.kt +57 -0
  191. package/kotlin/ExpoSources/expo/modules/kotlin/sharedobjects/SharedRef.kt +19 -0
  192. package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/ConcreteTypedArrays.kt +158 -0
  193. package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/GenericTypedArray.kt +8 -0
  194. package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/TypedArray.kt +29 -0
  195. package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/TypedArrayIterator.kt +9 -0
  196. package/kotlin/ExpoSources/expo/modules/kotlin/types/AnyType.kt +155 -0
  197. package/kotlin/ExpoSources/expo/modules/kotlin/types/Either.kt +91 -0
  198. package/kotlin/ExpoSources/expo/modules/kotlin/types/Enumerable.kt +6 -0
  199. package/kotlin/ExpoSources/expo/modules/kotlin/viewevent/ViewEvent.kt +54 -0
  200. package/kotlin/ExpoSources/expo/modules/kotlin/views/ExpoView.kt +23 -0
  201. package/kotlin/ExpoSources/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +71 -0
  202. package/kotlin/ExpoSources/expo/modules/kotlin/views/ViewProps.kt +35 -0
  203. package/kotlin/README.md +13 -3
  204. package/kotlin/Sources/android/os/Build.kt +17 -0
  205. package/kotlin/Sources/android/os/Handler.kt +35 -0
  206. package/kotlin/Sources/android/os/Looper.kt +17 -0
  207. package/kotlin/Sources/android/os/MessageQueue.kt +56 -0
  208. package/kotlin/Sources/android/os/SystemClock.kt +14 -0
  209. package/kotlin/Sources/android/util/Log.kt +64 -0
  210. package/kotlin/Sources/java/security/MessageDigest.kt +114 -0
  211. package/kotlin/Sources/kotlin/text/StringFormat.kt +9 -0
  212. package/kotlin/Sources/org/json/JSON.kt +44 -0
  213. package/kotlin/fixtures/counter/Counter.d.kt.ts +1 -0
  214. package/kotlin/fixtures/counter/Counter.kt +10 -3
  215. package/kotlin/fixtures/counter/CounterApp.native.tsx +1 -1
  216. package/kotlin/fixtures/counter/vite.config.ts +2 -2
  217. package/kotlin/fixtures/headless-counter/Headless.kt +7 -6
  218. package/kotlin/fixtures/import-animation/Animation.d.kt.ts +7 -0
  219. package/kotlin/fixtures/import-animation/Animation.kt +80 -0
  220. package/kotlin/fixtures/import-animation/ImportAnimation.native.tsx +13 -0
  221. package/kotlin/fixtures/import-animation/README.md +24 -0
  222. package/kotlin/fixtures/import-animation/app/_layout.tsx +4 -0
  223. package/kotlin/fixtures/import-animation/app/index+spa.tsx +1 -0
  224. package/kotlin/fixtures/import-animation/app/routes.d.ts +18 -0
  225. package/kotlin/fixtures/import-animation/package.json +23 -0
  226. package/kotlin/fixtures/import-animation/tsconfig.json +20 -0
  227. package/kotlin/fixtures/import-animation/vite.config.ts +20 -0
  228. package/kotlin/fixtures/import-editor/Editor.d.kt.ts +7 -0
  229. package/kotlin/fixtures/import-editor/Editor.kt +59 -0
  230. package/kotlin/fixtures/import-editor/ImportEditor.native.tsx +23 -0
  231. package/kotlin/fixtures/import-editor/README.md +27 -0
  232. package/kotlin/fixtures/import-editor/app/_layout.tsx +4 -0
  233. package/kotlin/fixtures/import-editor/app/index+spa.tsx +1 -0
  234. package/kotlin/fixtures/import-editor/package.json +23 -0
  235. package/kotlin/fixtures/import-editor/tsconfig.json +20 -0
  236. package/kotlin/fixtures/import-editor/vite.config.ts +20 -0
  237. package/kotlin/fixtures/import-effects/Effects.d.kt.ts +7 -0
  238. package/kotlin/fixtures/import-effects/Effects.kt +87 -0
  239. package/kotlin/fixtures/import-effects/ImportEffects.native.tsx +13 -0
  240. package/kotlin/fixtures/import-effects/README.md +19 -0
  241. package/kotlin/fixtures/import-effects/app/_layout.tsx +4 -0
  242. package/kotlin/fixtures/import-effects/app/index+spa.tsx +1 -0
  243. package/kotlin/fixtures/import-effects/package.json +23 -0
  244. package/kotlin/fixtures/import-effects/tsconfig.json +20 -0
  245. package/kotlin/fixtures/import-effects/vite.config.ts +20 -0
  246. package/kotlin/fixtures/import-layout/ImportLayout.native.tsx +13 -0
  247. package/kotlin/fixtures/import-layout/Layout.d.kt.ts +7 -0
  248. package/kotlin/fixtures/import-layout/Layout.kt +72 -0
  249. package/kotlin/fixtures/import-layout/README.md +24 -0
  250. package/kotlin/fixtures/import-layout/app/_layout.tsx +4 -0
  251. package/kotlin/fixtures/import-layout/app/index+spa.tsx +1 -0
  252. package/kotlin/fixtures/import-layout/package.json +23 -0
  253. package/kotlin/fixtures/import-layout/tsconfig.json +20 -0
  254. package/kotlin/fixtures/import-layout/vite.config.ts +20 -0
  255. package/kotlin/fixtures/import-navigation/ImportNavigation.native.tsx +18 -0
  256. package/kotlin/fixtures/import-navigation/Navigation.d.kt.ts +7 -0
  257. package/kotlin/fixtures/import-navigation/Navigation.kt +104 -0
  258. package/kotlin/fixtures/import-navigation/README.md +31 -0
  259. package/kotlin/fixtures/import-navigation/app/_layout.tsx +4 -0
  260. package/kotlin/fixtures/import-navigation/app/index+spa.tsx +1 -0
  261. package/kotlin/fixtures/import-navigation/package.json +23 -0
  262. package/kotlin/fixtures/import-navigation/tsconfig.json +20 -0
  263. package/kotlin/fixtures/import-navigation/vite.config.ts +20 -0
  264. package/kotlin/fixtures/import-overlays/ImportOverlays.native.tsx +29 -0
  265. package/kotlin/fixtures/import-overlays/Overlays.d.kt.ts +7 -0
  266. package/kotlin/fixtures/import-overlays/Overlays.kt +93 -0
  267. package/kotlin/fixtures/import-overlays/README.md +34 -0
  268. package/kotlin/fixtures/import-overlays/app/_layout.tsx +4 -0
  269. package/kotlin/fixtures/import-overlays/app/index+spa.tsx +1 -0
  270. package/kotlin/fixtures/import-overlays/package.json +23 -0
  271. package/kotlin/fixtures/import-overlays/tsconfig.json +20 -0
  272. package/kotlin/fixtures/import-overlays/vite.config.ts +20 -0
  273. package/kotlin/fixtures/import-scroll/ImportScroll.native.tsx +13 -0
  274. package/kotlin/fixtures/import-scroll/README.md +23 -0
  275. package/kotlin/fixtures/import-scroll/Scroll.d.kt.ts +7 -0
  276. package/kotlin/fixtures/import-scroll/Scroll.kt +91 -0
  277. package/kotlin/fixtures/import-scroll/app/_layout.tsx +4 -0
  278. package/kotlin/fixtures/import-scroll/app/index+spa.tsx +1 -0
  279. package/kotlin/fixtures/import-scroll/package.json +23 -0
  280. package/kotlin/fixtures/import-scroll/tsconfig.json +20 -0
  281. package/kotlin/fixtures/import-scroll/vite.config.ts +20 -0
  282. package/kotlin/fixtures/import-selection/ImportSelection.native.tsx +44 -0
  283. package/kotlin/fixtures/import-selection/README.md +32 -0
  284. package/kotlin/fixtures/import-selection/Selection.d.kt.ts +8 -0
  285. package/kotlin/fixtures/import-selection/Selection.kt +78 -0
  286. package/kotlin/fixtures/import-selection/app/_layout.tsx +4 -0
  287. package/kotlin/fixtures/import-selection/app/index+spa.tsx +1 -0
  288. package/kotlin/fixtures/import-selection/package.json +23 -0
  289. package/kotlin/fixtures/import-selection/tsconfig.json +20 -0
  290. package/kotlin/fixtures/import-selection/vite.config.ts +20 -0
  291. package/kotlin/fixtures/import-surfaces/ImportSurfaces.native.tsx +13 -0
  292. package/kotlin/fixtures/import-surfaces/README.md +22 -0
  293. package/kotlin/fixtures/import-surfaces/Surfaces.d.kt.ts +7 -0
  294. package/kotlin/fixtures/import-surfaces/Surfaces.kt +64 -0
  295. package/kotlin/fixtures/import-surfaces/app/_layout.tsx +4 -0
  296. package/kotlin/fixtures/import-surfaces/app/index+spa.tsx +1 -0
  297. package/kotlin/fixtures/import-surfaces/package.json +23 -0
  298. package/kotlin/fixtures/import-surfaces/tsconfig.json +20 -0
  299. package/kotlin/fixtures/import-surfaces/vite.config.ts +20 -0
  300. package/kotlin/fixtures/import-values/ImportValues.native.tsx +35 -0
  301. package/kotlin/fixtures/import-values/README.md +23 -0
  302. package/kotlin/fixtures/import-values/Values.d.kt.ts +11 -0
  303. package/kotlin/fixtures/import-values/Values.kt +66 -0
  304. package/kotlin/fixtures/import-values/app/_layout.tsx +4 -0
  305. package/kotlin/fixtures/import-values/app/index+spa.tsx +1 -0
  306. package/kotlin/fixtures/import-values/package.json +23 -0
  307. package/kotlin/fixtures/import-values/tsconfig.json +20 -0
  308. package/kotlin/fixtures/import-values/vite.config.ts +20 -0
  309. package/kotlin/fixtures/kotlin-app-variants/BarBehavior.kt +38 -0
  310. package/kotlin/fixtures/kotlin-app-variants/BarVisibility.kt +36 -0
  311. package/kotlin/fixtures/kotlin-app-variants/Ime.kt +3 -1
  312. package/kotlin/fixtures/kotlin-app-variants/TransientInsets.kt +50 -0
  313. package/kotlin/fork/NOTICE +6 -1
  314. package/kotlin/fork/README.md +15 -7
  315. package/kotlin/fork/build.sh +2 -0
  316. package/kotlin/fork/compose-worker-globals.patch +186 -4
  317. package/kotlin/fork/fork.json +2 -2
  318. package/kotlin/fork/skiko-worker-clock.patch +12 -0
  319. package/kotlin/toolchain.json +12 -12
  320. package/kotlin/tools/expo-types.main.kts +115 -0
  321. package/package.json +17 -23
  322. package/scripts/dev-server-scanner.ts +92 -66
  323. package/skills/contrast/SKILL.md +2 -2
  324. package/skills/peach-debug/SKILL.md +1 -1
  325. package/skills/peach-perf/SKILL.md +1 -1
  326. package/skills/peach-setup/SKILL.md +2 -1
  327. package/skills/peach-test/SKILL.md +8 -0
  328. package/src/assetCatalogContract.ts +43 -1
  329. package/src/bridge-contract-input.ts +46 -19
  330. package/src/bridge-contract.ts +0 -1
  331. package/src/bundle-channel.mjs +197 -84
  332. package/src/bundleGlobalFooter.ts +38 -0
  333. package/src/capture-contract.ts +107 -33
  334. package/src/cloud-contract.ts +5 -1
  335. package/src/cloud.ts +5 -2
  336. package/src/config.ts +22 -3
  337. package/src/configured-bundle-producer.ts +1 -1
  338. package/src/desktop-host-delivery.ts +95 -1
  339. package/src/expo-kotlin-bundle.ts +29 -0
  340. package/src/expo-kotlin-host.ts +201 -0
  341. package/src/expo-swift-host.ts +96 -76
  342. package/src/expoKotlinContract.ts +70 -0
  343. package/src/expoSwiftContract.ts +4 -25
  344. package/src/home-paths.ts +7 -4
  345. package/src/host/bridge-host.ts +23 -3
  346. package/src/host/fetch-proxy-handler.ts +13 -0
  347. package/src/host/fetch-proxy-overrides.ts +11 -0
  348. package/src/host/replacement-module-handler.ts +5 -2
  349. package/src/index.ts +3 -1
  350. package/src/kotlin-host.ts +463 -19
  351. package/src/metro-plugin.ts +56 -28
  352. package/src/metro-production-bundle.ts +2 -2
  353. package/src/native-app-identity-project.ts +190 -0
  354. package/src/native-app-identity.ts +367 -34
  355. package/src/native-firebase-config.ts +69 -15
  356. package/src/native-seam-manifest.ts +6 -0
  357. package/src/one-widget-discovery.ts +2 -1
  358. package/src/openstep-plist.ts +107 -0
  359. package/src/react-native-host-modules.ts +4 -0
  360. package/src/runtime-assets.ts +2 -2
  361. package/src/sim-client.ts +2 -2
  362. package/src/swift-binary-modules.ts +3 -1
  363. package/src/swift-compile.ts +286 -38
  364. package/src/swift-distribution-contract.ts +4 -0
  365. package/src/swift-distribution.lock.json +123 -12
  366. package/src/swift-distribution.ts +7 -3
  367. package/src/swift-host.ts +298 -83
  368. package/src/swift-package-manifest.ts +29 -2
  369. package/src/swift-package.ts +180 -10
  370. package/src/swift-packages.ts +4 -0
  371. package/src/swift-standin-emit.ts +4 -1
  372. package/src/swift-standins.ts +274 -15
  373. package/src/swift-submit.ts +62 -7
  374. package/src/swift-toolchain.ts +6 -1
  375. package/src/swiftContract.ts +126 -3
  376. package/src/vite-plugin-one.ts +13 -16
  377. package/src/vite-plugin-swift.ts +4 -5
  378. package/src/vite-plugin.ts +360 -144
  379. package/src/vite.d.ts +1 -1
  380. package/src/worker-system-chunks.ts +221 -0
  381. package/src/worklet-executable.ts +348 -38
  382. package/src/worklets-babel.ts +1 -1
  383. package/src/xcode-project.ts +243 -127
  384. package/dist-lib/agent-identity.cjs +0 -39
  385. package/dist-lib/agent-sessions.cjs +0 -760
  386. package/dist-lib/cli-constants.cjs +0 -32
  387. package/dist-lib/render-mode.cjs +0 -44
  388. package/kotlin/AppSources/android/view/View.kt +0 -74
  389. package/kotlin/AppSources/android/widget/FrameLayout.kt +0 -6
  390. package/src/render-mode.ts +0 -15
  391. /package/kotlin/{AppSources → AndroidViewSources}/android/content/Context.kt +0 -0
  392. /package/kotlin/{AppSources → AndroidViewSources}/android/content/res/Configuration.kt +0 -0
  393. /package/kotlin/{AppSources → AndroidViewSources}/android/graphics/Color.kt +0 -0
  394. /package/kotlin/{AppSources → AndroidViewSources}/android/util/DisplayMetrics.kt +0 -0
  395. /package/kotlin/{AppSources → AndroidViewSources}/dev/peach/app/JavaFormat.kt +0 -0
  396. /package/kotlin/{AppSources → Sources}/java/lang/Runnable.kt +0 -0
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.940 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! peach v0.1.1399 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1558,6 +1558,7 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
1558
1558
  } catch {
1559
1559
  return false;
1560
1560
  }
1561
+ if (url.pathname !== REPLACEMENT_MODULE_ROUTE) return false;
1561
1562
  if (options.requireLoopbackOrigin) {
1562
1563
  const origin = req.headers.origin;
1563
1564
  const remoteAddress = req.socket.remoteAddress?.replace(/^::ffff:/, "");
@@ -1575,7 +1576,6 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
1575
1576
  return true;
1576
1577
  }
1577
1578
  }
1578
- if (url.pathname !== REPLACEMENT_MODULE_ROUTE) return false;
1579
1579
  if (options.requestToken && url.searchParams.get("token") !== options.requestToken) {
1580
1580
  res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
1581
1581
  res.end("replacement module request token is invalid");
@@ -1983,10 +1983,16 @@ __export(config_exports, {
1983
1983
  hasPeachConfig: () => hasPeachConfig,
1984
1984
  isPeachConfig: () => isPeachConfig,
1985
1985
  mergePeachConfig: () => mergePeachConfig,
1986
+ readNativeRenderer: () => readNativeRenderer,
1986
1987
  readPeachBundleConfig: () => readPeachBundleConfig,
1987
1988
  readPeachBundleConfigFooter: () => readPeachBundleConfigFooter,
1988
1989
  readPeachConfigFromSearchParams: () => readPeachConfigFromSearchParams
1989
1990
  });
1991
+ function readNativeRenderer(value) {
1992
+ if (value === void 0) return void 0;
1993
+ if (value === "paper" || value === "fabric") return value;
1994
+ throw new Error("nativeRenderer must be paper or fabric");
1995
+ }
1990
1996
  function collectConfiguredFileModules(config) {
1991
1997
  return [
1992
1998
  ...new Set(
@@ -2002,7 +2008,7 @@ function collectConfiguredFileModules(config) {
2002
2008
  }
2003
2009
  function isPeachConfig(value) {
2004
2010
  if (!isRecord(value)) return false;
2005
- return (value.runtimeVersion === void 0 || typeof value.runtimeVersion === "string" && value.runtimeVersion === value.runtimeVersion.trim() && isValidRuntimeVersion(value.runtimeVersion)) && [
2011
+ return (value.nativeRenderer === void 0 || value.nativeRenderer === "paper" || value.nativeRenderer === "fabric") && (value.runtimeVersion === void 0 || typeof value.runtimeVersion === "string" && value.runtimeVersion === value.runtimeVersion.trim() && isValidRuntimeVersion(value.runtimeVersion)) && [
2006
2012
  "modules",
2007
2013
  "turboModules",
2008
2014
  "nativeModules",
@@ -2056,7 +2062,7 @@ function hasOwnKeys(value) {
2056
2062
  }
2057
2063
  function hasPeachConfig(config) {
2058
2064
  if (!config) return false;
2059
- return typeof config.runtimeVersion === "string" && config.runtimeVersion.length > 0 || hasOwnKeys(config.modules) || hasOwnKeys(config.turboModules) || hasOwnKeys(config.nativeModules) || hasOwnKeys(config.nativeViews) || hasOwnKeys(config.env) || hasOwnKeys(config.network?.remap) || hasOwnKeys(config.settings) || hasOwnKeys(config.initialState);
2065
+ return config.nativeRenderer !== void 0 || typeof config.runtimeVersion === "string" && config.runtimeVersion.length > 0 || hasOwnKeys(config.modules) || hasOwnKeys(config.turboModules) || hasOwnKeys(config.nativeModules) || hasOwnKeys(config.nativeViews) || hasOwnKeys(config.env) || hasOwnKeys(config.network?.remap) || hasOwnKeys(config.settings) || hasOwnKeys(config.initialState);
2060
2066
  }
2061
2067
  function mergePeachConfig(base, override) {
2062
2068
  if (!hasPeachConfig(base) && !hasPeachConfig(override)) return void 0;
@@ -2064,6 +2070,7 @@ function mergePeachConfig(base, override) {
2064
2070
  if (!hasPeachConfig(override)) return base ? { ...base } : void 0;
2065
2071
  return {
2066
2072
  runtimeVersion: override.runtimeVersion ?? base.runtimeVersion,
2073
+ nativeRenderer: override.nativeRenderer ?? base.nativeRenderer,
2067
2074
  modules: { ...base.modules || {}, ...override.modules || {} },
2068
2075
  turboModules: { ...base.turboModules || {}, ...override.turboModules || {} },
2069
2076
  nativeModules: {
@@ -2085,14 +2092,16 @@ function mergePeachConfig(base, override) {
2085
2092
  function readPeachConfigFromSearchParams(searchParams) {
2086
2093
  const raw = searchParams.get(PEACH_CONFIG_QUERY_PARAM);
2087
2094
  if (!raw) return void 0;
2095
+ let parsed;
2088
2096
  try {
2089
- const parsed = JSON.parse(raw);
2090
- return hasPeachConfig(parsed) ? parsed : void 0;
2097
+ parsed = JSON.parse(raw);
2091
2098
  } catch (error) {
2092
2099
  const message = error instanceof Error ? error.message : String(error);
2093
2100
  console.warn(`[peach] invalid ${PEACH_CONFIG_QUERY_PARAM}: ${message}`);
2094
2101
  return void 0;
2095
2102
  }
2103
+ if (isRecord(parsed)) readNativeRenderer(parsed.nativeRenderer);
2104
+ return isPeachConfig(parsed) && hasPeachConfig(parsed) ? parsed : void 0;
2096
2105
  }
2097
2106
  function applyPeachConfigToUrl(url, config) {
2098
2107
  const parsed = new URL(url);
@@ -2126,12 +2135,12 @@ function resolveFileEntries(entries, configDir) {
2126
2135
  return Object.fromEntries(
2127
2136
  Object.entries(entries).map(([name2, resolution]) => [
2128
2137
  name2,
2129
- resolution && typeof resolution === "object" && "file" in resolution && typeof resolution.file === "string" ? { ...resolution, file: import_node_path12.default.resolve(configDir, resolution.file) } : resolution
2138
+ resolution && typeof resolution === "object" && "file" in resolution && typeof resolution.file === "string" ? { ...resolution, file: import_node_path13.default.resolve(configDir, resolution.file) } : resolution
2130
2139
  ])
2131
2140
  );
2132
2141
  }
2133
2142
  function resolveConfigReplacementFiles(config, configPath) {
2134
- const configDir = import_node_path12.default.dirname(configPath);
2143
+ const configDir = import_node_path13.default.dirname(configPath);
2135
2144
  return {
2136
2145
  ...config,
2137
2146
  modules: resolveFileEntries(config.modules, configDir),
@@ -2166,11 +2175,11 @@ async function resolveRNXAppConfig(startDir = process.cwd()) {
2166
2175
  const project = resolveAppProject(startDir);
2167
2176
  return { project, config: await loadRNXAppConfig(project) };
2168
2177
  }
2169
- var import_node_path12, import_jiti;
2178
+ var import_node_path13, import_jiti;
2170
2179
  var init_app_config = __esm({
2171
2180
  "cli/app-config.ts"() {
2172
2181
  "use strict";
2173
- import_node_path12 = __toESM(require("node:path"), 1);
2182
+ import_node_path13 = __toESM(require("node:path"), 1);
2174
2183
  import_jiti = require("jiti");
2175
2184
  init_config();
2176
2185
  init_config();
@@ -2200,14 +2209,14 @@ async function produceConfiguredBundle(source, config, runtimePackages) {
2200
2209
  const neededPackages = /* @__PURE__ */ new Set();
2201
2210
  const factories = [];
2202
2211
  const visit3 = (filePath) => {
2203
- const real = import_node_fs11.default.realpathSync(filePath);
2212
+ const real = import_node_fs12.default.realpathSync(filePath);
2204
2213
  const previous = files.get(real);
2205
2214
  if (previous !== void 0) return previous;
2206
2215
  const id = "peach-config-file:" + files.size;
2207
2216
  files.set(real, id);
2208
2217
  const compiled = compileReplacementModule({
2209
2218
  filePath: real,
2210
- source: import_node_fs11.default.readFileSync(real, "utf8"),
2219
+ source: import_node_fs12.default.readFileSync(real, "utf8"),
2211
2220
  runtimePackages,
2212
2221
  localModuleUrl: (specifier) => visit3(resolveReplacementModuleFile(real, specifier))
2213
2222
  });
@@ -2223,7 +2232,7 @@ async function produceConfiguredBundle(source, config, runtimePackages) {
2223
2232
  if (!entries || typeof entries !== "object") continue;
2224
2233
  for (const resolution of Object.values(entries)) {
2225
2234
  if (resolution && typeof resolution === "object" && "file" in resolution && typeof resolution.file === "string") {
2226
- resolution.file = visit3(import_node_path13.default.resolve(resolution.file));
2235
+ resolution.file = visit3(import_node_path14.default.resolve(resolution.file));
2227
2236
  }
2228
2237
  }
2229
2238
  }
@@ -2234,7 +2243,7 @@ async function produceConfiguredBundle(source, config, runtimePackages) {
2234
2243
  const compact = await (0, import_terser.minify)(code, {
2235
2244
  compress: false,
2236
2245
  mangle: false,
2237
- format: { comments: false, beautify: false }
2246
+ format: { comments: false }
2238
2247
  });
2239
2248
  if (!compact.code || /[\n\r]/.test(compact.code))
2240
2249
  throw new Error("configured bundle prefix must preserve the guest source lines");
@@ -2247,12 +2256,12 @@ async function produceConfiguredBundle(source, config, runtimePackages) {
2247
2256
  const identityStart = source.lastIndexOf("\nglobalThis.__sootsimModulePaths=");
2248
2257
  return prefix2 + (identityStart < 0 ? source + footer : source.slice(0, identityStart) + footer + source.slice(identityStart));
2249
2258
  }
2250
- var import_node_fs11, import_node_path13, import_sucrase, import_terser;
2259
+ var import_node_fs12, import_node_path14, import_sucrase, import_terser;
2251
2260
  var init_configured_bundle_producer = __esm({
2252
2261
  "src/configured-bundle-producer.ts"() {
2253
2262
  "use strict";
2254
- import_node_fs11 = __toESM(require("node:fs"), 1);
2255
- import_node_path13 = __toESM(require("node:path"), 1);
2263
+ import_node_fs12 = __toESM(require("node:fs"), 1);
2264
+ import_node_path14 = __toESM(require("node:path"), 1);
2256
2265
  import_sucrase = require("sucrase");
2257
2266
  import_terser = require("terser");
2258
2267
  init_replacementModule();
@@ -2282,9 +2291,10 @@ __export(src_exports, {
2282
2291
  jumpToSourceBabelPlugin: () => sootsimJumpToSourceBabelPlugin,
2283
2292
  metroPlugin: () => metro_plugin_default,
2284
2293
  packRnxCaptureRegions: () => packRnxCaptureRegions,
2294
+ peachPlugin: () => peachPlugin,
2285
2295
  rnxCaptureRasterRegions: () => rnxCaptureRasterRegions,
2286
- rnxPlugin: () => rnxPlugin,
2287
2296
  rnxRasterFrames: () => rnxRasterFrames,
2297
+ rnxRasterRegionRequests: () => rnxRasterRegionRequests,
2288
2298
  selectRnxRasterNodeIds: () => selectRnxRasterNodeIds
2289
2299
  });
2290
2300
  module.exports = __toCommonJS(src_exports);
@@ -2303,7 +2313,6 @@ var import_react_native_host_modules = require("peachsim/react-native-host-modul
2303
2313
  init_backend_origin();
2304
2314
 
2305
2315
  // src/cloud-contract.ts
2306
- var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
2307
2316
  var RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES = 1024 * 1024;
2308
2317
  var RNX_CLOUD_COMMAND_SCOPES = {
2309
2318
  state: "read",
@@ -2713,17 +2722,17 @@ function visit(node, visitor) {
2713
2722
  visit.BREAK = BREAK;
2714
2723
  visit.SKIP = SKIP;
2715
2724
  visit.REMOVE = REMOVE;
2716
- function visit_(key, node, visitor, path16) {
2717
- const ctrl = callVisitor(key, node, visitor, path16);
2725
+ function visit_(key, node, visitor, path17) {
2726
+ const ctrl = callVisitor(key, node, visitor, path17);
2718
2727
  if (isNode(ctrl) || isPair(ctrl)) {
2719
- replaceNode(key, path16, ctrl);
2720
- return visit_(key, ctrl, visitor, path16);
2728
+ replaceNode(key, path17, ctrl);
2729
+ return visit_(key, ctrl, visitor, path17);
2721
2730
  }
2722
2731
  if (typeof ctrl !== "symbol") {
2723
2732
  if (isCollection(node)) {
2724
- path16 = Object.freeze(path16.concat(node));
2733
+ path17 = Object.freeze(path17.concat(node));
2725
2734
  for (let i = 0; i < node.items.length; ++i) {
2726
- const ci = visit_(i, node.items[i], visitor, path16);
2735
+ const ci = visit_(i, node.items[i], visitor, path17);
2727
2736
  if (typeof ci === "number")
2728
2737
  i = ci - 1;
2729
2738
  else if (ci === BREAK)
@@ -2734,13 +2743,13 @@ function visit_(key, node, visitor, path16) {
2734
2743
  }
2735
2744
  }
2736
2745
  } else if (isPair(node)) {
2737
- path16 = Object.freeze(path16.concat(node));
2738
- const ck = visit_("key", node.key, visitor, path16);
2746
+ path17 = Object.freeze(path17.concat(node));
2747
+ const ck = visit_("key", node.key, visitor, path17);
2739
2748
  if (ck === BREAK)
2740
2749
  return BREAK;
2741
2750
  else if (ck === REMOVE)
2742
2751
  node.key = null;
2743
- const cv = visit_("value", node.value, visitor, path16);
2752
+ const cv = visit_("value", node.value, visitor, path17);
2744
2753
  if (cv === BREAK)
2745
2754
  return BREAK;
2746
2755
  else if (cv === REMOVE)
@@ -2761,17 +2770,17 @@ async function visitAsync(node, visitor) {
2761
2770
  visitAsync.BREAK = BREAK;
2762
2771
  visitAsync.SKIP = SKIP;
2763
2772
  visitAsync.REMOVE = REMOVE;
2764
- async function visitAsync_(key, node, visitor, path16) {
2765
- const ctrl = await callVisitor(key, node, visitor, path16);
2773
+ async function visitAsync_(key, node, visitor, path17) {
2774
+ const ctrl = await callVisitor(key, node, visitor, path17);
2766
2775
  if (isNode(ctrl) || isPair(ctrl)) {
2767
- replaceNode(key, path16, ctrl);
2768
- return visitAsync_(key, ctrl, visitor, path16);
2776
+ replaceNode(key, path17, ctrl);
2777
+ return visitAsync_(key, ctrl, visitor, path17);
2769
2778
  }
2770
2779
  if (typeof ctrl !== "symbol") {
2771
2780
  if (isCollection(node)) {
2772
- path16 = Object.freeze(path16.concat(node));
2781
+ path17 = Object.freeze(path17.concat(node));
2773
2782
  for (let i = 0; i < node.items.length; ++i) {
2774
- const ci = await visitAsync_(i, node.items[i], visitor, path16);
2783
+ const ci = await visitAsync_(i, node.items[i], visitor, path17);
2775
2784
  if (typeof ci === "number")
2776
2785
  i = ci - 1;
2777
2786
  else if (ci === BREAK)
@@ -2782,13 +2791,13 @@ async function visitAsync_(key, node, visitor, path16) {
2782
2791
  }
2783
2792
  }
2784
2793
  } else if (isPair(node)) {
2785
- path16 = Object.freeze(path16.concat(node));
2786
- const ck = await visitAsync_("key", node.key, visitor, path16);
2794
+ path17 = Object.freeze(path17.concat(node));
2795
+ const ck = await visitAsync_("key", node.key, visitor, path17);
2787
2796
  if (ck === BREAK)
2788
2797
  return BREAK;
2789
2798
  else if (ck === REMOVE)
2790
2799
  node.key = null;
2791
- const cv = await visitAsync_("value", node.value, visitor, path16);
2800
+ const cv = await visitAsync_("value", node.value, visitor, path17);
2792
2801
  if (cv === BREAK)
2793
2802
  return BREAK;
2794
2803
  else if (cv === REMOVE)
@@ -2815,23 +2824,23 @@ function initVisitor(visitor) {
2815
2824
  }
2816
2825
  return visitor;
2817
2826
  }
2818
- function callVisitor(key, node, visitor, path16) {
2827
+ function callVisitor(key, node, visitor, path17) {
2819
2828
  if (typeof visitor === "function")
2820
- return visitor(key, node, path16);
2829
+ return visitor(key, node, path17);
2821
2830
  if (isMap(node))
2822
- return visitor.Map?.(key, node, path16);
2831
+ return visitor.Map?.(key, node, path17);
2823
2832
  if (isSeq(node))
2824
- return visitor.Seq?.(key, node, path16);
2833
+ return visitor.Seq?.(key, node, path17);
2825
2834
  if (isPair(node))
2826
- return visitor.Pair?.(key, node, path16);
2835
+ return visitor.Pair?.(key, node, path17);
2827
2836
  if (isScalar(node))
2828
- return visitor.Scalar?.(key, node, path16);
2837
+ return visitor.Scalar?.(key, node, path17);
2829
2838
  if (isAlias(node))
2830
- return visitor.Alias?.(key, node, path16);
2839
+ return visitor.Alias?.(key, node, path17);
2831
2840
  return void 0;
2832
2841
  }
2833
- function replaceNode(key, path16, node) {
2834
- const parent = path16[path16.length - 1];
2842
+ function replaceNode(key, path17, node) {
2843
+ const parent = path17[path17.length - 1];
2835
2844
  if (isCollection(parent)) {
2836
2845
  parent.items[key] = node;
2837
2846
  } else if (isPair(parent)) {
@@ -3311,10 +3320,10 @@ function createNode(value, tagName, ctx) {
3311
3320
  }
3312
3321
 
3313
3322
  // ../../node_modules/yaml/browser/dist/nodes/Collection.js
3314
- function collectionFromPath(schema4, path16, value) {
3323
+ function collectionFromPath(schema4, path17, value) {
3315
3324
  let v = value;
3316
- for (let i = path16.length - 1; i >= 0; --i) {
3317
- const k = path16[i];
3325
+ for (let i = path17.length - 1; i >= 0; --i) {
3326
+ const k = path17[i];
3318
3327
  if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
3319
3328
  const a = [];
3320
3329
  a[k] = v;
@@ -3333,7 +3342,7 @@ function collectionFromPath(schema4, path16, value) {
3333
3342
  sourceObjects: /* @__PURE__ */ new Map()
3334
3343
  });
3335
3344
  }
3336
- var isEmptyPath = (path16) => path16 == null || typeof path16 === "object" && !!path16[Symbol.iterator]().next().done;
3345
+ var isEmptyPath = (path17) => path17 == null || typeof path17 === "object" && !!path17[Symbol.iterator]().next().done;
3337
3346
  var Collection = class extends NodeBase {
3338
3347
  constructor(type, schema4) {
3339
3348
  super(type);
@@ -3363,11 +3372,11 @@ var Collection = class extends NodeBase {
3363
3372
  * be a Pair instance or a `{ key, value }` object, which may not have a key
3364
3373
  * that already exists in the map.
3365
3374
  */
3366
- addIn(path16, value) {
3367
- if (isEmptyPath(path16))
3375
+ addIn(path17, value) {
3376
+ if (isEmptyPath(path17))
3368
3377
  this.add(value);
3369
3378
  else {
3370
- const [key, ...rest] = path16;
3379
+ const [key, ...rest] = path17;
3371
3380
  const node = this.get(key, true);
3372
3381
  if (isCollection(node))
3373
3382
  node.addIn(rest, value);
@@ -3381,8 +3390,8 @@ var Collection = class extends NodeBase {
3381
3390
  * Removes a value from the collection.
3382
3391
  * @returns `true` if the item was found and removed.
3383
3392
  */
3384
- deleteIn(path16) {
3385
- const [key, ...rest] = path16;
3393
+ deleteIn(path17) {
3394
+ const [key, ...rest] = path17;
3386
3395
  if (rest.length === 0)
3387
3396
  return this.delete(key);
3388
3397
  const node = this.get(key, true);
@@ -3396,8 +3405,8 @@ var Collection = class extends NodeBase {
3396
3405
  * scalar values from their surrounding node; to disable set `keepScalar` to
3397
3406
  * `true` (collections are always returned intact).
3398
3407
  */
3399
- getIn(path16, keepScalar) {
3400
- const [key, ...rest] = path16;
3408
+ getIn(path17, keepScalar) {
3409
+ const [key, ...rest] = path17;
3401
3410
  const node = this.get(key, true);
3402
3411
  if (rest.length === 0)
3403
3412
  return !keepScalar && isScalar(node) ? node.value : node;
@@ -3415,8 +3424,8 @@ var Collection = class extends NodeBase {
3415
3424
  /**
3416
3425
  * Checks if the collection includes a value with the key `key`.
3417
3426
  */
3418
- hasIn(path16) {
3419
- const [key, ...rest] = path16;
3427
+ hasIn(path17) {
3428
+ const [key, ...rest] = path17;
3420
3429
  if (rest.length === 0)
3421
3430
  return this.has(key);
3422
3431
  const node = this.get(key, true);
@@ -3426,8 +3435,8 @@ var Collection = class extends NodeBase {
3426
3435
  * Sets a value in this collection. For `!!set`, `value` needs to be a
3427
3436
  * boolean to add/remove the item from the set.
3428
3437
  */
3429
- setIn(path16, value) {
3430
- const [key, ...rest] = path16;
3438
+ setIn(path17, value) {
3439
+ const [key, ...rest] = path17;
3431
3440
  if (rest.length === 0) {
3432
3441
  this.set(key, value);
3433
3442
  } else {
@@ -4876,9 +4885,9 @@ function visit2(cst, visitor) {
4876
4885
  visit2.BREAK = BREAK2;
4877
4886
  visit2.SKIP = SKIP2;
4878
4887
  visit2.REMOVE = REMOVE2;
4879
- visit2.itemAtPath = (cst, path16) => {
4888
+ visit2.itemAtPath = (cst, path17) => {
4880
4889
  let item = cst;
4881
- for (const [field, index] of path16) {
4890
+ for (const [field, index] of path17) {
4882
4891
  const tok = item?.[field];
4883
4892
  if (tok && "items" in tok) {
4884
4893
  item = tok.items[index];
@@ -4887,23 +4896,23 @@ visit2.itemAtPath = (cst, path16) => {
4887
4896
  }
4888
4897
  return item;
4889
4898
  };
4890
- visit2.parentCollection = (cst, path16) => {
4891
- const parent = visit2.itemAtPath(cst, path16.slice(0, -1));
4892
- const field = path16[path16.length - 1][0];
4899
+ visit2.parentCollection = (cst, path17) => {
4900
+ const parent = visit2.itemAtPath(cst, path17.slice(0, -1));
4901
+ const field = path17[path17.length - 1][0];
4893
4902
  const coll = parent?.[field];
4894
4903
  if (coll && "items" in coll)
4895
4904
  return coll;
4896
4905
  throw new Error("Parent collection not found");
4897
4906
  };
4898
- function _visit(path16, item, visitor) {
4899
- let ctrl = visitor(item, path16);
4907
+ function _visit(path17, item, visitor) {
4908
+ let ctrl = visitor(item, path17);
4900
4909
  if (typeof ctrl === "symbol")
4901
4910
  return ctrl;
4902
4911
  for (const field of ["key", "value"]) {
4903
4912
  const token = item[field];
4904
4913
  if (token && "items" in token) {
4905
4914
  for (let i = 0; i < token.items.length; ++i) {
4906
- const ci = _visit(Object.freeze(path16.concat([[field, i]])), token.items[i], visitor);
4915
+ const ci = _visit(Object.freeze(path17.concat([[field, i]])), token.items[i], visitor);
4907
4916
  if (typeof ci === "number")
4908
4917
  i = ci - 1;
4909
4918
  else if (ci === BREAK2)
@@ -4914,10 +4923,10 @@ function _visit(path16, item, visitor) {
4914
4923
  }
4915
4924
  }
4916
4925
  if (typeof ctrl === "function" && field === "key")
4917
- ctrl = ctrl(item, path16);
4926
+ ctrl = ctrl(item, path17);
4918
4927
  }
4919
4928
  }
4920
- return typeof ctrl === "function" ? ctrl(item, path16) : ctrl;
4929
+ return typeof ctrl === "function" ? ctrl(item, path17) : ctrl;
4921
4930
  }
4922
4931
 
4923
4932
  // ../../node_modules/yaml/browser/dist/parse/lexer.js
@@ -5378,7 +5387,8 @@ function writeSecureJsonAtomic(filepath, value) {
5378
5387
 
5379
5388
  // cli/current-sim.ts
5380
5389
  var CURRENT_SIM_VERSION = 2;
5381
- var CURRENT_SIM_PATH_ENV = "SOOTSIM_CLI_CURRENT_SIM_PATH";
5390
+ var CURRENT_SIM_PATH_ENV = "PEACH_CLI_CURRENT_SIM_PATH";
5391
+ var LEGACY_CURRENT_SIM_PATH_ENV = "SOOTSIM_CLI_CURRENT_SIM_PATH";
5382
5392
  var IDENTITY_ENV_VARS = [
5383
5393
  "PEACH_CLI_IDENTITY",
5384
5394
  // explicit override — fastest path, skips all pid lookups
@@ -5457,8 +5467,9 @@ function getOwnerProcessGroupId() {
5457
5467
  return pgid !== null && pgid > 1 ? pgid : null;
5458
5468
  }
5459
5469
  function getCurrentSimPath() {
5460
- if (process.env[CURRENT_SIM_PATH_ENV]) {
5461
- return (0, import_path.resolve)(process.env[CURRENT_SIM_PATH_ENV]);
5470
+ const envPath = process.env[CURRENT_SIM_PATH_ENV] || process.env[LEGACY_CURRENT_SIM_PATH_ENV];
5471
+ if (envPath) {
5472
+ return (0, import_path.resolve)(envPath);
5462
5473
  }
5463
5474
  const key = getCliIdentityKey();
5464
5475
  return (0, import_path.join)((0, import_os.tmpdir)(), `peach-current-sim-${key}.json`);
@@ -5568,9 +5579,9 @@ function pathContains(parent, child) {
5568
5579
  function resolveDefaultDevBridgeLockfile() {
5569
5580
  const lockfiles = liveDevBridgeLockfiles();
5570
5581
  if (lockfiles.length === 0) return null;
5571
- if (process.env.SOOTSIM_BRIDGE_PORT !== void 0 || process.env.PORT_OFFSET !== void 0) {
5582
+ if (process.env.PEACH_BRIDGE_PORT !== void 0 || process.env.PORT_OFFSET !== void 0) {
5572
5583
  const requestedPort = resolveSootsimBridgePort({
5573
- explicitPort: process.env.SOOTSIM_BRIDGE_PORT,
5584
+ explicitPort: process.env.PEACH_BRIDGE_PORT,
5574
5585
  portOffset: process.env.PORT_OFFSET
5575
5586
  });
5576
5587
  return lockfiles.find((lockfile) => lockfile.bridgePort === requestedPort) ?? null;
@@ -5615,10 +5626,10 @@ function resolveBridgeWorldFresh() {
5615
5626
  }
5616
5627
  const lock = readDaemonLockfile();
5617
5628
  const requestedPort = resolveSootsimBridgePort({
5618
- explicitPort: process.env.SOOTSIM_BRIDGE_PORT,
5629
+ explicitPort: process.env.PEACH_BRIDGE_PORT,
5619
5630
  portOffset: process.env.PORT_OFFSET
5620
5631
  });
5621
- const explicitWorld = process.env.SOOTSIM_BRIDGE_PORT !== void 0 || process.env.PORT_OFFSET !== void 0;
5632
+ const explicitWorld = process.env.PEACH_BRIDGE_PORT !== void 0 || process.env.PORT_OFFSET !== void 0;
5622
5633
  if (lock && isDaemonLockfileFresh(lock) && (!explicitWorld || lock.bridgePort === requestedPort)) {
5623
5634
  return {
5624
5635
  source: "daemon",
@@ -5743,7 +5754,8 @@ function createBridge(wsPort, opts = {}) {
5743
5754
  }
5744
5755
  function maybeNoticeTarget(cmdType, simId) {
5745
5756
  if (noticedTarget) return;
5746
- if (process.env.SOOTSIM_QUIET_TARGET_NOTICE === "1") return;
5757
+ if (process.env.PEACH_QUIET_TARGET_NOTICE === "1" || process.env.SOOTSIM_QUIET_TARGET_NOTICE === "1")
5758
+ return;
5747
5759
  if (cmdType.startsWith("bridge:") || cmdType === "focus" || cmdType === "close")
5748
5760
  return;
5749
5761
  noticedTarget = true;
@@ -5926,7 +5938,6 @@ function createBridge(wsPort, opts = {}) {
5926
5938
  }
5927
5939
 
5928
5940
  // src/bridge-contract.ts
5929
- var PUBLIC_NO_NETWORK_MARKER = "public Peach Cloud simulators have no network";
5930
5941
  var HEADLESS_TENANT_FETCH_HUNG_MARKER = "headless tenant fetch hung";
5931
5942
 
5932
5943
  // cli/commands/inspect/core.ts
@@ -6493,7 +6504,7 @@ async function inspectFind(bridge, q) {
6493
6504
  }
6494
6505
  function waitReadyReason(status) {
6495
6506
  if (status.bridgeError) {
6496
- if (status.bridgeError.includes(HEADLESS_TENANT_FETCH_HUNG_MARKER) || status.bridgeError.includes(PUBLIC_NO_NETWORK_MARKER)) {
6507
+ if (status.bridgeError.includes(HEADLESS_TENANT_FETCH_HUNG_MARKER)) {
6497
6508
  return status.bridgeError;
6498
6509
  }
6499
6510
  return `sim unreachable: ${status.bridgeError} \u2014 the target tab is closed or no sim is connected (check \`peach list\`, reopen with \`peach open\`)`;
@@ -6743,6 +6754,17 @@ async function resolveTargetCoords(bridge, target) {
6743
6754
  }
6744
6755
 
6745
6756
  // cli/commands/inspect/settling.ts
6757
+ var RuntimeReadinessUnsupportedError = class extends Error {
6758
+ constructor(runtimeVersion, missingFields) {
6759
+ super(
6760
+ `runtime ${runtimeVersion} cannot report animation readiness (${missingFields.join(", ")} missing); run \`peach upgrade\` and reopen the simulator`
6761
+ );
6762
+ this.runtimeVersion = runtimeVersion;
6763
+ this.missingFields = missingFields;
6764
+ this.name = "RuntimeReadinessUnsupportedError";
6765
+ }
6766
+ code = "runtime_readiness_unsupported";
6767
+ };
6746
6768
  async function waitForSootsimIdle({
6747
6769
  bridge,
6748
6770
  simId,
@@ -6752,16 +6774,23 @@ async function waitForSootsimIdle({
6752
6774
  strict = false,
6753
6775
  paintStill = false
6754
6776
  }) {
6755
- const result = await bridge.send(
6756
- {
6757
- type: "evaluate",
6758
- simId,
6759
- code: `(async () => {
6777
+ let result;
6778
+ try {
6779
+ result = await bridge.send(
6780
+ {
6781
+ type: "evaluate",
6782
+ simId,
6783
+ code: `(async () => {
6760
6784
  const start = Date.now()
6761
6785
  const deadline = start + ${Math.max(0, Math.round(maxMs))}
6762
6786
  const pollMs = ${Math.max(1, Math.round(pollMs))}
6763
6787
  const strict = ${strict ? "true" : "false"}
6764
6788
  const paintStill = ${paintStill ? "true" : "false"}
6789
+ // full mounted-geometry observation needs at least two hierarchy reads
6790
+ // plus the stillness window, which a sub-second budget cannot afford:
6791
+ // tight budgets (auto-wait) settle on worker stillness plus root
6792
+ // membership, generous ones confirm the geometry too.
6793
+ const fullGeometry = ${maxMs >= 1e3 ? "true" : "false"}
6765
6794
  const requiredStillMs = paintStill ? 0 : ${Math.max(1, Math.round(stablePolls)) * Math.max(1, Math.round(pollMs))}
6766
6795
  const minimumStablePolls = paintStill ? 1 : ${Math.min(2, Math.max(1, Math.round(stablePolls)))}
6767
6796
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
@@ -6798,58 +6827,177 @@ async function waitForSootsimIdle({
6798
6827
  }
6799
6828
  } catch {}
6800
6829
 
6830
+ // a worker that cannot answer within the remaining budget is busy, not
6831
+ // idle: its poll reads as unsettled. bounding each read by the budget
6832
+ // keeps a busy worker from holding a poll past the deadline.
6833
+ const BUSY = { busy: true }
6834
+ const answer = (read) =>
6835
+ Promise.race([
6836
+ Promise.resolve().then(read),
6837
+ new Promise((resolve) =>
6838
+ setTimeout(() => resolve(BUSY), Math.max(deadline - Date.now(), 100)),
6839
+ ),
6840
+ ])
6841
+
6801
6842
  const readSnapshot = async () => {
6802
6843
  let animating = false
6803
6844
  let layoutDirty = false
6804
6845
  let pendingFetches = 0
6846
+ let workerBusy = false
6805
6847
  let requestTotal = 0
6806
6848
  let requestInFlight = 0
6849
+ let appCommits = null
6850
+ let nodeCount = null
6807
6851
  let renderStatsAvailable = false
6808
6852
  let shellAnimating = false
6853
+ let webViewStarting = false
6854
+ let webViewBlocker = ''
6809
6855
  // strict also waits out shell motion: a system alert, sheet or menu
6810
6856
  // animates in the shell worker while the app's own stats read still,
6811
6857
  // so its presentation is complete only once the shell's list empties.
6812
6858
  if (strict) {
6813
- try {
6814
- const motion = await window.__sootsimTest?.listAnimations?.()
6815
- shellAnimating = Array.isArray(motion) && motion.some((anim) => anim.realm === 'shell')
6816
- } catch {}
6859
+ const motion = await answer(() => window.__sootsimTest?.listAnimations?.()).catch(() => null)
6860
+ if (motion === BUSY) workerBusy = true
6861
+ else shellAnimating = Array.isArray(motion) && motion.some((anim) => anim.realm === 'shell' && anim.priority !== 'low')
6817
6862
  }
6818
- try {
6819
- const stats = await window.__sootsimRenderHost?.queryStats?.()
6820
- if (stats) {
6821
- renderStatsAvailable = true
6822
- animating =
6823
- stats.hasActiveAnims === true ||
6824
- stats.hasActiveNativeAnimations === true ||
6825
- stats.hasPendingAnimationFrames === true
6826
- layoutDirty =
6827
- stats.layoutDirty === true && stats.renderRequested === true
6828
- // a freshly-pushed screen showing a skeleton is layout-stable
6829
- // but not actually settled \u2014 its data/images are still in
6830
- // flight. treat bounded image-loader fetches as not-idle so
6831
- // settle waits for real content, capped by the budget.
6832
- const pf = stats.memory && stats.memory.imageLoader
6833
- ? stats.memory.imageLoader.pendingFetches
6834
- : 0
6835
- pendingFetches = typeof pf === 'number' ? pf : 0
6863
+ const stats = await answer(() => window.__sootsimRenderHost?.queryStats?.()).catch(() => null)
6864
+ if (stats === BUSY) {
6865
+ workerBusy = true
6866
+ } else if (stats) {
6867
+ renderStatsAvailable = true
6868
+ const missingFields = ['hasActiveBlockingNativeAnimations', 'hasPendingBlockingAnimationFrames']
6869
+ .filter((field) => typeof stats[field] !== 'boolean')
6870
+ if (strict && missingFields.length > 0) {
6871
+ return {
6872
+ runtimeUnsupported: {
6873
+ error: 'runtime_readiness_unsupported',
6874
+ runtimeVersion: window.__sootsimRuntimeVersion || 'unknown',
6875
+ missingFields,
6876
+ },
6877
+ }
6836
6878
  }
6837
- } catch {}
6879
+ // positive checks only: an older runtime without the blocking
6880
+ // fields reads as still, and strict rejects that runtime above
6881
+ // instead of ever settling on unknown motion.
6882
+ animating =
6883
+ stats.hasActiveAnims === true ||
6884
+ stats.hasActiveBlockingNativeAnimations === true ||
6885
+ stats.hasPendingBlockingAnimationFrames === true
6886
+ layoutDirty =
6887
+ stats.layoutDirty === true && stats.renderRequested === true
6888
+ // a freshly-pushed screen showing a skeleton is layout-stable
6889
+ // but not actually settled \u2014 its data/images are still in
6890
+ // flight. treat bounded image-loader fetches as not-idle so
6891
+ // settle waits for real content, capped by the budget.
6892
+ const pf = stats.memory && stats.memory.imageLoader
6893
+ ? stats.memory.imageLoader.pendingFetches
6894
+ : 0
6895
+ pendingFetches = typeof pf === 'number' ? pf : 0
6896
+ // tenant layout commits: a screen that keeps committing is still
6897
+ // mounting or remounting, even with no animation flag raised.
6898
+ appCommits = typeof stats.appCommitCount === 'number' ? stats.appCommitCount : null
6899
+ }
6900
+ // image preparation ends in the tenant before the compositor decodes
6901
+ // and realizes its pixels. both owners must finish before settling.
6902
+ // the compositor rejects a stats request it is too busy to answer.
6903
+ const compositor = await answer(() => window.__sootsimCompositor.getStats()).catch(() => BUSY)
6904
+ if (compositor === BUSY) {
6905
+ workerBusy = true
6906
+ } else {
6907
+ pendingFetches += compositor.images.pendingFetches
6908
+ pendingFetches += compositor.imageRealization.pending
6909
+ if (compositor.webViewCaptureSettled === false) {
6910
+ webViewStarting = true
6911
+ webViewBlocker = 'compositor webView capture not settled'
6912
+ }
6913
+ }
6838
6914
  try {
6839
6915
  const counts = await window.__sootsimTest?.getRequestCounts?.()
6840
6916
  requestTotal = typeof counts?.total === 'number' ? counts.total : 0
6841
6917
  requestInFlight = typeof counts?.inFlight === 'number' ? counts.inFlight : 0
6842
6918
  } catch {}
6843
- const root = window.__sootsimRoot
6919
+ // mounted-root membership: the live node count moves while the tree
6920
+ // mounts, unmounts or recycles, in either render mode.
6921
+ try {
6922
+ const total = await window.__sootsimTest?.getNodeCount?.()
6923
+ nodeCount = typeof total === 'number' ? total : null
6924
+ } catch {}
6925
+ // the mounted hierarchy in render-worker mode comes from the test
6926
+ // bridge: window.__sootsimRoot is an empty placeholder there, so a
6927
+ // walk over it hashes every screen to the same empty string while
6928
+ // it moves. listInspectable is the worker-backed read describe
6929
+ // uses; a worker too busy to answer it reads as unsettled. tight
6930
+ // budgets skip this read and settle on the cheaper signals above.
6931
+ let hierarchy = null
6932
+ if (fullGeometry && typeof window.__sootsimTest?.listInspectable === 'function') {
6933
+ try {
6934
+ hierarchy = await answer(() => window.__sootsimTest.listInspectable({}))
6935
+ } catch {
6936
+ hierarchy = null
6937
+ }
6938
+ }
6939
+ if (hierarchy === BUSY) {
6940
+ workerBusy = true
6941
+ hierarchy = null
6942
+ } else if (!Array.isArray(hierarchy)) {
6943
+ hierarchy = null
6944
+ }
6844
6945
  const nodes = []
6845
- if (root) {
6846
- const walk = (n) => {
6847
- if (n.layout && n.layout.width > 0) {
6848
- nodes.push(Math.round(n.layout.x) + ',' + Math.round(n.layout.y) + ',' + Math.round(n.layout.width))
6946
+ const PREVIEW_PROGRESS_REGEX = /^(creating webview|loading html|fetching bundle|waiting for first render|starting preview|loading simulator|fetching app code|waiting for native preview|starting design|loading canvas|fetching screens|painting the canvas|waiting for webview|waiting for preview|waiting for canvas|preview stalled)/i
6947
+ const notePreviewProgress = (tid, text) => {
6948
+ if (typeof tid === 'string' && (tid === 'web-preview-progress' || tid.endsWith('-preview-progress'))) {
6949
+ webViewStarting = true
6950
+ if (!webViewBlocker) webViewBlocker = 'preview progress active (' + tid + ')'
6951
+ }
6952
+ if (typeof text === 'string' && PREVIEW_PROGRESS_REGEX.test(text.trim())) {
6953
+ webViewStarting = true
6954
+ if (!webViewBlocker) webViewBlocker = 'webView startup in progress ("' + text.trim() + '")'
6955
+ }
6956
+ }
6957
+ if (hierarchy) {
6958
+ for (const n of hierarchy) {
6959
+ const layout = n && n.layout
6960
+ if (layout && layout.width > 0) {
6961
+ const abs = (n && (n.absolute || n.absolutePosition)) || layout
6962
+ nodes.push(Math.round(abs.x) + ',' + Math.round(abs.y) + ',' + Math.round(layout.width))
6963
+ }
6964
+ notePreviewProgress(
6965
+ n.testID || n.testId,
6966
+ typeof n.text === 'string' ? n.text : '',
6967
+ )
6968
+ }
6969
+ } else {
6970
+ const root = window.__sootsimRoot
6971
+ if (root) {
6972
+ const walk = (n) => {
6973
+ if (n.layout && n.layout.width > 0) {
6974
+ nodes.push(Math.round(n.layout.x) + ',' + Math.round(n.layout.y) + ',' + Math.round(n.layout.width))
6975
+ }
6976
+ notePreviewProgress(
6977
+ n.testID || n.props?.testID || n.props?.testId,
6978
+ n.textContent || (typeof n.props?.children === 'string' ? n.props.children : ''),
6979
+ )
6980
+ for (const c of n.children || []) walk(c)
6981
+ }
6982
+ walk(root)
6983
+ }
6984
+ }
6985
+ if (!webViewStarting && typeof document !== 'undefined') {
6986
+ const progressEl = document.querySelector(
6987
+ '[data-testid$="-preview-progress"], [data-testid="web-preview-progress"], [data-testid="ios-preview-progress"], [data-testid="design-preview-progress"]'
6988
+ )
6989
+ if (progressEl) {
6990
+ webViewStarting = true
6991
+ webViewBlocker = 'preview progress element displayed'
6992
+ } else {
6993
+ const unreadyWebView = document.querySelector(
6994
+ '[data-sootsim-webview-loading="true"], [data-sootsim-webview-mode="placeholder"]'
6995
+ )
6996
+ if (unreadyWebView) {
6997
+ webViewStarting = true
6998
+ webViewBlocker = 'webView document still loading'
6849
6999
  }
6850
- for (const c of n.children || []) walk(c)
6851
7000
  }
6852
- walk(root)
6853
7001
  }
6854
7002
  if (paintStill) {
6855
7003
  const canvas = composite.getCanvas()
@@ -6863,7 +7011,7 @@ async function waitForSootsimIdle({
6863
7011
  pixelFrameToken = token
6864
7012
  }
6865
7013
  }
6866
- return { layout: nodes.join(';'), screenPixels, animating, shellAnimating, layoutDirty, pendingFetches, renderStatsAvailable, requestTotal, requestInFlight }
7014
+ return { layout: nodes.join(';'), screenPixels, animating, shellAnimating, layoutDirty, pendingFetches, workerBusy, webViewStarting, webViewBlocker, renderStatsAvailable, requestTotal, requestInFlight, appCommits, nodeCount }
6867
7015
  }
6868
7016
 
6869
7017
  // how long generic background network is allowed to keep us waiting AFTER
@@ -6881,6 +7029,8 @@ async function waitForSootsimIdle({
6881
7029
  let lastScreenPixels = null
6882
7030
  let screenChangedPolls = 0
6883
7031
  let lastRequestTotal = -1
7032
+ let lastAppCommits = null
7033
+ let lastNodeCount = null
6884
7034
  let stable = 0
6885
7035
  let visuallyStillSince = 0
6886
7036
  // counts across the whole budget: a flag that is true on every poll is a
@@ -6890,6 +7040,7 @@ async function waitForSootsimIdle({
6890
7040
  let dirtyPolls = 0
6891
7041
  let animatingPolls = 0
6892
7042
  let layoutChangedPolls = 0
7043
+ let webViewStartingPolls = 0
6893
7044
  const screenUnchanged = (pixels) => {
6894
7045
  if (!pixels || !lastScreenPixels || pixels.width !== lastScreenPixels.width || pixels.height !== lastScreenPixels.height) return false
6895
7046
  if (pixels === lastScreenPixels) return true
@@ -6900,9 +7051,11 @@ async function waitForSootsimIdle({
6900
7051
  }
6901
7052
  while (Date.now() < deadline) {
6902
7053
  const snapshot = await readSnapshot()
7054
+ if (snapshot.runtimeUnsupported) return snapshot.runtimeUnsupported
6903
7055
  polls++
6904
7056
  if (snapshot.layoutDirty) dirtyPolls++
6905
7057
  if (snapshot.animating || snapshot.shellAnimating) animatingPolls++
7058
+ if (snapshot.webViewStarting) webViewStartingPolls++
6906
7059
  if (polls > 1 && snapshot.layout !== lastLayout) layoutChangedPolls++
6907
7060
  const screenChanged = paintStill && !screenUnchanged(snapshot.screenPixels)
6908
7061
  if (polls > 1 && screenChanged) screenChangedPolls++
@@ -6912,12 +7065,24 @@ async function waitForSootsimIdle({
6912
7065
  !snapshot.animating &&
6913
7066
  !snapshot.shellAnimating &&
6914
7067
  !snapshot.layoutDirty)
6915
- // visually settled: no animations, no image content loading, layout
6916
- // unchanged since the last poll.
7068
+ // visually settled: no worker motion or layout work, no new layout
7069
+ // commits, a stable mounted node count, no image content loading,
7070
+ // no webview startup in progress, layout unchanged since the last
7071
+ // poll. both modes wait out finite worker motion now; strict
7072
+ // additionally implies the flags through strictOk and adds shell
7073
+ // motion plus the blocking-stats floor. a null count or commit
7074
+ // reading means the runtime does not report it, which reads as
7075
+ // stable the way a missing stats block does.
6917
7076
  const visuallyStill =
6918
7077
  strictOk &&
7078
+ !snapshot.animating &&
7079
+ !snapshot.layoutDirty &&
7080
+ (snapshot.appCommits === null || lastAppCommits === null || snapshot.appCommits === lastAppCommits) &&
7081
+ (snapshot.nodeCount === null || lastNodeCount === null || snapshot.nodeCount === lastNodeCount) &&
6919
7082
  !screenChanged &&
6920
7083
  snapshot.pendingFetches === 0 &&
7084
+ !snapshot.workerBusy &&
7085
+ !snapshot.webViewStarting &&
6921
7086
  snapshot.layout === lastLayout
6922
7087
  // generic network quiet: nothing in flight and no new requests issued.
6923
7088
  const networkQuiet =
@@ -6942,15 +7107,22 @@ async function waitForSootsimIdle({
6942
7107
  lastLayout = snapshot.layout
6943
7108
  lastScreenPixels = snapshot.screenPixels
6944
7109
  lastRequestTotal = snapshot.requestTotal
7110
+ lastAppCommits = snapshot.appCommits
7111
+ lastNodeCount = snapshot.nodeCount
6945
7112
  await sleep(pollMs)
6946
7113
  }
6947
7114
  const last = await readSnapshot()
7115
+ if (last.runtimeUnsupported) return last.runtimeUnsupported
6948
7116
  const blockers = []
6949
7117
  if (strict && !last.renderStatsAvailable) blockers.push('render stats unavailable')
6950
7118
  if (last.animating) blockers.push('animations still running')
6951
7119
  if (last.shellAnimating) blockers.push('shell animations still running')
6952
7120
  if (last.layoutDirty) blockers.push('layout still dirty')
7121
+ if (last.appCommits !== null && lastAppCommits !== null && last.appCommits !== lastAppCommits) blockers.push('layout commits still landing')
7122
+ if (last.nodeCount !== null && lastNodeCount !== null && last.nodeCount !== lastNodeCount) blockers.push('node count still changing')
6953
7123
  if (last.pendingFetches > 0) blockers.push(last.pendingFetches + ' image fetches pending')
7124
+ if (last.workerBusy) blockers.push('a render worker too busy to report')
7125
+ if (last.webViewStarting) blockers.push(last.webViewBlocker || 'webView still starting')
6954
7126
  if (last.layout !== lastLayout) blockers.push('layout still changing')
6955
7127
  if (paintStill && !last.screenPixels) blockers.push('screen pixels unavailable')
6956
7128
  else if (paintStill && !screenUnchanged(last.screenPixels)) blockers.push('screen pixels still changing')
@@ -6963,17 +7135,31 @@ async function waitForSootsimIdle({
6963
7135
  blockedBy:
6964
7136
  (blockers.length ? blockers.join(', ') : 'unknown') +
6965
7137
  ' over ' + polls + ' polls (layout changed ' + layoutChangedPolls +
6966
- 'x, layoutDirty ' + dirtyPolls + 'x, animating ' + animatingPolls + 'x, screen changed ' + screenChangedPolls + 'x)',
7138
+ 'x, layoutDirty ' + dirtyPolls + 'x, animating ' + animatingPolls + 'x, webViewStarting ' + webViewStartingPolls + 'x, screen changed ' + screenChangedPolls + 'x)',
6967
7139
  }
6968
7140
  } finally {
6969
7141
  unsubscribe?.()
6970
7142
  }
6971
7143
  })()`
6972
- },
6973
- {
6974
- timeoutMs: maxMs + 1e3
6975
- }
6976
- );
7144
+ },
7145
+ {
7146
+ timeoutMs: Math.max(5e3, maxMs + 2e3)
7147
+ }
7148
+ );
7149
+ } catch (error) {
7150
+ const message = error instanceof Error ? error.message : String(error);
7151
+ return {
7152
+ settled: false,
7153
+ elapsed: maxMs,
7154
+ blockedBy: message
7155
+ };
7156
+ }
7157
+ if (result?.error === "runtime_readiness_unsupported" && typeof result.runtimeVersion === "string" && Array.isArray(result.missingFields) && result.missingFields.every((field) => typeof field === "string")) {
7158
+ throw new RuntimeReadinessUnsupportedError(
7159
+ result.runtimeVersion,
7160
+ result.missingFields
7161
+ );
7162
+ }
6977
7163
  const { elapsed, settled, blockedBy } = result ?? {};
6978
7164
  return {
6979
7165
  elapsed: typeof elapsed === "number" ? elapsed : maxMs,
@@ -7424,7 +7610,7 @@ function buildSimOpenUrl(currentUrl, target) {
7424
7610
  const url = new URL(currentUrl);
7425
7611
  for (const param of TARGET_SEARCH_PARAMS) url.searchParams.delete(param);
7426
7612
  const pathname = url.pathname.replace(/\/+$/, "") || "/";
7427
- const prefix2 = pathname === "/__soot" || pathname.startsWith("/__soot/") ? "/__soot" : "";
7613
+ const prefix2 = pathname === "/__peachsim" || pathname.startsWith("/__peachsim/") ? "/__peachsim" : "";
7428
7614
  const normalized = String(target).trim();
7429
7615
  if (/^\d+$/.test(normalized)) {
7430
7616
  url.pathname = `${prefix2}/rn/${normalized}`;
@@ -7870,26 +8056,44 @@ function isLiveRasterSource(node) {
7870
8056
  const source = node.props?.source;
7871
8057
  return node.type === "image" && !!source && typeof source === "object" && "uri" in source && typeof source.uri === "string" && source.uri.startsWith("live:");
7872
8058
  }
8059
+ function rasterLayerFrame(node) {
8060
+ const visible = node.visibleFrame;
8061
+ if (isLiveRasterSource(node) && visible && visible.width > 0 && visible.height > 0) {
8062
+ return { x: visible.x, y: visible.y, width: visible.width, height: visible.height };
8063
+ }
8064
+ return node.frame ?? {
8065
+ x: node.absolutePosition.x,
8066
+ y: node.absolutePosition.y,
8067
+ width: node.layout.width,
8068
+ height: node.layout.height
8069
+ };
8070
+ }
7873
8071
  function selectRnxRasterNodeIds(tree) {
7874
8072
  const nodesById = new Map(tree.nodes.map((node) => [node.nodeId, node]));
7875
8073
  const maxLayerArea = tree.width * tree.height * 0.25;
7876
8074
  const eligible = /* @__PURE__ */ new Map();
7877
8075
  for (const node of tree.nodes) {
7878
8076
  const liveVideo = isLiveRasterSource(node);
7879
- const visibleFrame = liveVideo && node.visibleFrame && (node.visibleFrame.width <= 0 || node.visibleFrame.height <= 0) ? node.frame : node.visibleFrame ?? node.frame;
8077
+ const visibleFrame = liveVideo ? rasterLayerFrame(node) : node.visibleFrame ?? node.frame;
7880
8078
  if (!visibleFrame || visibleFrame.width <= 0 || visibleFrame.height <= 0) continue;
8079
+ const glass = node.style._liquidGlass !== void 0 || node.style._liquidGlassEdge !== void 0 || node.style._liquidGlassMaterialTint !== void 0;
7881
8080
  const unsupported = node.type === "masked-view" || liveVideo || node.type === "text" && typeof node.text === "string" && (new RegExp("\\p{Emoji_Presentation}", "u").test(node.text) || new RegExp("\\uFE0F|\\u200D|\\u20E3|\\p{Emoji_Modifier}|\\p{Regional_Indicator}", "u").test(
7882
8081
  node.text
7883
- )) || node.style._liquidGlass !== void 0 || node.style._liquidGlassEdge !== void 0 || node.style._liquidGlassMaterialTint !== void 0;
7884
- const area = visibleFrame.width * visibleFrame.height;
7885
- if (unsupported && (liveVideo || area <= maxLayerArea)) {
7886
- eligible.set(node.nodeId, { nodeId: node.nodeId, area, liveVideo });
8082
+ )) || glass;
8083
+ if (!unsupported) continue;
8084
+ const captured = rasterLayerFrame(node);
8085
+ const area = captured.width * captured.height;
8086
+ if (liveVideo || area <= maxLayerArea) {
8087
+ eligible.set(node.nodeId, { nodeId: node.nodeId, area, liveVideo, ownPaint: false });
8088
+ } else if (glass) {
8089
+ eligible.set(node.nodeId, { nodeId: node.nodeId, area, liveVideo, ownPaint: true });
7887
8090
  }
7888
8091
  }
7889
8092
  for (const nodeId of [...eligible.keys()]) {
7890
8093
  let parentNodeId = nodesById.get(nodeId)?.parentNodeId ?? null;
7891
8094
  while (parentNodeId !== null) {
7892
- if (eligible.has(parentNodeId)) {
8095
+ const parent = eligible.get(parentNodeId);
8096
+ if (parent && !parent.ownPaint) {
7893
8097
  eligible.delete(nodeId);
7894
8098
  break;
7895
8099
  }
@@ -7897,29 +8101,29 @@ function selectRnxRasterNodeIds(tree) {
7897
8101
  }
7898
8102
  }
7899
8103
  const candidates = [...eligible.values()].sort(
7900
- (left, right) => Number(right.liveVideo) - Number(left.liveVideo) || left.area - right.area || left.nodeId - right.nodeId
8104
+ (left, right) => Number(right.liveVideo) - Number(left.liveVideo) || Number(right.ownPaint) - Number(left.ownPaint) || left.area - right.area || left.nodeId - right.nodeId
7901
8105
  );
7902
8106
  const screenArea = tree.width * tree.height;
7903
- const selected = /* @__PURE__ */ new Set();
8107
+ const selection = { nodeIds: /* @__PURE__ */ new Set(), ownPaint: /* @__PURE__ */ new Set() };
7904
8108
  let atlasArea = 0;
8109
+ let layerArea = 0;
7905
8110
  for (const candidate of candidates) {
7906
- const maxAtlasArea = screenArea * (candidate.liveVideo ? 1 : 0.5);
7907
- if (atlasArea + candidate.area > maxAtlasArea) continue;
7908
- selected.add(candidate.nodeId);
8111
+ const leading = candidate.liveVideo || candidate.ownPaint;
8112
+ if (atlasArea + candidate.area > screenArea * (leading ? 1 : 1.25) || !leading && layerArea + candidate.area > screenArea * 0.5) {
8113
+ continue;
8114
+ }
8115
+ selection.nodeIds.add(candidate.nodeId);
8116
+ if (candidate.ownPaint) selection.ownPaint.add(candidate.nodeId);
7909
8117
  atlasArea += candidate.area;
8118
+ if (!leading) layerArea += candidate.area;
7910
8119
  }
7911
- return selected;
8120
+ return selection;
7912
8121
  }
7913
8122
  function rnxRasterFrames(tree, nodeIds) {
7914
8123
  const frames = /* @__PURE__ */ new Map();
7915
8124
  for (const node of tree.nodes) {
7916
8125
  if (!nodeIds.has(node.nodeId)) continue;
7917
- const frame = node.frame ?? {
7918
- x: node.absolutePosition.x,
7919
- y: node.absolutePosition.y,
7920
- width: node.layout.width,
7921
- height: node.layout.height
7922
- };
8126
+ const frame = rasterLayerFrame(node);
7923
8127
  const glassOutset = liquidGlassPaintOutset(node.style._liquidGlass, frame);
7924
8128
  const shadowRadius = typeof node.style.shadowRadius === "number" ? node.style.shadowRadius : 0;
7925
8129
  const shadowOffset = node.style.shadowOffset;
@@ -7993,11 +8197,22 @@ function rnxCaptureRasterRegions(capture) {
7993
8197
  visibleFrame: node.layout.visibleFrame
7994
8198
  }))
7995
8199
  };
7996
- const nodeIds = selectRnxRasterNodeIds(tree);
7997
- const frames = rnxRasterFrames(tree, nodeIds);
7998
- return [...nodeIds].flatMap((nodeId) => {
8200
+ const selection = selectRnxRasterNodeIds(tree);
8201
+ return rnxRasterRegionRequests(tree, selection);
8202
+ }
8203
+ function rnxRasterRegionRequests(tree, selection) {
8204
+ const frames = rnxRasterFrames(tree, selection.nodeIds);
8205
+ return [...selection.nodeIds].flatMap((nodeId) => {
7999
8206
  const frame = frames.get(nodeId);
8000
- return frame ? [{ key: String(nodeId), nodeId, frame }] : [];
8207
+ if (!frame) return [];
8208
+ return [
8209
+ {
8210
+ key: String(nodeId),
8211
+ nodeId,
8212
+ frame,
8213
+ ...selection.ownPaint.has(nodeId) ? { ownPaint: true } : {}
8214
+ }
8215
+ ];
8001
8216
  });
8002
8217
  }
8003
8218
  function packRnxCaptureRegions(regions, pixelRatio, surface) {
@@ -8018,6 +8233,7 @@ function packRnxCaptureRegions(regions, pixelRatio, surface) {
8018
8233
  return {
8019
8234
  key: region.key,
8020
8235
  nodeId: region.nodeId,
8236
+ ...region.ownPaint ? { ownPaint: true } : {},
8021
8237
  frame: {
8022
8238
  x: left / pixelRatio,
8023
8239
  y: top / pixelRatio,
@@ -8083,6 +8299,7 @@ function packRnxCaptureRegions(regions, pixelRatio, surface) {
8083
8299
  atlasRegions: best.regions.map((region) => ({
8084
8300
  key: region.key,
8085
8301
  nodeId: region.nodeId,
8302
+ ...region.ownPaint ? { ownPaint: true } : {},
8086
8303
  frame: region.frame,
8087
8304
  // a region flush with the far edge is anchored to the logical edge so
8088
8305
  // its source never runs past the atlas by a rounding hair
@@ -8159,7 +8376,7 @@ function isRnxCaptureRegionAtlas(value) {
8159
8376
  }
8160
8377
  const keys = /* @__PURE__ */ new Set();
8161
8378
  for (const region of value.regions) {
8162
- if (!captureRecord(region) || typeof region.key !== "string" || region.key.length === 0 || keys.has(region.key) || !captureInteger(region.nodeId) || region.nodeId <= 0 || !captureRect(region.frame) || region.frame.width <= 0 || region.frame.height <= 0 || !captureRect(region.source) || region.source.x < 0 || region.source.y < 0 || region.source.width !== region.frame.width || region.source.height !== region.frame.height || region.source.x + region.source.width > value.width || region.source.y + region.source.height > value.height) {
8379
+ if (!captureRecord(region) || typeof region.key !== "string" || region.key.length === 0 || keys.has(region.key) || !captureInteger(region.nodeId) || region.nodeId <= 0 || region.ownPaint !== void 0 && region.ownPaint !== true || !captureRect(region.frame) || region.frame.width <= 0 || region.frame.height <= 0 || !captureRect(region.source) || region.source.x < 0 || region.source.y < 0 || region.source.width !== region.frame.width || region.source.height !== region.frame.height || region.source.x + region.source.width > value.width || region.source.y + region.source.height > value.height) {
8163
8380
  return false;
8164
8381
  }
8165
8382
  keys.add(region.key);
@@ -8170,7 +8387,7 @@ function isRnxCaptureRegionAtlas(value) {
8170
8387
  // src/vite-plugin-one.ts
8171
8388
  var import_fs4 = __toESM(require("fs"), 1);
8172
8389
  var import_node_crypto5 = require("node:crypto");
8173
- var import_node_module2 = require("node:module");
8390
+ var import_node_url = require("node:url");
8174
8391
  var import_path3 = __toESM(require("path"), 1);
8175
8392
  var import_ws2 = require("ws");
8176
8393
 
@@ -8312,6 +8529,8 @@ var SWIFT_HMR_PATH = "/__peach/swift-hmr";
8312
8529
  var MAX_SWIFT_COMPILE_SOURCE_BYTES = 2 * 1024 * 1024;
8313
8530
  var MAX_SWIFT_COMPILE_RESOURCE_BYTES = 2 * 1024 * 1024;
8314
8531
  var MAX_SWIFT_COMPILE_RESOURCE_TOTAL_BYTES = 8 * 1024 * 1024;
8532
+ var MAX_SWIFT_COMPILE_METAL_BYTES = 2 * 1024 * 1024;
8533
+ var MAX_SWIFT_COMPILE_METAL_TOTAL_BYTES = 8 * 1024 * 1024;
8315
8534
  var MAX_SWIFT_COMPILE_IMAGE_BYTES = 4 * 1024 * 1024;
8316
8535
  var MAX_SWIFT_COMPILE_IMAGE_TOTAL_BYTES = 16 * 1024 * 1024;
8317
8536
 
@@ -8662,8 +8881,8 @@ var loadSwiftHost = () => swiftHost ??= import("peachsim/vite-swift");
8662
8881
  var KOTLIN_ROUTE_PREFIX = "/__peach/kotlin";
8663
8882
  var kotlinHost;
8664
8883
  var loadKotlinHost = () => kotlinHost ??= import("peachsim/kotlin-host");
8665
- function rnxPlugin(options = {}) {
8666
- const prefix2 = options.prefix || "/__soot";
8884
+ function peachPlugin(options = {}) {
8885
+ const prefix2 = options.prefix || "/__peachsim";
8667
8886
  return {
8668
8887
  name: "sootsim-one",
8669
8888
  // use-latest-callback ships a CJS main (module.exports, no default) with
@@ -8684,12 +8903,9 @@ function rnxPlugin(options = {}) {
8684
8903
  let swiftModuleRoot;
8685
8904
  const moduleRootFor = () => {
8686
8905
  if (swiftModuleRoot === void 0) {
8687
- const peachsimPackage = (0, import_node_module2.createRequire)(
8688
- import_path3.default.join(server.config.root, "package.json")
8689
- ).resolve("peachsim/package.json");
8690
8906
  const moduleRoot = import_path3.default.resolve(
8691
- import_path3.default.dirname(peachsimPackage),
8692
- "../sootsim-swift"
8907
+ import_path3.default.dirname((0, import_node_url.fileURLToPath)(__sootsim_import_meta_url)),
8908
+ "../../sootsim-swift"
8693
8909
  );
8694
8910
  swiftModuleRoot = import_fs4.default.existsSync(import_path3.default.join(moduleRoot, "toolchain.json")) ? moduleRoot : null;
8695
8911
  }
@@ -8776,7 +8992,7 @@ function rnxPlugin(options = {}) {
8776
8992
  if (!pathname.startsWith(KOTLIN_ROUTE_PREFIX)) return next();
8777
8993
  loadKotlinHost().then(async (host) => {
8778
8994
  if (!kotlinModuleRoot) {
8779
- kotlinModuleRoot = host.peachKotlinModuleRoot(server.config.root);
8995
+ kotlinModuleRoot = host.peachKotlinModuleRoot();
8780
8996
  server.watcher.add(import_path3.default.join(kotlinModuleRoot, "Sources"));
8781
8997
  }
8782
8998
  const served = await host.serveKotlinRequest(pathname, res, {
@@ -9009,6 +9225,101 @@ var import_path4 = __toESM(require("path"), 1);
9009
9225
  init_app_project();
9010
9226
  init_replacement_module_handler();
9011
9227
 
9228
+ // src/openstep-plist.ts
9229
+ var isDict = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
9230
+ var str = (value) => typeof value === "string" ? value : void 0;
9231
+ var list = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
9232
+ function parseOpenStepPlist(text2) {
9233
+ let i = 0;
9234
+ const fail = (message) => {
9235
+ const line = text2.slice(0, i).split("\n").length;
9236
+ throw new Error(`project.pbxproj line ${line}: ${message}`);
9237
+ };
9238
+ const skip = () => {
9239
+ for (; ; ) {
9240
+ const ch = text2[i];
9241
+ if (ch === " " || ch === " " || ch === "\n" || ch === "\r") i++;
9242
+ else if (ch === "/" && text2[i + 1] === "*") {
9243
+ const end = text2.indexOf("*/", i + 2);
9244
+ if (end < 0) fail("unterminated comment");
9245
+ i = end + 2;
9246
+ } else if (ch === "/" && text2[i + 1] === "/") {
9247
+ const end = text2.indexOf("\n", i);
9248
+ i = end < 0 ? text2.length : end + 1;
9249
+ } else return;
9250
+ }
9251
+ };
9252
+ const quoted = () => {
9253
+ i++;
9254
+ let out = "";
9255
+ for (; ; ) {
9256
+ const ch = text2[i++];
9257
+ if (ch === void 0) fail("unterminated string");
9258
+ if (ch === '"') return out;
9259
+ if (ch !== "\\") {
9260
+ out += ch;
9261
+ continue;
9262
+ }
9263
+ const next = text2[i++];
9264
+ if (next === "n") out += "\n";
9265
+ else if (next === "t") out += " ";
9266
+ else if (next === "r") out += "\r";
9267
+ else if (next === "U") {
9268
+ out += String.fromCharCode(parseInt(text2.slice(i, i + 4), 16));
9269
+ i += 4;
9270
+ } else out += next;
9271
+ }
9272
+ };
9273
+ const value = () => {
9274
+ skip();
9275
+ const ch = text2[i];
9276
+ if (ch === "{") {
9277
+ i++;
9278
+ const dict = {};
9279
+ for (; ; ) {
9280
+ skip();
9281
+ if (text2[i] === "}") {
9282
+ i++;
9283
+ return dict;
9284
+ }
9285
+ const key = value();
9286
+ if (typeof key !== "string") fail("dictionary key is not a string");
9287
+ skip();
9288
+ if (text2[i++] !== "=") fail("expected =");
9289
+ if (Object.hasOwn(dict, key)) fail(`duplicate key ${key}`);
9290
+ dict[key] = value();
9291
+ skip();
9292
+ if (text2[i++] !== ";") fail("expected ;");
9293
+ }
9294
+ }
9295
+ if (ch === "(") {
9296
+ i++;
9297
+ const list2 = [];
9298
+ for (; ; ) {
9299
+ skip();
9300
+ if (text2[i] === ")") {
9301
+ i++;
9302
+ return list2;
9303
+ }
9304
+ list2.push(value());
9305
+ skip();
9306
+ if (text2[i] === ",") i++;
9307
+ else if (text2[i] !== ")") fail("expected , or )");
9308
+ }
9309
+ }
9310
+ if (ch === '"') return quoted();
9311
+ const start = i;
9312
+ while (i < text2.length && /[A-Za-z0-9_$+/:.\-<>]/.test(text2[i])) i++;
9313
+ if (i === start) fail(`unexpected ${JSON.stringify(ch ?? "end of file")}`);
9314
+ return text2.slice(start, i);
9315
+ };
9316
+ if (text2.startsWith("// !$*UTF8*$!")) i = text2.indexOf("\n") + 1;
9317
+ const root = value();
9318
+ skip();
9319
+ if (i !== text2.length) fail("trailing content");
9320
+ return root;
9321
+ }
9322
+
9012
9323
  // src/native-app-identity.ts
9013
9324
  var NATIVE_APP_IDENTITY_PREFIX = "globalThis.__sootsimNativeAppIdentity=";
9014
9325
  var METRO_MODULE_PATHS_PREFIX = "globalThis.__sootsimModulePaths=";
@@ -9019,7 +9330,9 @@ function nonEmptyString(value) {
9019
9330
  return typeof value === "string" && value.length > 0 ? value : null;
9020
9331
  }
9021
9332
  function createNativeAppIdentityFooter(identity) {
9022
- const payload = JSON.stringify(identity).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029").replace(/<\//g, "<\\/");
9333
+ const footerIdentity = { ...identity };
9334
+ delete footerIdentity.oneUpdates;
9335
+ const payload = JSON.stringify(footerIdentity).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029").replace(/<\//g, "<\\/");
9023
9336
  return `
9024
9337
  ${NATIVE_APP_IDENTITY_PREFIX}${payload};`;
9025
9338
  }
@@ -9120,30 +9433,119 @@ function appTargetReleaseSettings(pbxproj, targetName, infoPlistRelativePath) {
9120
9433
  (candidate) => candidate.name === "Release" && named(candidate.settings)
9121
9434
  )?.settings ?? null;
9122
9435
  }
9123
- function nativeAppIdentityFromIos(files, parseInfoPlist) {
9436
+ function nativeAppIdentityFromIos(files, parseInfoPlist, iosTarget) {
9124
9437
  const pbxprojPath = Object.keys(files).find(
9125
- (path16) => /(?:^|\/)ios\/[^/]+\.xcodeproj\/project\.pbxproj$/.test(path16)
9126
- );
9438
+ (path17) => /(?:^|\/)ios\/[^/]+\.xcodeproj\/project\.pbxproj$/.test(path17)
9439
+ ) ?? Object.keys(files).find(
9440
+ (path17) => /(?:^|\/)[^/]+\.xcodeproj\/project\.pbxproj$/.test(path17)
9441
+ ) ?? Object.keys(files).find((path17) => /(?:^|\/)project\.pbxproj$/.test(path17));
9127
9442
  if (!pbxprojPath) return null;
9128
9443
  const pbxproj = files[pbxprojPath];
9129
- const applicationTargets = new Set(
9130
- [
9131
- ...pbxproj.matchAll(
9132
- /isa = PBXNativeTarget;[^}]*?name = "?([^";]+)"?;[^}]*?productType = "com\.apple\.product-type\.application";/g
9133
- )
9134
- ].map((match) => match[1])
9444
+ let objects = {};
9445
+ try {
9446
+ const parsed = parseOpenStepPlist(pbxproj);
9447
+ if (isRecord2(parsed)) {
9448
+ objects = isRecord2(parsed.objects) ? parsed.objects : parsed;
9449
+ }
9450
+ } catch {
9451
+ }
9452
+ const targets = [];
9453
+ for (const [id, obj] of Object.entries(objects)) {
9454
+ if (isRecord2(obj) && obj.isa === "PBXNativeTarget" && typeof obj.name === "string") {
9455
+ targets.push({
9456
+ id,
9457
+ name: obj.name,
9458
+ productType: typeof obj.productType === "string" ? obj.productType : void 0,
9459
+ buildConfigurationList: typeof obj.buildConfigurationList === "string" ? obj.buildConfigurationList : void 0
9460
+ });
9461
+ }
9462
+ }
9463
+ const applicationTargetNames = new Set(
9464
+ targets.filter((t) => t.productType === "com.apple.product-type.application").map((t) => t.name)
9135
9465
  );
9136
- const appDelegatePattern = /(?:^|\/)ios\/([^/]+)\/AppDelegate\.(?:swift|mm|m)$/;
9137
- const targetName = Object.keys(files).filter((path16) => !path16.includes("/Pods/")).map((path16) => path16.match(appDelegatePattern)?.[1]).find((name2) => name2 !== void 0 && applicationTargets.has(name2)) ?? null;
9138
- if (!targetName) return null;
9139
- const plist3 = files[`ios/${targetName}/Info.plist`];
9466
+ if (applicationTargetNames.size === 0) {
9467
+ for (const match of pbxproj.matchAll(
9468
+ /isa = PBXNativeTarget;[^}]*?name = "?([^";]+)"?;[^}]*?productType = "com\.apple\.product-type\.application";/g
9469
+ )) {
9470
+ applicationTargetNames.add(match[1]);
9471
+ }
9472
+ }
9473
+ let targetName = null;
9474
+ if (iosTarget) {
9475
+ if (applicationTargetNames.has(iosTarget)) {
9476
+ targetName = iosTarget;
9477
+ } else {
9478
+ return null;
9479
+ }
9480
+ } else if (applicationTargetNames.size === 1) {
9481
+ targetName = [...applicationTargetNames][0];
9482
+ } else if (applicationTargetNames.size > 1) {
9483
+ const appDelegatePattern = /(?:^|\/)ios\/([^/]+)\/AppDelegate\.(?:swift|mm|m)$/;
9484
+ const delegateTargets = Object.keys(files).filter((path17) => !path17.includes("/Pods/")).map((path17) => path17.match(appDelegatePattern)?.[1]).filter(
9485
+ (name2) => typeof name2 === "string" && applicationTargetNames.has(name2)
9486
+ );
9487
+ if (delegateTargets.length === 1) {
9488
+ targetName = delegateTargets[0];
9489
+ } else {
9490
+ return null;
9491
+ }
9492
+ } else {
9493
+ return null;
9494
+ }
9495
+ const selectedTarget = targets.find((t) => t.name === targetName);
9496
+ const settings = {
9497
+ TARGET_NAME: targetName,
9498
+ PRODUCT_NAME: targetName
9499
+ };
9500
+ for (const obj of Object.values(objects)) {
9501
+ if (isRecord2(obj) && obj.isa === "PBXProject" && typeof obj.buildConfigurationList === "string") {
9502
+ const listObj = objects[obj.buildConfigurationList];
9503
+ if (isRecord2(listObj) && Array.isArray(listObj.buildConfigurations)) {
9504
+ for (const configId of listObj.buildConfigurations) {
9505
+ if (typeof configId === "string") {
9506
+ const configObj = objects[configId];
9507
+ if (isRecord2(configObj) && configObj.name === "Release" && isRecord2(configObj.buildSettings)) {
9508
+ for (const [k, v] of Object.entries(configObj.buildSettings)) {
9509
+ if (typeof v === "string") settings[k] = v;
9510
+ }
9511
+ }
9512
+ }
9513
+ }
9514
+ }
9515
+ }
9516
+ }
9517
+ if (selectedTarget?.buildConfigurationList) {
9518
+ const listObj = objects[selectedTarget.buildConfigurationList];
9519
+ if (isRecord2(listObj) && Array.isArray(listObj.buildConfigurations)) {
9520
+ for (const configId of listObj.buildConfigurations) {
9521
+ if (typeof configId === "string") {
9522
+ const configObj = objects[configId];
9523
+ if (isRecord2(configObj) && configObj.name === "Release" && isRecord2(configObj.buildSettings)) {
9524
+ for (const [k, v] of Object.entries(configObj.buildSettings)) {
9525
+ if (typeof v === "string") settings[k] = v;
9526
+ }
9527
+ }
9528
+ }
9529
+ }
9530
+ }
9531
+ } else {
9532
+ const legacy = appTargetReleaseSettings(
9533
+ pbxproj,
9534
+ targetName,
9535
+ `${targetName}/Info.plist`
9536
+ );
9537
+ if (legacy) Object.assign(settings, legacy);
9538
+ }
9539
+ let plist3;
9540
+ const infoPlistPath = settings.INFOPLIST_FILE;
9541
+ if (infoPlistPath) {
9542
+ const normalized = infoPlistPath.replace(/^"|"$/g, "");
9543
+ plist3 = files[`ios/${normalized}`] ?? files[normalized] ?? Object.entries(files).find(([k]) => k.endsWith(`/${normalized}`))?.[1];
9544
+ }
9545
+ if (!plist3) {
9546
+ plist3 = files[`ios/${targetName}/Info.plist`] ?? files[`${targetName}/Info.plist`] ?? Object.entries(files).find(([k]) => k.endsWith(`/${targetName}/Info.plist`))?.[1];
9547
+ }
9140
9548
  if (!plist3) return null;
9141
- const settings = appTargetReleaseSettings(
9142
- pbxproj,
9143
- targetName,
9144
- `${targetName}/Info.plist`
9145
- );
9146
- if (!settings) return null;
9147
9549
  const bundleIdentifier = identityFieldFrom(
9148
9550
  settings,
9149
9551
  plistString(plist3, "CFBundleIdentifier"),
@@ -9170,6 +9572,12 @@ function nativeAppIdentityFromIos(files, parseInfoPlist) {
9170
9572
  const applicationName = identityFieldFrom(settings, plistString(plist3, "CFBundleDisplayName"), void 0) ?? bundleName;
9171
9573
  const dictionary = parseInfoPlist(plist3);
9172
9574
  if (!isRecord2(dictionary)) throw new Error("native app Info.plist is not a dictionary");
9575
+ const declaredDisplayName = dictionary.CFBundleDisplayName;
9576
+ const applicationDisplayName = typeof declaredDisplayName === "string" ? resolveBuildSetting(declaredDisplayName, settings) : void 0;
9577
+ if (applicationDisplayName === null)
9578
+ throw new Error("native app Info.plist CFBundleDisplayName is unresolved");
9579
+ const declaredBackgroundColor = dictionary.RCTRootViewBackgroundColor;
9580
+ const rootViewBackgroundColor = typeof declaredBackgroundColor === "number" && Number.isInteger(declaredBackgroundColor) ? declaredBackgroundColor : void 0;
9173
9581
  const icons = dictionary.CFBundleIcons;
9174
9582
  const alternates = isRecord2(icons) ? icons.CFBundleAlternateIcons : void 0;
9175
9583
  const alternateIconNames = /* @__PURE__ */ new Set();
@@ -9189,6 +9597,32 @@ function nativeAppIdentityFromIos(files, parseInfoPlist) {
9189
9597
  }
9190
9598
  const intentIds = dictionary.OneAppIntentIdentifiers;
9191
9599
  const appIntentIdentifiers = Array.isArray(intentIds) && intentIds.every((value) => typeof value === "string") ? intentIds.map((value) => resolveBuildSetting(value, settings)) : [];
9600
+ const backgroundIds = dictionary.BGTaskSchedulerPermittedIdentifiers;
9601
+ const backgroundTaskIdentifiers = Array.isArray(backgroundIds) && backgroundIds.every((value) => typeof value === "string") ? backgroundIds.map((value) => resolveBuildSetting(value, settings)) : [];
9602
+ const declaredModes = dictionary.UIBackgroundModes;
9603
+ const backgroundModes = Array.isArray(declaredModes) && declaredModes.every((value) => typeof value === "string") ? declaredModes.map((value) => resolveBuildSetting(value, settings)) : [];
9604
+ const screenOrientationLists = [
9605
+ "UISupportedInterfaceOrientations",
9606
+ "UISupportedInterfaceOrientations~ipad"
9607
+ ].map((key) => {
9608
+ const list2 = dictionary[key];
9609
+ if (!Array.isArray(list2) || !list2.every((value) => typeof value === "string"))
9610
+ return [];
9611
+ return list2.map((value) => {
9612
+ const resolved = resolveBuildSetting(value, settings);
9613
+ if (resolved === null) throw new Error(`native app Info.plist ${key} is unresolved`);
9614
+ return resolved;
9615
+ });
9616
+ });
9617
+ const [supportedInterfaceOrientations, ipadSupportedInterfaceOrientations] = screenOrientationLists;
9618
+ const declaredDefaultOrientationMask = dictionary.EXDefaultScreenOrientationMask;
9619
+ const defaultScreenOrientationMask = typeof declaredDefaultOrientationMask === "string" ? resolveBuildSetting(declaredDefaultOrientationMask, settings) : void 0;
9620
+ if (defaultScreenOrientationMask === null)
9621
+ throw new Error("native app Info.plist EXDefaultScreenOrientationMask is unresolved");
9622
+ const declaredShareGroup = dictionary.ExpoShareIntoAppGroupId;
9623
+ const shareIntoAppGroupId = typeof declaredShareGroup === "string" ? resolveBuildSetting(declaredShareGroup, settings) : void 0;
9624
+ if (shareIntoAppGroupId === null)
9625
+ throw new Error("native app Info.plist ExpoShareIntoAppGroupId is unresolved");
9192
9626
  const querySchemes = dictionary.LSApplicationQueriesSchemes;
9193
9627
  if (querySchemes !== void 0 && !Array.isArray(querySchemes)) {
9194
9628
  throw new Error("native app Info.plist LSApplicationQueriesSchemes is not an array");
@@ -9202,7 +9636,8 @@ function nativeAppIdentityFromIos(files, parseInfoPlist) {
9202
9636
  });
9203
9637
  const permissionUsageDescriptions = {};
9204
9638
  for (const [key, value] of Object.entries(dictionary)) {
9205
- if (!/^NS.*UsageDescription$/.test(key)) continue;
9639
+ if (!/^NS.*UsageDescription$/.test(key) && key !== "NSLocationTemporaryUsageDescriptionDictionary")
9640
+ continue;
9206
9641
  if (typeof value !== "string") {
9207
9642
  permissionUsageDescriptions[key] = value;
9208
9643
  continue;
@@ -9223,29 +9658,35 @@ function nativeAppIdentityFromIos(files, parseInfoPlist) {
9223
9658
  }
9224
9659
  return {
9225
9660
  applicationName,
9661
+ ...applicationDisplayName === void 0 ? {} : { applicationDisplayName },
9662
+ ...rootViewBackgroundColor === void 0 ? {} : { rootViewBackgroundColor },
9226
9663
  bundleName,
9227
9664
  appVersion,
9228
9665
  buildVersion,
9229
9666
  bundleIdentifier,
9230
9667
  platform: "ios",
9668
+ supportedInterfaceOrientations,
9669
+ ipadSupportedInterfaceOrientations,
9670
+ ...defaultScreenOrientationMask === void 0 ? {} : { defaultScreenOrientationMask },
9231
9671
  alternateIconNames: [...alternateIconNames],
9232
9672
  permissionUsageDescriptions,
9233
9673
  urlQuerySchemes,
9674
+ ...shareIntoAppGroupId === void 0 ? {} : { shareIntoAppGroupId },
9675
+ backgroundTaskIdentifiers: backgroundTaskIdentifiers.every((value) => value !== null) ? backgroundTaskIdentifiers : [],
9676
+ backgroundModes: backgroundModes.every((value) => value !== null) ? backgroundModes : [],
9234
9677
  appIntentIdentifiers: appIntentIdentifiers.every((value) => value !== null) ? appIntentIdentifiers : []
9235
9678
  };
9236
9679
  }
9237
9680
  function canExtractNativeAppIdentity(platform) {
9238
9681
  return platform === "ios";
9239
9682
  }
9240
- function extractNativeAppIdentityFromFiles(files, platform, parseInfoPlist) {
9241
- return canExtractNativeAppIdentity(platform) ? nativeAppIdentityFromIos(files, parseInfoPlist) : null;
9683
+ function extractNativeAppIdentityFromFiles(files, platform, parseInfoPlist, iosTarget) {
9684
+ return canExtractNativeAppIdentity(platform) ? nativeAppIdentityFromIos(files, parseInfoPlist, iosTarget) : null;
9242
9685
  }
9243
9686
 
9244
- // src/native-firebase-config.ts
9687
+ // src/native-app-identity-project.ts
9245
9688
  var import_node_fs10 = __toESM(require("node:fs"), 1);
9246
- var import_node_module3 = require("node:module");
9247
9689
  var import_node_path11 = __toESM(require("node:path"), 1);
9248
- init_is_record();
9249
9690
 
9250
9691
  // src/plist.ts
9251
9692
  var import_plist = __toESM(require_plist(), 1);
@@ -9592,98 +10033,6 @@ function isJsonObject(value) {
9592
10033
  }
9593
10034
 
9594
10035
  // src/xcode-project.ts
9595
- function parseOpenStepPlist(text2) {
9596
- let i = 0;
9597
- const fail = (message) => {
9598
- const line = text2.slice(0, i).split("\n").length;
9599
- throw new Error(`project.pbxproj line ${line}: ${message}`);
9600
- };
9601
- const skip = () => {
9602
- for (; ; ) {
9603
- const ch = text2[i];
9604
- if (ch === " " || ch === " " || ch === "\n" || ch === "\r") i++;
9605
- else if (ch === "/" && text2[i + 1] === "*") {
9606
- const end = text2.indexOf("*/", i + 2);
9607
- if (end < 0) fail("unterminated comment");
9608
- i = end + 2;
9609
- } else if (ch === "/" && text2[i + 1] === "/") {
9610
- const end = text2.indexOf("\n", i);
9611
- i = end < 0 ? text2.length : end + 1;
9612
- } else return;
9613
- }
9614
- };
9615
- const quoted = () => {
9616
- i++;
9617
- let out = "";
9618
- for (; ; ) {
9619
- const ch = text2[i++];
9620
- if (ch === void 0) fail("unterminated string");
9621
- if (ch === '"') return out;
9622
- if (ch !== "\\") {
9623
- out += ch;
9624
- continue;
9625
- }
9626
- const next = text2[i++];
9627
- if (next === "n") out += "\n";
9628
- else if (next === "t") out += " ";
9629
- else if (next === "r") out += "\r";
9630
- else if (next === "U") {
9631
- out += String.fromCharCode(parseInt(text2.slice(i, i + 4), 16));
9632
- i += 4;
9633
- } else out += next;
9634
- }
9635
- };
9636
- const value = () => {
9637
- skip();
9638
- const ch = text2[i];
9639
- if (ch === "{") {
9640
- i++;
9641
- const dict = {};
9642
- for (; ; ) {
9643
- skip();
9644
- if (text2[i] === "}") {
9645
- i++;
9646
- return dict;
9647
- }
9648
- const key = value();
9649
- if (typeof key !== "string") fail("dictionary key is not a string");
9650
- skip();
9651
- if (text2[i++] !== "=") fail("expected =");
9652
- dict[key] = value();
9653
- skip();
9654
- if (text2[i++] !== ";") fail("expected ;");
9655
- }
9656
- }
9657
- if (ch === "(") {
9658
- i++;
9659
- const list2 = [];
9660
- for (; ; ) {
9661
- skip();
9662
- if (text2[i] === ")") {
9663
- i++;
9664
- return list2;
9665
- }
9666
- list2.push(value());
9667
- skip();
9668
- if (text2[i] === ",") i++;
9669
- else if (text2[i] !== ")") fail("expected , or )");
9670
- }
9671
- }
9672
- if (ch === '"') return quoted();
9673
- const start = i;
9674
- while (i < text2.length && /[A-Za-z0-9_$+/:.\-<>]/.test(text2[i])) i++;
9675
- if (i === start) fail(`unexpected ${JSON.stringify(ch ?? "end of file")}`);
9676
- return text2.slice(start, i);
9677
- };
9678
- if (text2.startsWith("// !$*UTF8*$!")) i = text2.indexOf("\n") + 1;
9679
- const root = value();
9680
- skip();
9681
- if (i !== text2.length) fail("trailing content");
9682
- return root;
9683
- }
9684
- var isDict = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
9685
- var str = (value) => typeof value === "string" ? value : void 0;
9686
- var list = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
9687
10036
  var APPLICATION = "com.apple.product-type.application";
9688
10037
  var MODULE_PRODUCTS = /* @__PURE__ */ new Set([
9689
10038
  "com.apple.product-type.framework",
@@ -9710,9 +10059,9 @@ function walkFiles(dir) {
9710
10059
  return out;
9711
10060
  }
9712
10061
  var isDirectory = (dir) => import_node_fs9.default.existsSync(dir) && import_node_fs9.default.statSync(dir).isDirectory();
9713
- function readXcconfig(file, seen = /* @__PURE__ */ new Set()) {
9714
- if (seen.has(file) || !import_node_fs9.default.existsSync(file)) return {};
9715
- seen.add(file);
10062
+ function readXcconfig(file, read) {
10063
+ if (read.includes(file) || !import_node_fs9.default.existsSync(file)) return {};
10064
+ read.push(file);
9716
10065
  const settings = {};
9717
10066
  for (const raw of import_node_fs9.default.readFileSync(file, "utf8").split("\n")) {
9718
10067
  const line = raw.replace(/\/\/.*$/, "").trim();
@@ -9720,7 +10069,7 @@ function readXcconfig(file, seen = /* @__PURE__ */ new Set()) {
9720
10069
  if (include) {
9721
10070
  Object.assign(
9722
10071
  settings,
9723
- readXcconfig(import_node_path10.default.resolve(import_node_path10.default.dirname(file), include[1]), seen)
10072
+ readXcconfig(import_node_path10.default.resolve(import_node_path10.default.dirname(file), include[1]), read)
9724
10073
  );
9725
10074
  continue;
9726
10075
  }
@@ -9868,17 +10217,30 @@ function loadProject(xcodeproj) {
9868
10217
  loaded.set(projectFile, { mtimeMs, project: result });
9869
10218
  return result;
9870
10219
  }
9871
- function targetSettings(ref, builtins) {
10220
+ function defaultConfiguration(project) {
10221
+ const configList = project.object(str(project.project.buildConfigurationList));
10222
+ const names = list(configList?.buildConfigurations).flatMap(
10223
+ (id) => str(project.object(id)?.name) ?? []
10224
+ );
10225
+ return names.includes("Debug") ? "Debug" : str(configList?.defaultConfigurationName) ?? names[0] ?? "Debug";
10226
+ }
10227
+ function targetSettings(ref, configuration, builtins) {
9872
10228
  const { project, target } = ref;
10229
+ const xcconfigs = [];
9873
10230
  const level = (listId) => {
9874
- const configs2 = list(project.object(listId)?.buildConfigurations).map(project.object);
9875
- const config = configs2.find((entry) => entry?.name === "Debug") ?? configs2.find(Boolean);
10231
+ const configList = project.object(listId);
10232
+ const configs2 = list(configList?.buildConfigurations).map(project.object);
10233
+ const config = configs2.find((entry) => entry?.name === configuration) ?? configs2.find((entry) => entry?.name === str(configList?.defaultConfigurationName));
9876
10234
  if (!config) return [];
9877
- const name2 = str(config.name) ?? "Debug";
10235
+ const name2 = str(config.name) ?? configuration;
9878
10236
  const base = str(config.baseConfigurationReference);
9879
10237
  const own = isDict(config.buildSettings) ? config.buildSettings : {};
10238
+ const baseFile = base ? project.resolvePath(base) : null;
10239
+ const read = [];
10240
+ const fromFile = baseFile ? readXcconfig(baseFile, read) : {};
10241
+ xcconfigs.push(...read);
9880
10242
  return [
9881
- applyConditions(base ? readXcconfig(project.resolvePath(base) ?? "") : {}, name2),
10243
+ applyConditions(fromFile, name2),
9882
10244
  applyConditions(
9883
10245
  Object.fromEntries(
9884
10246
  Object.entries(own).flatMap(
@@ -9890,7 +10252,7 @@ function targetSettings(ref, builtins) {
9890
10252
  ];
9891
10253
  };
9892
10254
  const levels = [
9893
- builtins,
10255
+ { ...builtins, CONFIGURATION: configuration },
9894
10256
  ...level(str(project.project.buildConfigurationList)),
9895
10257
  ...level(str(target.buildConfigurationList))
9896
10258
  ];
@@ -9929,9 +10291,30 @@ function targetSettings(ref, builtins) {
9929
10291
  };
9930
10292
  return {
9931
10293
  get: (key) => valueAt(key, levels.length - 1),
9932
- keys: new Set(levels.flatMap((values) => Object.keys(values)))
10294
+ keys: new Set(levels.flatMap((values) => Object.keys(values))),
10295
+ xcconfigs
9933
10296
  };
9934
10297
  }
10298
+ function settingList(value) {
10299
+ const items2 = [];
10300
+ for (const [, quoted, plain] of value.matchAll(
10301
+ /"((?:\\.|[^"\\])*)"|((?:\\.|[^\s"])+)/g
10302
+ ))
10303
+ items2.push((quoted ?? plain).replace(/\\(.)/g, "$1"));
10304
+ return items2;
10305
+ }
10306
+ function compilationConditions(settings) {
10307
+ const flags = settingList(settings("OTHER_SWIFT_FLAGS"));
10308
+ const defined = flags.flatMap(
10309
+ (flag, index) => flag === "-D" ? flags[index + 1] ?? [] : flag.startsWith("-D") ? flag.slice(2) : []
10310
+ );
10311
+ return [
10312
+ .../* @__PURE__ */ new Set([
10313
+ ...settingList(settings("SWIFT_ACTIVE_COMPILATION_CONDITIONS")),
10314
+ ...defined
10315
+ ])
10316
+ ];
10317
+ }
9935
10318
  function expand(value, lookup) {
9936
10319
  return value.replace(
9937
10320
  /\$(?:\(([A-Za-z_][A-Za-z0-9_]*)((?::[^)]*)?)\)|\{([A-Za-z_][A-Za-z0-9_]*)((?::[^}]*)?)\}|([A-Za-z_][A-Za-z0-9_]*))/g,
@@ -9942,8 +10325,9 @@ function expand(value, lookup) {
9942
10325
  }
9943
10326
  );
9944
10327
  }
9945
- function targetMembers(ref) {
10328
+ function targetMembers(ref, settings, options = {}) {
9946
10329
  const { project, target, id: targetId } = ref;
10330
+ const targetName = str(target.name) ?? targetId;
9947
10331
  const sources = /* @__PURE__ */ new Set();
9948
10332
  const allSources = /* @__PURE__ */ new Set();
9949
10333
  const resources = /* @__PURE__ */ new Set();
@@ -9964,6 +10348,29 @@ function targetMembers(ref) {
9964
10348
  const resolved = project.resolvePath(refId);
9965
10349
  return resolved ? [resolved] : [];
9966
10350
  };
10351
+ const scriptForOutput = /* @__PURE__ */ new Map();
10352
+ const noteScriptOutput = (raw, script) => {
10353
+ const expanded = expand(raw, settings);
10354
+ if (!expanded.endsWith(".swift")) return;
10355
+ const absolute = import_node_path10.default.isAbsolute(expanded) ? import_node_path10.default.normalize(expanded) : import_node_path10.default.resolve(project.projectDir, expanded);
10356
+ if (!scriptForOutput.has(absolute)) scriptForOutput.set(absolute, script);
10357
+ };
10358
+ for (const phaseId of list(target.buildPhases)) {
10359
+ const phase = project.object(phaseId);
10360
+ if (phase?.isa !== "PBXShellScriptBuildPhase") continue;
10361
+ const script = str(phase.name) ?? phaseId;
10362
+ for (const raw of list(phase.outputPaths)) noteScriptOutput(raw, script);
10363
+ for (const listPath of list(phase.outputFileListPaths)) {
10364
+ const expandedList = expand(listPath, settings);
10365
+ const absoluteList = import_node_path10.default.isAbsolute(expandedList) ? expandedList : import_node_path10.default.resolve(project.projectDir, expandedList);
10366
+ if (!import_node_fs9.default.existsSync(absoluteList)) continue;
10367
+ for (const line of import_node_fs9.default.readFileSync(absoluteList, "utf8").split("\n")) {
10368
+ const trimmed = line.trim();
10369
+ if (trimmed === "" || trimmed.startsWith("#")) continue;
10370
+ noteScriptOutput(trimmed, script);
10371
+ }
10372
+ }
10373
+ }
9967
10374
  for (const phaseId of list(target.buildPhases)) {
9968
10375
  const phase = project.object(phaseId);
9969
10376
  if (phase?.isa !== "PBXSourcesBuildPhase" && phase?.isa !== "PBXResourcesBuildPhase")
@@ -9971,13 +10378,30 @@ function targetMembers(ref) {
9971
10378
  for (const buildFileId of list(phase.files)) {
9972
10379
  for (const file of fileRefPaths(str(project.object(buildFileId)?.fileRef) ?? "")) {
9973
10380
  if (phase.isa === "PBXSourcesBuildPhase") {
9974
- if (!import_node_fs9.default.existsSync(file)) continue;
10381
+ if (!import_node_fs9.default.existsSync(file)) {
10382
+ if (options.requireSources === false) continue;
10383
+ const script = scriptForOutput.get(import_node_path10.default.normalize(file));
10384
+ throw new Error(
10385
+ script ? `${targetName}: missing generated source ${file} (Run Script "${script}" declares it in outputPaths; run the script or check in its output)` : `${targetName}: missing source ${file}`
10386
+ );
10387
+ }
9975
10388
  allSources.add(file);
9976
10389
  if (file.endsWith(".swift")) sources.add(file);
9977
10390
  } else if (phase.isa === "PBXResourcesBuildPhase") addResource(file);
9978
10391
  }
9979
10392
  }
9980
10393
  }
10394
+ for (const [file, script] of scriptForOutput) {
10395
+ if (sources.has(file) || allSources.has(file)) continue;
10396
+ if (!import_node_fs9.default.existsSync(file)) {
10397
+ if (options.requireSources === false) continue;
10398
+ throw new Error(
10399
+ `${targetName}: missing generated source ${file} (Run Script "${script}" declares it in outputPaths; run the script or check in its output)`
10400
+ );
10401
+ }
10402
+ allSources.add(file);
10403
+ sources.add(file);
10404
+ }
9981
10405
  const addSynchronized = (folder, relative2) => {
9982
10406
  const file = import_node_path10.default.join(folder, relative2);
9983
10407
  if (NEVER_MEMBER.test(relative2)) return;
@@ -10080,7 +10504,7 @@ function nativeTargets(project) {
10080
10504
  function listXcodeAppTargets(xcodeprojOrWorkspace) {
10081
10505
  return workspaceProjects(xcodeprojOrWorkspace).projects.flatMap(nativeTargets).filter((ref) => ref.target.productType === APPLICATION).map((ref) => str(ref.target.name) ?? ref.id);
10082
10506
  }
10083
- function readXcodeAppTarget(input, targetName) {
10507
+ function readXcodeAppTarget(input, targetName, configurationName, options = {}) {
10084
10508
  const xcodeprojOrWorkspace = import_node_fs9.default.realpathSync(input);
10085
10509
  const workspace = xcodeprojOrWorkspace.endsWith(".xcworkspace") ? xcodeprojOrWorkspace : null;
10086
10510
  const { listed, projects, projectAt } = workspaceProjects(xcodeprojOrWorkspace);
@@ -10095,6 +10519,7 @@ function readXcodeAppTarget(input, targetName) {
10095
10519
  );
10096
10520
  }
10097
10521
  const app = named[0];
10522
+ const configuration = configurationName ?? defaultConfiguration(app.project);
10098
10523
  const byProduct = /* @__PURE__ */ new Map();
10099
10524
  for (const ref of allTargets) {
10100
10525
  const product = ref.project.object(str(ref.target.productReference));
@@ -10145,9 +10570,14 @@ function readXcodeAppTarget(input, targetName) {
10145
10570
  order.push(ref);
10146
10571
  };
10147
10572
  visit3(app);
10573
+ const xcconfigs = /* @__PURE__ */ new Set();
10148
10574
  const moduleTarget = (ref) => {
10149
10575
  const name2 = str(ref.target.name) ?? ref.id;
10150
- const { get: settings2, keys } = targetSettings(ref, {
10576
+ const {
10577
+ get: settings2,
10578
+ keys,
10579
+ xcconfigs: read
10580
+ } = targetSettings(ref, configuration, {
10151
10581
  TARGET_NAME: name2,
10152
10582
  PROJECT_NAME: import_node_path10.default.basename(ref.project.xcodeproj, ".xcodeproj"),
10153
10583
  SRCROOT: ref.project.projectDir,
@@ -10155,6 +10585,7 @@ function readXcodeAppTarget(input, targetName) {
10155
10585
  PROJECT_DIR: ref.project.projectDir,
10156
10586
  DEVELOPMENT_LANGUAGE: str(ref.project.project.developmentRegion) ?? "en"
10157
10587
  });
10588
+ for (const file of read) xcconfigs.add(file);
10158
10589
  const swiftVersion = Number.parseFloat(settings2("SWIFT_VERSION") || "5");
10159
10590
  return {
10160
10591
  settings: settings2,
@@ -10162,9 +10593,10 @@ function readXcodeAppTarget(input, targetName) {
10162
10593
  module: {
10163
10594
  name: name2,
10164
10595
  moduleName: applyOperator(settings2("PRODUCT_MODULE_NAME"), "c99extidentifier"),
10165
- ...targetMembers(ref),
10596
+ ...targetMembers(ref, settings2, options),
10166
10597
  languageMode: swiftVersion >= 6 ? 6 : 5,
10167
- mainActorIsolation: settings2("SWIFT_DEFAULT_ACTOR_ISOLATION") === "MainActor"
10598
+ mainActorIsolation: settings2("SWIFT_DEFAULT_ACTOR_ISOLATION") === "MainActor",
10599
+ defines: compilationConditions(settings2)
10168
10600
  }
10169
10601
  };
10170
10602
  };
@@ -10270,7 +10702,9 @@ function readXcodeAppTarget(input, targetName) {
10270
10702
  )
10271
10703
  ].map((dir) => import_node_fs9.default.realpathSync(dir))
10272
10704
  ),
10273
- projectFiles: [...new Set(used.map((project) => project.projectFile))].sort(),
10705
+ projectFiles: [
10706
+ .../* @__PURE__ */ new Set([...used.map((project) => project.projectFile), ...xcconfigs])
10707
+ ].sort(),
10274
10708
  appIconName: settings("ASSETCATALOG_COMPILER_APPICON_NAME"),
10275
10709
  infoPlist: import_plist2.default.build(info),
10276
10710
  infoPlistFile,
@@ -10281,16 +10715,138 @@ function readXcodeAppTarget(input, targetName) {
10281
10715
  ].sort(),
10282
10716
  binaryFrameworks: [...binaryFrameworks].map(([name2, file]) => ({ name: name2, path: file })).sort((left, right) => left.name.localeCompare(right.name)),
10283
10717
  packageResolved: import_node_fs9.default.existsSync(resolvedFile) ? resolvedFile : null,
10284
- appTargets: appTargetNames
10718
+ appTargets: appTargetNames,
10719
+ configuration,
10720
+ settings
10285
10721
  };
10286
10722
  }
10287
10723
 
10724
+ // src/native-app-identity-project.ts
10725
+ function isRecord3(value) {
10726
+ return typeof value === "object" && value !== null && !Array.isArray(value);
10727
+ }
10728
+ function nonEmptyString2(value) {
10729
+ return typeof value === "string" && value.length > 0 ? value : void 0;
10730
+ }
10731
+ function readNativeAppIdentityFromXcodeTarget(app, parseInfoPlist = parsePlistSource) {
10732
+ const dictionary = parseInfoPlist(app.infoPlist);
10733
+ if (!isRecord3(dictionary)) throw new Error("native app Info.plist is not a dictionary");
10734
+ const settings = app.settings;
10735
+ const bundleIdentifier = nonEmptyString2(dictionary.CFBundleIdentifier) ?? nonEmptyString2(settings?.("PRODUCT_BUNDLE_IDENTIFIER"));
10736
+ if (!bundleIdentifier) throw new Error("native app has no bundle identifier");
10737
+ const appVersion = nonEmptyString2(dictionary.CFBundleShortVersionString) ?? nonEmptyString2(settings?.("MARKETING_VERSION"));
10738
+ const buildVersion = nonEmptyString2(dictionary.CFBundleVersion) ?? nonEmptyString2(settings?.("CURRENT_PROJECT_VERSION"));
10739
+ if (!appVersion || !buildVersion) {
10740
+ throw new Error("native app has no version or build version");
10741
+ }
10742
+ const bundleName = nonEmptyString2(dictionary.CFBundleName) ?? nonEmptyString2(settings?.("PRODUCT_NAME")) ?? app.name;
10743
+ const applicationDisplayName = nonEmptyString2(dictionary.CFBundleDisplayName);
10744
+ const applicationName = applicationDisplayName ?? bundleName;
10745
+ const declaredBackgroundColor = dictionary.RCTRootViewBackgroundColor;
10746
+ const rootViewBackgroundColor = typeof declaredBackgroundColor === "number" && Number.isInteger(declaredBackgroundColor) ? declaredBackgroundColor : void 0;
10747
+ const alternateIconNames = /* @__PURE__ */ new Set();
10748
+ const icons = dictionary.CFBundleIcons;
10749
+ const alternates = isRecord3(icons) ? icons.CFBundleAlternateIcons : void 0;
10750
+ if (isRecord3(alternates)) {
10751
+ for (const name2 of Object.keys(alternates)) {
10752
+ if (name2) alternateIconNames.add(name2);
10753
+ }
10754
+ }
10755
+ const alternateSetting = settings?.("ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES") ?? "";
10756
+ for (const match of alternateSetting.replace(/\\"/g, '"').matchAll(/"([^"]*)"|([^\s(),]+)/g)) {
10757
+ const val = match[1] ?? match[2];
10758
+ if (val) alternateIconNames.add(val);
10759
+ }
10760
+ const permissionUsageDescriptions = {};
10761
+ for (const [key, value] of Object.entries(dictionary)) {
10762
+ if (!/^NS.*UsageDescription$/.test(key) && key !== "NSLocationTemporaryUsageDescriptionDictionary") {
10763
+ continue;
10764
+ }
10765
+ permissionUsageDescriptions[key] = value;
10766
+ }
10767
+ const querySchemes = dictionary.LSApplicationQueriesSchemes;
10768
+ const urlQuerySchemes = Array.isArray(querySchemes) ? querySchemes : [];
10769
+ const intentIds = dictionary.OneAppIntentIdentifiers;
10770
+ const appIntentIdentifiers = Array.isArray(intentIds) && intentIds.every((v) => typeof v === "string") ? intentIds : [];
10771
+ const backgroundIds = dictionary.BGTaskSchedulerPermittedIdentifiers;
10772
+ const backgroundTaskIdentifiers = Array.isArray(backgroundIds) && backgroundIds.every((v) => typeof v === "string") ? backgroundIds : [];
10773
+ const declaredModes = dictionary.UIBackgroundModes;
10774
+ const backgroundModes = Array.isArray(declaredModes) && declaredModes.every((v) => typeof v === "string") ? declaredModes : [];
10775
+ const supportedInterfaceOrientations = Array.isArray(dictionary.UISupportedInterfaceOrientations) && dictionary.UISupportedInterfaceOrientations.every((v) => typeof v === "string") ? dictionary.UISupportedInterfaceOrientations : [];
10776
+ const ipadSupportedInterfaceOrientations = Array.isArray(dictionary["UISupportedInterfaceOrientations~ipad"]) && dictionary["UISupportedInterfaceOrientations~ipad"].every(
10777
+ (v) => typeof v === "string"
10778
+ ) ? dictionary["UISupportedInterfaceOrientations~ipad"] : [];
10779
+ const defaultScreenOrientationMask = nonEmptyString2(
10780
+ dictionary.EXDefaultScreenOrientationMask
10781
+ );
10782
+ const shareIntoAppGroupId = nonEmptyString2(dictionary.ExpoShareIntoAppGroupId);
10783
+ return {
10784
+ applicationName,
10785
+ ...applicationDisplayName ? { applicationDisplayName } : {},
10786
+ ...rootViewBackgroundColor !== void 0 ? { rootViewBackgroundColor } : {},
10787
+ bundleName,
10788
+ appVersion,
10789
+ buildVersion,
10790
+ bundleIdentifier,
10791
+ platform: "ios",
10792
+ supportedInterfaceOrientations,
10793
+ ipadSupportedInterfaceOrientations,
10794
+ ...defaultScreenOrientationMask ? { defaultScreenOrientationMask } : {},
10795
+ alternateIconNames: [...alternateIconNames],
10796
+ permissionUsageDescriptions,
10797
+ urlQuerySchemes,
10798
+ ...shareIntoAppGroupId ? { shareIntoAppGroupId } : {},
10799
+ backgroundTaskIdentifiers,
10800
+ backgroundModes,
10801
+ appIntentIdentifiers
10802
+ };
10803
+ }
10804
+ function readNativeAppIdentityFromProject(projectRoot, platform, parseInfoPlist = parsePlistSource, iosTarget) {
10805
+ if (!canExtractNativeAppIdentity(platform)) return null;
10806
+ const iosRoot = import_node_path11.default.join(projectRoot, "ios");
10807
+ if (!import_node_fs10.default.existsSync(iosRoot)) return null;
10808
+ const projects = import_node_fs10.default.readdirSync(iosRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.endsWith(".xcodeproj"));
10809
+ if (projects.length === 0) return null;
10810
+ if (projects.length > 1 && !iosTarget) {
10811
+ throw new Error("native app identity requires a selected Xcode project");
10812
+ }
10813
+ let project = projects[0];
10814
+ if (iosTarget && projects.length > 1) {
10815
+ const matches = projects.filter(
10816
+ (entry) => listXcodeAppTargets(import_node_path11.default.join(iosRoot, entry.name)).includes(iosTarget)
10817
+ );
10818
+ if (matches.length === 0) {
10819
+ throw new Error(`native app identity has no application target ${iosTarget}`);
10820
+ }
10821
+ if (matches.length > 1) {
10822
+ throw new Error(
10823
+ `native app identity target ${iosTarget} is ambiguous across ${matches.map((entry) => entry.name).join(", ")}`
10824
+ );
10825
+ }
10826
+ project = matches[0];
10827
+ }
10828
+ const xcodeproj = import_node_path11.default.join(iosRoot, project.name);
10829
+ const appTargets = listXcodeAppTargets(xcodeproj);
10830
+ if (!iosTarget && appTargets.length > 1) {
10831
+ throw new Error("native app identity requires a selected app target");
10832
+ }
10833
+ const app = readXcodeAppTarget(xcodeproj, iosTarget ?? appTargets[0], "Release", {
10834
+ requireSources: false
10835
+ });
10836
+ return readNativeAppIdentityFromXcodeTarget(app, parseInfoPlist);
10837
+ }
10838
+
10288
10839
  // src/native-firebase-config.ts
10289
- function readNativeFirebaseConfig(projectRoot, platforms = ["ios", "android"]) {
10840
+ var import_node_child_process3 = require("node:child_process");
10841
+ var import_node_fs11 = __toESM(require("node:fs"), 1);
10842
+ var import_node_os2 = __toESM(require("node:os"), 1);
10843
+ var import_node_path12 = __toESM(require("node:path"), 1);
10844
+ init_is_record();
10845
+ function readNativeFirebaseConfig(projectRoot, platforms = ["ios", "android"], iosTarget) {
10290
10846
  const result = {};
10291
10847
  let config = {};
10292
- const appJsonPath = import_node_path11.default.join(projectRoot, "app.json");
10293
- const appJson = import_node_fs10.default.existsSync(appJsonPath) ? JSON.parse(import_node_fs10.default.readFileSync(appJsonPath, "utf8")) : null;
10848
+ const appJsonPath = import_node_path12.default.join(projectRoot, "app.json");
10849
+ const appJson = import_node_fs11.default.existsSync(appJsonPath) ? JSON.parse(import_node_fs11.default.readFileSync(appJsonPath, "utf8")) : null;
10294
10850
  const staticExpo = isRecord(appJson) && (isRecord(appJson.expo) || [appJson.ios, appJson.android].some(
10295
10851
  (value) => isRecord(value) && typeof value.googleServicesFile === "string"
10296
10852
  ));
@@ -10299,41 +10855,76 @@ function readNativeFirebaseConfig(projectRoot, platforms = ["ios", "android"]) {
10299
10855
  "app.config.ts",
10300
10856
  "app.config.cjs",
10301
10857
  "app.config.mjs"
10302
- ].some((name2) => import_node_fs10.default.existsSync(import_node_path11.default.join(projectRoot, name2)));
10858
+ ].some((name2) => import_node_fs11.default.existsSync(import_node_path12.default.join(projectRoot, name2)));
10303
10859
  if (staticExpo || dynamicExpo) {
10304
- const require2 = (0, import_node_module3.createRequire)(import_node_path11.default.join(projectRoot, "package.json"));
10305
- const configModule = require2("@expo/config");
10306
- if (!isRecord(configModule) || typeof configModule.getConfig !== "function")
10307
- throw new Error("Expo native configuration is unavailable.");
10308
- const resolved = Reflect.apply(configModule.getConfig, configModule, [
10309
- projectRoot,
10310
- { skipSDKVersionRequirement: true }
10311
- ]);
10312
- config = isRecord(resolved) && isRecord(resolved.exp) ? resolved.exp : {};
10860
+ const directory = import_node_fs11.default.mkdtempSync(import_node_path12.default.join(import_node_os2.default.tmpdir(), "peach-expo-config-"));
10861
+ const resultPath = import_node_path12.default.join(directory, "config.json");
10862
+ try {
10863
+ const child = (0, import_node_child_process3.spawnSync)(
10864
+ "node",
10865
+ [
10866
+ "--input-type=commonjs",
10867
+ "-e",
10868
+ `const { createRequire } = require('node:module');
10869
+ const { writeFileSync } = require('node:fs');
10870
+ const { join } = require('node:path');
10871
+ const root = process.argv[1];
10872
+ const { getConfig } = createRequire(join(root, 'package.json'))('@expo/config');
10873
+ const result = JSON.stringify(getConfig(root, { skipSDKVersionRequirement: true }).exp);
10874
+ if (Buffer.byteLength(result) > 1024 * 1024) throw new Error('Expo native configuration exceeds 1 MiB.');
10875
+ writeFileSync(process.argv[2], result, { mode: 0o600 });`,
10876
+ import_node_path12.default.resolve(projectRoot),
10877
+ resultPath
10878
+ ],
10879
+ {
10880
+ cwd: projectRoot,
10881
+ encoding: "utf8",
10882
+ stdio: ["ignore", "ignore", "pipe"],
10883
+ timeout: 3e4,
10884
+ maxBuffer: 1024 * 1024
10885
+ }
10886
+ );
10887
+ if (child.error) throw child.error;
10888
+ if (child.status !== 0)
10889
+ throw new Error(child.stderr || "Expo native configuration evaluation failed.");
10890
+ const resolved = JSON.parse(import_node_fs11.default.readFileSync(resultPath, "utf8"));
10891
+ if (!isRecord(resolved))
10892
+ throw new Error("Expo native configuration is unavailable.");
10893
+ config = resolved;
10894
+ } finally {
10895
+ import_node_fs11.default.rmSync(directory, { recursive: true, force: true });
10896
+ }
10313
10897
  }
10314
10898
  const ios = config.ios;
10315
10899
  if (platforms.includes("ios") && (!isRecord(ios) || typeof ios.googleServicesFile !== "string")) {
10316
- const iosRoot = import_node_path11.default.join(projectRoot, "ios");
10317
- if (import_node_fs10.default.existsSync(iosRoot)) {
10318
- const projects = import_node_fs10.default.readdirSync(iosRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.endsWith(".xcodeproj"));
10900
+ const iosRoot = import_node_path12.default.join(projectRoot, "ios");
10901
+ if (import_node_fs11.default.existsSync(iosRoot)) {
10902
+ const projects = import_node_fs11.default.readdirSync(iosRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.endsWith(".xcodeproj"));
10319
10903
  if (projects.length > 1)
10320
10904
  throw new Error("native Firebase configuration requires a selected Xcode project");
10321
10905
  if (projects.length === 1) {
10322
- const xcodeproj = import_node_path11.default.join(iosRoot, projects[0].name);
10906
+ const xcodeproj = import_node_path12.default.join(iosRoot, projects[0].name);
10323
10907
  const appTargets = listXcodeAppTargets(xcodeproj);
10324
- if (appTargets.length > 1)
10908
+ if (!iosTarget && appTargets.length > 1)
10325
10909
  throw new Error("native Firebase configuration requires a selected app target");
10326
- if (appTargets.length === 1) {
10327
- const app = readXcodeAppTarget(xcodeproj, appTargets[0]);
10910
+ if (iosTarget || appTargets.length === 1) {
10911
+ const app = readXcodeAppTarget(
10912
+ xcodeproj,
10913
+ iosTarget ?? appTargets[0],
10914
+ void 0,
10915
+ {
10916
+ requireSources: false
10917
+ }
10918
+ );
10328
10919
  const delegates = app.allSources.filter(
10329
- (file) => /^AppDelegate\.(swift|mm|m)$/.test(import_node_path11.default.basename(file))
10920
+ (file) => /^AppDelegate\.(swift|mm|m)$/.test(import_node_path12.default.basename(file))
10330
10921
  );
10331
10922
  const defaultConfigured = delegates.some((file) => {
10332
- const source = import_node_fs10.default.readFileSync(file, "utf8").replace(
10923
+ const source = import_node_fs11.default.readFileSync(file, "utf8").replace(
10333
10924
  /\/\*[\s\S]*?\*\/|\/\/[^\n]*|"(?:\\.|[^"\\])*"/g,
10334
10925
  (token) => token.startsWith('"') ? '""' : token.replace(/[^\n]/g, " ")
10335
10926
  );
10336
- const launch = /(?:\bfunc\s+application\s*\([\s\S]*?didFinishLaunchingWithOptions[\s\S]*?\)\s*->\s*Bool|^-\s*\(BOOL\)\s*application\s*:[\s\S]*?didFinishLaunchingWithOptions[^\{]*)\s*\{/m.exec(
10927
+ const launch = /(?:\bfunc\s+application\s*\([\s\S]*?didFinishLaunchingWithOptions[\s\S]*?\)\s*->\s*Bool|^-\s*\(BOOL\)\s*application\s*:[\s\S]*?didFinishLaunchingWithOptions[^{]*)\s*\{/m.exec(
10337
10928
  source
10338
10929
  );
10339
10930
  if (!launch) return false;
@@ -10349,7 +10940,21 @@ function readNativeFirebaseConfig(projectRoot, platforms = ["ios", "android"]) {
10349
10940
  if (token === "}") depth -= 1;
10350
10941
  if (depth === 0) return false;
10351
10942
  }
10352
- if (depth !== 1 || /\b(?:return|throw)\b|^\s*#(?:if|elseif|else)/m.test(before))
10943
+ let conditionalDepth = 0;
10944
+ for (const directive of before.matchAll(
10945
+ /^\s*#\s*(if|ifdef|ifndef|elseif|elif|else|endif)\b/gm
10946
+ )) {
10947
+ const kind = directive[1];
10948
+ if (kind === "if" || kind === "ifdef" || kind === "ifndef") {
10949
+ conditionalDepth += 1;
10950
+ } else if (conditionalDepth === 0) {
10951
+ conditionalDepth = -1;
10952
+ break;
10953
+ } else if (kind === "endif") {
10954
+ conditionalDepth -= 1;
10955
+ }
10956
+ }
10957
+ if (depth !== 1 || conditionalDepth !== 0 || /\b(?:return|throw)\b/.test(before))
10353
10958
  throw new Error(
10354
10959
  "native Firebase initialization must be unconditional in the app launch method"
10355
10960
  );
@@ -10357,15 +10962,15 @@ function readNativeFirebaseConfig(projectRoot, platforms = ["ios", "android"]) {
10357
10962
  });
10358
10963
  if (defaultConfigured) {
10359
10964
  const resources = app.resources.filter(
10360
- (file) => /^GoogleService-Info\.plist$/.test(import_node_path11.default.basename(file))
10965
+ (file) => /^GoogleService-Info\.plist$/.test(import_node_path12.default.basename(file))
10361
10966
  );
10362
10967
  if (resources.length !== 1)
10363
10968
  throw new Error(
10364
10969
  "native Firebase default initialization requires one GoogleService-Info.plist build resource"
10365
10970
  );
10366
10971
  config.ios = {
10367
- googleServicesFile: import_node_path11.default.relative(
10368
- import_node_fs10.default.realpathSync(projectRoot),
10972
+ googleServicesFile: import_node_path12.default.relative(
10973
+ import_node_fs11.default.realpathSync(projectRoot),
10369
10974
  resources[0]
10370
10975
  )
10371
10976
  };
@@ -10378,8 +10983,8 @@ function readNativeFirebaseConfig(projectRoot, platforms = ["ios", "android"]) {
10378
10983
  const native = config[platform];
10379
10984
  if (!isRecord(native) || typeof native.googleServicesFile !== "string") continue;
10380
10985
  try {
10381
- const source = import_node_fs10.default.readFileSync(
10382
- import_node_path11.default.resolve(projectRoot, native.googleServicesFile),
10986
+ const source = import_node_fs11.default.readFileSync(
10987
+ import_node_path12.default.resolve(projectRoot, native.googleServicesFile),
10383
10988
  "utf8"
10384
10989
  );
10385
10990
  const parsed = platform === "ios" ? parsePlistSource(source) : JSON.parse(source);
@@ -10511,7 +11116,7 @@ ${MODULE_PREFIX}`);
10511
11116
  }
10512
11117
 
10513
11118
  // src/metro-plugin.ts
10514
- var prefix = "/__soot";
11119
+ var prefix = "/__peachsim";
10515
11120
  function readCallableMetroExport(moduleValue, label) {
10516
11121
  const callable = typeof moduleValue === "function" ? moduleValue : typeof moduleValue === "object" && moduleValue !== null ? Reflect.get(moduleValue, "default") : void 0;
10517
11122
  if (typeof callable !== "function") {
@@ -10519,8 +11124,8 @@ function readCallableMetroExport(moduleValue, label) {
10519
11124
  }
10520
11125
  return (...args) => Reflect.apply(callable, void 0, args);
10521
11126
  }
10522
- function createMetroDefaultSerializer(projectRoot) {
10523
- const projectRequire = (0, import_module2.createRequire)(import_path4.default.join(projectRoot, "package.json"));
11127
+ function createMetroDefaultSerializer(asyncRequireModulePath) {
11128
+ const projectRequire = (0, import_module2.createRequire)(asyncRequireModulePath);
10524
11129
  const metroRoot = import_path4.default.dirname(projectRequire.resolve("metro/package.json"));
10525
11130
  const baseJSBundle = readCallableMetroExport(
10526
11131
  projectRequire(import_path4.default.join(metroRoot, "src/DeltaBundler/Serializers/baseJSBundle.js")),
@@ -10579,7 +11184,7 @@ function appendRNXModulePaths(result, graph, options, projectRoot) {
10579
11184
  };
10580
11185
  return typeof result === "string" ? appendRNXMetroModuleIdentityFooter(result, identity) : { ...result, code: appendRNXMetroModuleIdentityFooter(result.code, identity) };
10581
11186
  }
10582
- function withRNX(config) {
11187
+ function withPeach(config, options = {}) {
10583
11188
  const cfgProjectRoot = config.projectRoot || process.cwd();
10584
11189
  const configuredBundleUrl = "/index.bundle?platform=ios&dev=true&hot=true&minify=false";
10585
11190
  const cfgServer = config.server;
@@ -10599,7 +11204,9 @@ function withRNX(config) {
10599
11204
  serializer: {
10600
11205
  ...cfgSerializer,
10601
11206
  customSerializer: async (entryPoint, preModules, graph, serializerOptions) => {
10602
- const serializer = existingSerializer || (defaultSerializer ||= createMetroDefaultSerializer(cfgProjectRoot));
11207
+ const serializer = existingSerializer || (defaultSerializer ||= createMetroDefaultSerializer(
11208
+ serializerOptions.asyncRequireModulePath
11209
+ ));
10603
11210
  const result = await serializer(entryPoint, preModules, graph, serializerOptions);
10604
11211
  let annotated = appendRNXModulePaths(
10605
11212
  result,
@@ -10610,21 +11217,36 @@ function withRNX(config) {
10610
11217
  const iosRoot = import_path4.default.join(cfgProjectRoot, "ios");
10611
11218
  const bundlePlatform = graph.transformOptions?.platform;
10612
11219
  if (canExtractNativeAppIdentity(bundlePlatform) && import_fs5.default.existsSync(iosRoot)) {
10613
- const files = {};
10614
- for (const entry of import_fs5.default.readdirSync(iosRoot, { withFileTypes: true })) {
10615
- if (!entry.isDirectory() || entry.name === "Pods") continue;
10616
- const names = entry.name.endsWith(".xcodeproj") ? ["project.pbxproj"] : ["Info.plist", "AppDelegate.swift", "AppDelegate.mm", "AppDelegate.m"];
10617
- for (const name2 of names) {
10618
- const relative2 = `ios/${entry.name}/${name2}`;
10619
- const file = import_path4.default.join(cfgProjectRoot, relative2);
10620
- if (import_fs5.default.existsSync(file)) files[relative2] = import_fs5.default.readFileSync(file, "utf8");
10621
- }
10622
- }
10623
- const identity = extractNativeAppIdentityFromFiles(
10624
- files,
11220
+ let identity = readNativeAppIdentityFromProject(
11221
+ cfgProjectRoot,
10625
11222
  bundlePlatform,
10626
- parsePlistSource
11223
+ parsePlistSource,
11224
+ options.iosTarget
10627
11225
  );
11226
+ if (!identity) {
11227
+ const files = {};
11228
+ for (const entry of import_fs5.default.readdirSync(iosRoot, { withFileTypes: true })) {
11229
+ if (entry.name === "Pods") continue;
11230
+ if (entry.isDirectory()) {
11231
+ const names = entry.name.endsWith(".xcodeproj") ? ["project.pbxproj"] : ["Info.plist", "AppDelegate.swift", "AppDelegate.mm", "AppDelegate.m"];
11232
+ for (const name2 of names) {
11233
+ const relative2 = `ios/${entry.name}/${name2}`;
11234
+ const file = import_path4.default.join(cfgProjectRoot, relative2);
11235
+ if (import_fs5.default.existsSync(file)) files[relative2] = import_fs5.default.readFileSync(file, "utf8");
11236
+ }
11237
+ } else if (/AppDelegate\.(?:swift|mm|m)$/.test(entry.name)) {
11238
+ const relative2 = `ios/${entry.name}`;
11239
+ const file = import_path4.default.join(cfgProjectRoot, relative2);
11240
+ if (import_fs5.default.existsSync(file)) files[relative2] = import_fs5.default.readFileSync(file, "utf8");
11241
+ }
11242
+ }
11243
+ identity = extractNativeAppIdentityFromFiles(
11244
+ files,
11245
+ bundlePlatform,
11246
+ parsePlistSource,
11247
+ options.iosTarget
11248
+ );
11249
+ }
10628
11250
  if (identity) {
10629
11251
  annotated = typeof annotated === "string" ? insertNativeAppIdentityFooter(annotated, identity) : {
10630
11252
  ...annotated,
@@ -10638,7 +11260,8 @@ function withRNX(config) {
10638
11260
  const firebase = readNativeFirebaseMetadata(
10639
11261
  readNativeFirebaseConfig(
10640
11262
  cfgProjectRoot,
10641
- typeof bundlePlatform === "string" ? [bundlePlatform] : void 0
11263
+ typeof bundlePlatform === "string" ? [bundlePlatform] : void 0,
11264
+ options.iosTarget
10642
11265
  )
10643
11266
  );
10644
11267
  if (firebase)
@@ -10703,7 +11326,11 @@ function withRNX(config) {
10703
11326
  res.setHeader("Content-Type", "application/json");
10704
11327
  res.setHeader("Cache-Control", "no-store");
10705
11328
  res.setHeader("Access-Control-Allow-Origin", "*");
10706
- res.end(JSON.stringify(readNativeFirebaseConfig(cfgProjectRoot)));
11329
+ res.end(
11330
+ JSON.stringify(
11331
+ readNativeFirebaseConfig(cfgProjectRoot, void 0, options.iosTarget)
11332
+ )
11333
+ );
10707
11334
  } catch (error) {
10708
11335
  res.statusCode = 400;
10709
11336
  res.end(
@@ -10779,16 +11406,16 @@ function resolveMetroPort(server) {
10779
11406
  }
10780
11407
  return port;
10781
11408
  }
10782
- var metro_plugin_default = withRNX;
11409
+ var metro_plugin_default = withPeach;
10783
11410
 
10784
11411
  // src/jump-to-source-babel.ts
10785
- function normalizeSourcePath(path16) {
10786
- const queryStart = path16.indexOf("?");
10787
- const clean = queryStart >= 0 ? path16.slice(0, queryStart) : path16;
11412
+ function normalizeSourcePath(path17) {
11413
+ const queryStart = path17.indexOf("?");
11414
+ const clean = queryStart >= 0 ? path17.slice(0, queryStart) : path17;
10788
11415
  return clean.replace(/\\/g, "/");
10789
11416
  }
10790
- function matchesPath(path16, matcher) {
10791
- return typeof matcher === "string" ? path16.includes(matcher) : matcher.test(path16);
11417
+ function matchesPath(path17, matcher) {
11418
+ return typeof matcher === "string" ? path17.includes(matcher) : matcher.test(path17);
10792
11419
  }
10793
11420
  function shouldStampFile(filename, options) {
10794
11421
  const normalized = normalizeSourcePath(filename);
@@ -10821,11 +11448,11 @@ function sootsimJumpToSourceBabelPlugin(api, options = {}) {
10821
11448
  return {
10822
11449
  name: "sootsim-jump-to-source",
10823
11450
  visitor: {
10824
- JSXOpeningElement(path16, state) {
11451
+ JSXOpeningElement(path17, state) {
10825
11452
  if (options.enabled === false) return;
10826
11453
  const filename = state.file?.opts?.filename;
10827
11454
  if (!filename || !shouldStampFile(filename, options)) return;
10828
- const node = path16.node;
11455
+ const node = path17.node;
10829
11456
  const tagName = getJSXName(node.name);
10830
11457
  if (!tagName || tagName === "Fragment" || tagName.endsWith(".Fragment")) return;
10831
11458
  if (hasAttribute(node, attrName)) return;
@@ -10863,8 +11490,9 @@ function sootsimJumpToSourceBabelPlugin(api, options = {}) {
10863
11490
  jumpToSourceBabelPlugin,
10864
11491
  metroPlugin,
10865
11492
  packRnxCaptureRegions,
11493
+ peachPlugin,
10866
11494
  rnxCaptureRasterRegions,
10867
- rnxPlugin,
10868
11495
  rnxRasterFrames,
11496
+ rnxRasterRegionRequests,
10869
11497
  selectRnxRasterNodeIds
10870
11498
  });