rnxsim 0.1.392 → 0.1.394

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/cloud-client.ts +74 -52
  2. package/cli/cloud-dispatch.ts +2 -1
  3. package/cli/commands/inspect/core.ts +33 -2
  4. package/cli/commands/platform.ts +34 -9
  5. package/detox/attempt-events.cjs +23 -0
  6. package/detox/element-types.ts +11 -2
  7. package/detox/expectations.ts +7 -3
  8. package/detox/gestures.ts +23 -2
  9. package/detox/index.ts +42 -62
  10. package/detox/navigation-lifecycle.ts +290 -0
  11. package/dist-lib/agent-daemon-client.cjs +1 -1
  12. package/dist-lib/agent-events.cjs +1 -1
  13. package/dist-lib/agent-identity.cjs +1 -1
  14. package/dist-lib/agent-sessions.cjs +1 -1
  15. package/dist-lib/attached-projects.cjs +1 -1
  16. package/dist-lib/auth/shared-session.cjs +1 -1
  17. package/dist-lib/backend-origin.cjs +1 -1
  18. package/dist-lib/beta.cjs +1 -1
  19. package/dist-lib/beta.mjs +1 -1
  20. package/dist-lib/bridge-constants.cjs +1 -1
  21. package/dist-lib/bridge-contract-input.cjs +12 -1
  22. package/dist-lib/bridge-contract-input.mjs +10 -1
  23. package/dist-lib/bridge-contract.cjs +7 -1
  24. package/dist-lib/bridge-contract.mjs +5 -1
  25. package/dist-lib/capture-contract.cjs +1 -1
  26. package/dist-lib/capture-contract.mjs +1 -1
  27. package/dist-lib/cli-constants.cjs +1 -1
  28. package/dist-lib/cloud-contract.cjs +29 -3
  29. package/dist-lib/cloud-contract.mjs +26 -2
  30. package/dist-lib/config.cjs +1 -1
  31. package/dist-lib/detox/index.cjs +240 -48
  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 +1 -1
  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 +23 -3
  41. package/dist-lib/jump-to-source-babel.cjs +1 -1
  42. package/dist-lib/menu.cjs +1 -1
  43. package/dist-lib/menu.mjs +1 -1
  44. package/dist-lib/metro-production-bundle.cjs +132 -3
  45. package/dist-lib/metro-production-bundle.mjs +129 -2
  46. package/dist-lib/metro.cjs +1 -1
  47. package/dist-lib/profiles.cjs +1 -1
  48. package/dist-lib/public-brand.cjs +1 -1
  49. package/dist-lib/react-native-host-modules.cjs +1 -1
  50. package/dist-lib/react-native-host-modules.mjs +1 -1
  51. package/dist-lib/render-mode.cjs +1 -1
  52. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  53. package/dist-lib/sdk.cjs +24 -3
  54. package/dist-lib/sdk.mjs +24 -3
  55. package/dist-lib/skills.cjs +51 -80
  56. package/dist-lib/vite.cjs +1 -1
  57. package/package.json +1 -1
  58. package/src/bridge-contract-input.ts +12 -0
  59. package/src/bridge-contract.ts +7 -0
  60. package/src/cloud-contract.ts +29 -0
  61. package/src/metro-production-bundle.ts +200 -0
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.392 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.394 | (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;
@@ -109,6 +109,33 @@ var require_motion_change = __commonJS({
109
109
  }
110
110
  });
111
111
 
