rnxsim 0.1.393 → 0.1.395
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 +12 -5
- package/cli/cloud-client.ts +74 -52
- package/cli/cloud-dispatch.ts +2 -1
- package/cli/commands/inspect/core.ts +33 -2
- package/cli/commands/platform.ts +34 -9
- 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 +12 -1
- package/dist-lib/bridge-contract-input.mjs +10 -1
- package/dist-lib/bridge-contract.cjs +7 -1
- package/dist-lib/bridge-contract.mjs +5 -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 +29 -3
- package/dist-lib/cloud-contract.mjs +26 -2
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +1 -1
- 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 +25 -55
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +132 -8
- package/dist-lib/metro-production-bundle.mjs +129 -6
- package/dist-lib/metro.cjs +3 -55
- 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 +24 -3
- package/dist-lib/sdk.mjs +24 -3
- package/dist-lib/skills.cjs +28 -25
- package/dist-lib/vite.cjs +1 -1
- package/package.json +1 -1
- package/src/bridge-contract-input.ts +12 -0
- package/src/bridge-contract.ts +7 -0
- package/src/cloud-contract.ts +29 -0
- package/src/metro-plugin.ts +17 -98
- package/src/metro-production-bundle.ts +204 -3
- package/dist-lib/metro-host-modules/react-dom.js +0 -6
- package/dist-lib/metro-host-modules/react-native-web.js +0 -6
- package/dist-lib/metro-host-modules/react-native.js +0 -6
- package/dist-lib/metro-host-modules/react.js +0 -6
- package/dist-lib/metro-host-modules/react__jsx-dev-runtime.js +0 -6
- package/dist-lib/metro-host-modules/react__jsx-runtime.js +0 -6
- package/src/metro-host-modules/react-dom.js +0 -6
- package/src/metro-host-modules/react-native-web.js +0 -6
- package/src/metro-host-modules/react-native.js +0 -6
- package/src/metro-host-modules/react.js +0 -6
- package/src/metro-host-modules/react__jsx-dev-runtime.js +0 -6
- package/src/metro-host-modules/react__jsx-runtime.js +0 -6
package/dist-lib/metro.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (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;
|
|
@@ -410,7 +410,6 @@ exports.jsxDEV = exports.jsx`,
|
|
|
410
410
|
}
|
|
411
411
|
|
|
412
412
|
// src/metro-production-bundle.ts
|
|
413
|
-
var RNXSIM_METRO_PRODUCTION_BUNDLE_OPTION = "rnxsim";
|
|
414
413
|
var RNXSIM_METRO_MODULE_PATHS_PREFIX = "globalThis.__sootsimModulePaths=";
|
|
415
414
|
function toRNXProductionBundleUrl(bundleUrl) {
|
|
416
415
|
const relative = bundleUrl.startsWith("/");
|
|
@@ -418,8 +417,6 @@ function toRNXProductionBundleUrl(bundleUrl) {
|
|
|
418
417
|
url.searchParams.set("dev", "false");
|
|
419
418
|
url.searchParams.set("hot", "false");
|
|
420
419
|
url.searchParams.set("minify", "true");
|
|
421
|
-
url.searchParams.set(`resolver.${RNXSIM_METRO_PRODUCTION_BUNDLE_OPTION}`, "true");
|
|
422
|
-
url.searchParams.set(`transform.${RNXSIM_METRO_PRODUCTION_BUNDLE_OPTION}`, "true");
|
|
423
420
|
return relative ? `${url.pathname}${url.search}${url.hash}` : url.toString();
|
|
424
421
|
}
|
|
425
422
|
function createRNXMetroModulePathsFooter(modulePaths) {
|
|
@@ -606,35 +603,6 @@ function serveRuntimeFile(req, res, fullPath) {
|
|
|
606
603
|
|
|
607
604
|
// src/metro-plugin.ts
|
|
608
605
|
var prefix = "/__soot";
|
|
609
|
-
var hostModuleSpecifiers = [
|
|
610
|
-
"react",
|
|
611
|
-
"react-dom",
|
|
612
|
-
"react/jsx-runtime",
|
|
613
|
-
"react/jsx-dev-runtime",
|
|
614
|
-
"react-native",
|
|
615
|
-
"react-native-web"
|
|
616
|
-
];
|
|
617
|
-
function isRNXProductionBundle(graph) {
|
|
618
|
-
return graph.transformOptions?.dev === false && graph.transformOptions.customTransformOptions?.[RNXSIM_METRO_PRODUCTION_BUNDLE_OPTION] === "true";
|
|
619
|
-
}
|
|
620
|
-
function assertProductionEnvironment() {
|
|
621
|
-
if (process.env.NODE_ENV === "production") return;
|
|
622
|
-
throw new Error(
|
|
623
|
-
"rnxsim: production bundle requests require NODE_ENV=production; restart Metro with NODE_ENV=production"
|
|
624
|
-
);
|
|
625
|
-
}
|
|
626
|
-
function hostModuleFileName(specifier) {
|
|
627
|
-
return `${specifier.replaceAll("/", "__")}.js`;
|
|
628
|
-
}
|
|
629
|
-
function resolveHostModules() {
|
|
630
|
-
const root = import_path2.default.join(__dirname, "metro-host-modules");
|
|
631
|
-
const files = /* @__PURE__ */ new Map();
|
|
632
|
-
for (const specifier of hostModuleSpecifiers) {
|
|
633
|
-
const filePath = import_path2.default.join(root, hostModuleFileName(specifier));
|
|
634
|
-
files.set(specifier, filePath);
|
|
635
|
-
}
|
|
636
|
-
return { root, files };
|
|
637
|
-
}
|
|
638
606
|
function readCallableMetroExport(moduleValue, label) {
|
|
639
607
|
const callable = typeof moduleValue === "function" ? moduleValue : typeof moduleValue === "object" && moduleValue !== null ? Reflect.get(moduleValue, "default") : void 0;
|
|
640
608
|
if (typeof callable !== "function") {
|
|
@@ -664,7 +632,7 @@ function createMetroDefaultSerializer(projectRoot) {
|
|
|
664
632
|
return code;
|
|
665
633
|
};
|
|
666
634
|
}
|
|
667
|
-
function
|
|
635
|
+
function appendRNXModulePaths(result, graph, options, projectRoot) {
|
|
668
636
|
const dependencies = graph.dependencies;
|
|
669
637
|
const createModuleId = options.createModuleId;
|
|
670
638
|
if (!dependencies || !createModuleId) {
|
|
@@ -697,44 +665,24 @@ function withRNX(config, options = {}) {
|
|
|
697
665
|
cfgProjectRoot,
|
|
698
666
|
appName
|
|
699
667
|
);
|
|
700
|
-
const cfgResolver = config.resolver;
|
|
701
668
|
const cfgSerializer = config.serializer;
|
|
702
669
|
const existingEnhance = cfgServer?.enhanceMiddleware;
|
|
703
|
-
const existingResolveRequest = cfgResolver?.resolveRequest;
|
|
704
670
|
const existingSerializer = cfgSerializer?.customSerializer;
|
|
705
671
|
let productionConfig = {};
|
|
706
672
|
if (options.productionBundles) {
|
|
707
|
-
const hostModules = resolveHostModules();
|
|
708
673
|
let defaultSerializer;
|
|
709
674
|
productionConfig = {
|
|
710
|
-
watchFolders: [
|
|
711
|
-
...config.watchFolders || [],
|
|
712
|
-
hostModules.root
|
|
713
|
-
],
|
|
714
|
-
resolver: {
|
|
715
|
-
...cfgResolver,
|
|
716
|
-
resolveRequest: (context, moduleName, platform) => {
|
|
717
|
-
if (context.customResolverOptions?.[RNXSIM_METRO_PRODUCTION_BUNDLE_OPTION] === "true") {
|
|
718
|
-
assertProductionEnvironment();
|
|
719
|
-
const hostModule = hostModules.files.get(moduleName);
|
|
720
|
-
if (hostModule) return { type: "sourceFile", filePath: hostModule };
|
|
721
|
-
}
|
|
722
|
-
return existingResolveRequest ? existingResolveRequest(context, moduleName, platform) : context.resolveRequest(context, moduleName, platform);
|
|
723
|
-
}
|
|
724
|
-
},
|
|
725
675
|
serializer: {
|
|
726
676
|
...cfgSerializer,
|
|
727
677
|
customSerializer: async (entryPoint, preModules, graph, serializerOptions) => {
|
|
728
678
|
const serializer = existingSerializer || (defaultSerializer ||= createMetroDefaultSerializer(cfgProjectRoot));
|
|
729
|
-
const productionBundle = isRNXProductionBundle(graph);
|
|
730
|
-
if (productionBundle) assertProductionEnvironment();
|
|
731
679
|
const result = await serializer(
|
|
732
680
|
entryPoint,
|
|
733
681
|
preModules,
|
|
734
682
|
graph,
|
|
735
683
|
serializerOptions
|
|
736
684
|
);
|
|
737
|
-
return
|
|
685
|
+
return graph.transformOptions?.dev === false ? appendRNXModulePaths(result, graph, serializerOptions, cfgProjectRoot) : result;
|
|
738
686
|
}
|
|
739
687
|
}
|
|
740
688
|
};
|
package/dist-lib/profiles.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (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.395 | (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.395 | (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.395 | (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.395 | (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.395 | (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;
|
|
@@ -1402,8 +1402,9 @@ async function inspectWaitReady(bridge, timeoutMs = 2e4, options = {}) {
|
|
|
1402
1402
|
};
|
|
1403
1403
|
}
|
|
1404
1404
|
const probe = result.probe;
|
|
1405
|
+
const externalError = probe?.externalError ?? "";
|
|
1405
1406
|
const status = {
|
|
1406
|
-
ready: result.matched,
|
|
1407
|
+
ready: result.matched && !externalError,
|
|
1407
1408
|
elapsedMs: result.elapsedMs,
|
|
1408
1409
|
nodes: probe?.nodes ?? 0,
|
|
1409
1410
|
targets: probe?.targets ?? 0,
|
|
@@ -1414,7 +1415,7 @@ async function inspectWaitReady(bridge, timeoutMs = 2e4, options = {}) {
|
|
|
1414
1415
|
loadingText: probe?.loadingText ?? "",
|
|
1415
1416
|
externalReady: probe?.externalReady ?? null,
|
|
1416
1417
|
externalStatus: probe?.externalStatus ?? "",
|
|
1417
|
-
externalError
|
|
1418
|
+
externalError,
|
|
1418
1419
|
suppressedEntryError: probe?.suppressedEntryError ?? "",
|
|
1419
1420
|
errors: probe?.errors ?? 0,
|
|
1420
1421
|
bridgeError: result.error ?? ""
|
|
@@ -1783,6 +1784,26 @@ async function setDebugChannels(bridge, action, channels) {
|
|
|
1783
1784
|
});
|
|
1784
1785
|
}
|
|
1785
1786
|
async function inspectMemory(bridge) {
|
|
1787
|
+
if (bridge.plane === "cloud") {
|
|
1788
|
+
const value = await bridge.send({ type: "memory" });
|
|
1789
|
+
const rawWasmHeapBytes = typeof value === "object" && value !== null ? Reflect.get(value, "wasmHeapBytes") : null;
|
|
1790
|
+
const wasmHeapBytes = typeof rawWasmHeapBytes === "number" ? rawWasmHeapBytes : null;
|
|
1791
|
+
return {
|
|
1792
|
+
tenant: {
|
|
1793
|
+
nodesRegistered: null,
|
|
1794
|
+
nodesDetached: null,
|
|
1795
|
+
detachedTypes: null,
|
|
1796
|
+
objects: null,
|
|
1797
|
+
activeNativeAnimations: null,
|
|
1798
|
+
imageLoader: null,
|
|
1799
|
+
workerHeap: null,
|
|
1800
|
+
wasmHeapBytes
|
|
1801
|
+
},
|
|
1802
|
+
shell: null,
|
|
1803
|
+
compositor: null,
|
|
1804
|
+
hostHeap: null
|
|
1805
|
+
};
|
|
1806
|
+
}
|
|
1786
1807
|
const result = await bridge.send({
|
|
1787
1808
|
type: "evaluate",
|
|
1788
1809
|
code: `(async () => {
|
package/dist-lib/sdk.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (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);
|
|
@@ -1307,8 +1307,9 @@ async function inspectWaitReady(bridge, timeoutMs = 2e4, options = {}) {
|
|
|
1307
1307
|
};
|
|
1308
1308
|
}
|
|
1309
1309
|
const probe = result.probe;
|
|
1310
|
+
const externalError = probe?.externalError ?? "";
|
|
1310
1311
|
const status = {
|
|
1311
|
-
ready: result.matched,
|
|
1312
|
+
ready: result.matched && !externalError,
|
|
1312
1313
|
elapsedMs: result.elapsedMs,
|
|
1313
1314
|
nodes: probe?.nodes ?? 0,
|
|
1314
1315
|
targets: probe?.targets ?? 0,
|
|
@@ -1319,7 +1320,7 @@ async function inspectWaitReady(bridge, timeoutMs = 2e4, options = {}) {
|
|
|
1319
1320
|
loadingText: probe?.loadingText ?? "",
|
|
1320
1321
|
externalReady: probe?.externalReady ?? null,
|
|
1321
1322
|
externalStatus: probe?.externalStatus ?? "",
|
|
1322
|
-
externalError
|
|
1323
|
+
externalError,
|
|
1323
1324
|
suppressedEntryError: probe?.suppressedEntryError ?? "",
|
|
1324
1325
|
errors: probe?.errors ?? 0,
|
|
1325
1326
|
bridgeError: result.error ?? ""
|
|
@@ -1688,6 +1689,26 @@ async function setDebugChannels(bridge, action, channels) {
|
|
|
1688
1689
|
});
|
|
1689
1690
|
}
|
|
1690
1691
|
async function inspectMemory(bridge) {
|
|
1692
|
+
if (bridge.plane === "cloud") {
|
|
1693
|
+
const value = await bridge.send({ type: "memory" });
|
|
1694
|
+
const rawWasmHeapBytes = typeof value === "object" && value !== null ? Reflect.get(value, "wasmHeapBytes") : null;
|
|
1695
|
+
const wasmHeapBytes = typeof rawWasmHeapBytes === "number" ? rawWasmHeapBytes : null;
|
|
1696
|
+
return {
|
|
1697
|
+
tenant: {
|
|
1698
|
+
nodesRegistered: null,
|
|
1699
|
+
nodesDetached: null,
|
|
1700
|
+
detachedTypes: null,
|
|
1701
|
+
objects: null,
|
|
1702
|
+
activeNativeAnimations: null,
|
|
1703
|
+
imageLoader: null,
|
|
1704
|
+
workerHeap: null,
|
|
1705
|
+
wasmHeapBytes
|
|
1706
|
+
},
|
|
1707
|
+
shell: null,
|
|
1708
|
+
compositor: null,
|
|
1709
|
+
hostHeap: null
|
|
1710
|
+
};
|
|
1711
|
+
}
|
|
1691
1712
|
const result = await bridge.send({
|
|
1692
1713
|
type: "evaluate",
|
|
1693
1714
|
code: `(async () => {
|
package/dist-lib/skills.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (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;
|
|
@@ -21396,12 +21396,34 @@ var init_cli_constants = __esm({
|
|
|
21396
21396
|
});
|
|
21397
21397
|
|
|
21398
21398
|
// src/cloud-contract.ts
|
|
21399
|
-
|
|
21399
|
+
function isRnxCloudCommandType(value) {
|
|
21400
|
+
return RNX_CLOUD_COMMAND_TYPE_SET.has(value);
|
|
21401
|
+
}
|
|
21402
|
+
var RNX_CLOUD_MAX_ARTIFACT_BYTES, RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES, RNX_CLOUD_COMMAND_TYPES, RNX_CLOUD_COMMAND_TYPE_SET;
|
|
21400
21403
|
var init_cloud_contract = __esm({
|
|
21401
21404
|
"src/cloud-contract.ts"() {
|
|
21402
21405
|
"use strict";
|
|
21403
21406
|
RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
|
|
21404
21407
|
RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES = 1024 * 1024;
|
|
21408
|
+
RNX_CLOUD_COMMAND_TYPES = Object.freeze([
|
|
21409
|
+
"state",
|
|
21410
|
+
"query",
|
|
21411
|
+
"resolve",
|
|
21412
|
+
"perform",
|
|
21413
|
+
"waitFor",
|
|
21414
|
+
"reset",
|
|
21415
|
+
"screenshot",
|
|
21416
|
+
"capture",
|
|
21417
|
+
"captureRegions",
|
|
21418
|
+
"settle",
|
|
21419
|
+
"setAppearance",
|
|
21420
|
+
"openUrl",
|
|
21421
|
+
"tree",
|
|
21422
|
+
"tap",
|
|
21423
|
+
"longPress",
|
|
21424
|
+
"memory"
|
|
21425
|
+
]);
|
|
21426
|
+
RNX_CLOUD_COMMAND_TYPE_SET = new Set(RNX_CLOUD_COMMAND_TYPES);
|
|
21405
21427
|
}
|
|
21406
21428
|
});
|
|
21407
21429
|
|
|
@@ -21520,27 +21542,7 @@ function cloudCommand(command) {
|
|
|
21520
21542
|
for (const [key, value] of Object.entries(command)) {
|
|
21521
21543
|
if (key !== "id" && key !== "simId") clean[key] = value;
|
|
21522
21544
|
}
|
|
21523
|
-
if (command.type
|
|
21524
|
-
const query = command.query;
|
|
21525
|
-
if (!isRecord4(query) || query.kind !== "tree" && query.kind !== "find" && query.kind !== "count") {
|
|
21526
|
-
throw new Error("RNX Cloud supports only structured tree, node, and count queries");
|
|
21527
|
-
}
|
|
21528
|
-
return clean;
|
|
21529
|
-
}
|
|
21530
|
-
if (command.type === "waitFor") {
|
|
21531
|
-
const options = command.waitForOptions;
|
|
21532
|
-
const condition = isRecord4(options) ? options.condition : null;
|
|
21533
|
-
if (!isRecord4(condition) || condition.type !== "ready" && condition.type !== "present" && condition.type !== "absent") {
|
|
21534
|
-
throw new Error("RNX Cloud supports only ready and selector waits");
|
|
21535
|
-
}
|
|
21536
|
-
return clean;
|
|
21537
|
-
}
|
|
21538
|
-
if (command.type === "state") return clean;
|
|
21539
|
-
if (command.type === "capture" || command.type === "captureRegions") return clean;
|
|
21540
|
-
if (command.type === "setAppearance" || command.type === "openUrl") return clean;
|
|
21541
|
-
if (command.type === "screenshot" && command.crop === void 0 && command.captureFilter === void 0 && (command.layers === void 0 || command.layers === "tenant")) {
|
|
21542
|
-
return clean;
|
|
21543
|
-
}
|
|
21545
|
+
if (isRnxCloudCommandType(command.type)) return clean;
|
|
21544
21546
|
throw new Error(`RNX Cloud does not support bridge command type ${command.type}`);
|
|
21545
21547
|
}
|
|
21546
21548
|
function createCloudBridgeForParsed(parsed) {
|
|
@@ -23604,8 +23606,9 @@ async function inspectWaitReady(bridge, timeoutMs = 2e4, options = {}) {
|
|
|
23604
23606
|
};
|
|
23605
23607
|
}
|
|
23606
23608
|
const probe3 = result.probe;
|
|
23609
|
+
const externalError = probe3?.externalError ?? "";
|
|
23607
23610
|
const status = {
|
|
23608
|
-
ready: result.matched,
|
|
23611
|
+
ready: result.matched && !externalError,
|
|
23609
23612
|
elapsedMs: result.elapsedMs,
|
|
23610
23613
|
nodes: probe3?.nodes ?? 0,
|
|
23611
23614
|
targets: probe3?.targets ?? 0,
|
|
@@ -23616,7 +23619,7 @@ async function inspectWaitReady(bridge, timeoutMs = 2e4, options = {}) {
|
|
|
23616
23619
|
loadingText: probe3?.loadingText ?? "",
|
|
23617
23620
|
externalReady: probe3?.externalReady ?? null,
|
|
23618
23621
|
externalStatus: probe3?.externalStatus ?? "",
|
|
23619
|
-
externalError
|
|
23622
|
+
externalError,
|
|
23620
23623
|
suppressedEntryError: probe3?.suppressedEntryError ?? "",
|
|
23621
23624
|
errors: probe3?.errors ?? 0,
|
|
23622
23625
|
bridgeError: result.error ?? ""
|
package/dist-lib/vite.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.395 | (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
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// WebSocket routes) validates its request bodies here rather than growing a
|
|
4
4
|
// second reader for the same shapes.
|
|
5
5
|
|
|
6
|
+
import { SIM_LONG_PRESS_MAX_MS } from './bridge-contract'
|
|
6
7
|
import type {
|
|
7
8
|
ResetOptions,
|
|
8
9
|
SemanticWaitOptions,
|
|
@@ -130,6 +131,17 @@ export function parsePerformStep(value: unknown, index: number): SimPerformStep
|
|
|
130
131
|
}
|
|
131
132
|
case 'longPress': {
|
|
132
133
|
const durationMs = optionalNumber(step, 'durationMs', path)
|
|
134
|
+
if (
|
|
135
|
+
durationMs !== undefined &&
|
|
136
|
+
(!Number.isInteger(durationMs) ||
|
|
137
|
+
durationMs < 1 ||
|
|
138
|
+
durationMs > SIM_LONG_PRESS_MAX_MS)
|
|
139
|
+
) {
|
|
140
|
+
validationFailure(
|
|
141
|
+
`${path}.durationMs`,
|
|
142
|
+
`must be an integer between 1 and ${SIM_LONG_PRESS_MAX_MS}`,
|
|
143
|
+
)
|
|
144
|
+
}
|
|
133
145
|
return {
|
|
134
146
|
type,
|
|
135
147
|
x: numberValue(step.x, `${path}.x`),
|
package/src/bridge-contract.ts
CHANGED
|
@@ -22,6 +22,7 @@ export type BridgeCommandType =
|
|
|
22
22
|
| 'settle'
|
|
23
23
|
| 'setAppearance'
|
|
24
24
|
| 'openUrl'
|
|
25
|
+
| 'memory'
|
|
25
26
|
| 'tap'
|
|
26
27
|
| 'longPress'
|
|
27
28
|
| 'keyboard'
|
|
@@ -216,6 +217,12 @@ export interface SemanticReadyProbe {
|
|
|
216
217
|
suppressedEntryError: string
|
|
217
218
|
}
|
|
218
219
|
|
|
220
|
+
// react native's own Pressable/Touchable delayLongPress default, and the
|
|
221
|
+
// ceiling any transport accepts for a press-and-hold. a driver that holds
|
|
222
|
+
// longer than this is describing a drag, not a long press.
|
|
223
|
+
export const SIM_LONG_PRESS_DEFAULT_MS = 500
|
|
224
|
+
export const SIM_LONG_PRESS_MAX_MS = 5_000
|
|
225
|
+
|
|
219
226
|
export const SEMANTIC_READY_CONTENT_NODE_FLOOR = 100
|
|
220
227
|
export const SEMANTIC_READY_NODE_STABLE_MS = 750
|
|
221
228
|
export const SEMANTIC_READY_POLL_MS = 150
|
package/src/cloud-contract.ts
CHANGED
|
@@ -1,8 +1,37 @@
|
|
|
1
|
+
import type { BridgeCommandType } from './bridge-contract'
|
|
2
|
+
|
|
1
3
|
export const RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024
|
|
2
4
|
export const RNX_CLOUD_DESIGN_PARALLEL_JOB_LIMIT = 16
|
|
3
5
|
export const RNX_CLOUD_DESIGN_MAX_STORAGE_ENTRIES = 256
|
|
4
6
|
export const RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES = 1024 * 1024
|
|
5
7
|
|
|
8
|
+
export const RNX_CLOUD_COMMAND_TYPES = Object.freeze([
|
|
9
|
+
'state',
|
|
10
|
+
'query',
|
|
11
|
+
'resolve',
|
|
12
|
+
'perform',
|
|
13
|
+
'waitFor',
|
|
14
|
+
'reset',
|
|
15
|
+
'screenshot',
|
|
16
|
+
'capture',
|
|
17
|
+
'captureRegions',
|
|
18
|
+
'settle',
|
|
19
|
+
'setAppearance',
|
|
20
|
+
'openUrl',
|
|
21
|
+
'tree',
|
|
22
|
+
'tap',
|
|
23
|
+
'longPress',
|
|
24
|
+
'memory',
|
|
25
|
+
]) satisfies readonly BridgeCommandType[]
|
|
26
|
+
|
|
27
|
+
const RNX_CLOUD_COMMAND_TYPE_SET = new Set<string>(RNX_CLOUD_COMMAND_TYPES)
|
|
28
|
+
|
|
29
|
+
export function isRnxCloudCommandType(
|
|
30
|
+
value: string,
|
|
31
|
+
): value is (typeof RNX_CLOUD_COMMAND_TYPES)[number] {
|
|
32
|
+
return RNX_CLOUD_COMMAND_TYPE_SET.has(value)
|
|
33
|
+
}
|
|
34
|
+
|
|
6
35
|
export interface RnxCloudClaim {
|
|
7
36
|
id: string
|
|
8
37
|
expiresAt: number
|
package/src/metro-plugin.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// rnx metro plugin for opt-in dev shell and production bundle
|
|
1
|
+
// rnx metro plugin for opt-in dev shell and production bundle annotation.
|
|
2
2
|
// shell assets come from an engine runtime under ~/.rnx/runtimes/, fetched
|
|
3
3
|
// by `rnx runtime install`. ordinary localhost requests
|
|
4
4
|
// follow active; a version-owned localhost origin stays on its exact directory
|
|
@@ -24,7 +24,6 @@ import {
|
|
|
24
24
|
isReplacementModuleRequestUrl,
|
|
25
25
|
} from './host/replacement-module-handler'
|
|
26
26
|
import {
|
|
27
|
-
RNXSIM_METRO_PRODUCTION_BUNDLE_OPTION,
|
|
28
27
|
createRNXMetroModulePathsFooter,
|
|
29
28
|
toRNXProductionBundleUrl,
|
|
30
29
|
} from './metro-production-bundle'
|
|
@@ -39,37 +38,10 @@ import {
|
|
|
39
38
|
const prefix = '/__soot'
|
|
40
39
|
export { toRNXProductionBundleUrl }
|
|
41
40
|
|
|
42
|
-
const hostModuleSpecifiers = [
|
|
43
|
-
'react',
|
|
44
|
-
'react-dom',
|
|
45
|
-
'react/jsx-runtime',
|
|
46
|
-
'react/jsx-dev-runtime',
|
|
47
|
-
'react-native',
|
|
48
|
-
'react-native-web',
|
|
49
|
-
] as const
|
|
50
|
-
|
|
51
|
-
type MetroResolverContext = {
|
|
52
|
-
customResolverOptions?: Record<string, unknown>
|
|
53
|
-
resolveRequest: MetroResolver
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
type MetroResolution = {
|
|
57
|
-
type: string
|
|
58
|
-
filePath?: string
|
|
59
|
-
[key: string]: unknown
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
type MetroResolver = (
|
|
63
|
-
context: MetroResolverContext,
|
|
64
|
-
moduleName: string,
|
|
65
|
-
platform: string | null,
|
|
66
|
-
) => MetroResolution
|
|
67
|
-
|
|
68
41
|
type MetroSerializerGraph = {
|
|
69
42
|
dependencies?: ReadonlyMap<unknown, { path: string }>
|
|
70
43
|
transformOptions?: {
|
|
71
44
|
dev?: boolean
|
|
72
|
-
customTransformOptions?: Record<string, unknown>
|
|
73
45
|
}
|
|
74
46
|
}
|
|
75
47
|
|
|
@@ -92,6 +64,11 @@ export interface RNXMetroOptions {
|
|
|
92
64
|
bundleUrl?: string
|
|
93
65
|
devServer?: boolean
|
|
94
66
|
open?: RnxDesktopOpenOption
|
|
67
|
+
/**
|
|
68
|
+
* append the `moduleId -> sourcePath` identity footer to every production
|
|
69
|
+
* bundle. resolution is untouched, so the annotated artifact is the same
|
|
70
|
+
* bundle the app ships and rnx can load it directly.
|
|
71
|
+
*/
|
|
95
72
|
productionBundles?: boolean
|
|
96
73
|
}
|
|
97
74
|
|
|
@@ -99,11 +76,6 @@ export interface RNXMetroOptions {
|
|
|
99
76
|
// shape consumers pass while letting us extend `server.enhanceMiddleware`.
|
|
100
77
|
type MetroConfigWithServer = {
|
|
101
78
|
projectRoot?: string
|
|
102
|
-
watchFolders?: readonly string[]
|
|
103
|
-
resolver?: {
|
|
104
|
-
resolveRequest?: MetroResolver
|
|
105
|
-
[key: string]: unknown
|
|
106
|
-
}
|
|
107
79
|
serializer?: {
|
|
108
80
|
customSerializer?: MetroSerializer
|
|
109
81
|
[key: string]: unknown
|
|
@@ -115,38 +87,6 @@ type MetroConfigWithServer = {
|
|
|
115
87
|
}
|
|
116
88
|
}
|
|
117
89
|
|
|
118
|
-
function isRNXProductionBundle(graph: MetroSerializerGraph): boolean {
|
|
119
|
-
return (
|
|
120
|
-
graph.transformOptions?.dev === false &&
|
|
121
|
-
graph.transformOptions.customTransformOptions?.[
|
|
122
|
-
RNXSIM_METRO_PRODUCTION_BUNDLE_OPTION
|
|
123
|
-
] === 'true'
|
|
124
|
-
)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function assertProductionEnvironment(): void {
|
|
128
|
-
if (process.env.NODE_ENV === 'production') return
|
|
129
|
-
throw new Error(
|
|
130
|
-
'rnxsim: production bundle requests require NODE_ENV=production; restart Metro with NODE_ENV=production',
|
|
131
|
-
)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function hostModuleFileName(specifier: (typeof hostModuleSpecifiers)[number]): string {
|
|
135
|
-
return `${specifier.replaceAll('/', '__')}.js`
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function resolveHostModules(): { root: string; files: ReadonlyMap<string, string> } {
|
|
139
|
-
const root = path.join(__dirname, 'metro-host-modules')
|
|
140
|
-
const files = new Map<string, string>()
|
|
141
|
-
|
|
142
|
-
for (const specifier of hostModuleSpecifiers) {
|
|
143
|
-
const filePath = path.join(root, hostModuleFileName(specifier))
|
|
144
|
-
files.set(specifier, filePath)
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return { root, files }
|
|
148
|
-
}
|
|
149
|
-
|
|
150
90
|
function readCallableMetroExport(
|
|
151
91
|
moduleValue: unknown,
|
|
152
92
|
label: string,
|
|
@@ -190,7 +130,12 @@ function createMetroDefaultSerializer(projectRoot: string): MetroSerializer {
|
|
|
190
130
|
}
|
|
191
131
|
}
|
|
192
132
|
|
|
193
|
-
|
|
133
|
+
// the only thing rnx adds to a production bundle. Metro drops the fourth `__d`
|
|
134
|
+
// argument when `dev` is false, so nothing in the artifact names its modules;
|
|
135
|
+
// the engine's `__d` trap needs those names to swap react, react-native, and
|
|
136
|
+
// the native-seam packages for its own. the footer restores exactly that, and
|
|
137
|
+
// is inert everywhere else — on a device it assigns one unused global.
|
|
138
|
+
function appendRNXModulePaths(
|
|
194
139
|
result: MetroSerializerResult,
|
|
195
140
|
graph: MetroSerializerGraph,
|
|
196
141
|
options: MetroSerializerOptions,
|
|
@@ -241,42 +186,15 @@ export function withRNX<T extends Record<string, unknown>>(
|
|
|
241
186
|
cfgProjectRoot,
|
|
242
187
|
appName,
|
|
243
188
|
)
|
|
244
|
-
const cfgResolver = (config as MetroConfigWithServer).resolver
|
|
245
189
|
const cfgSerializer = (config as MetroConfigWithServer).serializer
|
|
246
190
|
const existingEnhance = cfgServer?.enhanceMiddleware
|
|
247
|
-
const existingResolveRequest = cfgResolver?.resolveRequest
|
|
248
191
|
const existingSerializer = cfgSerializer?.customSerializer
|
|
249
192
|
let productionConfig: Partial<MetroConfigWithServer> = {}
|
|
250
193
|
|
|
251
194
|
if (options.productionBundles) {
|
|
252
|
-
const hostModules = resolveHostModules()
|
|
253
195
|
let defaultSerializer: MetroSerializer | undefined
|
|
254
196
|
|
|
255
197
|
productionConfig = {
|
|
256
|
-
watchFolders: [
|
|
257
|
-
...((config as MetroConfigWithServer).watchFolders || []),
|
|
258
|
-
hostModules.root,
|
|
259
|
-
],
|
|
260
|
-
resolver: {
|
|
261
|
-
...cfgResolver,
|
|
262
|
-
resolveRequest: (
|
|
263
|
-
context: MetroResolverContext,
|
|
264
|
-
moduleName: string,
|
|
265
|
-
platform: string | null,
|
|
266
|
-
) => {
|
|
267
|
-
if (
|
|
268
|
-
context.customResolverOptions?.[RNXSIM_METRO_PRODUCTION_BUNDLE_OPTION] ===
|
|
269
|
-
'true'
|
|
270
|
-
) {
|
|
271
|
-
assertProductionEnvironment()
|
|
272
|
-
const hostModule = hostModules.files.get(moduleName)
|
|
273
|
-
if (hostModule) return { type: 'sourceFile', filePath: hostModule }
|
|
274
|
-
}
|
|
275
|
-
return existingResolveRequest
|
|
276
|
-
? existingResolveRequest(context, moduleName, platform)
|
|
277
|
-
: context.resolveRequest(context, moduleName, platform)
|
|
278
|
-
},
|
|
279
|
-
},
|
|
280
198
|
serializer: {
|
|
281
199
|
...cfgSerializer,
|
|
282
200
|
customSerializer: async (
|
|
@@ -288,16 +206,17 @@ export function withRNX<T extends Record<string, unknown>>(
|
|
|
288
206
|
const serializer =
|
|
289
207
|
existingSerializer ||
|
|
290
208
|
(defaultSerializer ||= createMetroDefaultSerializer(cfgProjectRoot))
|
|
291
|
-
const productionBundle = isRNXProductionBundle(graph)
|
|
292
|
-
if (productionBundle) assertProductionEnvironment()
|
|
293
209
|
const result = await serializer(
|
|
294
210
|
entryPoint,
|
|
295
211
|
preModules,
|
|
296
212
|
graph,
|
|
297
213
|
serializerOptions,
|
|
298
214
|
)
|
|
299
|
-
|
|
300
|
-
|
|
215
|
+
// every production build gets the footer, so the artifact the app
|
|
216
|
+
// already ships is the one rnx loads. a development build keeps
|
|
217
|
+
// Metro's fourth `__d` argument and needs nothing.
|
|
218
|
+
return graph.transformOptions?.dev === false
|
|
219
|
+
? appendRNXModulePaths(result, graph, serializerOptions, cfgProjectRoot)
|
|
301
220
|
: result
|
|
302
221
|
},
|
|
303
222
|
},
|