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
@@ -22,12 +22,15 @@ import {
22
22
  } from './swift-distribution-contract'
23
23
  import { swiftIcuAsset, type SwiftIcuAsset } from './swift-icu'
24
24
  import {
25
+ swiftManifestCxxLanguageStandard,
25
26
  swiftManifestTargets,
26
27
  swiftPackagePartition,
27
28
  type SwiftPackageTarget,
28
29
  } from './swift-package'
30
+ import { isSwiftResourceBundles } from './swiftContract'
29
31
  import type { SwiftImageUpload } from './swift-submit'
30
32
  import type { SwiftWasmSdk } from './swift-toolchain'
33
+ import type { SwiftResourceBundle } from './swiftContract'
31
34
 
32
35
  export { swiftIcuAsset, type SwiftIcuAsset }
33
36
 
@@ -47,17 +50,25 @@ const BUILD_JOBS = String(Math.min(4, Math.max(1, Math.floor(cores / 2))))
47
50
 
48
51
  export interface SwiftCompileInput {
49
52
  files: Record<string, string>
53
+ metalSources?: Record<string, string>
50
54
  resources?: Record<string, string>
51
55
  /** project-relative resource paths retained before the bundle namespace flattens. */
52
56
  resourcePaths?: string[]
57
+ resourceBundles?: SwiftResourceBundle[]
53
58
  images?: Record<string, SwiftImageUpload>
54
59
  entry: string
55
60
  /**
56
61
  * the sources are a One swift package. One's pod compiles every file with
57
- * `-import-module One`, so `RNXModule`, `RNXPackage` and `JSON` resolve
62
+ * `-import-module One`, so `PeachModule`, `PeachPackage` and `JSON` resolve
58
63
  * without an import; the compile links Peach's `One` module the same way.
59
64
  */
60
65
  oneModule?: boolean
66
+ /**
67
+ * WebAssembly static libraries a local compile links, base64 by the target
68
+ * they link into: a vendored c framework's own wasm build, whose functions
69
+ * replace the stand-in's traps.
70
+ */
71
+ libraries?: Record<string, string>
61
72
  }
62
73
 
