rnxsim 0.1.344 → 0.1.346
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 +59 -31
- package/cli/app-fonts.ts +8 -28
- package/cli/app-project.ts +12 -184
- package/cli/app-splash.ts +3 -17
- package/cli/bin.ts +15 -28
- package/cli/commands/control.ts +20 -30
- package/cli/commands/daemon.ts +19 -44
- package/cli/commands/flow.ts +0 -27
- package/cli/commands/install-desktop.ts +2 -16
- package/cli/commands/login.ts +3 -43
- package/cli/commands/logout.ts +0 -7
- package/cli/commands/serve.ts +2 -32
- package/cli/commands/setup.ts +20 -194
- package/cli/commands/telemetry.ts +7 -5
- package/cli/commands/upload.ts +1 -48
- package/cli/commands/welcome.ts +64 -0
- package/cli/outbound-endpoints.ts +586 -0
- package/cli/privacy.ts +53 -0
- package/cli/runtime-notes.ts +2 -2
- package/cli/telemetry.ts +46 -149
- package/dist-cli/bin.js +6 -6
- package/dist-cli/chunks/{agent-HTSE5FA4.js → agent-U6HZUHAQ.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-L6X2AEZL.js → agent-wrapper-IM2VL6XP.js} +2 -2
- package/dist-cli/chunks/{app-fonts-FGF3ETYH.js → app-fonts-LHVTPWCN.js} +2 -2
- package/dist-cli/chunks/{assert-HA2ZYVDN.js → assert-UMGCZXWN.js} +2 -2
- package/dist-cli/chunks/{auth-HONDAV75.js → auth-PQY57FPY.js} +2 -2
- package/dist-cli/chunks/{beta-U7EE4GMR.js → beta-3MMNRHL7.js} +2 -2
- package/dist-cli/chunks/{camera-RTKNUTIX.js → camera-UKISEHMH.js} +2 -2
- package/dist-cli/chunks/{chunk-CNLPLCO2.js → chunk-36P343FE.js} +2 -2
- package/dist-cli/chunks/{chunk-IWR4HFC4.js → chunk-3KPJVR63.js} +2 -2
- package/dist-cli/chunks/chunk-54Y5IXWQ.js +15 -0
- package/dist-cli/chunks/{chunk-EPEZZ6YS.js → chunk-5KMV7NAJ.js} +2 -2
- package/dist-cli/chunks/{chunk-NDGAF5OF.js → chunk-5WIYZI5H.js} +2 -2
- package/dist-cli/chunks/{chunk-KBSVSAAE.js → chunk-6GXUQ3DM.js} +2 -2
- package/dist-cli/chunks/{chunk-KT6WMCUS.js → chunk-6MUEKKJ4.js} +1 -1
- package/dist-cli/chunks/{chunk-TOHQI2II.js → chunk-6Q6S53R7.js} +1 -1
- package/dist-cli/chunks/{chunk-63NZGJ4A.js → chunk-6SQCDLTJ.js} +1 -1
- package/dist-cli/chunks/{chunk-Q2B6EQPB.js → chunk-6UW6O575.js} +2 -2
- package/dist-cli/chunks/chunk-6VH3UUYQ.js +4 -0
- package/dist-cli/chunks/{chunk-BGLWR43R.js → chunk-6XJGGFMD.js} +1 -1
- package/dist-cli/chunks/{chunk-TZNRKIS3.js → chunk-75LMZXF5.js} +2 -2
- package/dist-cli/chunks/{chunk-FZ5DRZJE.js → chunk-7CJNUNQA.js} +3 -3
- package/dist-cli/chunks/{chunk-UCVQOQCY.js → chunk-BQDGFR4B.js} +2 -2
- package/dist-cli/chunks/{chunk-H4J7EWZC.js → chunk-BSIVS2SQ.js} +1 -1
- package/dist-cli/chunks/{chunk-6E6SBYIO.js → chunk-CD2LITQX.js} +1 -1
- package/dist-cli/chunks/{chunk-PNMCALX5.js → chunk-DGH3D6WS.js} +2 -2
- package/dist-cli/chunks/chunk-EP6XBKPM.js +11 -0
- package/dist-cli/chunks/{chunk-OCUXAA6O.js → chunk-EVX6Y7ZM.js} +2 -2
- package/dist-cli/chunks/chunk-EYRKIWHE.js +4 -0
- package/dist-cli/chunks/{chunk-N5PFDTFL.js → chunk-FSYB2S6Q.js} +17 -17
- package/dist-cli/chunks/{chunk-6PEZSVIG.js → chunk-HPCTBEAP.js} +1 -1
- package/dist-cli/chunks/chunk-HS2BME6V.js +6 -0
- package/dist-cli/chunks/{chunk-G6IPT2PS.js → chunk-I3GUDHG2.js} +2 -2
- package/dist-cli/chunks/{chunk-MWUXQIA3.js → chunk-I4HVFKLM.js} +2 -2
- package/dist-cli/chunks/{chunk-ZPTFL5FQ.js → chunk-IBNK7SWL.js} +2 -2
- package/dist-cli/chunks/chunk-IUG4GWQC.js +25 -0
- package/dist-cli/chunks/{chunk-XQFDEY3F.js → chunk-IUIKD2YI.js} +1 -1
- package/dist-cli/chunks/{chunk-JFUVWIJT.js → chunk-JPVXLY7X.js} +1 -1
- package/dist-cli/chunks/{chunk-JLUEQPEF.js → chunk-K4PZLT2K.js} +1 -1
- package/dist-cli/chunks/{chunk-CRWYKW67.js → chunk-KNIKUJPD.js} +1 -1
- package/dist-cli/chunks/{chunk-EZLLZDYX.js → chunk-L6GWDWGZ.js} +2 -2
- package/dist-cli/chunks/chunk-LAVDDUQR.js +4 -0
- package/dist-cli/chunks/{chunk-22WJPMTQ.js → chunk-LPXKPZ4B.js} +1 -1
- package/dist-cli/chunks/{chunk-IPC45HTT.js → chunk-LYLK5VRP.js} +2 -2
- package/dist-cli/chunks/{chunk-S6LBAUWH.js → chunk-ME46FC4L.js} +1 -1
- package/dist-cli/chunks/chunk-NNXSLD76.js +99 -0
- package/dist-cli/chunks/{chunk-7V4ULF3U.js → chunk-PNH3YBZ4.js} +2 -2
- package/dist-cli/chunks/{chunk-GRX6NSBG.js → chunk-PPEJMNRO.js} +2 -2
- package/dist-cli/chunks/{chunk-K3VNCCEJ.js → chunk-SEWGXJG6.js} +3 -3
- package/dist-cli/chunks/{chunk-R3UYHE6G.js → chunk-T4JPZI32.js} +1 -1
- package/dist-cli/chunks/{chunk-NRTHFEPM.js → chunk-TAQYETRH.js} +2 -2
- package/dist-cli/chunks/{chunk-7JEEO33Y.js → chunk-TBVBWJJL.js} +2 -2
- package/dist-cli/chunks/{chunk-HRBMD2FS.js → chunk-UA54YLWR.js} +26 -26
- package/dist-cli/chunks/{chunk-G3UAFZE2.js → chunk-UV3TXNMG.js} +1 -1
- package/dist-cli/chunks/{chunk-EH35QQG4.js → chunk-VZ6YFPIN.js} +45 -45
- package/dist-cli/chunks/chunk-W54SRZ5K.js +14 -0
- package/dist-cli/chunks/chunk-WAC75WN6.js +4 -0
- package/dist-cli/chunks/{chunk-S7CSBQ6G.js → chunk-X2WIEZ7Q.js} +1 -1
- package/dist-cli/chunks/{chunk-EN32LN2B.js → chunk-XWTYFWZ3.js} +2 -2
- package/dist-cli/chunks/chunk-Y2C3CZVD.js +4 -0
- package/dist-cli/chunks/chunk-YM4L2CFB.js +4 -0
- package/dist-cli/chunks/{chunk-ZZSBCGHC.js → chunk-YXDR4CAQ.js} +1 -1
- package/dist-cli/chunks/{chunk-6NLWKL7Y.js → chunk-Z6P427WC.js} +2 -2
- package/dist-cli/chunks/{cleanup-EMYD5WZG.js → cleanup-KXPS5VSK.js} +2 -2
- package/dist-cli/chunks/cli-version-LJ6NFLBP.js +4 -0
- package/dist-cli/chunks/{compat-W2N5QTVG.js → compat-JWF7N3VO.js} +2 -2
- package/dist-cli/chunks/config-M42VJXNK.js +13 -0
- package/dist-cli/chunks/{control-4SFBROUE.js → control-HMZDIS6P.js} +2 -2
- package/dist-cli/chunks/daemon-MQ4UYKNQ.js +4 -0
- package/dist-cli/chunks/{debug-HCR2KFUA.js → debug-F44GWYMF.js} +3 -3
- package/dist-cli/chunks/{desktop-T2KS5PBJ.js → desktop-YJMWW6MW.js} +3 -3
- package/dist-cli/chunks/{detox-5S7EHINH.js → detox-5B4ASTJO.js} +2 -2
- package/dist-cli/chunks/{device-LVM3MZRJ.js → device-2544YZNY.js} +2 -2
- package/dist-cli/chunks/{diagnose-WK37XKLI.js → diagnose-LS4245JR.js} +2 -2
- package/dist-cli/chunks/{disk-cleanup-X7VJOXMS.js → disk-cleanup-XYL2HQQY.js} +2 -2
- package/dist-cli/chunks/drivers-P5CRSKH6.js +4 -0
- package/dist-cli/chunks/{film-7KLTI3ER.js → film-LS3TIZRM.js} +3 -3
- package/dist-cli/chunks/flow-7V77GXAB.js +4 -0
- package/dist-cli/chunks/help-HRESIFZX.js +4 -0
- package/dist-cli/chunks/{hidden-runtime-alias-4RVGUVFO.js → hidden-runtime-alias-HGN2EEQR.js} +2 -2
- package/dist-cli/chunks/{home-paths-5DHSAEGZ.js → home-paths-T3NTXE4U.js} +2 -2
- package/dist-cli/chunks/inspect-UC44UH4M.js +4 -0
- package/dist-cli/chunks/install-desktop-RDV66JHG.js +4 -0
- package/dist-cli/chunks/login-WVP5H5NQ.js +26 -0
- package/dist-cli/chunks/logout-GXX5OY6X.js +4 -0
- package/dist-cli/chunks/{maestro-HTRLQDJE.js → maestro-MQMGBNOB.js} +3 -3
- package/dist-cli/chunks/{maestro-generate-GX2QNA3F.js → maestro-generate-CO355QV2.js} +3 -3
- package/dist-cli/chunks/{mode-GM6KZHQP.js → mode-QFB3M2AA.js} +2 -2
- package/dist-cli/chunks/{optional-demo-registry-B4TD7JQP.js → optional-demo-registry-UIPVSBHV.js} +2 -2
- package/dist-cli/chunks/{perf-3PRXJQIC.js → perf-TDOSW3LD.js} +2 -2
- package/dist-cli/chunks/{permissions-TJZIRF2S.js → permissions-TEVQLCGJ.js} +2 -2
- package/dist-cli/chunks/privacy-DVHAMHR6.js +4 -0
- package/dist-cli/chunks/{record-LI55DTPE.js → record-OFEQLSWA.js} +3 -3
- package/dist-cli/chunks/{report-issue-TBGJVQIQ.js → report-issue-B2UPOERJ.js} +2 -2
- package/dist-cli/chunks/reset-XQQYM55B.js +4 -0
- package/dist-cli/chunks/runtime-GN6HITVB.js +4 -0
- package/dist-cli/chunks/{screenshot-command-BEN7YYIF.js → screenshot-command-NTLAY7QN.js} +3 -3
- package/dist-cli/chunks/{screenshot-layers-3IU4KYNO.js → screenshot-layers-BBLKNRQU.js} +2 -2
- package/dist-cli/chunks/{screenshots-capture-ZRC54ST6.js → screenshots-capture-6GHIRCTG.js} +2 -2
- package/dist-cli/chunks/serve-H6GJ4OHW.js +118 -0
- package/dist-cli/chunks/setup-6YLKSMWS.js +30 -0
- package/dist-cli/chunks/{skills-GKBR2HQB.js → skills-FUL7D6C7.js} +2 -2
- package/dist-cli/chunks/{state-LIHZJSL7.js → state-O2HE7XSR.js} +2 -2
- package/dist-cli/chunks/{storage-4TPN3NFB.js → storage-WIZTF7RN.js} +4 -4
- package/dist-cli/chunks/store-NJ2MBZC2.js +4 -0
- package/dist-cli/chunks/telemetry-BEC6W5WP.js +4 -0
- package/dist-cli/chunks/{timeline-EX63UNWU.js → timeline-MA4JT7UJ.js} +2 -2
- package/dist-cli/chunks/{upgrade-O6Y6EINE.js → upgrade-H5LSDXBH.js} +2 -2
- package/dist-cli/chunks/upload-Q4DWKIA4.js +4 -0
- package/dist-cli/chunks/{version-HLNL3NFB.js → version-4UWEEDVP.js} +2 -2
- package/dist-cli/chunks/{web-4EDPYPW7.js → web-F3LXRN3K.js} +2 -2
- package/dist-cli/chunks/welcome-AZBOSIG2.js +5 -0
- package/dist-cli/chunks/{what-happened-77VNUEPK.js → what-happened-6OSNLOAY.js} +2 -2
- 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 +13 -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.cjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +43 -13
- package/dist-lib/home-paths.cjs +145 -11
- package/dist-lib/host/bridge-host.cjs +326 -78
- 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 +71 -4
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +337 -37
- 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 +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +484 -14
- 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 +120 -50
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +493 -439
- package/dist-lib/vite.cjs +193 -37
- package/package.json +2 -1
- package/scripts/dev-server-scanner.ts +112 -51
- package/skills/rnx-test/SKILL.md +4 -0
- package/src/backend-origin.ts +15 -1
- package/src/dev-bundle-resolution.ts +42 -18
- package/src/dev-server-open.ts +197 -0
- package/src/home-paths.ts +168 -15
- package/src/host/bridge-host.ts +2 -2
- package/src/host/replacement-module-handler.ts +68 -2
- package/src/metro-plugin.ts +83 -5
- package/src/native-dev-bundle-url.ts +22 -0
- package/src/vite-plugin-one.ts +42 -28
- package/dist-cli/chunks/chunk-3JC7H4PR.js +0 -25
- package/dist-cli/chunks/chunk-6DLIC7BZ.js +0 -4
- package/dist-cli/chunks/chunk-7TNPO2OJ.js +0 -9
- package/dist-cli/chunks/chunk-AMF5KTOI.js +0 -4
- package/dist-cli/chunks/chunk-BX5VXTOQ.js +0 -101
- package/dist-cli/chunks/chunk-D73H7ACZ.js +0 -4
- package/dist-cli/chunks/chunk-DY4O7KYI.js +0 -4
- package/dist-cli/chunks/chunk-GU2V4JDG.js +0 -15
- package/dist-cli/chunks/chunk-POOCKX5B.js +0 -14
- package/dist-cli/chunks/chunk-Z2HMSVSN.js +0 -4
- package/dist-cli/chunks/cli-version-CN3NTKLH.js +0 -4
- package/dist-cli/chunks/config-SELKGT4F.js +0 -13
- package/dist-cli/chunks/daemon-V2SFCU2E.js +0 -4
- package/dist-cli/chunks/drivers-3YFTJ5WA.js +0 -4
- package/dist-cli/chunks/flow-36ANTMJU.js +0 -4
- package/dist-cli/chunks/help-ZGL26SPK.js +0 -4
- package/dist-cli/chunks/inspect-R3B55RTS.js +0 -4
- package/dist-cli/chunks/install-desktop-TZ3H3VWK.js +0 -4
- package/dist-cli/chunks/login-4DFULI7S.js +0 -28
- package/dist-cli/chunks/logout-QMCVYMBB.js +0 -4
- package/dist-cli/chunks/reset-O6MW6X7X.js +0 -4
- package/dist-cli/chunks/runtime-JESXBHRQ.js +0 -4
- package/dist-cli/chunks/serve-QGKTWPNF.js +0 -118
- package/dist-cli/chunks/setup-3WPWATCX.js +0 -32
- package/dist-cli/chunks/store-VBX3L46S.js +0 -4
- package/dist-cli/chunks/telemetry-ACNNIQIG.js +0 -4
- package/dist-cli/chunks/upload-OD2UQHMM.js +0 -4
package/dist-lib/vite.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.346 | (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;
|
|
@@ -37,43 +37,119 @@ __export(vite_plugin_one_exports, {
|
|
|
37
37
|
sootsimPlugin: () => sootsimPlugin
|
|
38
38
|
});
|
|
39
39
|
module.exports = __toCommonJS(vite_plugin_one_exports);
|
|
40
|
-
var import_child_process = require("child_process");
|
|
41
40
|
var import_fs2 = __toESM(require("fs"), 1);
|
|
41
|
+
var import_node_crypto2 = require("node:crypto");
|
|
42
42
|
var import_path2 = __toESM(require("path"), 1);
|
|
43
|
-
var import_url2 = require("url");
|
|
44
43
|
|
|
45
44
|
// src/bridge-constants.ts
|
|
46
45
|
var DEFAULT_SOOTSIM_BRIDGE_PORT = 7668;
|
|
47
46
|
var DEFAULT_SOOTSIM_BRIDGE_URL = `http://localhost:${DEFAULT_SOOTSIM_BRIDGE_PORT}/`;
|
|
48
47
|
|
|
49
|
-
// src/
|
|
48
|
+
// src/dev-server-open.ts
|
|
49
|
+
var import_node_child_process = require("node:child_process");
|
|
50
|
+
var import_node_crypto = require("node:crypto");
|
|
50
51
|
var import_node_fs = __toESM(require("node:fs"), 1);
|
|
51
|
-
var import_node_os = require("node:os");
|
|
52
52
|
var import_node_path = __toESM(require("node:path"), 1);
|
|
53
|
+
var import_node_url = require("node:url");
|
|
54
|
+
function resolveRnxDesktopAppName(open, projectRoot) {
|
|
55
|
+
if (!open) return null;
|
|
56
|
+
if (typeof open === "object") {
|
|
57
|
+
const appName = open.appName.trim();
|
|
58
|
+
if (!appName) throw new Error("rnx: open.appName must not be empty");
|
|
59
|
+
return appName;
|
|
60
|
+
}
|
|
61
|
+
const packageJsonPath = import_node_path.default.join(projectRoot, "package.json");
|
|
62
|
+
const packageJson = JSON.parse(import_node_fs.default.readFileSync(packageJsonPath, "utf8"));
|
|
63
|
+
const packageName = packageJson && typeof packageJson === "object" ? Reflect.get(packageJson, "name") : void 0;
|
|
64
|
+
if (typeof packageName !== "string" || !packageName.trim()) {
|
|
65
|
+
throw new Error(`rnx: ${packageJsonPath} must declare a package name`);
|
|
66
|
+
}
|
|
67
|
+
return packageName.trim();
|
|
68
|
+
}
|
|
69
|
+
function tagRnxBundleForPlugin(bundleUrl, replacementOrigin, replacementToken, projectRoot, appName) {
|
|
70
|
+
const absolute = /^[a-z][a-z\d+.-]*:\/\//i.test(bundleUrl);
|
|
71
|
+
const url = new URL(bundleUrl, absolute ? void 0 : "http://rnx.local");
|
|
72
|
+
if (appName) {
|
|
73
|
+
url.searchParams.set("rnxAppName", appName);
|
|
74
|
+
url.searchParams.set(
|
|
75
|
+
"rnxProjectId",
|
|
76
|
+
(0, import_node_crypto.createHash)("sha256").update(import_node_fs.default.realpathSync(projectRoot)).digest("hex").slice(0, 32)
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
url.searchParams.set("rnxReplacementOrigin", replacementOrigin);
|
|
80
|
+
url.searchParams.set("rnxReplacementToken", replacementToken);
|
|
81
|
+
return absolute ? url.toString() : `${url.pathname}${url.search}${url.hash}`;
|
|
82
|
+
}
|
|
83
|
+
function resolveRnxDesktopLaunchTarget(port, bundleUrl) {
|
|
84
|
+
return new URL(bundleUrl, `http://localhost:${port}`).toString();
|
|
85
|
+
}
|
|
86
|
+
function buildRnxDesktopOpenArgs(bundleUrl) {
|
|
87
|
+
return ["open", bundleUrl, "--new", "--driver", "electron", "--no-describe"];
|
|
88
|
+
}
|
|
89
|
+
function observeRnxDesktopLaunch(child, appName) {
|
|
90
|
+
let stderr = "";
|
|
91
|
+
let spawnFailed = false;
|
|
92
|
+
child.stderr?.setEncoding("utf8");
|
|
93
|
+
child.stderr?.on("data", (chunk) => {
|
|
94
|
+
stderr = `${stderr}${chunk}`.slice(-16384);
|
|
95
|
+
});
|
|
96
|
+
child.once("error", (error) => {
|
|
97
|
+
spawnFailed = true;
|
|
98
|
+
console.error(`[rnx] could not open ${appName}: ${error.message}`);
|
|
99
|
+
});
|
|
100
|
+
child.once("close", (code, signal) => {
|
|
101
|
+
if (spawnFailed) return;
|
|
102
|
+
if (code === 0) {
|
|
103
|
+
console.log(`[rnx] opened ${appName} in the desktop simulator`);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const detail = stderr.trim() || (signal ? `signal ${signal}` : `exit ${code}`);
|
|
107
|
+
console.error(`[rnx] could not open ${appName}: ${detail}`);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function launchRnxDesktop(bundleUrl, appName) {
|
|
111
|
+
const packageRoot = import_node_path.default.resolve(import_node_path.default.dirname((0, import_node_url.fileURLToPath)(__sootsim_import_meta_url)), "..");
|
|
112
|
+
const binPath = import_node_path.default.join(packageRoot, "dist-cli", "bin.js");
|
|
113
|
+
console.log(`[rnx] opening ${appName} in the desktop simulator`);
|
|
114
|
+
const child = (0, import_node_child_process.spawn)(
|
|
115
|
+
process.execPath,
|
|
116
|
+
[binPath, ...buildRnxDesktopOpenArgs(bundleUrl)],
|
|
117
|
+
{
|
|
118
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
119
|
+
windowsHide: true
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
observeRnxDesktopLaunch(child, appName);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/home-paths.ts
|
|
126
|
+
var import_node_fs2 = __toESM(require("node:fs"), 1);
|
|
127
|
+
var import_node_os = require("node:os");
|
|
128
|
+
var import_node_path2 = __toESM(require("node:path"), 1);
|
|
53
129
|
var SOOTSIM_HOME_ENV = "SOOTSIM_HOME";
|
|
54
130
|
var ACTIVE_RUNTIME_FILE = "active";
|
|
55
131
|
var DAEMON_LOCKFILE = "daemon.json";
|
|
56
132
|
var DAEMON_HEARTBEAT_STALE_MS = 3e4;
|
|
57
133
|
function sootsimHomeDir() {
|
|
58
134
|
const override = process.env[SOOTSIM_HOME_ENV];
|
|
59
|
-
if (override && override.length > 0) return
|
|
60
|
-
return
|
|
135
|
+
if (override && override.length > 0) return import_node_path2.default.resolve(override);
|
|
136
|
+
return import_node_path2.default.join((0, import_node_os.homedir)(), ".sootsim");
|
|
61
137
|
}
|
|
62
138
|
function runtimesDir() {
|
|
63
|
-
return
|
|
139
|
+
return import_node_path2.default.join(sootsimHomeDir(), "runtimes");
|
|
64
140
|
}
|
|
65
141
|
function runtimeDir(version) {
|
|
66
|
-
return
|
|
142
|
+
return import_node_path2.default.join(runtimesDir(), version);
|
|
67
143
|
}
|
|
68
144
|
function activeRuntimeFile() {
|
|
69
|
-
return
|
|
145
|
+
return import_node_path2.default.join(runtimesDir(), ACTIVE_RUNTIME_FILE);
|
|
70
146
|
}
|
|
71
147
|
function daemonLockfilePath() {
|
|
72
|
-
return
|
|
148
|
+
return import_node_path2.default.join(sootsimHomeDir(), DAEMON_LOCKFILE);
|
|
73
149
|
}
|
|
74
150
|
function readActiveRuntime() {
|
|
75
151
|
try {
|
|
76
|
-
const value =
|
|
152
|
+
const value = import_node_fs2.default.readFileSync(activeRuntimeFile(), "utf8").trim();
|
|
77
153
|
return value.length > 0 ? value : null;
|
|
78
154
|
} catch {
|
|
79
155
|
return null;
|
|
@@ -82,10 +158,10 @@ function readActiveRuntime() {
|
|
|
82
158
|
var DAEMON_LOCKFILE_MAX_BYTES = 16 * 1024;
|
|
83
159
|
function readDaemonLockfile() {
|
|
84
160
|
try {
|
|
85
|
-
const fd =
|
|
161
|
+
const fd = import_node_fs2.default.openSync(daemonLockfilePath(), "r");
|
|
86
162
|
try {
|
|
87
163
|
const buf = Buffer.alloc(DAEMON_LOCKFILE_MAX_BYTES);
|
|
88
|
-
const bytesRead =
|
|
164
|
+
const bytesRead = import_node_fs2.default.readSync(fd, buf, 0, DAEMON_LOCKFILE_MAX_BYTES, 0);
|
|
89
165
|
const raw = buf.subarray(0, bytesRead).toString("utf8");
|
|
90
166
|
const parsed = JSON.parse(raw);
|
|
91
167
|
if (parsed && parsed.schema === 1 && typeof parsed.pid === "number" && typeof parsed.bridgePort === "number" && typeof parsed.runtimePort === "number" && typeof parsed.startedAt === "number" && typeof parsed.heartbeatAt === "number" && (parsed.servedRuntimes === void 0 || Array.isArray(parsed.servedRuntimes) && parsed.servedRuntimes.every((version) => typeof version === "string"))) {
|
|
@@ -93,7 +169,7 @@ function readDaemonLockfile() {
|
|
|
93
169
|
}
|
|
94
170
|
return null;
|
|
95
171
|
} finally {
|
|
96
|
-
|
|
172
|
+
import_node_fs2.default.closeSync(fd);
|
|
97
173
|
}
|
|
98
174
|
} catch {
|
|
99
175
|
return null;
|
|
@@ -112,12 +188,23 @@ function isDaemonLockfileFresh(lock, now = Date.now()) {
|
|
|
112
188
|
|
|
113
189
|
// src/host/replacement-module-handler.ts
|
|
114
190
|
var import_promises = __toESM(require("node:fs/promises"), 1);
|
|
115
|
-
var
|
|
191
|
+
var import_node_path3 = __toESM(require("node:path"), 1);
|
|
116
192
|
var import_esbuild = require("esbuild");
|
|
193
|
+
|
|
194
|
+
// src/backend-origin.ts
|
|
195
|
+
function normalizeHostname(hostname) {
|
|
196
|
+
return hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
197
|
+
}
|
|
198
|
+
function isLoopbackHost(hostname) {
|
|
199
|
+
const normalized = normalizeHostname(hostname);
|
|
200
|
+
return normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "0.0.0.0" || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// src/host/replacement-module-handler.ts
|
|
117
204
|
var REPLACEMENT_MODULE_ROUTE = "/__sootsim-replacement-module";
|
|
118
205
|
var REPLACEMENT_RUNTIME_PREFIX = "/__sootsim-replacement-runtime";
|
|
119
206
|
function getReplacementLoader(filePath) {
|
|
120
|
-
const ext =
|
|
207
|
+
const ext = import_node_path3.default.extname(filePath).toLowerCase();
|
|
121
208
|
switch (ext) {
|
|
122
209
|
case ".js":
|
|
123
210
|
return "js";
|
|
@@ -214,9 +301,18 @@ export const Appearance = rn.Appearance
|
|
|
214
301
|
`;
|
|
215
302
|
}
|
|
216
303
|
function sendJavaScript(req, res, source) {
|
|
304
|
+
const origin = req.headers.origin;
|
|
305
|
+
let allowedOrigin;
|
|
306
|
+
if (origin) {
|
|
307
|
+
try {
|
|
308
|
+
if (isLoopbackHost(new URL(origin).hostname)) allowedOrigin = origin;
|
|
309
|
+
} catch {
|
|
310
|
+
}
|
|
311
|
+
}
|
|
217
312
|
res.writeHead(200, {
|
|
218
313
|
"Content-Type": "application/javascript; charset=utf-8",
|
|
219
|
-
"Cache-Control": "no-cache"
|
|
314
|
+
"Cache-Control": "no-cache",
|
|
315
|
+
...allowedOrigin ? { "Access-Control-Allow-Origin": allowedOrigin, Vary: "Origin" } : {}
|
|
220
316
|
});
|
|
221
317
|
res.end(req.method === "HEAD" ? void 0 : source);
|
|
222
318
|
}
|
|
@@ -228,6 +324,23 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
|
|
|
228
324
|
} catch {
|
|
229
325
|
return false;
|
|
230
326
|
}
|
|
327
|
+
if (options.requireLoopbackOrigin) {
|
|
328
|
+
const origin = req.headers.origin;
|
|
329
|
+
const remoteAddress = req.socket.remoteAddress?.replace(/^::ffff:/, "");
|
|
330
|
+
let allowed = Boolean(remoteAddress && isLoopbackHost(remoteAddress));
|
|
331
|
+
if (allowed && origin) {
|
|
332
|
+
try {
|
|
333
|
+
allowed = isLoopbackHost(new URL(origin).hostname);
|
|
334
|
+
} catch {
|
|
335
|
+
allowed = false;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
if (!allowed) {
|
|
339
|
+
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
340
|
+
res.end("replacement modules are available only to loopback origins");
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
231
344
|
if (url.pathname === `${REPLACEMENT_RUNTIME_PREFIX}/react`) {
|
|
232
345
|
sendJavaScript(req, res, reactRuntimeSource(options.reactBridgeUrl));
|
|
233
346
|
return true;
|
|
@@ -237,6 +350,11 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
|
|
|
237
350
|
return true;
|
|
238
351
|
}
|
|
239
352
|
if (url.pathname !== REPLACEMENT_MODULE_ROUTE) return false;
|
|
353
|
+
if (options.requestToken && url.searchParams.get("token") !== options.requestToken) {
|
|
354
|
+
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
355
|
+
res.end("replacement module request token is invalid");
|
|
356
|
+
return true;
|
|
357
|
+
}
|
|
240
358
|
const targetPath = url.searchParams.get("path");
|
|
241
359
|
if (!targetPath) {
|
|
242
360
|
res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
|
|
@@ -249,17 +367,42 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
|
|
|
249
367
|
res.end("replacement files must be .js, .jsx, .ts, or .tsx");
|
|
250
368
|
return true;
|
|
251
369
|
}
|
|
370
|
+
if (!import_node_path3.default.isAbsolute(targetPath)) {
|
|
371
|
+
res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
|
|
372
|
+
res.end("replacement file path must be absolute");
|
|
373
|
+
return true;
|
|
374
|
+
}
|
|
375
|
+
let resolvedProjectRoot;
|
|
376
|
+
if (options.projectRoot) {
|
|
377
|
+
const lexicalProjectRoot = import_node_path3.default.resolve(options.projectRoot);
|
|
378
|
+
resolvedProjectRoot = await import_promises.default.realpath(options.projectRoot);
|
|
379
|
+
const lexicalTarget = import_node_path3.default.relative(lexicalProjectRoot, targetPath);
|
|
380
|
+
if (lexicalTarget.startsWith("..") || import_node_path3.default.isAbsolute(lexicalTarget)) {
|
|
381
|
+
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
382
|
+
res.end("replacement file must be inside the project root");
|
|
383
|
+
return true;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
let resolvedTargetPath;
|
|
252
387
|
try {
|
|
253
|
-
await import_promises.default.
|
|
388
|
+
resolvedTargetPath = await import_promises.default.realpath(targetPath);
|
|
254
389
|
} catch (error) {
|
|
255
390
|
const message = error instanceof Error ? error.message : String(error);
|
|
256
391
|
res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
|
257
392
|
res.end(`replacement file not found: ${message}`);
|
|
258
393
|
return true;
|
|
259
394
|
}
|
|
395
|
+
if (resolvedProjectRoot) {
|
|
396
|
+
const relativeTarget = import_node_path3.default.relative(resolvedProjectRoot, resolvedTargetPath);
|
|
397
|
+
if (relativeTarget.startsWith("..") || import_node_path3.default.isAbsolute(relativeTarget)) {
|
|
398
|
+
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
399
|
+
res.end("replacement file must be inside the project root");
|
|
400
|
+
return true;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
260
403
|
try {
|
|
261
404
|
const result = await (0, import_esbuild.build)({
|
|
262
|
-
entryPoints: [
|
|
405
|
+
entryPoints: [resolvedTargetPath],
|
|
263
406
|
bundle: true,
|
|
264
407
|
write: false,
|
|
265
408
|
format: "esm",
|
|
@@ -446,11 +589,25 @@ function rnxPlugin(options = {}) {
|
|
|
446
589
|
configureServer(server) {
|
|
447
590
|
if (options.enabled === false) return;
|
|
448
591
|
const bundleUrl = options.bundleUrl || "/node_modules/one/metro-entry.bundle?platform=ios&dev=true&minify=false";
|
|
592
|
+
const appName = resolveRnxDesktopAppName(options.open, server.config.root);
|
|
593
|
+
const replacementToken = (0, import_node_crypto2.randomUUID)();
|
|
594
|
+
const configuredPort = server.config.server.port || 8081;
|
|
595
|
+
const listeningPort = () => {
|
|
596
|
+
const address = server.httpServer?.address();
|
|
597
|
+
return address && typeof address === "object" ? address.port : configuredPort;
|
|
598
|
+
};
|
|
599
|
+
const bundleForPort = (port2) => tagRnxBundleForPlugin(
|
|
600
|
+
bundleUrl,
|
|
601
|
+
`http://localhost:${port2}`,
|
|
602
|
+
replacementToken,
|
|
603
|
+
server.config.root,
|
|
604
|
+
appName
|
|
605
|
+
);
|
|
449
606
|
const buildShellHtml = (runtimeRoot) => {
|
|
450
607
|
const html = import_fs2.default.readFileSync(import_path2.default.join(runtimeRoot, "index.html"), "utf8");
|
|
451
608
|
const lock = readDaemonLockfile();
|
|
452
609
|
const bridgePort = lock && isDaemonLockfileFresh(lock) && lock.bridgePort > 0 ? lock.bridgePort : DEFAULT_SOOTSIM_BRIDGE_PORT;
|
|
453
|
-
const inject = `<script>(function(){var u=new URL(location.href);if(!u.searchParams.has('bundle'))u.searchParams.set('bundle',${JSON.stringify(
|
|
610
|
+
const inject = `<script>(function(){var u=new URL(location.href);if(!u.searchParams.has('bundle'))u.searchParams.set('bundle',${JSON.stringify(bundleForPort(listeningPort()))});window.__sootsimBridgePort=${bridgePort};history.replaceState(null,'','${prefix}/'+u.search)})()</script>`;
|
|
454
611
|
return html.replace("</head>", inject + "</head>");
|
|
455
612
|
};
|
|
456
613
|
server.middlewares.use((req, res, next) => {
|
|
@@ -471,8 +628,9 @@ function rnxPlugin(options = {}) {
|
|
|
471
628
|
});
|
|
472
629
|
server.middlewares.use((req, res, next) => {
|
|
473
630
|
if ((req.url || "").split("?")[0] !== "/__server-scan") return next();
|
|
474
|
-
const scanPort =
|
|
475
|
-
const
|
|
631
|
+
const scanPort = listeningPort();
|
|
632
|
+
const pluginBundleUrl = bundleForPort(scanPort);
|
|
633
|
+
const absoluteBundleUrl = pluginBundleUrl.startsWith("http") ? pluginBundleUrl : `http://localhost:${scanPort}${pluginBundleUrl}`;
|
|
476
634
|
res.setHeader("content-type", "application/json");
|
|
477
635
|
res.end(
|
|
478
636
|
JSON.stringify([
|
|
@@ -480,13 +638,18 @@ function rnxPlugin(options = {}) {
|
|
|
480
638
|
port: scanPort,
|
|
481
639
|
framework: "one",
|
|
482
640
|
bundleUrl: absoluteBundleUrl,
|
|
641
|
+
...appName ? { projectName: appName } : {},
|
|
483
642
|
lastSeen: Date.now()
|
|
484
643
|
}
|
|
485
644
|
])
|
|
486
645
|
);
|
|
487
646
|
});
|
|
488
647
|
server.middlewares.use((req, res, next) => {
|
|
489
|
-
void handleReplacementModuleRequest(req, res
|
|
648
|
+
void handleReplacementModuleRequest(req, res, {
|
|
649
|
+
projectRoot: server.config.root,
|
|
650
|
+
requestToken: replacementToken,
|
|
651
|
+
requireLoopbackOrigin: true
|
|
652
|
+
}).then((handled) => {
|
|
490
653
|
if (!handled) next();
|
|
491
654
|
});
|
|
492
655
|
});
|
|
@@ -533,23 +696,16 @@ function rnxPlugin(options = {}) {
|
|
|
533
696
|
}
|
|
534
697
|
next();
|
|
535
698
|
});
|
|
536
|
-
const port =
|
|
699
|
+
const port = configuredPort;
|
|
537
700
|
const sootsimUrl = `http://localhost:${port}${prefix}/`;
|
|
538
701
|
console.log(`[rnx] serving at ${sootsimUrl}`);
|
|
539
|
-
if (
|
|
702
|
+
if (appName && !process.env.CI && !process.env.SOOTSIM_NO_OPEN) {
|
|
540
703
|
server.httpServer?.once("listening", () => {
|
|
541
|
-
const
|
|
542
|
-
|
|
543
|
-
|
|
704
|
+
const openPort = listeningPort();
|
|
705
|
+
launchRnxDesktop(
|
|
706
|
+
resolveRnxDesktopLaunchTarget(openPort, bundleForPort(openPort)),
|
|
707
|
+
appName
|
|
544
708
|
);
|
|
545
|
-
const binPath = import_path2.default.join(packageRoot, "dist-cli", "bin.js");
|
|
546
|
-
const openPort = server.config.server.port || port;
|
|
547
|
-
console.log(`[rnx] opening simulator for :${openPort}`);
|
|
548
|
-
(0, import_child_process.spawn)(process.execPath, [binPath, "open", String(openPort)], {
|
|
549
|
-
detached: true,
|
|
550
|
-
stdio: "ignore",
|
|
551
|
-
windowsHide: true
|
|
552
|
-
}).unref();
|
|
553
709
|
});
|
|
554
710
|
}
|
|
555
711
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rnxsim",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.346",
|
|
4
4
|
"description": "rnx CLI, Vite and Metro plugins, and agent skills for driving React Native apps in the browser.",
|
|
5
5
|
"author": "Tamagui LLC",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -200,6 +200,7 @@
|
|
|
200
200
|
"@expo/plist": "^0.5.4",
|
|
201
201
|
"esbuild": "^0.25.0",
|
|
202
202
|
"jiti": "2.7.0",
|
|
203
|
+
"playwright-core": "1.61.0",
|
|
203
204
|
"ws": "^8.18.0"
|
|
204
205
|
},
|
|
205
206
|
"peerDependencies": {
|