peachsim 0.1.527
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 +22 -0
- package/README.md +640 -0
- package/cli/app-config.ts +82 -0
- package/cli/app-fonts.ts +388 -0
- package/cli/app-project.ts +59 -0
- package/cli/app-splash.ts +171 -0
- package/cli/app-state-reset.ts +26 -0
- package/cli/auth.ts +184 -0
- package/cli/bin.ts +59 -0
- package/cli/bridge-diagnostics.ts +226 -0
- package/cli/bridge-flow-runner.ts +2806 -0
- package/cli/browser-backend.ts +44 -0
- package/cli/browser-evals.ts +96 -0
- package/cli/cli-update.ts +261 -0
- package/cli/cloud-client.ts +1530 -0
- package/cli/cloud-dispatch.ts +206 -0
- package/cli/cloud-session.ts +227 -0
- package/cli/command-contract.ts +221 -0
- package/cli/command-registry.ts +304 -0
- package/cli/commands/agent-wrapper.ts +1048 -0
- package/cli/commands/agent.ts +439 -0
- package/cli/commands/app-fonts.ts +99 -0
- package/cli/commands/assert.ts +542 -0
- package/cli/commands/auth.ts +71 -0
- package/cli/commands/box/bundle-plane.ts +71 -0
- package/cli/commands/box/checkout-plane.ts +256 -0
- package/cli/commands/box/plane-share.ts +208 -0
- package/cli/commands/box/rnx-command.ts +60 -0
- package/cli/commands/box/search-command.ts +157 -0
- package/cli/commands/box.ts +925 -0
- package/cli/commands/camera.ts +266 -0
- package/cli/commands/cleanup.ts +169 -0
- package/cli/commands/compat.ts +176 -0
- package/cli/commands/config.ts +34 -0
- package/cli/commands/control.ts +2154 -0
- package/cli/commands/cpu-profile.ts +941 -0
- package/cli/commands/daemon-mac-app.ts +165 -0
- package/cli/commands/daemon.ts +800 -0
- package/cli/commands/debug.ts +751 -0
- package/cli/commands/desktop.ts +39 -0
- package/cli/commands/detect.ts +201 -0
- package/cli/commands/detox.ts +481 -0
- package/cli/commands/device.ts +134 -0
- package/cli/commands/diagnose.ts +589 -0
- package/cli/commands/do-chain.ts +408 -0
- package/cli/commands/electron.ts +94 -0
- package/cli/commands/film.ts +379 -0
- package/cli/commands/flow.ts +1240 -0
- package/cli/commands/inspect/actions.ts +516 -0
- package/cli/commands/inspect/core.ts +2086 -0
- package/cli/commands/inspect/count.ts +17 -0
- package/cli/commands/inspect/describe.ts +119 -0
- package/cli/commands/inspect/env.ts +25 -0
- package/cli/commands/inspect/find.ts +169 -0
- package/cli/commands/inspect/get-layout.ts +53 -0
- package/cli/commands/inspect/keyboard.ts +54 -0
- package/cli/commands/inspect/list.ts +175 -0
- package/cli/commands/inspect/memory.ts +215 -0
- package/cli/commands/inspect/redaction.ts +39 -0
- package/cli/commands/inspect/resolve-target.ts +77 -0
- package/cli/commands/inspect/screens.ts +78 -0
- package/cli/commands/inspect/settle.ts +32 -0
- package/cli/commands/inspect/settling.ts +197 -0
- package/cli/commands/inspect/shared.ts +259 -0
- package/cli/commands/inspect/sleep.ts +15 -0
- package/cli/commands/inspect/tree.ts +23 -0
- package/cli/commands/inspect/url.ts +17 -0
- package/cli/commands/inspect/wait-event.ts +211 -0
- package/cli/commands/inspect/wait-idle.ts +25 -0
- package/cli/commands/inspect/wait-ready.ts +87 -0
- package/cli/commands/inspect/wait-selector.ts +59 -0
- package/cli/commands/inspect/wait.ts +32 -0
- package/cli/commands/inspect.ts +4738 -0
- package/cli/commands/install-cli.ts +275 -0
- package/cli/commands/install-desktop.ts +385 -0
- package/cli/commands/login.ts +357 -0
- package/cli/commands/logout.ts +24 -0
- package/cli/commands/maestro-generate.ts +375 -0
- package/cli/commands/maestro.ts +536 -0
- package/cli/commands/mode.ts +58 -0
- package/cli/commands/no-bridge-hint.ts +80 -0
- package/cli/commands/perf.ts +67 -0
- package/cli/commands/permissions.ts +203 -0
- package/cli/commands/platform.ts +410 -0
- package/cli/commands/preview.ts +103 -0
- package/cli/commands/profile.ts +106 -0
- package/cli/commands/react.ts +353 -0
- package/cli/commands/record.ts +1435 -0
- package/cli/commands/report-issue.ts +305 -0
- package/cli/commands/reset.ts +89 -0
- package/cli/commands/runtime.ts +348 -0
- package/cli/commands/screenshot-command.ts +106 -0
- package/cli/commands/screenshot-layers.ts +144 -0
- package/cli/commands/screenshot-mode.ts +38 -0
- package/cli/commands/screenshot.ts +492 -0
- package/cli/commands/screenshots-capture.ts +608 -0
- package/cli/commands/screenshots.ts +127 -0
- package/cli/commands/serve.ts +139 -0
- package/cli/commands/setup.ts +416 -0
- package/cli/commands/shell-boolean-mode.ts +82 -0
- package/cli/commands/skills.ts +468 -0
- package/cli/commands/slides.ts +357 -0
- package/cli/commands/state.ts +94 -0
- package/cli/commands/storage.ts +58 -0
- package/cli/commands/telemetry.ts +55 -0
- package/cli/commands/test.ts +535 -0
- package/cli/commands/three-mode.ts +771 -0
- package/cli/commands/timeline.ts +121 -0
- package/cli/commands/upgrade.ts +167 -0
- package/cli/commands/upload.ts +1203 -0
- package/cli/commands/version.ts +63 -0
- package/cli/commands/welcome.ts +17 -0
- package/cli/commands/what-happened.ts +328 -0
- package/cli/current-sim.ts +217 -0
- package/cli/desktop-companion.ts +315 -0
- package/cli/drivers/electron.ts +70 -0
- package/cli/drivers/index.ts +20 -0
- package/cli/drivers/playwright-provisioning.ts +184 -0
- package/cli/drivers/playwright-sim-host.ts +537 -0
- package/cli/drivers/playwright.ts +209 -0
- package/cli/drivers/registry.ts +65 -0
- package/cli/drivers/types.ts +102 -0
- package/cli/flow-export.ts +55 -0
- package/cli/flow-file.ts +142 -0
- package/cli/flow-live-status.ts +126 -0
- package/cli/flow-session.ts +140 -0
- package/cli/help-core.ts +143 -0
- package/cli/help.ts +44 -0
- package/cli/hidden-runtime-alias.ts +19 -0
- package/cli/hints.ts +214 -0
- package/cli/inspect-notice-state.ts +114 -0
- package/cli/internal-child.ts +176 -0
- package/cli/maestro-js.ts +323 -0
- package/cli/main.ts +704 -0
- package/cli/open-url.ts +8 -0
- package/cli/outbound-endpoints.ts +830 -0
- package/cli/parent-pid.ts +204 -0
- package/cli/parse-args.ts +189 -0
- package/cli/privacy.ts +53 -0
- package/cli/prompt.ts +56 -0
- package/cli/recording-access.ts +108 -0
- package/cli/registry.ts +2 -0
- package/cli/resolve-assets.ts +63 -0
- package/cli/rnx-in-process.ts +98 -0
- package/cli/run-registry.ts +226 -0
- package/cli/run-rnx-core.ts +148 -0
- package/cli/run-rnx.ts +137 -0
- package/cli/runtime-notes.ts +66 -0
- package/cli/runtime-summary.ts +25 -0
- package/cli/secure-file.ts +31 -0
- package/cli/self-invocation.ts +58 -0
- package/cli/send-to-box.ts +109 -0
- package/cli/setup-repository.ts +191 -0
- package/cli/shell-init.ts +98 -0
- package/cli/standalone.ts +4 -0
- package/cli/telemetry.ts +84 -0
- package/cli/ui.ts +68 -0
- package/cli/ws-bridge.ts +1020 -0
- package/detox/attempt-events.cjs +23 -0
- package/detox/colors.ts +54 -0
- package/detox/config-loader.ts +135 -0
- package/detox/element-types.ts +48 -0
- package/detox/expectations.ts +534 -0
- package/detox/gestures.ts +501 -0
- package/detox/index.ts +2694 -0
- package/detox/jest-preset.cjs +29 -0
- package/detox/jest-setup-after-env.cjs +22 -0
- package/detox/matchers.ts +30 -0
- package/detox/motion-change.cjs +109 -0
- package/detox/motion-change.d.cts +35 -0
- package/detox/navigation-lifecycle.ts +290 -0
- package/detox/navigation.ts +43 -0
- package/detox/proof-frame.cjs +114 -0
- package/detox/record-block-execution.cjs +78 -0
- package/detox/screenshots/animated-color-test-rest-norngh.png +0 -0
- package/detox/screenshots/color-test-after-drag-norngh.png +0 -0
- package/detox/screenshots/color-test-rest-norngh.png +0 -0
- package/detox/screenshots/theme-blue-toggle.png +0 -0
- package/detox/screenshots/theme-blue.png +0 -0
- package/detox/screenshots/theme-red-toggle.png +0 -0
- package/detox/screenshots/theme-red.png +0 -0
- package/dist-lib/agent-daemon-client.cjs +502 -0
- package/dist-lib/agent-events.cjs +48 -0
- package/dist-lib/agent-identity.cjs +53 -0
- package/dist-lib/agent-sessions.cjs +759 -0
- package/dist-lib/attached-projects.cjs +526 -0
- package/dist-lib/auth/shared-session.cjs +208 -0
- package/dist-lib/backend-origin.cjs +88 -0
- package/dist-lib/beta.cjs +41 -0
- package/dist-lib/beta.mjs +13 -0
- package/dist-lib/bridge-constants.cjs +161 -0
- package/dist-lib/bridge-contract-input.cjs +451 -0
- package/dist-lib/bridge-contract-input.mjs +414 -0
- package/dist-lib/bridge-contract.cjs +130 -0
- package/dist-lib/bridge-contract.mjs +94 -0
- package/dist-lib/capture-contract.cjs +220 -0
- package/dist-lib/capture-contract.mjs +190 -0
- package/dist-lib/cli-constants.cjs +32 -0
- package/dist-lib/cloud-contract.cjs +194 -0
- package/dist-lib/cloud-contract.mjs +145 -0
- package/dist-lib/cloud.cjs +670 -0
- package/dist-lib/cloud.mjs +639 -0
- package/dist-lib/config.cjs +96 -0
- package/dist-lib/detox/index.cjs +3789 -0
- package/dist-lib/detox/jest-preset.cjs +29 -0
- package/dist-lib/dev-bundle-resolution.cjs +290 -0
- package/dist-lib/home-paths.cjs +638 -0
- package/dist-lib/host/bridge-host.cjs +10903 -0
- package/dist-lib/host/fetch-proxy-handler.cjs +421 -0
- package/dist-lib/host/fetch-proxy-overrides.cjs +63 -0
- package/dist-lib/host/fetch-proxy-overrides.mjs +37 -0
- package/dist-lib/host/replacement-module-handler.cjs +469 -0
- package/dist-lib/host/websocket-proxy.cjs +298 -0
- package/dist-lib/index.cjs +4268 -0
- package/dist-lib/jump-to-source-babel.cjs +93 -0
- package/dist-lib/jump-to-source-native.cjs +112 -0
- package/dist-lib/menu.cjs +646 -0
- package/dist-lib/menu.mjs +604 -0
- package/dist-lib/metro-fingerprint-registry.cjs +186 -0
- package/dist-lib/metro-fingerprint-registry.mjs +156 -0
- package/dist-lib/metro-production-bundle.cjs +329 -0
- package/dist-lib/metro-production-bundle.mjs +295 -0
- package/dist-lib/metro.cjs +904 -0
- package/dist-lib/profiles.cjs +246 -0
- package/dist-lib/public-brand.cjs +39 -0
- package/dist-lib/react-native-host-modules.cjs +51 -0
- package/dist-lib/react-native-host-modules.mjs +25 -0
- package/dist-lib/render-mode.cjs +54 -0
- package/dist-lib/scripts/dev-server-scanner.cjs +1232 -0
- package/dist-lib/sdk.cjs +2433 -0
- package/dist-lib/sdk.mjs +2336 -0
- package/dist-lib/skills.cjs +39132 -0
- package/dist-lib/swift-submit.cjs +92 -0
- package/dist-lib/swift-submit.mjs +65 -0
- package/dist-lib/swift.cjs +1646 -0
- package/dist-lib/vite.cjs +1591 -0
- package/package.json +290 -0
- package/scripts/dev-server-scanner.ts +1291 -0
- package/scripts/optional-demo-registry.ts +113 -0
- package/skills/contrast/SKILL.md +165 -0
- package/skills/rnx-debug/SKILL.md +433 -0
- package/skills/rnx-perf/SKILL.md +399 -0
- package/skills/rnx-setup/SKILL.md +172 -0
- package/skills/rnx-test/SKILL.md +321 -0
- package/skills/rnx-visual/SKILL.md +126 -0
- package/src/agent-daemon-client.ts +410 -0
- package/src/agent-events.ts +71 -0
- package/src/agent-identity.ts +23 -0
- package/src/agent-prompt.ts +71 -0
- package/src/agent-sessions.ts +580 -0
- package/src/app-url.ts +39 -0
- package/src/attached-projects.ts +539 -0
- package/src/auth/shared-session.ts +235 -0
- package/src/backend-origin.ts +70 -0
- package/src/beta.ts +19 -0
- package/src/bridge-constants.ts +175 -0
- package/src/bridge-contract-input.ts +502 -0
- package/src/bridge-contract.ts +558 -0
- package/src/browser-cache.ts +16 -0
- package/src/capture-contract.ts +587 -0
- package/src/cli-constants.ts +1 -0
- package/src/cli-version.ts +40 -0
- package/src/cloud-contract.ts +274 -0
- package/src/cloud.ts +762 -0
- package/src/codex-client.ts +234 -0
- package/src/config.ts +132 -0
- package/src/connect.ts +101 -0
- package/src/dev-bundle-resolution.ts +346 -0
- package/src/dev-server-open.ts +198 -0
- package/src/disk-cleanup.ts +540 -0
- package/src/flow-timeout-scale.ts +15 -0
- package/src/home-paths.ts +806 -0
- package/src/host/agent-host.ts +666 -0
- package/src/host/bridge-host.ts +2788 -0
- package/src/host/fetch-proxy-handler.ts +449 -0
- package/src/host/fetch-proxy-overrides.ts +51 -0
- package/src/host/open-url.ts +89 -0
- package/src/host/plane-host.ts +203 -0
- package/src/host/replacement-module-handler.ts +158 -0
- package/src/host/websocket-proxy.ts +315 -0
- package/src/index.ts +71 -0
- package/src/jump-to-source-babel.ts +135 -0
- package/src/jump-to-source-native.ts +102 -0
- package/src/menu.ts +777 -0
- package/src/metro-fingerprint-registry.ts +302 -0
- package/src/metro-plugin.ts +341 -0
- package/src/metro-production-bundle.ts +471 -0
- package/src/native-dev-bundle-url.ts +118 -0
- package/src/native-seam-manifest.ts +341 -0
- package/src/playwright-host-log.ts +16 -0
- package/src/plist.ts +27 -0
- package/src/poll-until.ts +123 -0
- package/src/profiles.ts +179 -0
- package/src/public-brand.ts +9 -0
- package/src/react-native-host-modules.ts +26 -0
- package/src/render-mode.ts +27 -0
- package/src/rolldown-plugin-swift.ts +240 -0
- package/src/runtime-assets.ts +233 -0
- package/src/runtime-delivery.ts +54 -0
- package/src/screenshots/compose.ts +422 -0
- package/src/screenshots/frame-compose.ts +514 -0
- package/src/screenshots/orchestrate.ts +256 -0
- package/src/screenshots/org-deck.ts +91 -0
- package/src/screenshots/registry.ts +58 -0
- package/src/screenshots/schema.ts +364 -0
- package/src/sdk.ts +15 -0
- package/src/settings-bundle.ts +418 -0
- package/src/shell-bridge-identity.ts +15 -0
- package/src/sim-client.ts +697 -0
- package/src/skills/builtin/a11y-review.ts +132 -0
- package/src/skills/builtin/compat-check.ts +71 -0
- package/src/skills/builtin/maestro-test.ts +121 -0
- package/src/skills/builtin/perf-profile.ts +90 -0
- package/src/skills/builtin/screenshot-all.ts +52 -0
- package/src/skills/builtin/visual-diff.ts +100 -0
- package/src/skills/registry.ts +107 -0
- package/src/skills/types.ts +41 -0
- package/src/swift-submit.ts +185 -0
- package/src/swift.ts +7 -0
- package/src/team-machine-prompt.ts +73 -0
- package/src/vite-plugin-one.ts +264 -0
- package/src/vite-plugin-swift.ts +620 -0
- package/src/vite-plugin.ts +1946 -0
- package/src/worklets-babel.ts +250 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
export const RNX_METRO_FINGERPRINT_SCHEMA_VERSION = 2
|
|
2
|
+
export const RNX_METRO_FINGERPRINT_POINTER_PATH = '/compile/metro-fingerprints.json'
|
|
3
|
+
export const RNX_METRO_FINGERPRINT_MAX_POINTER_BYTES = 16 * 1024
|
|
4
|
+
export const RNX_METRO_FINGERPRINT_MAX_PAYLOAD_BYTES = 8 * 1024 * 1024
|
|
5
|
+
|
|
6
|
+
export type RNXMetroFingerprintPlatform = 'ios' | 'android'
|
|
7
|
+
|
|
8
|
+
export interface RNXMetroFingerprintAtom {
|
|
9
|
+
key: string
|
|
10
|
+
exports: string[]
|
|
11
|
+
literals: string[]
|
|
12
|
+
dependencyArity: number
|
|
13
|
+
factoryDigest: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface RNXMetroFingerprintNode {
|
|
17
|
+
atom: number
|
|
18
|
+
internalDependencies: Array<{ position: number; node: number }>
|
|
19
|
+
landmarkPath?: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface RNXMetroFingerprintRoot {
|
|
23
|
+
node: number
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface RNXMetroFingerprintTemplate {
|
|
27
|
+
packageName: string
|
|
28
|
+
packageVersion: string
|
|
29
|
+
sourceIntegrity: string
|
|
30
|
+
profile: string
|
|
31
|
+
platform: RNXMetroFingerprintPlatform
|
|
32
|
+
nodes: RNXMetroFingerprintNode[]
|
|
33
|
+
roots: RNXMetroFingerprintRoot[]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface RNXMetroFingerprintCandidate {
|
|
37
|
+
template: number
|
|
38
|
+
root: number
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface RNXMetroFingerprintRegistry {
|
|
42
|
+
schemaVersion: typeof RNX_METRO_FINGERPRINT_SCHEMA_VERSION
|
|
43
|
+
revision: string
|
|
44
|
+
atoms: RNXMetroFingerprintAtom[]
|
|
45
|
+
templates: RNXMetroFingerprintTemplate[]
|
|
46
|
+
candidatesByFactoryDigest: Record<string, RNXMetroFingerprintCandidate[]>
|
|
47
|
+
candidatesByDiscriminator: Record<string, RNXMetroFingerprintCandidate[]>
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface RNXMetroFingerprintPointer {
|
|
51
|
+
schemaVersion: typeof RNX_METRO_FINGERPRINT_SCHEMA_VERSION
|
|
52
|
+
revision: string
|
|
53
|
+
integrity: string
|
|
54
|
+
bytes: number
|
|
55
|
+
payloadUrl: string
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
59
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function isSha256(value: unknown): value is string {
|
|
63
|
+
return typeof value === 'string' && /^[a-f0-9]{64}$/.test(value)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function readStringArray(value: unknown): string[] | null {
|
|
67
|
+
if (!Array.isArray(value) || !value.every((entry) => typeof entry === 'string')) {
|
|
68
|
+
return null
|
|
69
|
+
}
|
|
70
|
+
const entries = [...value]
|
|
71
|
+
if (
|
|
72
|
+
new Set(entries).size !== entries.length ||
|
|
73
|
+
entries.some((entry, index) => index > 0 && entries[index - 1] >= entry)
|
|
74
|
+
) {
|
|
75
|
+
return null
|
|
76
|
+
}
|
|
77
|
+
return entries
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function parseRNXMetroFingerprintPointer(
|
|
81
|
+
value: unknown,
|
|
82
|
+
): RNXMetroFingerprintPointer | null {
|
|
83
|
+
if (!isRecord(value)) return null
|
|
84
|
+
const { schemaVersion, revision, integrity, bytes, payloadUrl } = value
|
|
85
|
+
if (
|
|
86
|
+
schemaVersion !== RNX_METRO_FINGERPRINT_SCHEMA_VERSION ||
|
|
87
|
+
!isSha256(revision) ||
|
|
88
|
+
!isSha256(integrity) ||
|
|
89
|
+
typeof bytes !== 'number' ||
|
|
90
|
+
!Number.isSafeInteger(bytes) ||
|
|
91
|
+
bytes < 1 ||
|
|
92
|
+
typeof payloadUrl !== 'string' ||
|
|
93
|
+
payloadUrl.length === 0
|
|
94
|
+
) {
|
|
95
|
+
return null
|
|
96
|
+
}
|
|
97
|
+
return { schemaVersion, revision, integrity, bytes, payloadUrl }
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function parseRNXMetroFingerprintRegistry(
|
|
101
|
+
value: unknown,
|
|
102
|
+
): RNXMetroFingerprintRegistry | null {
|
|
103
|
+
if (!isRecord(value)) return null
|
|
104
|
+
const { schemaVersion, revision } = value
|
|
105
|
+
if (
|
|
106
|
+
schemaVersion !== RNX_METRO_FINGERPRINT_SCHEMA_VERSION ||
|
|
107
|
+
!isSha256(revision) ||
|
|
108
|
+
!Array.isArray(value.atoms) ||
|
|
109
|
+
!Array.isArray(value.templates) ||
|
|
110
|
+
!isRecord(value.candidatesByFactoryDigest) ||
|
|
111
|
+
!isRecord(value.candidatesByDiscriminator)
|
|
112
|
+
) {
|
|
113
|
+
return null
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const atoms: RNXMetroFingerprintAtom[] = []
|
|
117
|
+
for (const atomValue of value.atoms) {
|
|
118
|
+
if (!isRecord(atomValue)) return null
|
|
119
|
+
const exports = readStringArray(atomValue.exports)
|
|
120
|
+
const literals = readStringArray(atomValue.literals)
|
|
121
|
+
if (
|
|
122
|
+
typeof atomValue.key !== 'string' ||
|
|
123
|
+
atomValue.key.length === 0 ||
|
|
124
|
+
!exports ||
|
|
125
|
+
!literals ||
|
|
126
|
+
typeof atomValue.dependencyArity !== 'number' ||
|
|
127
|
+
!Number.isSafeInteger(atomValue.dependencyArity) ||
|
|
128
|
+
atomValue.dependencyArity < 0 ||
|
|
129
|
+
!isSha256(atomValue.factoryDigest)
|
|
130
|
+
) {
|
|
131
|
+
return null
|
|
132
|
+
}
|
|
133
|
+
atoms.push({
|
|
134
|
+
key: atomValue.key,
|
|
135
|
+
exports,
|
|
136
|
+
literals,
|
|
137
|
+
dependencyArity: atomValue.dependencyArity,
|
|
138
|
+
factoryDigest: atomValue.factoryDigest,
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const templates: RNXMetroFingerprintTemplate[] = []
|
|
143
|
+
for (const templateValue of value.templates) {
|
|
144
|
+
if (
|
|
145
|
+
!isRecord(templateValue) ||
|
|
146
|
+
typeof templateValue.packageName !== 'string' ||
|
|
147
|
+
templateValue.packageName.length === 0 ||
|
|
148
|
+
typeof templateValue.packageVersion !== 'string' ||
|
|
149
|
+
templateValue.packageVersion.length === 0 ||
|
|
150
|
+
!isSha256(templateValue.sourceIntegrity) ||
|
|
151
|
+
typeof templateValue.profile !== 'string' ||
|
|
152
|
+
templateValue.profile.length === 0 ||
|
|
153
|
+
(templateValue.platform !== 'ios' && templateValue.platform !== 'android') ||
|
|
154
|
+
!Array.isArray(templateValue.nodes) ||
|
|
155
|
+
templateValue.nodes.length === 0 ||
|
|
156
|
+
!Array.isArray(templateValue.roots) ||
|
|
157
|
+
templateValue.roots.length === 0
|
|
158
|
+
) {
|
|
159
|
+
return null
|
|
160
|
+
}
|
|
161
|
+
const nodes: RNXMetroFingerprintNode[] = []
|
|
162
|
+
for (const nodeValue of templateValue.nodes) {
|
|
163
|
+
if (
|
|
164
|
+
!isRecord(nodeValue) ||
|
|
165
|
+
typeof nodeValue.atom !== 'number' ||
|
|
166
|
+
!Number.isSafeInteger(nodeValue.atom) ||
|
|
167
|
+
nodeValue.atom < 0 ||
|
|
168
|
+
nodeValue.atom >= atoms.length ||
|
|
169
|
+
!Array.isArray(nodeValue.internalDependencies) ||
|
|
170
|
+
(nodeValue.landmarkPath !== undefined &&
|
|
171
|
+
(typeof nodeValue.landmarkPath !== 'string' ||
|
|
172
|
+
nodeValue.landmarkPath.length === 0))
|
|
173
|
+
) {
|
|
174
|
+
return null
|
|
175
|
+
}
|
|
176
|
+
const internalDependencies: Array<{ position: number; node: number }> = []
|
|
177
|
+
const positions = new Set<number>()
|
|
178
|
+
for (const edgeValue of nodeValue.internalDependencies) {
|
|
179
|
+
if (
|
|
180
|
+
!isRecord(edgeValue) ||
|
|
181
|
+
typeof edgeValue.position !== 'number' ||
|
|
182
|
+
!Number.isSafeInteger(edgeValue.position) ||
|
|
183
|
+
edgeValue.position < 0 ||
|
|
184
|
+
positions.has(edgeValue.position) ||
|
|
185
|
+
typeof edgeValue.node !== 'number' ||
|
|
186
|
+
!Number.isSafeInteger(edgeValue.node) ||
|
|
187
|
+
edgeValue.node < 0 ||
|
|
188
|
+
edgeValue.node >= templateValue.nodes.length
|
|
189
|
+
) {
|
|
190
|
+
return null
|
|
191
|
+
}
|
|
192
|
+
positions.add(edgeValue.position)
|
|
193
|
+
internalDependencies.push({
|
|
194
|
+
position: edgeValue.position,
|
|
195
|
+
node: edgeValue.node,
|
|
196
|
+
})
|
|
197
|
+
}
|
|
198
|
+
internalDependencies.sort((left, right) => left.position - right.position)
|
|
199
|
+
nodes.push({
|
|
200
|
+
atom: nodeValue.atom,
|
|
201
|
+
internalDependencies,
|
|
202
|
+
...(typeof nodeValue.landmarkPath === 'string'
|
|
203
|
+
? { landmarkPath: nodeValue.landmarkPath }
|
|
204
|
+
: {}),
|
|
205
|
+
})
|
|
206
|
+
}
|
|
207
|
+
const roots: RNXMetroFingerprintRoot[] = []
|
|
208
|
+
for (const rootValue of templateValue.roots) {
|
|
209
|
+
if (
|
|
210
|
+
!isRecord(rootValue) ||
|
|
211
|
+
typeof rootValue.node !== 'number' ||
|
|
212
|
+
!Number.isSafeInteger(rootValue.node) ||
|
|
213
|
+
rootValue.node < 0 ||
|
|
214
|
+
rootValue.node >= nodes.length ||
|
|
215
|
+
!nodes[rootValue.node].landmarkPath
|
|
216
|
+
) {
|
|
217
|
+
return null
|
|
218
|
+
}
|
|
219
|
+
roots.push({ node: rootValue.node })
|
|
220
|
+
}
|
|
221
|
+
templates.push({
|
|
222
|
+
packageName: templateValue.packageName,
|
|
223
|
+
packageVersion: templateValue.packageVersion,
|
|
224
|
+
sourceIntegrity: templateValue.sourceIntegrity,
|
|
225
|
+
profile: templateValue.profile,
|
|
226
|
+
platform: templateValue.platform,
|
|
227
|
+
nodes,
|
|
228
|
+
roots,
|
|
229
|
+
})
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const candidatesByFactoryDigest: Record<string, RNXMetroFingerprintCandidate[]> = {}
|
|
233
|
+
for (const [factoryDigest, candidateValues] of Object.entries(
|
|
234
|
+
value.candidatesByFactoryDigest,
|
|
235
|
+
)) {
|
|
236
|
+
if (!isSha256(factoryDigest) || !Array.isArray(candidateValues)) return null
|
|
237
|
+
const candidates: RNXMetroFingerprintCandidate[] = []
|
|
238
|
+
for (const candidateValue of candidateValues) {
|
|
239
|
+
if (
|
|
240
|
+
!isRecord(candidateValue) ||
|
|
241
|
+
typeof candidateValue.template !== 'number' ||
|
|
242
|
+
!Number.isSafeInteger(candidateValue.template) ||
|
|
243
|
+
candidateValue.template < 0 ||
|
|
244
|
+
candidateValue.template >= templates.length ||
|
|
245
|
+
typeof candidateValue.root !== 'number' ||
|
|
246
|
+
!Number.isSafeInteger(candidateValue.root) ||
|
|
247
|
+
candidateValue.root < 0 ||
|
|
248
|
+
candidateValue.root >= templates[candidateValue.template].roots.length
|
|
249
|
+
) {
|
|
250
|
+
return null
|
|
251
|
+
}
|
|
252
|
+
const template = templates[candidateValue.template]
|
|
253
|
+
const root = template.roots[candidateValue.root]
|
|
254
|
+
if (atoms[template.nodes[root.node].atom].factoryDigest !== factoryDigest) {
|
|
255
|
+
return null
|
|
256
|
+
}
|
|
257
|
+
candidates.push({
|
|
258
|
+
template: candidateValue.template,
|
|
259
|
+
root: candidateValue.root,
|
|
260
|
+
})
|
|
261
|
+
}
|
|
262
|
+
candidatesByFactoryDigest[factoryDigest] = candidates
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const candidatesByDiscriminator: Record<string, RNXMetroFingerprintCandidate[]> = {}
|
|
266
|
+
for (const [discriminator, candidateValues] of Object.entries(
|
|
267
|
+
value.candidatesByDiscriminator,
|
|
268
|
+
)) {
|
|
269
|
+
if (!/^(?:e|l|ea|la|el|ela):[a-f0-9]{16}$/.test(discriminator)) return null
|
|
270
|
+
if (!Array.isArray(candidateValues) || candidateValues.length === 0) return null
|
|
271
|
+
const candidates: RNXMetroFingerprintCandidate[] = []
|
|
272
|
+
for (const candidateValue of candidateValues) {
|
|
273
|
+
if (
|
|
274
|
+
!isRecord(candidateValue) ||
|
|
275
|
+
typeof candidateValue.template !== 'number' ||
|
|
276
|
+
!Number.isSafeInteger(candidateValue.template) ||
|
|
277
|
+
candidateValue.template < 0 ||
|
|
278
|
+
candidateValue.template >= templates.length ||
|
|
279
|
+
typeof candidateValue.root !== 'number' ||
|
|
280
|
+
!Number.isSafeInteger(candidateValue.root) ||
|
|
281
|
+
candidateValue.root < 0 ||
|
|
282
|
+
candidateValue.root >= templates[candidateValue.template].roots.length
|
|
283
|
+
) {
|
|
284
|
+
return null
|
|
285
|
+
}
|
|
286
|
+
candidates.push({
|
|
287
|
+
template: candidateValue.template,
|
|
288
|
+
root: candidateValue.root,
|
|
289
|
+
})
|
|
290
|
+
}
|
|
291
|
+
candidatesByDiscriminator[discriminator] = candidates
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return {
|
|
295
|
+
schemaVersion,
|
|
296
|
+
revision,
|
|
297
|
+
atoms,
|
|
298
|
+
templates,
|
|
299
|
+
candidatesByFactoryDigest,
|
|
300
|
+
candidatesByDiscriminator,
|
|
301
|
+
}
|
|
302
|
+
}
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
// rnx metro plugin for dev shell and bundle module identity annotation.
|
|
2
|
+
// shell assets come from an engine runtime under ~/.rnx/runtimes/, fetched
|
|
3
|
+
// by `rnx runtime install`. ordinary localhost requests
|
|
4
|
+
// follow active; a version-owned localhost origin stays on its exact directory
|
|
5
|
+
// when active changes, so one loaded shell cannot mix runtime chunk trees.
|
|
6
|
+
//
|
|
7
|
+
// usage in metro.config.js:
|
|
8
|
+
// const { withRNX } = require('rnxsim/metro')
|
|
9
|
+
// module.exports = withRNX(getDefaultConfig(__dirname))
|
|
10
|
+
|
|
11
|
+
import fs from 'fs'
|
|
12
|
+
import { createRequire } from 'module'
|
|
13
|
+
import { randomUUID } from 'node:crypto'
|
|
14
|
+
import path from 'path'
|
|
15
|
+
import { tagRnxBundleForPlugin } from './dev-server-open'
|
|
16
|
+
import {
|
|
17
|
+
handleReplacementModuleRequest,
|
|
18
|
+
isReplacementModuleRequestUrl,
|
|
19
|
+
} from './host/replacement-module-handler'
|
|
20
|
+
import {
|
|
21
|
+
appendRNXMetroModuleIdentityFooter,
|
|
22
|
+
RNX_METRO_MODULE_IDENTITY_VERSION,
|
|
23
|
+
toRNXDevelopmentBundleUrl,
|
|
24
|
+
toRNXProductionBundleUrl,
|
|
25
|
+
type RNXMetroModuleIdentityMetadata,
|
|
26
|
+
} from './metro-production-bundle'
|
|
27
|
+
import {
|
|
28
|
+
isRootRuntimeAssetPath,
|
|
29
|
+
resolveRuntimeFilePath,
|
|
30
|
+
resolveRuntimeRootForRequestHost,
|
|
31
|
+
serveRuntimeFile,
|
|
32
|
+
SOOTSIM_RUNTIME_MISSING_MESSAGE,
|
|
33
|
+
} from './runtime-assets'
|
|
34
|
+
|
|
35
|
+
const prefix = '/__soot'
|
|
36
|
+
export { toRNXDevelopmentBundleUrl, toRNXProductionBundleUrl }
|
|
37
|
+
|
|
38
|
+
type MetroSerializerModule = {
|
|
39
|
+
path: string
|
|
40
|
+
dependencies?: ReadonlyMap<
|
|
41
|
+
string,
|
|
42
|
+
{
|
|
43
|
+
absolutePath?: string
|
|
44
|
+
data?: { name?: string }
|
|
45
|
+
}
|
|
46
|
+
>
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
type MetroSerializerGraph = {
|
|
50
|
+
dependencies?: ReadonlyMap<unknown, MetroSerializerModule>
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
type MetroSerializerOptions = {
|
|
54
|
+
createModuleId?: (modulePath: string) => number
|
|
55
|
+
dev?: boolean
|
|
56
|
+
[key: string]: unknown
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
type MetroSerializerResult = string | { code: string; map: string }
|
|
60
|
+
|
|
61
|
+
type MetroSerializer = (
|
|
62
|
+
entryPoint: string,
|
|
63
|
+
preModules: readonly unknown[],
|
|
64
|
+
graph: MetroSerializerGraph,
|
|
65
|
+
options: MetroSerializerOptions,
|
|
66
|
+
) => MetroSerializerResult | Promise<MetroSerializerResult>
|
|
67
|
+
|
|
68
|
+
type MetroConfigWithServer = {
|
|
69
|
+
projectRoot?: string
|
|
70
|
+
serializer?: {
|
|
71
|
+
customSerializer?: MetroSerializer
|
|
72
|
+
[key: string]: unknown
|
|
73
|
+
}
|
|
74
|
+
server?: {
|
|
75
|
+
enhanceMiddleware?: (middleware: unknown, server: unknown) => unknown
|
|
76
|
+
port?: number
|
|
77
|
+
[key: string]: unknown
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function readCallableMetroExport(
|
|
82
|
+
moduleValue: unknown,
|
|
83
|
+
label: string,
|
|
84
|
+
): (...args: readonly unknown[]) => unknown {
|
|
85
|
+
const callable =
|
|
86
|
+
typeof moduleValue === 'function'
|
|
87
|
+
? moduleValue
|
|
88
|
+
: typeof moduleValue === 'object' && moduleValue !== null
|
|
89
|
+
? Reflect.get(moduleValue, 'default')
|
|
90
|
+
: undefined
|
|
91
|
+
if (typeof callable !== 'function') {
|
|
92
|
+
throw new Error(`rnxsim: Metro ${label} module did not export a function`)
|
|
93
|
+
}
|
|
94
|
+
return (...args) => Reflect.apply(callable, undefined, args)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function createMetroDefaultSerializer(projectRoot: string): MetroSerializer {
|
|
98
|
+
const projectRequire = createRequire(path.join(projectRoot, 'package.json'))
|
|
99
|
+
const metroRoot = path.dirname(projectRequire.resolve('metro/package.json'))
|
|
100
|
+
const baseJSBundle = readCallableMetroExport(
|
|
101
|
+
projectRequire(path.join(metroRoot, 'src/DeltaBundler/Serializers/baseJSBundle.js')),
|
|
102
|
+
'baseJSBundle',
|
|
103
|
+
)
|
|
104
|
+
const bundleToString = readCallableMetroExport(
|
|
105
|
+
projectRequire(path.join(metroRoot, 'src/lib/bundleToString.js')),
|
|
106
|
+
'bundleToString',
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
return (entryPoint, preModules, graph, options) => {
|
|
110
|
+
const serialized = bundleToString(
|
|
111
|
+
baseJSBundle(entryPoint, preModules, graph, options),
|
|
112
|
+
)
|
|
113
|
+
const code =
|
|
114
|
+
typeof serialized === 'object' && serialized !== null
|
|
115
|
+
? Reflect.get(serialized, 'code')
|
|
116
|
+
: undefined
|
|
117
|
+
if (typeof code !== 'string') {
|
|
118
|
+
throw new Error('rnxsim: Metro bundleToString did not return bundle code')
|
|
119
|
+
}
|
|
120
|
+
return code
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// the only thing rnx adds to an ordinary Metro bundle. production needs the
|
|
125
|
+
// footer because Metro drops the fourth `__d` argument when `dev` is false;
|
|
126
|
+
// development keeps that verbose name and receives the same identity without
|
|
127
|
+
// changing resolution, transforms, or the trailing source map.
|
|
128
|
+
function appendRNXModulePaths(
|
|
129
|
+
result: MetroSerializerResult,
|
|
130
|
+
graph: MetroSerializerGraph,
|
|
131
|
+
options: MetroSerializerOptions,
|
|
132
|
+
projectRoot: string,
|
|
133
|
+
): MetroSerializerResult {
|
|
134
|
+
const dependencies = graph.dependencies
|
|
135
|
+
const createModuleId = options.createModuleId
|
|
136
|
+
if (!dependencies || !createModuleId) {
|
|
137
|
+
return result
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const modulePaths: Record<string, string> = {}
|
|
141
|
+
for (const module of dependencies.values()) {
|
|
142
|
+
modulePaths[String(createModuleId(module.path))] = path
|
|
143
|
+
.relative(projectRoot, module.path)
|
|
144
|
+
.replaceAll(path.sep, '/')
|
|
145
|
+
}
|
|
146
|
+
if (Object.keys(modulePaths).length !== dependencies.size) {
|
|
147
|
+
throw new Error('rnxsim: bundle module IDs were not unique')
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const specifiersByModuleId = new Map<string, Set<string>>()
|
|
151
|
+
for (const module of dependencies.values()) {
|
|
152
|
+
for (const [dependencyKey, dependency] of module.dependencies ?? []) {
|
|
153
|
+
const specifier = dependency.data?.name ?? dependencyKey
|
|
154
|
+
if (
|
|
155
|
+
specifier.length === 0 ||
|
|
156
|
+
specifier.startsWith('.') ||
|
|
157
|
+
specifier.startsWith('/') ||
|
|
158
|
+
typeof dependency.absolutePath !== 'string'
|
|
159
|
+
) {
|
|
160
|
+
continue
|
|
161
|
+
}
|
|
162
|
+
const moduleId = String(createModuleId(dependency.absolutePath))
|
|
163
|
+
if (!Object.prototype.hasOwnProperty.call(modulePaths, moduleId)) continue
|
|
164
|
+
const found = specifiersByModuleId.get(moduleId)
|
|
165
|
+
if (found) found.add(specifier)
|
|
166
|
+
else specifiersByModuleId.set(moduleId, new Set([specifier]))
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const logicalSpecifiers = Object.fromEntries(
|
|
170
|
+
[...specifiersByModuleId]
|
|
171
|
+
.sort(([left], [right]) => Number(left) - Number(right))
|
|
172
|
+
.map(([moduleId, specifiers]) => [moduleId, [...specifiers].sort()]),
|
|
173
|
+
)
|
|
174
|
+
const identity: RNXMetroModuleIdentityMetadata = {
|
|
175
|
+
version: RNX_METRO_MODULE_IDENTITY_VERSION,
|
|
176
|
+
identitySource: 'rnx-plugin',
|
|
177
|
+
modulePaths,
|
|
178
|
+
logicalSpecifiers,
|
|
179
|
+
}
|
|
180
|
+
return typeof result === 'string'
|
|
181
|
+
? appendRNXMetroModuleIdentityFooter(result, identity)
|
|
182
|
+
: { ...result, code: appendRNXMetroModuleIdentityFooter(result.code, identity) }
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function withRNX<T extends Record<string, unknown>>(config: T): T {
|
|
186
|
+
const cfgProjectRoot = (config as MetroConfigWithServer).projectRoot || process.cwd()
|
|
187
|
+
const configuredBundleUrl = '/index.bundle?platform=ios&dev=true&hot=true&minify=false'
|
|
188
|
+
|
|
189
|
+
const cfgServer = (config as MetroConfigWithServer).server
|
|
190
|
+
const port = resolveMetroPort(cfgServer)
|
|
191
|
+
const metroServerId = randomUUID()
|
|
192
|
+
const bundleUrl = tagRnxBundleForPlugin(
|
|
193
|
+
configuredBundleUrl,
|
|
194
|
+
`http://localhost:${port}`,
|
|
195
|
+
metroServerId,
|
|
196
|
+
cfgProjectRoot,
|
|
197
|
+
)
|
|
198
|
+
const cfgSerializer = (config as MetroConfigWithServer).serializer
|
|
199
|
+
const existingEnhance = cfgServer?.enhanceMiddleware
|
|
200
|
+
const existingSerializer = cfgSerializer?.customSerializer
|
|
201
|
+
|
|
202
|
+
let defaultSerializer: MetroSerializer | undefined
|
|
203
|
+
|
|
204
|
+
const serializerConfig = {
|
|
205
|
+
serializer: {
|
|
206
|
+
...cfgSerializer,
|
|
207
|
+
customSerializer: async (
|
|
208
|
+
entryPoint: string,
|
|
209
|
+
preModules: readonly unknown[],
|
|
210
|
+
graph: MetroSerializerGraph,
|
|
211
|
+
serializerOptions: MetroSerializerOptions,
|
|
212
|
+
) => {
|
|
213
|
+
const serializer =
|
|
214
|
+
existingSerializer ||
|
|
215
|
+
(defaultSerializer ||= createMetroDefaultSerializer(cfgProjectRoot))
|
|
216
|
+
const result = await serializer(entryPoint, preModules, graph, serializerOptions)
|
|
217
|
+
return appendRNXModulePaths(result, graph, serializerOptions, cfgProjectRoot)
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const serverConfig = {
|
|
223
|
+
...cfgServer,
|
|
224
|
+
enhanceMiddleware: (metroMiddleware: any, metroServer: any) => {
|
|
225
|
+
let middleware = metroMiddleware
|
|
226
|
+
if (existingEnhance) {
|
|
227
|
+
middleware = existingEnhance(metroMiddleware, metroServer)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
let connect: any
|
|
231
|
+
try {
|
|
232
|
+
connect = require('connect')
|
|
233
|
+
} catch {
|
|
234
|
+
console.warn('[rnx] connect not available')
|
|
235
|
+
return middleware
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const server = connect()
|
|
239
|
+
|
|
240
|
+
server.use((req: any, res: any, next: any) => {
|
|
241
|
+
if (isReplacementModuleRequestUrl(req.url)) {
|
|
242
|
+
void handleReplacementModuleRequest(req, res, {
|
|
243
|
+
projectRoot: cfgProjectRoot,
|
|
244
|
+
requestToken: metroServerId,
|
|
245
|
+
requireLoopbackOrigin: true,
|
|
246
|
+
}).then((handled) => {
|
|
247
|
+
if (!handled) next()
|
|
248
|
+
})
|
|
249
|
+
return
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const url = req.url || ''
|
|
253
|
+
const pathname = url.split('?')[0]
|
|
254
|
+
|
|
255
|
+
const runtimeRoot = resolveRuntimeRootForRequestHost(req.headers?.host)
|
|
256
|
+
|
|
257
|
+
if (!runtimeRoot) {
|
|
258
|
+
if (pathname === prefix || pathname === prefix + '/') {
|
|
259
|
+
res.statusCode = 500
|
|
260
|
+
res.end(SOOTSIM_RUNTIME_MISSING_MESSAGE)
|
|
261
|
+
return
|
|
262
|
+
}
|
|
263
|
+
next()
|
|
264
|
+
return
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// root-relative runtime assets emitted by the shell and engine vite
|
|
268
|
+
// builds. if a user app has its own /assets/foo request, we only
|
|
269
|
+
// intercept when that exact file exists in the runtime; otherwise
|
|
270
|
+
// metro handles it normally.
|
|
271
|
+
if (isRootRuntimeAssetPath(pathname)) {
|
|
272
|
+
const fullPath = resolveRuntimeFilePath(runtimeRoot, pathname)
|
|
273
|
+
if (fullPath) {
|
|
274
|
+
serveRuntimeFile(req, res, fullPath)
|
|
275
|
+
return
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// /__soot/* — serve runtime assets
|
|
280
|
+
if (pathname.startsWith(prefix + '/')) {
|
|
281
|
+
const fullPath = resolveRuntimeFilePath(
|
|
282
|
+
runtimeRoot,
|
|
283
|
+
pathname.slice(prefix.length),
|
|
284
|
+
)
|
|
285
|
+
if (fullPath) {
|
|
286
|
+
serveRuntimeFile(req, res, fullPath)
|
|
287
|
+
return
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// serve HTML shell for /__soot and extensionless in-shell routes.
|
|
292
|
+
if (
|
|
293
|
+
pathname === prefix ||
|
|
294
|
+
pathname === prefix + '/' ||
|
|
295
|
+
pathname.startsWith(prefix + '/')
|
|
296
|
+
) {
|
|
297
|
+
const ext = path.extname(pathname)
|
|
298
|
+
if (!ext) {
|
|
299
|
+
const htmlPath = path.join(runtimeRoot, 'index.html')
|
|
300
|
+
let html = fs.readFileSync(htmlPath, 'utf8')
|
|
301
|
+
const script = `<script>(function(){var u=new URL(location.href);if(!u.searchParams.has('bundle'))u.searchParams.set('bundle',${JSON.stringify(bundleUrl)});history.replaceState(null,'','${prefix}/'+u.search)})()</script>`
|
|
302
|
+
html = html.includes('</head>')
|
|
303
|
+
? html.replace('</head>', `${script}</head>`)
|
|
304
|
+
: `${html}${script}`
|
|
305
|
+
res.setHeader('content-type', 'text/html')
|
|
306
|
+
res.end(html)
|
|
307
|
+
return
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
next()
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
server.use(middleware)
|
|
315
|
+
|
|
316
|
+
console.log(`[rnx] serving at ${prefix}/`)
|
|
317
|
+
return server
|
|
318
|
+
},
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return {
|
|
322
|
+
...config,
|
|
323
|
+
...serializerConfig,
|
|
324
|
+
server: serverConfig,
|
|
325
|
+
} as T
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function resolveMetroPort(server: MetroConfigWithServer['server']): number {
|
|
329
|
+
const inlinePort = process.argv.find((arg) => arg.startsWith('--port='))?.slice(7)
|
|
330
|
+
const portIndex = process.argv.indexOf('--port')
|
|
331
|
+
const splitPort = portIndex >= 0 ? process.argv[portIndex + 1] : undefined
|
|
332
|
+
const rawPort =
|
|
333
|
+
inlinePort || splitPort || process.env.RCT_METRO_PORT || server?.port || 8081
|
|
334
|
+
const port = Number(rawPort)
|
|
335
|
+
if (!Number.isInteger(port) || port <= 0) {
|
|
336
|
+
throw new Error(`rnx: Metro port must be a positive integer, got ${rawPort}`)
|
|
337
|
+
}
|
|
338
|
+
return port
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export default withRNX
|