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
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.939 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! peach v0.1.1399 | (c) 2026 Tamagui LLC | Proprietary; see LICENSE */
2
2
  let __sootsim_import_meta_url = '', __sootsim_import_meta_dirname = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; __sootsim_import_meta_dirname = __dirname; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -1252,6 +1252,7 @@ var require_attempt_events = __commonJS({
1252
1252
  var require_proof_frame = __commonJS({
1253
1253
  "detox/proof-frame.cjs"(exports2, module2) {
1254
1254
  "use strict";
1255
+ var { abs, max } = Math;
1255
1256
  var PROOF_CONTENT_DEFINITION = Object.freeze({
1256
1257
  channelThreshold: 24,
1257
1258
  contentBandInsetFraction: 0.08,
@@ -1296,10 +1297,10 @@ var require_proof_frame = __commonJS({
1296
1297
  for (let y = yStart; y < yEnd; y++) {
1297
1298
  for (let x = 0; x < width; x++) {
1298
1299
  const offset = (y * width + x) * 4;
1299
- if (Math.max(
1300
- Math.abs(data[offset] - dominant.red),
1301
- Math.abs(data[offset + 1] - dominant.green),
1302
- Math.abs(data[offset + 2] - dominant.blue)
1300
+ if (max(
1301
+ abs(data[offset] - dominant.red),
1302
+ abs(data[offset + 1] - dominant.green),
1303
+ abs(data[offset + 2] - dominant.blue)
1303
1304
  ) >= PROOF_CONTENT_DEFINITION.channelThreshold) {
1304
1305
  contentPixels++;
1305
1306
  }
@@ -1954,9 +1955,19 @@ function readBrowserCompositeCaptureRequest(value) {
1954
1955
 
1955
1956
  // ../peach-compat/src/stubs/native-seams/react-native-cookies.ts
1956
1957
  var cookieListeners = /* @__PURE__ */ new WeakMap();
1958
+ var cookiePolicies = /* @__PURE__ */ new WeakMap();
1959
+ var cookieBatches = /* @__PURE__ */ new WeakMap();
1960
+ function notifyCookieListeners(store) {
1961
+ const batch = cookieBatches.get(store);
1962
+ if (batch) {
1963
+ batch.changed = true;
1964
+ return;
1965
+ }
1966
+ for (const listener of cookieListeners.get(store) ?? []) listener();
1967
+ }
1957
1968
  var WebKitCookieJar = class extends Map {
1958
1969
  changed() {
1959
- for (const listener of cookieListeners.get(this) ?? []) listener();
1970
+ notifyCookieListeners(this);
1960
1971
  }
1961
1972
  set(key, value) {
1962
1973
  super.set(key, value);
@@ -1981,15 +1992,18 @@ var cookieStores = {
1981
1992
  function createCookieOperations() {
1982
1993
  const INVALID_URL_MISSING_HTTP = "Invalid URL: It may be missing a protocol (ex. http:// or https://).";
1983
1994
  const INVALID_COOKIE_VALUES = "Unable to add cookie - invalid values";
1995
+ function cookieError(kind, message) {
1996
+ return Object.assign(new Error(message), { kind });
1997
+ }
1984
1998
  function parseCookieUrl2(url) {
1985
1999
  try {
1986
2000
  const parsed = new URL(url);
1987
2001
  if (!parsed.hostname || parsed.protocol !== "http:" && parsed.protocol !== "https:") {
1988
- throw new Error(INVALID_URL_MISSING_HTTP);
2002
+ throw cookieError("invalid-url", INVALID_URL_MISSING_HTTP);
1989
2003
  }
1990
2004
  return parsed;
1991
2005
  } catch {
1992
- throw new Error(INVALID_URL_MISSING_HTTP);
2006
+ throw cookieError("invalid-url", INVALID_URL_MISSING_HTTP);
1993
2007
  }
1994
2008
  }
1995
2009
  function normalizedDomain2(domain) {
@@ -2036,12 +2050,13 @@ function createCookieOperations() {
2036
2050
  function setCookie2(store, url, cookie) {
2037
2051
  const parsed = parseCookieUrl2(url);
2038
2052
  if (!cookie || typeof cookie.name !== "string" || cookie.name.length === 0 || typeof cookie.value !== "string") {
2039
- throw new Error(INVALID_COOKIE_VALUES);
2053
+ throw cookieError("invalid-cookie", INVALID_COOKIE_VALUES);
2040
2054
  }
2041
2055
  const suppliedDomain = typeof cookie.domain === "string" && cookie.domain.length > 0 ? cookie.domain : null;
2042
2056
  const domain = suppliedDomain ?? parsed.hostname;
2043
2057
  if (!domainMatches2(parsed.hostname, domain, suppliedDomain === null)) {
2044
- throw new Error(
2058
+ throw cookieError(
2059
+ "domain-mismatch",
2045
2060
  `Cookie URL host ${parsed.hostname} and domain ${domain} mismatched. The cookie won't set correctly.`
2046
2061
  );
2047
2062
  }
@@ -2064,16 +2079,16 @@ function createCookieOperations() {
2064
2079
  storeCookie2(store, stored);
2065
2080
  return true;
2066
2081
  }
2067
- function getCookies2(store, url) {
2068
- const parsed = parseCookieUrl2(url);
2082
+ function cookiesMatching2(store, parsed) {
2069
2083
  purgeExpired2(store);
2084
+ return [...store.values()].filter(
2085
+ (cookie) => domainMatches2(parsed.hostname, cookie.domain, cookie.hostOnly) && pathMatches2(parsed.pathname || "/", cookie.path) && (!cookie.secure || parsed.protocol === "https:" || parsed.protocol === "wss:")
2086
+ );
2087
+ }
2088
+ function getCookies2(store, url) {
2070
2089
  const cookies = {};
2071
- for (const cookie of store.values()) {
2072
- if (!domainMatches2(parsed.hostname, cookie.domain, cookie.hostOnly)) continue;
2073
- if (!pathMatches2(parsed.pathname || "/", cookie.path)) continue;
2074
- if (cookie.secure && parsed.protocol !== "https:") continue;
2090
+ for (const cookie of cookiesMatching2(store, parseCookieUrl2(url)))
2075
2091
  cookies[cookie.name] = publicCookie2(cookie);
2076
- }
2077
2092
  return cookies;
2078
2093
  }
2079
2094
  function getAllCookies2(store) {
@@ -2084,12 +2099,12 @@ function createCookieOperations() {
2084
2099
  }
2085
2100
  function cookieFromResponse2(cookieString) {
2086
2101
  if (typeof cookieString !== "string" || cookieString.length === 0) {
2087
- throw new Error(INVALID_COOKIE_VALUES);
2102
+ throw cookieError("invalid-cookie", INVALID_COOKIE_VALUES);
2088
2103
  }
2089
2104
  const parts = cookieString.split(";");
2090
2105
  const nameValue = parts.shift()?.trim() ?? "";
2091
2106
  const separator = nameValue.indexOf("=");
2092
- if (separator <= 0) throw new Error(INVALID_COOKIE_VALUES);
2107
+ if (separator <= 0) throw cookieError("invalid-cookie", INVALID_COOKIE_VALUES);
2093
2108
  const cookie = {
2094
2109
  name: nameValue.slice(0, separator).trim(),
2095
2110
  value: nameValue.slice(separator + 1).trim()
@@ -2167,6 +2182,7 @@ function createCookieOperations() {
2167
2182
  }
2168
2183
  return {
2169
2184
  restore,
2185
+ cookiesMatching: cookiesMatching2,
2170
2186
  parseCookieUrl: parseCookieUrl2,
2171
2187
  normalizedDomain: normalizedDomain2,
2172
2188
  domainMatches: domainMatches2,
@@ -2184,6 +2200,7 @@ function createCookieOperations() {
2184
2200
  };
2185
2201
  }
2186
2202
  var {
2203
+ cookiesMatching,
2187
2204
  parseCookieUrl,
2188
2205
  normalizedDomain,
2189
2206
  domainMatches,
@@ -2199,7 +2216,10 @@ var {
2199
2216
  clearCookiesByName,
2200
2217
  removeSessionCookies
2201
2218
  } = createCookieOperations();
2202
- var webKitCookieOperationsSource = `(${createCookieOperations.toString()})()`;
2219
+ var webKitCookieOperationsSource = `(() => {
2220
+ function __name(fn, name) { Object.defineProperty(fn, 'name', { value: name, configurable: true }); return fn; }
2221
+ return (${createCookieOperations.toString()})();
2222
+ })()`;
2203
2223
  var webKitCookieStorage = {
2204
2224
  default: cookieStores.webKit,
2205
2225
  isolated: () => new WebKitCookieJar(),
@@ -2216,6 +2236,7 @@ var webKitCookieStorage = {
2216
2236
  return Object.values(getCookies(store, url)).filter((cookie) => !script || !cookie.httpOnly).map((cookie) => `${cookie.name}=${cookie.value}`).join("; ");
2217
2237
  },
2218
2238
  script(store, url, line) {
2239
+ if (cookiePolicies.get(store) === 1) return;
2219
2240
  const cookie = cookieFromResponse(line);
2220
2241
  cookie.httpOnly = false;
2221
2242
  const parsed = parseCookieUrl(url);
@@ -2227,6 +2248,31 @@ var webKitCookieStorage = {
2227
2248
  if (store.get(key)?.httpOnly) return;
2228
2249
  setCookie(store, url, cookie);
2229
2250
  },
2251
+ policy(store) {
2252
+ return cookiePolicies.get(store) ?? 0;
2253
+ },
2254
+ setPolicy(store, policy) {
2255
+ cookiePolicies.set(store, policy);
2256
+ },
2257
+ matching(store, url) {
2258
+ let parsed;
2259
+ try {
2260
+ parsed = new URL(url);
2261
+ } catch {
2262
+ return [];
2263
+ }
2264
+ return cookiesMatching(store, parsed);
2265
+ },
2266
+ setMany(store, cookies) {
2267
+ const batch = { changed: false };
2268
+ cookieBatches.set(store, batch);
2269
+ try {
2270
+ for (const cookie of cookies) webKitCookieStorage.set(store, cookie);
2271
+ } finally {
2272
+ cookieBatches.delete(store);
2273
+ if (batch.changed) notifyCookieListeners(store);
2274
+ }
2275
+ },
2230
2276
  all(store) {
2231
2277
  purgeExpired(store);
2232
2278
  return [...store.values()];
@@ -2247,6 +2293,7 @@ var webKitCookieStorage = {
2247
2293
  // ../peach-engine/src/webview-automation-host.ts
2248
2294
  var WEBVIEW_INSTANCE_ATTRIBUTE = "data-peach-webview";
2249
2295
  var WEBVIEW_HOST_BINDING = "__peachWebViewHost";
2296
+ var WEBVIEW_EXPO_DOM_PROMPT_CAPABILITY = "peach.webview.expoDomPrompt";
2250
2297
  var WEBVIEW_SCHEME_NAVIGATION_EVENT = "peach:webview-scheme-navigation";
2251
2298
  var WEBVIEW_LOAD_EVENT = "peach:webview-load";
2252
2299
  var WEBVIEW_NETWORK_NAVIGATION_EVENT = "peach:webview-network-navigation";
@@ -2273,7 +2320,9 @@ function readWebViewHostRequest(value) {
2273
2320
  if (kind === "detach") return { kind, instanceId };
2274
2321
  if (kind === "evaluate") {
2275
2322
  const js = text("js");
2276
- return js === null ? null : { kind, instanceId, js };
2323
+ const userAgent = field("userAgent");
2324
+ if (userAgent !== void 0 && typeof userAgent !== "string") return null;
2325
+ return js === null ? null : { kind, instanceId, js, ...typeof userAgent === "string" ? { userAgent } : {} };
2277
2326
  }
2278
2327
  if (kind === "tap") {
2279
2328
  const x = field("x");
@@ -2289,6 +2338,21 @@ function readWebViewHostRequest(value) {
2289
2338
  const afterContent = text("afterContent");
2290
2339
  const incognito = field("incognito");
2291
2340
  const rawHeaders = field("headers");
2341
+ const method = field("method");
2342
+ const bodyBase64 = field("bodyBase64");
2343
+ const data = field("documentData");
2344
+ let documentData;
2345
+ if (data !== void 0) {
2346
+ if (!data || typeof data !== "object" || !("bytesBase64" in data) || typeof data.bytesBase64 !== "string" || !("mimeType" in data) || typeof data.mimeType !== "string" || !("characterEncodingName" in data) || typeof data.characterEncodingName !== "string")
2347
+ return null;
2348
+ documentData = {
2349
+ bytesBase64: data.bytesBase64,
2350
+ mimeType: data.mimeType,
2351
+ characterEncodingName: data.characterEncodingName
2352
+ };
2353
+ }
2354
+ if (method !== void 0 && typeof method !== "string") return null;
2355
+ if (bodyBase64 !== void 0 && typeof bodyBase64 !== "string") return null;
2292
2356
  if (frameName === null || url === null || config === null || beforeKey === null || beforeContent === null || afterContent === null || typeof incognito !== "boolean" || !rawHeaders || typeof rawHeaders !== "object") {
2293
2357
  return null;
2294
2358
  }
@@ -2302,6 +2366,9 @@ function readWebViewHostRequest(value) {
2302
2366
  frameName,
2303
2367
  url,
2304
2368
  headers,
2369
+ ...typeof method === "string" ? { method } : {},
2370
+ ...typeof bodyBase64 === "string" ? { bodyBase64 } : {},
2371
+ ...documentData ? { documentData } : {},
2305
2372
  config,
2306
2373
  beforeKey,
2307
2374
  beforeContent,
@@ -2418,6 +2485,14 @@ function isSameDocumentRequest(requested, url) {
2418
2485
  return false;
2419
2486
  }
2420
2487
  }
2488
+ function redirectRequestHeaders(headers, from, to, discardBody = false) {
2489
+ const sameOrigin = new URL(from).origin === new URL(to).origin;
2490
+ return Object.fromEntries(
2491
+ Object.entries(headers).filter(
2492
+ ([name2]) => (sameOrigin || !/^(authorization|cookie)$/i.test(name2)) && (!discardBody || !/^content-(type|length)$/i.test(name2))
2493
+ )
2494
+ );
2495
+ }
2421
2496
  var webViewAutomationHelpers = {
2422
2497
  cookieOperations: createCookieOperations,
2423
2498
  readRequest: readWebViewHostRequest,
@@ -2427,7 +2502,8 @@ var webViewAutomationHelpers = {
2427
2502
  beforeContentScript: webViewBeforeContentScript,
2428
2503
  evaluationScripts: webViewEvaluationScripts,
2429
2504
  isAppScheme: isAppSchemeUrl,
2430
- isSameDocument: isSameDocumentRequest
2505
+ isSameDocument: isSameDocumentRequest,
2506
+ redirectRequestHeaders
2431
2507
  };
2432
2508
  function webViewAutomationNames(timingName, bootstrapSource) {
2433
2509
  return {
@@ -2459,6 +2535,96 @@ async function automateWebViewFrames(context, names, helpers) {
2459
2535
  }
2460
2536
  return session;
2461
2537
  };
2538
+ const expoPromptHeader = "__EXPO_DOM_WEBVIEW_JS_EVAL__";
2539
+ const evaluateExpoPrompt = (page, instanceId, webViewId, message) => {
2540
+ return new Promise((resolve2) => {
2541
+ const workers = page.workers();
2542
+ let pending = workers.length;
2543
+ if (pending === 0) resolve2(null);
2544
+ for (const worker of workers) {
2545
+ void worker.evaluate(
2546
+ ({ instanceId: instanceId2, webViewId: webViewId2, message: message2 }) => {
2547
+ const expo = Reflect.get(globalThis, "expo");
2548
+ if (!expo || typeof expo !== "object") return null;
2549
+ const modules = Reflect.get(expo, "modules");
2550
+ if (!modules || typeof modules !== "object") return null;
2551
+ const module2 = Reflect.get(modules, "ExpoDomWebViewModule");
2552
+ if (!module2 || typeof module2 !== "object") return null;
2553
+ const handler = Reflect.get(module2, "evalJsForWebViewPrompt");
2554
+ if (typeof handler !== "function") return null;
2555
+ const result = Reflect.apply(handler, module2, [
2556
+ instanceId2,
2557
+ webViewId2,
2558
+ message2
2559
+ ]);
2560
+ if (!result || typeof result !== "object") return null;
2561
+ if (Reflect.get(result, "handled") !== true) return null;
2562
+ const response = Reflect.get(result, "response");
2563
+ return typeof response === "string" ? response : null;
2564
+ },
2565
+ { instanceId, webViewId, message }
2566
+ ).then(
2567
+ (response) => {
2568
+ if (typeof response === "string") resolve2(response);
2569
+ },
2570
+ () => {
2571
+ }
2572
+ ).finally(() => {
2573
+ pending -= 1;
2574
+ if (pending === 0) resolve2(null);
2575
+ });
2576
+ }
2577
+ });
2578
+ };
2579
+ const observePageDialogs = (page) => {
2580
+ page.on("dialog", (dialog) => {
2581
+ const message = dialog.message();
2582
+ if (dialog.type() !== "prompt" || !message.startsWith(expoPromptHeader)) {
2583
+ void dialog.dismiss().catch(() => {
2584
+ });
2585
+ return;
2586
+ }
2587
+ let envelope;
2588
+ try {
2589
+ envelope = JSON.parse(message.slice(expoPromptHeader.length));
2590
+ } catch {
2591
+ void dialog.dismiss().catch(() => {
2592
+ });
2593
+ return;
2594
+ }
2595
+ if (!envelope || typeof envelope !== "object" && typeof envelope !== "function") {
2596
+ void dialog.dismiss().catch(() => {
2597
+ });
2598
+ return;
2599
+ }
2600
+ const instanceId = Reflect.get(envelope, "instanceId");
2601
+ const webViewId = Reflect.get(envelope, "webViewId");
2602
+ const params = Reflect.get(envelope, "params");
2603
+ if (typeof instanceId !== "string" || typeof webViewId !== "number" || !Number.isSafeInteger(webViewId) || webViewId < 0 || typeof params !== "string") {
2604
+ void dialog.dismiss().catch(() => {
2605
+ });
2606
+ return;
2607
+ }
2608
+ const bound = byInstance.get(instanceId);
2609
+ if (!bound || bound.page !== page) {
2610
+ void dialog.dismiss().catch(() => {
2611
+ });
2612
+ return;
2613
+ }
2614
+ const response = evaluateExpoPrompt(
2615
+ page,
2616
+ instanceId,
2617
+ webViewId,
2618
+ expoPromptHeader + params
2619
+ );
2620
+ void response.then(
2621
+ (response2) => response2 === null ? dialog.dismiss() : dialog.accept(response2)
2622
+ ).catch(() => dialog.dismiss()).catch(() => {
2623
+ });
2624
+ });
2625
+ };
2626
+ for (const page of context.pages()) observePageDialogs(page);
2627
+ context.on("page", observePageDialogs);
2462
2628
  const instanceOf = async (frame) => {
2463
2629
  const page = frame.page();
2464
2630
  if (frame.parentFrame() !== page.mainFrame()) return null;
@@ -2478,16 +2644,6 @@ async function automateWebViewFrames(context, names, helpers) {
2478
2644
  ).catch(() => {
2479
2645
  });
2480
2646
  };
2481
- context.on("request", (request) => {
2482
- if (request.serviceWorker()) return;
2483
- if (!request.isNavigationRequest() || request.redirectedFrom()) return;
2484
- if (!helpers.isAppScheme(request.url())) return;
2485
- const frame = request.frame();
2486
- void instanceOf(frame).then((instanceId) => {
2487
- if (instanceId !== null)
2488
- reportSchemeNavigation(frame.page(), instanceId, request.url());
2489
- });
2490
- });
2491
2647
  const storeFirstPartyCookies = async (lines, url) => {
2492
2648
  const now = Math.floor(Date.now() / 1e3);
2493
2649
  for (const line of lines) {
@@ -2504,24 +2660,6 @@ async function automateWebViewFrames(context, names, helpers) {
2504
2660
  }
2505
2661
  }
2506
2662
  };
2507
- context.on("response", (response) => {
2508
- const request = response.request();
2509
- if (request.serviceWorker()) return;
2510
- const frame = request.frame();
2511
- if (request.isNavigationRequest()) return;
2512
- if (frame.parentFrame() !== frame.page().mainFrame()) return;
2513
- void (async () => {
2514
- const lines = await response.headerValues("set-cookie");
2515
- if (lines.length === 0) return;
2516
- const instanceId = await instanceOf(frame);
2517
- const bound = instanceId === null ? void 0 : byInstance.get(instanceId);
2518
- if (!bound || bound.incognito) return;
2519
- const fetchSite = await request.headerValue("sec-fetch-site");
2520
- if (fetchSite !== "same-origin" && fetchSite !== "same-site") return;
2521
- await storeFirstPartyCookies(lines, response.url());
2522
- })().catch(() => {
2523
- });
2524
- });
2525
2663
  const reportDocumentLoad = async (frameId, url, result) => {
2526
2664
  const bound = byFrameId.get(frameId);
2527
2665
  if (!bound || bound.navigation) return;
@@ -2535,22 +2673,45 @@ async function automateWebViewFrames(context, names, helpers) {
2535
2673
  ]
2536
2674
  );
2537
2675
  };
2676
+ const schemeNavigations = /* @__PURE__ */ new Set();
2538
2677
  const watchDocumentNetwork = async (session) => {
2539
2678
  const documents = /* @__PURE__ */ new Map();
2679
+ const loads = /* @__PURE__ */ new Map();
2680
+ const fetchSites = /* @__PURE__ */ new Map();
2540
2681
  session.on(
2541
2682
  "Network.requestWillBeSent",
2542
2683
  (event) => {
2543
- if (event.type === "Document" && event.frameId)
2684
+ if (!event.frameId) return;
2685
+ if (event.type === "Document") {
2544
2686
  documents.set(event.requestId, {
2545
2687
  frameId: event.frameId,
2546
2688
  url: event.request.url
2547
2689
  });
2690
+ const bound = byFrameId.get(event.frameId);
2691
+ if (bound && !event.redirectResponse && helpers.isAppScheme(event.request.url) && !schemeNavigations.has(event.requestId)) {
2692
+ schemeNavigations.add(event.requestId);
2693
+ reportSchemeNavigation(bound.page, bound.instanceId, event.request.url);
2694
+ }
2695
+ } else if (byFrameId.has(event.frameId)) {
2696
+ loads.set(event.requestId, { frameId: event.frameId, url: event.request.url });
2697
+ }
2698
+ }
2699
+ );
2700
+ session.on(
2701
+ "Network.requestWillBeSentExtraInfo",
2702
+ (event) => {
2703
+ const site = Object.entries(event.headers).find(
2704
+ ([name2]) => name2.toLowerCase() === "sec-fetch-site"
2705
+ );
2706
+ if (site) fetchSites.set(event.requestId, site[1]);
2548
2707
  }
2549
2708
  );
2550
2709
  session.on(
2551
2710
  "Network.responseReceivedExtraInfo",
2552
2711
  (event) => {
2553
- const load = documents.get(event.requestId);
2712
+ const subresource = loads.get(event.requestId);
2713
+ const site = fetchSites.get(event.requestId);
2714
+ const load = subresource && (site === "same-origin" || site === "same-site") ? subresource : documents.get(event.requestId);
2554
2715
  if (!load) return;
2555
2716
  const bound = byFrameId.get(load.frameId);
2556
2717
  if (!bound || bound.incognito) return;
@@ -2581,12 +2742,16 @@ async function automateWebViewFrames(context, names, helpers) {
2581
2742
  );
2582
2743
  session.on("Network.loadingFinished", (event) => {
2583
2744
  documents.delete(event.requestId);
2745
+ loads.delete(event.requestId);
2746
+ fetchSites.delete(event.requestId);
2584
2747
  });
2585
2748
  session.on(
2586
2749
  "Network.loadingFailed",
2587
2750
  (event) => {
2588
2751
  const load = documents.get(event.requestId);
2589
2752
  documents.delete(event.requestId);
2753
+ loads.delete(event.requestId);
2754
+ fetchSites.delete(event.requestId);
2590
2755
  if (!load || event.canceled) return;
2591
2756
  const result = event.errorText === "net::ERR_CONNECTION_REFUSED" ? { kind: "refused" } : event.errorText === "net::ERR_UNSAFE_PORT" ? { kind: "restrictedPort" } : { kind: "ok" };
2592
2757
  void reportDocumentLoad(load.frameId, load.url, result).catch(() => {
@@ -2696,6 +2861,25 @@ async function automateWebViewFrames(context, names, helpers) {
2696
2861
  void fulfill(requestId, event, helpers.withFrameEmbedderHeaders(received2));
2697
2862
  return;
2698
2863
  }
2864
+ if (requestStage && event.resourceType === "Document" && bound.load?.documentData && helpers.isSameDocument(event.request.url, bound.load.url)) {
2865
+ const documentData = bound.load.documentData;
2866
+ bound.load = null;
2867
+ void settle("Fetch.fulfillRequest", {
2868
+ responseCode: 200,
2869
+ responseHeaders: helpers.withFrameEmbedderHeaders([
2870
+ {
2871
+ name: "Content-Type",
2872
+ value: documentData.mimeType + "; charset=" + documentData.characterEncodingName
2873
+ },
2874
+ {
2875
+ name: "Server-Timing",
2876
+ value: `${names.configTimingName};desc="${encodeURIComponent(bound.config)}"`
2877
+ }
2878
+ ]),
2879
+ body: documentData.bytesBase64
2880
+ });
2881
+ return;
2882
+ }
2699
2883
  if (requestStage && bound.navigation) {
2700
2884
  const operations = cookieOperations;
2701
2885
  const config = JSON.parse(bound.config);
@@ -2703,9 +2887,51 @@ async function automateWebViewFrames(context, names, helpers) {
2703
2887
  const store = operations.restore(cookies);
2704
2888
  const cookie = Object.values(operations.getCookies(store, event.request.url)).map((entry) => `${entry.name}=${entry.value}`).join("; ");
2705
2889
  const headers = Object.entries(event.request.headers).filter(([name2]) => name2.toLowerCase() !== "cookie").map(([name2, value]) => ({ name: name2, value: String(value) }));
2890
+ if (typeof config.webKit.userAgent === "string") {
2891
+ for (let index = headers.length - 1; index >= 0; index--)
2892
+ if (headers[index].name.toLowerCase() === "user-agent") headers.splice(index, 1);
2893
+ headers.push({ name: "User-Agent", value: config.webKit.userAgent });
2894
+ }
2706
2895
  if (cookie) headers.push({ name: "Cookie", value: cookie });
2896
+ const load = event.resourceType === "Document" ? bound.load : null;
2897
+ if (load && load.method === "GET" && load.bodyBase64 !== void 0) {
2898
+ bound.load = null;
2899
+ const navigation = bound.navigation.id;
2900
+ void (async () => {
2901
+ await bound.page.evaluate(
2902
+ ([eventName, detail]) => window.dispatchEvent(new CustomEvent(eventName, { detail })),
2903
+ [
2904
+ names.networkNavigationEvent,
2905
+ {
2906
+ instanceId: bound.instanceId,
2907
+ navigation,
2908
+ phase: "failure",
2909
+ url: event.request.url,
2910
+ domain: "NSURLErrorDomain",
2911
+ code: -1103,
2912
+ description: "resource exceeds maximum size"
2913
+ }
2914
+ ]
2915
+ );
2916
+ await settle("Fetch.failRequest", { errorReason: "Aborted" });
2917
+ })();
2918
+ return;
2919
+ }
2920
+ if (load) {
2921
+ for (const [name2, value] of Object.entries(load.headers)) {
2922
+ if (name2.toLowerCase() === "user-agent") continue;
2923
+ for (let index = headers.length - 1; index >= 0; index--)
2924
+ if (headers[index].name.toLowerCase() === name2.toLowerCase())
2925
+ headers.splice(index, 1);
2926
+ headers.push({ name: name2, value });
2927
+ }
2928
+ }
2707
2929
  void settle("Fetch.continueRequest", {
2708
2930
  headers,
2931
+ ...load ? {
2932
+ method: load.method,
2933
+ ...load.bodyBase64 !== void 0 ? { postData: load.bodyBase64 } : {}
2934
+ } : {},
2709
2935
  interceptResponse: event.resourceType === "Document"
2710
2936
  });
2711
2937
  return;
@@ -2751,11 +2977,28 @@ async function automateWebViewFrames(context, names, helpers) {
2751
2977
  }
2752
2978
  if (bound.navigation && location) {
2753
2979
  const target = new URL(location.value, event.request.url).href;
2980
+ if (bound.load) {
2981
+ const discardBody = (status === 301 || status === 302) && bound.load.method === "POST" || status === 303 && bound.load.method !== "HEAD";
2982
+ bound.load = {
2983
+ method: discardBody ? "GET" : bound.load.method,
2984
+ bodyBase64: discardBody ? void 0 : bound.load.bodyBase64,
2985
+ url: target,
2986
+ headers: helpers.redirectRequestHeaders(
2987
+ bound.load.headers,
2988
+ event.request.url,
2989
+ target,
2990
+ discardBody
2991
+ )
2992
+ };
2993
+ }
2754
2994
  void decideNavigation(bound, {
2755
2995
  phase: "redirect",
2756
2996
  url: target,
2757
2997
  status,
2758
- mime: ""
2998
+ mime: "",
2999
+ headers: bound.load?.headers ?? {},
3000
+ method: bound.load?.method ?? event.request.method,
3001
+ bodyBase64: bound.load?.bodyBase64
2759
3002
  }).then(
2760
3003
  (allow) => allow ? continueRedirect() : settle("Fetch.failRequest", { errorReason: "Aborted" })
2761
3004
  );
@@ -2777,6 +3020,7 @@ async function automateWebViewFrames(context, names, helpers) {
2777
3020
  }
2778
3021
  }
2779
3022
  if (bound.navigation) {
3023
+ bound.load = null;
2780
3024
  const config = JSON.parse(bound.config);
2781
3025
  config.documentUrl = event.request.url;
2782
3026
  bound.config = JSON.stringify(config);
@@ -2797,32 +3041,11 @@ async function automateWebViewFrames(context, names, helpers) {
2797
3041
  if (await instanceOf(candidate) === bound.instanceId) frame = candidate;
2798
3042
  }
2799
3043
  if (!frame) return;
2800
- let session = null;
2801
- let contextId;
2802
- try {
2803
- session = await context.newCDPSession(frame);
2804
- } catch {
2805
- session = await pageSession(bound.page);
2806
- const contexts = [];
2807
- const collect = (event) => {
2808
- contexts.push(event.context);
2809
- };
2810
- session.on("Runtime.executionContextCreated", collect);
2811
- await session.send("Runtime.enable");
2812
- await session.send("Runtime.disable");
2813
- session.off("Runtime.executionContextCreated", collect);
2814
- contextId = contexts.find(
2815
- (entry) => entry.auxData?.frameId === bound.frameId && entry.auxData.isDefault
2816
- )?.id;
2817
- if (contextId === void 0) return;
2818
- }
2819
- try {
2820
- for (const expression of scripts) {
2821
- await session.send("Runtime.evaluate", { expression, contextId });
2822
- }
2823
- } finally {
2824
- if (contextId === void 0) await session.detach().catch(() => {
2825
- });
3044
+ for (const expression of scripts) {
3045
+ await frame.evaluate((source) => {
3046
+ ;
3047
+ (0, eval)(source);
3048
+ }, expression);
2826
3049
  }
2827
3050
  };
2828
3051
  await context.exposeBinding(names.hostBinding, async (source, value) => {
@@ -2874,6 +3097,12 @@ async function automateWebViewFrames(context, names, helpers) {
2874
3097
  if (request.kind === "evaluate") {
2875
3098
  const bound2 = byInstance.get(request.instanceId);
2876
3099
  if (!bound2) return;
3100
+ if (request.userAgent !== void 0) {
3101
+ const config2 = JSON.parse(bound2.config);
3102
+ config2.webKit.userAgent = request.userAgent;
3103
+ bound2.config = JSON.stringify(config2);
3104
+ if (request.js === "") return;
3105
+ }
2877
3106
  const scripts = helpers.evaluationScripts(request.js);
2878
3107
  bound2.evaluations = bound2.evaluations.then(() => evaluateIn(bound2, scripts)).catch(() => {
2879
3108
  });
@@ -2910,7 +3139,13 @@ async function automateWebViewFrames(context, names, helpers) {
2910
3139
  incognito: request.incognito,
2911
3140
  navigation: config.webKit ? { id: config.webKit.navigation, type: config.webKit.navigationType } : null,
2912
3141
  decisions: /* @__PURE__ */ new Map(),
2913
- load: { url: request.url, headers: request.headers },
3142
+ load: {
3143
+ url: request.url,
3144
+ headers: request.headers,
3145
+ method: request.method ?? "GET",
3146
+ bodyBase64: request.bodyBase64,
3147
+ documentData: request.documentData
3148
+ },
2914
3149
  evaluations: Promise.resolve(),
2915
3150
  frameSession: null
2916
3151
  };
@@ -3063,6 +3298,14 @@ var WEBVIEW_FRAME_BRIDGE_SOURCE = `function (config) {
3063
3298
  // originWhitelist and Linking handling) has to speak that url, so map the
3064
3299
  // frame's own search and hash onto it.
3065
3300
  var documentUrl = config.documentUrl;
3301
+ // document.write parses decoded Unicode; native retains the source byte metadata.
3302
+ if (config.dataDocumentMetadata) {
3303
+ var dataMetadata = config.dataDocumentMetadata;
3304
+ ['characterSet', 'charset', 'inputEncoding'].forEach(function(name) {
3305
+ Object.defineProperty(document, name, { configurable: true, get: function() { return dataMetadata.encoding; } });
3306
+ });
3307
+ Object.defineProperty(document, 'contentType', { configurable: true, get: function() { return dataMetadata.mimeType; } });
3308
+ }
3066
3309
  ${WEBVIEW_FRAME_COLOR_SCHEME_SOURCE} var webKit = config.webKit || null;
3067
3310
  function nativeValue(value, seen) {
3068
3311
  if (value === null) return { type: 'null' };
@@ -3091,6 +3334,8 @@ ${WEBVIEW_FRAME_COLOR_SCHEME_SOURCE} var webKit = config.webKit || null;
3091
3334
  var scriptReplies = new Map();
3092
3335
  var nextScriptReply = 0;
3093
3336
  function setMessageHandlers(names) {
3337
+ if (names.length === 0) { delete window.webkit; return; }
3338
+ if (!window.webkit) window.webkit = { messageHandlers: Object.create(null) };
3094
3339
  Object.keys(window.webkit.messageHandlers).forEach(function(name) { if (names.indexOf(name) === -1) delete window.webkit.messageHandlers[name]; });
3095
3340
  names.forEach(function(name) {
3096
3341
  if (Object.hasOwn(window.webkit.messageHandlers, name)) return;
@@ -3115,11 +3360,13 @@ ${WEBVIEW_FRAME_COLOR_SCHEME_SOURCE} var webKit = config.webKit || null;
3115
3360
  fontHeadObserver.observe(document, { childList: true, subtree: true });
3116
3361
  if (document.head) { document.head.prepend(defaultStyle); fontHeadObserver.disconnect(); }
3117
3362
  }
3363
+ var nativeUserAgent = webKit && webKit.userAgent;
3364
+ if (typeof nativeUserAgent === 'string') {
3365
+ Object.defineProperty(navigator, 'userAgent', { configurable: true, get: function() { return nativeUserAgent; } });
3366
+ }
3118
3367
  if (webKit) {
3119
3368
  Object.defineProperty(window, 'devicePixelRatio', { configurable: true, get: function() { return config.deviceScale; } });
3120
3369
  window.parent.postMessage({ __sootsimWebViewKind: 'webKitCommit', url: config.documentUrl }, '*');
3121
- window.webkit = window.webkit || {};
3122
- window.webkit.messageHandlers = Object.create(null);
3123
3370
  setMessageHandlers(webKit.messageHandlers);
3124
3371
  }
3125
3372
  var userScripts = (webKit ? webKit.userScripts : []).slice();
@@ -3154,6 +3401,12 @@ ${WEBVIEW_FRAME_COLOR_SCHEME_SOURCE} var webKit = config.webKit || null;
3154
3401
  return injectedObjectJson;
3155
3402
  };
3156
3403
  }
3404
+ if (
3405
+ typeof config.expoDomWebViewGlobalsSource === 'string' &&
3406
+ window[Symbol.for(${JSON.stringify(WEBVIEW_EXPO_DOM_PROMPT_CAPABILITY)})] === true
3407
+ ) {
3408
+ (0, eval)(config.expoDomWebViewGlobalsSource);
3409
+ }
3157
3410
  // the page is top-level in a WKWebView, so a cookie it sets from script is
3158
3411
  // first-party there; under the sim page it is cross-site, where only
3159
3412
  // SameSite=None sticks. a secure context can state that; an insecure one
@@ -3166,7 +3419,8 @@ ${WEBVIEW_FRAME_COLOR_SCHEME_SOURCE} var webKit = config.webKit || null;
3166
3419
  if (webKit) {
3167
3420
  var cookieOperations = ${webKitCookieOperationsSource};
3168
3421
  var pageCookies = cookieOperations.restore(JSON.parse(webKit.cookies || '[]'));
3169
- window.__peachUpdateWebKitCookies = function(cookies) {
3422
+ window.__peachUpdateWebKitCookies = function(cookies, policy) {
3423
+ webKit.cookiePolicy = policy;
3170
3424
  pageCookies = cookieOperations.restore(cookies);
3171
3425
  window.parent.postMessage({ __sootsimWebViewKind: 'webKitCookieSnapshot', cookies: JSON.stringify(cookies) }, '*');
3172
3426
  };
@@ -3176,6 +3430,7 @@ ${WEBVIEW_FRAME_COLOR_SCHEME_SOURCE} var webKit = config.webKit || null;
3176
3430
  return Object.values(cookieOperations.getCookies(pageCookies, documentUrl)).filter(function(cookie) { return !cookie.httpOnly; }).map(function(cookie) { return cookie.name + '=' + cookie.value; }).join('; ');
3177
3431
  },
3178
3432
  set: function(value) {
3433
+ if (webKit.cookiePolicy === 1) return;
3179
3434
  var line = String(value);
3180
3435
  var cookie = cookieOperations.cookieFromResponse(line);
3181
3436
  cookie.httpOnly = false;
@@ -3515,11 +3770,32 @@ ${WEBVIEW_FRAME_COLOR_SCHEME_SOURCE} var webKit = config.webKit || null;
3515
3770
  }, '*');
3516
3771
  });
3517
3772
  var lastEditable = null;
3518
- function editorIsEmpty(editor) {
3519
- return 'value' in editor
3520
- ? String(editor.value || '').length === 0
3521
- : String(editor.textContent || '').length === 0;
3522
- }
3773
+ function editorState(editor) {
3774
+ if ('value' in editor) return {
3775
+ text: String(editor.value), selectionStart: editor.selectionStart === null ? 0 : editor.selectionStart,
3776
+ selectionEnd: editor.selectionEnd === null ? 0 : editor.selectionEnd
3777
+ };
3778
+ var selection = window.getSelection();
3779
+ var whole = document.createRange();
3780
+ whole.selectNodeContents(editor);
3781
+ var prefix = whole.cloneRange();
3782
+ var start = 0, end = 0;
3783
+ if (selection && selection.rangeCount && editor.contains(selection.anchorNode) && editor.contains(selection.focusNode)) {
3784
+ var range = selection.getRangeAt(0);
3785
+ prefix.setEnd(range.startContainer, range.startOffset);
3786
+ start = prefix.toString().length;
3787
+ prefix.setEnd(range.endContainer, range.endOffset);
3788
+ end = prefix.toString().length;
3789
+ }
3790
+ return { text: whole.toString(), selectionStart: start, selectionEnd: end };
3791
+ }
3792
+ function postEditorState(edited) {
3793
+ if (!lastEditable || lastEditable !== document.activeElement) return;
3794
+ window.parent.postMessage(Object.assign({
3795
+ __sootsimWebViewKind: 'webViewEditorState', edited: edited === true
3796
+ }, editorState(lastEditable)), '*');
3797
+ }
3798
+ document.addEventListener('selectionchange', function () { postEditorState(false); }, true);
3523
3799
  document.addEventListener('focusin', function (event) {
3524
3800
  var element = event.target;
3525
3801
  if (!element || !element.closest) return;
@@ -3542,7 +3818,7 @@ ${WEBVIEW_FRAME_COLOR_SCHEME_SOURCE} var webKit = config.webKit || null;
3542
3818
  try {
3543
3819
  hasActivation = !!(navigator.userActivation && navigator.userActivation.isActive);
3544
3820
  } catch (_) {}
3545
- window.parent.postMessage({
3821
+ window.parent.postMessage(Object.assign({
3546
3822
  __sootsimWebViewKind: 'webViewEditorFocus',
3547
3823
  inputType: editor.type || '',
3548
3824
  inputMode: editor.inputMode || '',
@@ -3550,9 +3826,8 @@ ${WEBVIEW_FRAME_COLOR_SCHEME_SOURCE} var webKit = config.webKit || null;
3550
3826
  autoCapitalize: editor.autocapitalize || editor.getAttribute('autocapitalize') || '',
3551
3827
  autoCorrect: editor.autocorrect || editor.getAttribute('autocorrect') || '',
3552
3828
  spellCheck: editor.spellcheck,
3553
- empty: editorIsEmpty(editor),
3554
3829
  userGesture: hasActivation && !evaluatingInjectedScript
3555
- }, '*');
3830
+ }, editorState(editor)), '*');
3556
3831
  }, true);
3557
3832
  document.addEventListener('focusout', function (event) {
3558
3833
  var element = event.target;
@@ -3583,10 +3858,7 @@ ${WEBVIEW_FRAME_COLOR_SCHEME_SOURCE} var webKit = config.webKit || null;
3583
3858
  // execCommand from an injected script. the native oracle raises the
3584
3859
  // keyboard on an insert into a focused field even when the focus
3585
3860
  // itself was programmatic, so the host needs this to match.
3586
- window.parent.postMessage({
3587
- __sootsimWebViewKind: 'webViewEditorState',
3588
- empty: editorIsEmpty(editor)
3589
- }, '*');
3861
+ postEditorState(true);
3590
3862
  }, true);
3591
3863
  window.addEventListener('message', function (event) {
3592
3864
  // only the shell host drives this frame. the host already checks that an
@@ -3624,6 +3896,34 @@ ${WEBVIEW_FRAME_COLOR_SCHEME_SOURCE} var webKit = config.webKit || null;
3624
3896
  lastEditable = null;
3625
3897
  return;
3626
3898
  }
3899
+ if (payload.__sootsimWebViewKind === 'keyboardAcceptCandidate') {
3900
+ event.stopImmediatePropagation();
3901
+ if (!lastEditable || !lastEditable.isConnected) return;
3902
+ var state = editorState(lastEditable);
3903
+ var candidate = payload.candidate;
3904
+ if (!candidate || state.selectionStart !== state.selectionEnd ||
3905
+ state.selectionEnd !== candidate.end || candidate.end !== state.text.length ||
3906
+ state.text.slice(candidate.start, candidate.end) !== candidate.text) return;
3907
+ if ('value' in lastEditable) lastEditable.setSelectionRange(candidate.start, candidate.end);
3908
+ else {
3909
+ var walker = document.createTreeWalker(lastEditable, NodeFilter.SHOW_TEXT);
3910
+ var textNode, offset = 0, range = document.createRange();
3911
+ range.selectNodeContents(lastEditable);
3912
+ while ((textNode = walker.nextNode())) {
3913
+ if (offset + textNode.length >= candidate.start) {
3914
+ range.setStart(textNode, candidate.start - offset);
3915
+ break;
3916
+ }
3917
+ offset += textNode.length;
3918
+ }
3919
+ var selection = window.getSelection();
3920
+ selection.removeAllRanges();
3921
+ selection.addRange(range);
3922
+ }
3923
+ document.execCommand('insertText', false, candidate.text + ' ');
3924
+ postEditorState();
3925
+ return;
3926
+ }
3627
3927
  if (payload.__sootsimWebViewKind === 'keyboardKeyPress') {
3628
3928
  event.stopImmediatePropagation();
3629
3929
  if (!lastEditable || !lastEditable.isConnected) return;
@@ -3735,25 +4035,43 @@ ${WEBVIEW_FRAME_COLOR_SCHEME_SOURCE} var webKit = config.webKit || null;
3735
4035
  }
3736
4036
  if (payload.__sootsimWebViewKind === 'evaluateJavaScript') {
3737
4037
  event.stopImmediatePropagation();
3738
- var result;
3739
- window[Symbol.for('peach.webkitException')] = {};
3740
- try {
3741
- var value = (0, eval)(String(payload.js || ''));
4038
+ if (typeof payload.userAgent === 'string') nativeUserAgent = payload.userAgent;
4039
+ var evaluationMetadata = {};
4040
+ window[Symbol.for('peach.webkitException')] = evaluationMetadata;
4041
+ function sendEvaluation(result) {
4042
+ result.title = String(document.title || '');
4043
+ window.parent.postMessage({ __sootsimWebViewKind: 'webKitEvaluation', requestId: payload.requestId, result: result }, '*');
4044
+ }
4045
+ function evaluationSuccess(value) {
4046
+ var result;
3742
4047
  try { result = value === undefined ? { undefined: true } : { value: nativeValue(value, []) }; }
3743
4048
  catch (_) { result = { errorCode: 5, errorInfo: { NSLocalizedDescription: 'JavaScript execution returned a result of an unsupported type' } }; }
3744
- } catch (error) {
3745
- var metadata = window[Symbol.for('peach.webkitException')] || {};
4049
+ sendEvaluation(result);
4050
+ }
4051
+ function evaluationFailure(error) {
4052
+ var metadata = evaluationMetadata.asyncFunction ? evaluationMetadata : window[Symbol.for('peach.webkitException')] || {};
3746
4053
  var exceptionLocation = metadata.value === error && metadata.thrown ? metadata.thrown : error instanceof SyntaxError ? metadata.thrown : error instanceof ReferenceError ? metadata.read : metadata.call;
3747
4054
  var message = String(error);
3748
4055
  if (error instanceof ReferenceError && metadata.read) message = "ReferenceError: Can't find variable: " + metadata.read.name;
3749
4056
  if (error instanceof TypeError && metadata.call && metadata.call.property && metadata.receiver != null && !Reflect.has(Object(metadata.receiver), metadata.call.property)) {
3750
4057
  message = "TypeError: " + metadata.call.callee + " is not a function. (In '" + metadata.call.source + "', '" + metadata.call.callee + "' is undefined)";
3751
4058
  }
3752
- result = { errorCode: 4, errorInfo: { NSLocalizedDescription: 'A JavaScript exception occurred', WKJavaScriptExceptionMessage: message, WKJavaScriptExceptionSourceURL: String(document.baseURI) } };
3753
- if (exceptionLocation) { result.errorInfo.WKJavaScriptExceptionLineNumber = exceptionLocation.line; result.errorInfo.WKJavaScriptExceptionColumnNumber = exceptionLocation.column; }
4059
+ var result = { errorCode: 4, errorInfo: { NSLocalizedDescription: 'A JavaScript exception occurred', WKJavaScriptExceptionMessage: message } };
4060
+ if (metadata.asyncFunction) {
4061
+ result.errorInfo.WKJavaScriptExceptionLineNumber = 0;
4062
+ result.errorInfo.WKJavaScriptExceptionColumnNumber = 0;
4063
+ } else {
4064
+ result.errorInfo.WKJavaScriptExceptionSourceURL = String(document.baseURI);
4065
+ if (exceptionLocation) { result.errorInfo.WKJavaScriptExceptionLineNumber = exceptionLocation.line; result.errorInfo.WKJavaScriptExceptionColumnNumber = exceptionLocation.column; }
4066
+ }
4067
+ sendEvaluation(result);
3754
4068
  }
3755
- result.title = String(document.title || '');
3756
- window.parent.postMessage({ __sootsimWebViewKind: 'webKitEvaluation', requestId: payload.requestId, result: result }, '*');
4069
+ try {
4070
+ var value = (0, eval)(String(payload.js || ''));
4071
+ if (evaluationMetadata.asyncFunction && value instanceof Promise) {
4072
+ Promise.resolve(value).then(evaluationSuccess, evaluationFailure);
4073
+ } else evaluationSuccess(value);
4074
+ } catch (error) { evaluationFailure(error); }
3757
4075
  return;
3758
4076
  }
3759
4077
  if (payload.__sootsimWebViewKind !== 'injectJavaScript') return;
@@ -3781,6 +4099,8 @@ var WEBVIEW_SAME_ORIGIN_BOOTSTRAP_SOURCE = `(function () {
3781
4099
  if (config.beforeContent) (0, eval)(config.beforeContent);
3782
4100
  })();`;
3783
4101
  var WEBVIEW_HOST_BOOTSTRAP_SOURCE = `function (timingName) {
4102
+ window[Symbol.for(${JSON.stringify(WEBVIEW_EXPO_DOM_PROMPT_CAPABILITY)})] = true;
4103
+ var host = window[${JSON.stringify(WEBVIEW_HOST_BINDING)}];
3784
4104
  if (window === window.top || window.parent !== window.top) return;
3785
4105
  var entry = performance.getEntriesByType('navigation')[0];
3786
4106
  var timings = (entry && entry.serverTiming) || [];
@@ -3791,7 +4111,6 @@ var WEBVIEW_HOST_BOOTSTRAP_SOURCE = `function (timingName) {
3791
4111
  // the host runs injectedJavaScript once the document is parsed, after the
3792
4112
  // page's own DOMContentLoaded listeners, as WebKit runs a document-end
3793
4113
  // WKUserScript after it dispatches DOMContentLoaded.
3794
- var host = window[${JSON.stringify(WEBVIEW_HOST_BINDING)}];
3795
4114
  var hook = window[Symbol.for(${JSON.stringify(WEBVIEW_FRAME_HOOK)})];
3796
4115
  window.addEventListener('DOMContentLoaded', function () {
3797
4116
  hook.documentEnd = host({ kind: 'documentEnd' });
@@ -3800,6 +4119,9 @@ var WEBVIEW_HOST_BOOTSTRAP_SOURCE = `function (timingName) {
3800
4119
  }
3801
4120
  }`;
3802
4121
 
4122
+ // ../peach-engine/src/render-worker/app-load.ts
4123
+ var import_config = require("peachsim/config");
4124
+
3803
4125
  // ../peach-engine/src/remote-stream/remoteEngineParam.ts
3804
4126
  function readRemoteEngineParam(search, hash) {
3805
4127
  const fromQuery = new URLSearchParams(search).get("remoteEngine");
@@ -3818,11 +4140,13 @@ function getVisibleHarnessAppForUrl(initUrl) {
3818
4140
  const parsed = new URL(initUrl);
3819
4141
  const testName = parsed.searchParams.get("test");
3820
4142
  if (testName) {
4143
+ const iconImage = parsed.searchParams.get("fixtureIcon");
3821
4144
  return {
3822
4145
  id: TEST_FIXTURE_SHELL_APP_ID,
3823
4146
  name: testName,
3824
4147
  color: "#0f172a",
3825
4148
  icon: "T",
4149
+ ...iconImage ? { iconImage } : {},
3826
4150
  hidden: true
3827
4151
  };
3828
4152
  }
@@ -3911,7 +4235,6 @@ var import_metro_production_bundle = require("peachsim/metro-production-bundle")
3911
4235
  var import_react_native_host_modules = require("peachsim/react-native-host-modules");
3912
4236
 
3913
4237
  // src/cloud-contract.ts
3914
- var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
3915
4238
  var RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES = 1024 * 1024;
3916
4239
  var RNX_CLOUD_COMMAND_SCOPES = {
3917
4240
  state: "read",
@@ -6496,7 +6819,8 @@ function writeSecureJsonAtomic(filepath, value) {
6496
6819
 
6497
6820
  // cli/current-sim.ts
6498
6821
  var CURRENT_SIM_VERSION = 2;
6499
- var CURRENT_SIM_PATH_ENV = "SOOTSIM_CLI_CURRENT_SIM_PATH";
6822
+ var CURRENT_SIM_PATH_ENV = "PEACH_CLI_CURRENT_SIM_PATH";
6823
+ var LEGACY_CURRENT_SIM_PATH_ENV = "SOOTSIM_CLI_CURRENT_SIM_PATH";
6500
6824
  var IDENTITY_ENV_VARS = [
6501
6825
  "PEACH_CLI_IDENTITY",
6502
6826
  // explicit override — fastest path, skips all pid lookups
@@ -6575,8 +6899,9 @@ function getOwnerProcessGroupId() {
6575
6899
  return pgid !== null && pgid > 1 ? pgid : null;
6576
6900
  }
6577
6901
  function getCurrentSimPath() {
6578
- if (process.env[CURRENT_SIM_PATH_ENV]) {
6579
- return (0, import_path.resolve)(process.env[CURRENT_SIM_PATH_ENV]);
6902
+ const envPath = process.env[CURRENT_SIM_PATH_ENV] || process.env[LEGACY_CURRENT_SIM_PATH_ENV];
6903
+ if (envPath) {
6904
+ return (0, import_path.resolve)(envPath);
6580
6905
  }
6581
6906
  const key = getCliIdentityKey();
6582
6907
  return (0, import_path.join)((0, import_os.tmpdir)(), `peach-current-sim-${key}.json`);
@@ -6744,7 +7069,8 @@ function createBridge(wsPort, opts = {}) {
6744
7069
  }
6745
7070
  function maybeNoticeTarget(cmdType, simId) {
6746
7071
  if (noticedTarget) return;
6747
- if (process.env.SOOTSIM_QUIET_TARGET_NOTICE === "1") return;
7072
+ if (process.env.PEACH_QUIET_TARGET_NOTICE === "1" || process.env.SOOTSIM_QUIET_TARGET_NOTICE === "1")
7073
+ return;
6748
7074
  if (cmdType.startsWith("bridge:") || cmdType === "focus" || cmdType === "close")
6749
7075
  return;
6750
7076
  noticedTarget = true;
@@ -7225,7 +7551,7 @@ async function dragScrollNode(page, node, pixels, direction, startPositionX, sta
7225
7551
  let recognitionSootSimY = startSootSimY;
7226
7552
  let endSootSimX = startSootSimX;
7227
7553
  let endSootSimY = startSootSimY;
7228
- const slop = 2 * scrollTouchSlop(DETOX_PLATFORM, 1);
7554
+ const slop = scrollTouchSlop(DETOX_PLATFORM, 1);
7229
7555
  const travel = pixels + slop;
7230
7556
  switch (direction) {
7231
7557
  case "down":
@@ -7847,7 +8173,14 @@ function recordPageDiagnostic(page, diagnostic, persist = false) {
7847
8173
  if (persist) (0, import_attempt_events.writeAttemptEvent)(diagnostic);
7848
8174
  }
7849
8175
  function isTopLevelDocumentRequest(page, request) {
7850
- return request.isNavigationRequest() && request.resourceType() === "document" && request.frame() === page.mainFrame();
8176
+ if (!request.isNavigationRequest() || request.resourceType() !== "document") {
8177
+ return false;
8178
+ }
8179
+ try {
8180
+ return request.frame() === page.mainFrame();
8181
+ } catch {
8182
+ return false;
8183
+ }
7851
8184
  }
7852
8185
  function recordNavigationMilestoneFor(page, active, milestone, details = {}) {
7853
8186
  recordPageDiagnostic(
@@ -8013,7 +8346,7 @@ function getSootsimNavigationDiagnostics(page) {
8013
8346
  // detox/index.ts
8014
8347
  var import_proof_frame = __toESM(require_proof_frame(), 1);
8015
8348
  var BASE_URL = process.env.PEACH_URL || "http://localhost:5173";
8016
- var SCREENSHOT_DIR = process.env.PEACH_SCREENSHOT_DIR || path.join(process.cwd(), "test", "detox-driver", "screenshots");
8349
+ var SCREENSHOT_DIR = process.env.PEACH_SCREENSHOT_DIR || path.join(process.cwd(), "test", "detox-driver", "screenshots", String(process.pid));
8017
8350
  var _browser = null;
8018
8351
  var _reapBrowserNow = null;
8019
8352
  var _context = null;
@@ -8378,7 +8711,9 @@ async function waitForSootsimIdle(page, maxMs = 3e3, strict = false, transitionS
8378
8711
  } catch {
8379
8712
  }
8380
8713
  }
8714
+ let webViewStarting = false;
8381
8715
  if (root) {
8716
+ const PREVIEW_PROGRESS_REGEX = /^(creating webview|loading html|fetching bundle|waiting for first render|starting preview|loading simulator|fetching app code|waiting for native preview|starting design|loading canvas|fetching screens|painting the canvas|waiting for webview|waiting for preview|waiting for canvas|preview stalled)/i;
8382
8717
  const walk = (node) => {
8383
8718
  if (node.layout && node.layout.width > 0) {
8384
8719
  layout.push(
@@ -8388,16 +8723,32 @@ async function waitForSootsimIdle(page, maxMs = 3e3, strict = false, transitionS
8388
8723
  Math.round(node.layout.height)
8389
8724
  );
8390
8725
  }
8726
+ const tid = node.testID || node.props?.testID || node.props?.testId;
8727
+ if (typeof tid === "string" && (tid === "web-preview-progress" || tid.endsWith("-preview-progress"))) {
8728
+ webViewStarting = true;
8729
+ }
8730
+ const text = node.textContent || (typeof node.props?.children === "string" ? node.props.children : "");
8731
+ if (typeof text === "string" && PREVIEW_PROGRESS_REGEX.test(text.trim())) {
8732
+ webViewStarting = true;
8733
+ }
8391
8734
  for (const child of node.children || []) walk(child);
8392
8735
  };
8393
8736
  walk(root);
8394
8737
  }
8738
+ if (!webViewStarting && typeof document !== "undefined") {
8739
+ if (document.querySelector(
8740
+ '[data-testid$="-preview-progress"], [data-testid="web-preview-progress"], [data-testid="ios-preview-progress"], [data-testid="design-preview-progress"], [data-sootsim-webview-loading="true"], [data-sootsim-webview-mode="placeholder"]'
8741
+ )) {
8742
+ webViewStarting = true;
8743
+ }
8744
+ }
8395
8745
  return {
8396
8746
  animating,
8397
8747
  auxSurfaceDebug,
8398
8748
  layout,
8399
8749
  layoutDirty,
8400
- renderStatsAvailable
8750
+ renderStatsAvailable,
8751
+ webViewStarting
8401
8752
  };
8402
8753
  };
8403
8754
  let stableLayout = null;
@@ -8406,7 +8757,7 @@ async function waitForSootsimIdle(page, maxMs = 3e3, strict = false, transitionS
8406
8757
  while (Date.now() < deadline) {
8407
8758
  const snapshot = await readSnapshot();
8408
8759
  lastSnapshot = snapshot;
8409
- if ((!strict2 || snapshot.renderStatsAvailable) && !snapshot.animating && !snapshot.layoutDirty && isLayoutStable(stableLayout, snapshot.layout)) {
8760
+ if ((!strict2 || snapshot.renderStatsAvailable) && !snapshot.animating && !snapshot.layoutDirty && !snapshot.webViewStarting && isLayoutStable(stableLayout, snapshot.layout)) {
8410
8761
  stable++;
8411
8762
  if (stable >= requiredStablePolls) {
8412
8763
  return { settled: true, elapsed: Date.now() - start };
@@ -8420,7 +8771,7 @@ async function waitForSootsimIdle(page, maxMs = 3e3, strict = false, transitionS
8420
8771
  return {
8421
8772
  settled: false,
8422
8773
  elapsed: Date.now() - start,
8423
- reason: transitionError ? `layout fallback after screen transition wait failed: ${transitionError}` : !lastSnapshot ? "deadline spent before the first idle poll" : strict2 ? `strict idle state unavailable: renderStats=${lastSnapshot?.renderStatsAvailable === true} animating=${lastSnapshot?.animating === true} layoutDirty=${lastSnapshot?.layoutDirty === true} layoutNodes=${(lastSnapshot?.layout.length ?? 0) / 4} aux=${JSON.stringify(lastSnapshot?.auxSurfaceDebug)}` : "layout fallback"
8774
+ reason: transitionError ? `layout fallback after screen transition wait failed: ${transitionError}` : !lastSnapshot ? "deadline spent before the first idle poll" : strict2 ? `strict idle state unavailable: renderStats=${lastSnapshot?.renderStatsAvailable === true} animating=${lastSnapshot?.animating === true} layoutDirty=${lastSnapshot?.layoutDirty === true} webViewStarting=${lastSnapshot?.webViewStarting === true} layoutNodes=${(lastSnapshot?.layout.length ?? 0) / 4} aux=${JSON.stringify(lastSnapshot?.auxSurfaceDebug)}` : "layout fallback"
8424
8775
  };
8425
8776
  },
8426
8777
  { maxMs, strict, transitionStartWindowMs }
@@ -8509,9 +8860,9 @@ async function dispatchTapAtSootsimPoint(page, x, y, token) {
8509
8860
  async ({ x: x2, y: y2, token: token2 }) => {
8510
8861
  const interactTap = window.SootSim?.bridges?.interact?.tap;
8511
8862
  if (typeof interactTap === "function") {
8863
+ if (token2) window.__sootsimAnchorTimedInput?.(token2);
8512
8864
  const result = await interactTap(x2, y2);
8513
8865
  if (result && (typeof result !== "object" || result.hit !== false)) {
8514
- if (token2) window.__sootsimAnchorTimedInput?.(token2);
8515
8866
  return;
8516
8867
  }
8517
8868
  }
@@ -8519,8 +8870,8 @@ async function dispatchTapAtSootsimPoint(page, x, y, token) {
8519
8870
  if (typeof tap !== "function") {
8520
8871
  throw new Error("sootsim tap bridge is not installed");
8521
8872
  }
8522
- await tap(x2, y2);
8523
8873
  if (token2) window.__sootsimAnchorTimedInput?.(token2);
8874
+ await tap(x2, y2);
8524
8875
  },
8525
8876
  { x, y, token }
8526
8877
  );
@@ -8829,8 +9180,8 @@ function createSootSimElement(matcher) {
8829
9180
  if (typeof longPress !== "function") {
8830
9181
  throw new Error("sootsim longPress bridge is not installed");
8831
9182
  }
8832
- await longPress(x, y, duration2);
8833
9183
  if (token) window.__sootsimAnchorTimedInput?.(token);
9184
+ await longPress(x, y, duration2);
8834
9185
  },
8835
9186
  { duration, x: target.x, y: target.y, token: captureToken }
8836
9187
  );
@@ -8883,6 +9234,11 @@ function createSootSimElement(matcher) {
8883
9234
  await focusElementForTextEntry(el);
8884
9235
  await page.keyboard.type(text);
8885
9236
  },
9237
+ async tapReturnKey() {
9238
+ const page = getPage();
9239
+ await focusElementForTextEntry(el);
9240
+ await page.keyboard.press("Enter");
9241
+ },
8886
9242
  async replaceText(text) {
8887
9243
  const page = getPage();
8888
9244
  const node = await findNodeByMatcher(matcher);
@@ -9012,8 +9368,8 @@ function createSootSimElement(matcher) {
9012
9368
  if (typeof drag !== "function") {
9013
9369
  throw new Error("sootsim interact bridge is not installed");
9014
9370
  }
9015
- await drag(fromX, fromY, toX, toY, steps2, stepMs);
9016
9371
  if (token) window.__sootsimAnchorTimedInput?.(token);
9372
+ await drag(fromX, fromY, toX, toY, steps2, stepMs);
9017
9373
  },
9018
9374
  {
9019
9375
  fromX: startSootSimX,
@@ -9540,8 +9896,10 @@ var device = {
9540
9896
  _lastRecordingPath: "",
9541
9897
  // park every render clock before the interaction, detect the first changed
9542
9898
  // stepped frame inside the named component, then advance exact 60fps frames
9543
- // to each requested offset. native extraction also chooses the first frame
9544
- // at or after an offset, so both sides use the same rounding convention.
9899
+ // to each requested offset from that frame. native extraction anchors at
9900
+ // its detection frame's pts, so both legs zero at the first painted change
9901
+ // and native also chooses the first frame at or after an offset, which is
9902
+ // the same rounding convention from the same zero.
9545
9903
  async takeScreenshotStagesFromVisibleChangeFast(namePrefix, stages, options) {
9546
9904
  const page = getPage();
9547
9905
  const token = `motion-${process.pid}-${Date.now()}-${Math.random()}`;
@@ -9711,7 +10069,6 @@ var device = {
9711
10069
  }
9712
10070
  let visibleStart = null;
9713
10071
  let detectedMeasurement = null;
9714
- let previousReceipt = null;
9715
10072
  let previousBitmap = null;
9716
10073
  if (input.platform === "android") {
9717
10074
  const candidateBitmap = await captureBitmap();
@@ -9748,24 +10105,23 @@ var device = {
9748
10105
  width: bounds.width
9749
10106
  });
9750
10107
  if (measurement.passedMinimum) {
9751
- candidateBitmap.close();
10108
+ previousBitmap?.close();
10109
+ previousBitmap = null;
9752
10110
  visibleStart = receipt;
9753
10111
  detectedMeasurement = measurement;
10112
+ keptFrames.set(receipt.frameIndex, candidateBitmap);
9754
10113
  break;
9755
10114
  }
9756
10115
  previousBitmap?.close();
9757
10116
  previousBitmap = candidateBitmap;
9758
- previousReceipt = receipt;
9759
- }
9760
- if (previousReceipt && previousBitmap) {
9761
- keptFrames.set(previousReceipt.frameIndex, previousBitmap);
9762
10117
  }
9763
10118
  if (!visibleStart || !detectedMeasurement) {
10119
+ previousBitmap?.close();
9764
10120
  throw new Error(
9765
10121
  `peach motion had no visible change before ${input.detectionTimeoutMs}ms`
9766
10122
  );
9767
10123
  }
9768
- const driveStart = input.platform === "android" ? visibleStart : previousReceipt ?? visibleStart;
10124
+ const driveStart = visibleStart;
9769
10125
  let currentReceipt = visibleStart;
9770
10126
  const resolvedAnchors = /* @__PURE__ */ new Map();
9771
10127
  const anchorRecords = [];
@@ -9824,14 +10180,14 @@ var device = {
9824
10180
  } else {
9825
10181
  latePeakPercent = Math.max(latePeakPercent, measurement.changePercent);
9826
10182
  }
9827
- if (measurement.passedMinimum) {
9828
- candidateBitmap.close();
9829
- onsetMeasurement = measurement;
9830
- break;
9831
- }
10183
+ const passed = measurement.passedMinimum;
9832
10184
  anchorBitmap.close();
9833
10185
  anchorBitmap = candidateBitmap;
9834
10186
  anchorReceipt = receipt;
10187
+ if (passed) {
10188
+ onsetMeasurement = measurement;
10189
+ break;
10190
+ }
9835
10191
  }
9836
10192
  if (!onsetMeasurement) {
9837
10193
  anchorBitmap.close();
@@ -10229,7 +10585,7 @@ var device = {
10229
10585
  const simId = await page.evaluate(() => window.SootSim?.state.simId);
10230
10586
  if (!simId) throw new Error("peach location requires a registered harness sim");
10231
10587
  const port = resolveSootsimBridgePortForHttpPort({
10232
- explicitPort: process.env.SOOTSIM_BRIDGE_PORT,
10588
+ explicitPort: process.env.PEACH_BRIDGE_PORT,
10233
10589
  httpPort: new URL(page.url()).port,
10234
10590
  baseHttpPort: 5173
10235
10591
  });
@@ -10304,9 +10660,9 @@ var device = {
10304
10660
  async ({ x: tx, y: ty, token }) => {
10305
10661
  const interactTap = window.SootSim?.bridges?.interact?.tap;
10306
10662
  if (typeof interactTap === "function") {
10663
+ if (token) window.__sootsimAnchorTimedInput?.(token);
10307
10664
  const result = await interactTap(tx, ty);
10308
10665
  if (result && (typeof result !== "object" || result.hit !== false)) {
10309
- if (token) window.__sootsimAnchorTimedInput?.(token);
10310
10666
  return;
10311
10667
  }
10312
10668
  }
@@ -10314,8 +10670,8 @@ var device = {
10314
10670
  if (typeof tap !== "function") {
10315
10671
  throw new Error("sootsim tap bridge is not installed");
10316
10672
  }
10317
- await tap(tx, ty);
10318
10673
  if (token) window.__sootsimAnchorTimedInput?.(token);
10674
+ await tap(tx, ty);
10319
10675
  },
10320
10676
  { x, y, token: captureToken }
10321
10677
  );
@@ -10336,11 +10692,11 @@ var device = {
10336
10692
  if (typeof longPress !== "function") {
10337
10693
  throw new Error("sootsim longPress bridge is not installed");
10338
10694
  }
10695
+ if (token) window.__sootsimAnchorTimedInput?.(token);
10339
10696
  const hit = await longPress(px, py, ms);
10340
10697
  if (!hit) {
10341
10698
  throw new Error(`sootsim longPress missed at ${px},${py}`);
10342
10699
  }
10343
- if (token) window.__sootsimAnchorTimedInput?.(token);
10344
10700
  },
10345
10701
  { x, y, ms: durationMs, token: captureToken }
10346
10702
  );