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/metro.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;
|
|
@@ -39,8 +39,421 @@ __export(metro_plugin_exports, {
|
|
|
39
39
|
module.exports = __toCommonJS(metro_plugin_exports);
|
|
40
40
|
var import_fs2 = __toESM(require("fs"), 1);
|
|
41
41
|
var import_module = require("module");
|
|
42
|
+
var import_node_crypto2 = require("node:crypto");
|
|
42
43
|
var import_path2 = __toESM(require("path"), 1);
|
|
43
44
|
|
|
45
|
+
// src/dev-server-open.ts
|
|
46
|
+
var import_node_child_process = require("node:child_process");
|
|
47
|
+
var import_node_crypto = require("node:crypto");
|
|
48
|
+
var import_node_fs = __toESM(require("node:fs"), 1);
|
|
49
|
+
var import_node_http = __toESM(require("node:http"), 1);
|
|
50
|
+
var import_node_path = __toESM(require("node:path"), 1);
|
|
51
|
+
var import_node_url = require("node:url");
|
|
52
|
+
var scheduledMetroOpens = /* @__PURE__ */ new Set();
|
|
53
|
+
function resolveRnxDesktopAppName(open, projectRoot) {
|
|
54
|
+
if (!open) return null;
|
|
55
|
+
if (typeof open === "object") {
|
|
56
|
+
const appName = open.appName.trim();
|
|
57
|
+
if (!appName) throw new Error("rnx: open.appName must not be empty");
|
|
58
|
+
return appName;
|
|
59
|
+
}
|
|
60
|
+
const packageJsonPath = import_node_path.default.join(projectRoot, "package.json");
|
|
61
|
+
const packageJson = JSON.parse(import_node_fs.default.readFileSync(packageJsonPath, "utf8"));
|
|
62
|
+
const packageName = packageJson && typeof packageJson === "object" ? Reflect.get(packageJson, "name") : void 0;
|
|
63
|
+
if (typeof packageName !== "string" || !packageName.trim()) {
|
|
64
|
+
throw new Error(`rnx: ${packageJsonPath} must declare a package name`);
|
|
65
|
+
}
|
|
66
|
+
return packageName.trim();
|
|
67
|
+
}
|
|
68
|
+
function tagRnxBundleForPlugin(bundleUrl, replacementOrigin, replacementToken, projectRoot, appName) {
|
|
69
|
+
const absolute = /^[a-z][a-z\d+.-]*:\/\//i.test(bundleUrl);
|
|
70
|
+
const url = new URL(bundleUrl, absolute ? void 0 : "http://rnx.local");
|
|
71
|
+
if (appName) {
|
|
72
|
+
url.searchParams.set("rnxAppName", appName);
|
|
73
|
+
url.searchParams.set(
|
|
74
|
+
"rnxProjectId",
|
|
75
|
+
(0, import_node_crypto.createHash)("sha256").update(import_node_fs.default.realpathSync(projectRoot)).digest("hex").slice(0, 32)
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
url.searchParams.set("rnxReplacementOrigin", replacementOrigin);
|
|
79
|
+
url.searchParams.set("rnxReplacementToken", replacementToken);
|
|
80
|
+
return absolute ? url.toString() : `${url.pathname}${url.search}${url.hash}`;
|
|
81
|
+
}
|
|
82
|
+
function resolveRnxDesktopLaunchTarget(port, bundleUrl) {
|
|
83
|
+
return new URL(bundleUrl, `http://localhost:${port}`).toString();
|
|
84
|
+
}
|
|
85
|
+
function buildRnxDesktopOpenArgs(bundleUrl) {
|
|
86
|
+
return ["open", bundleUrl, "--new", "--driver", "electron", "--no-describe"];
|
|
87
|
+
}
|
|
88
|
+
function observeRnxDesktopLaunch(child, appName) {
|
|
89
|
+
let stderr = "";
|
|
90
|
+
let spawnFailed = false;
|
|
91
|
+
child.stderr?.setEncoding("utf8");
|
|
92
|
+
child.stderr?.on("data", (chunk) => {
|
|
93
|
+
stderr = `${stderr}${chunk}`.slice(-16384);
|
|
94
|
+
});
|
|
95
|
+
child.once("error", (error) => {
|
|
96
|
+
spawnFailed = true;
|
|
97
|
+
console.error(`[rnx] could not open ${appName}: ${error.message}`);
|
|
98
|
+
});
|
|
99
|
+
child.once("close", (code, signal) => {
|
|
100
|
+
if (spawnFailed) return;
|
|
101
|
+
if (code === 0) {
|
|
102
|
+
console.log(`[rnx] opened ${appName} in the desktop simulator`);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const detail = stderr.trim() || (signal ? `signal ${signal}` : `exit ${code}`);
|
|
106
|
+
console.error(`[rnx] could not open ${appName}: ${detail}`);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
function launchRnxDesktop(bundleUrl, appName) {
|
|
110
|
+
const packageRoot = import_node_path.default.resolve(import_node_path.default.dirname((0, import_node_url.fileURLToPath)(__sootsim_import_meta_url)), "..");
|
|
111
|
+
const binPath = import_node_path.default.join(packageRoot, "dist-cli", "bin.js");
|
|
112
|
+
console.log(`[rnx] opening ${appName} in the desktop simulator`);
|
|
113
|
+
const child = (0, import_node_child_process.spawn)(
|
|
114
|
+
process.execPath,
|
|
115
|
+
[binPath, ...buildRnxDesktopOpenArgs(bundleUrl)],
|
|
116
|
+
{
|
|
117
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
118
|
+
windowsHide: true
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
observeRnxDesktopLaunch(child, appName);
|
|
122
|
+
}
|
|
123
|
+
function openRnxDesktopWhenMetroIsReady({
|
|
124
|
+
port,
|
|
125
|
+
bundleUrl,
|
|
126
|
+
appName,
|
|
127
|
+
projectRoot,
|
|
128
|
+
serverId,
|
|
129
|
+
intervalMs = 100,
|
|
130
|
+
timeoutMs = 3e4,
|
|
131
|
+
launch = launchRnxDesktop
|
|
132
|
+
}) {
|
|
133
|
+
const key = `${projectRoot}\0${port}`;
|
|
134
|
+
if (scheduledMetroOpens.has(key)) return Promise.resolve(false);
|
|
135
|
+
scheduledMetroOpens.add(key);
|
|
136
|
+
const deadline = Date.now() + timeoutMs;
|
|
137
|
+
return new Promise((resolve) => {
|
|
138
|
+
let finished = false;
|
|
139
|
+
const finish = (opened) => {
|
|
140
|
+
if (finished) return;
|
|
141
|
+
finished = true;
|
|
142
|
+
scheduledMetroOpens.delete(key);
|
|
143
|
+
resolve(opened);
|
|
144
|
+
};
|
|
145
|
+
const retry = () => {
|
|
146
|
+
if (finished) return;
|
|
147
|
+
if (Date.now() >= deadline) {
|
|
148
|
+
console.error(
|
|
149
|
+
`[rnx] could not open ${appName}: Metro did not become ready on port ${port}`
|
|
150
|
+
);
|
|
151
|
+
finish(false);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const timer = setTimeout(check, intervalMs);
|
|
155
|
+
timer.unref();
|
|
156
|
+
};
|
|
157
|
+
const check = () => {
|
|
158
|
+
const request = import_node_http.default.get(
|
|
159
|
+
`http://127.0.0.1:${port}/__server-scan`,
|
|
160
|
+
{ headers: { Accept: "application/json" } },
|
|
161
|
+
(response) => {
|
|
162
|
+
let body = "";
|
|
163
|
+
response.setEncoding("utf8");
|
|
164
|
+
response.on("data", (chunk) => {
|
|
165
|
+
body = `${body}${chunk}`.slice(0, 65536);
|
|
166
|
+
});
|
|
167
|
+
response.once("end", () => {
|
|
168
|
+
try {
|
|
169
|
+
const scan = JSON.parse(body);
|
|
170
|
+
const matches = response.statusCode === 200 && Array.isArray(scan) && scan.some((entry) => {
|
|
171
|
+
if (!entry || typeof entry !== "object") return false;
|
|
172
|
+
const scannedPort = Reflect.get(entry, "port");
|
|
173
|
+
const projectName = Reflect.get(entry, "projectName");
|
|
174
|
+
const scannedServerId = Reflect.get(entry, "rnxServerId");
|
|
175
|
+
const scannedBundle = Reflect.get(entry, "bundleUrl");
|
|
176
|
+
if (scannedPort !== port || projectName !== appName || scannedServerId !== serverId || typeof scannedBundle !== "string") {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
return new URL(scannedBundle).searchParams.get("rnxAppName") === appName;
|
|
180
|
+
});
|
|
181
|
+
if (matches) {
|
|
182
|
+
launch(bundleUrl, appName);
|
|
183
|
+
finish(true);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
} catch {
|
|
187
|
+
}
|
|
188
|
+
retry();
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
);
|
|
192
|
+
request.setTimeout(Math.min(1e3, timeoutMs), () => request.destroy());
|
|
193
|
+
request.once("error", retry);
|
|
194
|
+
};
|
|
195
|
+
check();
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// src/host/replacement-module-handler.ts
|
|
200
|
+
var import_promises = __toESM(require("node:fs/promises"), 1);
|
|
201
|
+
var import_node_path2 = __toESM(require("node:path"), 1);
|
|
202
|
+
var import_esbuild = require("esbuild");
|
|
203
|
+
|
|
204
|
+
// src/backend-origin.ts
|
|
205
|
+
function normalizeHostname(hostname) {
|
|
206
|
+
return hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
207
|
+
}
|
|
208
|
+
function isLoopbackHost(hostname) {
|
|
209
|
+
const normalized = normalizeHostname(hostname);
|
|
210
|
+
return normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "0.0.0.0" || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// src/host/replacement-module-handler.ts
|
|
214
|
+
var REPLACEMENT_MODULE_ROUTE = "/__sootsim-replacement-module";
|
|
215
|
+
var REPLACEMENT_RUNTIME_PREFIX = "/__sootsim-replacement-runtime";
|
|
216
|
+
function getReplacementLoader(filePath) {
|
|
217
|
+
const ext = import_node_path2.default.extname(filePath).toLowerCase();
|
|
218
|
+
switch (ext) {
|
|
219
|
+
case ".js":
|
|
220
|
+
return "js";
|
|
221
|
+
case ".jsx":
|
|
222
|
+
return "jsx";
|
|
223
|
+
case ".ts":
|
|
224
|
+
return "ts";
|
|
225
|
+
case ".tsx":
|
|
226
|
+
return "tsx";
|
|
227
|
+
default:
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function reactRuntimeSource(reactBridgeUrl) {
|
|
232
|
+
if (reactBridgeUrl) {
|
|
233
|
+
return `export * from ${JSON.stringify(reactBridgeUrl)};
|
|
234
|
+
import React from ${JSON.stringify(reactBridgeUrl)};
|
|
235
|
+
export default React;
|
|
236
|
+
`;
|
|
237
|
+
}
|
|
238
|
+
return `const bridge = globalThis.__sootsim_react_bridge
|
|
239
|
+
if (!bridge) throw new Error('[rnx] replacement React bridge is not ready')
|
|
240
|
+
export default bridge.default
|
|
241
|
+
export const Activity = bridge.Activity
|
|
242
|
+
export const Children = bridge.Children
|
|
243
|
+
export const Component = bridge.Component
|
|
244
|
+
export const Fragment = bridge.Fragment
|
|
245
|
+
export const Profiler = bridge.Profiler
|
|
246
|
+
export const PureComponent = bridge.PureComponent
|
|
247
|
+
export const StrictMode = bridge.StrictMode
|
|
248
|
+
export const Suspense = bridge.Suspense
|
|
249
|
+
export const __CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE = bridge.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE
|
|
250
|
+
export const __COMPILER_RUNTIME = bridge.__COMPILER_RUNTIME
|
|
251
|
+
export const __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = bridge.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
|
|
252
|
+
export const act = bridge.act
|
|
253
|
+
export const cache = bridge.cache
|
|
254
|
+
export const cacheSignal = bridge.cacheSignal
|
|
255
|
+
export const captureOwnerStack = bridge.captureOwnerStack
|
|
256
|
+
export const cloneElement = bridge.cloneElement
|
|
257
|
+
export const createContext = bridge.createContext
|
|
258
|
+
export const createElement = bridge.createElement
|
|
259
|
+
export const createRef = bridge.createRef
|
|
260
|
+
export const forwardRef = bridge.forwardRef
|
|
261
|
+
export const isValidElement = bridge.isValidElement
|
|
262
|
+
export const lazy = bridge.lazy
|
|
263
|
+
export const memo = bridge.memo
|
|
264
|
+
export const startTransition = bridge.startTransition
|
|
265
|
+
export const unstable_useCacheRefresh = bridge.unstable_useCacheRefresh
|
|
266
|
+
export const use = bridge.use
|
|
267
|
+
export const useActionState = bridge.useActionState
|
|
268
|
+
export const useCallback = bridge.useCallback
|
|
269
|
+
export const useContext = bridge.useContext
|
|
270
|
+
export const useDebugValue = bridge.useDebugValue
|
|
271
|
+
export const useDeferredValue = bridge.useDeferredValue
|
|
272
|
+
export const useEffect = bridge.useEffect
|
|
273
|
+
export const useEffectEvent = bridge.useEffectEvent
|
|
274
|
+
export const useId = bridge.useId
|
|
275
|
+
export const useImperativeHandle = bridge.useImperativeHandle
|
|
276
|
+
export const useInsertionEffect = bridge.useInsertionEffect
|
|
277
|
+
export const useLayoutEffect = bridge.useLayoutEffect
|
|
278
|
+
export const useMemo = bridge.useMemo
|
|
279
|
+
export const useOptimistic = bridge.useOptimistic
|
|
280
|
+
export const useReducer = bridge.useReducer
|
|
281
|
+
export const useRef = bridge.useRef
|
|
282
|
+
export const useState = bridge.useState
|
|
283
|
+
export const useSyncExternalStore = bridge.useSyncExternalStore
|
|
284
|
+
export const useTransition = bridge.useTransition
|
|
285
|
+
export const version = bridge.version
|
|
286
|
+
`;
|
|
287
|
+
}
|
|
288
|
+
function reactNativeRuntimeSource() {
|
|
289
|
+
return `const rn = globalThis.__sootsim_components__ || {}
|
|
290
|
+
export default rn
|
|
291
|
+
export const View = rn.View
|
|
292
|
+
export const Text = rn.Text
|
|
293
|
+
export const Image = rn.Image
|
|
294
|
+
export const ScrollView = rn.ScrollView
|
|
295
|
+
export const FlatList = rn.FlatList
|
|
296
|
+
export const Pressable = rn.Pressable
|
|
297
|
+
export const TouchableOpacity = rn.TouchableOpacity
|
|
298
|
+
export const TouchableWithoutFeedback = rn.TouchableWithoutFeedback
|
|
299
|
+
export const TouchableHighlight = rn.TouchableHighlight
|
|
300
|
+
export const TextInput = rn.TextInput
|
|
301
|
+
export const ActivityIndicator = rn.ActivityIndicator
|
|
302
|
+
export const KeyboardAvoidingView = rn.KeyboardAvoidingView
|
|
303
|
+
export const Button = rn.Button
|
|
304
|
+
export const Modal = rn.Modal
|
|
305
|
+
export const Switch = rn.Switch
|
|
306
|
+
export const StyleSheet = rn.StyleSheet
|
|
307
|
+
export const Platform = rn.Platform
|
|
308
|
+
export const Keyboard = rn.Keyboard
|
|
309
|
+
export const Dimensions = rn.Dimensions
|
|
310
|
+
export const Appearance = rn.Appearance
|
|
311
|
+
`;
|
|
312
|
+
}
|
|
313
|
+
function sendJavaScript(req, res, source) {
|
|
314
|
+
const origin = req.headers.origin;
|
|
315
|
+
let allowedOrigin;
|
|
316
|
+
if (origin) {
|
|
317
|
+
try {
|
|
318
|
+
if (isLoopbackHost(new URL(origin).hostname)) allowedOrigin = origin;
|
|
319
|
+
} catch {
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
res.writeHead(200, {
|
|
323
|
+
"Content-Type": "application/javascript; charset=utf-8",
|
|
324
|
+
"Cache-Control": "no-cache",
|
|
325
|
+
...allowedOrigin ? { "Access-Control-Allow-Origin": allowedOrigin, Vary: "Origin" } : {}
|
|
326
|
+
});
|
|
327
|
+
res.end(req.method === "HEAD" ? void 0 : source);
|
|
328
|
+
}
|
|
329
|
+
function isReplacementModuleRequestUrl(rawUrl) {
|
|
330
|
+
if (!rawUrl) return false;
|
|
331
|
+
try {
|
|
332
|
+
const pathname = new URL(rawUrl, "http://rnx.local").pathname;
|
|
333
|
+
return pathname === REPLACEMENT_MODULE_ROUTE || pathname.startsWith(`${REPLACEMENT_RUNTIME_PREFIX}/`);
|
|
334
|
+
} catch {
|
|
335
|
+
return false;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
async function handleReplacementModuleRequest(req, res, options = {}) {
|
|
339
|
+
const rawUrl = req.url || "";
|
|
340
|
+
let url;
|
|
341
|
+
try {
|
|
342
|
+
url = new URL(rawUrl, "http://rnx.local");
|
|
343
|
+
} catch {
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
if (options.requireLoopbackOrigin) {
|
|
347
|
+
const origin = req.headers.origin;
|
|
348
|
+
const remoteAddress = req.socket.remoteAddress?.replace(/^::ffff:/, "");
|
|
349
|
+
let allowed = Boolean(remoteAddress && isLoopbackHost(remoteAddress));
|
|
350
|
+
if (allowed && origin) {
|
|
351
|
+
try {
|
|
352
|
+
allowed = isLoopbackHost(new URL(origin).hostname);
|
|
353
|
+
} catch {
|
|
354
|
+
allowed = false;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
if (!allowed) {
|
|
358
|
+
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
359
|
+
res.end("replacement modules are available only to loopback origins");
|
|
360
|
+
return true;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
if (url.pathname === `${REPLACEMENT_RUNTIME_PREFIX}/react`) {
|
|
364
|
+
sendJavaScript(req, res, reactRuntimeSource(options.reactBridgeUrl));
|
|
365
|
+
return true;
|
|
366
|
+
}
|
|
367
|
+
if (url.pathname === `${REPLACEMENT_RUNTIME_PREFIX}/react-native`) {
|
|
368
|
+
sendJavaScript(req, res, reactNativeRuntimeSource());
|
|
369
|
+
return true;
|
|
370
|
+
}
|
|
371
|
+
if (url.pathname !== REPLACEMENT_MODULE_ROUTE) return false;
|
|
372
|
+
if (options.requestToken && url.searchParams.get("token") !== options.requestToken) {
|
|
373
|
+
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
374
|
+
res.end("replacement module request token is invalid");
|
|
375
|
+
return true;
|
|
376
|
+
}
|
|
377
|
+
const targetPath = url.searchParams.get("path");
|
|
378
|
+
if (!targetPath) {
|
|
379
|
+
res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
|
|
380
|
+
res.end("missing path param");
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
const loader = getReplacementLoader(targetPath);
|
|
384
|
+
if (!loader) {
|
|
385
|
+
res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
|
|
386
|
+
res.end("replacement files must be .js, .jsx, .ts, or .tsx");
|
|
387
|
+
return true;
|
|
388
|
+
}
|
|
389
|
+
if (!import_node_path2.default.isAbsolute(targetPath)) {
|
|
390
|
+
res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
|
|
391
|
+
res.end("replacement file path must be absolute");
|
|
392
|
+
return true;
|
|
393
|
+
}
|
|
394
|
+
let resolvedProjectRoot;
|
|
395
|
+
if (options.projectRoot) {
|
|
396
|
+
const lexicalProjectRoot = import_node_path2.default.resolve(options.projectRoot);
|
|
397
|
+
resolvedProjectRoot = await import_promises.default.realpath(options.projectRoot);
|
|
398
|
+
const lexicalTarget = import_node_path2.default.relative(lexicalProjectRoot, targetPath);
|
|
399
|
+
if (lexicalTarget.startsWith("..") || import_node_path2.default.isAbsolute(lexicalTarget)) {
|
|
400
|
+
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
401
|
+
res.end("replacement file must be inside the project root");
|
|
402
|
+
return true;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
let resolvedTargetPath;
|
|
406
|
+
try {
|
|
407
|
+
resolvedTargetPath = await import_promises.default.realpath(targetPath);
|
|
408
|
+
} catch (error) {
|
|
409
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
410
|
+
res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
|
411
|
+
res.end(`replacement file not found: ${message}`);
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
if (resolvedProjectRoot) {
|
|
415
|
+
const relativeTarget = import_node_path2.default.relative(resolvedProjectRoot, resolvedTargetPath);
|
|
416
|
+
if (relativeTarget.startsWith("..") || import_node_path2.default.isAbsolute(relativeTarget)) {
|
|
417
|
+
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
418
|
+
res.end("replacement file must be inside the project root");
|
|
419
|
+
return true;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
try {
|
|
423
|
+
const result = await (0, import_esbuild.build)({
|
|
424
|
+
entryPoints: [resolvedTargetPath],
|
|
425
|
+
bundle: true,
|
|
426
|
+
write: false,
|
|
427
|
+
format: "esm",
|
|
428
|
+
platform: "browser",
|
|
429
|
+
target: "es2022",
|
|
430
|
+
jsx: "transform",
|
|
431
|
+
jsxFactory: "React.createElement",
|
|
432
|
+
jsxFragment: "React.Fragment",
|
|
433
|
+
tsconfigRaw: { compilerOptions: { jsx: "react" } },
|
|
434
|
+
sourcemap: "inline",
|
|
435
|
+
logLevel: "silent",
|
|
436
|
+
external: ["react", "react-native"]
|
|
437
|
+
});
|
|
438
|
+
const bundledCode = result.outputFiles[0]?.text ?? "";
|
|
439
|
+
const hasReactBinding = /\bimport\s+(?:\*\s+as\s+React|React(?:\s*,|\s+from)|\{[^}]*\bdefault\s+as\s+React\b)/.test(
|
|
440
|
+
bundledCode
|
|
441
|
+
);
|
|
442
|
+
const reactImport = /\bReact\.(?:createElement|Fragment)\b/.test(bundledCode) && !hasReactBinding ? `import * as React from '${REPLACEMENT_RUNTIME_PREFIX}/react';
|
|
443
|
+
` : "";
|
|
444
|
+
const runtimeCode = (reactImport + bundledCode).replace(
|
|
445
|
+
/from\s*["']react-native["']/g,
|
|
446
|
+
`from '${REPLACEMENT_RUNTIME_PREFIX}/react-native'`
|
|
447
|
+
).replace(/from\s*["']react["']/g, `from '${REPLACEMENT_RUNTIME_PREFIX}/react'`);
|
|
448
|
+
sendJavaScript(req, res, runtimeCode);
|
|
449
|
+
} catch (error) {
|
|
450
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
451
|
+
res.writeHead(500, { "Content-Type": "text/plain; charset=utf-8" });
|
|
452
|
+
res.end(`replacement bundle failed: ${message}`);
|
|
453
|
+
}
|
|
454
|
+
return true;
|
|
455
|
+
}
|
|
456
|
+
|
|
44
457
|
// src/metro-production-bundle.ts
|
|
45
458
|
var RNXSIM_METRO_PRODUCTION_BUNDLE_OPTION = "rnxsim";
|
|
46
459
|
var RNXSIM_METRO_MODULE_PATHS_PREFIX = "globalThis.__sootsimModulePaths=";
|
|
@@ -71,28 +484,28 @@ function isValidRuntimeVersion(value) {
|
|
|
71
484
|
}
|
|
72
485
|
|
|
73
486
|
// src/home-paths.ts
|
|
74
|
-
var
|
|
487
|
+
var import_node_fs2 = __toESM(require("node:fs"), 1);
|
|
75
488
|
var import_node_os = require("node:os");
|
|
76
|
-
var
|
|
489
|
+
var import_node_path3 = __toESM(require("node:path"), 1);
|
|
77
490
|
var SOOTSIM_HOME_ENV = "SOOTSIM_HOME";
|
|
78
491
|
var ACTIVE_RUNTIME_FILE = "active";
|
|
79
492
|
function sootsimHomeDir() {
|
|
80
493
|
const override = process.env[SOOTSIM_HOME_ENV];
|
|
81
|
-
if (override && override.length > 0) return
|
|
82
|
-
return
|
|
494
|
+
if (override && override.length > 0) return import_node_path3.default.resolve(override);
|
|
495
|
+
return import_node_path3.default.join((0, import_node_os.homedir)(), ".sootsim");
|
|
83
496
|
}
|
|
84
497
|
function runtimesDir() {
|
|
85
|
-
return
|
|
498
|
+
return import_node_path3.default.join(sootsimHomeDir(), "runtimes");
|
|
86
499
|
}
|
|
87
500
|
function runtimeDir(version) {
|
|
88
|
-
return
|
|
501
|
+
return import_node_path3.default.join(runtimesDir(), version);
|
|
89
502
|
}
|
|
90
503
|
function activeRuntimeFile() {
|
|
91
|
-
return
|
|
504
|
+
return import_node_path3.default.join(runtimesDir(), ACTIVE_RUNTIME_FILE);
|
|
92
505
|
}
|
|
93
506
|
function readActiveRuntime() {
|
|
94
507
|
try {
|
|
95
|
-
const value =
|
|
508
|
+
const value = import_node_fs2.default.readFileSync(activeRuntimeFile(), "utf8").trim();
|
|
96
509
|
return value.length > 0 ? value : null;
|
|
97
510
|
} catch {
|
|
98
511
|
return null;
|
|
@@ -315,12 +728,22 @@ function prependRNXModulePaths(result, graph, options, projectRoot) {
|
|
|
315
728
|
return typeof result === "string" ? result + footer : { ...result, code: result.code + footer };
|
|
316
729
|
}
|
|
317
730
|
function withRNX(config, options = {}) {
|
|
318
|
-
if (!options.devServer && !options.productionBundles) return config;
|
|
319
|
-
const
|
|
731
|
+
if (!options.devServer && !options.open && !options.productionBundles) return config;
|
|
732
|
+
const cfgProjectRoot = config.projectRoot || process.cwd();
|
|
733
|
+
const appName = resolveRnxDesktopAppName(options.open, cfgProjectRoot);
|
|
734
|
+
const configuredBundleUrl = options.bundleUrl || "/index.bundle?platform=ios&dev=true&hot=true&minify=false";
|
|
320
735
|
const cfgServer = config.server;
|
|
736
|
+
const port = resolveMetroPort(cfgServer);
|
|
737
|
+
const metroServerId = (0, import_node_crypto2.randomUUID)();
|
|
738
|
+
const bundleUrl = tagRnxBundleForPlugin(
|
|
739
|
+
configuredBundleUrl,
|
|
740
|
+
`http://localhost:${port}`,
|
|
741
|
+
metroServerId,
|
|
742
|
+
cfgProjectRoot,
|
|
743
|
+
appName
|
|
744
|
+
);
|
|
321
745
|
const cfgResolver = config.resolver;
|
|
322
746
|
const cfgSerializer = config.serializer;
|
|
323
|
-
const cfgProjectRoot = config.projectRoot || process.cwd();
|
|
324
747
|
const existingEnhance = cfgServer?.enhanceMiddleware;
|
|
325
748
|
const existingResolveRequest = cfgResolver?.resolveRequest;
|
|
326
749
|
const existingSerializer = cfgSerializer?.customSerializer;
|
|
@@ -377,8 +800,35 @@ function withRNX(config, options = {}) {
|
|
|
377
800
|
}
|
|
378
801
|
const server = connect();
|
|
379
802
|
server.use((req, res, next) => {
|
|
803
|
+
if (isReplacementModuleRequestUrl(req.url)) {
|
|
804
|
+
void handleReplacementModuleRequest(req, res, {
|
|
805
|
+
projectRoot: cfgProjectRoot,
|
|
806
|
+
requestToken: metroServerId,
|
|
807
|
+
requireLoopbackOrigin: true
|
|
808
|
+
}).then((handled) => {
|
|
809
|
+
if (!handled) next();
|
|
810
|
+
});
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
380
813
|
const url = req.url || "";
|
|
381
814
|
const pathname = url.split("?")[0];
|
|
815
|
+
if (pathname === "/__server-scan") {
|
|
816
|
+
const absoluteBundleUrl = bundleUrl.startsWith("http") ? bundleUrl : `http://localhost:${port}${bundleUrl}`;
|
|
817
|
+
res.setHeader("content-type", "application/json");
|
|
818
|
+
res.end(
|
|
819
|
+
JSON.stringify([
|
|
820
|
+
{
|
|
821
|
+
port,
|
|
822
|
+
framework: "metro",
|
|
823
|
+
rnxServerId: metroServerId,
|
|
824
|
+
bundleUrl: absoluteBundleUrl,
|
|
825
|
+
...appName ? { projectName: appName } : {},
|
|
826
|
+
lastSeen: Date.now()
|
|
827
|
+
}
|
|
828
|
+
])
|
|
829
|
+
);
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
382
832
|
const runtimeRoot = resolveRuntimeRootForRequestHost(req.headers?.host);
|
|
383
833
|
if (!runtimeRoot) {
|
|
384
834
|
if (pathname === prefix || pathname === prefix + "/") {
|
|
@@ -413,7 +863,7 @@ function withRNX(config, options = {}) {
|
|
|
413
863
|
let html = import_fs2.default.readFileSync(htmlPath, "utf8");
|
|
414
864
|
html = html.replace(
|
|
415
865
|
"</head>",
|
|
416
|
-
`<script>history.replaceState(null,'','${prefix}
|
|
866
|
+
`<script>(function(){var u=new URL(location.href);if(!u.searchParams.has('bundle'))u.searchParams.set('bundle',${JSON.stringify(bundleUrl)});history.replaceState(null,'','${prefix}/'+u.search)})()</script></head>`
|
|
417
867
|
);
|
|
418
868
|
res.setHeader("content-type", "text/html");
|
|
419
869
|
res.end(html);
|
|
@@ -427,12 +877,32 @@ function withRNX(config, options = {}) {
|
|
|
427
877
|
return server;
|
|
428
878
|
}
|
|
429
879
|
};
|
|
880
|
+
if (appName && !process.env.CI && !process.env.SOOTSIM_NO_OPEN) {
|
|
881
|
+
void openRnxDesktopWhenMetroIsReady({
|
|
882
|
+
port,
|
|
883
|
+
bundleUrl: resolveRnxDesktopLaunchTarget(port, bundleUrl),
|
|
884
|
+
appName,
|
|
885
|
+
projectRoot: cfgProjectRoot,
|
|
886
|
+
serverId: metroServerId
|
|
887
|
+
});
|
|
888
|
+
}
|
|
430
889
|
return {
|
|
431
890
|
...config,
|
|
432
891
|
...productionConfig,
|
|
433
|
-
...options.devServer ? { server: serverConfig } : {}
|
|
892
|
+
...options.devServer || options.open ? { server: serverConfig } : {}
|
|
434
893
|
};
|
|
435
894
|
}
|
|
895
|
+
function resolveMetroPort(server) {
|
|
896
|
+
const inlinePort = process.argv.find((arg) => arg.startsWith("--port="))?.slice(7);
|
|
897
|
+
const portIndex = process.argv.indexOf("--port");
|
|
898
|
+
const splitPort = portIndex >= 0 ? process.argv[portIndex + 1] : void 0;
|
|
899
|
+
const rawPort = inlinePort || splitPort || process.env.RCT_METRO_PORT || server?.port || 8081;
|
|
900
|
+
const port = Number(rawPort);
|
|
901
|
+
if (!Number.isInteger(port) || port <= 0) {
|
|
902
|
+
throw new Error(`rnx: Metro port must be a positive integer, got ${rawPort}`);
|
|
903
|
+
}
|
|
904
|
+
return port;
|
|
905
|
+
}
|
|
436
906
|
var metro_plugin_default = withRNX;
|
|
437
907
|
// Annotate the CommonJS export names for ESM import in node:
|
|
438
908
|
0 && (module.exports = {
|
package/dist-lib/profiles.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;
|
|
@@ -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 __defProp = Object.defineProperty;
|
|
@@ -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 __defProp = Object.defineProperty;
|
package/dist-lib/render-mode.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 __defProp = Object.defineProperty;
|