rnxsim 0.1.504 → 0.1.506

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 (61) hide show
  1. package/cli/bridge-flow-runner.ts +7 -2
  2. package/cli/commands/agent-wrapper.ts +7 -3
  3. package/cli/commands/detox.ts +19 -3
  4. package/cli/commands/flow.ts +1 -0
  5. package/cli/commands/inspect.ts +2 -2
  6. package/cli/commands/test.ts +4 -1
  7. package/cli/flow-live-status.ts +8 -2
  8. package/dist-lib/agent-daemon-client.cjs +1 -1
  9. package/dist-lib/agent-events.cjs +1 -1
  10. package/dist-lib/agent-identity.cjs +1 -1
  11. package/dist-lib/agent-sessions.cjs +1 -1
  12. package/dist-lib/attached-projects.cjs +1 -1
  13. package/dist-lib/auth/shared-session.cjs +1 -1
  14. package/dist-lib/backend-origin.cjs +1 -1
  15. package/dist-lib/beta.cjs +1 -1
  16. package/dist-lib/beta.mjs +1 -1
  17. package/dist-lib/bridge-constants.cjs +1 -1
  18. package/dist-lib/bridge-contract-input.cjs +1 -1
  19. package/dist-lib/bridge-contract-input.mjs +1 -1
  20. package/dist-lib/bridge-contract.cjs +1 -1
  21. package/dist-lib/bridge-contract.mjs +1 -1
  22. package/dist-lib/capture-contract.cjs +1 -1
  23. package/dist-lib/capture-contract.mjs +1 -1
  24. package/dist-lib/cli-constants.cjs +1 -1
  25. package/dist-lib/cloud-contract.cjs +1 -1
  26. package/dist-lib/cloud-contract.mjs +1 -1
  27. package/dist-lib/cloud.cjs +1 -1
  28. package/dist-lib/cloud.mjs +1 -1
  29. package/dist-lib/config.cjs +1 -1
  30. package/dist-lib/detox/index.cjs +1 -1
  31. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  32. package/dist-lib/home-paths.cjs +1 -1
  33. package/dist-lib/host/bridge-host.cjs +142 -56
  34. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  35. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  36. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  37. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  38. package/dist-lib/host/websocket-proxy.cjs +1 -1
  39. package/dist-lib/index.cjs +1 -1
  40. package/dist-lib/jump-to-source-babel.cjs +1 -1
  41. package/dist-lib/jump-to-source-native.cjs +1 -1
  42. package/dist-lib/menu.cjs +1 -1
  43. package/dist-lib/menu.mjs +1 -1
  44. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  45. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  46. package/dist-lib/metro-production-bundle.cjs +1 -1
  47. package/dist-lib/metro-production-bundle.mjs +1 -1
  48. package/dist-lib/metro.cjs +1 -1
  49. package/dist-lib/profiles.cjs +1 -1
  50. package/dist-lib/public-brand.cjs +1 -1
  51. package/dist-lib/react-native-host-modules.cjs +1 -1
  52. package/dist-lib/react-native-host-modules.mjs +1 -1
  53. package/dist-lib/render-mode.cjs +1 -1
  54. package/dist-lib/scripts/dev-server-scanner.cjs +36 -18
  55. package/dist-lib/sdk.cjs +1 -1
  56. package/dist-lib/sdk.mjs +1 -1
  57. package/dist-lib/skills.cjs +189 -67
  58. package/dist-lib/vite.cjs +1 -1
  59. package/package.json +1 -1
  60. package/scripts/dev-server-scanner.ts +37 -20
  61. package/src/screenshots/frame-compose.ts +71 -11
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.504 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.506 | (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;
@@ -20007,20 +20007,34 @@ function applyManifest(result, manifestRes, buildIconProxyUrl) {
20007
20007
  if (launchUrl2 && !result.patched && !isDirectOneBundleUrl(result.bundleUrl)) {
20008
20008
  result.bundleUrl = withRuntimeConfig(result.port, launchUrl2, result.cwd);
20009
20009
  }
20010
- const rawIconUrl = client.iconUrl || client.ios?.iconUrl || client.icon || client.ios?.icon;
20011
- if (rawIconUrl) {
20012
- result.iconPath = rawIconUrl;
20013
- if (buildIconProxyUrl) {
20014
- if (rawIconUrl.startsWith("http")) {
20015
- result.iconUrl = buildIconProxyUrl(rawIconUrl);
20010
+ const localIcon = client.icon || client.ios?.icon;
20011
+ const remoteIcon = client.iconUrl || client.ios?.iconUrl;
20012
+ const rawIcon = localIcon || remoteIcon;
20013
+ if (rawIcon) {
20014
+ result.iconPath = rawIcon;
20015
+ let resolvedIconUrl;
20016
+ if (rawIcon.startsWith("http://") || rawIcon.startsWith("https://")) {
20017
+ let isLoopback = false;
20018
+ try {
20019
+ const parsed = new URL(rawIcon);
20020
+ isLoopback = isLoopbackHost(parsed.hostname);
20021
+ } catch {
20022
+ }
20023
+ if (buildIconProxyUrl) {
20024
+ if (isLoopback) {
20025
+ resolvedIconUrl = buildIconProxyUrl(rawIcon);
20026
+ }
20016
20027
  } else {
20017
- const cleanPath = rawIconUrl.replace(/^\.\//, "");
20018
- result.iconUrl = buildIconProxyUrl(
20019
- `${buildLoopbackProbeBaseUrl("http:", manifestRes.hostname, result.port)}/assets/${cleanPath}`
20020
- );
20028
+ resolvedIconUrl = rawIcon;
20021
20029
  }
20022
20030
  } else {
20023
- result.iconUrl = rawIconUrl.startsWith("http") ? rawIconUrl : `${buildLoopbackProbeBaseUrl("http:", manifestRes.hostname, result.port)}/assets/${rawIconUrl.replace(/^\.\//, "")}`;
20031
+ const cleanPath = rawIcon.replace(/^\.?\//, "");
20032
+ const assetPath = cleanPath.startsWith("assets/") ? `/${cleanPath}` : `/assets/${cleanPath}`;
20033
+ const localUrl = `${buildLoopbackProbeBaseUrl("http:", manifestRes.hostname, result.port)}${assetPath}`;
20034
+ resolvedIconUrl = buildIconProxyUrl ? buildIconProxyUrl(localUrl) : localUrl;
20035
+ }
20036
+ if (resolvedIconUrl) {
20037
+ result.iconUrl = resolvedIconUrl;
20024
20038
  }
20025
20039
  }
20026
20040
  } catch {
@@ -24787,6 +24801,9 @@ function modernButtons(action, volumeUp, volumeDown, power) {
24787
24801
  function uniformFrameInsets(value) {
24788
24802
  return { top: value, right: value, bottom: value, left: value };
24789
24803
  }
24804
+ function cornerRadii(value) {
24805
+ return { topLeft: value, topRight: value, bottomRight: value, bottomLeft: value };
24806
+ }
24790
24807
  function iosDevice(spec) {
24791
24808
  return {
24792
24809
  ...spec,
@@ -24808,8 +24825,36 @@ function iosDevice(spec) {
24808
24825
  modelName: spec.name
24809
24826
  };
24810
24827
  }
24811
- function getDevice(model) {
24812
- return devices[model];
24828
+ function resolveDevicePosture(model, posture) {
24829
+ const supported = devices[model].supportedPostures;
24830
+ return posture && supported?.includes(posture) ? posture : supported?.[0] ?? "closed";
24831
+ }
24832
+ function getDevice(model, posture) {
24833
+ const device = devices[model];
24834
+ if (!device.supportedPostures) return device;
24835
+ const resolvedPosture = resolveDevicePosture(model, posture);
24836
+ if (resolvedPosture === "closed") return device;
24837
+ return {
24838
+ ...device,
24839
+ // inner display size from apple's ios 27 ui kit. corners and insets are
24840
+ // measured from apple's 2d inner product art: every display corner fits a
24841
+ // 53pt circle within 0.4px, and the silhouette sits 19.5pt outside the
24842
+ // display on every edge as 16pt of black glass plus a 3.5pt rail.
24843
+ width: 951,
24844
+ height: 669,
24845
+ statusBarHeight: 44,
24846
+ cornerRadius: cornerRadii(53),
24847
+ continuousCornerRadius: cornerRadii(53),
24848
+ frameInsets: uniformFrameInsets(19.5),
24849
+ housing: { rail: uniformFrameInsets(3.5), hingeBarrel: null },
24850
+ cameraCutout: null,
24851
+ physicalPPI: 430,
24852
+ posture: "open",
24853
+ // open inner display keeps horizontal bars in this slice; preserve the
24854
+ // previous trailing status lane so open layouts do not pick up the closed
24855
+ // 84pt Vertical Bar inset.
24856
+ safeAreaInsets: { top: 0, bottom: 0, left: 0, right: 72 }
24857
+ };
24813
24858
  }
24814
24859
  function listDeviceModels() {
24815
24860
  return Object.keys(devices);
@@ -24858,8 +24903,8 @@ var init_devices = __esm({
24858
24903
  scale: 1,
24859
24904
  statusBarHeight: 0,
24860
24905
  homeIndicatorHeight: 0,
24861
- cornerRadius: 0,
24862
- continuousCornerRadius: 0,
24906
+ cornerRadius: cornerRadii(0),
24907
+ continuousCornerRadius: cornerRadii(0),
24863
24908
  frameInsets: uniformFrameInsets(16),
24864
24909
  dynamicIsland: null,
24865
24910
  safeAreaInsets: { top: 0, bottom: 0, left: 0, right: 0 },
@@ -24883,8 +24928,8 @@ var init_devices = __esm({
24883
24928
  scale: 2,
24884
24929
  statusBarHeight: 20,
24885
24930
  homeIndicatorHeight: 0,
24886
- cornerRadius: 0,
24887
- continuousCornerRadius: 0,
24931
+ cornerRadius: cornerRadii(0),
24932
+ continuousCornerRadius: cornerRadii(0),
24888
24933
  // legacy home-button frame uses asymmetric LEGACY_*_BEZEL constants in the
24889
24934
  // shell (111pt forehead/chin, 29pt sides); uniform frameInsets are a sane
24890
24935
  // modern-path value and mirror the SE's ~28.7pt side bezel.
@@ -24903,8 +24948,8 @@ var init_devices = __esm({
24903
24948
  scale: 3,
24904
24949
  statusBarHeight: 47,
24905
24950
  homeIndicatorHeight: 34,
24906
- cornerRadius: 46.2,
24907
- continuousCornerRadius: 67.462,
24951
+ cornerRadius: cornerRadii(46.2),
24952
+ continuousCornerRadius: cornerRadii(67.462),
24908
24953
  frameInsets: uniformFrameInsets(19.5),
24909
24954
  dynamicIsland: null,
24910
24955
  safeAreaInsets: { top: 47, bottom: 34, left: 0, right: 0 },
@@ -24925,8 +24970,8 @@ var init_devices = __esm({
24925
24970
  scale: 3,
24926
24971
  statusBarHeight: 59,
24927
24972
  homeIndicatorHeight: 34,
24928
- cornerRadius: 53.9,
24929
- continuousCornerRadius: 73.402,
24973
+ cornerRadius: cornerRadii(53.9),
24974
+ continuousCornerRadius: cornerRadii(73.402),
24930
24975
  frameInsets: uniformFrameInsets(18.2),
24931
24976
  dynamicIsland: { width: 126, height: 37.3, top: 14.1 },
24932
24977
  safeAreaInsets: { top: 59, bottom: 34, left: 0, right: 0 },
@@ -24947,8 +24992,8 @@ var init_devices = __esm({
24947
24992
  scale: 3,
24948
24993
  statusBarHeight: 59,
24949
24994
  homeIndicatorHeight: 34,
24950
- cornerRadius: 53.9,
24951
- continuousCornerRadius: 74.654,
24995
+ cornerRadius: cornerRadii(53.9),
24996
+ continuousCornerRadius: cornerRadii(74.654),
24952
24997
  frameInsets: uniformFrameInsets(17.3),
24953
24998
  dynamicIsland: { width: 126, height: 37.3, top: 11.4 },
24954
24999
  safeAreaInsets: { top: 59, bottom: 34, left: 0, right: 0 },
@@ -24969,8 +25014,8 @@ var init_devices = __esm({
24969
25014
  scale: 3,
24970
25015
  statusBarHeight: 59,
24971
25016
  homeIndicatorHeight: 34,
24972
- cornerRadius: 53.9,
24973
- continuousCornerRadius: 73.402,
25017
+ cornerRadius: cornerRadii(53.9),
25018
+ continuousCornerRadius: cornerRadii(73.402),
24974
25019
  frameInsets: uniformFrameInsets(15.3),
24975
25020
  dynamicIsland: { width: 126, height: 38, top: 13.4 },
24976
25021
  safeAreaInsets: { top: 59, bottom: 34, left: 0, right: 0 },
@@ -24991,8 +25036,8 @@ var init_devices = __esm({
24991
25036
  scale: 3,
24992
25037
  statusBarHeight: 59,
24993
25038
  homeIndicatorHeight: 34,
24994
- cornerRadius: 53.9,
24995
- continuousCornerRadius: 74.654,
25039
+ cornerRadius: cornerRadii(53.9),
25040
+ continuousCornerRadius: cornerRadii(74.654),
24996
25041
  frameInsets: uniformFrameInsets(15.3),
24997
25042
  dynamicIsland: { width: 126, height: 38, top: 13.3 },
24998
25043
  safeAreaInsets: { top: 59, bottom: 34, left: 0, right: 0 },
@@ -25017,8 +25062,8 @@ var init_devices = __esm({
25017
25062
  // mask (extracted from the simdevicetype bundle PDF; see
25018
25063
  // packages/sootsim-engine/assets/device-frame-geometry). radius is a paint clip only — the
25019
25064
  // calibrated conformance-oracle layout fields below are unchanged.
25020
- cornerRadius: 53.9,
25021
- continuousCornerRadius: 73.402,
25065
+ cornerRadius: cornerRadii(53.9),
25066
+ continuousCornerRadius: cornerRadii(73.402),
25022
25067
  frameInsets: uniformFrameInsets(15.3),
25023
25068
  // island top kept at 11 (real 11.3) — this is the calibrated conformance /
25024
25069
  // proof oracle profile; the status-bar clock offsets are tuned against it.
@@ -25041,8 +25086,8 @@ var init_devices = __esm({
25041
25086
  scale: 3,
25042
25087
  statusBarHeight: 59,
25043
25088
  homeIndicatorHeight: 34,
25044
- cornerRadius: 53.9,
25045
- continuousCornerRadius: 74.654,
25089
+ cornerRadius: cornerRadii(53.9),
25090
+ continuousCornerRadius: cornerRadii(74.654),
25046
25091
  frameInsets: uniformFrameInsets(15.3),
25047
25092
  dynamicIsland: { width: 126, height: 37.3, top: 11.4 },
25048
25093
  safeAreaInsets: { top: 59, bottom: 34, left: 0, right: 0 },
@@ -25065,8 +25110,8 @@ var init_devices = __esm({
25065
25110
  // app content at y=186px, i.e. 62 logical pt at 3x.
25066
25111
  statusBarHeight: 62,
25067
25112
  homeIndicatorHeight: 34,
25068
- cornerRadius: 61,
25069
- continuousCornerRadius: 84.661,
25113
+ cornerRadius: cornerRadii(61),
25114
+ continuousCornerRadius: cornerRadii(84.661),
25070
25115
  frameInsets: uniformFrameInsets(15.3),
25071
25116
  dynamicIsland: { width: 126, height: 38, top: 13.5 },
25072
25117
  safeAreaInsets: { top: 62, bottom: 34, left: 0, right: 0 },
@@ -25090,8 +25135,8 @@ var init_devices = __esm({
25090
25135
  // remains at the 59pt profile.
25091
25136
  statusBarHeight: 62,
25092
25137
  homeIndicatorHeight: 34,
25093
- cornerRadius: 61.3,
25094
- continuousCornerRadius: 85.163,
25138
+ cornerRadius: cornerRadii(61.3),
25139
+ continuousCornerRadius: cornerRadii(85.163),
25095
25140
  frameInsets: uniformFrameInsets(15.4),
25096
25141
  dynamicIsland: { width: 126, height: 38, top: 14 },
25097
25142
  safeAreaInsets: { top: 62, bottom: 34, left: 0, right: 0 },
@@ -25112,8 +25157,8 @@ var init_devices = __esm({
25112
25157
  scale: 3,
25113
25158
  statusBarHeight: 59,
25114
25159
  homeIndicatorHeight: 34,
25115
- cornerRadius: 61,
25116
- continuousCornerRadius: 84.661,
25160
+ cornerRadius: cornerRadii(61),
25161
+ continuousCornerRadius: cornerRadii(84.661),
25117
25162
  // display border 1.44mm plus the visible flat housing rail.
25118
25163
  frameInsets: uniformFrameInsets(15.3),
25119
25164
  dynamicIsland: { width: 126, height: 37.3, top: 14 },
@@ -25138,8 +25183,8 @@ var init_devices = __esm({
25138
25183
  scale: 3,
25139
25184
  statusBarHeight: 59,
25140
25185
  homeIndicatorHeight: 34,
25141
- cornerRadius: 64.6,
25142
- continuousCornerRadius: 88.313,
25186
+ cornerRadius: cornerRadii(64.6),
25187
+ continuousCornerRadius: cornerRadii(88.313),
25143
25188
  // WHICH QUANTITY THIS IS, because it has been flipped twice and each pass
25144
25189
  // read the other one as a bug: frameInsets is the VISIBLE FACE-ON frame —
25145
25190
  // the black display border plus however much housing rail you actually see
@@ -25175,8 +25220,8 @@ var init_devices = __esm({
25175
25220
  scale: 3,
25176
25221
  statusBarHeight: 59,
25177
25222
  homeIndicatorHeight: 34,
25178
- cornerRadius: 61,
25179
- continuousCornerRadius: 84.661,
25223
+ cornerRadius: cornerRadii(61),
25224
+ continuousCornerRadius: cornerRadii(84.661),
25180
25225
  // display border 1.44mm plus the visible flat housing rail.
25181
25226
  frameInsets: uniformFrameInsets(15.3),
25182
25227
  dynamicIsland: { width: 126, height: 38, top: 14 },
@@ -25200,8 +25245,8 @@ var init_devices = __esm({
25200
25245
  // iphone 16 pro max screens proof oracle.
25201
25246
  statusBarHeight: 62,
25202
25247
  homeIndicatorHeight: 34,
25203
- cornerRadius: 61.3,
25204
- continuousCornerRadius: 85.163,
25248
+ cornerRadius: cornerRadii(61.3),
25249
+ continuousCornerRadius: cornerRadii(85.163),
25205
25250
  // display border 1.36mm plus the visible flat housing rail.
25206
25251
  frameInsets: uniformFrameInsets(15.4),
25207
25252
  dynamicIsland: { width: 126, height: 38, top: 14 },
@@ -25216,6 +25261,47 @@ var init_devices = __esm({
25216
25261
  [292.2, 98.3]
25217
25262
  )
25218
25263
  }),
25264
+ "iphone-duo": {
25265
+ ...iosDevice({
25266
+ name: "iPhone Duo",
25267
+ width: 466,
25268
+ height: 678,
25269
+ scale: 3,
25270
+ statusBarHeight: 66,
25271
+ homeIndicatorHeight: 0,
25272
+ // hinge on the left. the hinge-side display corners measure 5pt in
25273
+ // apple's 2d outer product art; the free side keeps the 61pt pro curve.
25274
+ cornerRadius: { topLeft: 5, topRight: 61, bottomRight: 61, bottomLeft: 5 },
25275
+ continuousCornerRadius: {
25276
+ topLeft: 5,
25277
+ topRight: 61,
25278
+ bottomRight: 61,
25279
+ bottomLeft: 5
25280
+ },
25281
+ // display edge to silhouette. left is black glass 8.6 + rail 5.4 + hinge
25282
+ // barrel 14.1; right is black glass 8.7 + rail 7.7.
25283
+ frameInsets: { top: 19, right: 16.4, bottom: 16.3, left: 28.1 },
25284
+ housing: {
25285
+ rail: { top: 10.4, right: 7.7, bottom: 7.7, left: 19.5 },
25286
+ hingeBarrel: { width: 14.1, endInset: 6.4 }
25287
+ },
25288
+ dynamicIsland: null,
25289
+ // 84pt trailing Vertical Bar on the outer display (Apple iOS 27 UI kit).
25290
+ safeAreaInsets: { top: 0, bottom: 0, left: 0, right: 84 },
25291
+ iosVersion: "27.1",
25292
+ keyboardHeight: 0,
25293
+ physicalPPI: 460,
25294
+ // official model extraction for button positions is outside this slice.
25295
+ hardwareButtons: modernButtons([0, 0], [0, 0], [0, 0], [0, 0]),
25296
+ posture: "closed",
25297
+ supportedPostures: ["closed", "open"]
25298
+ }),
25299
+ cameraCutout: {
25300
+ diameter: 37,
25301
+ top: 29,
25302
+ trailing: 29
25303
+ }
25304
+ },
25219
25305
  "pixel-8": {
25220
25306
  platform: "android",
25221
25307
  name: "Pixel 8",
@@ -25235,8 +25321,8 @@ var init_devices = __esm({
25235
25321
  left: 0,
25236
25322
  right: 0
25237
25323
  },
25238
- cornerRadius: 39,
25239
- continuousCornerRadius: 39,
25324
+ cornerRadius: cornerRadii(39),
25325
+ continuousCornerRadius: cornerRadii(39),
25240
25326
  // android studio's pixel 8 device art places the 1080x2400 display at
25241
25327
  // (49,55) in a 1187x2513 body. the right side button occupies the final
25242
25328
  // 8 physical pixels, so the body insets are 49/50/58/55 at 2.625x.
@@ -25283,8 +25369,8 @@ var init_devices = __esm({
25283
25369
  left: 0,
25284
25370
  right: 0
25285
25371
  },
25286
- cornerRadius: 39,
25287
- continuousCornerRadius: 39,
25372
+ cornerRadius: cornerRadii(39),
25373
+ continuousCornerRadius: cornerRadii(39),
25288
25374
  frameInsets: {
25289
25375
  top: 55 / 2.625,
25290
25376
  right: 50 / 2.625,
@@ -25323,8 +25409,8 @@ var init_devices = __esm({
25323
25409
  keyboardHeight: 308,
25324
25410
  navigationBarMode: "gesture",
25325
25411
  displayCutout: { top: 40, bottom: 0, left: 0, right: 0 },
25326
- cornerRadius: 41,
25327
- continuousCornerRadius: 41,
25412
+ cornerRadius: cornerRadii(41),
25413
+ continuousCornerRadius: cornerRadii(41),
25328
25414
  // Pixel 9 Pro XL body 162.8×76.6mm over a 70.2mm panel → ~1.8mm ≈ 12pt.
25329
25415
  frameInsets: uniformFrameInsets(12),
25330
25416
  dynamicIsland: null,
@@ -25359,8 +25445,8 @@ var init_devices = __esm({
25359
25445
  keyboardHeight: 308,
25360
25446
  navigationBarMode: "gesture",
25361
25447
  displayCutout: { top: 40, bottom: 0, left: 0, right: 0 },
25362
- cornerRadius: 40,
25363
- continuousCornerRadius: 40,
25448
+ cornerRadius: cornerRadii(40),
25449
+ continuousCornerRadius: cornerRadii(40),
25364
25450
  // the 72mm body surrounds a roughly 65.1mm-wide 6.3-inch panel, which
25365
25451
  // resolves to about 18 logical points of frame around the 1080px display.
25366
25452
  frameInsets: uniformFrameInsets(18),
@@ -25396,8 +25482,8 @@ var init_devices = __esm({
25396
25482
  keyboardHeight: 308,
25397
25483
  navigationBarMode: "gesture",
25398
25484
  displayCutout: { top: 36, bottom: 0, left: 0, right: 0 },
25399
- cornerRadius: 36,
25400
- continuousCornerRadius: 36,
25485
+ cornerRadius: cornerRadii(36),
25486
+ continuousCornerRadius: cornerRadii(36),
25401
25487
  // Galaxy S24 body 147.0×70.6mm over a 65.9mm panel → ~1.2mm ≈ 8pt (Samsung
25402
25488
  // flat-display bezels are noticeably thinner than Pixel's).
25403
25489
  frameInsets: uniformFrameInsets(8),
@@ -25434,8 +25520,8 @@ var init_devices = __esm({
25434
25520
  keyboardHeight: 308,
25435
25521
  navigationBarMode: "gesture",
25436
25522
  displayCutout: { top: 36, bottom: 0, left: 0, right: 0 },
25437
- cornerRadius: 24,
25438
- continuousCornerRadius: 24,
25523
+ cornerRadius: cornerRadii(24),
25524
+ continuousCornerRadius: cornerRadii(24),
25439
25525
  // Galaxy S24 Ultra body 162.3×79.0mm over a 72.4mm panel → ~1.5mm ≈ 9pt.
25440
25526
  frameInsets: uniformFrameInsets(9),
25441
25527
  dynamicIsland: null,
@@ -35571,10 +35657,12 @@ var require_proof_frame = __commonJS({
35571
35657
  function getFramedScreenshotLayout(model) {
35572
35658
  const spec = (0, import_settings2.getDevice)(model);
35573
35659
  const renderScale = spec.scale;
35574
- const isLegacyHardware = spec.statusBarHeight > 0 && !spec.dynamicIsland && spec.homeIndicatorHeight === 0 && spec.cornerRadius === 0;
35660
+ const isLegacyHardware = spec.statusBarHeight > 0 && !spec.dynamicIsland && spec.homeIndicatorHeight === 0 && // home-button iphones have a square display, so any corner reads 0
35661
+ spec.cornerRadius.topLeft === 0;
35575
35662
  const logicalScreenWidth = spec.width;
35576
35663
  const logicalScreenHeight = spec.height;
35577
35664
  const modernGeometry = (0, import_settings2.resolveDeviceFrameGeometry)(spec);
35665
+ const housing = isLegacyHardware ? null : modernGeometry.housing;
35578
35666
  const logicalFrameWidth = isLegacyHardware ? spec.width + import_chrome_metrics.LEGACY_SIDE_BEZEL * 2 : modernGeometry.frameWidth;
35579
35667
  const logicalFrameHeight = isLegacyHardware ? spec.height + import_chrome_metrics.LEGACY_TOP_BEZEL + import_chrome_metrics.LEGACY_BOTTOM_BEZEL : modernGeometry.frameHeight;
35580
35668
  const logicalFrameLeft = import_chrome_metrics.SIDE_BUTTON_RESERVE;
@@ -35583,7 +35671,7 @@ function getFramedScreenshotLayout(model) {
35583
35671
  const logicalOuterHeight = logicalFrameHeight + FRAME_OUTLINE_BLEED * 2;
35584
35672
  const logicalScreenLeft = logicalFrameLeft + (isLegacyHardware ? import_chrome_metrics.LEGACY_SIDE_BEZEL : modernGeometry.screenLeft);
35585
35673
  const logicalScreenTop = isLegacyHardware ? import_chrome_metrics.LEGACY_TOP_BEZEL : modernGeometry.screenTop;
35586
- const logicalFrameRadius = isLegacyHardware ? import_chrome_metrics.LEGACY_FRAME_RADIUS : modernGeometry.frameRadius;
35674
+ const logicalFrameRadius = isLegacyHardware ? (0, import_settings2.cornerRadii)(import_chrome_metrics.LEGACY_FRAME_RADIUS) : modernGeometry.frameRadius;
35587
35675
  const buttons = [
35588
35676
  {
35589
35677
  side: spec.hardwareButtons.lock.side,
@@ -35625,11 +35713,12 @@ function getFramedScreenshotLayout(model) {
35625
35713
  logicalScreenHeight,
35626
35714
  logicalScreenLeft,
35627
35715
  logicalScreenTop,
35628
- logicalScreenRadius: isLegacyHardware ? 0 : modernGeometry.screenRadius,
35716
+ logicalScreenRadius: isLegacyHardware ? (0, import_settings2.cornerRadii)(0) : modernGeometry.screenRadius,
35629
35717
  logicalFrameRadius,
35630
- frameBackground: isLegacyHardware ? "linear-gradient(180deg, #1b1c20 0%, #0f1012 42%, #050608 100%)" : "#000000",
35631
- frameOutline: isLegacyHardware ? "0 0 0 1px #1f2125" : "0 0 0 1px #333",
35632
- metallicRingShadow: isLegacyHardware ? null : METALLIC_RING_SHADOW,
35718
+ housing,
35719
+ frameBackground: isLegacyHardware ? "linear-gradient(180deg, #1b1c20 0%, #0f1012 42%, #050608 100%)" : housing ? import_chrome_metrics.HOUSING_RAIL_COLOR : "#000000",
35720
+ frameOutline: isLegacyHardware ? "0 0 0 1px #1f2125" : housing ? import_chrome_metrics.HOUSING_RAIL_OUTLINE : "0 0 0 1px #333",
35721
+ metallicRingShadow: isLegacyHardware || housing ? null : METALLIC_RING_SHADOW,
35633
35722
  buttons,
35634
35723
  legacyHomeButton: isLegacyHardware ? {
35635
35724
  top: import_chrome_metrics.LEGACY_TOP_BEZEL + spec.height + (import_chrome_metrics.LEGACY_BOTTOM_BEZEL - import_chrome_metrics.LEGACY_HOME_BUTTON_SIZE) / 2,
@@ -35679,13 +35768,45 @@ function renderFrameHtml(layout, rawImageDataUrl) {
35679
35768
  style="
35680
35769
  position:absolute;
35681
35770
  inset:0;
35682
- border-radius:${layout.logicalFrameRadius}px;
35771
+ border-radius:${(0, import_settings2.formatCornerRadii)(layout.logicalFrameRadius)};
35683
35772
  box-shadow:${layout.metallicRingShadow};
35684
35773
  pointer-events:none;
35685
35774
  z-index:10;
35686
35775
  "
35687
35776
  ></div>
35688
35777
  ` : "";
35778
+ const housingHtml = layout.housing ? `
35779
+ <div
35780
+ aria-hidden="true"
35781
+ style="
35782
+ position:absolute;
35783
+ top:${layout.housing.rail.top}px;
35784
+ right:${layout.housing.rail.right}px;
35785
+ bottom:${layout.housing.rail.bottom}px;
35786
+ left:${layout.housing.rail.left}px;
35787
+ border-radius:${(0, import_settings2.formatCornerRadii)(layout.housing.glassRadius)};
35788
+ background:#000000;
35789
+ pointer-events:none;
35790
+ "
35791
+ ></div>
35792
+ ${layout.housing.hingeBarrel ? `
35793
+ <div
35794
+ aria-hidden="true"
35795
+ style="
35796
+ position:absolute;
35797
+ top:${layout.housing.hingeBarrel.endInset}px;
35798
+ bottom:${layout.housing.hingeBarrel.endInset}px;
35799
+ left:0;
35800
+ width:${layout.housing.hingeBarrel.width}px;
35801
+ border-radius:${layout.housing.hingeBarrel.width / 2}px 0 0 ${layout.housing.hingeBarrel.width / 2}px;
35802
+ background:${import_chrome_metrics.HINGE_BARREL_BACKGROUND};
35803
+ box-shadow:${import_chrome_metrics.HINGE_BARREL_SHADOW};
35804
+ pointer-events:none;
35805
+ z-index:11;
35806
+ "
35807
+ ></div>
35808
+ ` : ""}
35809
+ ` : "";
35689
35810
  const legacyHomeButtonHtml = layout.legacyHomeButton ? `
35690
35811
  <div
35691
35812
  aria-hidden="true"
@@ -35799,7 +35920,7 @@ function renderFrameHtml(layout, rawImageDataUrl) {
35799
35920
  left:${layout.logicalFrameLeft}px;
35800
35921
  width:${layout.logicalFrameWidth}px;
35801
35922
  height:${layout.logicalFrameHeight}px;
35802
- border-radius:${layout.logicalFrameRadius}px;
35923
+ border-radius:${(0, import_settings2.formatCornerRadii)(layout.logicalFrameRadius)};
35803
35924
  box-sizing:border-box;
35804
35925
  overflow:visible;
35805
35926
  background:${layout.frameBackground};
@@ -35808,6 +35929,7 @@ function renderFrameHtml(layout, rawImageDataUrl) {
35808
35929
  >
35809
35930
  ${buttonsHtml}
35810
35931
  ${ringHtml}
35932
+ ${housingHtml}
35811
35933
  ${legacyHomeButtonHtml}
35812
35934
  <div
35813
35935
  id="screen"
@@ -35817,7 +35939,7 @@ function renderFrameHtml(layout, rawImageDataUrl) {
35817
35939
  left:${layout.logicalScreenLeft - layout.logicalFrameLeft}px;
35818
35940
  width:${layout.logicalScreenWidth}px;
35819
35941
  height:${layout.logicalScreenHeight}px;
35820
- border-radius:${layout.logicalScreenRadius}px;
35942
+ border-radius:${(0, import_settings2.formatCornerRadii)(layout.logicalScreenRadius)};
35821
35943
  overflow:hidden;
35822
35944
  background:#000;
35823
35945
  "
@@ -37239,7 +37361,7 @@ var init_bridge_flow_runner = __esm({
37239
37361
  });
37240
37362
  const deadline = Date.now() + 3e3;
37241
37363
  while (Date.now() < deadline) {
37242
- const state = await this.evaluate(`(() => {
37364
+ const state = await this.evaluate(`(async () => {
37243
37365
  const keyboard =
37244
37366
  window.__sootsimKeyboard ??
37245
37367
  window.SootSim?.bridges?.keyboard ??
@@ -37247,7 +37369,7 @@ var init_bridge_flow_runner = __esm({
37247
37369
  const test = window.__sootsimTest
37248
37370
  return {
37249
37371
  visible: !!keyboard?.isVisible?.(),
37250
- focused: !!test?.isTextInputFocused?.(),
37372
+ focused: !!(await test?.isTextInputFocused?.()),
37251
37373
  }
37252
37374
  })()`);
37253
37375
  if (!state?.visible && !state?.focused) {
package/dist-lib/vite.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.504 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.506 | (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.504",
3
+ "version": "0.1.506",
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",
@@ -21,6 +21,7 @@ import { realpathSync } from 'node:fs'
21
21
  import { resolve } from 'node:path'
22
22
  import {
23
23
  buildLoopbackProbeBaseUrl,
24
+ isLoopbackHost,
24
25
  LOOPBACK_PROBE_HOSTNAMES,
25
26
  normalizeHostname,
26
27
  } from '../src/backend-origin.ts'
@@ -624,24 +625,35 @@ function applyManifest(
624
625
  if (launchUrl && !result.patched && !isDirectOneBundleUrl(result.bundleUrl)) {
625
626
  result.bundleUrl = withRuntimeConfig(result.port, launchUrl, result.cwd)
626
627
  }
627
- const rawIconUrl =
628
- client.iconUrl || client.ios?.iconUrl || client.icon || client.ios?.icon
629
- if (rawIconUrl) {
630
- result.iconPath = rawIconUrl
631
- if (buildIconProxyUrl) {
632
- if (rawIconUrl.startsWith('http')) {
633
- result.iconUrl = buildIconProxyUrl(rawIconUrl)
628
+ const localIcon = client.icon || client.ios?.icon
629
+ const remoteIcon = client.iconUrl || client.ios?.iconUrl
630
+ const rawIcon = localIcon || remoteIcon
631
+ if (rawIcon) {
632
+ result.iconPath = rawIcon
633
+ let resolvedIconUrl: string | undefined
634
+ if (rawIcon.startsWith('http://') || rawIcon.startsWith('https://')) {
635
+ let isLoopback = false
636
+ try {
637
+ const parsed = new URL(rawIcon)
638
+ isLoopback = isLoopbackHost(parsed.hostname)
639
+ } catch {}
640
+ if (buildIconProxyUrl) {
641
+ if (isLoopback) {
642
+ resolvedIconUrl = buildIconProxyUrl(rawIcon)
643
+ }
634
644
  } else {
635
- const cleanPath = rawIconUrl.replace(/^\.\//, '')
636
- result.iconUrl = buildIconProxyUrl(
637
- `${buildLoopbackProbeBaseUrl('http:', manifestRes.hostname, result.port)}/assets/${cleanPath}`,
638
- )
645
+ resolvedIconUrl = rawIcon
639
646
  }
640
647
  } else {
641
- // no proxy requested — use the raw URL
642
- result.iconUrl = rawIconUrl.startsWith('http')
643
- ? rawIconUrl
644
- : `${buildLoopbackProbeBaseUrl('http:', manifestRes.hostname, result.port)}/assets/${rawIconUrl.replace(/^\.\//, '')}`
648
+ const cleanPath = rawIcon.replace(/^\.?\//, '')
649
+ const assetPath = cleanPath.startsWith('assets/')
650
+ ? `/${cleanPath}`
651
+ : `/assets/${cleanPath}`
652
+ const localUrl = `${buildLoopbackProbeBaseUrl('http:', manifestRes.hostname, result.port)}${assetPath}`
653
+ resolvedIconUrl = buildIconProxyUrl ? buildIconProxyUrl(localUrl) : localUrl
654
+ }
655
+ if (resolvedIconUrl) {
656
+ result.iconUrl = resolvedIconUrl
645
657
  }
646
658
  }
647
659
  } catch {}
@@ -651,12 +663,17 @@ function applyManifest(
651
663
  export function __applyManifestForTests(
652
664
  result: DiscoveredServer,
653
665
  manifestBody: string,
666
+ buildIconProxyUrl?: (externalUrl: string) => string,
654
667
  ): DiscoveredServer {
655
- return applyManifest(result, {
656
- statusCode: 200,
657
- body: manifestBody,
658
- hostname: new URL(result.bundleUrl).hostname,
659
- })
668
+ return applyManifest(
669
+ result,
670
+ {
671
+ statusCode: 200,
672
+ body: manifestBody,
673
+ hostname: new URL(result.bundleUrl).hostname,
674
+ },
675
+ buildIconProxyUrl,
676
+ )
660
677
  }
661
678
 
662
679
  // ── name/icon enrichment ────────────────────────────────────────────────────