rnxsim 0.1.495 → 0.1.497

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.
Files changed (59) hide show
  1. package/cli/cloud-client.ts +33 -65
  2. package/cli/commands/box.ts +1 -2
  3. package/cli/commands/platform.ts +5 -14
  4. package/cli/commands/preview.ts +2 -3
  5. package/cli/help-core.ts +3 -3
  6. package/cli/send-to-box.ts +0 -3
  7. package/dist-lib/agent-daemon-client.cjs +1 -1
  8. package/dist-lib/agent-events.cjs +1 -1
  9. package/dist-lib/agent-identity.cjs +1 -1
  10. package/dist-lib/agent-sessions.cjs +1 -1
  11. package/dist-lib/attached-projects.cjs +1 -1
  12. package/dist-lib/auth/shared-session.cjs +1 -1
  13. package/dist-lib/backend-origin.cjs +1 -1
  14. package/dist-lib/beta.cjs +1 -1
  15. package/dist-lib/beta.mjs +1 -1
  16. package/dist-lib/bridge-constants.cjs +1 -1
  17. package/dist-lib/bridge-contract-input.cjs +1 -1
  18. package/dist-lib/bridge-contract-input.mjs +1 -1
  19. package/dist-lib/bridge-contract.cjs +1 -1
  20. package/dist-lib/bridge-contract.mjs +1 -1
  21. package/dist-lib/capture-contract.cjs +1 -1
  22. package/dist-lib/capture-contract.mjs +1 -1
  23. package/dist-lib/cli-constants.cjs +1 -1
  24. package/dist-lib/cloud-contract.cjs +1 -1
  25. package/dist-lib/cloud-contract.mjs +1 -1
  26. package/dist-lib/cloud.cjs +1 -1
  27. package/dist-lib/cloud.mjs +1 -1
  28. package/dist-lib/config.cjs +1 -1
  29. package/dist-lib/detox/index.cjs +1 -1
  30. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  31. package/dist-lib/home-paths.cjs +1 -1
  32. package/dist-lib/host/bridge-host.cjs +20 -43
  33. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  34. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  35. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  36. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  37. package/dist-lib/host/websocket-proxy.cjs +1 -1
  38. package/dist-lib/index.cjs +1 -1
  39. package/dist-lib/jump-to-source-babel.cjs +1 -1
  40. package/dist-lib/jump-to-source-native.cjs +1 -1
  41. package/dist-lib/menu.cjs +1 -1
  42. package/dist-lib/menu.mjs +1 -1
  43. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  44. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  45. package/dist-lib/metro-production-bundle.cjs +1 -1
  46. package/dist-lib/metro-production-bundle.mjs +1 -1
  47. package/dist-lib/metro.cjs +1 -1
  48. package/dist-lib/profiles.cjs +1 -1
  49. package/dist-lib/public-brand.cjs +1 -1
  50. package/dist-lib/react-native-host-modules.cjs +1 -1
  51. package/dist-lib/react-native-host-modules.mjs +1 -1
  52. package/dist-lib/render-mode.cjs +1 -1
  53. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  54. package/dist-lib/sdk.cjs +1 -1
  55. package/dist-lib/sdk.mjs +1 -1
  56. package/dist-lib/skills.cjs +20 -43
  57. package/dist-lib/vite.cjs +1 -1
  58. package/package.json +1 -1
  59. package/src/vite-plugin.ts +22 -4
