peachsim 0.1.1404 → 0.1.1463
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/LICENSE +8 -4
- package/README.md +22 -2
- package/cli/app-fonts.ts +50 -44
- package/cli/bin.ts +5 -4
- package/cli/bridge-diagnostics.ts +5 -0
- package/cli/bridge-flow-runner.ts +21 -13
- package/cli/cloud-client.ts +4 -3
- package/cli/commands/control.ts +155 -123
- package/cli/commands/daemon-mac-app.ts +3 -3
- package/cli/commands/daemon.ts +2 -2
- package/cli/commands/do-chain.ts +9 -2
- package/cli/commands/electron.ts +4 -1
- package/cli/commands/inspect/core.ts +1 -1
- package/cli/commands/inspect/settle.ts +19 -7
- package/cli/commands/inspect/settling.ts +92 -56
- package/cli/commands/inspect/wait-idle.ts +21 -9
- package/cli/commands/inspect/wait-ready.ts +22 -8
- package/cli/commands/inspect.ts +101 -134
- package/cli/commands/setup.ts +26 -16
- package/cli/commands/upgrade.ts +53 -9
- package/cli/desktop-companion.ts +1 -1
- package/cli/drivers/playwright-sim-host.ts +22 -13
- package/cli/drivers/playwright.ts +3 -3
- package/cli/main.ts +14 -5
- package/cli/outbound-endpoints.ts +1 -9
- package/detox/index.ts +6 -1
- 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 +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +3 -3
- package/dist-lib/bridge-contract.mjs +3 -3
- package/dist-lib/bundle-channel.cjs +322 -274
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/config.mjs +1 -1
- package/dist-lib/detox/index.cjs +843 -46
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/expo-swift-bundle.cjs +69 -33
- package/dist-lib/expo-swift-metadata.cjs +1 -1
- package/dist-lib/expo-swift-metadata.mjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +3650 -3528
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +327 -123
- 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 +10 -5
- 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 +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +49 -47
- package/dist-lib/native-app-identity-project.cjs +1 -1
- package/dist-lib/native-app-identity-project.mjs +1 -1
- package/dist-lib/native-app-identity.cjs +1 -1
- package/dist-lib/native-app-identity.mjs +1 -1
- 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 +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +23 -17
- package/dist-lib/sdk.cjs +99 -61
- package/dist-lib/sdk.mjs +97 -61
- package/dist-lib/skills.cjs +2959 -2780
- package/dist-lib/swift-compile.cjs +26 -12
- package/dist-lib/swift-compile.mjs +26 -12
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +2 -2
- package/dist-lib/swift-submit.mjs +2 -2
- package/dist-lib/swift-toolchain.cjs +1 -1
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite-swift.cjs +66 -31
- package/dist-lib/vite.cjs +1 -1
- package/dist-lib/worklet-executable.cjs +1 -1
- package/dist-lib/worklet-executable.mjs +1 -1
- package/kotlin/AppSources/android/view/Window.kt +2 -0
- package/kotlin/AppSources/dev/peach/app/PeachApp.kt +1 -1
- package/kotlin/ComposeSources/PeachComposeHost.kt +35 -9
- package/kotlin/ExpoComposeSources/dev/peach/expo/PeachExpoCompose.kt +2 -2
- package/kotlin/ExpoSources/dev/peach/expo/PeachExpoRuntime.kt +9 -6
- package/kotlin/ExpoSources/dev/peach/expo/PeachExpoTypes.kt +4 -4
- package/kotlin/ExpoSources/expo/modules/kotlin/modules/Module.kt +2 -2
- package/kotlin/ExpoSources/expo/modules/kotlin/viewevent/ViewEvent.kt +22 -8
- package/kotlin/ExpoSources/expo/modules/kotlin/views/ExpoView.kt +0 -3
- package/kotlin/ExpoSources/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +10 -9
- package/kotlin/ExpoSources/expo/modules/kotlin/views/ViewProps.kt +6 -5
- package/kotlin/fixtures/import-drawing/Drawing.d.kt.ts +7 -0
- package/kotlin/fixtures/import-drawing/Drawing.kt +101 -0
- package/kotlin/fixtures/import-drawing/ImportDrawing.native.tsx +18 -0
- package/kotlin/fixtures/import-drawing/README.md +34 -0
- package/kotlin/fixtures/import-drawing/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-drawing/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-drawing/package.json +23 -0
- package/kotlin/fixtures/import-drawing/tsconfig.json +20 -0
- package/kotlin/fixtures/import-drawing/vite.config.ts +20 -0
- package/kotlin/fixtures/import-scroll/ImportNested.native.tsx +10 -0
- package/kotlin/fixtures/import-scroll/Nested.d.kt.ts +4 -0
- package/kotlin/fixtures/import-scroll/README.md +15 -0
- package/kotlin/fixtures/import-scroll/app/nested+spa.tsx +1 -0
- package/kotlin/fixtures/import-values/ImportValues.native.tsx +26 -0
- package/kotlin/fixtures/import-values/README.md +6 -1
- package/kotlin/fixtures/import-values/Values.d.kt.ts +4 -0
- package/kotlin/fixtures/import-values/Values.kt +18 -0
- package/kotlin/tools/expo-types.main.kts +17 -5
- package/package.json +2 -1
- package/scripts/dev-server-scanner.ts +33 -23
- package/src/assetCatalogContract.ts +7 -0
- package/src/bridge-contract.ts +21 -3
- package/src/connect.ts +18 -5
- package/src/desktop-host-delivery.ts +33 -3
- package/src/expo-swift-host.ts +6 -3
- package/src/host/bridge-host.ts +2 -0
- package/src/host/fetch-proxy-transport.ts +8 -0
- package/src/kotlin-host.ts +11 -5
- package/src/native-firebase-config.ts +95 -54
- package/src/process-output.ts +16 -0
- package/src/sdk.ts +6 -1
- package/src/sim-client.ts +6 -1
- package/src/swift-compile.ts +36 -15
- package/src/swift-distribution.lock.json +8 -8
- package/src/swift-standin-emit.ts +10 -1
- package/src/swift-standins.ts +21 -7
- package/src/swift-submit.ts +6 -1
- /package/kotlin/fixtures/{kotlin-app-variants → import-scroll}/Nested.kt +0 -0
package/LICENSE
CHANGED
|
@@ -5,10 +5,14 @@ Copyright (c) Tamagui LLC. All rights reserved.
|
|
|
5
5
|
This package (peachsim) is proprietary software of Tamagui LLC, licensed under
|
|
6
6
|
the Peach Software License Agreement: https://peachsim.com/legal/license
|
|
7
7
|
|
|
8
|
-
In summary (the agreement governs):
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
In summary (the agreement governs): Seed is free for individuals and companies
|
|
9
|
+
under 10 people and under $1M yearly revenue, including commercial desktop and
|
|
10
|
+
local use. A company at or above either limit needs Team while it has under
|
|
11
|
+
100 people and under $10M yearly revenue, or Enterprise at or above either of
|
|
12
|
+
those limits. Members, agents, API keys and local simulators are unlimited.
|
|
13
|
+
Company size is self-reported and enforced through the license terms only.
|
|
14
|
+
Embedding or redistributing the software requires a separate written agreement
|
|
15
|
+
with Tamagui LLC.
|
|
12
16
|
|
|
13
17
|
Versions of this package published before this license change remain under
|
|
14
18
|
the license they were published with.
|
package/README.md
CHANGED
|
@@ -11,7 +11,8 @@ installation. The `peachsim` npm package contains bundler plugins, testing
|
|
|
11
11
|
drivers, and library exports; its only command, `npx peachsim`, runs that same
|
|
12
12
|
installer from the copy of `install.sh` it ships.
|
|
13
13
|
|
|
14
|
-
The executable updates itself with `peach upgrade
|
|
14
|
+
The executable updates itself with `peach upgrade`, which then restarts a running
|
|
15
|
+
background daemon onto the new executable and runtime. Successful interactive human
|
|
15
16
|
commands refresh a cached stable CLI version in a detached process at most once
|
|
16
17
|
every 20 hours. A newer version produces one short notice on stderr, once per
|
|
17
18
|
version and no more than weekly. CI, agents, JSON output, pipes, and
|
|
@@ -151,7 +152,8 @@ graph TD
|
|
|
151
152
|
**The CLI process** (`cli/bin.ts` routes, `cli/main.ts` parses argv) lazy-imports
|
|
152
153
|
exactly one command module per run. Bare `peach` opens ConnectRN, whose simulator UI discovers
|
|
153
154
|
running React Native development servers. The first human run offers the
|
|
154
|
-
recommended background service and
|
|
155
|
+
recommended background service and simulator window; on Mac, Desktop uses an
|
|
156
|
+
already installed app. It then opens the simulator
|
|
155
157
|
before asking about private diagnostics or an optional repository install. `peach open`
|
|
156
158
|
ensures the engine runtime exists when the bridge supplies the shell and starts
|
|
157
159
|
a local foreground bridge when no daemon is reachable, then opens a `WsBridge`
|
|
@@ -173,6 +175,16 @@ browser launch inside a Team Machine session and prints the URL plus
|
|
|
173
175
|
`--driver playwright --headless` guidance. Interactive human launches keep
|
|
174
176
|
their system browser behavior.
|
|
175
177
|
|
|
178
|
+
For apps using `react-native-config`, open with `peach open <app-port> --load-env`.
|
|
179
|
+
This reads the local project's native dotenv values for `RNCConfigModule`;
|
|
180
|
+
`runtimeConfig.env` populates the guest's `process.env` independently. Starting a
|
|
181
|
+
sidecar or supplying process environment variables does not select the app's
|
|
182
|
+
native API roots. Verify the mounted app's `Config` values and captured request
|
|
183
|
+
destinations before driving a network flow. Without `--load-env`, the native
|
|
184
|
+
config dictionary is empty and the app can select its own public defaults.
|
|
185
|
+
Preserve failures from those endpoints rather than remapping them to a successful
|
|
186
|
+
local response. The same flag is available on `peach flow`.
|
|
187
|
+
|
|
176
188
|
**The daemon is one process** — `SootSimBridgeHost` (`src/host/bridge-host.ts`).
|
|
177
189
|
`peach serve` runs it in the foreground; the background daemon is the *same
|
|
178
190
|
process* wrapped with autostart and the `~/.peach/daemon.json` lockfile. It is
|
|
@@ -194,6 +206,9 @@ shell's bridge world without reading the other process's lockfile directory.
|
|
|
194
206
|
An explicit `--port` also participates in `--sim` ownership discovery even
|
|
195
207
|
without a local heartbeat record. The bridge must report that simulator as
|
|
196
208
|
open; a port that names another simulator's world is rejected.
|
|
209
|
+
SDK `connect({ sim })` and batched `do --then` actions use that same ownership
|
|
210
|
+
discovery. An inferred default port does not override the named sim's world;
|
|
211
|
+
an explicit SDK port or CLI `--port` retains the ownership check.
|
|
197
212
|
|
|
198
213
|
**The sim** is a browser/Electron *page* launched by a CLI driver. Inside that
|
|
199
214
|
page run three workers: the **shell worker** owns device and native state, the
|
|
@@ -278,6 +293,11 @@ library path, so no host needs `apt-get` or root. The bundle is pinned in
|
|
|
278
293
|
`cli/drivers/linux-browser-libs.lock.json`; `bun scripts/linux-browser-libs.ts
|
|
279
294
|
resolve` re-pins it, and the CLI release publishes any bundle the bucket lacks.
|
|
280
295
|
|
|
296
|
+
On Mac, headless launches attach an installed compatible native host. With no
|
|
297
|
+
host, they render in the browser without downloading or placing the app. The
|
|
298
|
+
browser logo menu offers the app; `peach desktop install --native` remains the
|
|
299
|
+
explicit CLI installer. Linux still acquires its standalone host under `~/.peach`.
|
|
300
|
+
|
|
281
301
|
Headed launches on Linux use full Chromium, whose extra libraries the bundle
|
|
282
302
|
also carries. Later opens reuse that sim and
|
|
283
303
|
reload it at the requested target. Use `peach do reload` when the target has not
|
package/cli/app-fonts.ts
CHANGED
|
@@ -22,6 +22,11 @@ export type DiscoveredAppFontSpec = ConfigPluginFontSpec
|
|
|
22
22
|
|
|
23
23
|
type ExpoConfigGetter = (dir: string, opts: Record<string, unknown>) => { exp?: unknown }
|
|
24
24
|
|
|
25
|
+
// every font file is found on disk, so the asset urls are decided here and
|
|
26
|
+
// never by asking the dev server: metro's asset endpoint resolves a path
|
|
27
|
+
// against its config.projectRoot, which is the root it advertises and the one
|
|
28
|
+
// projectDir names. a reachability request would make the result depend on how
|
|
29
|
+
// busy the dev server is, and a cold build answers late enough to drop fonts.
|
|
25
30
|
export function discoverNativeLinkedAppFonts(opts: {
|
|
26
31
|
bundleUrl: string
|
|
27
32
|
projectDir: string
|
|
@@ -29,13 +34,35 @@ export function discoverNativeLinkedAppFonts(opts: {
|
|
|
29
34
|
}): DiscoveredAppFontSpec[] {
|
|
30
35
|
const metroOrigin = loopbackOriginOf(opts.bundleUrl)
|
|
31
36
|
if (!metroOrigin) return []
|
|
32
|
-
|
|
37
|
+
const specs = metroFontSpecsFromPaths(
|
|
38
|
+
projectRelativeFontPaths(opts.projectDir, discoverNativeLinkedAppFontPaths(opts)),
|
|
39
|
+
metroOrigin,
|
|
40
|
+
)
|
|
41
|
+
// a family linked from more than one file keeps the first declaration.
|
|
42
|
+
const byFamily = new Map<string, DiscoveredAppFontSpec>()
|
|
43
|
+
for (const spec of specs)
|
|
44
|
+
if (!byFamily.has(spec.family)) byFamily.set(spec.family, spec)
|
|
45
|
+
return [...byFamily.values()]
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function projectRelativeFontPaths(projectDir: string, fontPaths: string[]): string[] {
|
|
49
|
+
return fontPaths.map((fontPath) =>
|
|
50
|
+
path.relative(path.resolve(projectDir), fontPath).split(path.sep).join('/'),
|
|
51
|
+
)
|
|
33
52
|
}
|
|
34
53
|
|
|
54
|
+
function isFile(filePath: string): boolean {
|
|
55
|
+
try {
|
|
56
|
+
return fs.statSync(filePath).isFile()
|
|
57
|
+
} catch {
|
|
58
|
+
return false
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// absolute paths of every existing font file the native app links.
|
|
35
63
|
function discoverNativeLinkedAppFontPaths(opts: {
|
|
36
64
|
projectDir: string
|
|
37
65
|
platform?: string
|
|
38
|
-
bundleUrl?: string
|
|
39
66
|
}): string[] {
|
|
40
67
|
const project = resolveAppProject(opts.projectDir)
|
|
41
68
|
const selectedAppDir = project?.appDir ?? null
|
|
@@ -69,10 +96,14 @@ function discoverNativeLinkedAppFontPaths(opts: {
|
|
|
69
96
|
} catch {}
|
|
70
97
|
}
|
|
71
98
|
|
|
99
|
+
// a declared path with no file behind it links nothing natively.
|
|
72
100
|
const fontPaths = expoFontPathsFromPlugins(
|
|
73
101
|
plugins,
|
|
74
102
|
platform === 'android' ? 'android' : 'ios',
|
|
75
|
-
)
|
|
103
|
+
)
|
|
104
|
+
.slice(0, 256)
|
|
105
|
+
.map((fontPath) => path.resolve(selectedAppDir, fontPath))
|
|
106
|
+
.filter(isFile)
|
|
76
107
|
// the walk is bounded by WORK, not by a clock: at most 64 readdirs, at most 64
|
|
77
108
|
// queued dirs, 4 levels deep, 256 paths. those ceilings are what keep a stray
|
|
78
109
|
// node_modules from being crawled, and no machine can blow through them. a
|
|
@@ -81,7 +112,7 @@ function discoverNativeLinkedAppFontPaths(opts: {
|
|
|
81
112
|
// and no error at all.
|
|
82
113
|
let scannedFontDirectories = 0
|
|
83
114
|
|
|
84
|
-
const collectFontFiles = (root: string
|
|
115
|
+
const collectFontFiles = (root: string): void => {
|
|
85
116
|
const pending: Array<{ dir: string; depth: number }> = [{ dir: root, depth: 0 }]
|
|
86
117
|
let nextIndex = 0
|
|
87
118
|
while (
|
|
@@ -108,8 +139,7 @@ function discoverNativeLinkedAppFontPaths(opts: {
|
|
|
108
139
|
continue
|
|
109
140
|
}
|
|
110
141
|
if (!entry.isFile() || !/\.(ttf|otf|woff|woff2)$/i.test(entry.name)) continue
|
|
111
|
-
|
|
112
|
-
fontPaths.push(path.posix.join(metroPathPrefix, relative))
|
|
142
|
+
fontPaths.push(fullPath)
|
|
113
143
|
if (fontPaths.length >= 256) break
|
|
114
144
|
}
|
|
115
145
|
}
|
|
@@ -145,18 +175,7 @@ function discoverNativeLinkedAppFontPaths(opts: {
|
|
|
145
175
|
const root = path.resolve(selectedAppDir, configuredDir)
|
|
146
176
|
const relativeRoot = path.relative(selectedAppDir, root)
|
|
147
177
|
if (!relativeRoot.startsWith('..') && !path.isAbsolute(relativeRoot)) {
|
|
148
|
-
collectFontFiles(root
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// the bundle path is the entry relative to metro's root, so a bundle at
|
|
152
|
-
// /apps/app/index.bundle served for /repo/apps/app puts that root at /repo.
|
|
153
|
-
const bundleDir = path.posix
|
|
154
|
-
.dirname(opts.bundleUrl ? new URL(opts.bundleUrl).pathname : '/')
|
|
155
|
-
.replace(/^\/+/, '')
|
|
156
|
-
const appRelativeDir = bundleDir.split('/').join(path.sep)
|
|
157
|
-
const metroRootCandidates = [selectedAppDir]
|
|
158
|
-
if (bundleDir && selectedAppDir.endsWith(path.sep + appRelativeDir)) {
|
|
159
|
-
metroRootCandidates.push(selectedAppDir.slice(0, -appRelativeDir.length - 1))
|
|
178
|
+
collectFontFiles(root)
|
|
160
179
|
}
|
|
161
180
|
const vectorIconRequire = createRequire(path.join(selectedAppDir, 'package.json'))
|
|
162
181
|
for (const dependencyName of vectorIconDependencies) {
|
|
@@ -170,18 +189,9 @@ function discoverNativeLinkedAppFontPaths(opts: {
|
|
|
170
189
|
const fontsDir =
|
|
171
190
|
dependencyName === 'react-native-vector-icons' ? 'Fonts' : 'fonts'
|
|
172
191
|
// the package can sit outside the app (a hoisted workspace
|
|
173
|
-
// node_modules or a pnpm store)
|
|
174
|
-
//
|
|
175
|
-
|
|
176
|
-
// path from each candidate root; the reachability check keeps the
|
|
177
|
-
// one metro actually serves.
|
|
178
|
-
const fontsRoot = path.join(packageRoot, fontsDir)
|
|
179
|
-
for (const metroRoot of metroRootCandidates) {
|
|
180
|
-
collectFontFiles(
|
|
181
|
-
fontsRoot,
|
|
182
|
-
path.relative(metroRoot, fontsRoot).split(path.sep).join('/'),
|
|
183
|
-
)
|
|
184
|
-
}
|
|
192
|
+
// node_modules or a pnpm store); its fonts are then served through
|
|
193
|
+
// metro's unstable_path from the watch folder that holds its js.
|
|
194
|
+
collectFontFiles(path.join(packageRoot, fontsDir))
|
|
185
195
|
} catch {}
|
|
186
196
|
}
|
|
187
197
|
}
|
|
@@ -206,7 +216,7 @@ function discoverNativeLinkedAppFontPaths(opts: {
|
|
|
206
216
|
const root = path.resolve(selectedAppDir, assetDir)
|
|
207
217
|
const relativeRoot = path.relative(selectedAppDir, root)
|
|
208
218
|
if (relativeRoot.startsWith('..') || path.isAbsolute(relativeRoot)) continue
|
|
209
|
-
collectFontFiles(root
|
|
219
|
+
collectFontFiles(root)
|
|
210
220
|
}
|
|
211
221
|
}
|
|
212
222
|
}
|
|
@@ -252,16 +262,9 @@ function discoverNativeLinkedAppFontPaths(opts: {
|
|
|
252
262
|
const fontPath = candidates.find((candidate) => {
|
|
253
263
|
const relative = path.relative(selectedAppDir, candidate)
|
|
254
264
|
if (relative.startsWith('..') || path.isAbsolute(relative)) return false
|
|
255
|
-
|
|
256
|
-
return fs.statSync(candidate).isFile()
|
|
257
|
-
} catch {
|
|
258
|
-
return false
|
|
259
|
-
}
|
|
265
|
+
return isFile(candidate)
|
|
260
266
|
})
|
|
261
|
-
if (
|
|
262
|
-
fontPaths.push(
|
|
263
|
-
path.relative(selectedAppDir, fontPath).split(path.sep).join('/'),
|
|
264
|
-
)
|
|
267
|
+
if (fontPath) fontPaths.push(fontPath)
|
|
265
268
|
}
|
|
266
269
|
}
|
|
267
270
|
} catch {}
|
|
@@ -280,10 +283,13 @@ export function readNativeLinkedAppFontsWire(opts: {
|
|
|
280
283
|
throw new Error(`native font project is unavailable: ${opts.projectDir}`)
|
|
281
284
|
}
|
|
282
285
|
return encodeAppFontsWire(
|
|
283
|
-
nativeLinkedFontSpecsFromPaths(
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
286
|
+
nativeLinkedFontSpecsFromPaths(
|
|
287
|
+
projectRelativeFontPaths(opts.projectDir, discoverNativeLinkedAppFontPaths(opts)),
|
|
288
|
+
(fontPath) => {
|
|
289
|
+
const bytes = fs.readFileSync(path.resolve(opts.projectDir, fontPath))
|
|
290
|
+
return `data:${fontContentType(fontPath)};base64,${bytes.toString('base64')}`
|
|
291
|
+
},
|
|
292
|
+
),
|
|
287
293
|
)
|
|
288
294
|
}
|
|
289
295
|
|
package/cli/bin.ts
CHANGED
|
@@ -10,16 +10,17 @@
|
|
|
10
10
|
// whole process, so the CLI itself lives in `./main` and is imported only once
|
|
11
11
|
// none of them has claimed the run.
|
|
12
12
|
|
|
13
|
+
import { exitWithFlushedOutput } from '../src/process-output'
|
|
13
14
|
import { RNX_FORKED_SCRIPT_ENV, RNX_INTERNAL_COMMAND } from './internal-child'
|
|
14
15
|
|
|
15
16
|
if (process.argv[2] === '__shell-init') {
|
|
16
17
|
const { renderRnxShellInit } = await import('./shell-init')
|
|
17
18
|
try {
|
|
18
19
|
process.stdout.write(renderRnxShellInit(process.argv[3] ?? ''))
|
|
19
|
-
|
|
20
|
+
await exitWithFlushedOutput(0)
|
|
20
21
|
} catch (error) {
|
|
21
22
|
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`)
|
|
22
|
-
|
|
23
|
+
await exitWithFlushedOutput(1)
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
26
|
|
|
@@ -34,14 +35,14 @@ if (process.argv[2] === '__cloud-confirm') {
|
|
|
34
35
|
// a box has no claim to keep alive: its simulator is held by the Box page
|
|
35
36
|
// for as long as the box runs, so a shell on a box confirms nothing.
|
|
36
37
|
if (session.service === 'sim') await confirmCloudSimulator(session)
|
|
37
|
-
|
|
38
|
+
await exitWithFlushedOutput(0)
|
|
38
39
|
} catch (error) {
|
|
39
40
|
process.stderr.write(
|
|
40
41
|
`Peach Cloud confirmation failed: ${
|
|
41
42
|
error instanceof Error ? error.message : String(error)
|
|
42
43
|
}\n`,
|
|
43
44
|
)
|
|
44
|
-
|
|
45
|
+
await exitWithFlushedOutput(1)
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
|
|
@@ -201,6 +201,11 @@ export async function printBridgeFailureDiagnostics(
|
|
|
201
201
|
bridge: WsBridge,
|
|
202
202
|
opts: FailureDiagnosticsOptions = {},
|
|
203
203
|
) {
|
|
204
|
+
try {
|
|
205
|
+
if (!(await bridge.listSims()).some((sim) => sim.readyState === 'open')) return
|
|
206
|
+
} catch {
|
|
207
|
+
// an unavailable inventory must not discard the existing diagnostic reads
|
|
208
|
+
}
|
|
204
209
|
try {
|
|
205
210
|
await printBridgeStateSummary(bridge)
|
|
206
211
|
} catch {
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
isPeachAccessibilityTree,
|
|
11
11
|
waitReadyReason,
|
|
12
12
|
} from './commands/inspect/core'
|
|
13
|
-
import { waitForSootsimIdle } from './commands/inspect/settling'
|
|
13
|
+
import { IdleObservationError, waitForSootsimIdle } from './commands/inspect/settling'
|
|
14
14
|
import { callShellCommandWhenReady, getShellState } from './commands/inspect/shared'
|
|
15
15
|
import { PERMISSION_KINDS } from './commands/permissions'
|
|
16
16
|
import { saveCurrentSimId } from './current-sim'
|
|
@@ -2753,18 +2753,26 @@ export class SootSimBridgeFlowRunner {
|
|
|
2753
2753
|
// a screen that never stops proceeds when the budget runs out, as there,
|
|
2754
2754
|
// and names what kept it moving: every such step pays the whole budget.
|
|
2755
2755
|
private async waitForAppToSettle() {
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2756
|
+
try {
|
|
2757
|
+
const result = await waitForSootsimIdle({
|
|
2758
|
+
bridge: this.bridge,
|
|
2759
|
+
simId: this.opts.simId,
|
|
2760
|
+
maxMs: 3000,
|
|
2761
|
+
pollMs: 32,
|
|
2762
|
+
strict: true,
|
|
2763
|
+
paintStill: true,
|
|
2764
|
+
})
|
|
2765
|
+
if (!result.settled) {
|
|
2766
|
+
console.warn(
|
|
2767
|
+
` [flow] still moving after ${result.elapsed}ms: ${result.blockedBy}`,
|
|
2768
|
+
)
|
|
2769
|
+
}
|
|
2770
|
+
} catch (error) {
|
|
2771
|
+
if (error instanceof IdleObservationError) {
|
|
2772
|
+
console.warn(` [flow] ${error.message}`)
|
|
2773
|
+
return
|
|
2774
|
+
}
|
|
2775
|
+
throw error
|
|
2768
2776
|
}
|
|
2769
2777
|
}
|
|
2770
2778
|
|
package/cli/cloud-client.ts
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
buildRnxCloudArtifact,
|
|
25
25
|
type RnxCloudArtifactReceipt,
|
|
26
26
|
} from '../../contrast-bundler/src/metroCloudArtifact.ts'
|
|
27
|
+
import { rewriteGuestImportMeta } from '../../peach-engine/src/guest-import-meta.ts'
|
|
27
28
|
import { loadMetroFingerprintRegistry } from '../../peach-engine/src/metro-fingerprint-registry-client.ts'
|
|
28
29
|
import { inferMetroModuleIdentity } from '../../peach-engine/src/metro-fingerprint.ts'
|
|
29
30
|
import { isLoopbackHost } from '../src/backend-origin.ts'
|
|
@@ -260,10 +261,10 @@ async function loadBundleSource(bundleInput: string): Promise<string> {
|
|
|
260
261
|
const source = isRemoteBundleInput(bundleInput)
|
|
261
262
|
? await fetchBundleSource(bundleInput)
|
|
262
263
|
: readImmutableBundleSource(bundleInput)
|
|
263
|
-
//
|
|
264
|
-
// allocating a
|
|
264
|
+
// validate the actual runtime script form without executing guest code or
|
|
265
|
+
// allocating a host.
|
|
265
266
|
try {
|
|
266
|
-
new Script(source, { filename: bundleInput })
|
|
267
|
+
new Script(rewriteGuestImportMeta(source), { filename: bundleInput })
|
|
267
268
|
} catch (error) {
|
|
268
269
|
throw new Error(
|
|
269
270
|
`${REMOTE_COMMAND} bundle contains invalid JavaScript: ${
|