peachsim 0.1.939 → 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 +999 -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 +688 -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 +325 -25
  133. package/dist-lib/native-app-identity.mjs +323 -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 +398 -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
package/src/vite.d.ts CHANGED
@@ -7,4 +7,4 @@ export interface PeachPluginOptions {
7
7
  open?: boolean | { appName: string }
8
8
  }
9
9
 
10
- export declare function rnxPlugin(options?: PeachPluginOptions): Plugin
10
+ export declare function peachPlugin(options?: PeachPluginOptions): Plugin
@@ -0,0 +1,221 @@
1
+ import fs from 'node:fs'
2
+ import { createRequire } from 'node:module'
3
+ import { Worker } from 'node:worker_threads'
4
+ import { rollup } from 'rollup'
5
+ import { isRecord } from './is-record'
6
+
7
+ const require = createRequire(import.meta.url)
8
+ const systemRuntime = fs.readFileSync(require.resolve('systemjs/dist/s.min.js'), 'utf8')
9
+ const minifierModule = require.resolve('terser')
10
+ type MinifiedWorkerChunk = { code: string; map: string }
11
+ const minifierWorker = `
12
+ const { parentPort, workerData } = require('node:worker_threads');
13
+ const { minify } = require(workerData.module);
14
+ parentPort.on('message', async ({ code, map, keepNames }) => {
15
+ try {
16
+ const result = await minify(code, {
17
+ module: true,
18
+ compress: { passes: 2 },
19
+ mangle: true,
20
+ keep_fnames: keepNames,
21
+ keep_classnames: keepNames,
22
+ sourceMap: { content: map },
23
+ });
24
+ parentPort.postMessage({ code: result.code, map: result.map });
25
+ } catch (error) {
26
+ parentPort.postMessage({ error: error instanceof Error ? error.message : String(error) });
27
+ }
28
+ });
29
+ `
30
+ type MinifierJob = {
31
+ code: string
32
+ map: string
33
+ keepNames: boolean
34
+ resolve: (result: MinifiedWorkerChunk) => void
35
+ reject: (error: Error) => void
36
+ }
37
+ type MinifierSlot = {
38
+ worker: Worker
39
+ job: MinifierJob | undefined
40
+ failure: Error | undefined
41
+ }
42
+ // share two reusable isolates across every worker build in this vite process.
43
+ const minifiers = new Set<MinifierSlot>()
44
+ const pendingMinifiers: MinifierJob[] = []
45
+
46
+ function runMinifiers() {
47
+ while (pendingMinifiers.length) {
48
+ let slot = [...minifiers].find((candidate) => !candidate.job && !candidate.failure)
49
+ if (!slot) {
50
+ if (minifiers.size === 2) return
51
+ let worker: Worker
52
+ try {
53
+ worker = new Worker(minifierWorker, {
54
+ eval: true,
55
+ execArgv: [],
56
+ workerData: { module: minifierModule },
57
+ })
58
+ } catch (error) {
59
+ pendingMinifiers
60
+ .shift()
61
+ ?.reject(error instanceof Error ? error : new Error(String(error)))
62
+ continue
63
+ }
64
+ const created: MinifierSlot = { worker, job: undefined, failure: undefined }
65
+ minifiers.add(created)
66
+ worker.on('message', (message: unknown) => {
67
+ if (created.failure) return
68
+ const job = created.job
69
+ let result: MinifiedWorkerChunk | Error
70
+ if (isRecord(message) && typeof message.error === 'string') {
71
+ result = new Error(message.error)
72
+ } else if (
73
+ isRecord(message) &&
74
+ typeof message.code === 'string' &&
75
+ message.code &&
76
+ typeof message.map === 'string'
77
+ ) {
78
+ result = { code: message.code, map: message.map }
79
+ } else {
80
+ created.failure = new Error(
81
+ 'worker minification produced no code or source map',
82
+ )
83
+ void worker.terminate()
84
+ return
85
+ }
86
+ if (!job) {
87
+ created.failure = new Error('worker minifier returned an unexpected result')
88
+ void worker.terminate()
89
+ return
90
+ }
91
+ created.job = undefined
92
+ // idle isolates must not keep a completed build process alive.
93
+ worker.unref()
94
+ if (result instanceof Error) job.reject(result)
95
+ else job.resolve(result)
96
+ runMinifiers()
97
+ })
98
+ worker.on('error', (error) => {
99
+ created.failure = error instanceof Error ? error : new Error(String(error))
100
+ })
101
+ // a failed isolate owns its slot until its thread has actually exited.
102
+ worker.once('exit', (status) => {
103
+ minifiers.delete(created)
104
+ created.job?.reject(
105
+ created.failure ??
106
+ new Error(`worker minifier exited ${status} without a result`),
107
+ )
108
+ runMinifiers()
109
+ })
110
+ slot = created
111
+ }
112
+ const job = pendingMinifiers.shift()
113
+ if (!job) return
114
+ slot.job = job
115
+ slot.worker.ref()
116
+ try {
117
+ slot.worker.postMessage({ code: job.code, map: job.map, keepNames: job.keepNames })
118
+ } catch (error) {
119
+ slot.failure = error instanceof Error ? error : new Error(String(error))
120
+ void slot.worker.terminate()
121
+ }
122
+ }
123
+ }
124
+
125
+ // systemjs owns linking, live exports, cycles and evaluation identity. its
126
+ // instantiate hook uses the same fetch and script evaluation in every worker
127
+ // host, including public JavaScriptCore. each fetch captures its own anonymous
128
+ // registration so concurrent chunks cannot consume one another's declarations.
129
+ const workerLoader = `
130
+ // chunk fetching yields before the worker's message listener is installed.
131
+ // retain the payloads and transferred ports until linking ends. intercepted
132
+ // events keep their immediate-propagation flag, so replay fresh native events.
133
+ const pendingWorkerMessages = [];
134
+ const WorkerMessageEvent = globalThis.MessageEvent;
135
+ const dispatchWorkerMessage = globalThis.dispatchEvent.bind(globalThis);
136
+ const removeWorkerMessageListener = globalThis.removeEventListener.bind(globalThis);
137
+ function bufferWorkerMessage(event) {
138
+ pendingWorkerMessages.push(new WorkerMessageEvent('message', {
139
+ data: event.data,
140
+ origin: event.origin,
141
+ lastEventId: event.lastEventId,
142
+ source: event.source,
143
+ ports: event.ports,
144
+ }));
145
+ event.stopImmediatePropagation();
146
+ }
147
+ globalThis.addEventListener('message', bufferWorkerMessage, true);
148
+ const workerEntryUrl = globalThis.location.href;
149
+ const workerEntryRegistration = System.getRegister();
150
+ System.instantiate = async function(url) {
151
+ if (url === workerEntryUrl) return workerEntryRegistration;
152
+ const response = await fetch(url, { credentials: 'same-origin' });
153
+ if (!response.ok) throw new Error(url + ': HTTP ' + response.status);
154
+ let registration;
155
+ new Function('System', await response.text())({
156
+ register(dependencies, declare) { registration = [dependencies, declare]; }
157
+ });
158
+ if (!registration) throw new Error(url + ': missing worker registration');
159
+ return registration;
160
+ };
161
+ await System.import(workerEntryUrl);
162
+ removeWorkerMessageListener('message', bufferWorkerMessage, true);
163
+ for (const event of pendingWorkerMessages) dispatchWorkerMessage(event);
164
+ pendingWorkerMessages.length = 0;
165
+ `
166
+
167
+ export async function renderWorkerSystemChunk(
168
+ code: string,
169
+ isEntry: boolean,
170
+ keepNames = false,
171
+ ) {
172
+ const entry = '\0peach-worker-chunk'
173
+ const bundle = await rollup({
174
+ input: entry,
175
+ treeshake: false,
176
+ plugins: [
177
+ {
178
+ name: 'peach-worker-system-chunk',
179
+ resolveId(id) {
180
+ return id === entry ? id : { id, external: true }
181
+ },
182
+ load(id) {
183
+ return id === entry ? code : null
184
+ },
185
+ renderDynamicImport({ targetModuleId }) {
186
+ // runtime-supplied URLs name ES modules outside the generated graph.
187
+ // generated chunk imports retain their SystemJS registration loader.
188
+ if (targetModuleId === null) return { left: 'import(', right: ')' }
189
+ },
190
+ },
191
+ ],
192
+ })
193
+ let loweredCode: string
194
+ let loweredMap: string
195
+ try {
196
+ const { output } = await bundle.generate({
197
+ format: 'system',
198
+ sourcemap: true,
199
+ banner: isEntry ? systemRuntime : undefined,
200
+ footer: isEntry ? workerLoader : undefined,
201
+ })
202
+ const chunk = output[0]
203
+ if (!chunk || chunk.type !== 'chunk' || !chunk.map)
204
+ throw new Error('worker module lowering produced no chunk or source map')
205
+ loweredCode = chunk.code
206
+ loweredMap = chunk.map.toString()
207
+ } finally {
208
+ await bundle.close()
209
+ }
210
+
211
+ return new Promise<MinifiedWorkerChunk>((resolve, reject) => {
212
+ pendingMinifiers.push({
213
+ code: loweredCode,
214
+ map: loweredMap,
215
+ keepNames,
216
+ resolve,
217
+ reject,
218
+ })
219
+ runMinifiers()
220
+ })
221
+ }
@@ -12,14 +12,14 @@ function isNode(value: unknown): value is SyntaxNode {
12
12
  )
