peachsim 0.1.940 → 0.1.1400
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.
- package/README.md +28 -22
- package/cli/app-catalog.ts +29 -14
- package/cli/app-fonts.ts +17 -8
- package/cli/bridge-flow-runner.ts +40 -29
- package/cli/cloud-client.ts +57 -21
- package/cli/cloud-test-tunnel.ts +12 -18
- package/cli/commands/agent.ts +1 -1
- package/cli/commands/app-fonts.ts +3 -3
- package/cli/commands/assert.ts +8 -8
- package/cli/commands/auth.ts +8 -3
- package/cli/commands/box/bundle-plane.ts +13 -1
- package/cli/commands/box.ts +16 -5
- package/cli/commands/compat.ts +1 -1
- package/cli/commands/config.ts +2 -2
- package/cli/commands/control.ts +125 -71
- package/cli/commands/cpu-profile.ts +45 -1
- package/cli/commands/daemon.ts +131 -33
- package/cli/commands/debug.ts +24 -17
- package/cli/commands/desktop.ts +7 -1
- package/cli/commands/detect.ts +101 -0
- package/cli/commands/detox.ts +6 -6
- package/cli/commands/device.ts +12 -12
- package/cli/commands/electron.ts +32 -14
- package/cli/commands/flow.ts +49 -41
- package/cli/commands/guest-host.ts +39 -1
- package/cli/commands/inspect/core.ts +14 -8
- package/cli/commands/inspect/list.ts +1 -1
- package/cli/commands/inspect/settle.ts +5 -3
- package/cli/commands/inspect/settling.ts +229 -44
- package/cli/commands/inspect/wait-idle.ts +3 -2
- package/cli/commands/inspect.ts +107 -95
- package/cli/commands/install-cli.ts +36 -15
- package/cli/commands/install-desktop.ts +68 -195
- package/cli/commands/kotlin.ts +6 -5
- package/cli/commands/login.ts +5 -5
- package/cli/commands/maestro-compare.ts +554 -0
- package/cli/commands/maestro-generate.ts +6 -3
- package/cli/commands/maestro.ts +22 -0
- package/cli/commands/mode.ts +2 -2
- package/cli/commands/no-bridge-hint.ts +6 -2
- package/cli/commands/platform.ts +35 -6
- package/cli/commands/preview.ts +6 -0
- package/cli/commands/project-report.ts +10 -12
- package/cli/commands/record.ts +37 -37
- package/cli/commands/runtime.ts +9 -9
- package/cli/commands/screenshot-layers.ts +4 -4
- package/cli/commands/screenshot-mode.ts +2 -2
- package/cli/commands/screenshot.ts +19 -16
- package/cli/commands/screenshots-capture.ts +2 -2
- package/cli/commands/serve.ts +9 -12
- package/cli/commands/setup.ts +29 -14
- package/cli/commands/shell-boolean-mode.ts +2 -2
- package/cli/commands/show-touches-mode.ts +2 -2
- package/cli/commands/skills.ts +11 -11
- package/cli/commands/swift.ts +29 -11
- package/cli/commands/telemetry.ts +2 -2
- package/cli/commands/test.ts +5 -0
- package/cli/commands/three-mode.ts +3 -3
- package/cli/commands/timeline.ts +4 -4
- package/cli/commands/upgrade.ts +2 -2
- package/cli/commands/upload.ts +15 -15
- package/cli/commands/what-happened.ts +2 -2
- package/cli/current-sim.ts +6 -3
- package/cli/desktop-companion.ts +55 -149
- package/cli/dev-build-freshness.ts +2 -2
- package/cli/drivers/desktop.ts +17 -9
- package/cli/drivers/electron.ts +1 -2
- package/cli/drivers/playwright-sim-host.ts +11 -2
- package/cli/drivers/playwright.ts +35 -2
- package/cli/drivers/types.ts +8 -0
- package/cli/maestro-compare.ts +670 -0
- package/cli/outbound-endpoints.ts +50 -8
- package/cli/recording-access.ts +6 -6
- package/cli/run-registry.ts +1 -1
- package/cli/runtime-compat.ts +5 -1
- package/cli/screenshot-output.ts +17 -0
- package/cli/send-to-box.ts +3 -3
- package/cli/shell-init.ts +2 -1
- package/cli/ws-bridge.ts +9 -5
- package/detox/element-types.ts +1 -0
- package/detox/gestures.ts +3 -3
- package/detox/index.ts +67 -38
- package/detox/navigation-lifecycle.ts +9 -6
- package/detox/proof-frame.cjs +6 -4
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +42 -17
- package/dist-lib/bridge-contract-input.mjs +41 -16
- package/dist-lib/bridge-contract.cjs +1 -4
- package/dist-lib/bridge-contract.mjs +1 -3
- package/dist-lib/bundle-channel.cjs +2918 -550
- package/dist-lib/capture-contract.cjs +65 -24
- package/dist-lib/capture-contract.mjs +63 -24
- package/dist-lib/cloud-contract.cjs +2 -2
- package/dist-lib/cloud-contract.mjs +2 -2
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +3 -3
- package/dist-lib/cloud.mjs +3 -3
- package/dist-lib/config.cjs +15 -5
- package/dist-lib/config.mjs +154 -0
- package/dist-lib/detox/index.cjs +495 -139
- package/dist-lib/dev-bundle-resolution.cjs +3 -1
- package/dist-lib/expo-swift-bundle.cjs +1168 -238
- package/dist-lib/expo-swift-metadata.cjs +34 -23
- package/dist-lib/expo-swift-metadata.mjs +32 -23
- package/dist-lib/home-paths.cjs +2 -2
- package/dist-lib/host/bridge-host.cjs +2938 -654
- package/dist-lib/host/fetch-proxy-handler.cjs +14 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +7 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +5 -1
- package/dist-lib/host/replacement-module-handler.cjs +2 -2
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +981 -353
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/kotlin-host.cjs +332 -19
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +7 -7
- package/dist-lib/metro-production-bundle.mjs +5 -5
- package/dist-lib/metro.cjs +670 -250
- package/dist-lib/native-app-identity-project.cjs +2647 -0
- package/dist-lib/native-app-identity-project.mjs +1257 -0
- package/dist-lib/native-app-identity.cjs +304 -25
- package/dist-lib/native-app-identity.mjs +302 -25
- package/dist-lib/native-firebase-metadata.cjs +1 -1
- package/dist-lib/native-firebase-metadata.mjs +1 -1
- package/dist-lib/plist.cjs +1 -1
- package/dist-lib/plist.mjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +5 -1
- package/dist-lib/react-native-host-modules.mjs +5 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +57 -32
- package/dist-lib/sdk.cjs +231 -51
- package/dist-lib/sdk.mjs +231 -51
- package/dist-lib/skills.cjs +4114 -1376
- package/dist-lib/swift-compile.cjs +290 -30
- package/dist-lib/swift-compile.mjs +290 -30
- package/dist-lib/swift-package.cjs +143 -12
- package/dist-lib/swift-package.mjs +137 -11
- package/dist-lib/swift-submit.cjs +47 -5
- package/dist-lib/swift-submit.mjs +42 -5
- package/dist-lib/swift-toolchain.cjs +7 -2
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite-swift.cjs +1392 -458
- package/dist-lib/vite.cjs +13 -17
- package/dist-lib/worklet-executable.cjs +248 -33
- package/dist-lib/worklet-executable.mjs +248 -33
- package/install.sh +10 -1
- package/kotlin/{AppSources → AndroidViewSources}/android/content/res/Resources.kt +9 -9
- package/kotlin/AndroidViewSources/android/graphics/Canvas.kt +20 -0
- package/kotlin/AndroidViewSources/android/view/View.kt +211 -0
- package/kotlin/AndroidViewSources/android/widget/FrameLayout.kt +61 -0
- package/kotlin/AndroidViewSources/android/widget/LinearLayout.kt +49 -0
- package/kotlin/AppSources/android/view/Window.kt +36 -0
- package/kotlin/AppSources/android/view/WindowInsets.kt +9 -0
- package/kotlin/AppSources/android/view/WindowInsetsController.kt +5 -0
- package/kotlin/AppSources/android/window/OnBackInvokedDispatcher.kt +48 -0
- package/kotlin/AppSources/androidx/activity/OnBackPressedDispatcher.kt +20 -5
- package/kotlin/AppSources/androidx/compose/foundation/layout/WindowInsets.kt +15 -0
- package/kotlin/AppSources/androidx/compose/ui/platform/ComposeView.kt +2 -1
- package/kotlin/AppSources/dev/peach/app/PeachApp.kt +42 -50
- package/kotlin/ComposeSources/PeachComposeHost.kt +200 -84
- package/kotlin/ExpoComposeSources/PeachAndroidView.kt +87 -0
- package/kotlin/ExpoComposeSources/PeachExpoViewMount.kt +24 -0
- package/kotlin/ExpoComposeSources/dev/peach/expo/PeachExpoCompose.kt +28 -0
- package/kotlin/ExpoComposeSources/expo/modules/kotlin/views/ExpoComposeView.kt +70 -0
- package/kotlin/ExpoSources/dev/peach/expo/PeachExpoRuntime.kt +513 -0
- package/kotlin/ExpoSources/dev/peach/expo/PeachExpoTypes.kt +173 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/AppContext.kt +20 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/Promise.kt +19 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/classcomponent/ClassComponentBuilder.kt +198 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/exception/CodedException.kt +126 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/functions/Functions.kt +132 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/jni/JavaScriptTypedArray.kt +81 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/modules/Module.kt +98 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +236 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/records/Record.kt +12 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/runtime/Runtime.kt +9 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/sharedobjects/SharedObject.kt +50 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/sharedobjects/SharedObjectRegistry.kt +57 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/sharedobjects/SharedRef.kt +19 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/ConcreteTypedArrays.kt +158 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/GenericTypedArray.kt +8 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/TypedArray.kt +29 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/TypedArrayIterator.kt +9 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/types/AnyType.kt +155 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/types/Either.kt +91 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/types/Enumerable.kt +6 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/viewevent/ViewEvent.kt +54 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/views/ExpoView.kt +23 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +71 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/views/ViewProps.kt +35 -0
- package/kotlin/README.md +13 -3
- package/kotlin/Sources/android/os/Build.kt +17 -0
- package/kotlin/Sources/android/os/Handler.kt +35 -0
- package/kotlin/Sources/android/os/Looper.kt +17 -0
- package/kotlin/Sources/android/os/MessageQueue.kt +56 -0
- package/kotlin/Sources/android/os/SystemClock.kt +14 -0
- package/kotlin/Sources/android/util/Log.kt +64 -0
- package/kotlin/Sources/java/security/MessageDigest.kt +114 -0
- package/kotlin/Sources/kotlin/text/StringFormat.kt +9 -0
- package/kotlin/Sources/org/json/JSON.kt +44 -0
- package/kotlin/fixtures/counter/Counter.d.kt.ts +1 -0
- package/kotlin/fixtures/counter/Counter.kt +10 -3
- package/kotlin/fixtures/counter/CounterApp.native.tsx +1 -1
- package/kotlin/fixtures/counter/vite.config.ts +2 -2
- package/kotlin/fixtures/headless-counter/Headless.kt +7 -6
- package/kotlin/fixtures/import-animation/Animation.d.kt.ts +7 -0
- package/kotlin/fixtures/import-animation/Animation.kt +80 -0
- package/kotlin/fixtures/import-animation/ImportAnimation.native.tsx +13 -0
- package/kotlin/fixtures/import-animation/README.md +24 -0
- package/kotlin/fixtures/import-animation/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-animation/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-animation/app/routes.d.ts +18 -0
- package/kotlin/fixtures/import-animation/package.json +23 -0
- package/kotlin/fixtures/import-animation/tsconfig.json +20 -0
- package/kotlin/fixtures/import-animation/vite.config.ts +20 -0
- package/kotlin/fixtures/import-editor/Editor.d.kt.ts +7 -0
- package/kotlin/fixtures/import-editor/Editor.kt +59 -0
- package/kotlin/fixtures/import-editor/ImportEditor.native.tsx +23 -0
- package/kotlin/fixtures/import-editor/README.md +27 -0
- package/kotlin/fixtures/import-editor/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-editor/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-editor/package.json +23 -0
- package/kotlin/fixtures/import-editor/tsconfig.json +20 -0
- package/kotlin/fixtures/import-editor/vite.config.ts +20 -0
- package/kotlin/fixtures/import-effects/Effects.d.kt.ts +7 -0
- package/kotlin/fixtures/import-effects/Effects.kt +87 -0
- package/kotlin/fixtures/import-effects/ImportEffects.native.tsx +13 -0
- package/kotlin/fixtures/import-effects/README.md +19 -0
- package/kotlin/fixtures/import-effects/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-effects/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-effects/package.json +23 -0
- package/kotlin/fixtures/import-effects/tsconfig.json +20 -0
- package/kotlin/fixtures/import-effects/vite.config.ts +20 -0
- package/kotlin/fixtures/import-layout/ImportLayout.native.tsx +13 -0
- package/kotlin/fixtures/import-layout/Layout.d.kt.ts +7 -0
- package/kotlin/fixtures/import-layout/Layout.kt +72 -0
- package/kotlin/fixtures/import-layout/README.md +24 -0
- package/kotlin/fixtures/import-layout/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-layout/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-layout/package.json +23 -0
- package/kotlin/fixtures/import-layout/tsconfig.json +20 -0
- package/kotlin/fixtures/import-layout/vite.config.ts +20 -0
- package/kotlin/fixtures/import-navigation/ImportNavigation.native.tsx +18 -0
- package/kotlin/fixtures/import-navigation/Navigation.d.kt.ts +7 -0
- package/kotlin/fixtures/import-navigation/Navigation.kt +104 -0
- package/kotlin/fixtures/import-navigation/README.md +31 -0
- package/kotlin/fixtures/import-navigation/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-navigation/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-navigation/package.json +23 -0
- package/kotlin/fixtures/import-navigation/tsconfig.json +20 -0
- package/kotlin/fixtures/import-navigation/vite.config.ts +20 -0
- package/kotlin/fixtures/import-overlays/ImportOverlays.native.tsx +29 -0
- package/kotlin/fixtures/import-overlays/Overlays.d.kt.ts +7 -0
- package/kotlin/fixtures/import-overlays/Overlays.kt +93 -0
- package/kotlin/fixtures/import-overlays/README.md +34 -0
- package/kotlin/fixtures/import-overlays/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-overlays/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-overlays/package.json +23 -0
- package/kotlin/fixtures/import-overlays/tsconfig.json +20 -0
- package/kotlin/fixtures/import-overlays/vite.config.ts +20 -0
- package/kotlin/fixtures/import-scroll/ImportScroll.native.tsx +13 -0
- package/kotlin/fixtures/import-scroll/README.md +23 -0
- package/kotlin/fixtures/import-scroll/Scroll.d.kt.ts +7 -0
- package/kotlin/fixtures/import-scroll/Scroll.kt +91 -0
- package/kotlin/fixtures/import-scroll/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-scroll/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-scroll/package.json +23 -0
- package/kotlin/fixtures/import-scroll/tsconfig.json +20 -0
- package/kotlin/fixtures/import-scroll/vite.config.ts +20 -0
- package/kotlin/fixtures/import-selection/ImportSelection.native.tsx +44 -0
- package/kotlin/fixtures/import-selection/README.md +32 -0
- package/kotlin/fixtures/import-selection/Selection.d.kt.ts +8 -0
- package/kotlin/fixtures/import-selection/Selection.kt +78 -0
- package/kotlin/fixtures/import-selection/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-selection/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-selection/package.json +23 -0
- package/kotlin/fixtures/import-selection/tsconfig.json +20 -0
- package/kotlin/fixtures/import-selection/vite.config.ts +20 -0
- package/kotlin/fixtures/import-surfaces/ImportSurfaces.native.tsx +13 -0
- package/kotlin/fixtures/import-surfaces/README.md +22 -0
- package/kotlin/fixtures/import-surfaces/Surfaces.d.kt.ts +7 -0
- package/kotlin/fixtures/import-surfaces/Surfaces.kt +64 -0
- package/kotlin/fixtures/import-surfaces/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-surfaces/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-surfaces/package.json +23 -0
- package/kotlin/fixtures/import-surfaces/tsconfig.json +20 -0
- package/kotlin/fixtures/import-surfaces/vite.config.ts +20 -0
- package/kotlin/fixtures/import-values/ImportValues.native.tsx +35 -0
- package/kotlin/fixtures/import-values/README.md +23 -0
- package/kotlin/fixtures/import-values/Values.d.kt.ts +11 -0
- package/kotlin/fixtures/import-values/Values.kt +66 -0
- package/kotlin/fixtures/import-values/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-values/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-values/package.json +23 -0
- package/kotlin/fixtures/import-values/tsconfig.json +20 -0
- package/kotlin/fixtures/import-values/vite.config.ts +20 -0
- package/kotlin/fixtures/kotlin-app-variants/BarBehavior.kt +38 -0
- package/kotlin/fixtures/kotlin-app-variants/BarVisibility.kt +36 -0
- package/kotlin/fixtures/kotlin-app-variants/Ime.kt +3 -1
- package/kotlin/fixtures/kotlin-app-variants/TransientInsets.kt +50 -0
- package/kotlin/fork/NOTICE +6 -1
- package/kotlin/fork/README.md +15 -7
- package/kotlin/fork/build.sh +2 -0
- package/kotlin/fork/compose-worker-globals.patch +186 -4
- package/kotlin/fork/fork.json +2 -2
- package/kotlin/fork/skiko-worker-clock.patch +12 -0
- package/kotlin/toolchain.json +12 -12
- package/kotlin/tools/expo-types.main.kts +115 -0
- package/package.json +17 -23
- package/scripts/dev-server-scanner.ts +92 -66
- package/skills/contrast/SKILL.md +2 -2
- package/skills/peach-debug/SKILL.md +1 -1
- package/skills/peach-perf/SKILL.md +1 -1
- package/skills/peach-setup/SKILL.md +2 -1
- package/skills/peach-test/SKILL.md +8 -0
- package/src/assetCatalogContract.ts +43 -1
- package/src/bridge-contract-input.ts +46 -19
- package/src/bridge-contract.ts +0 -1
- package/src/bundle-channel.mjs +197 -84
- package/src/bundleGlobalFooter.ts +38 -0
- package/src/capture-contract.ts +107 -33
- package/src/cloud-contract.ts +5 -1
- package/src/cloud.ts +5 -2
- package/src/config.ts +22 -3
- package/src/configured-bundle-producer.ts +1 -1
- package/src/desktop-host-delivery.ts +95 -1
- package/src/dev-bundle-resolution.ts +1 -1
- package/src/expo-kotlin-bundle.ts +29 -0
- package/src/expo-kotlin-host.ts +201 -0
- package/src/expo-swift-host.ts +96 -76
- package/src/expoKotlinContract.ts +70 -0
- package/src/expoSwiftContract.ts +4 -25
- package/src/home-paths.ts +7 -4
- package/src/host/bridge-host.ts +23 -3
- package/src/host/fetch-proxy-handler.ts +13 -0
- package/src/host/fetch-proxy-overrides.ts +11 -0
- package/src/host/replacement-module-handler.ts +5 -2
- package/src/index.ts +3 -1
- package/src/kotlin-host.ts +463 -19
- package/src/metro-plugin.ts +56 -28
- package/src/metro-production-bundle.ts +2 -2
- package/src/native-app-identity-project.ts +190 -0
- package/src/native-app-identity.ts +367 -34
- package/src/native-firebase-config.ts +69 -15
- package/src/native-seam-manifest.ts +6 -0
- package/src/one-widget-discovery.ts +2 -1
- package/src/openstep-plist.ts +107 -0
- package/src/react-native-host-modules.ts +4 -0
- package/src/runtime-assets.ts +2 -2
- package/src/sim-client.ts +2 -2
- package/src/swift-binary-modules.ts +3 -1
- package/src/swift-compile.ts +286 -38
- package/src/swift-distribution-contract.ts +4 -0
- package/src/swift-distribution.lock.json +123 -12
- package/src/swift-distribution.ts +7 -3
- package/src/swift-host.ts +298 -83
- package/src/swift-package-manifest.ts +29 -2
- package/src/swift-package.ts +180 -10
- package/src/swift-packages.ts +4 -0
- package/src/swift-standin-emit.ts +4 -1
- package/src/swift-standins.ts +274 -15
- package/src/swift-submit.ts +62 -7
- package/src/swift-toolchain.ts +6 -1
- package/src/swiftContract.ts +126 -3
- package/src/vite-plugin-one.ts +13 -16
- package/src/vite-plugin-swift.ts +4 -5
- package/src/vite-plugin.ts +360 -144
- package/src/vite.d.ts +1 -1
- package/src/worker-system-chunks.ts +221 -0
- package/src/worklet-executable.ts +348 -38
- package/src/worklets-babel.ts +1 -1
- package/src/xcode-project.ts +243 -127
- package/dist-lib/agent-identity.cjs +0 -39
- package/dist-lib/agent-sessions.cjs +0 -760
- package/dist-lib/cli-constants.cjs +0 -32
- package/dist-lib/render-mode.cjs +0 -44
- package/kotlin/AppSources/android/view/View.kt +0 -74
- package/kotlin/AppSources/android/widget/FrameLayout.kt +0 -6
- package/src/render-mode.ts +0 -15
- /package/kotlin/{AppSources → AndroidViewSources}/android/content/Context.kt +0 -0
- /package/kotlin/{AppSources → AndroidViewSources}/android/content/res/Configuration.kt +0 -0
- /package/kotlin/{AppSources → AndroidViewSources}/android/graphics/Color.kt +0 -0
- /package/kotlin/{AppSources → AndroidViewSources}/android/util/DisplayMetrics.kt +0 -0
- /package/kotlin/{AppSources → AndroidViewSources}/dev/peach/app/JavaFormat.kt +0 -0
- /package/kotlin/{AppSources → Sources}/java/lang/Runnable.kt +0 -0
|
@@ -3,15 +3,29 @@
|
|
|
3
3
|
// against the Xcode Release build settings, or `android/app/build.gradle`), so
|
|
4
4
|
// a simulator tenant reports the same identity the native Release build does.
|
|
5
5
|
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
6
|
+
// identity travels in a bundle footer or response header. the one updates
|
|
7
|
+
// receipt travels only in the response header so publisher JavaScript stays
|
|
8
|
+
// unchanged. tenant boot validates both before evaluation and clears the realm
|
|
9
|
+
// store when neither carries identity.
|
|
10
|
+
|
|
11
|
+
import { parseOpenStepPlist } from './openstep-plist'
|
|
9
12
|
|
|
10
13
|
export type NativeAppIdentityPlatform = 'ios' | 'android'
|
|
11
14
|
|
|
15
|
+
export interface NativeOneUpdatesReceipt {
|
|
16
|
+
enabled: boolean
|
|
17
|
+
url: string | null
|
|
18
|
+
runtimeVersion: string | null
|
|
19
|
+
embeddedManifestJson: string | null
|
|
20
|
+
}
|
|
21
|
+
|
|
12
22
|
export interface NativeAppIdentity {
|
|
13
23
|
// the user-facing name (CFBundleDisplayName, else CFBundleName).
|
|
14
24
|
applicationName: string | null
|
|
25
|
+
// the literal CFBundleDisplayName, without a bundle-name fallback.
|
|
26
|
+
applicationDisplayName?: string
|
|
27
|
+
// the processed ARGB integer from RCTRootViewBackgroundColor.
|
|
28
|
+
rootViewBackgroundColor?: number
|
|
15
29
|
// CFBundleName, which CFNetwork stamps into the default User-Agent and iOS's
|
|
16
30
|
// own prompts use (the ASWebAuthenticationSession consent alert); distinct
|
|
17
31
|
// from the display name. absent in footers built before it was carried.
|
|
@@ -23,7 +37,16 @@ export interface NativeAppIdentity {
|
|
|
23
37
|
permissionUsageDescriptions?: Readonly<Record<string, unknown>>
|
|
24
38
|
urlQuerySchemes?: readonly unknown[]
|
|
25
39
|
appIntentIdentifiers?: readonly string[]
|
|
40
|
+
backgroundTaskIdentifiers?: readonly string[]
|
|
41
|
+
backgroundModes?: readonly string[]
|
|
42
|
+
supportedInterfaceOrientations?: readonly string[]
|
|
43
|
+
ipadSupportedInterfaceOrientations?: readonly string[]
|
|
44
|
+
defaultScreenOrientationMask?: string
|
|
45
|
+
shareIntoAppGroupId?: string
|
|
26
46
|
alternateIconNames?: readonly string[]
|
|
47
|
+
// one updates configuration travels only in response metadata, never in guest
|
|
48
|
+
// code or inferred from JavaScript build flags.
|
|
49
|
+
oneUpdates?: NativeOneUpdatesReceipt
|
|
27
50
|
}
|
|
28
51
|
|
|
29
52
|
export type NativeAppIdentityFiles = Record<string, string>
|
|
@@ -47,6 +70,24 @@ function nonEmptyString(value: unknown): string | null {
|
|
|
47
70
|
|
|
48
71
|
export function isNativeAppIdentity(value: unknown): value is NativeAppIdentity {
|
|
49
72
|
if (!isRecord(value)) return false
|
|
73
|
+
const oneUpdates = value.oneUpdates
|
|
74
|
+
if (
|
|
75
|
+
oneUpdates !== undefined &&
|
|
76
|
+
(!isRecord(oneUpdates) ||
|
|
77
|
+
typeof oneUpdates.enabled !== 'boolean' ||
|
|
78
|
+
(oneUpdates.url !== null && typeof oneUpdates.url !== 'string') ||
|
|
79
|
+
(oneUpdates.runtimeVersion !== null &&
|
|
80
|
+
typeof oneUpdates.runtimeVersion !== 'string') ||
|
|
81
|
+
(oneUpdates.embeddedManifestJson !== null &&
|
|
82
|
+
typeof oneUpdates.embeddedManifestJson !== 'string') ||
|
|
83
|
+
(oneUpdates.enabled &&
|
|
84
|
+
(typeof oneUpdates.url !== 'string' ||
|
|
85
|
+
oneUpdates.url.length === 0 ||
|
|
86
|
+
typeof oneUpdates.runtimeVersion !== 'string' ||
|
|
87
|
+
oneUpdates.runtimeVersion.length === 0)))
|
|
88
|
+
) {
|
|
89
|
+
return false
|
|
90
|
+
}
|
|
50
91
|
const descriptions = value.permissionUsageDescriptions
|
|
51
92
|
if (descriptions !== undefined && !isRecord(descriptions)) return false
|
|
52
93
|
if (value.urlQuerySchemes !== undefined && !Array.isArray(value.urlQuerySchemes))
|
|
@@ -57,6 +98,52 @@ export function isNativeAppIdentity(value: unknown): value is NativeAppIdentity
|
|
|
57
98
|
!value.appIntentIdentifiers.every((identifier) => typeof identifier === 'string'))
|
|
58
99
|
)
|
|
59
100
|
return false
|
|
101
|
+
if (
|
|
102
|
+
value.backgroundTaskIdentifiers !== undefined &&
|
|
103
|
+
(!Array.isArray(value.backgroundTaskIdentifiers) ||
|
|
104
|
+
!value.backgroundTaskIdentifiers.every(
|
|
105
|
+
(identifier) => typeof identifier === 'string',
|
|
106
|
+
))
|
|
107
|
+
)
|
|
108
|
+
return false
|
|
109
|
+
if (
|
|
110
|
+
value.backgroundModes !== undefined &&
|
|
111
|
+
(!Array.isArray(value.backgroundModes) ||
|
|
112
|
+
!value.backgroundModes.every((mode) => typeof mode === 'string'))
|
|
113
|
+
)
|
|
114
|
+
return false
|
|
115
|
+
if (
|
|
116
|
+
value.shareIntoAppGroupId !== undefined &&
|
|
117
|
+
typeof value.shareIntoAppGroupId !== 'string'
|
|
118
|
+
)
|
|
119
|
+
return false
|
|
120
|
+
if (
|
|
121
|
+
value.applicationDisplayName !== undefined &&
|
|
122
|
+
typeof value.applicationDisplayName !== 'string'
|
|
123
|
+
)
|
|
124
|
+
return false
|
|
125
|
+
if (
|
|
126
|
+
value.rootViewBackgroundColor !== undefined &&
|
|
127
|
+
(typeof value.rootViewBackgroundColor !== 'number' ||
|
|
128
|
+
!Number.isInteger(value.rootViewBackgroundColor))
|
|
129
|
+
)
|
|
130
|
+
return false
|
|
131
|
+
for (const orientations of [
|
|
132
|
+
value.supportedInterfaceOrientations,
|
|
133
|
+
value.ipadSupportedInterfaceOrientations,
|
|
134
|
+
]) {
|
|
135
|
+
if (
|
|
136
|
+
orientations !== undefined &&
|
|
137
|
+
(!Array.isArray(orientations) ||
|
|
138
|
+
!orientations.every((orientation) => typeof orientation === 'string'))
|
|
139
|
+
)
|
|
140
|
+
return false
|
|
141
|
+
}
|
|
142
|
+
if (
|
|
143
|
+
value.defaultScreenOrientationMask !== undefined &&
|
|
144
|
+
typeof value.defaultScreenOrientationMask !== 'string'
|
|
145
|
+
)
|
|
146
|
+
return false
|
|
60
147
|
const platform = value.platform
|
|
61
148
|
if (
|
|
62
149
|
value.alternateIconNames !== undefined &&
|
|
@@ -86,6 +173,12 @@ export function readNativeAppIdentity(value: unknown): NativeAppIdentity | null
|
|
|
86
173
|
}
|
|
87
174
|
return {
|
|
88
175
|
applicationName: value.applicationName,
|
|
176
|
+
...(value.applicationDisplayName === undefined
|
|
177
|
+
? {}
|
|
178
|
+
: { applicationDisplayName: value.applicationDisplayName }),
|
|
179
|
+
...(value.rootViewBackgroundColor === undefined
|
|
180
|
+
? {}
|
|
181
|
+
: { rootViewBackgroundColor: value.rootViewBackgroundColor }),
|
|
89
182
|
...(value.bundleName === undefined ? {} : { bundleName: value.bundleName }),
|
|
90
183
|
appVersion: value.appVersion,
|
|
91
184
|
buildVersion: value.buildVersion,
|
|
@@ -102,9 +195,43 @@ export function readNativeAppIdentity(value: unknown): NativeAppIdentity | null
|
|
|
102
195
|
...(value.appIntentIdentifiers === undefined
|
|
103
196
|
? {}
|
|
104
197
|
: { appIntentIdentifiers: [...value.appIntentIdentifiers] }),
|
|
198
|
+
...(value.backgroundTaskIdentifiers === undefined
|
|
199
|
+
? {}
|
|
200
|
+
: { backgroundTaskIdentifiers: [...value.backgroundTaskIdentifiers] }),
|
|
201
|
+
...(value.supportedInterfaceOrientations === undefined
|
|
202
|
+
? {}
|
|
203
|
+
: {
|
|
204
|
+
supportedInterfaceOrientations: [...value.supportedInterfaceOrientations],
|
|
205
|
+
}),
|
|
206
|
+
...(value.ipadSupportedInterfaceOrientations === undefined
|
|
207
|
+
? {}
|
|
208
|
+
: {
|
|
209
|
+
ipadSupportedInterfaceOrientations: [
|
|
210
|
+
...value.ipadSupportedInterfaceOrientations,
|
|
211
|
+
],
|
|
212
|
+
}),
|
|
213
|
+
...(value.defaultScreenOrientationMask === undefined
|
|
214
|
+
? {}
|
|
215
|
+
: { defaultScreenOrientationMask: value.defaultScreenOrientationMask }),
|
|
216
|
+
...(value.backgroundModes === undefined
|
|
217
|
+
? {}
|
|
218
|
+
: { backgroundModes: [...value.backgroundModes] }),
|
|
219
|
+
...(value.shareIntoAppGroupId === undefined
|
|
220
|
+
? {}
|
|
221
|
+
: { shareIntoAppGroupId: value.shareIntoAppGroupId }),
|
|
105
222
|
...(value.urlQuerySchemes === undefined
|
|
106
223
|
? {}
|
|
107
224
|
: { urlQuerySchemes: [...value.urlQuerySchemes] }),
|
|
225
|
+
...(value.oneUpdates === undefined
|
|
226
|
+
? {}
|
|
227
|
+
: {
|
|
228
|
+
oneUpdates: {
|
|
229
|
+
enabled: value.oneUpdates.enabled,
|
|
230
|
+
url: value.oneUpdates.url,
|
|
231
|
+
runtimeVersion: value.oneUpdates.runtimeVersion,
|
|
232
|
+
embeddedManifestJson: value.oneUpdates.embeddedManifestJson,
|
|
233
|
+
},
|
|
234
|
+
}),
|
|
108
235
|
}
|
|
109
236
|
}
|
|
110
237
|
|
|
@@ -145,7 +272,10 @@ export function readNativeAppIdentityFromBundle(
|
|
|
145
272
|
}
|
|
146
273
|
const identity = readNativeAppIdentity(value)
|
|
147
274
|
if (!identity) throw new Error('native app identity response header is malformed')
|
|
148
|
-
|
|
275
|
+
const footerIdentity = footer ? readNativeAppIdentity(footer) : null
|
|
276
|
+
const headerBase = { ...identity, oneUpdates: undefined }
|
|
277
|
+
const footerBase = footerIdentity && { ...footerIdentity, oneUpdates: undefined }
|
|
278
|
+
if (footerIdentity && !equalIdentityValues(headerBase, footerBase)) {
|
|
149
279
|
throw new Error('native app identity response header conflicts with bundle footer')
|
|
150
280
|
}
|
|
151
281
|
return identity
|
|
@@ -168,7 +298,10 @@ export function getAppliedNativeAppIdentity(): NativeAppIdentity | null {
|
|
|
168
298
|
// one line, so the footer survives a bundle whose last statement is the Metro
|
|
169
299
|
// module identity footer and can be found again by reading the text.
|
|
170
300
|
export function createNativeAppIdentityFooter(identity: NativeAppIdentity): string {
|
|
171
|
-
const
|
|
301
|
+
const footerIdentity = { ...identity }
|
|
302
|
+
// native update configuration belongs to response metadata, never guest code.
|
|
303
|
+
delete footerIdentity.oneUpdates
|
|
304
|
+
const payload = JSON.stringify(footerIdentity)
|
|
172
305
|
.replace(/\u2028/g, '\\u2028')
|
|
173
306
|
.replace(/\u2029/g, '\\u2029')
|
|
174
307
|
.replace(/<\//g, '<\\/')
|
|
@@ -196,6 +329,9 @@ export function readNativeAppIdentityFooter(source: string): NativeAppIdentity |
|
|
|
196
329
|
if (!isNativeAppIdentity(parsed)) {
|
|
197
330
|
throw new Error('native app identity footer is malformed')
|
|
198
331
|
}
|
|
332
|
+
if (parsed.oneUpdates !== undefined) {
|
|
333
|
+
throw new Error('native app identity footer cannot contain one updates receipt')
|
|
334
|
+
}
|
|
199
335
|
return parsed
|
|
200
336
|
}
|
|
201
337
|
|
|
@@ -372,39 +508,162 @@ function appTargetReleaseSettings(
|
|
|
372
508
|
function nativeAppIdentityFromIos(
|
|
373
509
|
files: NativeAppIdentityFiles,
|
|
374
510
|
parseInfoPlist: (source: string) => unknown,
|
|
511
|
+
iosTarget?: string,
|
|
375
512
|
): NativeAppIdentity | null {
|
|
376
|
-
const pbxprojPath =
|
|
377
|
-
|
|
378
|
-
|
|
513
|
+
const pbxprojPath =
|
|
514
|
+
Object.keys(files).find((path) =>
|
|
515
|
+
/(?:^|\/)ios\/[^/]+\.xcodeproj\/project\.pbxproj$/.test(path),
|
|
516
|
+
) ??
|
|
517
|
+
Object.keys(files).find((path) =>
|
|
518
|
+
/(?:^|\/)[^/]+\.xcodeproj\/project\.pbxproj$/.test(path),
|
|
519
|
+
) ??
|
|
520
|
+
Object.keys(files).find((path) => /(?:^|\/)project\.pbxproj$/.test(path))
|
|
379
521
|
if (!pbxprojPath) return null
|
|
380
522
|
const pbxproj = files[pbxprojPath]
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
523
|
+
|
|
524
|
+
let objects: Record<string, unknown> = {}
|
|
525
|
+
try {
|
|
526
|
+
const parsed = parseOpenStepPlist(pbxproj)
|
|
527
|
+
if (isRecord(parsed)) {
|
|
528
|
+
objects = isRecord(parsed.objects) ? parsed.objects : parsed
|
|
529
|
+
}
|
|
530
|
+
} catch {
|
|
531
|
+
// fallback if unparseable
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
interface NativeTargetSummary {
|
|
535
|
+
id: string
|
|
536
|
+
name: string
|
|
537
|
+
productType?: string
|
|
538
|
+
buildConfigurationList?: string
|
|
539
|
+
}
|
|
540
|
+
const targets: NativeTargetSummary[] = []
|
|
541
|
+
for (const [id, obj] of Object.entries(objects)) {
|
|
542
|
+
if (isRecord(obj) && obj.isa === 'PBXNativeTarget' && typeof obj.name === 'string') {
|
|
543
|
+
targets.push({
|
|
544
|
+
id,
|
|
545
|
+
name: obj.name,
|
|
546
|
+
productType: typeof obj.productType === 'string' ? obj.productType : undefined,
|
|
547
|
+
buildConfigurationList:
|
|
548
|
+
typeof obj.buildConfigurationList === 'string'
|
|
549
|
+
? obj.buildConfigurationList
|
|
550
|
+
: undefined,
|
|
551
|
+
})
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
const applicationTargetNames = new Set(
|
|
555
|
+
targets
|
|
556
|
+
.filter((t) => t.productType === 'com.apple.product-type.application')
|
|
557
|
+
.map((t) => t.name),
|
|
390
558
|
)
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
559
|
+
if (applicationTargetNames.size === 0) {
|
|
560
|
+
for (const match of pbxproj.matchAll(
|
|
561
|
+
/isa = PBXNativeTarget;[^}]*?name = "?([^";]+)"?;[^}]*?productType = "com\.apple\.product-type\.application";/g,
|
|
562
|
+
)) {
|
|
563
|
+
applicationTargetNames.add(match[1])
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
let targetName: string | null = null
|
|
568
|
+
if (iosTarget) {
|
|
569
|
+
if (applicationTargetNames.has(iosTarget)) {
|
|
570
|
+
targetName = iosTarget
|
|
571
|
+
} else {
|
|
572
|
+
return null
|
|
573
|
+
}
|
|
574
|
+
} else if (applicationTargetNames.size === 1) {
|
|
575
|
+
targetName = [...applicationTargetNames][0]!
|
|
576
|
+
} else if (applicationTargetNames.size > 1) {
|
|
577
|
+
const appDelegatePattern = /(?:^|\/)ios\/([^/]+)\/AppDelegate\.(?:swift|mm|m)$/
|
|
578
|
+
const delegateTargets = Object.keys(files)
|
|
394
579
|
.filter((path) => !path.includes('/Pods/'))
|
|
395
580
|
.map((path) => path.match(appDelegatePattern)?.[1])
|
|
396
|
-
.
|
|
397
|
-
|
|
581
|
+
.filter(
|
|
582
|
+
(name): name is string =>
|
|
583
|
+
typeof name === 'string' && applicationTargetNames.has(name),
|
|
584
|
+
)
|
|
585
|
+
if (delegateTargets.length === 1) {
|
|
586
|
+
targetName = delegateTargets[0]!
|
|
587
|
+
} else {
|
|
588
|
+
return null
|
|
589
|
+
}
|
|
590
|
+
} else {
|
|
591
|
+
return null
|
|
592
|
+
}
|
|
398
593
|
|
|
399
|
-
const
|
|
400
|
-
|
|
594
|
+
const selectedTarget = targets.find((t) => t.name === targetName)
|
|
595
|
+
const settings: Record<string, string> = {
|
|
596
|
+
TARGET_NAME: targetName,
|
|
597
|
+
PRODUCT_NAME: targetName,
|
|
598
|
+
}
|
|
599
|
+
for (const obj of Object.values(objects)) {
|
|
600
|
+
if (
|
|
601
|
+
isRecord(obj) &&
|
|
602
|
+
obj.isa === 'PBXProject' &&
|
|
603
|
+
typeof obj.buildConfigurationList === 'string'
|
|
604
|
+
) {
|
|
605
|
+
const listObj = objects[obj.buildConfigurationList]
|
|
606
|
+
if (isRecord(listObj) && Array.isArray(listObj.buildConfigurations)) {
|
|
607
|
+
for (const configId of listObj.buildConfigurations) {
|
|
608
|
+
if (typeof configId === 'string') {
|
|
609
|
+
const configObj = objects[configId]
|
|
610
|
+
if (
|
|
611
|
+
isRecord(configObj) &&
|
|
612
|
+
configObj.name === 'Release' &&
|
|
613
|
+
isRecord(configObj.buildSettings)
|
|
614
|
+
) {
|
|
615
|
+
for (const [k, v] of Object.entries(configObj.buildSettings)) {
|
|
616
|
+
if (typeof v === 'string') settings[k] = v
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
if (selectedTarget?.buildConfigurationList) {
|
|
625
|
+
const listObj = objects[selectedTarget.buildConfigurationList]
|
|
626
|
+
if (isRecord(listObj) && Array.isArray(listObj.buildConfigurations)) {
|
|
627
|
+
for (const configId of listObj.buildConfigurations) {
|
|
628
|
+
if (typeof configId === 'string') {
|
|
629
|
+
const configObj = objects[configId]
|
|
630
|
+
if (
|
|
631
|
+
isRecord(configObj) &&
|
|
632
|
+
configObj.name === 'Release' &&
|
|
633
|
+
isRecord(configObj.buildSettings)
|
|
634
|
+
) {
|
|
635
|
+
for (const [k, v] of Object.entries(configObj.buildSettings)) {
|
|
636
|
+
if (typeof v === 'string') settings[k] = v
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
} else {
|
|
643
|
+
const legacy = appTargetReleaseSettings(
|
|
644
|
+
pbxproj,
|
|
645
|
+
targetName,
|
|
646
|
+
`${targetName}/Info.plist`,
|
|
647
|
+
)
|
|
648
|
+
if (legacy) Object.assign(settings, legacy)
|
|
649
|
+
}
|
|
401
650
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
651
|
+
let plist: string | undefined
|
|
652
|
+
const infoPlistPath = settings.INFOPLIST_FILE
|
|
653
|
+
if (infoPlistPath) {
|
|
654
|
+
const normalized = infoPlistPath.replace(/^"|"$/g, '')
|
|
655
|
+
plist =
|
|
656
|
+
files[`ios/${normalized}`] ??
|
|
657
|
+
files[normalized] ??
|
|
658
|
+
Object.entries(files).find(([k]) => k.endsWith(`/${normalized}`))?.[1]
|
|
659
|
+
}
|
|
660
|
+
if (!plist) {
|
|
661
|
+
plist =
|
|
662
|
+
files[`ios/${targetName}/Info.plist`] ??
|
|
663
|
+
files[`${targetName}/Info.plist`] ??
|
|
664
|
+
Object.entries(files).find(([k]) => k.endsWith(`/${targetName}/Info.plist`))?.[1]
|
|
665
|
+
}
|
|
666
|
+
if (!plist) return null
|
|
408
667
|
|
|
409
668
|
const bundleIdentifier = identityFieldFrom(
|
|
410
669
|
settings,
|
|
@@ -444,6 +703,19 @@ function nativeAppIdentityFromIos(
|
|
|
444
703
|
// with the build-side parser; the browser transport has no XML dependency.
|
|
445
704
|
const dictionary = parseInfoPlist(plist)
|
|
446
705
|
if (!isRecord(dictionary)) throw new Error('native app Info.plist is not a dictionary')
|
|
706
|
+
const declaredDisplayName = dictionary.CFBundleDisplayName
|
|
707
|
+
const applicationDisplayName =
|
|
708
|
+
typeof declaredDisplayName === 'string'
|
|
709
|
+
? resolveBuildSetting(declaredDisplayName, settings)
|
|
710
|
+
: undefined
|
|
711
|
+
if (applicationDisplayName === null)
|
|
712
|
+
throw new Error('native app Info.plist CFBundleDisplayName is unresolved')
|
|
713
|
+
const declaredBackgroundColor = dictionary.RCTRootViewBackgroundColor
|
|
714
|
+
const rootViewBackgroundColor =
|
|
715
|
+
typeof declaredBackgroundColor === 'number' &&
|
|
716
|
+
Number.isInteger(declaredBackgroundColor)
|
|
717
|
+
? declaredBackgroundColor
|
|
718
|
+
: undefined
|
|
447
719
|
const icons = dictionary.CFBundleIcons
|
|
448
720
|
const alternates = isRecord(icons) ? icons.CFBundleAlternateIcons : undefined
|
|
449
721
|
const alternateIconNames = new Set<string>()
|
|
@@ -470,6 +742,48 @@ function nativeAppIdentityFromIos(
|
|
|
470
742
|
Array.isArray(intentIds) && intentIds.every((value) => typeof value === 'string')
|
|
471
743
|
? intentIds.map((value: string) => resolveBuildSetting(value, settings))
|
|
472
744
|
: []
|
|
745
|
+
const backgroundIds = dictionary.BGTaskSchedulerPermittedIdentifiers
|
|
746
|
+
const backgroundTaskIdentifiers =
|
|
747
|
+
Array.isArray(backgroundIds) &&
|
|
748
|
+
backgroundIds.every((value) => typeof value === 'string')
|
|
749
|
+
? backgroundIds.map((value: string) => resolveBuildSetting(value, settings))
|
|
750
|
+
: []
|
|
751
|
+
const declaredModes = dictionary.UIBackgroundModes
|
|
752
|
+
const backgroundModes =
|
|
753
|
+
Array.isArray(declaredModes) &&
|
|
754
|
+
declaredModes.every((value) => typeof value === 'string')
|
|
755
|
+
? declaredModes.map((value: string) => resolveBuildSetting(value, settings))
|
|
756
|
+
: []
|
|
757
|
+
// the root orientation controller casts each plist list as a whole [String].
|
|
758
|
+
const screenOrientationLists = [
|
|
759
|
+
'UISupportedInterfaceOrientations',
|
|
760
|
+
'UISupportedInterfaceOrientations~ipad',
|
|
761
|
+
].map((key) => {
|
|
762
|
+
const list = dictionary[key]
|
|
763
|
+
if (!Array.isArray(list) || !list.every((value) => typeof value === 'string'))
|
|
764
|
+
return []
|
|
765
|
+
return list.map((value: string) => {
|
|
766
|
+
const resolved = resolveBuildSetting(value, settings)
|
|
767
|
+
if (resolved === null) throw new Error(`native app Info.plist ${key} is unresolved`)
|
|
768
|
+
return resolved
|
|
769
|
+
})
|
|
770
|
+
})
|
|
771
|
+
const [supportedInterfaceOrientations, ipadSupportedInterfaceOrientations] =
|
|
772
|
+
screenOrientationLists
|
|
773
|
+
const declaredDefaultOrientationMask = dictionary.EXDefaultScreenOrientationMask
|
|
774
|
+
const defaultScreenOrientationMask =
|
|
775
|
+
typeof declaredDefaultOrientationMask === 'string'
|
|
776
|
+
? resolveBuildSetting(declaredDefaultOrientationMask, settings)
|
|
777
|
+
: undefined
|
|
778
|
+
if (defaultScreenOrientationMask === null)
|
|
779
|
+
throw new Error('native app Info.plist EXDefaultScreenOrientationMask is unresolved')
|
|
780
|
+
const declaredShareGroup = dictionary.ExpoShareIntoAppGroupId
|
|
781
|
+
const shareIntoAppGroupId =
|
|
782
|
+
typeof declaredShareGroup === 'string'
|
|
783
|
+
? resolveBuildSetting(declaredShareGroup, settings)
|
|
784
|
+
: undefined
|
|
785
|
+
if (shareIntoAppGroupId === null)
|
|
786
|
+
throw new Error('native app Info.plist ExpoShareIntoAppGroupId is unresolved')
|
|
473
787
|
const querySchemes = dictionary.LSApplicationQueriesSchemes
|
|
474
788
|
if (querySchemes !== undefined && !Array.isArray(querySchemes)) {
|
|
475
789
|
throw new Error('native app Info.plist LSApplicationQueriesSchemes is not an array')
|
|
@@ -483,7 +797,11 @@ function nativeAppIdentityFromIos(
|
|
|
483
797
|
})
|
|
484
798
|
const permissionUsageDescriptions: Record<string, unknown> = {}
|
|
485
799
|
for (const [key, value] of Object.entries(dictionary)) {
|
|
486
|
-
if (
|
|
800
|
+
if (
|
|
801
|
+
!/^NS.*UsageDescription$/.test(key) &&
|
|
802
|
+
key !== 'NSLocationTemporaryUsageDescriptionDictionary'
|
|
803
|
+
)
|
|
804
|
+
continue
|
|
487
805
|
// retain non-string plist values: the native factory checks key presence.
|
|
488
806
|
if (typeof value !== 'string') {
|
|
489
807
|
permissionUsageDescriptions[key] = value
|
|
@@ -509,14 +827,28 @@ function nativeAppIdentityFromIos(
|
|
|
509
827
|
|
|
510
828
|
return {
|
|
511
829
|
applicationName,
|
|
830
|
+
...(applicationDisplayName === undefined ? {} : { applicationDisplayName }),
|
|
831
|
+
...(rootViewBackgroundColor === undefined ? {} : { rootViewBackgroundColor }),
|
|
512
832
|
bundleName,
|
|
513
833
|
appVersion,
|
|
514
834
|
buildVersion,
|
|
515
835
|
bundleIdentifier,
|
|
516
836
|
platform: 'ios',
|
|
837
|
+
supportedInterfaceOrientations,
|
|
838
|
+
ipadSupportedInterfaceOrientations,
|
|
839
|
+
...(defaultScreenOrientationMask === undefined
|
|
840
|
+
? {}
|
|
841
|
+
: { defaultScreenOrientationMask }),
|
|
517
842
|
alternateIconNames: [...alternateIconNames],
|
|
518
843
|
permissionUsageDescriptions,
|
|
519
844
|
urlQuerySchemes,
|
|
845
|
+
...(shareIntoAppGroupId === undefined ? {} : { shareIntoAppGroupId }),
|
|
846
|
+
backgroundTaskIdentifiers: backgroundTaskIdentifiers.every((value) => value !== null)
|
|
847
|
+
? backgroundTaskIdentifiers
|
|
848
|
+
: [],
|
|
849
|
+
backgroundModes: backgroundModes.every((value) => value !== null)
|
|
850
|
+
? backgroundModes
|
|
851
|
+
: [],
|
|
520
852
|
appIntentIdentifiers: appIntentIdentifiers.every((value) => value !== null)
|
|
521
853
|
? appIntentIdentifiers
|
|
522
854
|
: [],
|
|
@@ -535,13 +867,14 @@ export function canExtractNativeAppIdentity(platform: unknown): platform is 'ios
|
|
|
535
867
|
// read the identity a bundle builder transports. files are project-relative
|
|
536
868
|
// paths to their text, so both a checked-out app directory and a stored
|
|
537
869
|
// project file map resolve identically. null when the project carries no
|
|
538
|
-
// resolvable native config
|
|
870
|
+
// resolvable native config.
|
|
539
871
|
export function extractNativeAppIdentityFromFiles(
|
|
540
872
|
files: NativeAppIdentityFiles,
|
|
541
|
-
platform:
|
|
873
|
+
platform: unknown,
|
|
542
874
|
parseInfoPlist: (source: string) => unknown,
|
|
875
|
+
iosTarget?: string,
|
|
543
876
|
): NativeAppIdentity | null {
|
|
544
877
|
return canExtractNativeAppIdentity(platform)
|
|
545
|
-
? nativeAppIdentityFromIos(files, parseInfoPlist)
|
|
878
|
+
? nativeAppIdentityFromIos(files, parseInfoPlist, iosTarget)
|
|
546
879
|
: null
|
|
547
880
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// read native default initialization inputs before the guest Firebase SDK starts.
|
|
2
2
|
// expose only FirebaseOptions, never a partner-specific extra configuration.
|
|
3
|
+
import { spawnSync } from 'node:child_process'
|
|
3
4
|
import fs from 'node:fs'
|
|
4
|
-
import
|
|
5
|
+
import os from 'node:os'
|
|
5
6
|
import path from 'node:path'
|
|
6
7
|
import { isRecord } from './is-record'
|
|
7
8
|
import { parsePlistSource } from './plist'
|
|
@@ -10,6 +11,7 @@ import { listXcodeAppTargets, readXcodeAppTarget } from './xcode-project'
|
|
|
10
11
|
export function readNativeFirebaseConfig(
|
|
11
12
|
projectRoot: string,
|
|
12
13
|
platforms: readonly string[] = ['ios', 'android'],
|
|
14
|
+
iosTarget?: string,
|
|
13
15
|
) {
|
|
14
16
|
const result: Record<string, unknown> = {}
|
|
15
17
|
let config: Record<string, unknown> = {}
|
|
@@ -30,15 +32,45 @@ export function readNativeFirebaseConfig(
|
|
|
30
32
|
'app.config.mjs',
|
|
31
33
|
].some((name) => fs.existsSync(path.join(projectRoot, name)))
|
|
32
34
|
if (staticExpo || dynamicExpo) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
// expo's synchronous ESM/TypeScript loader requires Node's module evaluator.
|
|
36
|
+
// a private result file keeps authored console output off the configuration wire.
|
|
37
|
+
const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'peach-expo-config-'))
|
|
38
|
+
const resultPath = path.join(directory, 'config.json')
|
|
39
|
+
try {
|
|
40
|
+
const child = spawnSync(
|
|
41
|
+
'node',
|
|
42
|
+
[
|
|
43
|
+
'--input-type=commonjs',
|
|
44
|
+
'-e',
|
|
45
|
+
`const { createRequire } = require('node:module');
|
|
46
|
+
const { writeFileSync } = require('node:fs');
|
|
47
|
+
const { join } = require('node:path');
|
|
48
|
+
const root = process.argv[1];
|
|
49
|
+
const { getConfig } = createRequire(join(root, 'package.json'))('@expo/config');
|
|
50
|
+
const result = JSON.stringify(getConfig(root, { skipSDKVersionRequirement: true }).exp);
|
|
51
|
+
if (Buffer.byteLength(result) > 1024 * 1024) throw new Error('Expo native configuration exceeds 1 MiB.');
|
|
52
|
+
writeFileSync(process.argv[2], result, { mode: 0o600 });`,
|
|
53
|
+
path.resolve(projectRoot),
|
|
54
|
+
resultPath,
|
|
55
|
+
],
|
|
56
|
+
{
|
|
57
|
+
cwd: projectRoot,
|
|
58
|
+
encoding: 'utf8',
|
|
59
|
+
stdio: ['ignore', 'ignore', 'pipe'],
|
|
60
|
+
timeout: 30_000,
|
|
61
|
+
maxBuffer: 1024 * 1024,
|
|
62
|
+
},
|
|
63
|
+
)
|
|
64
|
+
if (child.error) throw child.error
|
|
65
|
+
if (child.status !== 0)
|
|
66
|
+
throw new Error(child.stderr || 'Expo native configuration evaluation failed.')
|
|
67
|
+
const resolved: unknown = JSON.parse(fs.readFileSync(resultPath, 'utf8'))
|
|
68
|
+
if (!isRecord(resolved))
|
|
69
|
+
throw new Error('Expo native configuration is unavailable.')
|
|
70
|
+
config = resolved
|
|
71
|
+
} finally {
|
|
72
|
+
fs.rmSync(directory, { recursive: true, force: true })
|
|
73
|
+
}
|
|
42
74
|
}
|
|
43
75
|
const ios = config.ios
|
|
44
76
|
if (
|
|
@@ -55,10 +87,17 @@ export function readNativeFirebaseConfig(
|
|
|
55
87
|
if (projects.length === 1) {
|
|
56
88
|
const xcodeproj = path.join(iosRoot, projects[0].name)
|
|
57
89
|
const appTargets = listXcodeAppTargets(xcodeproj)
|
|
58
|
-
if (appTargets.length > 1)
|
|
90
|
+
if (!iosTarget && appTargets.length > 1)
|
|
59
91
|
throw new Error('native Firebase configuration requires a selected app target')
|
|
60
|
-
if (appTargets.length === 1) {
|
|
61
|
-
const app = readXcodeAppTarget(
|
|
92
|
+
if (iosTarget || appTargets.length === 1) {
|
|
93
|
+
const app = readXcodeAppTarget(
|
|
94
|
+
xcodeproj,
|
|
95
|
+
iosTarget ?? appTargets[0],
|
|
96
|
+
undefined,
|
|
97
|
+
{
|
|
98
|
+
requireSources: false,
|
|
99
|
+
},
|
|
100
|
+
)
|
|
62
101
|
const delegates = app.allSources.filter((file) =>
|
|
63
102
|
/^AppDelegate\.(swift|mm|m)$/.test(path.basename(file)),
|
|
64
103
|
)
|
|
@@ -69,7 +108,7 @@ export function readNativeFirebaseConfig(
|
|
|
69
108
|
token.startsWith('"') ? '""' : token.replace(/[^\n]/g, ' '),
|
|
70
109
|
)
|
|
71
110
|
const launch =
|
|
72
|
-
/(?:\bfunc\s+application\s*\([\s\S]*?didFinishLaunchingWithOptions[\s\S]*?\)\s*->\s*Bool|^-\s*\(BOOL\)\s*application\s*:[\s\S]*?didFinishLaunchingWithOptions[
|
|
111
|
+
/(?:\bfunc\s+application\s*\([\s\S]*?didFinishLaunchingWithOptions[\s\S]*?\)\s*->\s*Bool|^-\s*\(BOOL\)\s*application\s*:[\s\S]*?didFinishLaunchingWithOptions[^{]*)\s*\{/m.exec(
|
|
73
112
|
source,
|
|
74
113
|
)
|
|
75
114
|
if (!launch) return false
|
|
@@ -86,9 +125,24 @@ export function readNativeFirebaseConfig(
|
|
|
86
125
|
if (token === '}') depth -= 1
|
|
87
126
|
if (depth === 0) return false
|
|
88
127
|
}
|
|
128
|
+
let conditionalDepth = 0
|
|
129
|
+
for (const directive of before.matchAll(
|
|
130
|
+
/^\s*#\s*(if|ifdef|ifndef|elseif|elif|else|endif)\b/gm,
|
|
131
|
+
)) {
|
|
132
|
+
const kind = directive[1]
|
|
133
|
+
if (kind === 'if' || kind === 'ifdef' || kind === 'ifndef') {
|
|
134
|
+
conditionalDepth += 1
|
|
135
|
+
} else if (conditionalDepth === 0) {
|
|
136
|
+
conditionalDepth = -1
|
|
137
|
+
break
|
|
138
|
+
} else if (kind === 'endif') {
|
|
139
|
+
conditionalDepth -= 1
|
|
140
|
+
}
|
|
141
|
+
}
|
|
89
142
|
if (
|
|
90
143
|
depth !== 1 ||
|
|
91
|
-
|
|
144
|
+
conditionalDepth !== 0 ||
|
|
145
|
+
/\b(?:return|throw)\b/.test(before)
|
|
92
146
|
)
|
|
93
147
|
throw new Error(
|
|
94
148
|
'native Firebase initialization must be unconditional in the app launch method',
|
|
@@ -148,6 +148,12 @@ export const NATIVE_SEAM_MANIFEST: NativeSeamEntry[] = [
|
|
|
148
148
|
notes:
|
|
149
149
|
'ASAuthorizationAppleIDButton native view — render the system button surface while upstream AppleAuthenticationButton.tsx remains unchanged',
|
|
150
150
|
},
|
|
151
|
+
{
|
|
152
|
+
pkg: 'expo-asset',
|
|
153
|
+
seamBasenames: ['resolveAssetSource'],
|
|
154
|
+
target: path.resolve(NATIVE_SEAMS_DIR, '../rn-libraries/resolveAssetSource.ts'),
|
|
155
|
+
notes: 'the native Image resolver and transformer registration share one owner',
|
|
156
|
+
},
|
|
151
157
|
{
|
|
152
158
|
pkg: '@bam.tech/react-native-image-resizer',
|
|
153
159
|
// a Metro bundle reaches the same seam through the ImageResizer
|