rnxsim 0.1.499 → 0.1.501
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/cli/bridge-flow-runner.ts +6 -2
- package/cli/cloud-client.ts +90 -7
- package/cli/cloud-dispatch.ts +27 -27
- package/cli/cloud-session.ts +61 -6
- package/cli/commands/control.ts +33 -31
- package/cli/commands/detox.ts +157 -159
- package/cli/commands/inspect/core.ts +2 -0
- package/cli/commands/platform.ts +170 -48
- package/cli/commands/preview.ts +1 -1
- package/cli/commands/test.ts +403 -95
- package/cli/main.ts +11 -0
- package/cli/outbound-endpoints.ts +10 -0
- package/cli/ws-bridge.ts +18 -19
- package/detox/jest-preset.cjs +1 -6
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/cloud-contract.cjs +7 -1
- package/dist-lib/cloud-contract.mjs +5 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +1 -1
- package/dist-lib/detox/jest-preset.cjs +1 -6
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +54 -29
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +52 -22
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +7 -8
- package/dist-lib/sdk.mjs +7 -8
- package/dist-lib/skills.cjs +128 -63
- package/dist-lib/vite.cjs +1 -1
- package/package.json +1 -1
- package/skills/rnx-test/SKILL.md +2 -2
- package/src/cloud-contract.ts +2 -0
- package/src/sim-client.ts +8 -10
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.501 | (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/metro.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.501 | (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/profiles.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.501 | (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.
|
|
1
|
+
/*! rnx v0.1.501 | (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.
|
|
1
|
+
/*! rnx v0.1.501 | (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/render-mode.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.501 | (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.
|
|
1
|
+
/*! rnx v0.1.501 | (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.
|
|
1
|
+
/*! rnx v0.1.501 | (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;
|
|
@@ -742,6 +742,7 @@ async function inspectWaitReady(bridge, timeoutMs = 2e4, options = {}) {
|
|
|
742
742
|
result = await bridge.send(
|
|
743
743
|
{
|
|
744
744
|
type: "waitFor",
|
|
745
|
+
...options.simId ? { simId: options.simId } : {},
|
|
745
746
|
waitForOptions: { condition: { type: "ready" }, timeoutMs }
|
|
746
747
|
},
|
|
747
748
|
{ timeoutMs: timeoutMs + 1e3 }
|
|
@@ -2046,21 +2047,19 @@ var SimClient = class {
|
|
|
2046
2047
|
`sim ${this.simId} reported no URL to derive the shell from`
|
|
2047
2048
|
);
|
|
2048
2049
|
}
|
|
2049
|
-
const nextUrl = buildSimOpenUrl(currentUrl, target);
|
|
2050
|
-
const
|
|
2050
|
+
const nextUrl = new URL(buildSimOpenUrl(currentUrl, target));
|
|
2051
|
+
const token = `sim-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
2052
|
+
nextUrl.searchParams.set("inspectOpen", token);
|
|
2051
2053
|
await this.send({
|
|
2052
2054
|
type: "evaluate",
|
|
2053
|
-
code: `window.location.href = ${JSON.stringify(nextUrl)}`
|
|
2055
|
+
code: `window.location.href = ${JSON.stringify(nextUrl.toString())}`
|
|
2054
2056
|
});
|
|
2055
2057
|
const deadline = Date.now() + (opts.timeoutMs ?? 3e4);
|
|
2056
2058
|
while (Date.now() < deadline) {
|
|
2057
2059
|
await sleep(250);
|
|
2058
2060
|
try {
|
|
2059
2061
|
const { url } = await inspectUrl(this);
|
|
2060
|
-
|
|
2061
|
-
if (current.pathname === expected.pathname && current.searchParams.get("open") === expected.searchParams.get("open")) {
|
|
2062
|
-
return;
|
|
2063
|
-
}
|
|
2062
|
+
if (new URL(url).searchParams.get("inspectOpen") === token) return;
|
|
2064
2063
|
} catch {
|
|
2065
2064
|
}
|
|
2066
2065
|
}
|
package/dist-lib/sdk.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.501 | (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);
|
|
@@ -646,6 +646,7 @@ async function inspectWaitReady(bridge, timeoutMs = 2e4, options = {}) {
|
|
|
646
646
|
result = await bridge.send(
|
|
647
647
|
{
|
|
648
648
|
type: "waitFor",
|
|
649
|
+
...options.simId ? { simId: options.simId } : {},
|
|
649
650
|
waitForOptions: { condition: { type: "ready" }, timeoutMs }
|
|
650
651
|
},
|
|
651
652
|
{ timeoutMs: timeoutMs + 1e3 }
|
|
@@ -1950,21 +1951,19 @@ var SimClient = class {
|
|
|
1950
1951
|
`sim ${this.simId} reported no URL to derive the shell from`
|
|
1951
1952
|
);
|
|
1952
1953
|
}
|
|
1953
|
-
const nextUrl = buildSimOpenUrl(currentUrl, target);
|
|
1954
|
-
const
|
|
1954
|
+
const nextUrl = new URL(buildSimOpenUrl(currentUrl, target));
|
|
1955
|
+
const token = `sim-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1956
|
+
nextUrl.searchParams.set("inspectOpen", token);
|
|
1955
1957
|
await this.send({
|
|
1956
1958
|
type: "evaluate",
|
|
1957
|
-
code: `window.location.href = ${JSON.stringify(nextUrl)}`
|
|
1959
|
+
code: `window.location.href = ${JSON.stringify(nextUrl.toString())}`
|
|
1958
1960
|
});
|
|
1959
1961
|
const deadline = Date.now() + (opts.timeoutMs ?? 3e4);
|
|
1960
1962
|
while (Date.now() < deadline) {
|
|
1961
1963
|
await sleep(250);
|
|
1962
1964
|
try {
|
|
1963
1965
|
const { url } = await inspectUrl(this);
|
|
1964
|
-
|
|
1965
|
-
if (current.pathname === expected.pathname && current.searchParams.get("open") === expected.searchParams.get("open")) {
|
|
1966
|
-
return;
|
|
1967
|
-
}
|
|
1966
|
+
if (new URL(url).searchParams.get("inspectOpen") === token) return;
|
|
1968
1967
|
} catch {
|
|
1969
1968
|
}
|
|
1970
1969
|
}
|
package/dist-lib/skills.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.501 | (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;
|
|
@@ -27477,7 +27477,10 @@ function createCloudSession(input) {
|
|
|
27477
27477
|
simId: input.simId.trim(),
|
|
27478
27478
|
apiOrigin: normalizeCloudOrigin(input.apiOrigin.trim()),
|
|
27479
27479
|
claimId: input.claimId.trim(),
|
|
27480
|
-
token: input.token
|
|
27480
|
+
token: input.token,
|
|
27481
|
+
...input.platform ? { platform: input.platform } : {},
|
|
27482
|
+
...input.device?.trim() ? { device: input.device.trim() } : {},
|
|
27483
|
+
...input.artifact ? { artifact: input.artifact } : {}
|
|
27481
27484
|
};
|
|
27482
27485
|
if (!session.boxId || !session.boxToken || !session.simId || !session.claimId || !session.token) {
|
|
27483
27486
|
throw new Error("cloud session requires box, simulator, origin, claim, and tokens");
|
|
@@ -27490,7 +27493,10 @@ function createCloudBoxSession(input) {
|
|
|
27490
27493
|
service: "box",
|
|
27491
27494
|
boxId: input.boxId.trim(),
|
|
27492
27495
|
boxToken: input.boxToken,
|
|
27493
|
-
apiOrigin: normalizeCloudOrigin(input.apiOrigin.trim())
|
|
27496
|
+
apiOrigin: normalizeCloudOrigin(input.apiOrigin.trim()),
|
|
27497
|
+
...input.platform ? { platform: input.platform } : {},
|
|
27498
|
+
...input.device?.trim() ? { device: input.device.trim() } : {},
|
|
27499
|
+
...input.artifact ? { artifact: input.artifact } : {}
|
|
27494
27500
|
};
|
|
27495
27501
|
if (!session.boxId || !session.boxToken) {
|
|
27496
27502
|
throw new Error("cloud box session requires a box, an origin, and a box token");
|
|
@@ -27521,9 +27527,22 @@ function parseCloudSession(encoded) {
|
|
|
27521
27527
|
if (typeof boxId !== "string" || typeof boxToken !== "string" || typeof apiOrigin !== "string") {
|
|
27522
27528
|
throw new Error(`${RNX_CLOUD_SESSION_ENV} is invalid`);
|
|
27523
27529
|
}
|
|
27530
|
+
const platform = parsed.platform === "ios" || parsed.platform === "android" ? parsed.platform : void 0;
|
|
27531
|
+
const device = typeof parsed.device === "string" ? parsed.device : void 0;
|
|
27532
|
+
const artifact = isRecord4(parsed.artifact) && typeof parsed.artifact.sha256 === "string" ? {
|
|
27533
|
+
sha256: parsed.artifact.sha256,
|
|
27534
|
+
bytes: typeof parsed.artifact.bytes === "number" ? parsed.artifact.bytes : void 0
|
|
27535
|
+
} : void 0;
|
|
27524
27536
|
try {
|
|
27525
27537
|
if (parsed.service === "box") {
|
|
27526
|
-
return createCloudBoxSession({
|
|
27538
|
+
return createCloudBoxSession({
|
|
27539
|
+
boxId,
|
|
27540
|
+
boxToken,
|
|
27541
|
+
apiOrigin,
|
|
27542
|
+
platform,
|
|
27543
|
+
device,
|
|
27544
|
+
artifact
|
|
27545
|
+
});
|
|
27527
27546
|
}
|
|
27528
27547
|
const simId = parsed.simId;
|
|
27529
27548
|
const claimId = parsed.claimId;
|
|
@@ -27531,7 +27550,17 @@ function parseCloudSession(encoded) {
|
|
|
27531
27550
|
if (parsed.service !== "sim" || typeof simId !== "string" || typeof claimId !== "string" || typeof token !== "string") {
|
|
27532
27551
|
throw new Error("unreadable cloud session");
|
|
27533
27552
|
}
|
|
27534
|
-
return createCloudSession({
|
|
27553
|
+
return createCloudSession({
|
|
27554
|
+
boxId,
|
|
27555
|
+
boxToken,
|
|
27556
|
+
simId,
|
|
27557
|
+
apiOrigin,
|
|
27558
|
+
claimId,
|
|
27559
|
+
token,
|
|
27560
|
+
platform,
|
|
27561
|
+
device,
|
|
27562
|
+
artifact
|
|
27563
|
+
});
|
|
27535
27564
|
} catch {
|
|
27536
27565
|
throw new Error(`${RNX_CLOUD_SESSION_ENV} is invalid`);
|
|
27537
27566
|
}
|
|
@@ -27555,26 +27584,6 @@ var init_cloud_session = __esm({
|
|
|
27555
27584
|
});
|
|
27556
27585
|
|
|
27557
27586
|
// cli/commands/detect.ts
|
|
27558
|
-
function findProjectRoot(cwd) {
|
|
27559
|
-
let dir = cwd;
|
|
27560
|
-
while (true) {
|
|
27561
|
-
if ((0, import_fs2.existsSync)((0, import_path2.join)(dir, "turbo.json")) || (0, import_fs2.existsSync)((0, import_path2.join)(dir, "nx.json")) || (0, import_fs2.existsSync)((0, import_path2.join)(dir, "lerna.json")) || (0, import_fs2.existsSync)((0, import_path2.join)(dir, "pnpm-workspace.yaml"))) {
|
|
27562
|
-
return dir;
|
|
27563
|
-
}
|
|
27564
|
-
const pkgPath = (0, import_path2.join)(dir, "package.json");
|
|
27565
|
-
if ((0, import_fs2.existsSync)(pkgPath)) {
|
|
27566
|
-
try {
|
|
27567
|
-
const pkg = JSON.parse((0, import_fs2.readFileSync)(pkgPath, "utf8"));
|
|
27568
|
-
if (pkg.workspaces) return dir;
|
|
27569
|
-
} catch {
|
|
27570
|
-
}
|
|
27571
|
-
}
|
|
27572
|
-
const parent = (0, import_path2.dirname)(dir);
|
|
27573
|
-
if (parent === dir) break;
|
|
27574
|
-
dir = parent;
|
|
27575
|
-
}
|
|
27576
|
-
return cwd;
|
|
27577
|
-
}
|
|
27578
27587
|
function detectFramework2(deps) {
|
|
27579
27588
|
if (deps.one) return "one";
|
|
27580
27589
|
if (deps.expo) return "expo";
|
|
@@ -27851,9 +27860,28 @@ function searchMetroAssetDest(bundlePath, descriptors) {
|
|
|
27851
27860
|
(0, import_node_path15.resolve)(bundleDirectory, "..", "assets")
|
|
27852
27861
|
];
|
|
27853
27862
|
const cwd = process.cwd();
|
|
27854
|
-
|
|
27855
|
-
|
|
27856
|
-
|
|
27863
|
+
let projectDirectory = null;
|
|
27864
|
+
for (const start of [bundleDirectory, cwd]) {
|
|
27865
|
+
let directory = (0, import_node_path15.resolve)(start);
|
|
27866
|
+
while (true) {
|
|
27867
|
+
if (detectProject(directory)?.hasMetroConfig) {
|
|
27868
|
+
projectDirectory = directory;
|
|
27869
|
+
break;
|
|
27870
|
+
}
|
|
27871
|
+
const parent = (0, import_node_path15.dirname)(directory);
|
|
27872
|
+
if (parent === directory) break;
|
|
27873
|
+
directory = parent;
|
|
27874
|
+
}
|
|
27875
|
+
if (projectDirectory) break;
|
|
27876
|
+
}
|
|
27877
|
+
if (projectDirectory) {
|
|
27878
|
+
candidates.push(
|
|
27879
|
+
(0, import_node_path15.join)(projectDirectory, "assets"),
|
|
27880
|
+
(0, import_node_path15.join)(projectDirectory, "dist"),
|
|
27881
|
+
(0, import_node_path15.join)(projectDirectory, "dist", "assets"),
|
|
27882
|
+
(0, import_node_path15.join)(projectDirectory, "build"),
|
|
27883
|
+
(0, import_node_path15.join)(projectDirectory, "build", "assets")
|
|
27884
|
+
);
|
|
27857
27885
|
}
|
|
27858
27886
|
const searched = [];
|
|
27859
27887
|
const holders = [];
|
|
@@ -28050,6 +28078,10 @@ function readCreateResponse(value, expectedBytes, expectedSha256) {
|
|
|
28050
28078
|
};
|
|
28051
28079
|
}
|
|
28052
28080
|
async function createCloudBox(options) {
|
|
28081
|
+
const platform = options.platform ?? "ios";
|
|
28082
|
+
if (platform === "android") {
|
|
28083
|
+
throw new UnsupportedRemoteHostError("android", "nano");
|
|
28084
|
+
}
|
|
28053
28085
|
const apiOrigin = resolveCloudOrigin(options.apiOrigin);
|
|
28054
28086
|
const artifact = await produceCloudArtifact(options.bundlePath);
|
|
28055
28087
|
const boxName = options.boxName?.trim();
|
|
@@ -28057,7 +28089,7 @@ async function createCloudBox(options) {
|
|
|
28057
28089
|
authorization: options.authorization,
|
|
28058
28090
|
"x-rnx-box-size": "nano",
|
|
28059
28091
|
"x-rnx-artifact-sha256": artifact.sha256,
|
|
28060
|
-
"x-rnx-platform":
|
|
28092
|
+
"x-rnx-platform": platform,
|
|
28061
28093
|
"x-rnx-device": options.device,
|
|
28062
28094
|
...options.accountId ? { "x-rnx-account-id": options.accountId } : null,
|
|
28063
28095
|
...boxName ? { "x-rnx-box-name": boxName } : null
|
|
@@ -28103,7 +28135,13 @@ async function createCloudBox(options) {
|
|
|
28103
28135
|
simId: created.receipt.simulator.simId,
|
|
28104
28136
|
apiOrigin,
|
|
28105
28137
|
claimId: created.receipt.simulator.claim.id,
|
|
28106
|
-
token: created.simulatorToken
|
|
28138
|
+
token: created.simulatorToken,
|
|
28139
|
+
platform,
|
|
28140
|
+
device: options.device,
|
|
28141
|
+
artifact: {
|
|
28142
|
+
sha256: artifact.sha256,
|
|
28143
|
+
bytes: artifact.bytes.length
|
|
28144
|
+
}
|
|
28107
28145
|
});
|
|
28108
28146
|
return {
|
|
28109
28147
|
receipt: created.receipt,
|
|
@@ -28146,7 +28184,7 @@ function createCloudBridgeForParsed(parsed) {
|
|
|
28146
28184
|
if (!session) return null;
|
|
28147
28185
|
return session.service === "box" ? new CloudBoxBridge(session) : new CloudBridge(session);
|
|
28148
28186
|
}
|
|
28149
|
-
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, CloudBoxBridge;
|
|
28187
|
+
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;
|
|
28150
28188
|
var init_cloud_client = __esm({
|
|
28151
28189
|
"cli/cloud-client.ts"() {
|
|
28152
28190
|
"use strict";
|
|
@@ -28164,9 +28202,22 @@ var init_cloud_client = __esm({
|
|
|
28164
28202
|
init_auth();
|
|
28165
28203
|
init_cloud_session();
|
|
28166
28204
|
init_detect();
|
|
28205
|
+
UnsupportedRemoteHostError = class extends Error {
|
|
28206
|
+
code = "unsupported_host";
|
|
28207
|
+
platform;
|
|
28208
|
+
host;
|
|
28209
|
+
constructor(platform, host, message) {
|
|
28210
|
+
super(
|
|
28211
|
+
message ?? `rnx remote ${platform} does not support --${host}: rnxsim/cloud only creates iOS simulators`
|
|
28212
|
+
);
|
|
28213
|
+
this.name = "UnsupportedRemoteHostError";
|
|
28214
|
+
this.platform = platform;
|
|
28215
|
+
this.host = host;
|
|
28216
|
+
}
|
|
28217
|
+
};
|
|
28167
28218
|
DEFAULT_RNX_CLOUD_ORIGIN = rnxPublicBrand.origin;
|
|
28168
28219
|
MAX_RNX_CLOUD_BUNDLE_BYTES = RNX_CLOUD_MAX_ARTIFACT_BYTES;
|
|
28169
|
-
REMOTE_COMMAND = "rnx
|
|
28220
|
+
REMOTE_COMMAND = "rnx remote";
|
|
28170
28221
|
MAX_ASSET_DEST_FILES = 25e3;
|
|
28171
28222
|
ACCOUNT_CHOICE_REFUSALS = /* @__PURE__ */ new Set([
|
|
28172
28223
|
"accountId is required",
|
|
@@ -31103,15 +31154,17 @@ function createBridge(wsPort, opts = {}) {
|
|
|
31103
31154
|
let noticedTarget = false;
|
|
31104
31155
|
const hostPidBySimId = /* @__PURE__ */ new Map();
|
|
31105
31156
|
const lineageLookupBySimId = /* @__PURE__ */ new Map();
|
|
31106
|
-
function
|
|
31157
|
+
function pickReloadedTarget(sims, retiredSimId) {
|
|
31107
31158
|
const pinnedHostPid = hostPidBySimId.get(retiredSimId);
|
|
31108
31159
|
if (pinnedHostPid === void 0) return null;
|
|
31109
|
-
const
|
|
31110
|
-
(sim) => sim.
|
|
31160
|
+
const matches = (Array.isArray(sims) ? sims : []).filter(
|
|
31161
|
+
(sim) => sim.readyState === "open" && sim.meta?.sootsimHostPid === pinnedHostPid
|
|
31111
31162
|
);
|
|
31112
|
-
|
|
31113
|
-
|
|
31114
|
-
return
|
|
31163
|
+
const restored = matches.find((sim) => sim.id === retiredSimId);
|
|
31164
|
+
if (restored) return restored.id;
|
|
31165
|
+
if (matches.length !== 1) return null;
|
|
31166
|
+
hostPidBySimId.set(matches[0].id, pinnedHostPid);
|
|
31167
|
+
return matches[0].id;
|
|
31115
31168
|
}
|
|
31116
31169
|
function maybeNoticeTarget(cmdType, simId) {
|
|
31117
31170
|
if (noticedTarget) return;
|
|
@@ -31229,7 +31282,7 @@ function createBridge(wsPort, opts = {}) {
|
|
|
31229
31282
|
const message = error instanceof Error ? error.message : String(error);
|
|
31230
31283
|
const missingSimMessage = `no sim connected with id ${sentSimId}`;
|
|
31231
31284
|
if (opts.simIdSource !== "flag" && sentSimId && cmd.simId === void 0 && (message === missingSimMessage || message.startsWith(`${missingSimMessage};`))) {
|
|
31232
|
-
const successor =
|
|
31285
|
+
const successor = pickReloadedTarget(
|
|
31233
31286
|
await sendOnce(void 0, { type: "bridge:list-sims" }),
|
|
31234
31287
|
sentSimId
|
|
31235
31288
|
);
|
|
@@ -31255,10 +31308,10 @@ function createBridge(wsPort, opts = {}) {
|
|
|
31255
31308
|
},
|
|
31256
31309
|
// a caller holding its own pinned sim id (a flow runner sets simId on every
|
|
31257
31310
|
// command, so it never reaches the pin-following path in send) asks here
|
|
31258
|
-
// after a reload retires
|
|
31259
|
-
//
|
|
31311
|
+
// after a reload retires its socket. the page can reconnect under a new id
|
|
31312
|
+
// or restore the old id; null means no unique same-host target exists.
|
|
31260
31313
|
async resolveReloadedSim(retiredSimId) {
|
|
31261
|
-
return
|
|
31314
|
+
return pickReloadedTarget(await this.listSims(), retiredSimId);
|
|
31262
31315
|
},
|
|
31263
31316
|
async focusSim(simId) {
|
|
31264
31317
|
return this.send({ type: "focus", simId });
|
|
@@ -32574,6 +32627,7 @@ async function inspectWaitReady(bridge, timeoutMs = 2e4, options = {}) {
|
|
|
32574
32627
|
result = await bridge.send(
|
|
32575
32628
|
{
|
|
32576
32629
|
type: "waitFor",
|
|
32630
|
+
...options.simId ? { simId: options.simId } : {},
|
|
32577
32631
|
waitForOptions: { condition: { type: "ready" }, timeoutMs }
|
|
32578
32632
|
},
|
|
32579
32633
|
{ timeoutMs: timeoutMs + 1e3 }
|
|
@@ -34875,11 +34929,13 @@ async function runOpenCommand(args, opts = {}) {
|
|
|
34875
34929
|
printBridgeWorldNotice(parsed.wsPort, baseUrl);
|
|
34876
34930
|
const savedSimId = readCurrentSimId();
|
|
34877
34931
|
const shouldReuseCurrentSim = !openInNewSim;
|
|
34932
|
+
const token = `cli-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
34933
|
+
const simMatchesToken = (sim) => sim.url?.includes(`inspectOpen=${token}`) ?? false;
|
|
34878
34934
|
if (shouldReuseCurrentSim) {
|
|
34879
34935
|
const bridge = createBridgeFromParsed(parsed);
|
|
34880
34936
|
const simHint = parsed.simId ? ` --sim ${parsed.simId}` : "";
|
|
34881
34937
|
let fallBackToNewSim = false;
|
|
34882
|
-
let
|
|
34938
|
+
let navigatedShellUrl = null;
|
|
34883
34939
|
try {
|
|
34884
34940
|
let targetSim = null;
|
|
34885
34941
|
let targetShellUrl = null;
|
|
@@ -34929,17 +34985,18 @@ async function runOpenCommand(args, opts = {}) {
|
|
|
34929
34985
|
}
|
|
34930
34986
|
}
|
|
34931
34987
|
if (!fallBackToNewSim && targetSim) {
|
|
34932
|
-
preNavSimIds = new Set(sims.map((sim) => sim.id));
|
|
34933
34988
|
const resolvedBaseUrl = hasExplicitBaseUrl || looksLikeSootsimUrl(target) ? baseUrl : deriveCurrentSimBaseUrl(targetSim, baseUrl);
|
|
34934
|
-
|
|
34989
|
+
navigatedShellUrl = targetShellUrl ?? await buildShellUrl(
|
|
34935
34990
|
target,
|
|
34936
34991
|
applyRNXConfigToUrl(resolvedBaseUrl, runtimeConfig),
|
|
34937
34992
|
buildShellUrlOpts
|
|
34938
34993
|
);
|
|
34994
|
+
const navigationUrl = new URL(navigatedShellUrl);
|
|
34995
|
+
navigationUrl.searchParams.set("inspectOpen", token);
|
|
34939
34996
|
bridge.send({
|
|
34940
34997
|
type: "evaluate",
|
|
34941
34998
|
simId: targetSim.id,
|
|
34942
|
-
code: `window.location.href = ${JSON.stringify(
|
|
34999
|
+
code: `window.location.href = ${JSON.stringify(navigationUrl.toString())}`
|
|
34943
35000
|
}).catch(() => {
|
|
34944
35001
|
});
|
|
34945
35002
|
}
|
|
@@ -34954,18 +35011,25 @@ async function runOpenCommand(args, opts = {}) {
|
|
|
34954
35011
|
});
|
|
34955
35012
|
rnxExit(1);
|
|
34956
35013
|
}
|
|
34957
|
-
if (!fallBackToNewSim && targetSim) {
|
|
34958
|
-
await
|
|
34959
|
-
const navSim = targetSim;
|
|
34960
|
-
const reloadedSim = await waitForSimMatch(
|
|
35014
|
+
if (!fallBackToNewSim && targetSim && navigatedShellUrl) {
|
|
35015
|
+
const navigatedSim = await waitForSimMatch(
|
|
34961
35016
|
parsed.wsPort,
|
|
34962
35017
|
parsed.commandTimeoutMs,
|
|
34963
|
-
(sim) => sim.readyState === "open" && simUsesDriver(sim, driverId) && (sim
|
|
35018
|
+
(sim) => sim.readyState === "open" && simUsesDriver(sim, driverId) && simMatchesToken(sim),
|
|
34964
35019
|
{ attempts: Math.round(30 * flowTimeoutScale()) }
|
|
34965
35020
|
);
|
|
34966
|
-
if (
|
|
34967
|
-
|
|
35021
|
+
if (!navigatedSim) {
|
|
35022
|
+
console.error(
|
|
35023
|
+
` timed out waiting for sim ${targetSim.id} to load ${navigatedShellUrl}`
|
|
35024
|
+
);
|
|
35025
|
+
await printBridgeFailureDiagnostics(bridge, {
|
|
35026
|
+
errorsCommand: `rnx get errors 5${simHint}`,
|
|
35027
|
+
warningsCommand: `rnx get warnings 5${simHint}`,
|
|
35028
|
+
requestsCommand: `rnx get requests 5${simHint}`
|
|
35029
|
+
});
|
|
35030
|
+
rnxExit(1);
|
|
34968
35031
|
}
|
|
35032
|
+
targetSim = navigatedSim;
|
|
34969
35033
|
const ready = await waitForSimReady(
|
|
34970
35034
|
parsed.wsPort,
|
|
34971
35035
|
parsed.commandTimeoutMs,
|
|
@@ -34985,13 +35049,12 @@ async function runOpenCommand(args, opts = {}) {
|
|
|
34985
35049
|
}
|
|
34986
35050
|
ready.bridge.close();
|
|
34987
35051
|
saveCurrentSimId(targetSim.id);
|
|
34988
|
-
|
|
34989
|
-
|
|
34990
|
-
|
|
34991
|
-
|
|
34992
|
-
|
|
35052
|
+
printOpenedSim(
|
|
35053
|
+
navigatedShellUrl,
|
|
35054
|
+
{ ...targetSim, url: navigatedShellUrl },
|
|
35055
|
+
"current sim",
|
|
35056
|
+
quiet
|
|
34993
35057
|
);
|
|
34994
|
-
printOpenedSim(shellUrl, { ...targetSim, url: shellUrl }, "current sim", quiet);
|
|
34995
35058
|
await maybeDescribeAfterOpen(parsed.wsPort, targetSim.id, args);
|
|
34996
35059
|
return parsed.wsPort;
|
|
34997
35060
|
}
|
|
@@ -35000,7 +35063,6 @@ async function runOpenCommand(args, opts = {}) {
|
|
|
35000
35063
|
}
|
|
35001
35064
|
}
|
|
35002
35065
|
const configuredBaseUrl = applyRNXConfigToUrl(baseUrl, runtimeConfig);
|
|
35003
|
-
const token = `cli-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
35004
35066
|
const openUrl2 = await buildOpenUrl(target, configuredBaseUrl, token, buildShellUrlOpts);
|
|
35005
35067
|
const ownerPid = getStableOwnerPid();
|
|
35006
35068
|
if (!ownerPid) {
|
|
@@ -35009,7 +35071,6 @@ async function runOpenCommand(args, opts = {}) {
|
|
|
35009
35071
|
);
|
|
35010
35072
|
rnxExit(1);
|
|
35011
35073
|
}
|
|
35012
|
-
const simMatchesToken = (sim) => sim.url?.includes(`inspectOpen=${token}`) ?? false;
|
|
35013
35074
|
const driver = getDriver(driverId);
|
|
35014
35075
|
if (!driver) {
|
|
35015
35076
|
console.error(` unknown driver "${driverId}" \u2014 run \`rnx list --drivers\``);
|
|
@@ -36562,7 +36623,9 @@ var init_bridge_flow_runner = __esm({
|
|
|
36562
36623
|
});
|
|
36563
36624
|
}
|
|
36564
36625
|
async waitForTree(timeout = DEFAULT_TIMEOUT) {
|
|
36565
|
-
let status = await inspectWaitReady(this.bridge, scaledTimeout(timeout)
|
|
36626
|
+
let status = await inspectWaitReady(this.bridge, scaledTimeout(timeout), {
|
|
36627
|
+
simId: this.opts.simId
|
|
36628
|
+
});
|
|
36566
36629
|
if (status.ready) return;
|
|
36567
36630
|
if (status.externalError) {
|
|
36568
36631
|
throw new Error(`app failed to load: ${status.externalError}`);
|
|
@@ -36584,7 +36647,9 @@ var init_bridge_flow_runner = __esm({
|
|
|
36584
36647
|
);
|
|
36585
36648
|
this.opts.simId = successor;
|
|
36586
36649
|
saveCurrentSimId(successor);
|
|
36587
|
-
status = await inspectWaitReady(this.bridge, scaledTimeout(timeout)
|
|
36650
|
+
status = await inspectWaitReady(this.bridge, scaledTimeout(timeout), {
|
|
36651
|
+
simId: this.opts.simId
|
|
36652
|
+
});
|
|
36588
36653
|
if (status.ready) return;
|
|
36589
36654
|
}
|
|
36590
36655
|
}
|
package/dist-lib/vite.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.501 | (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
package/skills/rnx-test/SKILL.md
CHANGED
|
@@ -238,7 +238,7 @@ upstream detox surface.
|
|
|
238
238
|
```js
|
|
239
239
|
// rnx-detox.config.cjs
|
|
240
240
|
module.exports = {
|
|
241
|
-
preset: 'rnxsim/detox
|
|
241
|
+
preset: 'rnxsim/detox',
|
|
242
242
|
rootDir: __dirname,
|
|
243
243
|
testMatch: ['<rootDir>/e2e/**/*.test.ts'],
|
|
244
244
|
}
|
|
@@ -294,7 +294,7 @@ rnx detox init # scaffold config + e2e/example.test.ts
|
|
|
294
294
|
- **"no rnx shell reachable"** — start one yourself
|
|
295
295
|
(`rnx open <port>`) or pass `--port <n>`.
|
|
296
296
|
- **"jest cannot find module 'detox'"** — the preset isn't wired. confirm
|
|
297
|
-
`preset: 'rnxsim/detox
|
|
297
|
+
`preset: 'rnxsim/detox'` is in the jest config jest
|
|
298
298
|
actually loaded (`--config` overrides package.json).
|
|
299
299
|
- **matchers fail on elements that exist** — canvas has no DOM. use
|
|
300
300
|
`by.id` (testID); `rnx describe` shows what the shell sees.
|
package/src/cloud-contract.ts
CHANGED
|
@@ -3,6 +3,8 @@ import type { BridgeCommandType } from './bridge-contract.ts'
|
|
|
3
3
|
export const RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024
|
|
4
4
|
export const RNX_CLOUD_DESIGN_MAX_STORAGE_ENTRIES = 256
|
|
5
5
|
export const RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES = 1024 * 1024
|
|
6
|
+
export const RNX_CLOUD_TEST_FILES_MAX_COUNT = 256
|
|
7
|
+
export const RNX_CLOUD_TEST_FILES_MAX_BYTES = 500_000
|
|
6
8
|
|
|
7
9
|
export const RNX_CLOUD_COMMAND_TYPES = Object.freeze([
|
|
8
10
|
'state',
|
package/src/sim-client.ts
CHANGED
|
@@ -310,24 +310,22 @@ export class SimClient implements WsBridge, InspectBridge {
|
|
|
310
310
|
`sim ${this.simId} reported no URL to derive the shell from`,
|
|
311
311
|
)
|
|
312
312
|
}
|
|
313
|
-
const nextUrl = buildSimOpenUrl(currentUrl, target)
|
|
314
|
-
|
|
313
|
+
const nextUrl = new URL(buildSimOpenUrl(currentUrl, target))
|
|
314
|
+
// the page being replaced keeps answering until the browser commits the
|
|
315
|
+
// navigation, and it may already sit on this target. only a one-off token
|
|
316
|
+
// in the new URL proves the reloaded page is the one answering.
|
|
317
|
+
const token = `sim-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`
|
|
318
|
+
nextUrl.searchParams.set('inspectOpen', token)
|
|
315
319
|
await this.send({
|
|
316
320
|
type: 'evaluate',
|
|
317
|
-
code: `window.location.href = ${JSON.stringify(nextUrl)}`,
|
|
321
|
+
code: `window.location.href = ${JSON.stringify(nextUrl.toString())}`,
|
|
318
322
|
})
|
|
319
323
|
const deadline = Date.now() + (opts.timeoutMs ?? 30_000)
|
|
320
324
|
while (Date.now() < deadline) {
|
|
321
325
|
await sleep(250)
|
|
322
326
|
try {
|
|
323
327
|
const { url } = await inspectUrl(this)
|
|
324
|
-
|
|
325
|
-
if (
|
|
326
|
-
current.pathname === expected.pathname &&
|
|
327
|
-
current.searchParams.get('open') === expected.searchParams.get('open')
|
|
328
|
-
) {
|
|
329
|
-
return
|
|
330
|
-
}
|
|
328
|
+
if (new URL(url).searchParams.get('inspectOpen') === token) return
|
|
331
329
|
} catch {
|
|
332
330
|
// page is mid-reload; keep polling until the deadline.
|
|
333
331
|
}
|