112
+ // detox/attempt-events.cjs
113
+ var require_attempt_events = __commonJS({
114
+ "detox/attempt-events.cjs"(exports2, module2) {
115
+ "use strict";
116
+ var fs2 = require("node:fs");
117
+ var path2 = require("node:path");
118
+ function attemptEventsPath() {
119
+ const enabled = process.env.CONFORMANCE_PROOF === "1" || Boolean(process.env.CONFORMANCE_PROOF_DIR);
120
+ if (!enabled) return null;
121
+ const root = path2.resolve(
122
+ process.cwd(),
123
+ process.env.CONFORMANCE_PROOF_DIR || "artifacts/conformance-proof/latest"
124
+ );
125
+ return path2.join(root, "events.jsonl");
126
+ }
127
+ function writeAttemptEvent2(event) {
128
+ const output = attemptEventsPath();
129
+ if (output === null) return false;
130
+ fs2.mkdirSync(path2.dirname(output), { recursive: true });
131
+ fs2.appendFileSync(output, `${JSON.stringify(event)}
132
+ `);
133
+ return true;
134
+ }
135
+ module2.exports = { attemptEventsPath, writeAttemptEvent: writeAttemptEvent2 };
136
+ }
137
+ });
138
+
112
139
  // detox/proof-frame.cjs