63
74
  export interface SwiftCompileOptions {
@@ -124,6 +135,7 @@ export function swiftModuleInputFiles(root: string): string[] {
124
135
  'Package.swift',
125
136
  'scripts/contrast-app-Package.swift',
126
137
  'scripts/build-distribution.ts',
138
+ 'scripts/distribution-clang.ts',
127
139
  'scripts/build-distribution-plugins.sh',
128
140
  'scripts/build-preview-plugin.sh',
129
141
  'toolchain.json',
@@ -160,6 +172,10 @@ export function swiftMacroPlugins(moduleRoot: string): {
160
172
  stale: false,
161
173
  }
162
174
  const dir = path.join(moduleRoot, '.build/host/RnxPreviewMacros')
175
+ const release = JSON.parse(
176
+ readFileSync(path.join(moduleRoot, 'toolchain.json'), 'utf8'),
177
+ ).release
178
+ const compilerStamp = path.join(dir, 'compiler-release')
163
179
  // linux names a plugin's module from lib<Module>.so
164
180
  const ext = process.platform === 'darwin' ? 'dylib' : 'so'
165
181
  const plugins = [
@@ -174,16 +190,20 @@ export function swiftMacroPlugins(moduleRoot: string): {
174
190
  ]
175
191
  return {
176
192
  libraries: plugins.map(({ library }) => library),
177
- stale: plugins.some(
178
- ({ library, source }) =>
179
- !existsSync(library) || statSync(source).mtimeMs > statSync(library).mtimeMs,
180
- ),
193
+ stale:
194
+ !existsSync(compilerStamp) ||
195
+ readFileSync(compilerStamp, 'utf8').trim() !== release ||
196
+ plugins.some(
197
+ ({ library, source }) =>
198
+ !existsSync(library) || statSync(source).mtimeMs > statSync(library).mtimeMs,
199
+ ),
181
200
  }
182
201
  }
183
202
 
184
203
  async function ensureMacroPlugins(
185
204
  moduleRoot: string,
186
205
  toolchainBin: string,
206
+ release: string,
187
207
  ): Promise<string[]> {
188
208
  const { libraries, stale } = swiftMacroPlugins(moduleRoot)
189
209
  if (stale) {
@@ -192,6 +212,10 @@ async function ensureMacroPlugins(
192
212
  toolchainBin,
193
213
  libraries[0],
194
214
  ])
215
+ writeFileSync(
216
+ path.join(path.dirname(libraries[0]!), 'compiler-release'),
217
+ `${release}\n`,
218
+ )
195
219
  }
196
220
  return libraries
197
221
  }
@@ -279,6 +303,7 @@ const OPTIONAL_FRAMEWORK_DEPENDENCIES: Record<string, string[]> = {
279
303
  TikTokBusinessSDK: [],
280
304
  nSure: [],
281
305
  Statsig: [],
306
+ TOCropViewController: [],
282
307
  RiveRuntime: ['MetalKit'],
283
308
  MetalKit: [],
284
309
  DatadogCore: [],
@@ -293,6 +318,7 @@ const OPTIONAL_FRAMEWORK_DEPENDENCIES: Record<string, string[]> = {
293
318
  Intercom: [],
294
319
  FirebaseCore: [],
295
320
  FirebaseSharedSwift: ['FirebaseCore'],
321
+ FirebaseRemoteConfig: ['FirebaseCore', 'FirebaseSharedSwift'],
296
322
  FirebaseFirestoreInternal: ['FirebaseCore'],
297
323
  FirebaseAnalytics: ['FirebaseCore'],
298
324
  FirebaseAppCheck: ['FirebaseCore'],
@@ -300,6 +326,7 @@ const OPTIONAL_FRAMEWORK_DEPENDENCIES: Record<string, string[]> = {
300
326
  FirebaseCrashlytics: ['FirebaseCore'],
301
327
  FirebaseFirestore: ['FirebaseCore', 'FirebaseSharedSwift', 'FirebaseFirestoreInternal'],
302
328
  FirebaseStorage: ['FirebaseCore'],
329
+ GoogleMobileAds: [],
303
330
  FBAudienceNetwork: [],
304
331
  }
305
332
  const OPTIONAL_FRAMEWORKS = new Set(Object.keys(OPTIONAL_FRAMEWORK_DEPENDENCIES))
@@ -514,13 +541,21 @@ export function missingSwiftModules(
514
541
 
515
542
  export function swiftTargetDependencies(
516
543
  files: Record<string, string>,
517
- targets: Pick<SwiftPackageTarget, 'name' | 'path'>[],
544
+ targets: Pick<SwiftPackageTarget, 'name' | 'path' | 'dependencies'>[],
518
545
  ): Map<string, string[]> {
519
546
  const names = new Set([...OPTIONAL_FRAMEWORKS, ...targets.map((target) => target.name)])
520
547
  const siblings = new Map<string, string[]>()
521
548
  for (const target of targets) {
522
549
  const prefix = target.path === '.' ? '' : `${target.path}/`
523
- const deps = new Set<string>()
550
+ const deps = new Set(
551
+ (target.dependencies ?? []).flatMap((dependency) =>
552
+ dependency.kind === 'target' &&
553
+ dependency.name !== target.name &&
554
+ names.has(dependency.name)
555
+ ? [dependency.name]
556
+ : [],
557
+ ),
558
+ )
524
559
  for (const [file, contents] of Object.entries(files)) {
525
560
  if (file === 'Package.swift' || !file.startsWith(prefix)) continue
526
561
  if (
@@ -554,23 +589,22 @@ const importsSpriteKit = (files: Record<string, string>): boolean =>
554
589
  // every iOS source sees through Foundation what darwin's Foundation exports:
555
590
  // PeachObjC supplies the ObjectiveC module's selectors, Dispatch Foundation's
556
591
  // Darwin queue exports, and FoundationNetworking (re-exporting PeachFoundation)
557
- // URLSession, NotificationCenter, OperationQueue and the CoreFoundation types.
558
- // WASILibc is the platform libc the way Darwin's headers are on iOS: its
559
- // math.h answers the free round Kingfisher's SizeExtensions reaches, and its
560
- // pthread mutexes are what a Foundation-only source reaches there
561
- // (SwiftSoup's Mutex). pthread.h is not in the overlay's module: the sdk's
562
- // wasi-libc.modulemap (swift_static/wasi/wasm32) carries it as the separate
563
- // top-level module wasi_pthread, which nothing re-exports, so the flags name
564
- // both. these modules export only names iOS has, WASILibc's wasi-only names
565
- // aside; Peach's host plumbing is `package` or lives in PeachJSON, which none
566
- // of them re-exports. scripts/contrast-app-Package.swift and
592
+ // URLSession, NotificationCenter, OperationQueue and the CoreFoundation types,
593
+ // and PeachFoundationCombine the ObservableObject and Published aliases.
594
+ // Darwin is the platform libc and Mach, as Foundation re-exports it on iOS:
595
+ // it re-exports WASILibc, whose math.h answers the free round Kingfisher's
596
+ // SizeExtensions reaches, and the sdk's separate pthread module wasi_pthread,
597
+ // whose mutexes a Foundation-only source reaches (SwiftSoup's Mutex). these
598
+ // modules export only names iOS has, WASILibc's wasi-only names aside;
599
+ // Peach's host plumbing is `package` or lives in PeachJSON, which none of
600
+ // them re-exports. scripts/contrast-app-Package.swift and
567
601
  // example/Package.swift carry the same flags.
568
602
  export const FOUNDATION_IMPLICIT_MODULES = [
569
603
  'PeachObjC',
570
604
  'Dispatch',
571
605
  'FoundationNetworking',
572
- 'WASILibc',
573
- 'wasi_pthread',
606
+ 'PeachFoundationCombine',
607
+ 'Darwin',
574
608
  ]
575
609
  const FOUNDATION_IMPLICIT_FLAGS = FOUNDATION_IMPLICIT_MODULES.map(
576
610
  (module) => `, "-Xfrontend", "-import-module", "-Xfrontend", "${module}"`,
@@ -578,7 +612,7 @@ const FOUNDATION_IMPLICIT_FLAGS = FOUNDATION_IMPLICIT_MODULES.map(
578
612
  const ONE_IMPLICIT_FLAGS = ', "-Xfrontend", "-import-module", "-Xfrontend", "One"'
579
613
 
580
614
  /** bump with any change to the emitted multi-target manifest text. */
581
- export const MULTI_MANIFEST_VERSION = 12
615
+ export const MULTI_MANIFEST_VERSION = 18
582
616
 
583
617
  export function swiftArtifactHash(
584
618
  input: SwiftCompileInput,
@@ -586,6 +620,8 @@ export function swiftArtifactHash(
586
620
  moduleRoot: string,
587
621
  ): string {
588
622
  const hash = createHash('sha256')
623
+ // v22: Foundation sources see Darwin, which carries the libc and Mach
624
+ // v21: Foundation sources see the ObservableObject and Published aliases
589
625
  // v20: supplied table editing and swipe methods preserve objective-c selectors
590
626
  // v18: NSValue(time:) constructs NSStructBox through NSValue.boxedTime
591
627
  // v17: AVAsset(url:) constructs AVURLAsset for the class cluster
@@ -602,13 +638,22 @@ export function swiftArtifactHash(
602
638
  // v6: app and scene delegate classes compile final
603
639
  // (v5: a target declaring resources gets SwiftPM's Bundle.module accessor;
604
640
  // v4: sources compile through swiftSourceAsIOS)
605
- hash.update(`swift-compile/v20\n${release}\n`)
641
+ hash.update(`swift-compile/v23\n${release}\n`)
606
642
  if (input.oneModule) hash.update('one-module\n')
607
643
  hash.update(swiftModuleDigest(moduleRoot))
608
644
  for (const file of Object.keys(input.files).sort()) {
609
645
  hash.update(createHash('sha256').update(file).digest())
610
646
  hash.update(createHash('sha256').update(input.files[file]).digest())
611
647
  }
648
+ for (const file of Object.keys(input.metalSources ?? {}).sort()) {
649
+ hash.update('metal-source\n')
650
+ hash.update(createHash('sha256').update(file).digest())
651
+ hash.update(
652
+ createHash('sha256')
653
+ .update(input.metalSources?.[file] ?? '')
654
+ .digest(),
655
+ )
656
+ }
612
657
  for (const base of Object.keys(input.resources ?? {}).sort()) {
613
658
  hash.update(createHash('sha256').update(base).digest())
614
659
  hash.update(
@@ -628,6 +673,19 @@ export function swiftArtifactHash(
628
673
  hash.update('resource-path\n')
629
674
  hash.update(createHash('sha256').update(file).digest())
630
675
  }
676
+ hash.update(
677
+ JSON.stringify(
678
+ [...(input.resourceBundles ?? [])].sort((a, b) => a.target.localeCompare(b.target)),
679
+ ),
680
+ )
681
+ for (const target of Object.keys(input.libraries ?? {}).sort()) {
682
+ hash.update(`library\n${target}\n`)
683
+ hash.update(
684
+ createHash('sha256')
685
+ .update(input.libraries?.[target] ?? '')
686
+ .digest(),
687
+ )
688
+ }
631
689
  const targets = compileTargets(input)
632
690
  if (targets.length > 0) {
633
691
  hash.update(`swift-multi/v${MULTI_MANIFEST_VERSION}\n`)
@@ -643,14 +701,28 @@ export function swiftArtifactHash(
643
701
  return hash.digest('hex')
644
702
  }
645
703
 
704
+ interface SwiftNativeTargetPlan {
705
+ path: string
706
+ includeDirectory: string
707
+ // units that consume a swift-generated header: excluded from the original
708
+ // target and compiled by the downstream implementation target.
709
+ lateSources: string[]
710
+ late: { name: string; producers: string[] }
711
+ }
712
+
646
713
  export function emitSwiftPackageManifest(args: {
647
714
  targets: SwiftPackageTarget[]
715
+ cxxLanguageStandard?: string
716
+ native?: Map<string, SwiftNativeTargetPlan>
717
+ headerDirectory?: string
648
718
  siblings: Map<string, string[]>
649
719
  moduleRoot: string
650
720
  oneModule?: boolean
651
721
  spriteKit?: boolean
652
722
  /** link the prebuilt distribution at moduleRoot instead of its sources. */
653
723
  distribution?: SwiftDistributionManifest
724
+ /** the static library each target links, by target name. */
725
+ libraries?: Map<string, string>
654
726
  }): string {
655
727
  const { targets, siblings, moduleRoot, oneModule, spriteKit, distribution } = args
656
728
  const reachedFrameworks = new Set(
@@ -682,6 +754,10 @@ export function emitSwiftPackageManifest(args: {
682
754
  const isolation = target.mainActorIsolation
683
755
  ? ' .defaultIsolation(MainActor.self),'
684
756
  : ''
757
+ const interoperability = target.cxxInterop ? ' .interoperabilityMode(.Cxx),' : ''
758
+ const defines = (target.defines ?? [])
759
+ .map((name) => ` .define(${JSON.stringify(name)}),`)
760
+ .join('')
685
761
  // a distribution's modules import from its modules/ directory, and its
686
762
  // objects link as inputs, exactly as a source build links every object it
687
763
  // compiled: whole, and ahead of the sdk libraries, so PeachICU's
@@ -693,9 +769,29 @@ export function emitSwiftPackageManifest(args: {
693
769
  const imports = distribution
694
770
  ? `, "-I", ${JSON.stringify(path.join(moduleRoot, 'modules'))}`
695
771
  : ''
696
- const swiftSettings = `swiftSettings: [.swiftLanguageMode(.v${target.languageMode}),${isolation} .unsafeFlags(["-Osize"${FOUNDATION_IMPLICIT_FLAGS}${oneModule ? ONE_IMPLICIT_FLAGS : ''}${imports}])]`
772
+ const native = args.native?.get(target.name)
773
+ const nativeImports = (siblings.get(target.name) ?? [])
774
+ .filter((name) => args.native?.has(name))
775
+ .map(
776
+ (name) =>
777
+ `, "-Xfrontend", "-import-module", "-Xfrontend", ${JSON.stringify(name)}`,
778
+ )
779
+ .join('')
780
+ const header =
781
+ args.headerDirectory &&
782
+ [...(args.native?.values() ?? [])].some((value) =>
783
+ value.late.producers.includes(target.name),
784
+ )
785
+ ? `, "-emit-objc-header-path", ${JSON.stringify(path.join(args.headerDirectory, `${target.name}-Swift.h`))}`
786
+ : ''
787
+ const swiftSettings = `swiftSettings: [.swiftLanguageMode(.v${target.languageMode}),${isolation}${interoperability}${defines} .unsafeFlags(["-Osize"${FOUNDATION_IMPLICIT_FLAGS}${oneModule ? ONE_IMPLICIT_FLAGS : ''}${imports}${nativeImports}${header}])]`
697
788
  const deps = [
698
- ...(distribution
789
+ ...(target.executable
790
+ ? [...(args.native?.values() ?? [])].map((value) =>
791
+ JSON.stringify(value.late.name),
792
+ )
793
+ : []),
794
+ ...(distribution || native
699
795
  ? []
700
796
  : [
701
797
  '.product(name: "SwiftUI", package: "sootsim-swift")',
@@ -729,13 +825,17 @@ export function emitSwiftPackageManifest(args: {
729
825
  ]),
730
826
  .unsafeFlags(["-Xlinker", "--strip-all"], .when(configuration: .release)),
731
827
  ]`
732
- : ''
828
+ : args.libraries?.has(target.name)
829
+ ? `,
830
+ linkerSettings: [.unsafeFlags([${JSON.stringify(args.libraries.get(target.name))}])]`
831
+ : ''
733
832
  return [
734
833
  ` ${kind}(`,
735
834
  ` name: "${target.name}",`,
736
835
  ` dependencies: [${deps}],`,
737
836
  ` path: "${target.path}",`,
738
- ` ${swiftSettings}${link}`,
837
+ ...(native ? [` exclude: ${JSON.stringify(native.lateSources)},`] : []),
838
+ ` ${native ? 'cxxSettings: []' : swiftSettings}${link}`,
739
839
  ` ),`,
740
840
  ].join('\n')
741
841
  }
@@ -752,7 +852,17 @@ export function emitSwiftPackageManifest(args: {
752
852
  ` dependencies: [${distribution ? '' : `.package(path: "${moduleRoot}")`}],`,
753
853
  ' targets: [',
754
854
  ...targets.map(stanza),
755
- ' ]',
855
+ ...[...(args.native?.entries() ?? [])].flatMap(([name, native]) => [
856
+ ` .target(name: ${JSON.stringify(native.late.name)},`,
857
+ ` dependencies: ${JSON.stringify([name, ...native.late.producers])},`,
858
+ ` path: ${JSON.stringify(native.path)},`,
859
+ ` sources: ${JSON.stringify(native.lateSources)},`,
860
+ ` publicHeadersPath: "include",`,
861
+ ` cxxSettings: [.unsafeFlags(["-fno-cxx-modules", "-I", ${JSON.stringify(native.includeDirectory)}, "-I", ${JSON.stringify(args.headerDirectory)}])]),`,
862
+ ]),
863
+ args.cxxLanguageStandard
864
+ ? ` ],\n cxxLanguageStandard: .${args.cxxLanguageStandard}`
865
+ : ' ]',
756
866
  ')',
757
867
  '',
758
868
  ].join('\n')
@@ -761,7 +871,7 @@ export function emitSwiftPackageManifest(args: {
761
871
  // the build tree mirrors the input: a file is written only when its text
762
872
  // changed and a file the input dropped is removed, so an unchanged source
763
873
  // keeps its mtime and swiftpm rebuilds only what moved. `.build` stays.
764
- export function syncSwiftTree(base: string, files: Map<string, string>): void {
874
+ export function syncSwiftTree(base: string, files: Map<string, string | Buffer>): void {
765
875
  mkdirSync(base, { recursive: true })
766
876
  const walk = (dir: string): void => {
767
877
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
@@ -773,9 +883,15 @@ export function syncSwiftTree(base: string, files: Map<string, string>): void {
773
883
  }
774
884
  walk(base)
775
885
  for (const [full, contents] of files) {
776
- if (existsSync(full) && readFileSync(full, 'utf8') === contents) continue
886
+ if (
887
+ existsSync(full) &&
888
+ (typeof contents === 'string'
889
+ ? readFileSync(full, 'utf8') === contents
890
+ : readFileSync(full).equals(contents))
891
+ )
892
+ continue
777
893
  mkdirSync(path.dirname(full), { recursive: true })
778
- writeFileSync(full, contents, 'utf8')
894
+ writeFileSync(full, contents)
779
895
  }
780
896
  }
781
897
 
@@ -1009,7 +1125,12 @@ function liftExtensionOverrides(
1009
1125
  nameAt: number
1010
1126
  edits: [number, number, string][]
1011
1127
  }[] = []
1012
- const overrides: { type: string; member: string; at: number; nameAt: number }[] = []
1128
+ const overrides: {
1129
+ type: string
1130
+ member: string
1131
+ at: number
1132
+ nameAt: number
1133
+ }[] = []
1013
1134
  // the offset just past the brace that closes the one at `open`
1014
1135
  const closing = (open: number): number => closingBrace(source, tokens, open)
1015
1136
  for (const at of tokens) {
@@ -2203,6 +2324,11 @@ export function writeSwiftProject(
2203
2324
  input: SwiftCompileInput,
2204
2325
  moduleRoot: string,
2205
2326
  ): void {
2327
+ if (
2328
+ input.resourceBundles !== undefined &&
2329
+ !isSwiftResourceBundles(input.resourceBundles)
2330
+ )
2331
+ throw new Error('swift compile input has invalid target bundle assignments')
2206
2332
  const resourceTargets = swiftManifestTargets(
2207
2333
  input.files['Package.swift'] ?? '',
2208
2334
  input.resourcePaths,
@@ -2223,7 +2349,96 @@ export function writeSwiftProject(
2223
2349
  },
2224
2350
  ]
2225
2351
  : compileTargets(input)
2226
- const files = new Map<string, string>()
2352
+ const files = new Map<string, string | Buffer>()
2353
+ const native = new Map<string, SwiftNativeTargetPlan>()
2354
+ const headerDirectory = path.join(layout.root, '.build', 'peach-cxx-headers')
2355
+ // declarations are imported before swift can emit the header that native
2356
+ // implementations consume. give those implementations a downstream target.
2357
+ for (const target of targets) {
2358
+ const prefix = target.path === '.' ? '' : `${target.path}/`
2359
+ const entries = Object.entries(input.files).filter(
2360
+ ([file]) =>
2361
+ file.startsWith(prefix) &&
2362
+ !targets.some(
2363
+ (candidate) =>
2364
+ candidate.name !== target.name &&
2365
+ candidate.path !== '.' &&
2366
+ candidate.path.startsWith(prefix) &&
2367
+ file.startsWith(`${candidate.path}/`),
2368
+ ),
2369
+ )
2370
+ if (entries.some(([file]) => file.endsWith('.swift'))) continue
2371
+ const units = entries.filter(([file]) => /\.(?:c|cc|cpp|cxx|m|mm)$/.test(file))
2372
+ if (units.length === 0) continue
2373
+ const includes = `${prefix}include/`
2374
+ const consumers = new Map<string, Set<string>>()
2375
+ const reverse = new Map<string, string[]>()
2376
+ for (const [file, contents] of entries) {
2377
+ const producers = new Set<string>()
2378
+ // a block-commented include is not an edge.
2379
+ const source = contents.replace(/\/\*[\s\S]*?\*\//g, '')
2380
+ for (const match of source.matchAll(/^\s*#\s*include\s*[<"]([^>"]+)[>"]/gm)) {
2381
+ const include = match[1]!
2382
+ const producer = /(?:^|\/)([^/]+)-Swift\.h$/.exec(include)?.[1]
2383
+ if (producer && targets.some((value) => value.name === producer))
2384
+ producers.add(producer)
2385
+ const local = [
2386
+ path.posix.join(path.posix.dirname(file), include),
2387
+ `${includes}${include}`,
2388
+ ].find((candidate) => input.files[candidate] !== undefined)
2389
+ if (local) {
2390
+ reverse.set(local, [...(reverse.get(local) ?? []), file])
2391
+ }
2392
+ }
2393
+ consumers.set(file, producers)
2394
+ }
2395
+ const queue = [...consumers.keys()].filter((file) => consumers.get(file)!.size > 0)
2396
+ for (let index = 0; index < queue.length; index++) {
2397
+ const file = queue[index]!
2398
+ for (const parent of reverse.get(file) ?? []) {
2399
+ const inherited = consumers.get(parent)!
2400
+ const before = inherited.size
2401
+ for (const producer of consumers.get(file)!) inherited.add(producer)
2402
+ if (before !== inherited.size) queue.push(parent)
2403
+ }
2404
+ }
2405
+ const late = units.filter(([file]) => consumers.get(file)!.size > 0)
2406
+ if (late.length === 0) continue
2407
+ native.set(target.name, {
2408
+ path: target.path,
2409
+ includeDirectory: path.join(layout.root, includes),
2410
+ lateSources: late.map(([file]) => file.slice(prefix.length)),
2411
+ late: {
2412
+ name: `${target.name}SwiftImplementation`,
2413
+ producers: [
2414
+ ...new Set(late.flatMap(([file]) => [...consumers.get(file)!])),
2415
+ ].sort(),
2416
+ },
2417
+ })
2418
+ // only declaration roots belong to the imported clang module. headers
2419
+ // consuming swift's generated output belong to its implementation target.
2420
+ // a package that ships its own module map keeps it.
2421
+ if (input.files[`${includes}module.modulemap`] !== undefined) continue
2422
+ const roots = entries.filter(
2423
+ ([file]) =>
2424
+ file.startsWith(includes) &&
2425
+ /\.(?:h|hpp|hh|hxx)$/.test(file) &&
2426
+ consumers.get(file)!.size === 0,
2427
+ )
2428
+ files.set(
2429
+ path.join(layout.root, includes, 'module.modulemap'),
2430
+ [
2431
+ `module ${target.name} {`,
2432
+ ...roots.map(
2433
+ ([file]) => ` header ${JSON.stringify(file.slice(includes.length))}`,
2434
+ ),
2435
+ ' export *',
2436
+ '}',
2437
+ '',
2438
+ ].join('\n'),
2439
+ )
2440
+ }
2441
+ if (native.size > 0) mkdirSync(headerDirectory, { recursive: true })
2227
2442
  // swiftpm plans a build root's build once and reuses the plan until a
2228
2443
  // manifest changes, so a file added to the module would never compile
2229
2444
  // there (RAN: a broken new UIKitCore file built "complete" in 0.1s). the
@@ -2239,7 +2454,11 @@ export function writeSwiftProject(
2239
2454
  JSON.stringify(
2240
2455
  resourceTargets
2241
2456
  .filter((target) => target.resources)
2242
- .map((target) => [target.name, target.path]),
2457
+ .map((target) => [
2458
+ target.name,
2459
+ target.path,
2460
+ input.resourceBundles?.find((bundle) => bundle.target === target.name)?.path,
2461
+ ]),
2243
2462
  ),
2244
2463
  )
2245
2464
  .digest('hex')
@@ -2305,6 +2524,12 @@ export function writeSwiftProject(
2305
2524
  files.set(path.join(layout.root, 'Package.swift'), manifest + moduleFiles)
2306
2525
  } else {
2307
2526
  const base = layout.multi ? layout.root : layout.sources
2527
+ const libraries = new Map<string, string>()
2528
+ for (const [target, data] of Object.entries(input.libraries ?? {})) {
2529
+ const file = path.join(layout.root, '.peach-libraries', `lib${target}.a`)
2530
+ files.set(file, Buffer.from(data, 'base64'))
2531
+ libraries.set(target, file)
2532
+ }
2308
2533
  for (const [file, contents] of Object.entries(input.files)) {
2309
2534
  if (file === 'Package.swift') continue
2310
2535
  files.set(
@@ -2316,6 +2541,11 @@ export function writeSwiftProject(
2316
2541
  path.join(layout.root, 'Package.swift'),
2317
2542
  emitSwiftPackageManifest({
2318
2543
  targets,
2544
+ native,
2545
+ headerDirectory: native.size > 0 ? headerDirectory : undefined,
2546
+ cxxLanguageStandard: swiftManifestCxxLanguageStandard(
2547
+ input.files['Package.swift'] ?? '',
2548
+ ),
2319
2549
  siblings: swiftTargetDependencies(
2320
2550
  input.files,
2321
2551
  layout.multi ? targets : targets.map((target) => ({ ...target, path: '.' })),
@@ -2324,13 +2554,20 @@ export function writeSwiftProject(
2324
2554
  oneModule: input.oneModule,
2325
2555
  spriteKit: importsSpriteKit(input.files),
2326
2556
  distribution: distribution ?? undefined,
2557
+ libraries,
2327
2558
  }) + moduleFiles,
2328
2559
  )
2329
2560
  }
2330
- // peach serves all target resources from the mount's flat /res bundle.
2331
- // retain target ownership of the accessor even though its bytes share that bundle.
2561
+ // resource accessors and the /res pack share the original target assignment.
2332
2562
  for (const target of resourceTargets) {
2333
2563
  if (!target.resources) continue
2564
+ const bundle = input.resourceBundles?.find(
2565
+ (candidate) => candidate.target === target.name,
2566
+ )
2567
+ if (!bundle || bundle.sourcePath !== target.path)
2568
+ throw new Error(
2569
+ `swift resource target ${target.name} has no matching bundle assignment`,
2570
+ )
2334
2571
  const directory = layout.multi ? path.join(layout.root, target.path) : layout.sources
2335
2572
  files.set(
2336
2573
  path.join(directory, 'ResourceBundleAccessor.generated.swift'),
@@ -2338,7 +2575,9 @@ export function writeSwiftProject(
2338
2575
  'import Foundation',
2339
2576
  '',
2340
2577
  'extension Foundation.Bundle {',
2341
- ' static let module: Bundle = Bundle.main',
2578
+ bundle.path === '.'
2579
+ ? ' static let module: Bundle = Bundle.main'
2580
+ : ` static let module: Bundle = {\n let url = Bundle.main.bundleURL.appendingPathComponent(${JSON.stringify(bundle.path)})\n guard let bundle = Bundle(url: url) else { fatalError("resource bundle is missing: ${bundle.target}") }\n return bundle\n }()`,
2342
2581
  '}',
2343
2582
  '',
2344
2583
  ].join('\n'),
@@ -2434,7 +2673,6 @@ export function compileSwiftProjectUnit(
2434
2673
  process.platform === 'darwin' &&
2435
2674
  process.env.TM_SESSION &&
2436
2675
  process.env.CI !== 'true' &&
2437
- process.env.CONTRAST_HEAVY_ADMITTED !== '1' &&
2438
2676
  moduleRoot === path.resolve(import.meta.dirname, '../../sootsim-swift') &&
2439
2677
  !swiftDistributionAt(moduleRoot)
2440
2678
  ) {
@@ -2462,7 +2700,11 @@ export function compileSwiftProjectUnit(
2462
2700
  '--output',
2463
2701
  output,
2464
2702
  ],
2465
- { cwd: repo, timeout: options.timeoutMs, maxBuffer: 64 * 1024 * 1024 },
2703
+ {
2704
+ cwd: repo,
2705
+ timeout: options.timeoutMs,
2706
+ maxBuffer: 64 * 1024 * 1024,
2707
+ },
2466
2708
  )
2467
2709
  pending.child.stdout?.on('data', (bytes: Buffer) => process.stdout.write(bytes))
2468
2710
  pending.child.stderr?.on('data', (bytes: Buffer) => process.stderr.write(bytes))
@@ -2508,7 +2750,11 @@ export function compileSwiftProjectUnit(
2508
2750
  `swift-compile: no swift.org toolchain at ${options.toolchainBin}; install ${options.release} and its matching wasm sdk`,
2509
2751
  )
2510
2752
  }
2511
- const macroPlugins = await ensureMacroPlugins(moduleRoot, options.toolchainBin)
2753
+ const macroPlugins = await ensureMacroPlugins(
2754
+ moduleRoot,
2755
+ options.toolchainBin,
2756
+ options.release,
2757
+ )
2512
2758
  // memoized per toolchain, so only a process's first build waits on it,
2513
2759
  // and that one reads and gzips it while swift builds
2514
2760
  const sdk = swiftModuleSdk(moduleRoot).wasmSdkId
@@ -2518,6 +2764,8 @@ export function compileSwiftProjectUnit(
2518
2764
  swift,
2519
2765
  [
2520
2766
  'build',
2767
+ '--build-system',
2768
+ 'native',
2521
2769
  '-j',
2522
2770
  BUILD_JOBS,
2523
2771
  '--package-path',
@@ -52,6 +52,8 @@ export interface SwiftDistributionLock extends SwiftWasmSdk {
52
52
  release: string
53
53
  /** the commit the module sources were built from. */
54
54
  source: string
55
+ /** the Package.swift targets it was built from (swiftPeachModules). */
56
+ targets: string[]
55
57
  hosts: Record<SwiftDistributionHost, { sha256: string; size: number }>
56
58
  }
57
59
 
@@ -107,6 +109,7 @@ export function parseSwiftDistributionLock(value: unknown): SwiftDistributionLoc
107
109
  typeof value.wasmSdkUrl !== 'string' ||
108
110
  typeof value.wasmSdkChecksum !== 'string' ||
109
111
  typeof value.source !== 'string' ||
112
+ !isStrings(value.targets) ||
110
113
  !isRecord(value.hosts)
111
114
  ) {
112
115
  throw new Error('invalid Swift distribution lock')
@@ -131,6 +134,7 @@ export function parseSwiftDistributionLock(value: unknown): SwiftDistributionLoc
131
134
  wasmSdkUrl: value.wasmSdkUrl,
132
135
  wasmSdkChecksum: value.wasmSdkChecksum,
133
136
  source: value.source,
137
+ targets: value.targets,
134
138
  hosts: {
135
139
  'darwin-arm64': entry('darwin-arm64'),
136
140
  'linux-x64': entry('linux-x64'),