rnxsim 0.1.455 → 0.1.456
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/cli/cloud-client.ts +3 -1
- package/cli/cloud-dispatch.ts +17 -0
- package/cli/commands/do-chain.ts +1 -4
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +1 -1
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +541 -227
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +368 -39
- package/dist-lib/vite.cjs +1 -1
- package/package.json +1 -1
- package/skills/rnx-debug/SKILL.md +1 -1
- package/src/bridge-contract.ts +2 -1
- package/src/connect.ts +18 -0
package/dist-lib/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.456 | (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;
|
|
@@ -56,6 +56,514 @@ __export(src_exports, {
|
|
|
56
56
|
});
|
|
57
57
|
module.exports = __toCommonJS(src_exports);
|
|
58
58
|
|
|
59
|
+
// cli/cloud-client.ts
|
|
60
|
+
var import_node_crypto = require("node:crypto");
|
|
61
|
+
|
|
62
|
+
// ../sootsim-engine/src/metro-fingerprint-registry-client.ts
|
|
63
|
+
var import_metro_fingerprint_registry = require("rnxsim/metro-fingerprint-registry");
|
|
64
|
+
|
|
65
|
+
// ../sootsim-engine/src/metro-fingerprint.ts
|
|
66
|
+
var import_metro_production_bundle = require("rnxsim/metro-production-bundle");
|
|
67
|
+
var import_react_native_host_modules = require("rnxsim/react-native-host-modules");
|
|
68
|
+
|
|
69
|
+
// src/backend-origin.ts
|
|
70
|
+
function normalizeHostname(hostname) {
|
|
71
|
+
return hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
72
|
+
}
|
|
73
|
+
function isLoopbackHost(hostname) {
|
|
74
|
+
const normalized = normalizeHostname(hostname);
|
|
75
|
+
return normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "0.0.0.0" || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// src/cloud-contract.ts
|
|
79
|
+
var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
|
|
80
|
+
var RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES = 1024 * 1024;
|
|
81
|
+
var RNX_CLOUD_COMMAND_TYPES = Object.freeze([
|
|
82
|
+
"state",
|
|
83
|
+
"query",
|
|
84
|
+
"resolve",
|
|
85
|
+
"perform",
|
|
86
|
+
"waitFor",
|
|
87
|
+
"reset",
|
|
88
|
+
"screenshot",
|
|
89
|
+
"capture",
|
|
90
|
+
"captureRegions",
|
|
91
|
+
"settle",
|
|
92
|
+
"setAppearance",
|
|
93
|
+
"openUrl",
|
|
94
|
+
"tree",
|
|
95
|
+
"tap",
|
|
96
|
+
"longPress",
|
|
97
|
+
"memory",
|
|
98
|
+
"diagnostics"
|
|
99
|
+
]);
|
|
100
|
+
var RNX_CLOUD_COMMAND_TYPE_SET = new Set(RNX_CLOUD_COMMAND_TYPES);
|
|
101
|
+
function isRnxCloudCommandType(value) {
|
|
102
|
+
return RNX_CLOUD_COMMAND_TYPE_SET.has(value);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// src/metro-production-bundle.ts
|
|
106
|
+
var RNXSIM_METRO_MODULE_PATHS_PREFIX = "globalThis.__sootsimModulePaths=";
|
|
107
|
+
var RNX_METRO_MODULE_IDENTITY_VERSION = 2;
|
|
108
|
+
var RNXSIM_METRO_SOURCE_MAP_COMMENT = "//# sourceMappingURL=";
|
|
109
|
+
function detachRNXMetroSourceMapUrl(bundleText) {
|
|
110
|
+
const trimmedEnd = bundleText.replace(/\s+$/, "");
|
|
111
|
+
const commentStart = trimmedEnd.lastIndexOf(`
|
|
112
|
+
${RNXSIM_METRO_SOURCE_MAP_COMMENT}`);
|
|
113
|
+
if (commentStart < 0) return { source: bundleText, sourceMappingUrl: null };
|
|
114
|
+
const url = trimmedEnd.slice(commentStart + 1 + RNXSIM_METRO_SOURCE_MAP_COMMENT.length);
|
|
115
|
+
if (url.includes("\n")) return { source: bundleText, sourceMappingUrl: null };
|
|
116
|
+
return { source: trimmedEnd.slice(0, commentStart), sourceMappingUrl: url };
|
|
117
|
+
}
|
|
118
|
+
function createRNXMetroModuleIdentityFooter(identity) {
|
|
119
|
+
const payload = JSON.stringify(identity).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029").replace(/<\//g, "<\\/");
|
|
120
|
+
return `
|
|
121
|
+
${RNXSIM_METRO_MODULE_PATHS_PREFIX}${payload};`;
|
|
122
|
+
}
|
|
123
|
+
function appendRNXMetroModuleIdentityFooter(bundleText, identity) {
|
|
124
|
+
const footer = createRNXMetroModuleIdentityFooter(identity);
|
|
125
|
+
const detached = detachRNXMetroSourceMapUrl(bundleText);
|
|
126
|
+
return detached.sourceMappingUrl === null ? bundleText + footer : `${detached.source}${footer}
|
|
127
|
+
${RNXSIM_METRO_SOURCE_MAP_COMMENT}${detached.sourceMappingUrl}`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/public-brand.ts
|
|
131
|
+
var name = "rnx";
|
|
132
|
+
var rnxPublicBrand = Object.freeze({
|
|
133
|
+
name,
|
|
134
|
+
packageName: "rnxsim",
|
|
135
|
+
commandName: "rnx",
|
|
136
|
+
domain: "rnxsim.com",
|
|
137
|
+
origin: "https://rnxsim.com"
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// src/home-paths.ts
|
|
141
|
+
var import_node_fs = __toESM(require("node:fs"), 1);
|
|
142
|
+
var import_node_os = require("node:os");
|
|
143
|
+
var import_node_path = __toESM(require("node:path"), 1);
|
|
144
|
+
var RNX_HOME_ENV = "RNX_HOME";
|
|
145
|
+
var ACTIVE_RUNTIME_FILE = "active";
|
|
146
|
+
var DAEMON_LOCKFILE = "daemon.json";
|
|
147
|
+
var DEV_BRIDGES_DIR = "dev-bridges";
|
|
148
|
+
var DAEMON_HEARTBEAT_STALE_MS = 3e4;
|
|
149
|
+
function rnxHomeDir() {
|
|
150
|
+
const override = process.env[RNX_HOME_ENV];
|
|
151
|
+
if (override && override.length > 0) return import_node_path.default.resolve(override);
|
|
152
|
+
return import_node_path.default.join((0, import_node_os.homedir)(), ".rnx");
|
|
153
|
+
}
|
|
154
|
+
function runtimesDir() {
|
|
155
|
+
return import_node_path.default.join(rnxHomeDir(), "runtimes");
|
|
156
|
+
}
|
|
157
|
+
function runtimeDir(version) {
|
|
158
|
+
return import_node_path.default.join(runtimesDir(), version);
|
|
159
|
+
}
|
|
160
|
+
function activeRuntimeFile() {
|
|
161
|
+
return import_node_path.default.join(runtimesDir(), ACTIVE_RUNTIME_FILE);
|
|
162
|
+
}
|
|
163
|
+
function daemonLockfilePath() {
|
|
164
|
+
return import_node_path.default.join(rnxHomeDir(), DAEMON_LOCKFILE);
|
|
165
|
+
}
|
|
166
|
+
function devBridgesDir() {
|
|
167
|
+
return import_node_path.default.join(rnxHomeDir(), DEV_BRIDGES_DIR);
|
|
168
|
+
}
|
|
169
|
+
function readActiveRuntime() {
|
|
170
|
+
try {
|
|
171
|
+
const value = import_node_fs.default.readFileSync(activeRuntimeFile(), "utf8").trim();
|
|
172
|
+
return value.length > 0 ? value : null;
|
|
173
|
+
} catch {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
var DAEMON_LOCKFILE_MAX_BYTES = 16 * 1024;
|
|
178
|
+
function readDaemonLockfile() {
|
|
179
|
+
try {
|
|
180
|
+
const fd = import_node_fs.default.openSync(daemonLockfilePath(), "r");
|
|
181
|
+
try {
|
|
182
|
+
const buf = Buffer.alloc(DAEMON_LOCKFILE_MAX_BYTES);
|
|
183
|
+
const bytesRead = import_node_fs.default.readSync(fd, buf, 0, DAEMON_LOCKFILE_MAX_BYTES, 0);
|
|
184
|
+
const raw = buf.subarray(0, bytesRead).toString("utf8");
|
|
185
|
+
const parsed = JSON.parse(raw);
|
|
186
|
+
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"))) {
|
|
187
|
+
return parsed;
|
|
188
|
+
}
|
|
189
|
+
return null;
|
|
190
|
+
} finally {
|
|
191
|
+
import_node_fs.default.closeSync(fd);
|
|
192
|
+
}
|
|
193
|
+
} catch {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function parseDevBridgeLockfile(raw) {
|
|
198
|
+
try {
|
|
199
|
+
const parsed = JSON.parse(raw);
|
|
200
|
+
if (parsed && parsed.schema === 1 && parsed.source === "vite-dev" && typeof parsed.pid === "number" && typeof parsed.bridgePort === "number" && typeof parsed.runtimePort === "number" && typeof parsed.cwd === "string" && typeof parsed.startedAt === "number" && typeof parsed.heartbeatAt === "number" && (parsed.shellPort === void 0 || typeof parsed.shellPort === "number") && (parsed.servedRuntimes === void 0 || Array.isArray(parsed.servedRuntimes) && parsed.servedRuntimes.every((version) => typeof version === "string"))) {
|
|
201
|
+
return parsed;
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
204
|
+
} catch {
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function readDevBridgeLockfiles() {
|
|
209
|
+
let entries;
|
|
210
|
+
try {
|
|
211
|
+
entries = import_node_fs.default.readdirSync(devBridgesDir(), { withFileTypes: true });
|
|
212
|
+
} catch {
|
|
213
|
+
return [];
|
|
214
|
+
}
|
|
215
|
+
const lockfiles = [];
|
|
216
|
+
for (const entry of entries) {
|
|
217
|
+
if (!entry.isFile() || !/^\d+\.json$/.test(entry.name)) continue;
|
|
218
|
+
try {
|
|
219
|
+
const filePath = import_node_path.default.join(devBridgesDir(), entry.name);
|
|
220
|
+
const fd = import_node_fs.default.openSync(filePath, "r");
|
|
221
|
+
try {
|
|
222
|
+
const buf = Buffer.alloc(DAEMON_LOCKFILE_MAX_BYTES);
|
|
223
|
+
const bytesRead = import_node_fs.default.readSync(fd, buf, 0, DAEMON_LOCKFILE_MAX_BYTES, 0);
|
|
224
|
+
const lockfile = parseDevBridgeLockfile(
|
|
225
|
+
buf.subarray(0, bytesRead).toString("utf8")
|
|
226
|
+
);
|
|
227
|
+
if (lockfile && entry.name === `${lockfile.bridgePort}.json`) {
|
|
228
|
+
lockfiles.push(lockfile);
|
|
229
|
+
}
|
|
230
|
+
} finally {
|
|
231
|
+
import_node_fs.default.closeSync(fd);
|
|
232
|
+
}
|
|
233
|
+
} catch {
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return lockfiles.sort((left, right) => left.bridgePort - right.bridgePort);
|
|
237
|
+
}
|
|
238
|
+
function isDaemonLockfileFresh(lock, now = Date.now()) {
|
|
239
|
+
if (!lock) return false;
|
|
240
|
+
if (now - lock.heartbeatAt > DAEMON_HEARTBEAT_STALE_MS) return false;
|
|
241
|
+
try {
|
|
242
|
+
process.kill(lock.pid, 0);
|
|
243
|
+
return true;
|
|
244
|
+
} catch {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function isDevBridgeLockfileFresh(lock, now = Date.now()) {
|
|
249
|
+
if (!lock) return false;
|
|
250
|
+
if (now - lock.heartbeatAt > DAEMON_HEARTBEAT_STALE_MS) return false;
|
|
251
|
+
try {
|
|
252
|
+
process.kill(lock.pid, 0);
|
|
253
|
+
return true;
|
|
254
|
+
} catch {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// cli/run-rnx.ts
|
|
260
|
+
var import_node_async_hooks = require("node:async_hooks");
|
|
261
|
+
var sinks = new import_node_async_hooks.AsyncLocalStorage();
|
|
262
|
+
|
|
263
|
+
// cli/auth.ts
|
|
264
|
+
var CHOOSE_ACCOUNT_HINT = "this sign-in belongs to several accounts; run `rnx login --account <name>` to choose the one to bill";
|
|
265
|
+
|
|
266
|
+
// cli/cloud-session.ts
|
|
267
|
+
var CLOUD_SESSION_VERSION = 3;
|
|
268
|
+
var MAX_ENCODED_SESSION_BYTES = 32 * 1024;
|
|
269
|
+
var RNX_CLOUD_SESSION_ENV = "RNX_CLOUD_SESSION";
|
|
270
|
+
var RNX_SHELL_UPDATE_PREFIX = "__RNX_SHELL_UPDATE_V1__";
|
|
271
|
+
var RNX_SHELL_UPDATE_SET_PREFIX = `${RNX_SHELL_UPDATE_PREFIX}set:`;
|
|
272
|
+
var RNX_SHELL_UPDATE_UNSET = `${RNX_SHELL_UPDATE_PREFIX}unset`;
|
|
273
|
+
function isRecord(value) {
|
|
274
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
275
|
+
}
|
|
276
|
+
function normalizeCloudOrigin(source) {
|
|
277
|
+
let parsed;
|
|
278
|
+
try {
|
|
279
|
+
parsed = new URL(source);
|
|
280
|
+
} catch {
|
|
281
|
+
throw new Error(`invalid remote simulator origin: ${source}`);
|
|
282
|
+
}
|
|
283
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:" || parsed.username || parsed.password || parsed.pathname !== "/" || parsed.search || parsed.hash) {
|
|
284
|
+
throw new Error(`remote simulator origin must be an HTTP(S) origin: ${source}`);
|
|
285
|
+
}
|
|
286
|
+
if (parsed.protocol === "http:" && !isLoopbackHost(parsed.hostname)) {
|
|
287
|
+
throw new Error(`remote simulator origin requires HTTPS outside loopback: ${source}`);
|
|
288
|
+
}
|
|
289
|
+
return parsed.origin;
|
|
290
|
+
}
|
|
291
|
+
function createCloudSession(input) {
|
|
292
|
+
const session = {
|
|
293
|
+
version: CLOUD_SESSION_VERSION,
|
|
294
|
+
service: "sim",
|
|
295
|
+
boxId: input.boxId.trim(),
|
|
296
|
+
boxToken: input.boxToken,
|
|
297
|
+
simId: input.simId.trim(),
|
|
298
|
+
apiOrigin: normalizeCloudOrigin(input.apiOrigin.trim()),
|
|
299
|
+
claimId: input.claimId.trim(),
|
|
300
|
+
token: input.token
|
|
301
|
+
};
|
|
302
|
+
if (!session.boxId || !session.boxToken || !session.simId || !session.claimId || !session.token) {
|
|
303
|
+
throw new Error("cloud session requires box, simulator, origin, claim, and tokens");
|
|
304
|
+
}
|
|
305
|
+
return session;
|
|
306
|
+
}
|
|
307
|
+
function createCloudBoxSession(input) {
|
|
308
|
+
const session = {
|
|
309
|
+
version: CLOUD_SESSION_VERSION,
|
|
310
|
+
service: "box",
|
|
311
|
+
boxId: input.boxId.trim(),
|
|
312
|
+
boxToken: input.boxToken,
|
|
313
|
+
apiOrigin: normalizeCloudOrigin(input.apiOrigin.trim())
|
|
314
|
+
};
|
|
315
|
+
if (!session.boxId || !session.boxToken) {
|
|
316
|
+
throw new Error("cloud box session requires a box, an origin, and a box token");
|
|
317
|
+
}
|
|
318
|
+
return session;
|
|
319
|
+
}
|
|
320
|
+
function parseCloudSession(encoded) {
|
|
321
|
+
const value = encoded.trim();
|
|
322
|
+
if (!value || value.length > MAX_ENCODED_SESSION_BYTES || !/^[A-Za-z0-9_-]+$/.test(value)) {
|
|
323
|
+
throw new Error(`${RNX_CLOUD_SESSION_ENV} is invalid`);
|
|
324
|
+
}
|
|
325
|
+
let parsed;
|
|
326
|
+
try {
|
|
327
|
+
const bytes = Buffer.from(value, "base64url");
|
|
328
|
+
if (bytes.toString("base64url") !== value) {
|
|
329
|
+
throw new Error("non-canonical cloud session");
|
|
330
|
+
}
|
|
331
|
+
parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
332
|
+
} catch {
|
|
333
|
+
throw new Error(`${RNX_CLOUD_SESSION_ENV} is invalid`);
|
|
334
|
+
}
|
|
335
|
+
if (!isRecord(parsed) || parsed.version !== CLOUD_SESSION_VERSION) {
|
|
336
|
+
throw new Error(`${RNX_CLOUD_SESSION_ENV} is invalid`);
|
|
337
|
+
}
|
|
338
|
+
const boxId = parsed.boxId;
|
|
339
|
+
const boxToken = parsed.boxToken;
|
|
340
|
+
const apiOrigin = parsed.apiOrigin;
|
|
341
|
+
if (typeof boxId !== "string" || typeof boxToken !== "string" || typeof apiOrigin !== "string") {
|
|
342
|
+
throw new Error(`${RNX_CLOUD_SESSION_ENV} is invalid`);
|
|
343
|
+
}
|
|
344
|
+
try {
|
|
345
|
+
if (parsed.service === "box") {
|
|
346
|
+
return createCloudBoxSession({ boxId, boxToken, apiOrigin });
|
|
347
|
+
}
|
|
348
|
+
const simId = parsed.simId;
|
|
349
|
+
const claimId = parsed.claimId;
|
|
350
|
+
const token = parsed.token;
|
|
351
|
+
if (parsed.service !== "sim" || typeof simId !== "string" || typeof claimId !== "string" || typeof token !== "string") {
|
|
352
|
+
throw new Error("unreadable cloud session");
|
|
353
|
+
}
|
|
354
|
+
return createCloudSession({ boxId, boxToken, simId, apiOrigin, claimId, token });
|
|
355
|
+
} catch {
|
|
356
|
+
throw new Error(`${RNX_CLOUD_SESSION_ENV} is invalid`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
function readCloudSession(environment = process.env) {
|
|
360
|
+
const encoded = environment[RNX_CLOUD_SESSION_ENV];
|
|
361
|
+
return encoded?.trim() ? parseCloudSession(encoded) : null;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// cli/cloud-client.ts
|
|
365
|
+
var DEFAULT_RNX_CLOUD_ORIGIN = rnxPublicBrand.origin;
|
|
366
|
+
function isRecord2(value) {
|
|
367
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
368
|
+
}
|
|
369
|
+
function failureSentence(text) {
|
|
370
|
+
let parsed;
|
|
371
|
+
try {
|
|
372
|
+
parsed = JSON.parse(text);
|
|
373
|
+
} catch {
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
if (!isRecord2(parsed)) return null;
|
|
377
|
+
if (isRecord2(parsed.error) && typeof parsed.error.message === "string") {
|
|
378
|
+
return parsed.error.message;
|
|
379
|
+
}
|
|
380
|
+
if (typeof parsed.message === "string") return parsed.message;
|
|
381
|
+
if (typeof parsed.error === "string") return parsed.error;
|
|
382
|
+
return null;
|
|
383
|
+
}
|
|
384
|
+
var ACCOUNT_CHOICE_REFUSALS = /* @__PURE__ */ new Set([
|
|
385
|
+
"accountId is required",
|
|
386
|
+
"you do not have access to this account"
|
|
387
|
+
]);
|
|
388
|
+
function responseError(status, text) {
|
|
389
|
+
const parsed = text ? failureSentence(text) : null;
|
|
390
|
+
const sentence = parsed && ACCOUNT_CHOICE_REFUSALS.has(parsed) ? CHOOSE_ACCOUNT_HINT : parsed;
|
|
391
|
+
return new Error(
|
|
392
|
+
`remote simulator request failed (${status})${sentence ? `: ${sentence}` : text.trim() ? `: ${text.trim()}` : ""}`
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
function resolveCloudSessionForParsed(parsed) {
|
|
396
|
+
const session = readCloudSession();
|
|
397
|
+
if (!session) return null;
|
|
398
|
+
if (session.service === "box") {
|
|
399
|
+
if (parsed.simIdSource === "flag" && parsed.simId !== session.boxId) {
|
|
400
|
+
throw new Error(
|
|
401
|
+
`this shell is connected to box ${session.boxId}; ${parsed.simId ? `--sim ${parsed.simId}` : "the requested simulator"} is not available in this shell`
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
return session;
|
|
405
|
+
}
|
|
406
|
+
if (parsed.simIdSource === "flag" && parsed.simId !== session.simId) {
|
|
407
|
+
throw new Error(
|
|
408
|
+
`this shell is connected to remote simulator ${session.simId}; ${parsed.simId ? `--sim ${parsed.simId}` : "the requested simulator"} is not available in this shell`
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
return session;
|
|
412
|
+
}
|
|
413
|
+
function cloudCommand(command) {
|
|
414
|
+
const clean = {};
|
|
415
|
+
for (const [key, value] of Object.entries(command)) {
|
|
416
|
+
if (key !== "id" && key !== "simId") clean[key] = value;
|
|
417
|
+
}
|
|
418
|
+
if (isRnxCloudCommandType(command.type)) return clean;
|
|
419
|
+
throw new Error(
|
|
420
|
+
`a remote simulator does not support bridge command type ${command.type}`
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
var CloudBridge = class {
|
|
424
|
+
constructor(session) {
|
|
425
|
+
this.session = session;
|
|
426
|
+
}
|
|
427
|
+
plane = "cloud";
|
|
428
|
+
async send(command, options) {
|
|
429
|
+
const body = {
|
|
430
|
+
id: (0, import_node_crypto.randomUUID)(),
|
|
431
|
+
claimId: this.session.claimId,
|
|
432
|
+
command: cloudCommand(command)
|
|
433
|
+
};
|
|
434
|
+
let response;
|
|
435
|
+
try {
|
|
436
|
+
response = await fetch(
|
|
437
|
+
`${this.session.apiOrigin}/v1/sims/${encodeURIComponent(this.session.simId)}/commands`,
|
|
438
|
+
{
|
|
439
|
+
method: "POST",
|
|
440
|
+
headers: {
|
|
441
|
+
authorization: `Bearer ${this.session.token}`,
|
|
442
|
+
"content-type": "application/json"
|
|
443
|
+
},
|
|
444
|
+
body: JSON.stringify(body),
|
|
445
|
+
...options?.timeoutMs ? { signal: AbortSignal.timeout(options.timeoutMs) } : {}
|
|
446
|
+
}
|
|
447
|
+
);
|
|
448
|
+
} catch (error) {
|
|
449
|
+
throw new Error(
|
|
450
|
+
`could not reach the remote simulator at ${this.session.apiOrigin}: ${error instanceof Error ? error.message : String(error)}`
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
const text = await response.text();
|
|
454
|
+
if (!response.ok) throw responseError(response.status, text);
|
|
455
|
+
let parsed;
|
|
456
|
+
try {
|
|
457
|
+
parsed = JSON.parse(text);
|
|
458
|
+
} catch {
|
|
459
|
+
throw new Error("remote simulator command returned unreadable JSON");
|
|
460
|
+
}
|
|
461
|
+
if (!isRecord2(parsed) || parsed.id !== body.id) {
|
|
462
|
+
throw new Error("remote simulator command returned an invalid command receipt");
|
|
463
|
+
}
|
|
464
|
+
if (typeof parsed.error === "string" && parsed.error) throw new Error(parsed.error);
|
|
465
|
+
if (!Object.hasOwn(parsed, "result")) {
|
|
466
|
+
throw new Error("remote simulator command receipt has no result");
|
|
467
|
+
}
|
|
468
|
+
return parsed.result;
|
|
469
|
+
}
|
|
470
|
+
listSims() {
|
|
471
|
+
return Promise.reject(
|
|
472
|
+
new Error("a remote simulator does not expose a local simulator list")
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
focusSim() {
|
|
476
|
+
return Promise.reject(new Error("remote simulators have no browser window to focus"));
|
|
477
|
+
}
|
|
478
|
+
resolveReloadedSim() {
|
|
479
|
+
return Promise.resolve(null);
|
|
480
|
+
}
|
|
481
|
+
closeSim() {
|
|
482
|
+
return Promise.reject(
|
|
483
|
+
new Error("remote simulator close uses the simulator DELETE route")
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
claim() {
|
|
487
|
+
return Promise.reject(
|
|
488
|
+
new Error("remote simulator claim uses the simulator claim route")
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
close() {
|
|
492
|
+
}
|
|
493
|
+
};
|
|
494
|
+
var CloudBoxBridge = class {
|
|
495
|
+
constructor(session) {
|
|
496
|
+
this.session = session;
|
|
497
|
+
}
|
|
498
|
+
plane = "cloud";
|
|
499
|
+
async send(command, options) {
|
|
500
|
+
const id = (0, import_node_crypto.randomUUID)();
|
|
501
|
+
const payload = {};
|
|
502
|
+
for (const [key, value] of Object.entries(command)) {
|
|
503
|
+
if (key !== "id" && key !== "simId") payload[key] = value;
|
|
504
|
+
}
|
|
505
|
+
let response;
|
|
506
|
+
try {
|
|
507
|
+
response = await fetch(
|
|
508
|
+
`${this.session.apiOrigin}/v1/boxes/${encodeURIComponent(this.session.boxId)}/commands`,
|
|
509
|
+
{
|
|
510
|
+
method: "POST",
|
|
511
|
+
headers: {
|
|
512
|
+
authorization: `Bearer ${this.session.boxToken}`,
|
|
513
|
+
"content-type": "application/json"
|
|
514
|
+
},
|
|
515
|
+
body: JSON.stringify({ id, command: payload }),
|
|
516
|
+
...options?.timeoutMs ? { signal: AbortSignal.timeout(options.timeoutMs) } : {}
|
|
517
|
+
}
|
|
518
|
+
);
|
|
519
|
+
} catch (error) {
|
|
520
|
+
throw new Error(
|
|
521
|
+
`could not reach box ${this.session.boxId} at ${this.session.apiOrigin}: ${error instanceof Error ? error.message : String(error)}`
|
|
522
|
+
);
|
|
523
|
+
}
|
|
524
|
+
const text = await response.text();
|
|
525
|
+
if (!response.ok) throw responseError(response.status, text);
|
|
526
|
+
let parsed;
|
|
527
|
+
try {
|
|
528
|
+
parsed = JSON.parse(text);
|
|
529
|
+
} catch {
|
|
530
|
+
throw new Error("box command returned unreadable JSON");
|
|
531
|
+
}
|
|
532
|
+
if (!isRecord2(parsed) || parsed.id !== id) {
|
|
533
|
+
throw new Error("box command returned an invalid command receipt");
|
|
534
|
+
}
|
|
535
|
+
if (typeof parsed.error === "string" && parsed.error) throw new Error(parsed.error);
|
|
536
|
+
if (!Object.hasOwn(parsed, "result")) {
|
|
537
|
+
throw new Error("box command receipt has no result");
|
|
538
|
+
}
|
|
539
|
+
return parsed.result;
|
|
540
|
+
}
|
|
541
|
+
listSims() {
|
|
542
|
+
return Promise.reject(new Error("a box does not expose a local simulator list"));
|
|
543
|
+
}
|
|
544
|
+
focusSim() {
|
|
545
|
+
return Promise.reject(new Error("a box simulator has no browser window to focus"));
|
|
546
|
+
}
|
|
547
|
+
resolveReloadedSim() {
|
|
548
|
+
return Promise.resolve(null);
|
|
549
|
+
}
|
|
550
|
+
closeSim() {
|
|
551
|
+
return Promise.reject(new Error("close a box simulator with rnx box stop"));
|
|
552
|
+
}
|
|
553
|
+
claim() {
|
|
554
|
+
return Promise.reject(
|
|
555
|
+
new Error("a box simulator is held by its Box page and has nothing to claim")
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
close() {
|
|
559
|
+
}
|
|
560
|
+
};
|
|
561
|
+
function createCloudBridgeForParsed(parsed) {
|
|
562
|
+
const session = resolveCloudSessionForParsed(parsed);
|
|
563
|
+
if (!session) return null;
|
|
564
|
+
return session.service === "box" ? new CloudBoxBridge(session) : new CloudBridge(session);
|
|
565
|
+
}
|
|
566
|
+
|
|
59
567
|
// cli/current-sim.ts
|
|
60
568
|
var import_fs2 = require("fs");
|
|
61
569
|
var import_os = require("os");
|
|
@@ -215,25 +723,25 @@ function tryBuildDarwinCommFfi() {
|
|
|
215
723
|
}
|
|
216
724
|
|
|
217
725
|
// cli/secure-file.ts
|
|
218
|
-
var
|
|
219
|
-
var
|
|
220
|
-
var
|
|
726
|
+
var import_node_crypto2 = require("node:crypto");
|
|
727
|
+
var import_node_fs2 = require("node:fs");
|
|
728
|
+
var import_node_path2 = require("node:path");
|
|
221
729
|
function writeSecureJsonAtomic(filepath, value) {
|
|
222
|
-
(0,
|
|
223
|
-
const temporary = `${filepath}.tmp-${process.pid}-${(0,
|
|
730
|
+
(0, import_node_fs2.mkdirSync)((0, import_node_path2.dirname)(filepath), { recursive: true });
|
|
731
|
+
const temporary = `${filepath}.tmp-${process.pid}-${(0, import_node_crypto2.randomUUID)()}`;
|
|
224
732
|
let descriptor = null;
|
|
225
733
|
try {
|
|
226
|
-
descriptor = (0,
|
|
227
|
-
(0,
|
|
228
|
-
(0,
|
|
734
|
+
descriptor = (0, import_node_fs2.openSync)(temporary, "wx", 384);
|
|
735
|
+
(0, import_node_fs2.fchmodSync)(descriptor, 384);
|
|
736
|
+
(0, import_node_fs2.writeFileSync)(descriptor, `${JSON.stringify(value, null, 2)}
|
|
229
737
|
`);
|
|
230
|
-
(0,
|
|
231
|
-
(0,
|
|
738
|
+
(0, import_node_fs2.fsyncSync)(descriptor);
|
|
739
|
+
(0, import_node_fs2.closeSync)(descriptor);
|
|
232
740
|
descriptor = null;
|
|
233
|
-
(0,
|
|
741
|
+
(0, import_node_fs2.renameSync)(temporary, filepath);
|
|
234
742
|
} catch (error) {
|
|
235
|
-
if (descriptor !== null) (0,
|
|
236
|
-
(0,
|
|
743
|
+
if (descriptor !== null) (0, import_node_fs2.closeSync)(descriptor);
|
|
744
|
+
(0, import_node_fs2.rmSync)(temporary, { force: true });
|
|
237
745
|
throw error;
|
|
238
746
|
}
|
|
239
747
|
}
|
|
@@ -394,213 +902,6 @@ function resolveSootsimBridgePort(input = {}) {
|
|
|
394
902
|
// src/cli-constants.ts
|
|
395
903
|
var DEFAULT_SOOTSIM_SHELL_URL = "http://localhost:5173/";
|
|
396
904
|
|
|
397
|
-
// src/home-paths.ts
|
|
398
|
-
var import_node_fs2 = __toESM(require("node:fs"), 1);
|
|
399
|
-
var import_node_os = require("node:os");
|
|
400
|
-
var import_node_path2 = __toESM(require("node:path"), 1);
|
|
401
|
-
var RNX_HOME_ENV = "RNX_HOME";
|
|
402
|
-
var ACTIVE_RUNTIME_FILE = "active";
|
|
403
|
-
var DAEMON_LOCKFILE = "daemon.json";
|
|
404
|
-
var DEV_BRIDGES_DIR = "dev-bridges";
|
|
405
|
-
var DAEMON_HEARTBEAT_STALE_MS = 3e4;
|
|
406
|
-
function rnxHomeDir() {
|
|
407
|
-
const override = process.env[RNX_HOME_ENV];
|
|
408
|
-
if (override && override.length > 0) return import_node_path2.default.resolve(override);
|
|
409
|
-
return import_node_path2.default.join((0, import_node_os.homedir)(), ".rnx");
|
|
410
|
-
}
|
|
411
|
-
function runtimesDir() {
|
|
412
|
-
return import_node_path2.default.join(rnxHomeDir(), "runtimes");
|
|
413
|
-
}
|
|
414
|
-
function runtimeDir(version) {
|
|
415
|
-
return import_node_path2.default.join(runtimesDir(), version);
|
|
416
|
-
}
|
|
417
|
-
function activeRuntimeFile() {
|
|
418
|
-
return import_node_path2.default.join(runtimesDir(), ACTIVE_RUNTIME_FILE);
|
|
419
|
-
}
|
|
420
|
-
function daemonLockfilePath() {
|
|
421
|
-
return import_node_path2.default.join(rnxHomeDir(), DAEMON_LOCKFILE);
|
|
422
|
-
}
|
|
423
|
-
function devBridgesDir() {
|
|
424
|
-
return import_node_path2.default.join(rnxHomeDir(), DEV_BRIDGES_DIR);
|
|
425
|
-
}
|
|
426
|
-
function readActiveRuntime() {
|
|
427
|
-
try {
|
|
428
|
-
const value = import_node_fs2.default.readFileSync(activeRuntimeFile(), "utf8").trim();
|
|
429
|
-
return value.length > 0 ? value : null;
|
|
430
|
-
} catch {
|
|
431
|
-
return null;
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
var DAEMON_LOCKFILE_MAX_BYTES = 16 * 1024;
|
|
435
|
-
function readDaemonLockfile() {
|
|
436
|
-
try {
|
|
437
|
-
const fd = import_node_fs2.default.openSync(daemonLockfilePath(), "r");
|
|
438
|
-
try {
|
|
439
|
-
const buf = Buffer.alloc(DAEMON_LOCKFILE_MAX_BYTES);
|
|
440
|
-
const bytesRead = import_node_fs2.default.readSync(fd, buf, 0, DAEMON_LOCKFILE_MAX_BYTES, 0);
|
|
441
|
-
const raw = buf.subarray(0, bytesRead).toString("utf8");
|
|
442
|
-
const parsed = JSON.parse(raw);
|
|
443
|
-
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"))) {
|
|
444
|
-
return parsed;
|
|
445
|
-
}
|
|
446
|
-
return null;
|
|
447
|
-
} finally {
|
|
448
|
-
import_node_fs2.default.closeSync(fd);
|
|
449
|
-
}
|
|
450
|
-
} catch {
|
|
451
|
-
return null;
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
function parseDevBridgeLockfile(raw) {
|
|
455
|
-
try {
|
|
456
|
-
const parsed = JSON.parse(raw);
|
|
457
|
-
if (parsed && parsed.schema === 1 && parsed.source === "vite-dev" && typeof parsed.pid === "number" && typeof parsed.bridgePort === "number" && typeof parsed.runtimePort === "number" && typeof parsed.cwd === "string" && typeof parsed.startedAt === "number" && typeof parsed.heartbeatAt === "number" && (parsed.shellPort === void 0 || typeof parsed.shellPort === "number") && (parsed.servedRuntimes === void 0 || Array.isArray(parsed.servedRuntimes) && parsed.servedRuntimes.every((version) => typeof version === "string"))) {
|
|
458
|
-
return parsed;
|
|
459
|
-
}
|
|
460
|
-
return null;
|
|
461
|
-
} catch {
|
|
462
|
-
return null;
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
function readDevBridgeLockfiles() {
|
|
466
|
-
let entries;
|
|
467
|
-
try {
|
|
468
|
-
entries = import_node_fs2.default.readdirSync(devBridgesDir(), { withFileTypes: true });
|
|
469
|
-
} catch {
|
|
470
|
-
return [];
|
|
471
|
-
}
|
|
472
|
-
const lockfiles = [];
|
|
473
|
-
for (const entry of entries) {
|
|
474
|
-
if (!entry.isFile() || !/^\d+\.json$/.test(entry.name)) continue;
|
|
475
|
-
try {
|
|
476
|
-
const filePath = import_node_path2.default.join(devBridgesDir(), entry.name);
|
|
477
|
-
const fd = import_node_fs2.default.openSync(filePath, "r");
|
|
478
|
-
try {
|
|
479
|
-
const buf = Buffer.alloc(DAEMON_LOCKFILE_MAX_BYTES);
|
|
480
|
-
const bytesRead = import_node_fs2.default.readSync(fd, buf, 0, DAEMON_LOCKFILE_MAX_BYTES, 0);
|
|
481
|
-
const lockfile = parseDevBridgeLockfile(
|
|
482
|
-
buf.subarray(0, bytesRead).toString("utf8")
|
|
483
|
-
);
|
|
484
|
-
if (lockfile && entry.name === `${lockfile.bridgePort}.json`) {
|
|
485
|
-
lockfiles.push(lockfile);
|
|
486
|
-
}
|
|
487
|
-
} finally {
|
|
488
|
-
import_node_fs2.default.closeSync(fd);
|
|
489
|
-
}
|
|
490
|
-
} catch {
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
return lockfiles.sort((left, right) => left.bridgePort - right.bridgePort);
|
|
494
|
-
}
|
|
495
|
-
function isDaemonLockfileFresh(lock, now = Date.now()) {
|
|
496
|
-
if (!lock) return false;
|
|
497
|
-
if (now - lock.heartbeatAt > DAEMON_HEARTBEAT_STALE_MS) return false;
|
|
498
|
-
try {
|
|
499
|
-
process.kill(lock.pid, 0);
|
|
500
|
-
return true;
|
|
501
|
-
} catch {
|
|
502
|
-
return false;
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
function isDevBridgeLockfileFresh(lock, now = Date.now()) {
|
|
506
|
-
if (!lock) return false;
|
|
507
|
-
if (now - lock.heartbeatAt > DAEMON_HEARTBEAT_STALE_MS) return false;
|
|
508
|
-
try {
|
|
509
|
-
process.kill(lock.pid, 0);
|
|
510
|
-
return true;
|
|
511
|
-
} catch {
|
|
512
|
-
return false;
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
// ../sootsim-engine/src/metro-fingerprint-registry-client.ts
|
|
517
|
-
var import_metro_fingerprint_registry = require("rnxsim/metro-fingerprint-registry");
|
|
518
|
-
|
|
519
|
-
// ../sootsim-engine/src/metro-fingerprint.ts
|
|
520
|
-
var import_metro_production_bundle = require("rnxsim/metro-production-bundle");
|
|
521
|
-
var import_react_native_host_modules = require("rnxsim/react-native-host-modules");
|
|
522
|
-
|
|
523
|
-
// src/backend-origin.ts
|
|
524
|
-
function normalizeHostname(hostname) {
|
|
525
|
-
return hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
526
|
-
}
|
|
527
|
-
function isLoopbackHost(hostname) {
|
|
528
|
-
const normalized = normalizeHostname(hostname);
|
|
529
|
-
return normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "0.0.0.0" || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
// src/cloud-contract.ts
|
|
533
|
-
var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
|
|
534
|
-
var RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES = 1024 * 1024;
|
|
535
|
-
var RNX_CLOUD_COMMAND_TYPES = Object.freeze([
|
|
536
|
-
"state",
|
|
537
|
-
"query",
|
|
538
|
-
"resolve",
|
|
539
|
-
"perform",
|
|
540
|
-
"waitFor",
|
|
541
|
-
"reset",
|
|
542
|
-
"screenshot",
|
|
543
|
-
"capture",
|
|
544
|
-
"captureRegions",
|
|
545
|
-
"settle",
|
|
546
|
-
"setAppearance",
|
|
547
|
-
"openUrl",
|
|
548
|
-
"tree",
|
|
549
|
-
"tap",
|
|
550
|
-
"longPress",
|
|
551
|
-
"memory",
|
|
552
|
-
"diagnostics"
|
|
553
|
-
]);
|
|
554
|
-
var RNX_CLOUD_COMMAND_TYPE_SET = new Set(RNX_CLOUD_COMMAND_TYPES);
|
|
555
|
-
|
|
556
|
-
// src/metro-production-bundle.ts
|
|
557
|
-
var RNXSIM_METRO_MODULE_PATHS_PREFIX = "globalThis.__sootsimModulePaths=";
|
|
558
|
-
var RNX_METRO_MODULE_IDENTITY_VERSION = 2;
|
|
559
|
-
var RNXSIM_METRO_SOURCE_MAP_COMMENT = "//# sourceMappingURL=";
|
|
560
|
-
function detachRNXMetroSourceMapUrl(bundleText) {
|
|
561
|
-
const trimmedEnd = bundleText.replace(/\s+$/, "");
|
|
562
|
-
const commentStart = trimmedEnd.lastIndexOf(`
|
|
563
|
-
${RNXSIM_METRO_SOURCE_MAP_COMMENT}`);
|
|
564
|
-
if (commentStart < 0) return { source: bundleText, sourceMappingUrl: null };
|
|
565
|
-
const url = trimmedEnd.slice(commentStart + 1 + RNXSIM_METRO_SOURCE_MAP_COMMENT.length);
|
|
566
|
-
if (url.includes("\n")) return { source: bundleText, sourceMappingUrl: null };
|
|
567
|
-
return { source: trimmedEnd.slice(0, commentStart), sourceMappingUrl: url };
|
|
568
|
-
}
|
|
569
|
-
function createRNXMetroModuleIdentityFooter(identity) {
|
|
570
|
-
const payload = JSON.stringify(identity).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029").replace(/<\//g, "<\\/");
|
|
571
|
-
return `
|
|
572
|
-
${RNXSIM_METRO_MODULE_PATHS_PREFIX}${payload};`;
|
|
573
|
-
}
|
|
574
|
-
function appendRNXMetroModuleIdentityFooter(bundleText, identity) {
|
|
575
|
-
const footer = createRNXMetroModuleIdentityFooter(identity);
|
|
576
|
-
const detached = detachRNXMetroSourceMapUrl(bundleText);
|
|
577
|
-
return detached.sourceMappingUrl === null ? bundleText + footer : `${detached.source}${footer}
|
|
578
|
-
${RNXSIM_METRO_SOURCE_MAP_COMMENT}${detached.sourceMappingUrl}`;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
// src/public-brand.ts
|
|
582
|
-
var name = "rnx";
|
|
583
|
-
var rnxPublicBrand = Object.freeze({
|
|
584
|
-
name,
|
|
585
|
-
packageName: "rnxsim",
|
|
586
|
-
commandName: "rnx",
|
|
587
|
-
domain: "rnxsim.com",
|
|
588
|
-
origin: "https://rnxsim.com"
|
|
589
|
-
});
|
|
590
|
-
|
|
591
|
-
// cli/run-rnx.ts
|
|
592
|
-
var import_node_async_hooks = require("node:async_hooks");
|
|
593
|
-
var sinks = new import_node_async_hooks.AsyncLocalStorage();
|
|
594
|
-
|
|
595
|
-
// cli/cloud-session.ts
|
|
596
|
-
var MAX_ENCODED_SESSION_BYTES = 32 * 1024;
|
|
597
|
-
var RNX_SHELL_UPDATE_PREFIX = "__RNX_SHELL_UPDATE_V1__";
|
|
598
|
-
var RNX_SHELL_UPDATE_SET_PREFIX = `${RNX_SHELL_UPDATE_PREFIX}set:`;
|
|
599
|
-
var RNX_SHELL_UPDATE_UNSET = `${RNX_SHELL_UPDATE_PREFIX}unset`;
|
|
600
|
-
|
|
601
|
-
// cli/cloud-client.ts
|
|
602
|
-
var DEFAULT_RNX_CLOUD_ORIGIN = rnxPublicBrand.origin;
|
|
603
|
-
|
|
604
905
|
// cli/ws-bridge.ts
|
|
605
906
|
function bridgeWsUrl(wsPort) {
|
|
606
907
|
return `ws://localhost:${wsPort}`;
|
|
@@ -2675,6 +2976,19 @@ function pickSim(sims, wanted, port) {
|
|
|
2675
2976
|
return primary;
|
|
2676
2977
|
}
|
|
2677
2978
|
async function connect(options = {}) {
|
|
2979
|
+
const target = {
|
|
2980
|
+
simId: options.sim,
|
|
2981
|
+
simIdSource: options.sim ? "flag" : "none"
|
|
2982
|
+
};
|
|
2983
|
+
const cloud = resolveCloudSessionForParsed(target);
|
|
2984
|
+
if (cloud) {
|
|
2985
|
+
const bridge2 = createCloudBridgeForParsed(target);
|
|
2986
|
+
if (!bridge2)
|
|
2987
|
+
throw new SimConnectError("remote simulator session disappeared while connecting");
|
|
2988
|
+
return new SimClient(bridge2, cloud.service === "box" ? cloud.boxId : cloud.simId, {
|
|
2989
|
+
commandTimeoutMs: options.timeoutMs ?? 15e3
|
|
2990
|
+
});
|
|
2991
|
+
}
|
|
2678
2992
|
const port = options.port ?? resolveBridgeWorld().bridgePort;
|
|
2679
2993
|
const commandTimeoutMs = options.timeoutMs ?? 15e3;
|
|
2680
2994
|
const discovery = createBridge(port, { commandTimeoutMs, cliLabel: "sdk" });
|
|
@@ -2880,12 +3194,12 @@ function isRnxCaptureRegionAtlas(value) {
|
|
|
2880
3194
|
|
|
2881
3195
|
// src/vite-plugin-one.ts
|
|
2882
3196
|
var import_fs4 = __toESM(require("fs"), 1);
|
|
2883
|
-
var
|
|
3197
|
+
var import_node_crypto4 = require("node:crypto");
|
|
2884
3198
|
var import_path3 = __toESM(require("path"), 1);
|
|
2885
3199
|
|
|
2886
3200
|
// src/dev-server-open.ts
|
|
2887
3201
|
var import_node_child_process = require("node:child_process");
|
|
2888
|
-
var
|
|
3202
|
+
var import_node_crypto3 = require("node:crypto");
|
|
2889
3203
|
var import_node_fs4 = __toESM(require("node:fs"), 1);
|
|
2890
3204
|
var import_node_path4 = __toESM(require("node:path"), 1);
|
|
2891
3205
|
var import_node_url = require("node:url");
|
|
@@ -2911,7 +3225,7 @@ function tagRnxBundleForPlugin(bundleUrl, replacementOrigin, replacementToken, p
|
|
|
2911
3225
|
url.searchParams.set("rnxAppName", appName);
|
|
2912
3226
|
url.searchParams.set(
|
|
2913
3227
|
"rnxProjectId",
|
|
2914
|
-
(0,
|
|
3228
|
+
(0, import_node_crypto3.createHash)("sha256").update(import_node_fs4.default.realpathSync(projectRoot)).digest("hex").slice(0, 32)
|
|
2915
3229
|
);
|
|
2916
3230
|
}
|
|
2917
3231
|
url.searchParams.set("rnxReplacementOrigin", replacementOrigin);
|
|
@@ -3531,7 +3845,7 @@ function rnxPlugin(options = {}) {
|
|
|
3531
3845
|
if (options.enabled === false) return;
|
|
3532
3846
|
const bundleUrl = options.bundleUrl || "/node_modules/one/metro-entry.bundle?platform=ios&dev=true&minify=false";
|
|
3533
3847
|
const appName = resolveRnxDesktopAppName(options.open, server.config.root);
|
|
3534
|
-
const replacementToken = (0,
|
|
3848
|
+
const replacementToken = (0, import_node_crypto4.randomUUID)();
|
|
3535
3849
|
const configuredPort = server.config.server.port || 8081;
|
|
3536
3850
|
const listeningPort = () => {
|
|
3537
3851
|
const address = server.httpServer?.address();
|
|
@@ -3656,7 +3970,7 @@ function rnxPlugin(options = {}) {
|
|
|
3656
3970
|
// src/metro-plugin.ts
|
|
3657
3971
|
var import_fs5 = __toESM(require("fs"), 1);
|
|
3658
3972
|
var import_module2 = require("module");
|
|
3659
|
-
var
|
|
3973
|
+
var import_node_crypto5 = require("node:crypto");
|
|
3660
3974
|
var import_path4 = __toESM(require("path"), 1);
|
|
3661
3975
|
var prefix = "/__soot";
|
|
3662
3976
|
function readCallableMetroExport(moduleValue, label) {
|
|
@@ -3731,7 +4045,7 @@ function withRNX(config) {
|
|
|
3731
4045
|
const configuredBundleUrl = "/index.bundle?platform=ios&dev=true&hot=true&minify=false";
|
|
3732
4046
|
const cfgServer = config.server;
|
|
3733
4047
|
const port = resolveMetroPort(cfgServer);
|
|
3734
|
-
const metroServerId = (0,
|
|
4048
|
+
const metroServerId = (0, import_node_crypto5.randomUUID)();
|
|
3735
4049
|
const bundleUrl = tagRnxBundleForPlugin(
|
|
3736
4050
|
configuredBundleUrl,
|
|
3737
4051
|
`http://localhost:${port}`,
|