113
140
  var require_proof_frame = __commonJS({
114
141
  "detox/proof-frame.cjs"(exports2, module2) {
@@ -731,6 +758,13 @@ async function pollUntil(read, ready, options) {
731
758
  }
732
759
 
733
760
  // detox/gestures.ts
761
+ function resolveScrollStartPosition(value, label) {
762
+ const normalized = value === void 0 || Number.isNaN(value) ? 0.5 : value;
763
+ if (!Number.isFinite(normalized) || normalized < 0 || normalized > 1) {
764
+ throw new Error(`${label} must be between 0 and 1`);
765
+ }
766
+ return normalized;
767
+ }
734
768
  async function waitForSootsimGestureHandler(page, viewTag, handlerName) {
735
769
  await pollUntil(
736
770
  () => page.evaluate(
@@ -902,9 +936,17 @@ async function sootsimToPage(page, sootsimX, sootsimY, timeoutMs = 5e3) {
902
936
  y: metrics.canvas.top + sootsimY * scaleY
903
937
  };
904
938
  }
905
- async function dragScrollNode(page, node, pixels, direction) {
906
- const startSootSimX = node.absolutePosition.x + node.layout.width / 2;
907
- const startSootSimY = node.absolutePosition.y + node.layout.height / 2;
939
+ async function dragScrollNode(page, node, pixels, direction, startPositionX, startPositionY) {
940
+ const normalizedStartX = resolveScrollStartPosition(
941
+ startPositionX,
942
+ "scroll startPositionX"
943
+ );
944
+ const normalizedStartY = resolveScrollStartPosition(
945
+ startPositionY,
946
+ "scroll startPositionY"
947
+ );
948
+ const startSootSimX = node.absolutePosition.x + node.layout.width * normalizedStartX;
949
+ const startSootSimY = node.absolutePosition.y + node.layout.height * normalizedStartY;
908
950
  let endSootSimX = startSootSimX;
909
951
  let endSootSimY = startSootSimY;
910
952
  switch (direction) {
@@ -1044,13 +1086,13 @@ async function dispatchTwoFingerGesture(page, startA, startB, endA, endB, option
1044
1086
 
1045
1087
  // detox/expectations.ts
1046
1088
  var DEFAULT_VISIBILITY_THRESHOLD = 0.75;
1047
- async function scrollMatcherElement(page, findNode, matcher, pixels, direction) {
1089
+ async function scrollMatcherElement(page, findNode, matcher, pixels, direction, startPositionX, startPositionY) {
1048
1090
  const node = await findNode(matcher);
1049
1091
  if (!node) {
1050
1092
  throw new Error(`scroll container not found: ${JSON.stringify(matcher)}`);
1051
1093
  }
1052
1094
  const before = scrollOffsetOf(node);
1053
- await dragScrollNode(page, node, pixels, direction);
1095
+ await dragScrollNode(page, node, pixels, direction, startPositionX, startPositionY);
1054
1096
  const after = scrollOffsetOf(await findNode(matcher));
1055
1097
  return Math.abs(after.x - before.x) + Math.abs(after.y - before.y);
1056
1098
  }
@@ -1447,7 +1489,7 @@ var SootSimWaitForScrollAction = class {
1447
1489
  // the same assertion pass on an idle machine and fail on a loaded one,
1448
1490
  // because each 200px drag is a real pointer stream and fewer of them fit in
1449
1491
  // the budget. end on scroll exhaustion, which is a property of the content.
1450
- async scroll(pixels, direction, _startPositionX, _startPositionY) {
1492
+ async scroll(pixels, direction, startPositionX, startPositionY) {
1451
1493
  const page = this.getPage();
1452
1494
  let lastError = null;
1453
1495
  let stalledSteps = 0;
@@ -1463,7 +1505,9 @@ var SootSimWaitForScrollAction = class {
1463
1505
  this.findNode,
1464
1506
  this.matcher,
1465
1507
  pixels,
1466
- direction
1508
+ direction,
1509
+ startPositionX,
1510
+ startPositionY
1467
1511
  );
1468
1512
  stalledSteps = travelled < 0.5 ? stalledSteps + 1 : 0;
1469
1513
  }
@@ -1494,71 +1538,200 @@ var by = {
1494
1538
 
1495
1539
  // detox/index.ts
1496
1540
  var import_motion_change = __toESM(require_motion_change(), 1);
1497
- var import_proof_frame = __toESM(require_proof_frame(), 1);
1498
- var BASE_URL = process.env.RNX_URL || "http://localhost:5173";
1499
- var SCREENSHOT_DIR = process.env.RNX_SCREENSHOT_DIR || path.join(process.cwd(), "test", "detox-driver", "screenshots");
1500
- var DETOX_PLATFORM = process.env.RNX_PLATFORM === "android" ? "android" : "ios";
1501
- var _browser = null;
1502
- var _reapBrowserNow = null;
1503
- var _context = null;
1504
- var _page = null;
1505
- var _synchronizationEnabled = false;
1506
- var _suspendedAppId = null;
1541
+
1542
+ // detox/navigation-lifecycle.ts
1543
+ var import_attempt_events = __toESM(require_attempt_events(), 1);
1544
+ var DIAGNOSTIC_LIMIT = 40;
1507
1545
  var pageDiagnostics = /* @__PURE__ */ new WeakMap();
1508
- var STATUS_BAR_OVERRIDE_EVENT = "sootsim:statusBarOverride";
1509
- function getPage() {
1510
- if (!_page)
1511
- throw new Error("sootsim driver not initialized -- call device.launchApp() first");
1512
- return _page;
1513
- }
1514
- function recordPageDiagnostic(page, message) {
1546
+ var activeNavigations = /* @__PURE__ */ new WeakMap();
1547
+ var lastNavigations = /* @__PURE__ */ new WeakMap();
1548
+ var nextNavigationIdentity = 0;
1549
+ function recordPageDiagnostic(page, diagnostic, persist = false) {
1515
1550
  const entries = pageDiagnostics.get(page);
1516
1551
  if (!entries) return;
1517
- entries.push(message);
1518
- if (entries.length > 40) entries.shift();
1552
+ entries.push(diagnostic);
1553
+ if (entries.length > DIAGNOSTIC_LIMIT) entries.shift();
1554
+ if (persist) (0, import_attempt_events.writeAttemptEvent)(diagnostic);
1555
+ }
1556
+ function isTopLevelDocumentRequest(page, request) {
1557
+ return request.isNavigationRequest() && request.resourceType() === "document" && request.frame() === page.mainFrame();
1558
+ }
1559
+ function recordNavigationMilestoneFor(page, active, milestone, details = {}) {
1560
+ recordPageDiagnostic(
1561
+ page,
1562
+ {
1563
+ ...active,
1564
+ ...details,
1565
+ capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
1566
+ milestone,
1567
+ target: process.env.CONFORMANCE_PROOF_TARGET || "sootsim",
1568
+ type: "rnx-navigation",
1569
+ url: details.url ?? active.navigationUrl
1570
+ },
1571
+ true
1572
+ );
1573
+ }
1574
+ function recordNavigationMilestone(page, milestone, details = {}) {
1575
+ const active = activeNavigations.get(page);
1576
+ if (active) recordNavigationMilestoneFor(page, active, milestone, details);
1519
1577
  }
1520
1578
  function attachPageDiagnostics(page) {
1521
1579
  if (pageDiagnostics.has(page)) return;
1522
1580
  pageDiagnostics.set(page, []);
1523
1581
  page.on("console", (message) => {
1524
- recordPageDiagnostic(page, `[console:${message.type()}] ${message.text()}`);
1582
+ recordPageDiagnostic(page, {
1583
+ capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
1584
+ level: message.type(),
1585
+ message: message.text(),
1586
+ type: "page-console"
1587
+ });
1525
1588
  });
1526
1589
  page.on("pageerror", (error) => {
1527
- recordPageDiagnostic(page, `[pageerror] ${error.message}`);
1590
+ recordPageDiagnostic(page, {
1591
+ capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
1592
+ message: error.message,
1593
+ type: "page-error"
1594
+ });
1595
+ });
1596
+ page.on("request", (request) => {
1597
+ if (!isTopLevelDocumentRequest(page, request)) return;
1598
+ recordNavigationMilestone(page, "document-request", {
1599
+ method: request.method(),
1600
+ url: request.url()
1601
+ });
1602
+ });
1603
+ page.on("response", (response) => {
1604
+ const request = response.request();
1605
+ if (!isTopLevelDocumentRequest(page, request)) return;
1606
+ recordNavigationMilestone(page, "document-response", {
1607
+ headersReceived: true,
1608
+ status: response.status(),
1609
+ url: request.url()
1610
+ });
1611
+ });
1612
+ page.on("requestfinished", (request) => {
1613
+ if (!isTopLevelDocumentRequest(page, request)) return;
1614
+ recordNavigationMilestone(page, "document-request-finished", { url: request.url() });
1528
1615
  });
1529
1616
  page.on("requestfailed", (request) => {
1530
1617
  const failure = request.failure();
1531
- recordPageDiagnostic(
1532
- page,
1533
- `[requestfailed] ${request.method()} ${request.url()} ${failure?.errorText ?? ""}`
1534
- );
1618
+ const errorText = failure?.errorText ?? "";
1619
+ if (isTopLevelDocumentRequest(page, request)) {
1620
+ recordNavigationMilestone(page, "document-request-failed", {
1621
+ errorText,
1622
+ url: request.url()
1623
+ });
1624
+ return;
1625
+ }
1626
+ recordPageDiagnostic(page, {
1627
+ capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
1628
+ errorText,
1629
+ method: request.method(),
1630
+ type: "subresource-request-failed",
1631
+ url: request.url()
1632
+ });
1633
+ });
1634
+ page.on("domcontentloaded", () => {
1635
+ recordNavigationMilestone(page, "domcontentloaded");
1636
+ });
1637
+ page.on("load", () => {
1638
+ recordNavigationMilestone(page, "load");
1535
1639
  });
1536
1640
  }
1537
- async function describeSootsimBridgeFailure(page, cause) {
1538
- let pageState = null;
1641
+ async function readSootsimPageState(page) {
1539
1642
  try {
1540
- pageState = await page.evaluate(() => ({
1643
+ return await page.evaluate(() => ({
1541
1644
  bodyText: document.body?.innerText?.slice(0, 500) ?? "",
1645
+ bridges: {
1646
+ sootsim: Boolean(window.SootSim),
1647
+ test: Boolean(window.__sootsimTest)
1648
+ },
1542
1649
  globals: Object.keys(window).filter((key) => key.startsWith("__sootsim") || key === "SootSim").sort(),
1543
1650
  readyState: document.readyState,
1544
1651
  title: document.title,
1545
1652
  url: window.location.href
1546
1653
  }));
1547
1654
  } catch (error) {
1548
- pageState = {
1655
+ return {
1549
1656
  evaluateError: error instanceof Error ? error.message : String(error)
1550
1657
  };
1551
1658
  }
1659
+ }
1660
+ async function describeSootsimBridgeFailure(page, cause, summary = "timed out waiting for sootsim test bridge", pageState) {
1661
+ const recordBridgeFailure = pageState === void 0;
1662
+ const state = pageState ?? await readSootsimPageState(page);
1663
+ const navigation = lastNavigations.get(page);
1664
+ if (recordBridgeFailure && navigation) {
1665
+ recordNavigationMilestoneFor(page, navigation, "error", {
1666
+ errorText: cause instanceof Error ? cause.message : String(cause),
1667
+ failurePhase: "bridge",
1668
+ pageState: state
1669
+ });
1670
+ }
1552
1671
  return new Error(
1553
1672
  [
1554
- `timed out waiting for sootsim test bridge`,
1673
+ summary,
1555
1674
  `cause: ${cause instanceof Error ? cause.message : String(cause)}`,
1556
- `page: ${JSON.stringify(pageState)}`,
1675
+ `page: ${JSON.stringify(state)}`,
1557
1676
  `recent page diagnostics:
1558
- ${(pageDiagnostics.get(page) ?? []).join("\n") || "(none)"}`
1677
+ ${JSON.stringify(getSootsimNavigationDiagnostics(page))}`
1559
1678
  ].join("\n")
1560
1679
  );
1561
1680
  }
1681
+ async function navigateSootsimPage(page, url, identity) {
1682
+ attachPageDiagnostics(page);
1683
+ const navigation = {
1684
+ ...identity,
1685
+ navigationUrl: url,
1686
+ navigationId: ++nextNavigationIdentity
1687
+ };
1688
+ activeNavigations.set(page, navigation);
1689
+ lastNavigations.set(page, navigation);
1690
+ recordNavigationMilestone(page, "start");
1691
+ try {
1692
+ return await page.goto(url, { waitUntil: "load", timeout: 3e4 });
1693
+ } catch (error) {
1694
+ const pageState = await readSootsimPageState(page);
1695
+ recordNavigationMilestone(page, "error", {
1696
+ errorText: error instanceof Error ? error.message : String(error),
1697
+ failurePhase: "navigation",
1698
+ pageState
1699
+ });
1700
+ throw await describeSootsimBridgeFailure(
1701
+ page,
1702
+ error,
1703
+ "sootsim navigation failed",
1704
+ pageState
1705
+ );
1706
+ } finally {
1707
+ activeNavigations.delete(page);
1708
+ }
1709
+ }
1710
+ function getSootsimNavigationDiagnostics(page) {
1711
+ return [...pageDiagnostics.get(page) ?? []];
1712
+ }
1713
+
1714
+ // detox/index.ts
1715
+ var import_proof_frame = __toESM(require_proof_frame(), 1);
1716
+ var BASE_URL = process.env.RNX_URL || "http://localhost:5173";
1717
+ var SCREENSHOT_DIR = process.env.RNX_SCREENSHOT_DIR || path.join(process.cwd(), "test", "detox-driver", "screenshots");
1718
+ var DETOX_PLATFORM = process.env.RNX_PLATFORM === "android" ? "android" : "ios";
1719
+ var _browser = null;
1720
+ var _reapBrowserNow = null;
1721
+ var _context = null;
1722
+ var _page = null;
1723
+ var _synchronizationEnabled = false;
1724
+ var _suspendedAppId = null;
1725
+ var browserIdentity = 0;
1726
+ var contextIdentity = 0;
1727
+ var nextBrowserIdentity = 0;
1728
+ var nextContextIdentity = 0;
1729
+ var STATUS_BAR_OVERRIDE_EVENT = "sootsim:statusBarOverride";
1730
+ function getPage() {
1731
+ if (!_page)
1732
+ throw new Error("sootsim driver not initialized -- call device.launchApp() first");
1733
+ return _page;
1734
+ }
1562
1735
  async function waitForSootsimTree(page, timeout = 3e4) {
1563
1736
  try {
1564
1737
  await page.waitForFunction(() => !!window.__sootsimTest?.waitForTree, {
@@ -1724,6 +1897,7 @@ async function closeContext() {
1724
1897
  const context = _context;
1725
1898
  _context = null;
1726
1899
  _page = null;
1900
+ contextIdentity = 0;
1727
1901
  _synchronizationEnabled = false;
1728
1902
  if (context) await context.close();
1729
1903
  }
@@ -1733,6 +1907,7 @@ async function closeBrowser() {
1733
1907
  const reapBrowserNow = _reapBrowserNow;
1734
1908
  _browser = null;
1735
1909
  _reapBrowserNow = null;
1910
+ browserIdentity = 0;
1736
1911
  await closeContext();
1737
1912
  try {
1738
1913
  await browser.close();
@@ -2185,14 +2360,14 @@ function createSootSimElement(matcher) {
2185
2360
  await page.keyboard.press("Backspace");
2186
2361
  }
2187
2362
  },
2188
- async scroll(pixels, direction) {
2363
+ async scroll(pixels, direction, startPositionX, startPositionY) {
2189
2364
  const node = await findNodeByMatcher(matcher);
2190
2365
  if (!node)
2191
2366
  throw new Error(`element not found for scroll: ${JSON.stringify(matcher)}`);
2192
2367
  const page = getPage();
2193
- await dragScrollNode(page, node, pixels, direction);
2368
+ await dragScrollNode(page, node, pixels, direction, startPositionX, startPositionY);
2194
2369
  },
2195
- async scrollTo(edge) {
2370
+ async scrollTo(edge, startPositionX, startPositionY) {
2196
2371
  const node = await findNodeByMatcher(matcher);
2197
2372
  if (!node)
2198
2373
  throw new Error(`element not found for scrollTo: ${JSON.stringify(matcher)}`);
@@ -2202,8 +2377,16 @@ function createSootSimElement(matcher) {
2202
2377
  `scrollTo requires an id-backed scroll view: ${JSON.stringify(matcher)}`
2203
2378
  );
2204
2379
  }
2205
- const hitX = node.absolutePosition.x + node.layout.width / 2;
2206
- const hitY = node.absolutePosition.y + node.layout.height / 2;
2380
+ const normalizedStartX = resolveScrollStartPosition(
2381
+ startPositionX,
2382
+ "scrollTo startPositionX"
2383
+ );
2384
+ const normalizedStartY = resolveScrollStartPosition(
2385
+ startPositionY,
2386
+ "scrollTo startPositionY"
2387
+ );
2388
+ const hitX = node.absolutePosition.x + node.layout.width * normalizedStartX;
2389
+ const hitY = node.absolutePosition.y + node.layout.height * normalizedStartY;
2207
2390
  const page = getPage();
2208
2391
  const result = await page.evaluate(
2209
2392
  async ({ edge: edge2, hitX: hitX2, hitY: hitY2, targetId: targetId2 }) => {
@@ -2473,6 +2656,7 @@ var device = {
2473
2656
  );
2474
2657
  _browser = launched.browser;
2475
2658
  _reapBrowserNow = launched.reapNow;
2659
+ browserIdentity = ++nextBrowserIdentity;
2476
2660
  }
2477
2661
  if (!_page || opts?.newInstance || opts?.delete || opts?.recordVideoDir) {
2478
2662
  await closeContext();
@@ -2489,11 +2673,15 @@ var device = {
2489
2673
  }
2490
2674
  _context = await _browser.newContext(contextOpts);
2491
2675
  _page = await _context.newPage();
2492
- attachPageDiagnostics(_page);
2676
+ contextIdentity = ++nextContextIdentity;
2493
2677
  }
2494
2678
  const url = opts?.url || BASE_URL;
2495
2679
  device._currentUrl = url;
2496
- await _page.goto(url, { waitUntil: "load", timeout: 3e4 });
2680
+ await navigateSootsimPage(_page, url, {
2681
+ browserId: browserIdentity,
2682
+ contextId: contextIdentity,
2683
+ operation: "launchApp"
2684
+ });
2497
2685
  await waitForSootsimTree(_page, 3e4);
2498
2686
  await waitForSootsimSurfaceMetrics(_page, 3e4);
2499
2687
  await waitForSootsimShellReady(_page, 3e4);
@@ -2518,7 +2706,11 @@ var device = {
2518
2706
  },
2519
2707
  async openURL(url) {
2520
2708
  const page = getPage();
2521
- await page.goto(url.url, { waitUntil: "load", timeout: 3e4 });
2709
+ await navigateSootsimPage(page, url.url, {
2710
+ browserId: browserIdentity,
2711
+ contextId: contextIdentity,
2712
+ operation: "openURL"
2713
+ });
2522
2714
  await waitForSootsimTree(page, 1e4);
2523
2715
  await waitForSootsimSurfaceMetrics(page, 1e4);
2524
2716
  await waitForSootsimShellReady(page, 1e4);
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.392 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.394 | (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.392 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.394 | (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.392 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.394 | (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.392 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.394 | (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.392 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.394 | (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.392 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.394 | (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.392 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.394 | (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.392 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.394 | (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.392 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.394 | (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;
@@ -506,6 +506,25 @@ function isDevBridgeLockfileFresh(lock, now = Date.now()) {
506
506
  // src/cloud-contract.ts
507
507
  var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
508
508
  var RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES = 1024 * 1024;
509
+ var RNX_CLOUD_COMMAND_TYPES = Object.freeze([
510
+ "state",
511
+ "query",
512
+ "resolve",
513
+ "perform",
514
+ "waitFor",
515
+ "reset",
516
+ "screenshot",
517
+ "capture",
518
+ "captureRegions",
519
+ "settle",
520
+ "setAppearance",
521
+ "openUrl",
522
+ "tree",
523
+ "tap",
524
+ "longPress",
525
+ "memory"
526
+ ]);
527
+ var RNX_CLOUD_COMMAND_TYPE_SET = new Set(RNX_CLOUD_COMMAND_TYPES);
509
528
 
510
529
  // src/public-brand.ts
511
530
  var name = "rnx";
@@ -1934,8 +1953,9 @@ async function inspectWaitReady(bridge, timeoutMs = 2e4, options = {}) {
1934
1953
  };
1935
1954
  }
1936
1955
  const probe = result.probe;
1956
+ const externalError = probe?.externalError ?? "";
1937
1957
  const status = {
1938
- ready: result.matched,
1958
+ ready: result.matched && !externalError,
1939
1959
  elapsedMs: result.elapsedMs,
1940
1960
  nodes: probe?.nodes ?? 0,
1941
1961
  targets: probe?.targets ?? 0,
@@ -1946,7 +1966,7 @@ async function inspectWaitReady(bridge, timeoutMs = 2e4, options = {}) {
1946
1966
  loadingText: probe?.loadingText ?? "",
1947
1967
  externalReady: probe?.externalReady ?? null,
1948
1968
  externalStatus: probe?.externalStatus ?? "",
1949
- externalError: probe?.externalError ?? "",
1969
+ externalError,
1950
1970
  suppressedEntryError: probe?.suppressedEntryError ?? "",
1951
1971
  errors: probe?.errors ?? 0,
1952
1972
  bridgeError: result.error ?? ""
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.392 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.394 | (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.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.392 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.394 | (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.392 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.394 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/public-brand.ts
4
4
  var name = "rnx";