rnxsim 0.1.519 → 0.1.521

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 (71) hide show
  1. package/cli/cloud-client.ts +419 -287
  2. package/cli/cloud-dispatch.ts +2 -21
  3. package/cli/cloud-session.ts +31 -85
  4. package/cli/commands/box.ts +15 -11
  5. package/cli/commands/inspect.ts +34 -1
  6. package/cli/commands/platform.ts +184 -232
  7. package/cli/main.ts +10 -2
  8. package/cli/outbound-endpoints.ts +21 -6
  9. package/dist-lib/agent-daemon-client.cjs +1 -1
  10. package/dist-lib/agent-events.cjs +1 -1
  11. package/dist-lib/agent-identity.cjs +1 -1
  12. package/dist-lib/agent-sessions.cjs +1 -1
  13. package/dist-lib/attached-projects.cjs +1 -1
  14. package/dist-lib/auth/shared-session.cjs +1 -1
  15. package/dist-lib/backend-origin.cjs +1 -1
  16. package/dist-lib/beta.cjs +1 -1
  17. package/dist-lib/beta.mjs +1 -1
  18. package/dist-lib/bridge-constants.cjs +1 -1
  19. package/dist-lib/bridge-contract-input.cjs +7 -2
  20. package/dist-lib/bridge-contract-input.mjs +7 -2
  21. package/dist-lib/bridge-contract.cjs +1 -1
  22. package/dist-lib/bridge-contract.mjs +1 -1
  23. package/dist-lib/capture-contract.cjs +1 -1
  24. package/dist-lib/capture-contract.mjs +1 -1
  25. package/dist-lib/cli-constants.cjs +1 -1
  26. package/dist-lib/cloud-contract.cjs +1 -1
  27. package/dist-lib/cloud-contract.mjs +1 -1
  28. package/dist-lib/cloud.cjs +18 -2
  29. package/dist-lib/cloud.mjs +18 -2
  30. package/dist-lib/config.cjs +1 -1
  31. package/dist-lib/detox/index.cjs +1 -1
  32. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  33. package/dist-lib/home-paths.cjs +1 -1
  34. package/dist-lib/host/bridge-host.cjs +112 -39
  35. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  36. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  37. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  38. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  39. package/dist-lib/host/websocket-proxy.cjs +1 -1
  40. package/dist-lib/index.cjs +44 -117
  41. package/dist-lib/jump-to-source-babel.cjs +1 -1
  42. package/dist-lib/jump-to-source-native.cjs +1 -1
  43. package/dist-lib/menu.cjs +30 -1
  44. package/dist-lib/menu.mjs +27 -1
  45. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  46. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  47. package/dist-lib/metro-production-bundle.cjs +1 -1
  48. package/dist-lib/metro-production-bundle.mjs +1 -1
  49. package/dist-lib/metro.cjs +1 -1
  50. package/dist-lib/profiles.cjs +1 -1
  51. package/dist-lib/public-brand.cjs +1 -1
  52. package/dist-lib/react-native-host-modules.cjs +1 -1
  53. package/dist-lib/react-native-host-modules.mjs +1 -1
  54. package/dist-lib/render-mode.cjs +1 -1
  55. package/dist-lib/scripts/dev-server-scanner.cjs +41 -4
  56. package/dist-lib/sdk.cjs +1 -1
  57. package/dist-lib/sdk.mjs +1 -1
  58. package/dist-lib/skills.cjs +138 -164
  59. package/dist-lib/swift.cjs +766 -24
  60. package/dist-lib/vite.cjs +103 -30
  61. package/package.json +1 -1
  62. package/scripts/dev-server-scanner.ts +72 -5
  63. package/src/bridge-contract-input.ts +10 -0
  64. package/src/bridge-contract.ts +5 -0
  65. package/src/cloud-contract.ts +7 -1
  66. package/src/cloud.ts +45 -6
  67. package/src/connect.ts +1 -1
  68. package/src/menu.ts +44 -0
  69. package/src/swift.ts +2 -0
  70. package/src/vite-plugin-one.ts +12 -0
  71. package/src/vite-plugin-swift.ts +141 -39
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.519 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.521 | (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;
@@ -2078,25 +2078,25 @@ var init_capability_inventory_coverage = __esm({
2078
2078
  "react-native": {
2079
2079
  combined: {
2080
2080
  raw: {
2081
- covered: 7,
2082
- ratio: 0.00443037974684,
2081
+ covered: 0,
2082
+ ratio: 0,
2083
2083
  total: 1580
2084
2084
  },
2085
2085
  weighted: {
2086
- covered: 118040527248e-15,
2087
- ratio: 257946914525e-16,
2086
+ covered: 0,
2087
+ ratio: 0,
2088
2088
  total: 4.5761558135
2089
2089
  }
2090
2090
  },
2091
2091
  semantic: {
2092
2092
  raw: {
2093
- covered: 7,
2094
- ratio: 0.00621669626998,
2093
+ covered: 0,
2094
+ ratio: 0,
2095
2095
  total: 1126
2096
2096
  },
2097
2097
  weighted: {
2098
- covered: 118040527248e-15,
2099
- ratio: 106435819202e-15,
2098
+ covered: 0,
2099
+ ratio: 0,
2100
2100
  total: 1.10903010033
2101
2101
  }
2102
2102
  },
@@ -2154,25 +2154,25 @@ var init_capability_inventory_coverage = __esm({
2154
2154
  ios: {
2155
2155
  combined: {
2156
2156
  raw: {
2157
- covered: 235,
2158
- ratio: 0.168458781362,
2157
+ covered: 0,
2158
+ ratio: 0,
2159
2159
  total: 1395
2160
2160
  },
2161
2161
  weighted: {
2162
- covered: 0.602400157387,
2163
- ratio: 0.132022593024,
2162
+ covered: 0,
2163
+ ratio: 0,
2164
2164
  total: 4.56285658076
2165
2165
  }
2166
2166
  },
2167
2167
  semantic: {
2168
2168
  raw: {
2169
- covered: 235,
2170
- ratio: 0.235235235235,
2169
+ covered: 0,
2170
+ ratio: 0,
2171
2171
  total: 999
2172
2172
  },
2173
2173
  weighted: {
2174
- covered: 0.602400157387,
2175
- ratio: 0.547528789072,
2174
+ covered: 0,
2175
+ ratio: 0,
2176
2176
  total: 1.10021640763
2177
2177
  }
2178
2178
  },
@@ -19995,12 +19995,30 @@ function safeParseManifest(body) {
19995
19995
  return null;
19996
19996
  }
19997
19997
  }
19998
+ function metroAssetPath(rawIcon) {
19999
+ return `/assets/${rawIcon.replace(/^\.?\//, "")}`;
20000
+ }
20001
+ function staticAssetPath(rawIcon) {
20002
+ return `/${rawIcon.replace(/^\.?\//, "")}`;
20003
+ }
20004
+ async function resolveLocalIconPath(hostname, port, rawIcon) {
20005
+ const candidates = [metroAssetPath(rawIcon), staticAssetPath(rawIcon)];
20006
+ for (const candidate of candidates) {
20007
+ const res = await httpGet(hostname, port, candidate, "HEAD", ENRICH_TIMEOUT_MS);
20008
+ if (res?.statusCode === 200) {
20009
+ localIconPathCache.set(port, candidate);
20010
+ portCache.delete(port);
20011
+ return;
20012
+ }
20013
+ }
20014
+ }
19998
20015
  function applyManifest(result, manifestRes, buildIconProxyUrl) {
19999
20016
  if (!manifestRes) return result;
20000
20017
  try {
20001
20018
  const manifest = JSON.parse(manifestRes.body);
20002
20019
  const client = manifest?.extra?.expoClient || manifest?.extra || {};
20003
20020
  if (client.name) result.projectName = client.name;
20021
+ if (typeof client.primaryColor === "string") result.primaryColor = client.primaryColor;
20004
20022
  if (client.ios?.bundleIdentifier) result.bundleId = client.ios.bundleIdentifier;
20005
20023
  if (result.framework === "metro" && client.sdkVersion) result.framework = "expo";
20006
20024
  const rawLaunchUrl = manifest?.launchAsset?.url;
@@ -20032,9 +20050,9 @@ function applyManifest(result, manifestRes, buildIconProxyUrl) {
20032
20050
  resolvedIconUrl = rawIcon;
20033
20051
  }
20034
20052
  } else {
20035
- const cleanPath = rawIcon.replace(/^\.?\//, "");
20036
- const assetPath = cleanPath.startsWith("assets/") ? `/${cleanPath}` : `/assets/${cleanPath}`;
20037
- const localUrl = `${buildLoopbackProbeBaseUrl("http:", manifestRes.hostname, result.port)}${assetPath}`;
20053
+ const base = buildLoopbackProbeBaseUrl("http:", manifestRes.hostname, result.port);
20054
+ const assetPath = localIconPathCache.get(result.port) ?? metroAssetPath(rawIcon);
20055
+ const localUrl = `${base}${assetPath}`;
20038
20056
  resolvedIconUrl = buildIconProxyUrl ? buildIconProxyUrl(localUrl) : localUrl;
20039
20057
  }
20040
20058
  if (resolvedIconUrl) {
@@ -20045,7 +20063,20 @@ function applyManifest(result, manifestRes, buildIconProxyUrl) {
20045
20063
  }
20046
20064
  return result;
20047
20065
  }
20066
+ function ensureLocalIconPathResolved(result) {
20067
+ const rawIcon = result.iconPath;
20068
+ if (!rawIcon) return;
20069
+ if (rawIcon.startsWith("http://") || rawIcon.startsWith("https://")) return;
20070
+ if (localIconPathCache.has(result.port)) return;
20071
+ if (localIconProbeInFlight.has(result.port)) return;
20072
+ localIconProbeInFlight.add(result.port);
20073
+ const hostname = normalizeHostname(new URL(result.bundleUrl).hostname);
20074
+ void resolveLocalIconPath(hostname, result.port, rawIcon).finally(
20075
+ () => localIconProbeInFlight.delete(result.port)
20076
+ );
20077
+ }
20048
20078
  function enrichWithManifest(result, buildIconProxyUrl) {
20079
+ ensureLocalIconPathResolved(result);
20049
20080
  if (result.projectName) return result;
20050
20081
  const cached4 = enrichmentCache.get(result.port);
20051
20082
  if (cached4) {
@@ -20267,6 +20298,9 @@ async function scanDevServers(opts = {}) {
20267
20298
  for (const p of [...enrichmentCache.keys()]) {
20268
20299
  if (!currentPorts.has(p)) enrichmentCache.delete(p);
20269
20300
  }
20301
+ for (const p of [...localIconPathCache.keys()]) {
20302
+ if (!currentPorts.has(p)) localIconPathCache.delete(p);
20303
+ }
20270
20304
  const results = [];
20271
20305
  const toProbe = [];
20272
20306
  for (const { port, pid } of processes) {
@@ -20280,6 +20314,7 @@ async function scanDevServers(opts = {}) {
20280
20314
  knownNonExpo.delete(port);
20281
20315
  knownOne.delete(port);
20282
20316
  enrichmentCache.delete(port);
20317
+ localIconPathCache.delete(port);
20283
20318
  }
20284
20319
  toProbe.push({ port, pid });
20285
20320
  }
@@ -20314,7 +20349,7 @@ async function scanDevServers(opts = {}) {
20314
20349
  }
20315
20350
  return results.filter((r) => !isSootSimSelfServer(r));
20316
20351
  }
20317
- var import_child_process, import_promises2, import_http, import_net, import_node_fs2, import_node_path3, EXEC_EXIT_GRACE_MS, TIMEOUT_MS, MANIFEST_TIMEOUT_MS, TCP_GATE_MS, BODY_TIMEOUT_MS, FALLBACK_PORTS, SELF_PORT_RANGE_START, SELF_PORT_RANGE_END, DevServerScanUnavailableError, LISTING_TIMEOUT_MS, cwdByPid, ENRICH_TIMEOUT_MS, enrichmentCache, enrichmentInFlight, knownNonPatched, knownNonExpo, knownOne, portCache, NEGATIVE_CACHE_TTL_MS, WEAK_RESULT_CACHE_TTL_MS;
20352
+ var import_child_process, import_promises2, import_http, import_net, import_node_fs2, import_node_path3, EXEC_EXIT_GRACE_MS, TIMEOUT_MS, MANIFEST_TIMEOUT_MS, TCP_GATE_MS, BODY_TIMEOUT_MS, FALLBACK_PORTS, SELF_PORT_RANGE_START, SELF_PORT_RANGE_END, DevServerScanUnavailableError, LISTING_TIMEOUT_MS, cwdByPid, localIconPathCache, localIconProbeInFlight, ENRICH_TIMEOUT_MS, enrichmentCache, enrichmentInFlight, knownNonPatched, knownNonExpo, knownOne, portCache, NEGATIVE_CACHE_TTL_MS, WEAK_RESULT_CACHE_TTL_MS;
20318
20353
  var init_dev_server_scanner = __esm({
20319
20354
  "scripts/dev-server-scanner.ts"() {
20320
20355
  "use strict";
@@ -20355,6 +20390,8 @@ var init_dev_server_scanner = __esm({
20355
20390
  };
20356
20391
  LISTING_TIMEOUT_MS = 1e4;
20357
20392
  cwdByPid = /* @__PURE__ */ new Map();
20393
+ localIconPathCache = /* @__PURE__ */ new Map();
20394
+ localIconProbeInFlight = /* @__PURE__ */ new Set();
20358
20395
  ENRICH_TIMEOUT_MS = 2e4;
20359
20396
  enrichmentCache = /* @__PURE__ */ new Map();
20360
20397
  enrichmentInFlight = /* @__PURE__ */ new Set();
@@ -24872,10 +24909,11 @@ function listDeviceModels() {
24872
24909
  function getRuntimePlatform(model) {
24873
24910
  return getDevice(model).platform;
24874
24911
  }
24875
- var LEGACY_HARDWARE_BUTTONS, PIXEL_HARDWARE_BUTTONS, GALAXY_HARDWARE_BUTTONS, ANDROID_GESTURE_NAV_BAR_HEIGHT, ANDROID_OS_VERSION, ANDROID_API_LEVEL, PIXEL_8_WIDTH, PIXEL_8_HEIGHT, PIXEL_8_STATUS_BAR_HEIGHT, devices, DEFAULT_DEVICE, DEFAULT_DEVICE_BY_PLATFORM;
24912
+ var import_menu, LEGACY_HARDWARE_BUTTONS, PIXEL_HARDWARE_BUTTONS, GALAXY_HARDWARE_BUTTONS, ANDROID_GESTURE_NAV_BAR_HEIGHT, ANDROID_OS_VERSION, ANDROID_API_LEVEL, PIXEL_8_WIDTH, PIXEL_8_HEIGHT, PIXEL_8_STATUS_BAR_HEIGHT, devices, DEFAULT_DEVICE, DEFAULT_DEVICE_BY_PLATFORM;
24876
24913
  var init_devices = __esm({
24877
24914
  "../sootsim-engine/src/settings/devices.ts"() {
24878
24915
  "use strict";
24916
+ import_menu = require("rnxsim/menu");
24879
24917
  LEGACY_HARDWARE_BUTTONS = {
24880
24918
  width: 2.5,
24881
24919
  lock: { side: "right", top: 188.7, height: 68.1 },
@@ -25272,6 +25310,9 @@ var init_devices = __esm({
25272
25310
  )
25273
25311
  }),
25274
25312
  "iphone-duo": {
25313
+ // offered on contributor surfaces only while the 27 home and the hinge
25314
+ // measurements are still settling (nate, 2026-09-15).
25315
+ developmentOnly: true,
25275
25316
  ...iosDevice({
25276
25317
  name: "iPhone Duo",
25277
25318
  width: 466,
@@ -25579,6 +25620,9 @@ var init_metro_production_bundle = __esm({
25579
25620
  });
25580
25621
 
25581
25622
  // ../contrast-bundler/src/metroAssetArtifact.ts
25623
+ function isEmbeddedAssetDescriptor(descriptor) {
25624
+ return descriptor.fileUris?.length === descriptor.scales.length && descriptor.fileHashes?.length === descriptor.scales.length;
25625
+ }
25582
25626
  function assetDescriptorKey(descriptor) {
25583
25627
  return `${descriptor.httpServerLocation}::${descriptor.name}::${descriptor.type}::${descriptor.hash}`;
25584
25628
  }
@@ -26170,9 +26214,27 @@ async function embedMetroAssetFiles(bundle, read) {
26170
26214
  const sizes = [];
26171
26215
  let variants = 0;
26172
26216
  let bytes = 0;
26217
+ const kept = /* @__PURE__ */ new Set();
26173
26218
  for (const site of sites) {
26174
26219
  const key = assetDescriptorKey(site.descriptor);
26175
- if (embedded.has(key)) continue;
26220
+ if (embedded.has(key) || kept.has(key)) continue;
26221
+ if (isEmbeddedAssetDescriptor(site.descriptor)) {
26222
+ kept.add(key);
26223
+ let descriptorBytes2 = 0;
26224
+ for (const uri of site.descriptor.fileUris ?? []) {
26225
+ const encoded = uri.slice(uri.indexOf(",") + 1);
26226
+ const padding = encoded.endsWith("==") ? 2 : encoded.endsWith("=") ? 1 : 0;
26227
+ const length = Math.floor(encoded.length * 3 / 4) - padding;
26228
+ variants++;
26229
+ bytes += length;
26230
+ descriptorBytes2 += length;
26231
+ }
26232
+ sizes.push({
26233
+ asset: `${site.descriptor.httpServerLocation}/${site.descriptor.name}.${site.descriptor.type}`,
26234
+ bytes: descriptorBytes2
26235
+ });
26236
+ continue;
26237
+ }
26176
26238
  const fileUris = [];
26177
26239
  const fileHashes = [];
26178
26240
  const loaded = /* @__PURE__ */ new Map();
@@ -26227,7 +26289,7 @@ async function embedMetroAssetFiles(bundle, read) {
26227
26289
  return {
26228
26290
  code,
26229
26291
  assets: {
26230
- descriptors: embedded.size,
26292
+ descriptors: embedded.size + kept.size,
26231
26293
  variants,
26232
26294
  bytes,
26233
26295
  sizes: sortedAssetSizes(sizes)
@@ -27596,37 +27658,26 @@ function normalizeCloudOrigin(source) {
27596
27658
  return parsed.origin;
27597
27659
  }
27598
27660
  function createCloudSession(input) {
27661
+ const boxId = input.boxId?.trim() ?? "";
27662
+ const boxToken = input.boxToken ?? "";
27663
+ if (boxId === "" !== (boxToken === "")) {
27664
+ throw new Error("cloud session names a box with both its id and its token");
27665
+ }
27599
27666
  const session = {
27600
27667
  version: CLOUD_SESSION_VERSION,
27601
27668
  service: "sim",
27602
- boxId: input.boxId.trim(),
27603
- boxToken: input.boxToken,
27604
27669
  simId: input.simId.trim(),
27605
27670
  apiOrigin: normalizeCloudOrigin(input.apiOrigin.trim()),
27606
27671
  claimId: input.claimId.trim(),
27607
27672
  token: input.token,
27673
+ ...input.streamUrl ? { streamUrl: input.streamUrl } : {},
27608
27674
  ...input.platform ? { platform: input.platform } : {},
27609
27675
  ...input.device?.trim() ? { device: input.device.trim() } : {},
27610
- ...input.artifact ? { artifact: input.artifact } : {}
27611
- };
27612
- if (!session.boxId || !session.boxToken || !session.simId || !session.claimId || !session.token) {
27613
- throw new Error("cloud session requires box, simulator, origin, claim, and tokens");
27614
- }
27615
- return session;
27616
- }
27617
- function createCloudBoxSession(input) {
27618
- const session = {
27619
- version: CLOUD_SESSION_VERSION,
27620
- service: "box",
27621
- boxId: input.boxId.trim(),
27622
- boxToken: input.boxToken,
27623
- apiOrigin: normalizeCloudOrigin(input.apiOrigin.trim()),
27624
- ...input.platform ? { platform: input.platform } : {},
27625
- ...input.device?.trim() ? { device: input.device.trim() } : {},
27626
- ...input.artifact ? { artifact: input.artifact } : {}
27676
+ ...input.artifact ? { artifact: input.artifact } : {},
27677
+ ...boxId && boxToken ? { boxId, boxToken } : {}
27627
27678
  };
27628
- if (!session.boxId || !session.boxToken) {
27629
- throw new Error("cloud box session requires a box, an origin, and a box token");
27679
+ if (!session.simId || !session.claimId || !session.token) {
27680
+ throw new Error("cloud session requires a simulator, an origin, a claim, and a token");
27630
27681
  }
27631
27682
  return session;
27632
27683
  }
@@ -27648,10 +27699,8 @@ function parseCloudSession(encoded) {
27648
27699
  if (!isRecord4(parsed) || parsed.version !== CLOUD_SESSION_VERSION) {
27649
27700
  throw new Error(`${RNX_CLOUD_SESSION_ENV} is invalid`);
27650
27701
  }
27651
- const boxId = parsed.boxId;
27652
- const boxToken = parsed.boxToken;
27653
27702
  const apiOrigin = parsed.apiOrigin;
27654
- if (typeof boxId !== "string" || typeof boxToken !== "string" || typeof apiOrigin !== "string") {
27703
+ if (typeof apiOrigin !== "string") {
27655
27704
  throw new Error(`${RNX_CLOUD_SESSION_ENV} is invalid`);
27656
27705
  }
27657
27706
  const platform = parsed.platform === "ios" || parsed.platform === "android" ? parsed.platform : void 0;
@@ -27660,17 +27709,10 @@ function parseCloudSession(encoded) {
27660
27709
  sha256: parsed.artifact.sha256,
27661
27710
  bytes: typeof parsed.artifact.bytes === "number" ? parsed.artifact.bytes : void 0
27662
27711
  } : void 0;
27712
+ const streamUrl = typeof parsed.streamUrl === "string" ? parsed.streamUrl : void 0;
27713
+ const boxId = typeof parsed.boxId === "string" ? parsed.boxId : void 0;
27714
+ const boxToken = typeof parsed.boxToken === "string" ? parsed.boxToken : void 0;
27663
27715
  try {
27664
- if (parsed.service === "box") {
27665
- return createCloudBoxSession({
27666
- boxId,
27667
- boxToken,
27668
- apiOrigin,
27669
- platform,
27670
- device,
27671
- artifact
27672
- });
27673
- }
27674
27716
  const simId = parsed.simId;
27675
27717
  const claimId = parsed.claimId;
27676
27718
  const token = parsed.token;
@@ -27678,15 +27720,16 @@ function parseCloudSession(encoded) {
27678
27720
  throw new Error("unreadable cloud session");
27679
27721
  }
27680
27722
  return createCloudSession({
27681
- boxId,
27682
- boxToken,
27683
27723
  simId,
27684
27724
  apiOrigin,
27685
27725
  claimId,
27686
27726
  token,
27727
+ streamUrl,
27687
27728
  platform,
27688
27729
  device,
27689
- artifact
27730
+ artifact,
27731
+ boxId,
27732
+ boxToken
27690
27733
  });
27691
27734
  } catch {
27692
27735
  throw new Error(`${RNX_CLOUD_SESSION_ENV} is invalid`);
@@ -27768,7 +27811,8 @@ function failureSentence(text) {
27768
27811
  }
27769
27812
  if (!isRecord5(parsed)) return null;
27770
27813
  if (isRecord5(parsed.error) && typeof parsed.error.message === "string") {
27771
- return parsed.error.message;
27814
+ const code = typeof parsed.error.code === "string" && parsed.error.code ? ` [${parsed.error.code}]` : "";
27815
+ return `${parsed.error.message}${code}`;
27772
27816
  }
27773
27817
  if (typeof parsed.message === "string") return parsed.message;
27774
27818
  if (typeof parsed.error === "string") return parsed.error;
@@ -28090,10 +28134,21 @@ async function inferCloudModuleIdentity(source) {
28090
28134
  async function produceCloudArtifact(bundlePath, maxBytes = MAX_RNX_CLOUD_BUNDLE_BYTES) {
28091
28135
  return produceArtifact(bundlePath, maxBytes, REMOTE_COMMAND, "allow-placeholders");
28092
28136
  }
28093
- async function produceArtifact(bundlePath, maxBytes, command, assetPolicy) {
28137
+ async function embedBundleAssets(bundlePath, command, assetPolicy) {
28094
28138
  const source = await loadBundleSource(bundlePath);
28095
- const descriptors = extractAssetDescriptors(source);
28096
- const search = descriptors.length > 0 && !isRemoteBundleInput(bundlePath) ? searchMetroAssetDest(bundlePath, descriptors) : { dest: null, searched: [], truncated: false, unconfirmed: false };
28139
+ const descriptors = extractAssetDescriptors(source).filter(
28140
+ (descriptor) => !isEmbeddedAssetDescriptor(descriptor)
28141
+ );
28142
+ if (descriptors.length === 0) {
28143
+ return {
28144
+ source,
28145
+ code: source,
28146
+ search: { dest: null, searched: [], truncated: false, unconfirmed: false },
28147
+ dest: null,
28148
+ substituted: []
28149
+ };
28150
+ }
28151
+ const search = !isRemoteBundleInput(bundlePath) ? searchMetroAssetDest(bundlePath, descriptors) : { dest: null, searched: [], truncated: false, unconfirmed: false };
28097
28152
  const dest = search.dest;
28098
28153
  const placements = /* @__PURE__ */ new Map();
28099
28154
  descriptors.forEach((descriptor, index) => {
@@ -28142,7 +28197,17 @@ async function produceArtifact(bundlePath, maxBytes, command, assetPolicy) {
28142
28197
  `${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\`.`
28143
28198
  );
28144
28199
  });
28145
- const artifact = await buildRnxCloudArtifact(embedded.code, {
28200
+ return {
28201
+ source,
28202
+ code: embedded.code,
28203
+ search,
28204
+ dest,
28205
+ substituted
28206
+ };
28207
+ }
28208
+ async function produceArtifact(bundlePath, maxBytes, command, assetPolicy) {
28209
+ const prepared = await embedBundleAssets(bundlePath, command, assetPolicy);
28210
+ const artifact = await buildRnxCloudArtifact(prepared.code, {
28146
28211
  inferModuleIdentity: inferCloudModuleIdentity
28147
28212
  });
28148
28213
  const bytes = Buffer.from(artifact.code, "utf8");
@@ -28153,14 +28218,14 @@ async function produceArtifact(bundlePath, maxBytes, command, assetPolicy) {
28153
28218
  );
28154
28219
  }
28155
28220
  const warnings = [];
28156
- if (search.unconfirmed && dest) {
28221
+ if (prepared.search.unconfirmed && prepared.dest) {
28157
28222
  warnings.push(
28158
- `${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.`
28223
+ `${command} read this bundle's assets from ${prepared.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.`
28159
28224
  );
28160
28225
  }
28161
- if (substituted.length > 0) {
28226
+ if (prepared.substituted.length > 0) {
28162
28227
  warnings.push(
28163
- `${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.`
28228
+ `${command} embedded a placeholder image for ${prepared.substituted.length} asset(s) no scale of which is in ${prepared.search.searched.join(", ") || "any asset dest directory"}: ${prepared.substituted.join(", ")}. Rebuild with \`react-native bundle --assets-dest\` to ship the real images.`
28164
28229
  );
28165
28230
  }
28166
28231
  if (bytes.length >= Math.floor(maxBytes * 0.8)) {
@@ -28172,7 +28237,7 @@ async function produceArtifact(bundlePath, maxBytes, command, assetPolicy) {
28172
28237
  bytes,
28173
28238
  sha256: (0, import_node_crypto5.createHash)("sha256").update(bytes).digest("hex"),
28174
28239
  receipt: artifact.receipt,
28175
- assetsDirectory: dest?.directory ?? null,
28240
+ assetsDirectory: prepared.dest?.directory ?? null,
28176
28241
  warnings
28177
28242
  };
28178
28243
  }
@@ -28206,9 +28271,6 @@ function readCreateResponse(value, expectedBytes, expectedSha256) {
28206
28271
  }
28207
28272
  async function createCloudBox(options) {
28208
28273
  const platform = options.platform ?? "ios";
28209
- if (platform === "android") {
28210
- throw new UnsupportedRemoteHostError("android", "nano");
28211
- }
28212
28274
  const apiOrigin = resolveCloudOrigin(options.apiOrigin);
28213
28275
  const artifact = await produceCloudArtifact(options.bundlePath);
28214
28276
  const boxName = options.boxName?.trim();
@@ -28281,14 +28343,6 @@ async function createCloudBox(options) {
28281
28343
  function resolveCloudSessionForParsed(parsed) {
28282
28344
  const session = readCloudSession();
28283
28345
  if (!session) return null;
28284
- if (session.service === "box") {
28285
- if (parsed.simIdSource === "flag" && parsed.simId !== session.boxId) {
28286
- throw new Error(
28287
- `this shell is connected to box ${session.boxId}; ${parsed.simId ? `--sim ${parsed.simId}` : "the requested simulator"} is not available in this shell`
28288
- );
28289
- }
28290
- return session;
28291
- }
28292
28346
  if (parsed.simIdSource === "flag" && parsed.simId !== session.simId) {
28293
28347
  throw new Error(
28294
28348
  `this shell is connected to remote simulator ${session.simId}; ${parsed.simId ? `--sim ${parsed.simId}` : "the requested simulator"} is not available in this shell`
@@ -28316,9 +28370,9 @@ function cloudCommand(command) {
28316
28370
  function createCloudBridgeForParsed(parsed) {
28317
28371
  const session = resolveCloudSessionForParsed(parsed);
28318
28372
  if (!session) return null;
28319
- return session.service === "box" ? new CloudBoxBridge(session) : new CloudBridge(session);
28373
+ return new CloudBridge(session);
28320
28374
  }
28321
- var import_node_crypto5, import_node_fs14, import_node_path15, UnsupportedRemoteHostError, DEFAULT_RNX_CLOUD_ORIGIN, MAX_RNX_CLOUD_BUNDLE_BYTES, REMOTE_COMMAND, MAX_ASSET_DEST_FILES, ACCOUNT_CHOICE_REFUSALS, PROJECT_ONLY_DIRECTORIES, MAX_PLACEMENT_COMBINATIONS, CloudBridge, CloudBoxBridge;
28375
+ var import_node_crypto5, import_node_fs14, import_node_path15, DEFAULT_RNX_CLOUD_ORIGIN, MAX_RNX_CLOUD_BUNDLE_BYTES, REMOTE_COMMAND, MAX_ASSET_DEST_FILES, ACCOUNT_CHOICE_REFUSALS, PROJECT_ONLY_DIRECTORIES, MAX_PLACEMENT_COMBINATIONS, CloudBridge;
28322
28376
  var init_cloud_client = __esm({
28323
28377
  "cli/cloud-client.ts"() {
28324
28378
  "use strict";
@@ -28336,19 +28390,6 @@ var init_cloud_client = __esm({
28336
28390
  init_auth();
28337
28391
  init_cloud_session();
28338
28392
  init_detect();
28339
- UnsupportedRemoteHostError = class extends Error {
28340
- code = "unsupported_host";
28341
- platform;
28342
- host;
28343
- constructor(platform, host, message) {
28344
- super(
28345
- message ?? `rnx remote ${platform} does not support --${host}: rnxsim/cloud only creates iOS simulators`
28346
- );
28347
- this.name = "UnsupportedRemoteHostError";
28348
- this.platform = platform;
28349
- this.host = host;
28350
- }
28351
- };
28352
28393
  DEFAULT_RNX_CLOUD_ORIGIN = rnxPublicBrand.origin;
28353
28394
  MAX_RNX_CLOUD_BUNDLE_BYTES = RNX_CLOUD_MAX_ARTIFACT_BYTES;
28354
28395
  REMOTE_COMMAND = "rnx remote";
@@ -28439,73 +28480,6 @@ var init_cloud_client = __esm({
28439
28480
  close() {
28440
28481
  }
28441
28482
  };
28442
- CloudBoxBridge = class {
28443
- constructor(session) {
28444
- this.session = session;
28445
- }
28446
- plane = "cloud";
28447
- async send(command, options) {
28448
- const id = (0, import_node_crypto5.randomUUID)();
28449
- const payload = {};
28450
- for (const [key, value] of Object.entries(command)) {
28451
- if (key !== "id" && key !== "simId") payload[key] = value;
28452
- }
28453
- let response;
28454
- try {
28455
- response = await fetch(
28456
- `${this.session.apiOrigin}/v1/boxes/${encodeURIComponent(this.session.boxId)}/commands`,
28457
- {
28458
- method: "POST",
28459
- headers: {
28460
- authorization: `Bearer ${this.session.boxToken}`,
28461
- "content-type": "application/json"
28462
- },
28463
- body: JSON.stringify({ id, command: payload }),
28464
- ...options?.timeoutMs ? { signal: AbortSignal.timeout(options.timeoutMs) } : {}
28465
- }
28466
- );
28467
- } catch (error) {
28468
- throw new Error(
28469
- `could not reach box ${this.session.boxId} at ${this.session.apiOrigin}: ${error instanceof Error ? error.message : String(error)}`
28470
- );
28471
- }
28472
- const text = await response.text();
28473
- if (!response.ok) throw responseError(response.status, text);
28474
- let parsed;
28475
- try {
28476
- parsed = JSON.parse(text);
28477
- } catch {
28478
- throw new Error("box command returned unreadable JSON");
28479
- }
28480
- if (!isRecord5(parsed) || parsed.id !== id) {
28481
- throw new Error("box command returned an invalid command receipt");
28482
- }
28483
- if (typeof parsed.error === "string" && parsed.error) throw new Error(parsed.error);
28484
- if (!Object.hasOwn(parsed, "result")) {
28485
- throw new Error("box command receipt has no result");
28486
- }
28487
- return parsed.result;
28488
- }
28489
- listSims() {
28490
- return Promise.reject(new Error("a box does not expose a local simulator list"));
28491
- }
28492
- focusSim() {
28493
- return Promise.reject(new Error("a box simulator has no browser window to focus"));
28494
- }
28495
- resolveReloadedSim() {
28496
- return Promise.resolve(null);
28497
- }
28498
- closeSim() {
28499
- return Promise.reject(new Error("close a box simulator with rnx box stop"));
28500
- }
28501
- claim() {
28502
- return Promise.reject(
28503
- new Error("a box simulator is held by its Box page and has nothing to claim")
28504
- );
28505
- }
28506
- close() {
28507
- }
28508
- };
28509
28483
  }
28510
28484
  });
28511
28485