@@ -72,8 +72,6 @@ interface CreateCloudBoxOptions {
72
72
  authorization: string
73
73
  /** the account to bill when the authorization is a session token; an api key names its own */
74
74
  accountId: string | null
75
- /** the `--assets-dest` directory Metro wrote beside the bundle. */
76
- assetsPath?: string
77
75
  apiOrigin?: string
78
76
  /** the name this box carries in the account's box list. */
79
77
  boxName?: string | null
@@ -457,6 +455,14 @@ interface MetroAssetSearch {
457
455
  searched: string[]
458
456
  /** a walk stopped at the cap, so no directory can be called fully looked at. */
459
457
  truncated: boolean
458
+ /**
459
+ * the dest holds every filename but not one of Metro's digests could be
460
+ * reproduced from it, so it was taken on layout alone. ordinary when every
461
+ * asset in the bundle carries an Android rung such as @1.5x that an iOS dest
462
+ * never receives, and indistinguishable from a previous build's images left
463
+ * in place, so the producer says so rather than staying quiet.
464
+ */
465
+ unconfirmed: boolean
460
466
  }
461
467
 
462
468
  /**
@@ -536,7 +542,7 @@ function searchMetroAssetDest(
536
542
  `${REMOTE_COMMAND} found this bundle's assets in ${stale.join(', ')}, but their bytes are not the ones it was built against. Rebuild with \`react-native bundle --assets-dest ${stale[0]}\` so the bundle and the images match.`,
537
543
  )
538
544
  }
539
- return { dest: null, searched, truncated }
545
+ return { dest: null, searched, truncated, unconfirmed: false }
540
546
  }
541
547
  const best = Math.max(...holders.map((holder) => holder.verified))
542
548
  // a directory that confirmed nothing cannot outrank one that confirmed
@@ -544,46 +550,21 @@ function searchMetroAssetDest(
544
550
  const rivals = holders.filter((holder) => holder.verified === best)
545
551
  const distinct = new Set(rivals.map((rival) => unverifiedFileKey(rival.dest)))
546
552
  const winner = rivals[0]
547
- if (!winner) return { dest: null, searched, truncated }
553
+ if (!winner) return { dest: null, searched, truncated, unconfirmed: false }
548
554
  if (distinct.size > 1) {
549
555
  throw new Error(
550
556
  `${REMOTE_COMMAND} found this bundle's assets in more than one directory and cannot tell which build wrote them: ${rivals
551
557
  .map((rival) => rival.dest.directory)
552
558
  .join(
553
559
  ', ',
554
- )}. Pass --assets <dir> to name the one \`react-native bundle --assets-dest\` wrote.`,
555
- )
556
- }
557
- if (best === 0) {
558
- // every descriptor declares a scale this directory does not hold, so not
559
- // one of Metro's digests can be reproduced from it. that is ordinary for an
560
- // asset carrying an Android rung such as @1.5x, and it is also exactly what
561
- // a half-copied dest looks like, so there is nothing here to choose on.
562
- throw new Error(
563
- `${REMOTE_COMMAND} found images for this bundle in ${winner.dest.directory} but could not confirm a single one of them, so it will not guess that this is the build's own \`--assets-dest\`. Pass --assets <dir> to name the directory \`react-native bundle --assets-dest\` wrote.`,
560
+ )}. Delete the stale one, or rebuild with \`react-native bundle --assets-dest\` into a directory beside the bundle.`,
564
561
  )
565
562
  }
566
- return { dest: winner.dest, searched, truncated }
567
- }
568
-
569
- /**
570
- * an explicitly named `--assets <dir>`. the caller promised this is the dest,
571
- * so it is never ranked against anything, but its bytes are still checked
572
- * against Metro's hashes so a stale dest is caught rather than shipped.
573
- */
574
- function explicitMetroAssetDest(
575
- directory: string,
576
- descriptors: readonly MetroAssetDescriptor[],
577
- ): MetroAssetSearch {
578
- const listing = listMetroAssetDest(directory)
579
- const placements = descriptors.map((descriptor) =>
580
- placeMetroDescriptor(listing, descriptor),
581
- )
582
- return {
583
- dest: { directory: listing.directory, placements },
584
- searched: [listing.directory],
585
- truncated: listing.truncated,
586
- }
563
+ // `best === 0` means no digest could be reproduced, which is ordinary for an
564
+ // asset carrying an Android rung such as @1.5x. with one claimant there is
565
+ // nothing to choose between, and a genuinely half-copied dest still fails
566
+ // per asset below, naming the file it could not read.
567
+ return { dest: winner.dest, searched, truncated, unconfirmed: best === 0 }
587
568
  }
588
569
 
589
570
  function largestEmbeddedAssets(
@@ -651,30 +632,21 @@ export interface CloudArtifactProduction {
651
632
 
652
633
  export async function produceCloudArtifact(
653
634
  bundlePath: string,
654
- assetsPath?: string,
655
635
  /**
656
636
  * the largest artifact the consumer accepts. the nano simulator's limit is
657
637
  * the default; a box that accepts a larger artifact passes its own.
658
638
  */
659
639
  maxBytes: number = MAX_RNX_CLOUD_BUNDLE_BYTES,
660
640
  ): Promise<CloudArtifactProduction> {
661
- return produceArtifact(
662
- bundlePath,
663
- assetsPath,
664
- maxBytes,
665
- REMOTE_COMMAND,
666
- 'allow-placeholders',
667
- )
641
+ return produceArtifact(bundlePath, maxBytes, REMOTE_COMMAND, 'allow-placeholders')
668
642
  }
669
643
 
670
644
  /** prepares a standalone preview whose bytes must represent every Metro asset. */
671
645
  export async function producePreviewArtifact(
672
646
  bundlePath: string,
673
- assetsPath?: string,
674
647
  ): Promise<CloudArtifactProduction> {
675
648
  return produceArtifact(
676
649
  bundlePath,
677
- assetsPath,
678
650
  Number.POSITIVE_INFINITY,
679
651
  PREVIEW_COMMAND,
680
652
  'require-assets',
@@ -683,7 +655,6 @@ export async function producePreviewArtifact(
683
655
 
684
656
  async function produceArtifact(
685
657
  bundlePath: string,
686
- assetsPath: string | undefined,
687
658
  maxBytes: number,
688
659
  command: string,
689
660
  assetPolicy: 'allow-placeholders' | 'require-assets',
@@ -692,11 +663,10 @@ async function produceArtifact(
692
663
  const descriptors = extractAssetDescriptors(source)
693
664
  // an https bundle has no local tree to search, and a bundle with no assets
694
665
  // has nothing to search for.
695
- const search: MetroAssetSearch = assetsPath
696
- ? explicitMetroAssetDest(resolve(assetsPath), descriptors)
697
- : descriptors.length > 0 && !isRemoteBundleInput(bundlePath)
666
+ const search: MetroAssetSearch =
667
+ descriptors.length > 0 && !isRemoteBundleInput(bundlePath)
698
668
  ? searchMetroAssetDest(bundlePath, descriptors)
699
- : { dest: null, searched: [], truncated: false }
669
+ : { dest: null, searched: [], truncated: false, unconfirmed: false }
700
670
  const dest = search.dest
701
671
  // `embedMetroAssetFiles` re-parses the bundle, so its descriptors are equal
702
672
  // to the ones the search placed but not the same objects.
@@ -721,27 +691,20 @@ async function produceArtifact(
721
691
  if (placement && placement.files.size > 0) return null
722
692
  if (placement && placement.ambiguous.length > 0 && dest) {
723
693
  throw new Error(
724
- `${command} found more than one image for ${label} in ${dest.directory} and none of them is the one Metro hashed: ${placement.ambiguous.sort().join(', ')}. Pass --assets <dir> to name the directory \`react-native bundle --assets-dest\` wrote.`,
694
+ `${command} found more than one image for ${label} in ${dest.directory} and none of them is the one Metro hashed: ${placement.ambiguous.sort().join(', ')}. Rebuild with \`react-native bundle --assets-dest\` into a directory that holds only this build's assets.`,
725
695
  )
726
696
  }
727
697
  // a stand-in is only honest when the asset is genuinely absent from a
728
- // directory we know is the right one. an explicitly named dest is a
729
- // promise, not a guess, so a miss there is a typo, and a truncated walk
730
- // never finished looking. both refuse instead of shipping bytes nobody
731
- // chose.
732
- if (assetsPath) {
733
- throw new Error(
734
- `${command} could not find ${label} under --assets ${dest?.directory ?? resolve(assetsPath)}. Point --assets at the directory \`react-native bundle --assets-dest\` wrote, or drop the flag to let ${command} find it.`,
735
- )
736
- }
698
+ // directory we know is the right one. a truncated walk never finished
699
+ // looking, so it refuses instead of shipping bytes nobody chose.
737
700
  if (search.truncated) {
738
701
  throw new Error(
739
- `${command} stopped listing ${search.searched.join(', ')} after ${MAX_ASSET_DEST_FILES} files and never reached ${label}, so it cannot tell a missing asset from an unread one. Pass --assets <dir> to name the directory \`react-native bundle --assets-dest\` wrote.`,
702
+ `${command} stopped listing ${search.searched.join(', ')} after ${MAX_ASSET_DEST_FILES} files and never reached ${label}, so it cannot tell a missing asset from an unread one. Rebuild with \`react-native bundle --assets-dest\` into a directory beside the bundle.`,
740
703
  )
741
704
  }
742
705
  if (assetPolicy === 'require-assets') {
743
706
  throw new Error(
744
- `${command} could not find ${label}. Pass --assets <dir> pointing at the directory \`react-native bundle --assets-dest <dir>\` wrote, or build with \`--assets-dest\`.`,
707
+ `${command} could not find ${label}. Build the bundle with \`react-native bundle --assets-dest <dir>\` so its assets land beside it.`,
745
708
  )
746
709
  }
747
710
  // no scale of this asset exists anywhere the search looked. an image can
@@ -762,7 +725,7 @@ async function produceArtifact(
762
725
  metroIosAssetDestRelatives(variant.descriptor.httpServerLocation, filename)[0] ??
763
726
  filename
764
727
  throw new Error(
765
- `${command} could not read ${join(dest?.directory ?? '.', classic)} for ${variant.descriptor.name}.${variant.descriptor.type} at scale ${variant.scale}, and has no stand-in for a .${variant.descriptor.type} asset. Build the bundle with --assets-dest, or pass --assets <dir>.`,
728
+ `${command} could not read ${join(dest?.directory ?? '.', classic)} for ${variant.descriptor.name}.${variant.descriptor.type} at scale ${variant.scale}, and has no stand-in for a .${variant.descriptor.type} asset. Rebuild with \`react-native bundle --assets-dest\`.`,
766
729
  )
767
730
  })
768
731
  const artifact = await buildRnxCloudArtifact(embedded.code, {
@@ -776,9 +739,14 @@ async function produceArtifact(
776
739
  )
777
740
  }
778
741
  const warnings: string[] = []
742
+ if (search.unconfirmed && dest) {
743
+ warnings.push(
744
+ `${command} read this bundle's assets from ${dest.directory} on layout alone: every asset declares a scale that directory does not hold, so not one of Metro's hashes could be reproduced. Confirm these are the images this bundle was built against.`,
745
+ )
746
+ }
779
747
  if (substituted.length > 0) {
780
748
  warnings.push(
781
- `${command} embedded a placeholder image for ${substituted.length} asset(s) no scale of which is in ${search.searched.join(', ') || 'any asset dest directory'}: ${substituted.join(', ')}. Build the bundle with --assets-dest, or pass --assets <dir>, to ship the real images.`,
749
+ `${command} embedded a placeholder image for ${substituted.length} asset(s) no scale of which is in ${search.searched.join(', ') || 'any asset dest directory'}: ${substituted.join(', ')}. Rebuild with \`react-native bundle --assets-dest\` to ship the real images.`,
782
750
  )
783
751
  }
784
752
  // an artifact this close to the ceiling is one asset away from being refused,
@@ -866,7 +834,7 @@ export async function createCloudBox(options: CreateCloudBoxOptions): Promise<{
866
834
  warnings: string[]
867
835
  }> {
868
836
  const apiOrigin = resolveCloudOrigin(options.apiOrigin)
869
- const artifact = await produceCloudArtifact(options.bundlePath, options.assetsPath)
837
+ const artifact = await produceCloudArtifact(options.bundlePath)
870
838
  const boxName = options.boxName?.trim()
871
839
  const headers: Record<string, string> = {
872
840
  authorization: options.authorization,
@@ -245,7 +245,7 @@ async function runBoxSend(args: string[], opts: BoxCommandOptions): Promise<numb
245
245
  {
246
246
  port: opts.port,
247
247
  stripBooleanFlags: ['--no-auth', '--json'],
248
- stripValueFlags: ['--name', '--assets', '--api-origin'],
248
+ stripValueFlags: ['--name', '--api-origin'],
249
249
  },
250
250
  )
251
251
  const bridge = createBridgeFromParsed(parsed)
@@ -257,7 +257,6 @@ async function runBoxSend(args: string[], opts: BoxCommandOptions): Promise<numb
257
257
  accountId,
258
258
  carryAuth: !args.includes('--no-auth'),
259
259
  boxName: flag(args, 'name') ?? null,
260
- assetsPath: flag(args, 'assets') ?? null,
261
260
  apiOrigin: flag(args, 'api-origin'),
262
261
  })
263
262
  if (args.includes('--json')) console.log(JSON.stringify(result))
@@ -27,18 +27,16 @@ function isDeviceModel(value: string): value is DeviceModel {
27
27
  }
28
28
 
29
29
  const REMOTE_USAGE =
30
- 'usage: rnx ios --remote <local bundle.js|https://bundle-url> [--assets <dir>] [--device <model>]'
30
+ 'usage: rnx ios --remote <local bundle.js|https://bundle-url> [--device <model>]'
31
31
 
32
32
  // flags this command reads for itself rather than treating as the bundle.
33
- const REMOTE_VALUE_FLAGS = new Set(['--device', '--assets', '--name', '--endpoint'])
33
+ const REMOTE_VALUE_FLAGS = new Set(['--device', '--name', '--endpoint'])
34
34
 
35
35
  function remoteInputFromArgs(args: string[]): {
36
36
  bundlePath: string
37
- assetsPath: string | null
38
37
  name: string | null
39
38
  } {
40
39
  const positional: string[] = []
41
- let assetsPath: string | null = null
42
40
  let name: string | null = null
43
41
  for (let index = 0; index < args.length; index++) {
44
42
  const arg = args[index]
@@ -46,7 +44,6 @@ function remoteInputFromArgs(args: string[]): {
46
44
  if (REMOTE_VALUE_FLAGS.has(arg)) {
47
45
  const value = args[++index] ?? null
48
46
  if (!value) throw new Error(`rnx ios --remote ${arg} requires a value`)
49
- if (arg === '--assets') assetsPath = value
50
47
  if (arg === '--name') name = value
51
48
  continue
52
49
  }
@@ -54,7 +51,6 @@ function remoteInputFromArgs(args: string[]): {
54
51
  if (assigned && REMOTE_VALUE_FLAGS.has(assigned[1] ?? '')) {
55
52
  const value = assigned[2] ?? ''
56
53
  if (!value) throw new Error(`rnx ios --remote ${assigned[1]} requires a value`)
57
- if (assigned[1] === '--assets') assetsPath = value
58
54
  if (assigned[1] === '--name') name = value
59
55
  continue
60
56
  }
@@ -74,7 +70,7 @@ function remoteInputFromArgs(args: string[]): {
74
70
  positional.push(arg)
75
71
  }
76
72
  if (positional.length !== 1 || !positional[0]) throw new Error(REMOTE_USAGE)
77
- return { bundlePath: positional[0], assetsPath, name }
73
+ return { bundlePath: positional[0], name }
78
74
  }
79
75
 
80
76
  /**
@@ -176,7 +172,6 @@ export async function runPlatformCommand(
176
172
  const { closeCloudBox, createCloudBox } = await import('../cloud-client')
177
173
  const created = await createCloudBox({
178
174
  bundlePath: input.bundlePath,
179
- assetsPath: input.assetsPath ?? undefined,
180
175
  device: selectedDevice,
181
176
  authorization: header,
182
177
  accountId,
@@ -282,7 +277,7 @@ export function runRemotePlatformCommand(
282
277
  * is what its page reads to boot the bundle instead of building one.
283
278
  */
284
279
  async function runRemoteBox(
285
- input: { bundlePath: string; assetsPath: string | null; name: string | null },
280
+ input: { bundlePath: string; name: string | null },
286
281
  args: string[],
287
282
  ): Promise<number> {
288
283
  const command = 'ios --remote'
@@ -294,11 +289,7 @@ async function runRemoteBox(
294
289
  const accountId = cloudAccountIdOrExit(auth)
295
290
  // the Box holds the bundle in parts, so the size a single message can carry
296
291
  // is not what limits this one and there is no cap to apply here.
297
- const artifact = await produceCloudArtifact(
298
- input.bundlePath,
299
- input.assetsPath ?? undefined,
300
- Number.POSITIVE_INFINITY,
301
- )
292
+ const artifact = await produceCloudArtifact(input.bundlePath, Number.POSITIVE_INFINITY)
302
293
  const created = await box.createPrebuiltBundleBox({
303
294
  bundle: new Uint8Array(artifact.bytes),
304
295
  name: input.name ?? boxNameForBundle(input.bundlePath),
@@ -24,7 +24,7 @@ export async function runPreview(args: string[]): Promise<number> {
24
24
  rnx preview — publish a prebuilt React Native bundle as a standalone share
25
25
 
26
26
  usage:
27
- rnx preview <bundle.js|https://bundle-url> [--assets <dir>] [--platform ios|android] [--open]
27
+ rnx preview <bundle.js|https://bundle-url> [--platform ios|android] [--open]
28
28
 
29
29
  The share contains the immutable build and its Metro assets. It is not a recorded replay.
30
30
  `)
@@ -32,7 +32,6 @@ The share contains the immutable build and its Metro assets. It is not a recorde
32
32
  }
33
33
  try {
34
34
  const input = [...args]
35
- const assets = takeValue(input, '--assets')
36
35
  const origin = await resolveDefaultUploadOrigin(
37
36
  takeValue(input, '--origin') ?? undefined,
38
37
  )
@@ -54,7 +53,7 @@ The share contains the immutable build and its Metro assets. It is not a recorde
54
53
  if (!auth) throw new Error('rnx preview needs `rnx login` or RNX_API_KEY')
55
54
  const accountId = cloudAccountIdOrExit(auth)
56
55
 
57
- const artifact = await producePreviewArtifact(input[0], assets ?? undefined)
56
+ const artifact = await producePreviewArtifact(input[0])
58
57
  const bundle = brotliBundle(artifact.bytes)
59
58
  const initBody: InitRequestBody = {
60
59
  kind: 'build',
package/cli/help-core.ts CHANGED
@@ -43,10 +43,10 @@ function renderPreviewHelp(command: 'web' | 'ios' | 'android'): string {
43
43
  const remote =
44
44
  command === 'ios'
45
45
  ? `
46
- rnx ios --remote <bundle.js|https://bundle-url> [--assets <dir>] [--device <model>]
46
+ rnx ios --remote <bundle.js|https://bundle-url> [--device <model>]
47
47
  run the bundle on a headless remote simulator.
48
- its Metro assets are found for you; --assets
49
- overrides that search.`
48
+ its Metro assets are found beside it and confirmed
49
+ against the hashes Metro recorded.`
50
50
  : ''
51
51
  return `rnx ${command} — select or ensure the current branch's existing ${command} preview
52
52
 
@@ -32,8 +32,6 @@ export interface SendToBoxOptions {
32
32
  */
33
33
  carryAuth: boolean
34
34
  boxName?: string | null
35
- /** the `--assets-dest` directory Metro wrote, when the sender knows it. */
36
- assetsPath?: string | null
37
35
  apiOrigin?: string
38
36
  simId?: string
39
37
  }
@@ -85,7 +83,6 @@ export async function sendToBox(options: SendToBoxOptions): Promise<SendToBoxRes
85
83
  const storage: StorageSnapshot = dumped
86
84
  const created = await createCloudBox({
87
85
  bundlePath: toRNXProductionBundleUrl(bundleUrl),
88
- assetsPath: options.assetsPath ?? undefined,
89
86
  device:
90
87
  options.device ??
91
88
  cloudDevice(isRecord(captured.deviceSpec) ? captured.deviceSpec.model : null),
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/beta.ts
4
4
  var IS_BETA = true;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/bridge-contract.ts
4
4
  var SIM_LONG_PRESS_MAX_MS = 5e3;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/bridge-contract.ts
4
4
  var SIM_LONG_PRESS_DEFAULT_MS = 500;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/capture-contract.ts
4
4
  var RNX_SCREEN_CAPTURE_VERSION = 1;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/cloud-contract.ts
4
4
  var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  var __defProp = Object.defineProperty;
3
3
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
4
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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;
@@ -3816,37 +3816,21 @@ function searchMetroAssetDest(bundlePath, descriptors) {
3816
3816
  `${REMOTE_COMMAND} found this bundle's assets in ${stale.join(", ")}, but their bytes are not the ones it was built against. Rebuild with \`react-native bundle --assets-dest ${stale[0]}\` so the bundle and the images match.`
3817
3817
  );
3818
3818
  }
3819
- return { dest: null, searched, truncated };
3819
+ return { dest: null, searched, truncated, unconfirmed: false };
3820
3820
  }
3821
3821
  const best = Math.max(...holders.map((holder) => holder.verified));
3822
3822
  const rivals = holders.filter((holder) => holder.verified === best);
3823
3823
  const distinct = new Set(rivals.map((rival) => unverifiedFileKey(rival.dest)));
3824
3824
  const winner = rivals[0];
3825
- if (!winner) return { dest: null, searched, truncated };
3825
+ if (!winner) return { dest: null, searched, truncated, unconfirmed: false };
3826
3826
  if (distinct.size > 1) {
3827
3827
  throw new Error(
3828
3828
  `${REMOTE_COMMAND} found this bundle's assets in more than one directory and cannot tell which build wrote them: ${rivals.map((rival) => rival.dest.directory).join(
3829
3829
  ", "
3830
- )}. Pass --assets <dir> to name the one \`react-native bundle --assets-dest\` wrote.`
3830
+ )}. Delete the stale one, or rebuild with \`react-native bundle --assets-dest\` into a directory beside the bundle.`
3831
3831
  );
3832
3832
  }
3833
- if (best === 0) {
3834
- throw new Error(
3835
- `${REMOTE_COMMAND} found images for this bundle in ${winner.dest.directory} but could not confirm a single one of them, so it will not guess that this is the build's own \`--assets-dest\`. Pass --assets <dir> to name the directory \`react-native bundle --assets-dest\` wrote.`
3836
- );
3837
- }
3838
- return { dest: winner.dest, searched, truncated };
3839
- }
3840
- function explicitMetroAssetDest(directory, descriptors) {
3841
- const listing = listMetroAssetDest(directory);
3842
- const placements = descriptors.map(
3843
- (descriptor) => placeMetroDescriptor(listing, descriptor)
3844
- );
3845
- return {
3846
- dest: { directory: listing.directory, placements },
3847
- searched: [listing.directory],
3848
- truncated: listing.truncated
3849
- };
3833
+ return { dest: winner.dest, searched, truncated, unconfirmed: best === 0 };
3850
3834
  }
3851
3835
  function largestEmbeddedAssets(sizes, count) {
3852
3836
  if (sizes.length === 0) return "";
@@ -3880,19 +3864,13 @@ async function inferCloudModuleIdentity(source) {
3880
3864
  );
3881
3865
  }
3882
3866
  }
3883
- async function produceCloudArtifact(bundlePath, assetsPath, maxBytes = MAX_RNX_CLOUD_BUNDLE_BYTES) {
3884
- return produceArtifact(
3885
- bundlePath,
3886
- assetsPath,
3887
- maxBytes,
3888
- REMOTE_COMMAND,
3889
- "allow-placeholders"
3890
- );
3867
+ async function produceCloudArtifact(bundlePath, maxBytes = MAX_RNX_CLOUD_BUNDLE_BYTES) {
3868
+ return produceArtifact(bundlePath, maxBytes, REMOTE_COMMAND, "allow-placeholders");
3891
3869
  }
3892
- async function produceArtifact(bundlePath, assetsPath, maxBytes, command, assetPolicy) {
3870
+ async function produceArtifact(bundlePath, maxBytes, command, assetPolicy) {
3893
3871
  const source = await loadBundleSource(bundlePath);
3894
3872
  const descriptors = extractAssetDescriptors(source);
3895
- const search = assetsPath ? explicitMetroAssetDest((0, import_node_path15.resolve)(assetsPath), descriptors) : descriptors.length > 0 && !isRemoteBundleInput(bundlePath) ? searchMetroAssetDest(bundlePath, descriptors) : { dest: null, searched: [], truncated: false };
3873
+ const search = descriptors.length > 0 && !isRemoteBundleInput(bundlePath) ? searchMetroAssetDest(bundlePath, descriptors) : { dest: null, searched: [], truncated: false, unconfirmed: false };
3896
3874
  const dest = search.dest;
3897
3875
  const placements = /* @__PURE__ */ new Map();
3898
3876
  descriptors.forEach((descriptor, index) => {
@@ -3913,22 +3891,17 @@ async function produceArtifact(bundlePath, assetsPath, maxBytes, command, assetP
3913
3891
  if (placement && placement.files.size > 0) return null;
3914
3892
  if (placement && placement.ambiguous.length > 0 && dest) {
3915
3893
  throw new Error(
3916
- `${command} found more than one image for ${label} in ${dest.directory} and none of them is the one Metro hashed: ${placement.ambiguous.sort().join(", ")}. Pass --assets <dir> to name the directory \`react-native bundle --assets-dest\` wrote.`
3917
- );
3918
- }
3919
- if (assetsPath) {
3920
- throw new Error(
3921
- `${command} could not find ${label} under --assets ${dest?.directory ?? (0, import_node_path15.resolve)(assetsPath)}. Point --assets at the directory \`react-native bundle --assets-dest\` wrote, or drop the flag to let ${command} find it.`
3894
+ `${command} found more than one image for ${label} in ${dest.directory} and none of them is the one Metro hashed: ${placement.ambiguous.sort().join(", ")}. Rebuild with \`react-native bundle --assets-dest\` into a directory that holds only this build's assets.`
3922
3895
  );
3923
3896
  }
3924
3897
  if (search.truncated) {
3925
3898
  throw new Error(
3926
- `${command} stopped listing ${search.searched.join(", ")} after ${MAX_ASSET_DEST_FILES} files and never reached ${label}, so it cannot tell a missing asset from an unread one. Pass --assets <dir> to name the directory \`react-native bundle --assets-dest\` wrote.`
3899
+ `${command} stopped listing ${search.searched.join(", ")} after ${MAX_ASSET_DEST_FILES} files and never reached ${label}, so it cannot tell a missing asset from an unread one. Rebuild with \`react-native bundle --assets-dest\` into a directory beside the bundle.`
3927
3900
  );
3928
3901
  }
3929
3902
  if (assetPolicy === "require-assets") {
3930
3903
  throw new Error(
3931
- `${command} could not find ${label}. Pass --assets <dir> pointing at the directory \`react-native bundle --assets-dest <dir>\` wrote, or build with \`--assets-dest\`.`
3904
+ `${command} could not find ${label}. Build the bundle with \`react-native bundle --assets-dest <dir>\` so its assets land beside it.`
3932
3905
  );
3933
3906
  }
3934
3907
  const placeholder = metroAssetPlaceholderBytes(variant.descriptor.type);
@@ -3943,7 +3916,7 @@ async function produceArtifact(bundlePath, assetsPath, maxBytes, command, assetP
3943
3916
  );
3944
3917
  const classic = metroIosAssetDestRelatives(variant.descriptor.httpServerLocation, filename)[0] ?? filename;
3945
3918
  throw new Error(
3946
- `${command} could not read ${(0, import_node_path15.join)(dest?.directory ?? ".", classic)} for ${variant.descriptor.name}.${variant.descriptor.type} at scale ${variant.scale}, and has no stand-in for a .${variant.descriptor.type} asset. Build the bundle with --assets-dest, or pass --assets <dir>.`
3919
+ `${command} could not read ${(0, import_node_path15.join)(dest?.directory ?? ".", classic)} for ${variant.descriptor.name}.${variant.descriptor.type} at scale ${variant.scale}, and has no stand-in for a .${variant.descriptor.type} asset. Rebuild with \`react-native bundle --assets-dest\`.`
3947
3920
  );
3948
3921
  });
3949
3922
  const artifact = await buildRnxCloudArtifact(embedded.code, {
@@ -3957,9 +3930,14 @@ async function produceArtifact(bundlePath, assetsPath, maxBytes, command, assetP
3957
3930
  );
3958
3931
  }
3959
3932
  const warnings = [];
3933
+ if (search.unconfirmed && dest) {
3934
+ warnings.push(
3935
+ `${command} read this bundle's assets from ${dest.directory} on layout alone: every asset declares a scale that directory does not hold, so not one of Metro's hashes could be reproduced. Confirm these are the images this bundle was built against.`
3936
+ );
3937
+ }
3960
3938
  if (substituted.length > 0) {
3961
3939
  warnings.push(
3962
- `${command} embedded a placeholder image for ${substituted.length} asset(s) no scale of which is in ${search.searched.join(", ") || "any asset dest directory"}: ${substituted.join(", ")}. Build the bundle with --assets-dest, or pass --assets <dir>, to ship the real images.`
3940
+ `${command} embedded a placeholder image for ${substituted.length} asset(s) no scale of which is in ${search.searched.join(", ") || "any asset dest directory"}: ${substituted.join(", ")}. Rebuild with \`react-native bundle --assets-dest\` to ship the real images.`
3963
3941
  );
3964
3942
  }
3965
3943
  if (bytes.length >= Math.floor(maxBytes * 0.8)) {
@@ -4005,7 +3983,7 @@ function readCreateResponse(value, expectedBytes, expectedSha256) {
4005
3983
  }
4006
3984
  async function createCloudBox(options) {
4007
3985
  const apiOrigin = resolveCloudOrigin(options.apiOrigin);
4008
- const artifact = await produceCloudArtifact(options.bundlePath, options.assetsPath);
3986
+ const artifact = await produceCloudArtifact(options.bundlePath);
4009
3987
  const boxName = options.boxName?.trim();
4010
3988
  const headers = {
4011
3989
  authorization: options.authorization,
@@ -4142,7 +4120,6 @@ async function sendToBox(options) {
4142
4120
  const storage = dumped;
4143
4121
  const created = await createCloudBox({
4144
4122
  bundlePath: toRNXProductionBundleUrl(bundleUrl),
4145
- assetsPath: options.assetsPath ?? void 0,
4146
4123
  device: options.device ?? cloudDevice(isRecord5(captured.deviceSpec) ? captured.deviceSpec.model : null),
4147
4124
  authorization: options.authorization,
4148
4125
  accountId: options.accountId,
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/host/fetch-proxy-overrides.ts
4
4
  var FETCH_PROXY_BROWSER_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36";
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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;
package/dist-lib/menu.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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/menu.mjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/public-brand.ts
4
4
  var name = "rnx";
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/metro-fingerprint-registry.ts
4
4
  var RNX_METRO_FINGERPRINT_SCHEMA_VERSION = 2;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/metro-production-bundle.ts
4
4
  var RNXSIM_METRO_MODULE_PATHS_PREFIX = "globalThis.__sootsimModulePaths=";
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/react-native-host-modules.ts
4
4
  var REACT_NATIVE_PASSTHROUGH_SPECIFIERS = [
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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;
package/dist-lib/sdk.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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/sdk.mjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  var __defProp = Object.defineProperty;
3
3
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
4
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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;
@@ -27884,37 +27884,21 @@ function searchMetroAssetDest(bundlePath, descriptors) {
27884
27884
  `${REMOTE_COMMAND} found this bundle's assets in ${stale.join(", ")}, but their bytes are not the ones it was built against. Rebuild with \`react-native bundle --assets-dest ${stale[0]}\` so the bundle and the images match.`
27885
27885
  );
27886
27886
  }
27887
- return { dest: null, searched, truncated };
27887
+ return { dest: null, searched, truncated, unconfirmed: false };
27888
27888
  }
27889
27889
  const best = Math.max(...holders.map((holder) => holder.verified));
27890
27890
  const rivals = holders.filter((holder) => holder.verified === best);
27891
27891
  const distinct = new Set(rivals.map((rival) => unverifiedFileKey(rival.dest)));
27892
27892
  const winner = rivals[0];
27893
- if (!winner) return { dest: null, searched, truncated };
27893
+ if (!winner) return { dest: null, searched, truncated, unconfirmed: false };
27894
27894
  if (distinct.size > 1) {
27895
27895
  throw new Error(
27896
27896
  `${REMOTE_COMMAND} found this bundle's assets in more than one directory and cannot tell which build wrote them: ${rivals.map((rival) => rival.dest.directory).join(
27897
27897
  ", "
27898
- )}. Pass --assets <dir> to name the one \`react-native bundle --assets-dest\` wrote.`
27898
+ )}. Delete the stale one, or rebuild with \`react-native bundle --assets-dest\` into a directory beside the bundle.`
27899
27899
  );
27900
27900
  }
27901
- if (best === 0) {
27902
- throw new Error(
27903
- `${REMOTE_COMMAND} found images for this bundle in ${winner.dest.directory} but could not confirm a single one of them, so it will not guess that this is the build's own \`--assets-dest\`. Pass --assets <dir> to name the directory \`react-native bundle --assets-dest\` wrote.`
27904
- );
27905
- }
27906
- return { dest: winner.dest, searched, truncated };
27907
- }
27908
- function explicitMetroAssetDest(directory, descriptors) {
27909
- const listing = listMetroAssetDest(directory);
27910
- const placements = descriptors.map(
27911
- (descriptor) => placeMetroDescriptor(listing, descriptor)
27912
- );
27913
- return {
27914
- dest: { directory: listing.directory, placements },
27915
- searched: [listing.directory],
27916
- truncated: listing.truncated
27917
- };
27901
+ return { dest: winner.dest, searched, truncated, unconfirmed: best === 0 };
27918
27902
  }
27919
27903
  function largestEmbeddedAssets(sizes, count) {
27920
27904
  if (sizes.length === 0) return "";
@@ -27948,19 +27932,13 @@ async function inferCloudModuleIdentity(source) {
27948
27932
  );
27949
27933
  }
27950
27934
  }
27951
- async function produceCloudArtifact(bundlePath, assetsPath, maxBytes = MAX_RNX_CLOUD_BUNDLE_BYTES) {
27952
- return produceArtifact(
27953
- bundlePath,
27954
- assetsPath,
27955
- maxBytes,
27956
- REMOTE_COMMAND,
27957
- "allow-placeholders"
27958
- );
27935
+ async function produceCloudArtifact(bundlePath, maxBytes = MAX_RNX_CLOUD_BUNDLE_BYTES) {
27936
+ return produceArtifact(bundlePath, maxBytes, REMOTE_COMMAND, "allow-placeholders");
27959
27937
  }
27960
- async function produceArtifact(bundlePath, assetsPath, maxBytes, command, assetPolicy) {
27938
+ async function produceArtifact(bundlePath, maxBytes, command, assetPolicy) {
27961
27939
  const source = await loadBundleSource(bundlePath);
27962
27940
  const descriptors = extractAssetDescriptors(source);
27963
- const search = assetsPath ? explicitMetroAssetDest((0, import_node_path15.resolve)(assetsPath), descriptors) : descriptors.length > 0 && !isRemoteBundleInput(bundlePath) ? searchMetroAssetDest(bundlePath, descriptors) : { dest: null, searched: [], truncated: false };
27941
+ const search = descriptors.length > 0 && !isRemoteBundleInput(bundlePath) ? searchMetroAssetDest(bundlePath, descriptors) : { dest: null, searched: [], truncated: false, unconfirmed: false };
27964
27942
  const dest = search.dest;
27965
27943
  const placements = /* @__PURE__ */ new Map();
27966
27944
  descriptors.forEach((descriptor, index) => {
@@ -27981,22 +27959,17 @@ async function produceArtifact(bundlePath, assetsPath, maxBytes, command, assetP
27981
27959
  if (placement && placement.files.size > 0) return null;
27982
27960
  if (placement && placement.ambiguous.length > 0 && dest) {
27983
27961
  throw new Error(
27984
- `${command} found more than one image for ${label} in ${dest.directory} and none of them is the one Metro hashed: ${placement.ambiguous.sort().join(", ")}. Pass --assets <dir> to name the directory \`react-native bundle --assets-dest\` wrote.`
27985
- );
27986
- }
27987
- if (assetsPath) {
27988
- throw new Error(
27989
- `${command} could not find ${label} under --assets ${dest?.directory ?? (0, import_node_path15.resolve)(assetsPath)}. Point --assets at the directory \`react-native bundle --assets-dest\` wrote, or drop the flag to let ${command} find it.`
27962
+ `${command} found more than one image for ${label} in ${dest.directory} and none of them is the one Metro hashed: ${placement.ambiguous.sort().join(", ")}. Rebuild with \`react-native bundle --assets-dest\` into a directory that holds only this build's assets.`
27990
27963
  );
27991
27964
  }
27992
27965
  if (search.truncated) {
27993
27966
  throw new Error(
27994
- `${command} stopped listing ${search.searched.join(", ")} after ${MAX_ASSET_DEST_FILES} files and never reached ${label}, so it cannot tell a missing asset from an unread one. Pass --assets <dir> to name the directory \`react-native bundle --assets-dest\` wrote.`
27967
+ `${command} stopped listing ${search.searched.join(", ")} after ${MAX_ASSET_DEST_FILES} files and never reached ${label}, so it cannot tell a missing asset from an unread one. Rebuild with \`react-native bundle --assets-dest\` into a directory beside the bundle.`
27995
27968
  );
27996
27969
  }
27997
27970
  if (assetPolicy === "require-assets") {
27998
27971
  throw new Error(
27999
- `${command} could not find ${label}. Pass --assets <dir> pointing at the directory \`react-native bundle --assets-dest <dir>\` wrote, or build with \`--assets-dest\`.`
27972
+ `${command} could not find ${label}. Build the bundle with \`react-native bundle --assets-dest <dir>\` so its assets land beside it.`
28000
27973
  );
28001
27974
  }
28002
27975
  const placeholder = metroAssetPlaceholderBytes(variant.descriptor.type);
@@ -28011,7 +27984,7 @@ async function produceArtifact(bundlePath, assetsPath, maxBytes, command, assetP
28011
27984
  );
28012
27985
  const classic = metroIosAssetDestRelatives(variant.descriptor.httpServerLocation, filename)[0] ?? filename;
28013
27986
  throw new Error(
28014
- `${command} could not read ${(0, import_node_path15.join)(dest?.directory ?? ".", classic)} for ${variant.descriptor.name}.${variant.descriptor.type} at scale ${variant.scale}, and has no stand-in for a .${variant.descriptor.type} asset. Build the bundle with --assets-dest, or pass --assets <dir>.`
27987
+ `${command} could not read ${(0, import_node_path15.join)(dest?.directory ?? ".", classic)} for ${variant.descriptor.name}.${variant.descriptor.type} at scale ${variant.scale}, and has no stand-in for a .${variant.descriptor.type} asset. Rebuild with \`react-native bundle --assets-dest\`.`
28015
27988
  );
28016
27989
  });
28017
27990
  const artifact = await buildRnxCloudArtifact(embedded.code, {
@@ -28025,9 +27998,14 @@ async function produceArtifact(bundlePath, assetsPath, maxBytes, command, assetP
28025
27998
  );
28026
27999
  }
28027
28000
  const warnings = [];
28001
+ if (search.unconfirmed && dest) {
28002
+ warnings.push(
28003
+ `${command} read this bundle's assets from ${dest.directory} on layout alone: every asset declares a scale that directory does not hold, so not one of Metro's hashes could be reproduced. Confirm these are the images this bundle was built against.`
28004
+ );
28005
+ }
28028
28006
  if (substituted.length > 0) {
28029
28007
  warnings.push(
28030
- `${command} embedded a placeholder image for ${substituted.length} asset(s) no scale of which is in ${search.searched.join(", ") || "any asset dest directory"}: ${substituted.join(", ")}. Build the bundle with --assets-dest, or pass --assets <dir>, to ship the real images.`
28008
+ `${command} embedded a placeholder image for ${substituted.length} asset(s) no scale of which is in ${search.searched.join(", ") || "any asset dest directory"}: ${substituted.join(", ")}. Rebuild with \`react-native bundle --assets-dest\` to ship the real images.`
28031
28009
  );
28032
28010
  }
28033
28011
  if (bytes.length >= Math.floor(maxBytes * 0.8)) {
@@ -28073,7 +28051,7 @@ function readCreateResponse(value, expectedBytes, expectedSha256) {
28073
28051
  }
28074
28052
  async function createCloudBox(options) {
28075
28053
  const apiOrigin = resolveCloudOrigin(options.apiOrigin);
28076
- const artifact = await produceCloudArtifact(options.bundlePath, options.assetsPath);
28054
+ const artifact = await produceCloudArtifact(options.bundlePath);
28077
28055
  const boxName = options.boxName?.trim();
28078
28056
  const headers = {
28079
28057
  authorization: options.authorization,
@@ -28381,7 +28359,6 @@ async function sendToBox(options) {
28381
28359
  const storage = dumped;
28382
28360
  const created = await createCloudBox({
28383
28361
  bundlePath: toRNXProductionBundleUrl(bundleUrl),
28384
- assetsPath: options.assetsPath ?? void 0,
28385
28362
  device: options.device ?? cloudDevice(isRecord6(captured.deviceSpec) ? captured.deviceSpec.model : null),
28386
28363
  authorization: options.authorization,
28387
28364
  accountId: options.accountId,
package/dist-lib/vite.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.495 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.497 | (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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rnxsim",
3
- "version": "0.1.495",
3
+ "version": "0.1.497",
4
4
  "description": "Vite and Metro plugins, testing drivers, and SDK exports for rnx.",
5
5
  "author": "Tamagui LLC",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -469,12 +469,30 @@ function rnghUpstreamInternalResolvePlugin(): Plugin {
469
469
  // workletsBabelTransform populates `__closure` on user-code worklets so
470
470
  // useAnimatedStyle/useDerivedValue/etc. subscribe correctly inside the
471
471
  // worker. matching is content-driven today, so the predicate is `() => true`.
472
+ export function recordingPluginWorkerRedirect(): Plugin {
473
+ const workerTarget = path.resolve(
474
+ workspaceRoot,
475
+ 'packages/rnx-plugin-recording/src/worker.ts',
476
+ )
477
+ return {
478
+ name: 'sootsim-recording-plugin-worker-redirect',
479
+ enforce: 'pre',
480
+ resolveId(source) {
481
+ if (source === '@rnx/plugin-recording') {
482
+ return workerTarget
483
+ }
484
+ return null
485
+ },
486
+ }
487
+ }
488
+
472
489
  export function engineShellWorkerPlugins(): Plugin[] {
473
490
  return [
474
491
  workerReactBridgePlugin(),
475
492
  fixJsxRuntimeExports(),
476
493
  flowStripTransform(),
477
494
  nodeModulesJsxTransform(),
495
+ recordingPluginWorkerRedirect(),
478
496
  reanimatedNativeSeamRedirect(),
479
497
  manifestNativeSeamRedirect(),
480
498
  keyboardControllerBindingsRedirect(),
@@ -501,8 +519,8 @@ export function engineShellWorkerPlugins(): Plugin[] {
501
519
  export type WorkerBootClosure = {
502
520
  // substring of the worker entry module id this applies to
503
521
  entry: string
504
- // byte cap on the rendered worker file; raise it in the same change that
505
- // adds worker code, never silently
522
+ // byte cap on the rendered worker file; fix excess boot dependencies and
523
+ // unneeded inclusions rather than raising the cap
506
524
  maxBytes: number
507
525
  }
508
526
 
@@ -515,7 +533,7 @@ const ENGINE_WORKER_BOOT_CLOSURES: WorkerBootClosure[] = [
515
533
  // when adding font work here, or both caps take the parser again.
516
534
  // gesture handler 3's upstream hook surface moved the measured closure to
517
535
  // 3,446,531 bytes. the vector catalog lookup and PUA overlay add 675 bytes.
518
- { entry: 'src/render-worker/shell-worker-entry.ts', maxBytes: 3_460_000 },
536
+ { entry: 'src/render-worker/shell-worker-entry.ts', maxBytes: 3_451_000 },
519
537
  { entry: 'src/render-worker/compositor-worker-entry.ts', maxBytes: 1_080_000 },
520
538
  { entry: 'src/render-worker/compositor-worker-ganesh-entry.ts', maxBytes: 1_820_000 },
521
539
  ]
@@ -547,7 +565,7 @@ export function workerBootChunkPlugin(closures: WorkerBootClosure[]): Plugin {
547
565
  const bytes = Buffer.byteLength(chunks[0].code)
548
566
  if (bytes > closure.maxBytes) {
549
567
  this.error(
550
- `worker ${closure.entry}: ${chunks[0].fileName} is ${bytes} bytes, over the ${closure.maxBytes} byte cap; raise the cap in the same change that grows the worker`,
568
+ `worker ${closure.entry}: ${chunks[0].fileName} is ${bytes} bytes, over the ${closure.maxBytes} byte cap; eliminate excess boot dependencies rather than raising the cap`,
551
569
  )
552
570
  }
553
571
  },