rnxsim 0.1.499 → 0.1.501
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 +1 -1
- package/cli/bridge-flow-runner.ts +6 -2
- package/cli/cloud-client.ts +90 -7
- package/cli/cloud-dispatch.ts +27 -27
- package/cli/cloud-session.ts +61 -6
- package/cli/commands/control.ts +33 -31
- package/cli/commands/detox.ts +157 -159
- package/cli/commands/inspect/core.ts +2 -0
- package/cli/commands/platform.ts +170 -48
- package/cli/commands/preview.ts +1 -1
- package/cli/commands/test.ts +403 -95
- package/cli/main.ts +11 -0
- package/cli/outbound-endpoints.ts +10 -0
- package/cli/ws-bridge.ts +18 -19
- package/detox/jest-preset.cjs +1 -6
- 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 +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -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 +7 -1
- package/dist-lib/cloud-contract.mjs +5 -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/detox/index.cjs +1 -1
- package/dist-lib/detox/jest-preset.cjs +1 -6
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +54 -29
- 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 +52 -22
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- 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 +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/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +7 -8
- package/dist-lib/sdk.mjs +7 -8
- package/dist-lib/skills.cjs +128 -63
- package/dist-lib/vite.cjs +1 -1
- package/package.json +1 -1
- package/skills/rnx-test/SKILL.md +2 -2
- package/src/cloud-contract.ts +2 -0
- package/src/sim-client.ts +8 -10
package/cli/commands/platform.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
// `rnx ios` and `rnx android` — start a simulator on that platform.
|
|
2
2
|
//
|
|
3
|
-
// the platform picks the device; the command context picks
|
|
4
|
-
// (this machine, a local box, or
|
|
5
|
-
//
|
|
6
|
-
// device and hands the rest to the normal open path.
|
|
3
|
+
// the platform picks the device; the command context picks where the sim runs
|
|
4
|
+
// (this machine, a local box, or the `rnx remote` namespace). this file resolves
|
|
5
|
+
// the device and hands the rest to the normal open path.
|
|
7
6
|
|
|
8
7
|
import {
|
|
9
8
|
DEFAULT_DEVICE_BY_PLATFORM,
|
|
@@ -15,6 +14,7 @@ import {
|
|
|
15
14
|
} from 'sootsim-engine/settings'
|
|
16
15
|
import { settingsStore } from 'sootsim-engine/settings/store'
|
|
17
16
|
import { rnxPublicBrand } from '../../src/public-brand'
|
|
17
|
+
import { UnsupportedRemoteHostError } from '../cloud-client'
|
|
18
18
|
import { rethrowIfExit } from '../run-rnx'
|
|
19
19
|
|
|
20
20
|
const PLATFORM_LABEL: Record<RuntimePlatform, string> = {
|
|
@@ -26,13 +26,13 @@ function isDeviceModel(value: string): value is DeviceModel {
|
|
|
26
26
|
return value in devices
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
const REMOTE_USAGE =
|
|
30
|
-
'usage: rnx ios --remote <local bundle.js|https://bundle-url> [--device <model>]'
|
|
31
|
-
|
|
32
29
|
// flags this command reads for itself rather than treating as the bundle.
|
|
33
30
|
const REMOTE_VALUE_FLAGS = new Set(['--device', '--name', '--endpoint'])
|
|
34
31
|
|
|
35
|
-
function remoteInputFromArgs(
|
|
32
|
+
function remoteInputFromArgs(
|
|
33
|
+
args: string[],
|
|
34
|
+
platform: RuntimePlatform,
|
|
35
|
+
): {
|
|
36
36
|
bundlePath: string
|
|
37
37
|
name: string | null
|
|
38
38
|
} {
|
|
@@ -43,14 +43,15 @@ function remoteInputFromArgs(args: string[]): {
|
|
|
43
43
|
if (arg === '--remote' || arg === '--nano') continue
|
|
44
44
|
if (REMOTE_VALUE_FLAGS.has(arg)) {
|
|
45
45
|
const value = args[++index] ?? null
|
|
46
|
-
if (!value) throw new Error(`rnx
|
|
46
|
+
if (!value) throw new Error(`rnx remote ${platform} ${arg} requires a value`)
|
|
47
47
|
if (arg === '--name') name = value
|
|
48
48
|
continue
|
|
49
49
|
}
|
|
50
50
|
const assigned = arg.match(/^(--[a-z-]+)=(.*)$/)
|
|
51
51
|
if (assigned && REMOTE_VALUE_FLAGS.has(assigned[1] ?? '')) {
|
|
52
52
|
const value = assigned[2] ?? ''
|
|
53
|
-
if (!value)
|
|
53
|
+
if (!value)
|
|
54
|
+
throw new Error(`rnx remote ${platform} ${assigned[1]} requires a value`)
|
|
54
55
|
if (assigned[1] === '--name') name = value
|
|
55
56
|
continue
|
|
56
57
|
}
|
|
@@ -62,14 +63,20 @@ function remoteInputFromArgs(args: string[]): {
|
|
|
62
63
|
arg.startsWith('--session=') ||
|
|
63
64
|
arg.startsWith('--tab=')
|
|
64
65
|
) {
|
|
65
|
-
throw new Error(
|
|
66
|
+
throw new Error(
|
|
67
|
+
`rnx remote ${platform} creates a new simulator and cannot target --sim`,
|
|
68
|
+
)
|
|
66
69
|
}
|
|
67
70
|
if (arg.startsWith('-')) {
|
|
68
|
-
throw new Error(`rnx
|
|
71
|
+
throw new Error(`rnx remote ${platform} does not support ${arg}`)
|
|
69
72
|
}
|
|
70
73
|
positional.push(arg)
|
|
71
74
|
}
|
|
72
|
-
if (positional.length !== 1 || !positional[0])
|
|
75
|
+
if (positional.length !== 1 || !positional[0]) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
`usage: rnx remote ${platform} <local bundle.js|https://bundle-url> [--device <model>]`,
|
|
78
|
+
)
|
|
79
|
+
}
|
|
73
80
|
return { bundlePath: positional[0], name }
|
|
74
81
|
}
|
|
75
82
|
|
|
@@ -87,7 +94,7 @@ function boxNameForBundle(bundlePath: string): string {
|
|
|
87
94
|
.toLowerCase()
|
|
88
95
|
.replace(/[^a-z0-9]+/g, '-')
|
|
89
96
|
.replace(/^-+|-+$/g, '')
|
|
90
|
-
if (!name) throw new Error(`rnx
|
|
97
|
+
if (!name) throw new Error(`rnx remote could not name a box after ${bundlePath}`)
|
|
91
98
|
return name
|
|
92
99
|
}
|
|
93
100
|
|
|
@@ -99,7 +106,9 @@ export async function runPlatformCommand(
|
|
|
99
106
|
// `--device` is applied to the settings store before dispatch, so a
|
|
100
107
|
// contradiction shows up here as a platform mismatch. refuse it by name
|
|
101
108
|
// rather than silently overriding whichever one the user meant.
|
|
102
|
-
const
|
|
109
|
+
const assignedDevice = args.find((arg) => arg.startsWith('--device='))
|
|
110
|
+
const explicitDevice =
|
|
111
|
+
args.find((_, i) => args[i - 1] === '--device') ?? assignedDevice?.slice(9)
|
|
103
112
|
let selectedDevice: DeviceModel
|
|
104
113
|
if (explicitDevice !== undefined) {
|
|
105
114
|
if (!isDeviceModel(explicitDevice)) {
|
|
@@ -135,15 +144,16 @@ export async function runPlatformCommand(
|
|
|
135
144
|
}
|
|
136
145
|
|
|
137
146
|
if (args.includes('--remote')) {
|
|
138
|
-
if (platform
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
)
|
|
147
|
+
if (platform === 'android' && args.includes('--nano')) {
|
|
148
|
+
const error = new UnsupportedRemoteHostError('android', 'nano')
|
|
149
|
+
console.error(` ${error.message}`)
|
|
142
150
|
return 1
|
|
143
151
|
}
|
|
144
152
|
try {
|
|
145
|
-
const input = remoteInputFromArgs(args)
|
|
146
|
-
if (!args.includes('--nano'))
|
|
153
|
+
const input = remoteInputFromArgs(args, platform)
|
|
154
|
+
if (!args.includes('--nano')) {
|
|
155
|
+
return await runRemoteBox(input, args, platform, selectedDevice)
|
|
156
|
+
}
|
|
147
157
|
const {
|
|
148
158
|
publishCloudSessionToShell,
|
|
149
159
|
readCloudSession,
|
|
@@ -151,30 +161,63 @@ export async function runPlatformCommand(
|
|
|
151
161
|
} = await import('../cloud-session')
|
|
152
162
|
const descriptor = requireCloudSessionShellUpdate()
|
|
153
163
|
const { authHeaderOrExit, cloudAccountIdOrExit } = await import('../auth')
|
|
154
|
-
const { auth, header } = authHeaderOrExit(
|
|
164
|
+
const { auth, header } = authHeaderOrExit(`${platform} --remote`)
|
|
155
165
|
const accountId = cloudAccountIdOrExit(auth)
|
|
166
|
+
const { closeCloudBox, createCloudBox, claimCloudSimulator, addCloudSimulator } =
|
|
167
|
+
await import('../cloud-client')
|
|
168
|
+
const artifact = await (
|
|
169
|
+
await import('../cloud-client')
|
|
170
|
+
).produceCloudArtifact(input.bundlePath)
|
|
156
171
|
const existingSession = readCloudSession()
|
|
157
|
-
if (
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
172
|
+
if (
|
|
173
|
+
existingSession &&
|
|
174
|
+
existingSession.service === 'sim' &&
|
|
175
|
+
existingSession.platform === platform &&
|
|
176
|
+
existingSession.artifact?.sha256 &&
|
|
177
|
+
existingSession.artifact.sha256 === artifact.sha256 &&
|
|
178
|
+
args.includes('--reconnect')
|
|
179
|
+
) {
|
|
180
|
+
const claimed = await claimCloudSimulator(existingSession)
|
|
181
|
+
publishCloudSessionToShell(claimed.session, descriptor)
|
|
182
|
+
console.log(
|
|
183
|
+
` reconnected to remote simulator: ${existingSession.simId} (${platform})`,
|
|
184
|
+
)
|
|
185
|
+
console.log(` claim expires: ${claimed.claim.expiresAt}`)
|
|
167
186
|
console.log(
|
|
168
187
|
' commands: describe, find, get tree|node|count|memory, wait ready|selector, do, reset, logs, state, screenshot',
|
|
169
188
|
)
|
|
170
189
|
return 0
|
|
171
190
|
}
|
|
172
|
-
|
|
191
|
+
if (existingSession) {
|
|
192
|
+
if (
|
|
193
|
+
existingSession.service === 'sim' &&
|
|
194
|
+
(!existingSession.platform || existingSession.platform === platform) &&
|
|
195
|
+
(!existingSession.artifact ||
|
|
196
|
+
existingSession.artifact.sha256 === artifact.sha256 ||
|
|
197
|
+
args.includes('--new'))
|
|
198
|
+
) {
|
|
199
|
+
const added = await addCloudSimulator(existingSession, {
|
|
200
|
+
device: selectedDevice,
|
|
201
|
+
authorization: header,
|
|
202
|
+
accountId,
|
|
203
|
+
})
|
|
204
|
+
publishCloudSessionToShell(added.session, descriptor)
|
|
205
|
+
console.log(` remote simulator: ${added.receipt.simId}`)
|
|
206
|
+
console.log(` claim expires: ${added.receipt.claim.expiresAt}`)
|
|
207
|
+
console.log(
|
|
208
|
+
' commands: describe, find, get tree|node|count|memory, wait ready|selector, do, reset, logs, state, screenshot',
|
|
209
|
+
)
|
|
210
|
+
return 0
|
|
211
|
+
}
|
|
212
|
+
await closeCloudBox(existingSession)
|
|
213
|
+
publishCloudSessionToShell(null, descriptor)
|
|
214
|
+
}
|
|
173
215
|
const created = await createCloudBox({
|
|
174
216
|
bundlePath: input.bundlePath,
|
|
175
217
|
device: selectedDevice,
|
|
176
218
|
authorization: header,
|
|
177
219
|
accountId,
|
|
220
|
+
platform,
|
|
178
221
|
})
|
|
179
222
|
try {
|
|
180
223
|
publishCloudSessionToShell(created.session, descriptor)
|
|
@@ -185,6 +228,7 @@ export async function runPlatformCommand(
|
|
|
185
228
|
const receipt = created.receipt
|
|
186
229
|
const produced = created.artifact
|
|
187
230
|
console.log(` remote simulator: ${receipt.simulator.simId}`)
|
|
231
|
+
console.log(` platform: ${platform}`)
|
|
188
232
|
console.log(` artifact: ${receipt.artifact.id} (${receipt.artifact.bytes} bytes)`)
|
|
189
233
|
console.log(
|
|
190
234
|
` source bundle: sha256:${produced.source.sha256} (${produced.source.bytes} bytes)`,
|
|
@@ -209,7 +253,7 @@ export async function runPlatformCommand(
|
|
|
209
253
|
} catch (error) {
|
|
210
254
|
rethrowIfExit(error)
|
|
211
255
|
console.error(
|
|
212
|
-
` ${rnxPublicBrand.commandName}
|
|
256
|
+
` ${rnxPublicBrand.commandName} ${platform} --remote failed: ${
|
|
213
257
|
error instanceof Error ? error.message : String(error)
|
|
214
258
|
}`,
|
|
215
259
|
)
|
|
@@ -259,17 +303,16 @@ export function runRemotePlatformCommand(
|
|
|
259
303
|
args: string[],
|
|
260
304
|
opts: { port?: number } = {},
|
|
261
305
|
): Promise<number | undefined> {
|
|
262
|
-
if (platform === 'android') {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
)
|
|
306
|
+
if (platform === 'android' && args.includes('--nano')) {
|
|
307
|
+
const error = new UnsupportedRemoteHostError('android', 'nano')
|
|
308
|
+
console.error(` ${error.message}`)
|
|
266
309
|
return Promise.resolve(1)
|
|
267
310
|
}
|
|
268
311
|
return runPlatformCommand(platform, ['--remote', ...args], opts)
|
|
269
312
|
}
|
|
270
313
|
|
|
271
314
|
/**
|
|
272
|
-
* `rnx ios --remote` — the app runs in a Box.
|
|
315
|
+
* `rnx ios --remote` and `rnx android --remote` — the app runs in a Box.
|
|
273
316
|
*
|
|
274
317
|
* the artifact is produced here, self-contained, exactly as it always was: one
|
|
275
318
|
* JavaScript file with its Metro assets embedded, so nothing it needs is left
|
|
@@ -279,17 +322,69 @@ export function runRemotePlatformCommand(
|
|
|
279
322
|
async function runRemoteBox(
|
|
280
323
|
input: { bundlePath: string; name: string | null },
|
|
281
324
|
args: string[],
|
|
325
|
+
platform: RuntimePlatform = 'ios',
|
|
326
|
+
selectedDevice?: string,
|
|
282
327
|
): Promise<number> {
|
|
283
|
-
const command =
|
|
284
|
-
const [
|
|
285
|
-
|
|
328
|
+
const command = `${platform} --remote`
|
|
329
|
+
const [
|
|
330
|
+
{ produceCloudArtifact, closeCloudBox },
|
|
331
|
+
box,
|
|
332
|
+
{ readCloudBoxSession },
|
|
333
|
+
{ authHeaderOrExit, cloudAccountIdOrExit },
|
|
334
|
+
{
|
|
335
|
+
createCloudBoxSession,
|
|
336
|
+
publishCloudSessionToShell,
|
|
337
|
+
readCloudSession,
|
|
338
|
+
serializeCloudSession,
|
|
339
|
+
RNX_CLOUD_SESSION_ENV,
|
|
340
|
+
},
|
|
341
|
+
] = await Promise.all([
|
|
342
|
+
import('../cloud-client'),
|
|
343
|
+
import('./box'),
|
|
344
|
+
import('rnx-cloud-box/client'),
|
|
345
|
+
import('../auth'),
|
|
346
|
+
import('../cloud-session'),
|
|
347
|
+
])
|
|
348
|
+
const artifact = await produceCloudArtifact(input.bundlePath, Number.POSITIVE_INFINITY)
|
|
286
349
|
const endpoint = box.cloudBoxEndpoint(args, command)
|
|
287
350
|
if (!endpoint) return 1
|
|
351
|
+
|
|
352
|
+
const existingSession = readCloudSession()
|
|
353
|
+
if (
|
|
354
|
+
existingSession &&
|
|
355
|
+
existingSession.service === 'box' &&
|
|
356
|
+
existingSession.apiOrigin === endpoint &&
|
|
357
|
+
existingSession.platform === platform &&
|
|
358
|
+
existingSession.device === selectedDevice &&
|
|
359
|
+
existingSession.artifact?.sha256 === artifact.sha256
|
|
360
|
+
) {
|
|
361
|
+
const live = await readCloudBoxSession({
|
|
362
|
+
endpoint: existingSession.apiOrigin,
|
|
363
|
+
boxId: existingSession.boxId,
|
|
364
|
+
accessToken: existingSession.boxToken,
|
|
365
|
+
})
|
|
366
|
+
if (live.sessionId) {
|
|
367
|
+
console.log(
|
|
368
|
+
` reconnected to remote simulator: ${existingSession.boxId} (${platform})`,
|
|
369
|
+
)
|
|
370
|
+
console.log(
|
|
371
|
+
' commands: describe, find, get tree|node|count|memory, wait ready|selector, do, reset, logs, state, screenshot',
|
|
372
|
+
)
|
|
373
|
+
return 0
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
288
377
|
const { auth, header } = authHeaderOrExit(command)
|
|
289
378
|
const accountId = cloudAccountIdOrExit(auth)
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
379
|
+
|
|
380
|
+
if (existingSession) {
|
|
381
|
+
await closeCloudBox(existingSession)
|
|
382
|
+
try {
|
|
383
|
+
publishCloudSessionToShell(null)
|
|
384
|
+
} catch {
|
|
385
|
+
// no shell update channel is required outside an interactive rnx shell
|
|
386
|
+
}
|
|
387
|
+
}
|
|
293
388
|
const created = await box.createPrebuiltBundleBox({
|
|
294
389
|
bundle: new Uint8Array(artifact.bytes),
|
|
295
390
|
name: input.name ?? boxNameForBundle(input.bundlePath),
|
|
@@ -299,7 +394,27 @@ async function runRemoteBox(
|
|
|
299
394
|
accountId,
|
|
300
395
|
})
|
|
301
396
|
const produced = artifact.receipt
|
|
397
|
+
const session = createCloudBoxSession({
|
|
398
|
+
boxId: created.id,
|
|
399
|
+
boxToken: created.accessToken ?? '',
|
|
400
|
+
apiOrigin: endpoint,
|
|
401
|
+
platform,
|
|
402
|
+
device: selectedDevice,
|
|
403
|
+
artifact: {
|
|
404
|
+
sha256: artifact.sha256,
|
|
405
|
+
bytes: artifact.bytes.length,
|
|
406
|
+
},
|
|
407
|
+
})
|
|
408
|
+
try {
|
|
409
|
+
publishCloudSessionToShell(session)
|
|
410
|
+
} catch {
|
|
411
|
+
// shell update fd not configured
|
|
412
|
+
}
|
|
413
|
+
process.env[RNX_CLOUD_SESSION_ENV] = serializeCloudSession(session)
|
|
414
|
+
|
|
302
415
|
console.log(` box: ${created.id} (${artifact.bytes.length} bytes)`)
|
|
416
|
+
console.log(` platform: ${platform}`)
|
|
417
|
+
if (selectedDevice) console.log(` device: ${selectedDevice}`)
|
|
303
418
|
console.log(
|
|
304
419
|
` source bundle: sha256:${produced.source.sha256} (${produced.source.bytes} bytes)`,
|
|
305
420
|
)
|
|
@@ -313,11 +428,18 @@ async function runRemoteBox(
|
|
|
313
428
|
// against it, so say which one won rather than leaving it invisible.
|
|
314
429
|
if (artifact.assetsDirectory) console.log(` asset dest: ${artifact.assetsDirectory}`)
|
|
315
430
|
for (const warning of artifact.warnings) console.warn(` warning: ${warning}`)
|
|
316
|
-
|
|
317
|
-
|
|
431
|
+
console.log(
|
|
432
|
+
' commands: describe, find, get tree|node|count|memory, wait ready|selector, do, reset, logs, state, screenshot',
|
|
433
|
+
)
|
|
434
|
+
if (!created.description.pageUrl) {
|
|
318
435
|
console.error(' the box service returned no page to open')
|
|
319
436
|
return 1
|
|
320
437
|
}
|
|
438
|
+
const pageUrl = new URL(created.description.pageUrl)
|
|
439
|
+
pageUrl.searchParams.set(
|
|
440
|
+
'device',
|
|
441
|
+
selectedDevice ?? DEFAULT_DEVICE_BY_PLATFORM[platform],
|
|
442
|
+
)
|
|
321
443
|
console.log(` open ${pageUrl}`)
|
|
322
|
-
return box.openInBrowser(pageUrl)
|
|
444
|
+
return box.openInBrowser(pageUrl.toString())
|
|
323
445
|
}
|
package/cli/commands/preview.ts
CHANGED
|
@@ -26,7 +26,7 @@ rnx preview — publish a prebuilt React Native bundle as a standalone share
|
|
|
26
26
|
usage:
|
|
27
27
|
rnx preview <bundle.js|https://bundle-url> [--platform ios|android] [--open]
|
|
28
28
|
|
|
29
|
-
The share contains the immutable build and its Metro assets. It is not a recorded replay.
|
|
29
|
+
The share contains the immutable build and its automatically discovered Metro assets. It is not a recorded replay.
|
|
30
30
|
`)
|
|
31
31
|
return 0
|
|
32
32
|
}
|