rnxsim 0.1.343 → 0.1.345
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-RFD32ACU.js → agent-52G55XTO.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-2YLW2HQK.js → agent-wrapper-BOZM43ON.js} +2 -2
- package/dist-cli/chunks/{app-fonts-6OATDF3Y.js → app-fonts-A2L6V5EZ.js} +2 -2
- package/dist-cli/chunks/{assert-PSQICFOY.js → assert-CJKIP4LN.js} +2 -2
- package/dist-cli/chunks/{auth-XWLFKZT7.js → auth-VHHN3TOB.js} +2 -2
- package/dist-cli/chunks/{beta-I6WTVM6C.js → beta-EBDIGV3E.js} +2 -2
- package/dist-cli/chunks/{camera-45HKTLWG.js → camera-5F4KKCQ3.js} +2 -2
- package/dist-cli/chunks/chunk-3DBTS4MC.js +15 -0
- package/dist-cli/chunks/chunk-3N7M5HMJ.js +6 -0
- package/dist-cli/chunks/{chunk-RWYA2USN.js → chunk-4BIPA7MD.js} +1 -1
- package/dist-cli/chunks/chunk-4OKV7T5D.js +4 -0
- package/dist-cli/chunks/{chunk-T4T6DDKM.js → chunk-4ZILDTZX.js} +2 -2
- package/dist-cli/chunks/{chunk-R7X74I3I.js → chunk-5GXRRUOA.js} +26 -26
- package/dist-cli/chunks/chunk-63ASUHOV.js +4 -0
- package/dist-cli/chunks/{chunk-DASP2EKF.js → chunk-7GO2DSYQ.js} +1 -1
- package/dist-cli/chunks/{chunk-HJXIBZ35.js → chunk-7LGINKM6.js} +2 -2
- package/dist-cli/chunks/{chunk-2IPMH24A.js → chunk-7UIIAHVU.js} +2 -2
- package/dist-cli/chunks/{chunk-ES5BHPTS.js → chunk-7V4KPZ7O.js} +2 -2
- package/dist-cli/chunks/{chunk-FCHRGEHA.js → chunk-7YMQRA6L.js} +2 -2
- package/dist-cli/chunks/{chunk-DC7TS573.js → chunk-A2Q76LJV.js} +2 -2
- package/dist-cli/chunks/{chunk-SAUCA7SN.js → chunk-BCQV63BW.js} +45 -45
- package/dist-cli/chunks/{chunk-3FYJ7U3C.js → chunk-BFTDL2GX.js} +17 -17
- package/dist-cli/chunks/chunk-BHKSCNDC.js +4 -0
- package/dist-cli/chunks/{chunk-QPTJNLPT.js → chunk-DGTV3KOW.js} +1 -1
- package/dist-cli/chunks/chunk-DHM3JDCK.js +4 -0
- package/dist-cli/chunks/{chunk-TQRVLK64.js → chunk-DPP2M4AJ.js} +1 -1
- package/dist-cli/chunks/chunk-E2RGSCHT.js +4 -0
- package/dist-cli/chunks/{chunk-TQ5OPG33.js → chunk-EPLVIDPC.js} +1 -1
- package/dist-cli/chunks/{chunk-P3IDK7FR.js → chunk-GKGXULJK.js} +2 -2
- package/dist-cli/chunks/{chunk-34KDMQ6U.js → chunk-HK7YKH6N.js} +2 -2
- package/dist-cli/chunks/{chunk-BJUNXCPO.js → chunk-HXE344V3.js} +1 -1
- package/dist-cli/chunks/{chunk-HJHFC5ZZ.js → chunk-JC33TOAF.js} +1 -1
- package/dist-cli/chunks/{chunk-G3B2RZ47.js → chunk-KA4PJNTE.js} +2 -2
- package/dist-cli/chunks/{chunk-VC4TDPJQ.js → chunk-KH777UAO.js} +3 -3
- package/dist-cli/chunks/{chunk-4PFMDBLB.js → chunk-KRZPFXVN.js} +1 -1
- package/dist-cli/chunks/{chunk-6SLM6URN.js → chunk-KZFJNDH3.js} +1 -1
- package/dist-cli/chunks/{chunk-KLMWLQAO.js → chunk-LAQGSSTT.js} +1 -1
- package/dist-cli/chunks/chunk-LRM2XCEQ.js +11 -0
- package/dist-cli/chunks/{chunk-YKKVDKLE.js → chunk-NUPRHZQW.js} +2 -2
- package/dist-cli/chunks/{chunk-AKV2DGKM.js → chunk-OPHT4DUO.js} +1 -1
- package/dist-cli/chunks/{chunk-KON6XG4Y.js → chunk-P2CGGMU2.js} +2 -2
- package/dist-cli/chunks/{chunk-5FB4EA33.js → chunk-PLB6UVVX.js} +2 -2
- package/dist-cli/chunks/{chunk-FRRHCLG2.js → chunk-PLUWN2V5.js} +1 -1
- package/dist-cli/chunks/{chunk-WDA4QR6U.js → chunk-QNBBKRCA.js} +2 -2
- package/dist-cli/chunks/{chunk-G7S6T5OX.js → chunk-QNRWPAOA.js} +2 -2
- package/dist-cli/chunks/{chunk-2EVBZ37G.js → chunk-R7ZNRGQN.js} +1 -1
- package/dist-cli/chunks/{chunk-TMJGPUWJ.js → chunk-RB4VFUNM.js} +3 -3
- package/dist-cli/chunks/chunk-RT3DXTDP.js +25 -0
- package/dist-cli/chunks/{chunk-OYLIWHDB.js → chunk-RTDHX6CW.js} +2 -2
- package/dist-cli/chunks/{chunk-YLFDA4WW.js → chunk-T7SBFG5I.js} +2 -2
- package/dist-cli/chunks/{chunk-W7EXE22C.js → chunk-TEU5NGUA.js} +2 -2
- package/dist-cli/chunks/chunk-TMRD5MHL.js +99 -0
- package/dist-cli/chunks/{chunk-SU7RE3PV.js → chunk-TOF5TA5X.js} +11 -11
- package/dist-cli/chunks/{chunk-6IVEGYWV.js → chunk-U5YHXQHH.js} +2 -2
- package/dist-cli/chunks/{chunk-BA3HRFJ5.js → chunk-UVOEHIGP.js} +1 -1
- package/dist-cli/chunks/{chunk-SW4DV2TY.js → chunk-VLBN3KRC.js} +1 -1
- package/dist-cli/chunks/{chunk-7WKV6EKX.js → chunk-WPPGU5IK.js} +2 -2
- package/dist-cli/chunks/{chunk-JOE3J46E.js → chunk-WU72KL6Z.js} +2 -2
- package/dist-cli/chunks/chunk-XJBFJGNT.js +4 -0
- package/dist-cli/chunks/{chunk-3CMKNWRL.js → chunk-XXZLK4BY.js} +1 -1
- package/dist-cli/chunks/{chunk-BKMPV6N4.js → chunk-YVSUFVVB.js} +1 -1
- package/dist-cli/chunks/{chunk-RO3WVQPB.js → chunk-ZMTZ5G5H.js} +2 -2
- package/dist-cli/chunks/{cleanup-OU4VKFC3.js → cleanup-MAVZJXVW.js} +2 -2
- package/dist-cli/chunks/cli-version-2B4KRNML.js +4 -0
- package/dist-cli/chunks/{compat-GAEKP67T.js → compat-7AURLGCS.js} +2 -2
- package/dist-cli/chunks/config-TN3Y4J5N.js +13 -0
- package/dist-cli/chunks/{control-VQJURMFD.js → control-EV2ELU5R.js} +2 -2
- package/dist-cli/chunks/daemon-KKDG5MYR.js +4 -0
- package/dist-cli/chunks/{debug-F5N2LO4T.js → debug-JICITUB6.js} +3 -3
- package/dist-cli/chunks/{desktop-I4ILT4BS.js → desktop-4F5HGLLX.js} +3 -3
- package/dist-cli/chunks/{detox-2HMPYSP4.js → detox-ZC7NHLJI.js} +2 -2
- package/dist-cli/chunks/{device-5LWLOB5R.js → device-V57GHRXX.js} +2 -2
- package/dist-cli/chunks/{diagnose-5S4IQPAP.js → diagnose-FF4IWYXC.js} +2 -2
- package/dist-cli/chunks/{disk-cleanup-CJSZVJQX.js → disk-cleanup-T277L6ZO.js} +2 -2
- package/dist-cli/chunks/drivers-LCX7S76X.js +4 -0
- package/dist-cli/chunks/{film-HCPU2TDB.js → film-G7ZAPWB7.js} +3 -3
- package/dist-cli/chunks/flow-ONZGGFGD.js +4 -0
- package/dist-cli/chunks/help-DROVDXJM.js +4 -0
- package/dist-cli/chunks/{hidden-runtime-alias-YYUEZQPR.js → hidden-runtime-alias-VSJNNSNI.js} +2 -2
- package/dist-cli/chunks/{home-paths-3FXISM5I.js → home-paths-75HP3HKA.js} +2 -2
- package/dist-cli/chunks/inspect-MDA7ESGQ.js +4 -0
- package/dist-cli/chunks/install-desktop-EIVZHIFA.js +4 -0
- package/dist-cli/chunks/login-ZSIHGHUK.js +26 -0
- package/dist-cli/chunks/logout-Q4DXMI2C.js +4 -0
- package/dist-cli/chunks/{maestro-F5KK4RC4.js → maestro-LE5LCRBL.js} +3 -3
- package/dist-cli/chunks/{maestro-generate-6SUU3Y5I.js → maestro-generate-D3ZIJCRL.js} +3 -3
- package/dist-cli/chunks/{mode-CSWGOJLI.js → mode-BWX6MDPJ.js} +2 -2
- package/dist-cli/chunks/{optional-demo-registry-Y6VJ4SVV.js → optional-demo-registry-6CVASL3S.js} +2 -2
- package/dist-cli/chunks/{perf-NRWWAJL4.js → perf-NXQZISN6.js} +2 -2
- package/dist-cli/chunks/{permissions-OD62A3DJ.js → permissions-5PD67RRO.js} +2 -2
- package/dist-cli/chunks/privacy-H5KNRNIZ.js +4 -0
- package/dist-cli/chunks/{record-JZT2GM3G.js → record-YJF4KXMR.js} +3 -3
- package/dist-cli/chunks/{report-issue-ZWSNHOPB.js → report-issue-XOL5FQBG.js} +2 -2
- package/dist-cli/chunks/reset-5LZN5P5B.js +4 -0
- package/dist-cli/chunks/runtime-U36VWBH3.js +4 -0
- package/dist-cli/chunks/{screenshot-command-ZGJR7ICY.js → screenshot-command-VRPJXWFS.js} +3 -3
- package/dist-cli/chunks/{screenshot-layers-5AQKOJZK.js → screenshot-layers-QP4WA2F5.js} +2 -2
- package/dist-cli/chunks/{screenshots-capture-CPTWK5Y3.js → screenshots-capture-O2IBAVSP.js} +2 -2
- package/dist-cli/chunks/serve-WC6RZNJL.js +118 -0
- package/dist-cli/chunks/setup-A6BIG3KL.js +30 -0
- package/dist-cli/chunks/{skills-NVWRBMEO.js → skills-A7YC6RL5.js} +2 -2
- package/dist-cli/chunks/{state-QGLTKN6K.js → state-IJI5YROJ.js} +2 -2
- package/dist-cli/chunks/{storage-OZMEZ4AV.js → storage-Z2DBO2PQ.js} +4 -4
- package/dist-cli/chunks/store-BYTCKNIC.js +4 -0
- package/dist-cli/chunks/telemetry-JLHFMD7N.js +4 -0
- package/dist-cli/chunks/{timeline-EXLDREY3.js → timeline-N7V2M6QA.js} +2 -2
- package/dist-cli/chunks/{upgrade-4VWXQO6I.js → upgrade-P2NH3BOR.js} +2 -2
- package/dist-cli/chunks/upload-Z2WX5DCD.js +4 -0
- package/dist-cli/chunks/{version-WZM6XCD2.js → version-OUHCSCUS.js} +2 -2
- package/dist-cli/chunks/{web-ZYPEUVWL.js → web-6NRTF3UV.js} +2 -2
- package/dist-cli/chunks/welcome-6RS7PEJW.js +5 -0
- package/dist-cli/chunks/{what-happened-KF2HLWKW.js → what-happened-FUEL3BEF.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 +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.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 +18 -4
- package/dist-lib/home-paths.cjs +145 -11
- package/dist-lib/host/bridge-host.cjs +236 -31
- 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 +25 -2
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +384 -385
- package/dist-lib/vite.cjs +193 -37
- package/package.json +2 -1
- package/scripts/dev-server-scanner.ts +12 -5
- package/skills/rnx-test/SKILL.md +4 -0
- package/src/dev-bundle-resolution.ts +13 -6
- 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-44LRQEU3.js +0 -4
- package/dist-cli/chunks/chunk-4RKTGL63.js +0 -9
- package/dist-cli/chunks/chunk-5SCIDXJD.js +0 -25
- package/dist-cli/chunks/chunk-CUVY4A2A.js +0 -4
- package/dist-cli/chunks/chunk-DPJGB7MP.js +0 -101
- package/dist-cli/chunks/chunk-HD6P3W5R.js +0 -4
- package/dist-cli/chunks/chunk-HFNESSHG.js +0 -15
- package/dist-cli/chunks/chunk-I7HHBFSD.js +0 -4
- package/dist-cli/chunks/chunk-LV2G34IX.js +0 -4
- package/dist-cli/chunks/cli-version-REQOM22G.js +0 -4
- package/dist-cli/chunks/config-QTFXJKD6.js +0 -13
- package/dist-cli/chunks/daemon-ETA375WE.js +0 -4
- package/dist-cli/chunks/drivers-R4YB2XAF.js +0 -4
- package/dist-cli/chunks/flow-3VQL6XZT.js +0 -4
- package/dist-cli/chunks/help-2RYCKZ2G.js +0 -4
- package/dist-cli/chunks/inspect-XDSX5D6D.js +0 -4
- package/dist-cli/chunks/install-desktop-OKVRLL35.js +0 -4
- package/dist-cli/chunks/login-4VCBPAY2.js +0 -28
- package/dist-cli/chunks/logout-WSL5JS5R.js +0 -4
- package/dist-cli/chunks/reset-3C52YQCV.js +0 -4
- package/dist-cli/chunks/runtime-4V2RBUOR.js +0 -4
- package/dist-cli/chunks/serve-ERAZQGCJ.js +0 -118
- package/dist-cli/chunks/setup-UG6PLYIL.js +0 -32
- package/dist-cli/chunks/store-VPBQKKWA.js +0 -4
- package/dist-cli/chunks/telemetry-FRW7OCYZ.js +0 -4
- package/dist-cli/chunks/upload-C6676NST.js +0 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.345 | (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;
|
|
@@ -41,6 +41,17 @@ module.exports = __toCommonJS(replacement_module_handler_exports);
|
|
|
41
41
|
var import_promises = __toESM(require("node:fs/promises"), 1);
|
|
42
42
|
var import_node_path = __toESM(require("node:path"), 1);
|
|
43
43
|
var import_esbuild = require("esbuild");
|
|
44
|
+
|
|
45
|
+
// src/backend-origin.ts
|
|
46
|
+
function normalizeHostname(hostname) {
|
|
47
|
+
return hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
48
|
+
}
|
|
49
|
+
function isLoopbackHost(hostname) {
|
|
50
|
+
const normalized = normalizeHostname(hostname);
|
|
51
|
+
return normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "0.0.0.0" || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/host/replacement-module-handler.ts
|
|
44
55
|
var REPLACEMENT_MODULE_ROUTE = "/__sootsim-replacement-module";
|
|
45
56
|
var REPLACEMENT_RUNTIME_PREFIX = "/__sootsim-replacement-runtime";
|
|
46
57
|
function getReplacementLoader(filePath) {
|
|
@@ -141,9 +152,18 @@ export const Appearance = rn.Appearance
|
|
|
141
152
|
`;
|
|
142
153
|
}
|
|
143
154
|
function sendJavaScript(req, res, source) {
|
|
155
|
+
const origin = req.headers.origin;
|
|
156
|
+
let allowedOrigin;
|
|
157
|
+
if (origin) {
|
|
158
|
+
try {
|
|
159
|
+
if (isLoopbackHost(new URL(origin).hostname)) allowedOrigin = origin;
|
|
160
|
+
} catch {
|
|
161
|
+
}
|
|
162
|
+
}
|
|
144
163
|
res.writeHead(200, {
|
|
145
164
|
"Content-Type": "application/javascript; charset=utf-8",
|
|
146
|
-
"Cache-Control": "no-cache"
|
|
165
|
+
"Cache-Control": "no-cache",
|
|
166
|
+
...allowedOrigin ? { "Access-Control-Allow-Origin": allowedOrigin, Vary: "Origin" } : {}
|
|
147
167
|
});
|
|
148
168
|
res.end(req.method === "HEAD" ? void 0 : source);
|
|
149
169
|
}
|
|
@@ -164,6 +184,23 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
|
|
|
164
184
|
} catch {
|
|
165
185
|
return false;
|
|
166
186
|
}
|
|
187
|
+
if (options.requireLoopbackOrigin) {
|
|
188
|
+
const origin = req.headers.origin;
|
|
189
|
+
const remoteAddress = req.socket.remoteAddress?.replace(/^::ffff:/, "");
|
|
190
|
+
let allowed = Boolean(remoteAddress && isLoopbackHost(remoteAddress));
|
|
191
|
+
if (allowed && origin) {
|
|
192
|
+
try {
|
|
193
|
+
allowed = isLoopbackHost(new URL(origin).hostname);
|
|
194
|
+
} catch {
|
|
195
|
+
allowed = false;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (!allowed) {
|
|
199
|
+
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
200
|
+
res.end("replacement modules are available only to loopback origins");
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
167
204
|
if (url.pathname === `${REPLACEMENT_RUNTIME_PREFIX}/react`) {
|
|
168
205
|
sendJavaScript(req, res, reactRuntimeSource(options.reactBridgeUrl));
|
|
169
206
|
return true;
|
|
@@ -173,6 +210,11 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
|
|
|
173
210
|
return true;
|
|
174
211
|
}
|
|
175
212
|
if (url.pathname !== REPLACEMENT_MODULE_ROUTE) return false;
|
|
213
|
+
if (options.requestToken && url.searchParams.get("token") !== options.requestToken) {
|
|
214
|
+
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
215
|
+
res.end("replacement module request token is invalid");
|
|
216
|
+
return true;
|
|
217
|
+
}
|
|
176
218
|
const targetPath = url.searchParams.get("path");
|
|
177
219
|
if (!targetPath) {
|
|
178
220
|
res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
|
|
@@ -185,17 +227,42 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
|
|
|
185
227
|
res.end("replacement files must be .js, .jsx, .ts, or .tsx");
|
|
186
228
|
return true;
|
|
187
229
|
}
|
|
230
|
+
if (!import_node_path.default.isAbsolute(targetPath)) {
|
|
231
|
+
res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
|
|
232
|
+
res.end("replacement file path must be absolute");
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
let resolvedProjectRoot;
|
|
236
|
+
if (options.projectRoot) {
|
|
237
|
+
const lexicalProjectRoot = import_node_path.default.resolve(options.projectRoot);
|
|
238
|
+
resolvedProjectRoot = await import_promises.default.realpath(options.projectRoot);
|
|
239
|
+
const lexicalTarget = import_node_path.default.relative(lexicalProjectRoot, targetPath);
|
|
240
|
+
if (lexicalTarget.startsWith("..") || import_node_path.default.isAbsolute(lexicalTarget)) {
|
|
241
|
+
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
242
|
+
res.end("replacement file must be inside the project root");
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
let resolvedTargetPath;
|
|
188
247
|
try {
|
|
189
|
-
await import_promises.default.
|
|
248
|
+
resolvedTargetPath = await import_promises.default.realpath(targetPath);
|
|
190
249
|
} catch (error) {
|
|
191
250
|
const message = error instanceof Error ? error.message : String(error);
|
|
192
251
|
res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
|
193
252
|
res.end(`replacement file not found: ${message}`);
|
|
194
253
|
return true;
|
|
195
254
|
}
|
|
255
|
+
if (resolvedProjectRoot) {
|
|
256
|
+
const relativeTarget = import_node_path.default.relative(resolvedProjectRoot, resolvedTargetPath);
|
|
257
|
+
if (relativeTarget.startsWith("..") || import_node_path.default.isAbsolute(relativeTarget)) {
|
|
258
|
+
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
259
|
+
res.end("replacement file must be inside the project root");
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
196
263
|
try {
|
|
197
264
|
const result = await (0, import_esbuild.build)({
|
|
198
|
-
entryPoints: [
|
|
265
|
+
entryPoints: [resolvedTargetPath],
|
|
199
266
|
bundle: true,
|
|
200
267
|
write: false,
|
|
201
268
|
format: "esm",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.345 | (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/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.345 | (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;
|
|
@@ -2879,19 +2879,183 @@ async function connect(options = {}) {
|
|
|
2879
2879
|
}
|
|
2880
2880
|
|
|
2881
2881
|
// src/vite-plugin-one.ts
|
|
2882
|
-
var import_child_process2 = require("child_process");
|
|
2883
2882
|
var import_fs4 = __toESM(require("fs"), 1);
|
|
2883
|
+
var import_node_crypto2 = require("node:crypto");
|
|
2884
2884
|
var import_path3 = __toESM(require("path"), 1);
|
|
2885
|
-
|
|
2885
|
+
|
|
2886
|
+
// src/dev-server-open.ts
|
|
2887
|
+
var import_node_child_process = require("node:child_process");
|
|
2888
|
+
var import_node_crypto = require("node:crypto");
|
|
2889
|
+
var import_node_fs3 = __toESM(require("node:fs"), 1);
|
|
2890
|
+
var import_node_http = __toESM(require("node:http"), 1);
|
|
2891
|
+
var import_node_path3 = __toESM(require("node:path"), 1);
|
|
2892
|
+
var import_node_url = require("node:url");
|
|
2893
|
+
var scheduledMetroOpens = /* @__PURE__ */ new Set();
|
|
2894
|
+
function resolveRnxDesktopAppName(open, projectRoot) {
|
|
2895
|
+
if (!open) return null;
|
|
2896
|
+
if (typeof open === "object") {
|
|
2897
|
+
const appName = open.appName.trim();
|
|
2898
|
+
if (!appName) throw new Error("rnx: open.appName must not be empty");
|
|
2899
|
+
return appName;
|
|
2900
|
+
}
|
|
2901
|
+
const packageJsonPath = import_node_path3.default.join(projectRoot, "package.json");
|
|
2902
|
+
const packageJson = JSON.parse(import_node_fs3.default.readFileSync(packageJsonPath, "utf8"));
|
|
2903
|
+
const packageName = packageJson && typeof packageJson === "object" ? Reflect.get(packageJson, "name") : void 0;
|
|
2904
|
+
if (typeof packageName !== "string" || !packageName.trim()) {
|
|
2905
|
+
throw new Error(`rnx: ${packageJsonPath} must declare a package name`);
|
|
2906
|
+
}
|
|
2907
|
+
return packageName.trim();
|
|
2908
|
+
}
|
|
2909
|
+
function tagRnxBundleForPlugin(bundleUrl, replacementOrigin, replacementToken, projectRoot, appName) {
|
|
2910
|
+
const absolute = /^[a-z][a-z\d+.-]*:\/\//i.test(bundleUrl);
|
|
2911
|
+
const url = new URL(bundleUrl, absolute ? void 0 : "http://rnx.local");
|
|
2912
|
+
if (appName) {
|
|
2913
|
+
url.searchParams.set("rnxAppName", appName);
|
|
2914
|
+
url.searchParams.set(
|
|
2915
|
+
"rnxProjectId",
|
|
2916
|
+
(0, import_node_crypto.createHash)("sha256").update(import_node_fs3.default.realpathSync(projectRoot)).digest("hex").slice(0, 32)
|
|
2917
|
+
);
|
|
2918
|
+
}
|
|
2919
|
+
url.searchParams.set("rnxReplacementOrigin", replacementOrigin);
|
|
2920
|
+
url.searchParams.set("rnxReplacementToken", replacementToken);
|
|
2921
|
+
return absolute ? url.toString() : `${url.pathname}${url.search}${url.hash}`;
|
|
2922
|
+
}
|
|
2923
|
+
function resolveRnxDesktopLaunchTarget(port, bundleUrl) {
|
|
2924
|
+
return new URL(bundleUrl, `http://localhost:${port}`).toString();
|
|
2925
|
+
}
|
|
2926
|
+
function buildRnxDesktopOpenArgs(bundleUrl) {
|
|
2927
|
+
return ["open", bundleUrl, "--new", "--driver", "electron", "--no-describe"];
|
|
2928
|
+
}
|
|
2929
|
+
function observeRnxDesktopLaunch(child, appName) {
|
|
2930
|
+
let stderr = "";
|
|
2931
|
+
let spawnFailed = false;
|
|
2932
|
+
child.stderr?.setEncoding("utf8");
|
|
2933
|
+
child.stderr?.on("data", (chunk) => {
|
|
2934
|
+
stderr = `${stderr}${chunk}`.slice(-16384);
|
|
2935
|
+
});
|
|
2936
|
+
child.once("error", (error) => {
|
|
2937
|
+
spawnFailed = true;
|
|
2938
|
+
console.error(`[rnx] could not open ${appName}: ${error.message}`);
|
|
2939
|
+
});
|
|
2940
|
+
child.once("close", (code, signal) => {
|
|
2941
|
+
if (spawnFailed) return;
|
|
2942
|
+
if (code === 0) {
|
|
2943
|
+
console.log(`[rnx] opened ${appName} in the desktop simulator`);
|
|
2944
|
+
return;
|
|
2945
|
+
}
|
|
2946
|
+
const detail = stderr.trim() || (signal ? `signal ${signal}` : `exit ${code}`);
|
|
2947
|
+
console.error(`[rnx] could not open ${appName}: ${detail}`);
|
|
2948
|
+
});
|
|
2949
|
+
}
|
|
2950
|
+
function launchRnxDesktop(bundleUrl, appName) {
|
|
2951
|
+
const packageRoot = import_node_path3.default.resolve(import_node_path3.default.dirname((0, import_node_url.fileURLToPath)(__sootsim_import_meta_url)), "..");
|
|
2952
|
+
const binPath = import_node_path3.default.join(packageRoot, "dist-cli", "bin.js");
|
|
2953
|
+
console.log(`[rnx] opening ${appName} in the desktop simulator`);
|
|
2954
|
+
const child = (0, import_node_child_process.spawn)(
|
|
2955
|
+
process.execPath,
|
|
2956
|
+
[binPath, ...buildRnxDesktopOpenArgs(bundleUrl)],
|
|
2957
|
+
{
|
|
2958
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
2959
|
+
windowsHide: true
|
|
2960
|
+
}
|
|
2961
|
+
);
|
|
2962
|
+
observeRnxDesktopLaunch(child, appName);
|
|
2963
|
+
}
|
|
2964
|
+
function openRnxDesktopWhenMetroIsReady({
|
|
2965
|
+
port,
|
|
2966
|
+
bundleUrl,
|
|
2967
|
+
appName,
|
|
2968
|
+
projectRoot,
|
|
2969
|
+
serverId,
|
|
2970
|
+
intervalMs = 100,
|
|
2971
|
+
timeoutMs = 3e4,
|
|
2972
|
+
launch = launchRnxDesktop
|
|
2973
|
+
}) {
|
|
2974
|
+
const key = `${projectRoot}\0${port}`;
|
|
2975
|
+
if (scheduledMetroOpens.has(key)) return Promise.resolve(false);
|
|
2976
|
+
scheduledMetroOpens.add(key);
|
|
2977
|
+
const deadline = Date.now() + timeoutMs;
|
|
2978
|
+
return new Promise((resolve2) => {
|
|
2979
|
+
let finished = false;
|
|
2980
|
+
const finish = (opened) => {
|
|
2981
|
+
if (finished) return;
|
|
2982
|
+
finished = true;
|
|
2983
|
+
scheduledMetroOpens.delete(key);
|
|
2984
|
+
resolve2(opened);
|
|
2985
|
+
};
|
|
2986
|
+
const retry = () => {
|
|
2987
|
+
if (finished) return;
|
|
2988
|
+
if (Date.now() >= deadline) {
|
|
2989
|
+
console.error(
|
|
2990
|
+
`[rnx] could not open ${appName}: Metro did not become ready on port ${port}`
|
|
2991
|
+
);
|
|
2992
|
+
finish(false);
|
|
2993
|
+
return;
|
|
2994
|
+
}
|
|
2995
|
+
const timer = setTimeout(check, intervalMs);
|
|
2996
|
+
timer.unref();
|
|
2997
|
+
};
|
|
2998
|
+
const check = () => {
|
|
2999
|
+
const request = import_node_http.default.get(
|
|
3000
|
+
`http://127.0.0.1:${port}/__server-scan`,
|
|
3001
|
+
{ headers: { Accept: "application/json" } },
|
|
3002
|
+
(response) => {
|
|
3003
|
+
let body = "";
|
|
3004
|
+
response.setEncoding("utf8");
|
|
3005
|
+
response.on("data", (chunk) => {
|
|
3006
|
+
body = `${body}${chunk}`.slice(0, 65536);
|
|
3007
|
+
});
|
|
3008
|
+
response.once("end", () => {
|
|
3009
|
+
try {
|
|
3010
|
+
const scan = JSON.parse(body);
|
|
3011
|
+
const matches = response.statusCode === 200 && Array.isArray(scan) && scan.some((entry) => {
|
|
3012
|
+
if (!entry || typeof entry !== "object") return false;
|
|
3013
|
+
const scannedPort = Reflect.get(entry, "port");
|
|
3014
|
+
const projectName = Reflect.get(entry, "projectName");
|
|
3015
|
+
const scannedServerId = Reflect.get(entry, "rnxServerId");
|
|
3016
|
+
const scannedBundle = Reflect.get(entry, "bundleUrl");
|
|
3017
|
+
if (scannedPort !== port || projectName !== appName || scannedServerId !== serverId || typeof scannedBundle !== "string") {
|
|
3018
|
+
return false;
|
|
3019
|
+
}
|
|
3020
|
+
return new URL(scannedBundle).searchParams.get("rnxAppName") === appName;
|
|
3021
|
+
});
|
|
3022
|
+
if (matches) {
|
|
3023
|
+
launch(bundleUrl, appName);
|
|
3024
|
+
finish(true);
|
|
3025
|
+
return;
|
|
3026
|
+
}
|
|
3027
|
+
} catch {
|
|
3028
|
+
}
|
|
3029
|
+
retry();
|
|
3030
|
+
});
|
|
3031
|
+
}
|
|
3032
|
+
);
|
|
3033
|
+
request.setTimeout(Math.min(1e3, timeoutMs), () => request.destroy());
|
|
3034
|
+
request.once("error", retry);
|
|
3035
|
+
};
|
|
3036
|
+
check();
|
|
3037
|
+
});
|
|
3038
|
+
}
|
|
2886
3039
|
|
|
2887
3040
|
// src/host/replacement-module-handler.ts
|
|
2888
3041
|
var import_promises = __toESM(require("node:fs/promises"), 1);
|
|
2889
|
-
var
|
|
3042
|
+
var import_node_path4 = __toESM(require("node:path"), 1);
|
|
2890
3043
|
var import_esbuild = require("esbuild");
|
|
3044
|
+
|
|
3045
|
+
// src/backend-origin.ts
|
|
3046
|
+
function normalizeHostname(hostname) {
|
|
3047
|
+
return hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
3048
|
+
}
|
|
3049
|
+
function isLoopbackHost(hostname) {
|
|
3050
|
+
const normalized = normalizeHostname(hostname);
|
|
3051
|
+
return normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "0.0.0.0" || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
|
|
3052
|
+
}
|
|
3053
|
+
|
|
3054
|
+
// src/host/replacement-module-handler.ts
|
|
2891
3055
|
var REPLACEMENT_MODULE_ROUTE = "/__sootsim-replacement-module";
|
|
2892
3056
|
var REPLACEMENT_RUNTIME_PREFIX = "/__sootsim-replacement-runtime";
|
|
2893
3057
|
function getReplacementLoader(filePath) {
|
|
2894
|
-
const ext =
|
|
3058
|
+
const ext = import_node_path4.default.extname(filePath).toLowerCase();
|
|
2895
3059
|
switch (ext) {
|
|
2896
3060
|
case ".js":
|
|
2897
3061
|
return "js";
|
|
@@ -2988,12 +3152,30 @@ export const Appearance = rn.Appearance
|
|
|
2988
3152
|
`;
|
|
2989
3153
|
}
|
|
2990
3154
|
function sendJavaScript(req, res, source) {
|
|
3155
|
+
const origin = req.headers.origin;
|
|
3156
|
+
let allowedOrigin;
|
|
3157
|
+
if (origin) {
|
|
3158
|
+
try {
|
|
3159
|
+
if (isLoopbackHost(new URL(origin).hostname)) allowedOrigin = origin;
|
|
3160
|
+
} catch {
|
|
3161
|
+
}
|
|
3162
|
+
}
|
|
2991
3163
|
res.writeHead(200, {
|
|
2992
3164
|
"Content-Type": "application/javascript; charset=utf-8",
|
|
2993
|
-
"Cache-Control": "no-cache"
|
|
3165
|
+
"Cache-Control": "no-cache",
|
|
3166
|
+
...allowedOrigin ? { "Access-Control-Allow-Origin": allowedOrigin, Vary: "Origin" } : {}
|
|
2994
3167
|
});
|
|
2995
3168
|
res.end(req.method === "HEAD" ? void 0 : source);
|
|
2996
3169
|
}
|
|
3170
|
+
function isReplacementModuleRequestUrl(rawUrl) {
|
|
3171
|
+
if (!rawUrl) return false;
|
|
3172
|
+
try {
|
|
3173
|
+
const pathname = new URL(rawUrl, "http://rnx.local").pathname;
|
|
3174
|
+
return pathname === REPLACEMENT_MODULE_ROUTE || pathname.startsWith(`${REPLACEMENT_RUNTIME_PREFIX}/`);
|
|
3175
|
+
} catch {
|
|
3176
|
+
return false;
|
|
3177
|
+
}
|
|
3178
|
+
}
|
|
2997
3179
|
async function handleReplacementModuleRequest(req, res, options = {}) {
|
|
2998
3180
|
const rawUrl = req.url || "";
|
|
2999
3181
|
let url;
|
|
@@ -3002,6 +3184,23 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
|
|
|
3002
3184
|
} catch {
|
|
3003
3185
|
return false;
|
|
3004
3186
|
}
|
|
3187
|
+
if (options.requireLoopbackOrigin) {
|
|
3188
|
+
const origin = req.headers.origin;
|
|
3189
|
+
const remoteAddress = req.socket.remoteAddress?.replace(/^::ffff:/, "");
|
|
3190
|
+
let allowed = Boolean(remoteAddress && isLoopbackHost(remoteAddress));
|
|
3191
|
+
if (allowed && origin) {
|
|
3192
|
+
try {
|
|
3193
|
+
allowed = isLoopbackHost(new URL(origin).hostname);
|
|
3194
|
+
} catch {
|
|
3195
|
+
allowed = false;
|
|
3196
|
+
}
|
|
3197
|
+
}
|
|
3198
|
+
if (!allowed) {
|
|
3199
|
+
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
3200
|
+
res.end("replacement modules are available only to loopback origins");
|
|
3201
|
+
return true;
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3005
3204
|
if (url.pathname === `${REPLACEMENT_RUNTIME_PREFIX}/react`) {
|
|
3006
3205
|
sendJavaScript(req, res, reactRuntimeSource(options.reactBridgeUrl));
|
|
3007
3206
|
return true;
|
|
@@ -3011,6 +3210,11 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
|
|
|
3011
3210
|
return true;
|
|
3012
3211
|
}
|
|
3013
3212
|
if (url.pathname !== REPLACEMENT_MODULE_ROUTE) return false;
|
|
3213
|
+
if (options.requestToken && url.searchParams.get("token") !== options.requestToken) {
|
|
3214
|
+
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
3215
|
+
res.end("replacement module request token is invalid");
|
|
3216
|
+
return true;
|
|
3217
|
+
}
|
|
3014
3218
|
const targetPath = url.searchParams.get("path");
|
|
3015
3219
|
if (!targetPath) {
|
|
3016
3220
|
res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
|
|
@@ -3023,17 +3227,42 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
|
|
|
3023
3227
|
res.end("replacement files must be .js, .jsx, .ts, or .tsx");
|
|
3024
3228
|
return true;
|
|
3025
3229
|
}
|
|
3230
|
+
if (!import_node_path4.default.isAbsolute(targetPath)) {
|
|
3231
|
+
res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
|
|
3232
|
+
res.end("replacement file path must be absolute");
|
|
3233
|
+
return true;
|
|
3234
|
+
}
|
|
3235
|
+
let resolvedProjectRoot;
|
|
3236
|
+
if (options.projectRoot) {
|
|
3237
|
+
const lexicalProjectRoot = import_node_path4.default.resolve(options.projectRoot);
|
|
3238
|
+
resolvedProjectRoot = await import_promises.default.realpath(options.projectRoot);
|
|
3239
|
+
const lexicalTarget = import_node_path4.default.relative(lexicalProjectRoot, targetPath);
|
|
3240
|
+
if (lexicalTarget.startsWith("..") || import_node_path4.default.isAbsolute(lexicalTarget)) {
|
|
3241
|
+
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
3242
|
+
res.end("replacement file must be inside the project root");
|
|
3243
|
+
return true;
|
|
3244
|
+
}
|
|
3245
|
+
}
|
|
3246
|
+
let resolvedTargetPath;
|
|
3026
3247
|
try {
|
|
3027
|
-
await import_promises.default.
|
|
3248
|
+
resolvedTargetPath = await import_promises.default.realpath(targetPath);
|
|
3028
3249
|
} catch (error) {
|
|
3029
3250
|
const message = error instanceof Error ? error.message : String(error);
|
|
3030
3251
|
res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
|
3031
3252
|
res.end(`replacement file not found: ${message}`);
|
|
3032
3253
|
return true;
|
|
3033
3254
|
}
|
|
3255
|
+
if (resolvedProjectRoot) {
|
|
3256
|
+
const relativeTarget = import_node_path4.default.relative(resolvedProjectRoot, resolvedTargetPath);
|
|
3257
|
+
if (relativeTarget.startsWith("..") || import_node_path4.default.isAbsolute(relativeTarget)) {
|
|
3258
|
+
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
3259
|
+
res.end("replacement file must be inside the project root");
|
|
3260
|
+
return true;
|
|
3261
|
+
}
|
|
3262
|
+
}
|
|
3034
3263
|
try {
|
|
3035
3264
|
const result = await (0, import_esbuild.build)({
|
|
3036
|
-
entryPoints: [
|
|
3265
|
+
entryPoints: [resolvedTargetPath],
|
|
3037
3266
|
bundle: true,
|
|
3038
3267
|
write: false,
|
|
3039
3268
|
format: "esm",
|
|
@@ -3220,11 +3449,25 @@ function rnxPlugin(options = {}) {
|
|
|
3220
3449
|
configureServer(server) {
|
|
3221
3450
|
if (options.enabled === false) return;
|
|
3222
3451
|
const bundleUrl = options.bundleUrl || "/node_modules/one/metro-entry.bundle?platform=ios&dev=true&minify=false";
|
|
3452
|
+
const appName = resolveRnxDesktopAppName(options.open, server.config.root);
|
|
3453
|
+
const replacementToken = (0, import_node_crypto2.randomUUID)();
|
|
3454
|
+
const configuredPort = server.config.server.port || 8081;
|
|
3455
|
+
const listeningPort = () => {
|
|
3456
|
+
const address = server.httpServer?.address();
|
|
3457
|
+
return address && typeof address === "object" ? address.port : configuredPort;
|
|
3458
|
+
};
|
|
3459
|
+
const bundleForPort = (port2) => tagRnxBundleForPlugin(
|
|
3460
|
+
bundleUrl,
|
|
3461
|
+
`http://localhost:${port2}`,
|
|
3462
|
+
replacementToken,
|
|
3463
|
+
server.config.root,
|
|
3464
|
+
appName
|
|
3465
|
+
);
|
|
3223
3466
|
const buildShellHtml = (runtimeRoot) => {
|
|
3224
3467
|
const html = import_fs4.default.readFileSync(import_path3.default.join(runtimeRoot, "index.html"), "utf8");
|
|
3225
3468
|
const lock = readDaemonLockfile();
|
|
3226
3469
|
const bridgePort = lock && isDaemonLockfileFresh(lock) && lock.bridgePort > 0 ? lock.bridgePort : DEFAULT_SOOTSIM_BRIDGE_PORT;
|
|
3227
|
-
const inject = `<script>(function(){var u=new URL(location.href);if(!u.searchParams.has('bundle'))u.searchParams.set('bundle',${JSON.stringify(
|
|
3470
|
+
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,'','${prefix2}/'+u.search)})()</script>`;
|
|
3228
3471
|
return html.replace("</head>", inject + "</head>");
|
|
3229
3472
|
};
|
|
3230
3473
|
server.middlewares.use((req, res, next) => {
|
|
@@ -3245,8 +3488,9 @@ function rnxPlugin(options = {}) {
|
|
|
3245
3488
|
});
|
|
3246
3489
|
server.middlewares.use((req, res, next) => {
|
|
3247
3490
|
if ((req.url || "").split("?")[0] !== "/__server-scan") return next();
|
|
3248
|
-
const scanPort =
|
|
3249
|
-
const
|
|
3491
|
+
const scanPort = listeningPort();
|
|
3492
|
+
const pluginBundleUrl = bundleForPort(scanPort);
|
|
3493
|
+
const absoluteBundleUrl = pluginBundleUrl.startsWith("http") ? pluginBundleUrl : `http://localhost:${scanPort}${pluginBundleUrl}`;
|
|
3250
3494
|
res.setHeader("content-type", "application/json");
|
|
3251
3495
|
res.end(
|
|
3252
3496
|
JSON.stringify([
|
|
@@ -3254,13 +3498,18 @@ function rnxPlugin(options = {}) {
|
|
|
3254
3498
|
port: scanPort,
|
|
3255
3499
|
framework: "one",
|
|
3256
3500
|
bundleUrl: absoluteBundleUrl,
|
|
3501
|
+
...appName ? { projectName: appName } : {},
|
|
3257
3502
|
lastSeen: Date.now()
|
|
3258
3503
|
}
|
|
3259
3504
|
])
|
|
3260
3505
|
);
|
|
3261
3506
|
});
|
|
3262
3507
|
server.middlewares.use((req, res, next) => {
|
|
3263
|
-
void handleReplacementModuleRequest(req, res
|
|
3508
|
+
void handleReplacementModuleRequest(req, res, {
|
|
3509
|
+
projectRoot: server.config.root,
|
|
3510
|
+
requestToken: replacementToken,
|
|
3511
|
+
requireLoopbackOrigin: true
|
|
3512
|
+
}).then((handled) => {
|
|
3264
3513
|
if (!handled) next();
|
|
3265
3514
|
});
|
|
3266
3515
|
});
|
|
@@ -3307,23 +3556,16 @@ function rnxPlugin(options = {}) {
|
|
|
3307
3556
|
}
|
|
3308
3557
|
next();
|
|
3309
3558
|
});
|
|
3310
|
-
const port =
|
|
3559
|
+
const port = configuredPort;
|
|
3311
3560
|
const sootsimUrl = `http://localhost:${port}${prefix2}/`;
|
|
3312
3561
|
console.log(`[rnx] serving at ${sootsimUrl}`);
|
|
3313
|
-
if (
|
|
3562
|
+
if (appName && !process.env.CI && !process.env.SOOTSIM_NO_OPEN) {
|
|
3314
3563
|
server.httpServer?.once("listening", () => {
|
|
3315
|
-
const
|
|
3316
|
-
|
|
3317
|
-
|
|
3564
|
+
const openPort = listeningPort();
|
|
3565
|
+
launchRnxDesktop(
|
|
3566
|
+
resolveRnxDesktopLaunchTarget(openPort, bundleForPort(openPort)),
|
|
3567
|
+
appName
|
|
3318
3568
|
);
|
|
3319
|
-
const binPath = import_path3.default.join(packageRoot, "dist-cli", "bin.js");
|
|
3320
|
-
const openPort = server.config.server.port || port;
|
|
3321
|
-
console.log(`[rnx] opening simulator for :${openPort}`);
|
|
3322
|
-
(0, import_child_process2.spawn)(process.execPath, [binPath, "open", String(openPort)], {
|
|
3323
|
-
detached: true,
|
|
3324
|
-
stdio: "ignore",
|
|
3325
|
-
windowsHide: true
|
|
3326
|
-
}).unref();
|
|
3327
3569
|
});
|
|
3328
3570
|
}
|
|
3329
3571
|
}
|
|
@@ -3333,6 +3575,7 @@ function rnxPlugin(options = {}) {
|
|
|
3333
3575
|
// src/metro-plugin.ts
|
|
3334
3576
|
var import_fs5 = __toESM(require("fs"), 1);
|
|
3335
3577
|
var import_module2 = require("module");
|
|
3578
|
+
var import_node_crypto3 = require("node:crypto");
|
|
3336
3579
|
var import_path4 = __toESM(require("path"), 1);
|
|
3337
3580
|
|
|
3338
3581
|
// src/metro-production-bundle.ts
|
|
@@ -3423,12 +3666,22 @@ function prependRNXModulePaths(result, graph, options, projectRoot) {
|
|
|
3423
3666
|
return typeof result === "string" ? result + footer : { ...result, code: result.code + footer };
|
|
3424
3667
|
}
|
|
3425
3668
|
function withRNX(config, options = {}) {
|
|
3426
|
-
if (!options.devServer && !options.productionBundles) return config;
|
|
3427
|
-
const
|
|
3669
|
+
if (!options.devServer && !options.open && !options.productionBundles) return config;
|
|
3670
|
+
const cfgProjectRoot = config.projectRoot || process.cwd();
|
|
3671
|
+
const appName = resolveRnxDesktopAppName(options.open, cfgProjectRoot);
|
|
3672
|
+
const configuredBundleUrl = options.bundleUrl || "/index.bundle?platform=ios&dev=true&hot=true&minify=false";
|
|
3428
3673
|
const cfgServer = config.server;
|
|
3674
|
+
const port = resolveMetroPort(cfgServer);
|
|
3675
|
+
const metroServerId = (0, import_node_crypto3.randomUUID)();
|
|
3676
|
+
const bundleUrl = tagRnxBundleForPlugin(
|
|
3677
|
+
configuredBundleUrl,
|
|
3678
|
+
`http://localhost:${port}`,
|
|
3679
|
+
metroServerId,
|
|
3680
|
+
cfgProjectRoot,
|
|
3681
|
+
appName
|
|
3682
|
+
);
|
|
3429
3683
|
const cfgResolver = config.resolver;
|
|
3430
3684
|
const cfgSerializer = config.serializer;
|
|
3431
|
-
const cfgProjectRoot = config.projectRoot || process.cwd();
|
|
3432
3685
|
const existingEnhance = cfgServer?.enhanceMiddleware;
|
|
3433
3686
|
const existingResolveRequest = cfgResolver?.resolveRequest;
|
|
3434
3687
|
const existingSerializer = cfgSerializer?.customSerializer;
|
|
@@ -3485,8 +3738,35 @@ function withRNX(config, options = {}) {
|
|
|
3485
3738
|
}
|
|
3486
3739
|
const server = connect2();
|
|
3487
3740
|
server.use((req, res, next) => {
|
|
3741
|
+
if (isReplacementModuleRequestUrl(req.url)) {
|
|
3742
|
+
void handleReplacementModuleRequest(req, res, {
|
|
3743
|
+
projectRoot: cfgProjectRoot,
|
|
3744
|
+
requestToken: metroServerId,
|
|
3745
|
+
requireLoopbackOrigin: true
|
|
3746
|
+
}).then((handled) => {
|
|
3747
|
+
if (!handled) next();
|
|
3748
|
+
});
|
|
3749
|
+
return;
|
|
3750
|
+
}
|
|
3488
3751
|
const url = req.url || "";
|
|
3489
3752
|
const pathname = url.split("?")[0];
|
|
3753
|
+
if (pathname === "/__server-scan") {
|
|
3754
|
+
const absoluteBundleUrl = bundleUrl.startsWith("http") ? bundleUrl : `http://localhost:${port}${bundleUrl}`;
|
|
3755
|
+
res.setHeader("content-type", "application/json");
|
|
3756
|
+
res.end(
|
|
3757
|
+
JSON.stringify([
|
|
3758
|
+
{
|
|
3759
|
+
port,
|
|
3760
|
+
framework: "metro",
|
|
3761
|
+
rnxServerId: metroServerId,
|
|
3762
|
+
bundleUrl: absoluteBundleUrl,
|
|
3763
|
+
...appName ? { projectName: appName } : {},
|
|
3764
|
+
lastSeen: Date.now()
|
|
3765
|
+
}
|
|
3766
|
+
])
|
|
3767
|
+
);
|
|
3768
|
+
return;
|
|
3769
|
+
}
|
|
3490
3770
|
const runtimeRoot = resolveRuntimeRootForRequestHost(req.headers?.host);
|
|
3491
3771
|
if (!runtimeRoot) {
|
|
3492
3772
|
if (pathname === prefix || pathname === prefix + "/") {
|
|
@@ -3521,7 +3801,7 @@ function withRNX(config, options = {}) {
|
|
|
3521
3801
|
let html = import_fs5.default.readFileSync(htmlPath, "utf8");
|
|
3522
3802
|
html = html.replace(
|
|
3523
3803
|
"</head>",
|
|
3524
|
-
`<script>history.replaceState(null,'','${prefix}
|
|
3804
|
+
`<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>`
|
|
3525
3805
|
);
|
|
3526
3806
|
res.setHeader("content-type", "text/html");
|
|
3527
3807
|
res.end(html);
|
|
@@ -3535,22 +3815,42 @@ function withRNX(config, options = {}) {
|
|
|
3535
3815
|
return server;
|
|
3536
3816
|
}
|
|
3537
3817
|
};
|
|
3818
|
+
if (appName && !process.env.CI && !process.env.SOOTSIM_NO_OPEN) {
|
|
3819
|
+
void openRnxDesktopWhenMetroIsReady({
|
|
3820
|
+
port,
|
|
3821
|
+
bundleUrl: resolveRnxDesktopLaunchTarget(port, bundleUrl),
|
|
3822
|
+
appName,
|
|
3823
|
+
projectRoot: cfgProjectRoot,
|
|
3824
|
+
serverId: metroServerId
|
|
3825
|
+
});
|
|
3826
|
+
}
|
|
3538
3827
|
return {
|
|
3539
3828
|
...config,
|
|
3540
3829
|
...productionConfig,
|
|
3541
|
-
...options.devServer ? { server: serverConfig } : {}
|
|
3830
|
+
...options.devServer || options.open ? { server: serverConfig } : {}
|
|
3542
3831
|
};
|
|
3543
3832
|
}
|
|
3833
|
+
function resolveMetroPort(server) {
|
|
3834
|
+
const inlinePort = process.argv.find((arg) => arg.startsWith("--port="))?.slice(7);
|
|
3835
|
+
const portIndex = process.argv.indexOf("--port");
|
|
3836
|
+
const splitPort = portIndex >= 0 ? process.argv[portIndex + 1] : void 0;
|
|
3837
|
+
const rawPort = inlinePort || splitPort || process.env.RCT_METRO_PORT || server?.port || 8081;
|
|
3838
|
+
const port = Number(rawPort);
|
|
3839
|
+
if (!Number.isInteger(port) || port <= 0) {
|
|
3840
|
+
throw new Error(`rnx: Metro port must be a positive integer, got ${rawPort}`);
|
|
3841
|
+
}
|
|
3842
|
+
return port;
|
|
3843
|
+
}
|
|
3544
3844
|
var metro_plugin_default = withRNX;
|
|
3545
3845
|
|
|
3546
3846
|
// src/jump-to-source-babel.ts
|
|
3547
|
-
function normalizeSourcePath(
|
|
3548
|
-
const queryStart =
|
|
3549
|
-
const clean = queryStart >= 0 ?
|
|
3847
|
+
function normalizeSourcePath(path8) {
|
|
3848
|
+
const queryStart = path8.indexOf("?");
|
|
3849
|
+
const clean = queryStart >= 0 ? path8.slice(0, queryStart) : path8;
|
|
3550
3850
|
return clean.replace(/\\/g, "/");
|
|
3551
3851
|
}
|
|
3552
|
-
function matchesPath(
|
|
3553
|
-
return typeof matcher === "string" ?
|
|
3852
|
+
function matchesPath(path8, matcher) {
|
|
3853
|
+
return typeof matcher === "string" ? path8.includes(matcher) : matcher.test(path8);
|
|
3554
3854
|
}
|
|
3555
3855
|
function shouldStampFile(filename, options) {
|
|
3556
3856
|
const normalized = normalizeSourcePath(filename);
|
|
@@ -3583,11 +3883,11 @@ function sootsimJumpToSourceBabelPlugin(api, options = {}) {
|
|
|
3583
3883
|
return {
|
|
3584
3884
|
name: "sootsim-jump-to-source",
|
|
3585
3885
|
visitor: {
|
|
3586
|
-
JSXOpeningElement(
|
|
3886
|
+
JSXOpeningElement(path8, state) {
|
|
3587
3887
|
if (options.enabled === false) return;
|
|
3588
3888
|
const filename = state.file?.opts?.filename;
|
|
3589
3889
|
if (!filename || !shouldStampFile(filename, options)) return;
|
|
3590
|
-
const node =
|
|
3890
|
+
const node = path8.node;
|
|
3591
3891
|
const tagName = getJSXName(node.name);
|
|
3592
3892
|
if (!tagName || tagName === "Fragment" || tagName.endsWith(".Fragment")) return;
|
|
3593
3893
|
if (hasAttribute(node, attrName)) return;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.345 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __defProp = Object.defineProperty;
|
package/dist-lib/menu.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.345 | (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;
|