13
13
  }
14
14
 
15
- function walk(node: SyntaxNode, visit: (node: SyntaxNode) => void): void {
16
- visit(node)
17
- for (const value of Object.values(node)) {
18
- if (isNode(value)) walk(value, visit)
19
- else if (Array.isArray(value)) {
20
- for (const child of value) if (isNode(child)) walk(child, visit)
21
- }
22
- }
15
+ function childNodes(value: unknown): SyntaxNode[] {
16
+ return Array.isArray(value) ? value.filter(isNode) : []
17
+ }
18
+
19
+ function identifierName(node: unknown): string | undefined {
20
+ if (!isNode(node) || node.type !== 'Identifier') return undefined
21
+ const name = Reflect.get(node, 'name')
22
+ return typeof name === 'string' ? name : undefined
23
23
  }
24
24
 
25
25
  function propertyName(node: unknown): string | undefined {
@@ -28,48 +28,358 @@ function propertyName(node: unknown): string | undefined {
28
28
  return typeof name === 'string' ? name : undefined
29
29
  }
30
30
 
31
- // collect upstream init records by their actual __initData assignments, including
32
- // minified identifiers and inline records. babel and acorn share these node shapes.
33
- export function workletExecutableBodies(syntax: unknown): Array<{
31
+ // the static name a member or property key selects. a computed identifier names a
32
+ // variable, not a key, so it has none.
33
+ function keyName(owner: SyntaxNode, key: unknown): string | undefined {
34
+ if (Reflect.get(owner, 'computed') === true && isNode(key) && key.type === 'Identifier')
35
+ return undefined
36
+ return propertyName(key)
37
+ }
38
+
39
+ // the names a binding pattern declares or an assignment target writes.
40
+ function patternNames(node: unknown): string[] {
41
+ if (!isNode(node)) return []
42
+ switch (node.type) {
43
+ case 'Identifier': {
44
+ const name = identifierName(node)
45
+ return name === undefined ? [] : [name]
46
+ }
47
+ case 'AssignmentPattern':
48
+ return patternNames(Reflect.get(node, 'left'))
49
+ case 'RestElement':
50
+ return patternNames(Reflect.get(node, 'argument'))
51
+ case 'ArrayPattern':
52
+ return childNodes(Reflect.get(node, 'elements')).flatMap(patternNames)
53
+ case 'ObjectPattern':
54
+ return childNodes(Reflect.get(node, 'properties')).flatMap((property) =>
55
+ patternNames(
56
+ property.type === 'Property' || property.type === 'ObjectProperty'
57
+ ? Reflect.get(property, 'value')
58
+ : property,
59
+ ),
60
+ )
61
+ default:
62
+ return []
63
+ }
64
+ }
65
+
66
+ // a scope holds the names declared directly in one scope-owning node. `hoist`
67
+ // marks where `var` lands: a function body or the program.
68
+ interface Scope {
69
+ parent: Scope | undefined
70
+ hoist: boolean
71
+ names: Map<string, Binding>
72
+ }
73
+
74
+ type Binding =
75
+ | { kind: 'value'; init: SyntaxNode; scope: Scope }
76
+ // `key` is set when the parameter is a destructured property of that argument.
77
+ | { kind: 'param'; fn: SyntaxNode; index: number; key?: string }
78
+ | { kind: 'opaque' }
79
+
80
+ interface InitCollection {
81
+ // the right side of each `x.__initData = ...`, with the scope it evaluates in.
82
+ inits: Array<{ value: SyntaxNode; scope: Scope }>
83
+ // each immediately invoked function, keyed by its callee, with the call and its scope.
84
+ immediate: Map<SyntaxNode, { call: SyntaxNode; scope: Scope }>
85
+ // names written by assignment, resolved after the walk.
86
+ writes: Array<{ name: string; scope: Scope }>
87
+ // bindings written after their declaration; their value is not static.
88
+ reassigned: Set<Binding>
89
+ }
90
+
91
+ const FUNCTION_TYPES = new Set([
92
+ 'FunctionDeclaration',
93
+ 'FunctionExpression',
94
+ 'ArrowFunctionExpression',
95
+ ])
96
+ const MAX_RESOLUTION_DEPTH = 32
97
+
98
+ function newScope(parent: Scope | undefined, hoist: boolean): Scope {
99
+ return { parent, hoist, names: new Map() }
100
+ }
101
+
102
+ function hoistScope(scope: Scope): Scope {
103
+ let current = scope
104
+ while (!current.hoist && current.parent) current = current.parent
105
+ return current
106
+ }
107
+
108
+ // a second declaration of one name in one scope leaves its value order-dependent,
109
+ // so the name stays opaque rather than picking either declaration.
110
+ function declare(scope: Scope, name: string, binding: Binding): void {
111
+ scope.names.set(name, scope.names.has(name) ? { kind: 'opaque' } : binding)
112
+ }
113
+
114
+ function declareOpaque(scope: Scope, names: string[]): void {
115
+ for (const name of names) declare(scope, name, { kind: 'opaque' })
116
+ }
117
+
118
+ function lookup(scope: Scope, name: string): Binding | undefined {
119
+ for (let current: Scope | undefined = scope; current; current = current.parent) {
120
+ const binding = current.names.get(name)
121
+ if (binding) return binding
122
+ }
123
+ return undefined
124
+ }
125
+
126
+ // a destructured parameter binds each plain property to that key of its argument.
127
+ // rest elements, defaults and nested patterns stay opaque.
128
+ function declareParam(inner: Scope, fn: SyntaxNode, index: number, param: unknown): void {
129
+ const name = identifierName(param)
130
+ if (name !== undefined) {
131
+ declare(inner, name, { kind: 'param', fn, index })
132
+ return
133
+ }
134
+ if (!isNode(param) || param.type !== 'ObjectPattern') {
135
+ declareOpaque(inner, patternNames(param))
136
+ return
137
+ }
138
+ for (const property of childNodes(Reflect.get(param, 'properties'))) {
139
+ const key = keyName(property, Reflect.get(property, 'key'))
140
+ const value: unknown = Reflect.get(property, 'value')
141
+ const valueName = identifierName(value)
142
+ if (
143
+ key !== undefined &&
144
+ valueName !== undefined &&
145
+ ['Property', 'ObjectProperty'].includes(property.type)
146
+ )
147
+ declare(inner, valueName, { kind: 'param', fn, index, key })
148
+ else
149
+ declareOpaque(
150
+ inner,
151
+ patternNames(property.type === 'RestElement' ? property : value),
152
+ )
153
+ }
154
+ }
155
+
156
+ // the scope a node's children are visited in, after declaring the names it binds.
157
+ function enter(node: SyntaxNode, scope: Scope): Scope {
158
+ switch (node.type) {
159
+ case 'FunctionDeclaration':
160
+ case 'FunctionExpression':
161
+ case 'ArrowFunctionExpression': {
162
+ const inner = newScope(scope, true)
163
+ const params = Reflect.get(node, 'params')
164
+ if (Array.isArray(params)) {
165
+ params.forEach((param: unknown, index) => declareParam(inner, node, index, param))
166
+ }
167
+ const id = Reflect.get(node, 'id')
168
+ if (node.type === 'FunctionExpression') declareOpaque(inner, patternNames(id))
169
+ if (node.type === 'FunctionDeclaration') {
170
+ declareOpaque(scope, patternNames(id))
171
+ declareOpaque(hoistScope(scope), patternNames(id))
172
+ }
173
+ return inner
174
+ }
175
+ case 'BlockStatement':
176
+ case 'ForStatement':
177
+ case 'ForInStatement':
178
+ case 'ForOfStatement':
179
+ case 'SwitchStatement':
180
+ case 'StaticBlock':
181
+ return newScope(scope, false)
182
+ case 'CatchClause': {
183
+ const inner = newScope(scope, false)
184
+ declareOpaque(inner, patternNames(Reflect.get(node, 'param')))
185
+ return inner
186
+ }
187
+ case 'VariableDeclaration': {
188
+ const target = Reflect.get(node, 'kind') === 'var' ? hoistScope(scope) : scope
189
+ for (const declarator of childNodes(Reflect.get(node, 'declarations'))) {
190
+ const id = Reflect.get(declarator, 'id')
191
+ const init = Reflect.get(declarator, 'init')
192
+ const name = identifierName(id)
193
+ if (name !== undefined && isNode(init))
194
+ declare(target, name, { kind: 'value', init, scope })
195
+ else declareOpaque(target, patternNames(id))
196
+ }
197
+ return scope
198
+ }
199
+ case 'ImportDeclaration':
200
+ for (const specifier of childNodes(Reflect.get(node, 'specifiers')))
201
+ declareOpaque(scope, patternNames(Reflect.get(specifier, 'local')))
202
+ return scope
203
+ case 'ClassDeclaration':
204
+ declareOpaque(scope, patternNames(Reflect.get(node, 'id')))
205
+ return scope
206
+ default:
207
+ return scope
208
+ }
209
+ }
210
+
211
+ function recordWrites(target: unknown, scope: Scope, collection: InitCollection): void {
212
+ for (const name of patternNames(target)) collection.writes.push({ name, scope })
213
+ }
214
+
215
+ // facts read where they occur: init assignments, immediate calls and writes.
216
+ function record(node: SyntaxNode, scope: Scope, collection: InitCollection): void {
217
+ switch (node.type) {
218
+ case 'AssignmentExpression': {
219
+ const left = Reflect.get(node, 'left')
220
+ const right = Reflect.get(node, 'right')
221
+ if (
222
+ isNode(left) &&
223
+ left.type === 'MemberExpression' &&
224
+ keyName(left, Reflect.get(left, 'property')) === '__initData' &&
225
+ isNode(right)
226
+ )
227
+ collection.inits.push({ value: right, scope })
228
+ recordWrites(left, scope, collection)
229
+ return
230
+ }
231
+ case 'UpdateExpression':
232
+ recordWrites(Reflect.get(node, 'argument'), scope, collection)
233
+ return
234
+ case 'ForInStatement':
235
+ case 'ForOfStatement':
236
+ recordWrites(Reflect.get(node, 'left'), scope, collection)
237
+ return
238
+ case 'CallExpression': {
239
+ const callee = Reflect.get(node, 'callee')
240
+ if (isNode(callee) && FUNCTION_TYPES.has(callee.type))
241
+ collection.immediate.set(callee, { call: node, scope })
242
+ return
243
+ }
244
+ default:
245
+ return
246
+ }
247
+ }
248
+
249
+ function visit(node: SyntaxNode, scope: Scope, collection: InitCollection): void {
250
+ record(node, scope, collection)
251
+ const inner = enter(node, scope)
252
+ for (const value of Object.values(node)) {
253
+ if (isNode(value)) visit(value, inner, collection)
254
+ else for (const child of childNodes(value)) visit(child, inner, collection)
255
+ }
256
+ }
257
+
258
+ function collectInitData(root: SyntaxNode): InitCollection {
259
+ const collection: InitCollection = {
260
+ inits: [],
261
+ immediate: new Map(),
262
+ writes: [],
263
+ reassigned: new Set(),
264
+ }
265
+ visit(root, newScope(undefined, true), collection)
266
+ for (const { name, scope } of collection.writes) {
267
+ const binding = lookup(scope, name)
268
+ if (binding) collection.reassigned.add(binding)
269
+ }
270
+ return collection
271
+ }
272
+
273
+ // the argument an immediately invoked function passes to one parameter.
274
+ function immediateArgument(
275
+ fn: SyntaxNode,
276
+ index: number,
277
+ collection: InitCollection,
278
+ ): { argument: unknown; scope: Scope } | undefined {
279
+ const immediate = collection.immediate.get(fn)
280
+ const args: unknown = immediate && Reflect.get(immediate.call, 'arguments')
281
+ if (!immediate || !Array.isArray(args)) return undefined
282
+ // a spread before the parameter shifts every later argument position.
283
+ const preceding: unknown[] = args.slice(0, index + 1)
284
+ if (preceding.some((arg) => isNode(arg) && arg.type === 'SpreadElement'))
285
+ return undefined
286
+ return { argument: args[index], scope: immediate.scope }
287
+ }
288
+
289
+ // the value a literal holds under a static name. the last duplicate wins, as it
290
+ // does at run time. a spread makes the literal's keys unknown.
291
+ function propertyValue(object: SyntaxNode, name: string): SyntaxNode | undefined {
292
+ let value: SyntaxNode | undefined
293
+ for (const property of childNodes(Reflect.get(object, 'properties'))) {
294
+ if (property.type === 'SpreadElement') return undefined
295
+ if (!['Property', 'ObjectProperty'].includes(property.type)) continue
296
+ if (keyName(property, Reflect.get(property, 'key')) !== name) continue
297
+ const next: unknown = Reflect.get(property, 'value')
298
+ value = isNode(next) ? next : undefined
299
+ }
300
+ return value
301
+ }
302
+
303
+ interface ResolvedObject {
304
+ object: SyntaxNode
305
+ scope: Scope
306
+ }
307
+
308
+ // the object literal under one static key of a resolved owner.
309
+ function resolveProperty(
310
+ owner: ResolvedObject | undefined,
311
+ name: string,
312
+ collection: InitCollection,
313
+ depth: number,
314
+ ): ResolvedObject | undefined {
315
+ if (!owner) return undefined
316
+ const value = propertyValue(owner.object, name)
317
+ return value && resolveObject(value, owner.scope, collection, depth + 1)
318
+ }
319
+
320
+ // the object literal an expression yields, when it is statically known: a literal,
321
+ // a binding whose value is one, a parameter of an immediately invoked function
322
+ // bound to its argument (or to a key of it), or a static member of one of those.
323
+ function resolveObject(
324
+ expression: SyntaxNode,
325
+ scope: Scope,
326
+ collection: InitCollection,
327
+ depth: number,
328
+ ): ResolvedObject | undefined {
329
+ if (depth > MAX_RESOLUTION_DEPTH) return undefined
330
+ if (expression.type === 'ObjectExpression') return { object: expression, scope }
331
+ if (expression.type === 'Identifier') {
332
+ const name = identifierName(expression)
333
+ const binding = name === undefined ? undefined : lookup(scope, name)
334
+ if (!binding || collection.reassigned.has(binding)) return undefined
335
+ if (binding.kind === 'value')
336
+ return resolveObject(binding.init, binding.scope, collection, depth + 1)
337
+ if (binding.kind === 'param') {
338
+ const passed = immediateArgument(binding.fn, binding.index, collection)
339
+ if (!passed || !isNode(passed.argument)) return undefined
340
+ const argument = resolveObject(passed.argument, passed.scope, collection, depth + 1)
341
+ return binding.key === undefined
342
+ ? argument
343
+ : resolveProperty(argument, binding.key, collection, depth)
344
+ }
345
+ return undefined
346
+ }
347
+ if (expression.type === 'MemberExpression') {
348
+ const name = keyName(expression, Reflect.get(expression, 'property'))
349
+ const object: unknown = Reflect.get(expression, 'object')
350
+ if (name === undefined || !isNode(object)) return undefined
351
+ const owner = resolveObject(object, scope, collection, depth + 1)
352
+ return resolveProperty(owner, name, collection, depth)
353
+ }
354
+ return undefined
355
+ }
356
+
357
+ // collect upstream init records by their actual __initData assignments. each
358
+ // assigned expression resolves lexically to an inline literal, a variable or
359
+ // parameter, or a member of an immediately invoked function's argument, which is
360
+ // how minified bundles pass their init records. babel and acorn share these shapes.
361
+ export function workletExecutableBodies(
362
+ syntax: unknown,
363
+ includeCompiled = false,
364
+ ): Array<{
34
365
  initData: SyntaxNode
35
366
  codeProperty: SyntaxNode
36
367
  code: string
37
368
  }> {
38
369
  if (!isNode(syntax)) throw new Error('peach: expected worklet syntax')
39
- const tree = syntax
40
- const initNames = new Set<string>()
370
+ const collection = collectInitData(syntax)
41
371
  const objects = new Set<SyntaxNode>()
42
- walk(tree, (node) => {
43
- if (node.type !== 'AssignmentExpression') return
44
- const left = Reflect.get(node, 'left')
45
- if (
46
- !isNode(left) ||
47
- left.type !== 'MemberExpression' ||
48
- propertyName(Reflect.get(left, 'property')) !== '__initData'
49
- )
50
- return
51
- const right = Reflect.get(node, 'right')
52
- if (!isNode(right)) return
53
- if (right.type === 'ObjectExpression') objects.add(right)
54
- else if (right.type === 'Identifier') {
55
- const name = propertyName(right)
56
- if (name) initNames.add(name)
57
- }
58
- })
59
- walk(tree, (node) => {
60
- if (node.type !== 'VariableDeclarator') return
61
- const name = propertyName(Reflect.get(node, 'id'))
62
- const init = Reflect.get(node, 'init')
63
- if (name && initNames.has(name) && isNode(init) && init.type === 'ObjectExpression') {
64
- objects.add(init)
65
- }
66
- })
372
+ for (const { value, scope } of collection.inits) {
373
+ const resolved = resolveObject(value, scope, collection, 0)
374
+ if (resolved) objects.add(resolved.object)
375
+ }
67
376
  const bodies: Array<{ initData: SyntaxNode; codeProperty: SyntaxNode; code: string }> =
68
377
  []
69
378
  for (const object of objects) {
70
379
  const properties = Reflect.get(object, 'properties')
71
380
  if (!Array.isArray(properties)) continue
72
381
  if (
382
+ !includeCompiled &&
73
383
  properties.some(
74
384
  (property) =>
75
385
  isNode(property) &&
@@ -93,7 +93,7 @@ function isTypescriptFile(id: string): boolean {
93
93
  // normal dev rebuild changes a handful of files and replays the rest.
94
94
  export type WorkletBodyMode = 'executable' | 'transport'
95
95
 
96
- const CACHE_SCHEMA = 'v4'
96
+ const CACHE_SCHEMA = 'v5'
97
97
  const CACHE_ROOT = path.resolve(
98
98
  workspaceRoot,
99
99
  'node_modules',