rnxsim 0.1.393 → 0.1.395
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 +12 -5
- package/cli/cloud-client.ts +74 -52
- package/cli/cloud-dispatch.ts +2 -1
- package/cli/commands/inspect/core.ts +33 -2
- package/cli/commands/platform.ts +34 -9
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.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 +12 -1
- package/dist-lib/bridge-contract-input.mjs +10 -1
- package/dist-lib/bridge-contract.cjs +7 -1
- package/dist-lib/bridge-contract.mjs +5 -1
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/cloud-contract.cjs +29 -3
- package/dist-lib/cloud-contract.mjs +26 -2
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +1 -1
- 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 +25 -55
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +132 -8
- package/dist-lib/metro-production-bundle.mjs +129 -6
- package/dist-lib/metro.cjs +3 -55
- 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/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +24 -3
- package/dist-lib/sdk.mjs +24 -3
- package/dist-lib/skills.cjs +28 -25
- package/dist-lib/vite.cjs +1 -1
- package/package.json +1 -1
- package/src/bridge-contract-input.ts +12 -0
- package/src/bridge-contract.ts +7 -0
- package/src/cloud-contract.ts +29 -0
- package/src/metro-plugin.ts +17 -98
- package/src/metro-production-bundle.ts +204 -3
- package/dist-lib/metro-host-modules/react-dom.js +0 -6
- package/dist-lib/metro-host-modules/react-native-web.js +0 -6
- package/dist-lib/metro-host-modules/react-native.js +0 -6
- package/dist-lib/metro-host-modules/react.js +0 -6
- package/dist-lib/metro-host-modules/react__jsx-dev-runtime.js +0 -6
- package/dist-lib/metro-host-modules/react__jsx-runtime.js +0 -6
- package/src/metro-host-modules/react-dom.js +0 -6
- package/src/metro-host-modules/react-native-web.js +0 -6
- package/src/metro-host-modules/react-native.js +0 -6
- package/src/metro-host-modules/react.js +0 -6
- package/src/metro-host-modules/react__jsx-dev-runtime.js +0 -6
- package/src/metro-host-modules/react__jsx-runtime.js +0 -6
package/README.md
CHANGED
|
@@ -386,9 +386,15 @@ development Electron build against the same user-data directory may ask for
|
|
|
386
386
|
one-time Keychain approval. `RNX_NO_OPEN=1` keeps the server headless. The
|
|
387
387
|
Metro wrapper also has two independent non-window opt-ins.
|
|
388
388
|
`devServer` serves the RNX shell from the Metro process. `productionBundles`
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
389
|
+
appends Metro's exact module-ID-to-source-path map to every production bundle,
|
|
390
|
+
as a trailing `globalThis.__sootsimModulePaths = { ... }` assignment.
|
|
391
|
+
|
|
392
|
+
That footer is the only change. Metro drops the fourth `__d` argument when
|
|
393
|
+
`dev` is false, so a production bundle names none of its modules, and RNX needs
|
|
394
|
+
those names to recognize React, React Native, and native compatibility seams at
|
|
395
|
+
load time. Resolution, transforms, minification, and the source map stay the
|
|
396
|
+
app's own, so the annotated bundle is the bundle you ship: the footer assigns
|
|
397
|
+
one unused global on a device, and Hermes drops it during bytecode compilation.
|
|
392
398
|
|
|
393
399
|
```js
|
|
394
400
|
module.exports = withRNX(config, { productionBundles: true })
|
|
@@ -400,8 +406,9 @@ module.exports = withRNX(config, {
|
|
|
400
406
|
})
|
|
401
407
|
```
|
|
402
408
|
|
|
403
|
-
Calling `withRNX(config)` changes nothing.
|
|
404
|
-
Metro
|
|
409
|
+
Calling `withRNX(config)` changes nothing. To load a production bundle from a
|
|
410
|
+
running Metro dev server, use the URL helper, which sets Metro's ordinary
|
|
411
|
+
`dev=false&minify=true` options:
|
|
405
412
|
|
|
406
413
|
```js
|
|
407
414
|
const { toRNXProductionBundleUrl } = require('rnxsim/metro')
|
package/cli/cloud-client.ts
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { createHash, randomUUID } from 'node:crypto'
|
|
2
2
|
import { closeSync, fstatSync, openSync, readFileSync } from 'node:fs'
|
|
3
|
-
import { extname, resolve } from 'node:path'
|
|
4
|
-
import { assertSelfContainedMetroArtifactAssets } from '../../contrast-bundler/src/metroAssetArtifact'
|
|
3
|
+
import { dirname, extname, join, resolve } from 'node:path'
|
|
5
4
|
import {
|
|
5
|
+
embedMetroAssetFiles,
|
|
6
|
+
type MetroAssetVariant,
|
|
7
|
+
} from '../../contrast-bundler/src/metroAssetArtifact'
|
|
8
|
+
import {
|
|
9
|
+
buildRnxCloudArtifact,
|
|
10
|
+
type RnxCloudArtifactReceipt,
|
|
11
|
+
} from '../../contrast-bundler/src/metroCloudArtifact'
|
|
12
|
+
import {
|
|
13
|
+
isRnxCloudCommandType,
|
|
6
14
|
RNX_CLOUD_MAX_ARTIFACT_BYTES,
|
|
7
15
|
type RnxCloudCreateReceipt,
|
|
8
16
|
} from '../src/cloud-contract'
|
|
@@ -27,6 +35,8 @@ interface CreateCloudSimulatorOptions {
|
|
|
27
35
|
bundlePath: string
|
|
28
36
|
device: string
|
|
29
37
|
authorization: string
|
|
38
|
+
/** the `--assets-dest` directory Metro wrote beside the bundle. */
|
|
39
|
+
assetsPath?: string
|
|
30
40
|
apiOrigin?: string
|
|
31
41
|
}
|
|
32
42
|
|
|
@@ -61,9 +71,7 @@ function resolveCloudOrigin(value?: string): string {
|
|
|
61
71
|
return normalizeCloudOrigin(source)
|
|
62
72
|
}
|
|
63
73
|
|
|
64
|
-
|
|
65
|
-
bundlePath: string,
|
|
66
|
-
): Promise<{ bytes: Buffer; sha256: string }> {
|
|
74
|
+
function readImmutableBundleSource(bundlePath: string): string {
|
|
67
75
|
const filepath = resolve(bundlePath)
|
|
68
76
|
if (extname(filepath) !== '.js') {
|
|
69
77
|
throw new Error('rnx ios --cloud requires one local Metro .js bundle')
|
|
@@ -77,11 +85,6 @@ async function readImmutableBundle(
|
|
|
77
85
|
if (before.size <= 0n) {
|
|
78
86
|
throw new Error('rnx ios --cloud bundle is empty')
|
|
79
87
|
}
|
|
80
|
-
if (before.size > BigInt(MAX_RNX_CLOUD_BUNDLE_BYTES)) {
|
|
81
|
-
throw new Error(
|
|
82
|
-
`rnx ios --cloud bundle exceeds the ${MAX_RNX_CLOUD_BUNDLE_BYTES}-byte limit`,
|
|
83
|
-
)
|
|
84
|
-
}
|
|
85
88
|
const bytes = readFileSync(descriptor)
|
|
86
89
|
const after = fstatSync(descriptor, { bigint: true })
|
|
87
90
|
if (
|
|
@@ -102,16 +105,61 @@ async function readImmutableBundle(
|
|
|
102
105
|
if (source.includes('\0') || !source.includes('__d(') || !source.includes('__r(')) {
|
|
103
106
|
throw new Error('rnx ios --cloud requires a Metro JavaScript bundle')
|
|
104
107
|
}
|
|
105
|
-
|
|
106
|
-
return {
|
|
107
|
-
bytes,
|
|
108
|
-
sha256: createHash('sha256').update(bytes).digest('hex'),
|
|
109
|
-
}
|
|
108
|
+
return source
|
|
110
109
|
} finally {
|
|
111
110
|
closeSync(descriptor)
|
|
112
111
|
}
|
|
113
112
|
}
|
|
114
113
|
|
|
114
|
+
// `react-native bundle --assets-dest <dir>` and `expo export:embed` write every
|
|
115
|
+
// scale variant with getAssetDestPathIOS: the descriptor's httpServerLocation
|
|
116
|
+
// without its leading slash, each `../` collapsed to `_`, then the asset name
|
|
117
|
+
// with its scale suffix. reading that layout is what lets an ordinary Metro
|
|
118
|
+
// build reach the cloud with no per-app script.
|
|
119
|
+
function metroAssetDestPath(assetsPath: string, variant: MetroAssetVariant): string {
|
|
120
|
+
const { descriptor, scale } = variant
|
|
121
|
+
const suffix = scale === 1 ? '' : `@${scale}x`
|
|
122
|
+
return join(
|
|
123
|
+
assetsPath,
|
|
124
|
+
descriptor.httpServerLocation.slice(1).replace(/\.\.\//g, '_'),
|
|
125
|
+
`${descriptor.name}${suffix}.${descriptor.type}`,
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* turns the Metro production bundle a caller built into the immutable artifact
|
|
131
|
+
* the runner executes: every asset scale is read from the asset graph and
|
|
132
|
+
* embedded, module identity is normalized, and the JavaScript is minified.
|
|
133
|
+
*/
|
|
134
|
+
async function produceCloudArtifact(
|
|
135
|
+
bundlePath: string,
|
|
136
|
+
assetsPath: string,
|
|
137
|
+
): Promise<{ bytes: Buffer; sha256: string; receipt: RnxCloudArtifactReceipt }> {
|
|
138
|
+
const source = readImmutableBundleSource(bundlePath)
|
|
139
|
+
const embedded = await embedMetroAssetFiles(source, async (variant) => {
|
|
140
|
+
const file = metroAssetDestPath(assetsPath, variant)
|
|
141
|
+
try {
|
|
142
|
+
return readFileSync(file)
|
|
143
|
+
} catch {
|
|
144
|
+
throw new Error(
|
|
145
|
+
`rnx ios --cloud could not read ${file} for ${variant.descriptor.name}.${variant.descriptor.type} at scale ${variant.scale}. Build the bundle with --assets-dest, or pass --assets <dir>.`,
|
|
146
|
+
)
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
const artifact = await buildRnxCloudArtifact(embedded.code)
|
|
150
|
+
const bytes = Buffer.from(artifact.code, 'utf8')
|
|
151
|
+
if (bytes.length > MAX_RNX_CLOUD_BUNDLE_BYTES) {
|
|
152
|
+
throw new Error(
|
|
153
|
+
`rnx ios --cloud artifact is ${bytes.length} bytes and exceeds the ${MAX_RNX_CLOUD_BUNDLE_BYTES}-byte limit`,
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
bytes,
|
|
158
|
+
sha256: createHash('sha256').update(bytes).digest('hex'),
|
|
159
|
+
receipt: artifact.receipt,
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
115
163
|
function readCreateResponse(
|
|
116
164
|
value: unknown,
|
|
117
165
|
expectedBytes: number,
|
|
@@ -155,9 +203,16 @@ function readCreateResponse(
|
|
|
155
203
|
|
|
156
204
|
export async function createCloudSimulator(
|
|
157
205
|
options: CreateCloudSimulatorOptions,
|
|
158
|
-
): Promise<{
|
|
206
|
+
): Promise<{
|
|
207
|
+
receipt: RnxCloudCreateReceipt
|
|
208
|
+
session: CloudSession
|
|
209
|
+
artifact: RnxCloudArtifactReceipt
|
|
210
|
+
}> {
|
|
159
211
|
const apiOrigin = resolveCloudOrigin(options.apiOrigin)
|
|
160
|
-
const artifact = await
|
|
212
|
+
const artifact = await produceCloudArtifact(
|
|
213
|
+
options.bundlePath,
|
|
214
|
+
resolve(options.assetsPath ?? dirname(options.bundlePath)),
|
|
215
|
+
)
|
|
161
216
|
let response: Response
|
|
162
217
|
try {
|
|
163
218
|
response = await fetch(`${apiOrigin}/v1/sims`, {
|
|
@@ -193,7 +248,7 @@ export async function createCloudSimulator(
|
|
|
193
248
|
claimId: created.receipt.claim.id,
|
|
194
249
|
token: created.token,
|
|
195
250
|
})
|
|
196
|
-
return { receipt: created.receipt, session }
|
|
251
|
+
return { receipt: created.receipt, session, artifact: artifact.receipt }
|
|
197
252
|
}
|
|
198
253
|
|
|
199
254
|
export function resolveCloudSessionForParsed(
|
|
@@ -219,40 +274,7 @@ function cloudCommand(command: {
|
|
|
219
274
|
for (const [key, value] of Object.entries(command)) {
|
|
220
275
|
if (key !== 'id' && key !== 'simId') clean[key] = value
|
|
221
276
|
}
|
|
222
|
-
if (command.type
|
|
223
|
-
const query = command.query
|
|
224
|
-
if (
|
|
225
|
-
!isRecord(query) ||
|
|
226
|
-
(query.kind !== 'tree' && query.kind !== 'find' && query.kind !== 'count')
|
|
227
|
-
) {
|
|
228
|
-
throw new Error('RNX Cloud supports only structured tree, node, and count queries')
|
|
229
|
-
}
|
|
230
|
-
return clean
|
|
231
|
-
}
|
|
232
|
-
if (command.type === 'waitFor') {
|
|
233
|
-
const options = command.waitForOptions
|
|
234
|
-
const condition = isRecord(options) ? options.condition : null
|
|
235
|
-
if (
|
|
236
|
-
!isRecord(condition) ||
|
|
237
|
-
(condition.type !== 'ready' &&
|
|
238
|
-
condition.type !== 'present' &&
|
|
239
|
-
condition.type !== 'absent')
|
|
240
|
-
) {
|
|
241
|
-
throw new Error('RNX Cloud supports only ready and selector waits')
|
|
242
|
-
}
|
|
243
|
-
return clean
|
|
244
|
-
}
|
|
245
|
-
if (command.type === 'state') return clean
|
|
246
|
-
if (command.type === 'capture' || command.type === 'captureRegions') return clean
|
|
247
|
-
if (command.type === 'setAppearance' || command.type === 'openUrl') return clean
|
|
248
|
-
if (
|
|
249
|
-
command.type === 'screenshot' &&
|
|
250
|
-
command.crop === undefined &&
|
|
251
|
-
command.captureFilter === undefined &&
|
|
252
|
-
(command.layers === undefined || command.layers === 'tenant')
|
|
253
|
-
) {
|
|
254
|
-
return clean
|
|
255
|
-
}
|
|
277
|
+
if (isRnxCloudCommandType(command.type)) return clean
|
|
256
278
|
throw new Error(`RNX Cloud does not support bridge command type ${command.type}`)
|
|
257
279
|
}
|
|
258
280
|
|
package/cli/cloud-dispatch.ts
CHANGED
|
@@ -47,7 +47,7 @@ function supportsCloudRead(
|
|
|
47
47
|
if (command === 'state') return firstVerb(positional) === null
|
|
48
48
|
if (command === 'get') {
|
|
49
49
|
const verb = firstVerb(positional)
|
|
50
|
-
return verb === 'tree' || verb === 'node' || verb === 'count'
|
|
50
|
+
return verb === 'tree' || verb === 'node' || verb === 'count' || verb === 'memory'
|
|
51
51
|
}
|
|
52
52
|
if (command === 'wait') {
|
|
53
53
|
const verb = firstVerb(positional)
|
|
@@ -77,6 +77,7 @@ function supportsCloudRead(
|
|
|
77
77
|
].includes(arg),
|
|
78
78
|
)
|
|
79
79
|
}
|
|
80
|
+
if (command === 'do' || command === 'reset') return true
|
|
80
81
|
return false
|
|
81
82
|
}
|
|
82
83
|
|
|
@@ -1095,8 +1095,16 @@ export async function inspectWaitReady(
|
|
|
1095
1095
|
}
|
|
1096
1096
|
}
|
|
1097
1097
|
const probe = result.probe
|
|
1098
|
+
// a guest app that redboxes still paints: its ErrorBoundary is a real tree
|
|
1099
|
+
// with real nodes, so the engine's own readiness condition matches and every
|
|
1100
|
+
// caller reads exit 0 as "the app is up". an app that has errored is not
|
|
1101
|
+
// ready, so a guest error is disqualifying here rather than merely printed
|
|
1102
|
+
// on the failure path. `errors` (a console.error count) is deliberately not
|
|
1103
|
+
// used because apps can log errors benignly. `suppressedEntryError` remains
|
|
1104
|
+
// excluded because it never gates readiness by contract.
|
|
1105
|
+
const externalError = probe?.externalError ?? ''
|
|
1098
1106
|
const status: WaitReadyStatus = {
|
|
1099
|
-
ready: result.matched,
|
|
1107
|
+
ready: result.matched && !externalError,
|
|
1100
1108
|
elapsedMs: result.elapsedMs,
|
|
1101
1109
|
nodes: probe?.nodes ?? 0,
|
|
1102
1110
|
targets: probe?.targets ?? 0,
|
|
@@ -1107,7 +1115,7 @@ export async function inspectWaitReady(
|
|
|
1107
1115
|
loadingText: probe?.loadingText ?? '',
|
|
1108
1116
|
externalReady: probe?.externalReady ?? null,
|
|
1109
1117
|
externalStatus: probe?.externalStatus ?? '',
|
|
1110
|
-
externalError
|
|
1118
|
+
externalError,
|
|
1111
1119
|
suppressedEntryError: probe?.suppressedEntryError ?? '',
|
|
1112
1120
|
errors: probe?.errors ?? 0,
|
|
1113
1121
|
bridgeError: result.error ?? '',
|
|
@@ -1835,6 +1843,29 @@ export interface MemoryReport {
|
|
|
1835
1843
|
// picture and raster image — answers through its stats channel.
|
|
1836
1844
|
// performance.memory is chrome-only, null on webkit.
|
|
1837
1845
|
export async function inspectMemory(bridge: InspectBridge): Promise<MemoryReport> {
|
|
1846
|
+
if (bridge.plane === 'cloud') {
|
|
1847
|
+
const value: unknown = await bridge.send({ type: 'memory' })
|
|
1848
|
+
const rawWasmHeapBytes =
|
|
1849
|
+
typeof value === 'object' && value !== null
|
|
1850
|
+
? Reflect.get(value, 'wasmHeapBytes')
|
|
1851
|
+
: null
|
|
1852
|
+
const wasmHeapBytes = typeof rawWasmHeapBytes === 'number' ? rawWasmHeapBytes : null
|
|
1853
|
+
return {
|
|
1854
|
+
tenant: {
|
|
1855
|
+
nodesRegistered: null,
|
|
1856
|
+
nodesDetached: null,
|
|
1857
|
+
detachedTypes: null,
|
|
1858
|
+
objects: null,
|
|
1859
|
+
activeNativeAnimations: null,
|
|
1860
|
+
imageLoader: null,
|
|
1861
|
+
workerHeap: null,
|
|
1862
|
+
wasmHeapBytes,
|
|
1863
|
+
},
|
|
1864
|
+
shell: null,
|
|
1865
|
+
compositor: null,
|
|
1866
|
+
hostHeap: null,
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1838
1869
|
const result = (await bridge.send({
|
|
1839
1870
|
type: 'evaluate',
|
|
1840
1871
|
code: `(async () => {
|
package/cli/commands/platform.ts
CHANGED
|
@@ -26,8 +26,15 @@ function isDeviceModel(value: string): value is DeviceModel {
|
|
|
26
26
|
return value in devices
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
const CLOUD_USAGE =
|
|
30
|
+
'usage: rnx ios --cloud <local bundle.js> [--assets <dir>] [--device <model>]'
|
|
31
|
+
|
|
32
|
+
function cloudInputFromArgs(args: string[]): {
|
|
33
|
+
bundlePath: string
|
|
34
|
+
assetsPath: string | null
|
|
35
|
+
} {
|
|
30
36
|
const positional: string[] = []
|
|
37
|
+
let assetsPath: string | null = null
|
|
31
38
|
for (let index = 0; index < args.length; index++) {
|
|
32
39
|
const arg = args[index]
|
|
33
40
|
if (arg === '--cloud') continue
|
|
@@ -35,6 +42,16 @@ function cloudBundleFromArgs(args: string[]): string | null {
|
|
|
35
42
|
index++
|
|
36
43
|
continue
|
|
37
44
|
}
|
|
45
|
+
if (arg === '--assets') {
|
|
46
|
+
assetsPath = args[++index] ?? null
|
|
47
|
+
if (!assetsPath) throw new Error('rnx ios --cloud --assets requires a directory')
|
|
48
|
+
continue
|
|
49
|
+
}
|
|
50
|
+
if (arg.startsWith('--assets=')) {
|
|
51
|
+
assetsPath = arg.slice('--assets='.length) || null
|
|
52
|
+
if (!assetsPath) throw new Error('rnx ios --cloud --assets requires a directory')
|
|
53
|
+
continue
|
|
54
|
+
}
|
|
38
55
|
if (
|
|
39
56
|
arg === '--sim' ||
|
|
40
57
|
arg === '--session' ||
|
|
@@ -50,10 +67,8 @@ function cloudBundleFromArgs(args: string[]): string | null {
|
|
|
50
67
|
}
|
|
51
68
|
positional.push(arg)
|
|
52
69
|
}
|
|
53
|
-
if (positional.length !== 1)
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
return positional[0] ?? null
|
|
70
|
+
if (positional.length !== 1 || !positional[0]) throw new Error(CLOUD_USAGE)
|
|
71
|
+
return { bundlePath: positional[0], assetsPath }
|
|
57
72
|
}
|
|
58
73
|
|
|
59
74
|
export async function runPlatformCommand(
|
|
@@ -107,8 +122,7 @@ export async function runPlatformCommand(
|
|
|
107
122
|
return 1
|
|
108
123
|
}
|
|
109
124
|
try {
|
|
110
|
-
const
|
|
111
|
-
if (!bundlePath) throw new Error('rnx ios --cloud requires a local bundle.js')
|
|
125
|
+
const input = cloudInputFromArgs(args)
|
|
112
126
|
const {
|
|
113
127
|
publishCloudSessionToShell,
|
|
114
128
|
readCloudSession,
|
|
@@ -125,7 +139,8 @@ export async function runPlatformCommand(
|
|
|
125
139
|
await import('../cloud-client')
|
|
126
140
|
const { header } = authHeaderOrExit('ios --cloud')
|
|
127
141
|
const created = await createCloudSimulator({
|
|
128
|
-
bundlePath,
|
|
142
|
+
bundlePath: input.bundlePath,
|
|
143
|
+
assetsPath: input.assetsPath ?? undefined,
|
|
129
144
|
device: selectedDevice,
|
|
130
145
|
authorization: header,
|
|
131
146
|
})
|
|
@@ -136,11 +151,21 @@ export async function runPlatformCommand(
|
|
|
136
151
|
throw error
|
|
137
152
|
}
|
|
138
153
|
const receipt = created.receipt
|
|
154
|
+
const produced = created.artifact
|
|
139
155
|
console.log(` cloud sim: ${receipt.simId}`)
|
|
140
156
|
console.log(` artifact: ${receipt.artifact.id} (${receipt.artifact.bytes} bytes)`)
|
|
157
|
+
console.log(
|
|
158
|
+
` source bundle: sha256:${produced.source.sha256} (${produced.source.bytes} bytes)`,
|
|
159
|
+
)
|
|
160
|
+
console.log(
|
|
161
|
+
` normalized modules: ${produced.modules}; javascript ${produced.javascript.sourceBytes} -> ${produced.javascript.minifiedBytes} bytes`,
|
|
162
|
+
)
|
|
163
|
+
console.log(
|
|
164
|
+
` embedded assets: ${produced.assets.descriptors} descriptors, ${produced.assets.variants} scales, ${produced.assets.bytes} bytes (${produced.assets.encodedBytes} encoded)`,
|
|
165
|
+
)
|
|
141
166
|
console.log(` claim expires: ${receipt.claim.expiresAt}`)
|
|
142
167
|
console.log(
|
|
143
|
-
'
|
|
168
|
+
' commands: describe, find, get tree|node|count|memory, wait ready|selector, do, reset, logs, state, screenshot',
|
|
144
169
|
)
|
|
145
170
|
return 0
|
|
146
171
|
} catch (error) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __defProp = Object.defineProperty;
|
package/dist-lib/beta.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __defProp = Object.defineProperty;
|
package/dist-lib/beta.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -33,6 +33,11 @@ __export(bridge_contract_input_exports, {
|
|
|
33
33
|
parseStateOptions: () => parseStateOptions
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(bridge_contract_input_exports);
|
|
36
|
+
|
|
37
|
+
// src/bridge-contract.ts
|
|
38
|
+
var SIM_LONG_PRESS_MAX_MS = 5e3;
|
|
39
|
+
|
|
40
|
+
// src/bridge-contract-input.ts
|
|
36
41
|
var BridgeInputError = class extends Error {
|
|
37
42
|
constructor(message) {
|
|
38
43
|
super(message);
|
|
@@ -123,6 +128,12 @@ function parsePerformStep(value, index) {
|
|
|
123
128
|
}
|
|
124
129
|
case "longPress": {
|
|
125
130
|
const durationMs = optionalNumber(step, "durationMs", path);
|
|
131
|
+
if (durationMs !== void 0 && (!Number.isInteger(durationMs) || durationMs < 1 || durationMs > SIM_LONG_PRESS_MAX_MS)) {
|
|
132
|
+
validationFailure(
|
|
133
|
+
`${path}.durationMs`,
|
|
134
|
+
`must be an integer between 1 and ${SIM_LONG_PRESS_MAX_MS}`
|
|
135
|
+
);
|
|
136
|
+
}
|
|
126
137
|
return {
|
|
127
138
|
type,
|
|
128
139
|
x: numberValue(step.x, `${path}.x`),
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
|
|
3
|
+
// src/bridge-contract.ts
|
|
4
|
+
var SIM_LONG_PRESS_MAX_MS = 5e3;
|
|
2
5
|
|
|
3
6
|
// src/bridge-contract-input.ts
|
|
4
7
|
var BridgeInputError = class extends Error {
|
|
@@ -91,6 +94,12 @@ function parsePerformStep(value, index) {
|
|
|
91
94
|
}
|
|
92
95
|
case "longPress": {
|
|
93
96
|
const durationMs = optionalNumber(step, "durationMs", path);
|
|
97
|
+
if (durationMs !== void 0 && (!Number.isInteger(durationMs) || durationMs < 1 || durationMs > SIM_LONG_PRESS_MAX_MS)) {
|
|
98
|
+
validationFailure(
|
|
99
|
+
`${path}.durationMs`,
|
|
100
|
+
`must be an integer between 1 and ${SIM_LONG_PRESS_MAX_MS}`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
94
103
|
return {
|
|
95
104
|
type,
|
|
96
105
|
x: numberValue(step.x, `${path}.x`),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -25,10 +25,14 @@ __export(bridge_contract_exports, {
|
|
|
25
25
|
SEMANTIC_READY_CONTENT_NODE_FLOOR: () => SEMANTIC_READY_CONTENT_NODE_FLOOR,
|
|
26
26
|
SEMANTIC_READY_NODE_STABLE_MS: () => SEMANTIC_READY_NODE_STABLE_MS,
|
|
27
27
|
SEMANTIC_READY_POLL_MS: () => SEMANTIC_READY_POLL_MS,
|
|
28
|
+
SIM_LONG_PRESS_DEFAULT_MS: () => SIM_LONG_PRESS_DEFAULT_MS,
|
|
29
|
+
SIM_LONG_PRESS_MAX_MS: () => SIM_LONG_PRESS_MAX_MS,
|
|
28
30
|
readyProbeHasContent: () => readyProbeHasContent,
|
|
29
31
|
readyProbeHasTargetContent: () => readyProbeHasTargetContent
|
|
30
32
|
});
|
|
31
33
|
module.exports = __toCommonJS(bridge_contract_exports);
|
|
34
|
+
var SIM_LONG_PRESS_DEFAULT_MS = 500;
|
|
35
|
+
var SIM_LONG_PRESS_MAX_MS = 5e3;
|
|
32
36
|
var SEMANTIC_READY_CONTENT_NODE_FLOOR = 100;
|
|
33
37
|
var SEMANTIC_READY_NODE_STABLE_MS = 750;
|
|
34
38
|
var SEMANTIC_READY_POLL_MS = 150;
|
|
@@ -43,6 +47,8 @@ function readyProbeHasTargetContent(probe) {
|
|
|
43
47
|
SEMANTIC_READY_CONTENT_NODE_FLOOR,
|
|
44
48
|
SEMANTIC_READY_NODE_STABLE_MS,
|
|
45
49
|
SEMANTIC_READY_POLL_MS,
|
|
50
|
+
SIM_LONG_PRESS_DEFAULT_MS,
|
|
51
|
+
SIM_LONG_PRESS_MAX_MS,
|
|
46
52
|
readyProbeHasContent,
|
|
47
53
|
readyProbeHasTargetContent
|
|
48
54
|
});
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
|
|
3
3
|
// src/bridge-contract.ts
|
|
4
|
+
var SIM_LONG_PRESS_DEFAULT_MS = 500;
|
|
5
|
+
var SIM_LONG_PRESS_MAX_MS = 5e3;
|
|
4
6
|
var SEMANTIC_READY_CONTENT_NODE_FLOOR = 100;
|
|
5
7
|
var SEMANTIC_READY_NODE_STABLE_MS = 750;
|
|
6
8
|
var SEMANTIC_READY_POLL_MS = 150;
|
|
@@ -14,6 +16,8 @@ export {
|
|
|
14
16
|
SEMANTIC_READY_CONTENT_NODE_FLOOR,
|
|
15
17
|
SEMANTIC_READY_NODE_STABLE_MS,
|
|
16
18
|
SEMANTIC_READY_POLL_MS,
|
|
19
|
+
SIM_LONG_PRESS_DEFAULT_MS,
|
|
20
|
+
SIM_LONG_PRESS_MAX_MS,
|
|
17
21
|
readyProbeHasContent,
|
|
18
22
|
readyProbeHasTargetContent
|
|
19
23
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -22,20 +22,46 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
22
22
|
// src/cloud-contract.ts
|
|
23
23
|
var cloud_contract_exports = {};
|
|
24
24
|
__export(cloud_contract_exports, {
|
|
25
|
+
RNX_CLOUD_COMMAND_TYPES: () => RNX_CLOUD_COMMAND_TYPES,
|
|
25
26
|
RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES: () => RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES,
|
|
26
27
|
RNX_CLOUD_DESIGN_MAX_STORAGE_ENTRIES: () => RNX_CLOUD_DESIGN_MAX_STORAGE_ENTRIES,
|
|
27
28
|
RNX_CLOUD_DESIGN_PARALLEL_JOB_LIMIT: () => RNX_CLOUD_DESIGN_PARALLEL_JOB_LIMIT,
|
|
28
|
-
RNX_CLOUD_MAX_ARTIFACT_BYTES: () => RNX_CLOUD_MAX_ARTIFACT_BYTES
|
|
29
|
+
RNX_CLOUD_MAX_ARTIFACT_BYTES: () => RNX_CLOUD_MAX_ARTIFACT_BYTES,
|
|
30
|
+
isRnxCloudCommandType: () => isRnxCloudCommandType
|
|
29
31
|
});
|
|
30
32
|
module.exports = __toCommonJS(cloud_contract_exports);
|
|
31
33
|
var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
|
|
32
34
|
var RNX_CLOUD_DESIGN_PARALLEL_JOB_LIMIT = 16;
|
|
33
35
|
var RNX_CLOUD_DESIGN_MAX_STORAGE_ENTRIES = 256;
|
|
34
36
|
var RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES = 1024 * 1024;
|
|
37
|
+
var RNX_CLOUD_COMMAND_TYPES = Object.freeze([
|
|
38
|
+
"state",
|
|
39
|
+
"query",
|
|
40
|
+
"resolve",
|
|
41
|
+
"perform",
|
|
42
|
+
"waitFor",
|
|
43
|
+
"reset",
|
|
44
|
+
"screenshot",
|
|
45
|
+
"capture",
|
|
46
|
+
"captureRegions",
|
|
47
|
+
"settle",
|
|
48
|
+
"setAppearance",
|
|
49
|
+
"openUrl",
|
|
50
|
+
"tree",
|
|
51
|
+
"tap",
|
|
52
|
+
"longPress",
|
|
53
|
+
"memory"
|
|
54
|
+
]);
|
|
55
|
+
var RNX_CLOUD_COMMAND_TYPE_SET = new Set(RNX_CLOUD_COMMAND_TYPES);
|
|
56
|
+
function isRnxCloudCommandType(value) {
|
|
57
|
+
return RNX_CLOUD_COMMAND_TYPE_SET.has(value);
|
|
58
|
+
}
|
|
35
59
|
// Annotate the CommonJS export names for ESM import in node:
|
|
36
60
|
0 && (module.exports = {
|
|
61
|
+
RNX_CLOUD_COMMAND_TYPES,
|
|
37
62
|
RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES,
|
|
38
63
|
RNX_CLOUD_DESIGN_MAX_STORAGE_ENTRIES,
|
|
39
64
|
RNX_CLOUD_DESIGN_PARALLEL_JOB_LIMIT,
|
|
40
|
-
RNX_CLOUD_MAX_ARTIFACT_BYTES
|
|
65
|
+
RNX_CLOUD_MAX_ARTIFACT_BYTES,
|
|
66
|
+
isRnxCloudCommandType
|
|
41
67
|
});
|