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/skills.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;
|
|
@@ -9476,6 +9476,27 @@ var init_bridge_constants = __esm({
|
|
|
9476
9476
|
}
|
|
9477
9477
|
});
|
|
9478
9478
|
|
|
9479
|
+
// src/backend-origin.ts
|
|
9480
|
+
function normalizeHostname(hostname) {
|
|
9481
|
+
return hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
9482
|
+
}
|
|
9483
|
+
function buildLoopbackProbeBaseUrl(protocol, hostname, port) {
|
|
9484
|
+
const normalizedHostname = normalizeHostname(hostname);
|
|
9485
|
+
const urlHost = normalizedHostname.includes(":") ? `[${normalizedHostname}]` : normalizedHostname;
|
|
9486
|
+
return `${protocol}//${urlHost}:${port}`;
|
|
9487
|
+
}
|
|
9488
|
+
function isLoopbackHost(hostname) {
|
|
9489
|
+
const normalized = normalizeHostname(hostname);
|
|
9490
|
+
return normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "0.0.0.0" || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
|
|
9491
|
+
}
|
|
9492
|
+
var LOOPBACK_PROBE_HOSTNAMES;
|
|
9493
|
+
var init_backend_origin = __esm({
|
|
9494
|
+
"src/backend-origin.ts"() {
|
|
9495
|
+
"use strict";
|
|
9496
|
+
LOOPBACK_PROBE_HOSTNAMES = ["::1", "127.0.0.1"];
|
|
9497
|
+
}
|
|
9498
|
+
});
|
|
9499
|
+
|
|
9479
9500
|
// src/config.ts
|
|
9480
9501
|
function hasOwnKeys(value) {
|
|
9481
9502
|
return !!value && Object.keys(value).length > 0;
|
|
@@ -9531,6 +9552,19 @@ function isAbsoluteHttpUrl(url) {
|
|
|
9531
9552
|
function isNativeDevBundlePath(pathname) {
|
|
9532
9553
|
return pathname.endsWith(".bundle");
|
|
9533
9554
|
}
|
|
9555
|
+
function alignLoopbackBundleUrlWithProbe(bundleUrl, probeBaseUrl) {
|
|
9556
|
+
try {
|
|
9557
|
+
const bundle = new URL(bundleUrl);
|
|
9558
|
+
const probe3 = new URL(probeBaseUrl);
|
|
9559
|
+
if (!isLoopbackHost(bundle.hostname) || !isLoopbackHost(probe3.hostname)) {
|
|
9560
|
+
return bundleUrl;
|
|
9561
|
+
}
|
|
9562
|
+
bundle.hostname = probe3.hostname;
|
|
9563
|
+
return bundle.toString();
|
|
9564
|
+
} catch {
|
|
9565
|
+
return bundleUrl;
|
|
9566
|
+
}
|
|
9567
|
+
}
|
|
9534
9568
|
function applyPreviewProdBundle(parsed) {
|
|
9535
9569
|
if (!process.env.SOOTSIM_PREVIEW_PROD_BUNDLE) return;
|
|
9536
9570
|
parsed.searchParams.set("dev", "false");
|
|
@@ -9570,6 +9604,7 @@ var METRO_BUNDLE_PATH;
|
|
|
9570
9604
|
var init_native_dev_bundle_url = __esm({
|
|
9571
9605
|
"src/native-dev-bundle-url.ts"() {
|
|
9572
9606
|
"use strict";
|
|
9607
|
+
init_backend_origin();
|
|
9573
9608
|
METRO_BUNDLE_PATH = "/index.bundle?platform=ios&dev=true&hot=true&minify=false";
|
|
9574
9609
|
}
|
|
9575
9610
|
});
|
|
@@ -9678,9 +9713,9 @@ function safeChildPlistName(value) {
|
|
|
9678
9713
|
name: file.toLowerCase().endsWith(".plist") ? file : `${file}.plist`
|
|
9679
9714
|
};
|
|
9680
9715
|
}
|
|
9681
|
-
async function readableSettingsBundle(
|
|
9716
|
+
async function readableSettingsBundle(path18) {
|
|
9682
9717
|
try {
|
|
9683
|
-
const root = await (0, import_promises.stat)((0, import_node_path.join)(
|
|
9718
|
+
const root = await (0, import_promises.stat)((0, import_node_path.join)(path18, "Root.plist"));
|
|
9684
9719
|
return root.isFile() && root.size <= MAX_PLIST_BYTES;
|
|
9685
9720
|
} catch {
|
|
9686
9721
|
return false;
|
|
@@ -9725,11 +9760,11 @@ async function settingsBundleFingerprint(bundlePath) {
|
|
|
9725
9760
|
return null;
|
|
9726
9761
|
}
|
|
9727
9762
|
}
|
|
9728
|
-
async function parsePlistRecord(
|
|
9763
|
+
async function parsePlistRecord(path18) {
|
|
9729
9764
|
try {
|
|
9730
|
-
const metadata = await (0, import_promises.stat)(
|
|
9765
|
+
const metadata = await (0, import_promises.stat)(path18);
|
|
9731
9766
|
if (!metadata.isFile() || metadata.size > MAX_PLIST_BYTES) return null;
|
|
9732
|
-
const source = await (0, import_promises.readFile)(
|
|
9767
|
+
const source = await (0, import_promises.readFile)(path18, "utf8");
|
|
9733
9768
|
const parsed = parsePlistSource(source);
|
|
9734
9769
|
return isRecord2(parsed) ? parsed : null;
|
|
9735
9770
|
} catch {
|
|
@@ -9991,27 +10026,36 @@ var init_optional_demo_registry = __esm({
|
|
|
9991
10026
|
});
|
|
9992
10027
|
|
|
9993
10028
|
// scripts/dev-server-scanner.ts
|
|
9994
|
-
function tcpPing(port, timeout = TCP_GATE_MS) {
|
|
9995
|
-
|
|
9996
|
-
|
|
9997
|
-
|
|
9998
|
-
|
|
9999
|
-
|
|
10000
|
-
|
|
10001
|
-
|
|
10002
|
-
|
|
10003
|
-
|
|
10004
|
-
|
|
10005
|
-
|
|
10006
|
-
|
|
10007
|
-
|
|
10008
|
-
|
|
10009
|
-
|
|
10029
|
+
async function tcpPing(port, timeout = TCP_GATE_MS) {
|
|
10030
|
+
try {
|
|
10031
|
+
return await Promise.any(
|
|
10032
|
+
LOOPBACK_PROBE_HOSTNAMES.map(
|
|
10033
|
+
(hostname) => new Promise((resolve7, reject) => {
|
|
10034
|
+
const sock = new import_net.default.Socket();
|
|
10035
|
+
let settled = false;
|
|
10036
|
+
const done = (reachable) => {
|
|
10037
|
+
if (settled) return;
|
|
10038
|
+
settled = true;
|
|
10039
|
+
sock.destroy();
|
|
10040
|
+
if (reachable) resolve7(hostname);
|
|
10041
|
+
else reject(new Error(`unreachable loopback host ${hostname}`));
|
|
10042
|
+
};
|
|
10043
|
+
sock.setTimeout(timeout);
|
|
10044
|
+
sock.once("connect", () => done(true));
|
|
10045
|
+
sock.once("timeout", () => done(false));
|
|
10046
|
+
sock.once("error", () => done(false));
|
|
10047
|
+
sock.connect(port, hostname);
|
|
10048
|
+
})
|
|
10049
|
+
)
|
|
10050
|
+
);
|
|
10051
|
+
} catch {
|
|
10052
|
+
return null;
|
|
10053
|
+
}
|
|
10010
10054
|
}
|
|
10011
|
-
function httpGet(port,
|
|
10055
|
+
function httpGet(hostname, port, path18, method = "GET", timeout = TIMEOUT_MS, headers = {}) {
|
|
10012
10056
|
return new Promise((resolve7) => {
|
|
10013
10057
|
const req = import_http.default.request(
|
|
10014
|
-
{ hostname
|
|
10058
|
+
{ hostname, port, path: path18, method, timeout, headers },
|
|
10015
10059
|
(res) => {
|
|
10016
10060
|
let body = "";
|
|
10017
10061
|
res.on("data", (c) => body += c.toString());
|
|
@@ -10023,7 +10067,12 @@ function httpGet(port, path19, method = "GET", timeout = TIMEOUT_MS, headers = {
|
|
|
10023
10067
|
})();
|
|
10024
10068
|
res.on(
|
|
10025
10069
|
"end",
|
|
10026
|
-
() => resolve7({
|
|
10070
|
+
() => resolve7({
|
|
10071
|
+
statusCode: res.statusCode || 0,
|
|
10072
|
+
body,
|
|
10073
|
+
contentType,
|
|
10074
|
+
hostname
|
|
10075
|
+
})
|
|
10027
10076
|
);
|
|
10028
10077
|
}
|
|
10029
10078
|
);
|
|
@@ -10163,16 +10212,16 @@ async function resolveProcessCwd(pid) {
|
|
|
10163
10212
|
}
|
|
10164
10213
|
return null;
|
|
10165
10214
|
}
|
|
10166
|
-
function makeResult(port, framework, owner) {
|
|
10215
|
+
function makeResult(hostname, port, framework, owner) {
|
|
10167
10216
|
return {
|
|
10168
10217
|
port,
|
|
10169
10218
|
framework,
|
|
10170
10219
|
bundleUrl: withRuntimeConfig(
|
|
10171
10220
|
port,
|
|
10172
|
-
|
|
10221
|
+
`${buildLoopbackProbeBaseUrl("http:", hostname, port)}/index.bundle?platform=ios&dev=true&hot=true&minify=false`,
|
|
10173
10222
|
owner.cwd
|
|
10174
10223
|
),
|
|
10175
|
-
hmrUrl:
|
|
10224
|
+
hmrUrl: `${buildLoopbackProbeBaseUrl("ws:", hostname, port)}/hot`,
|
|
10176
10225
|
lastSeen: Date.now(),
|
|
10177
10226
|
...owner
|
|
10178
10227
|
};
|
|
@@ -10203,7 +10252,11 @@ function applyManifest(result, manifestRes, buildIconProxyUrl) {
|
|
|
10203
10252
|
if (client.name) result.projectName = client.name;
|
|
10204
10253
|
if (client.ios?.bundleIdentifier) result.bundleId = client.ios.bundleIdentifier;
|
|
10205
10254
|
if (result.framework === "metro" && client.sdkVersion) result.framework = "expo";
|
|
10206
|
-
const
|
|
10255
|
+
const rawLaunchUrl = manifest?.launchAsset?.url;
|
|
10256
|
+
const launchUrl2 = typeof rawLaunchUrl === "string" ? alignLoopbackBundleUrlWithProbe(
|
|
10257
|
+
rawLaunchUrl,
|
|
10258
|
+
buildLoopbackProbeBaseUrl("http:", manifestRes.hostname, result.port)
|
|
10259
|
+
) : rawLaunchUrl;
|
|
10207
10260
|
if (launchUrl2 && !result.patched && !isDirectOneBundleUrl(result.bundleUrl)) {
|
|
10208
10261
|
result.bundleUrl = withRuntimeConfig(result.port, launchUrl2, result.cwd);
|
|
10209
10262
|
}
|
|
@@ -10216,11 +10269,11 @@ function applyManifest(result, manifestRes, buildIconProxyUrl) {
|
|
|
10216
10269
|
} else {
|
|
10217
10270
|
const cleanPath = rawIconUrl.replace(/^\.\//, "");
|
|
10218
10271
|
result.iconUrl = buildIconProxyUrl(
|
|
10219
|
-
|
|
10272
|
+
`${buildLoopbackProbeBaseUrl("http:", manifestRes.hostname, result.port)}/assets/${cleanPath}`
|
|
10220
10273
|
);
|
|
10221
10274
|
}
|
|
10222
10275
|
} else {
|
|
10223
|
-
result.iconUrl = rawIconUrl.startsWith("http") ? rawIconUrl :
|
|
10276
|
+
result.iconUrl = rawIconUrl.startsWith("http") ? rawIconUrl : `${buildLoopbackProbeBaseUrl("http:", manifestRes.hostname, result.port)}/assets/${rawIconUrl.replace(/^\.\//, "")}`;
|
|
10224
10277
|
}
|
|
10225
10278
|
}
|
|
10226
10279
|
} catch {
|
|
@@ -10241,35 +10294,48 @@ function enrichWithManifest(result, buildIconProxyUrl) {
|
|
|
10241
10294
|
}
|
|
10242
10295
|
if (!enrichmentInFlight.has(result.port)) {
|
|
10243
10296
|
enrichmentInFlight.add(result.port);
|
|
10244
|
-
|
|
10245
|
-
|
|
10246
|
-
() => enrichmentInFlight.delete(port)
|
|
10297
|
+
void fetchManifestEnrichment(result, buildIconProxyUrl).finally(
|
|
10298
|
+
() => enrichmentInFlight.delete(result.port)
|
|
10247
10299
|
);
|
|
10248
10300
|
}
|
|
10249
10301
|
return result;
|
|
10250
10302
|
}
|
|
10251
|
-
async function fetchManifestEnrichment(
|
|
10252
|
-
const
|
|
10253
|
-
|
|
10254
|
-
|
|
10303
|
+
async function fetchManifestEnrichment(result, buildIconProxyUrl) {
|
|
10304
|
+
const hostname = normalizeHostname(new URL(result.bundleUrl).hostname);
|
|
10305
|
+
const manifestRes = await httpGet(
|
|
10306
|
+
hostname,
|
|
10307
|
+
result.port,
|
|
10308
|
+
"/",
|
|
10309
|
+
"GET",
|
|
10310
|
+
ENRICH_TIMEOUT_MS,
|
|
10311
|
+
{
|
|
10312
|
+
"expo-platform": "ios"
|
|
10313
|
+
}
|
|
10314
|
+
);
|
|
10255
10315
|
if (!manifestRes || manifestRes.statusCode !== 200) return;
|
|
10256
10316
|
const parsed = applyManifest(
|
|
10257
|
-
{
|
|
10317
|
+
{
|
|
10318
|
+
port: result.port,
|
|
10319
|
+
framework: "one",
|
|
10320
|
+
bundleUrl: `${buildLoopbackProbeBaseUrl("http:", hostname, result.port)}/index.bundle`,
|
|
10321
|
+
lastSeen: 0
|
|
10322
|
+
},
|
|
10258
10323
|
manifestRes,
|
|
10259
10324
|
buildIconProxyUrl
|
|
10260
10325
|
);
|
|
10261
10326
|
if (!parsed.projectName && !parsed.iconUrl) return;
|
|
10262
|
-
enrichmentCache.set(port, {
|
|
10327
|
+
enrichmentCache.set(result.port, {
|
|
10263
10328
|
projectName: parsed.projectName,
|
|
10264
10329
|
iconUrl: parsed.iconUrl,
|
|
10265
10330
|
iconPath: parsed.iconPath,
|
|
10266
10331
|
bundleId: parsed.bundleId
|
|
10267
10332
|
});
|
|
10268
|
-
portCache.delete(port);
|
|
10333
|
+
portCache.delete(result.port);
|
|
10269
10334
|
}
|
|
10270
10335
|
async function probePort(port, buildIconProxyUrl, listeningProcess) {
|
|
10271
10336
|
await loadOptionalDemoApps();
|
|
10272
|
-
|
|
10337
|
+
const probeHostname = await tcpPing(port);
|
|
10338
|
+
if (!probeHostname) return null;
|
|
10273
10339
|
const suppliedPid = listeningProcess?.pid;
|
|
10274
10340
|
const ownerPid = suppliedPid && suppliedPid > 0 ? suppliedPid : await resolveListeningPid(port);
|
|
10275
10341
|
const ownerCwd = ownerPid ? await resolveProcessCwd(ownerPid) : null;
|
|
@@ -10279,10 +10345,12 @@ async function probePort(port, buildIconProxyUrl, listeningProcess) {
|
|
|
10279
10345
|
};
|
|
10280
10346
|
const onePath = `/node_modules/one/metro-entry.bundle?platform=ios&dev=true`;
|
|
10281
10347
|
const [sootsimRes, statusRes, manifestRes, expoRes] = await Promise.all([
|
|
10282
|
-
knownNonPatched.has(port) ? Promise.resolve(null) : httpGet(port, "/__soot/"),
|
|
10283
|
-
httpGet(port, "/status"),
|
|
10284
|
-
knownOne.has(port) ? Promise.resolve(null) : httpGet(port, "/", "GET", MANIFEST_TIMEOUT_MS, {
|
|
10285
|
-
|
|
10348
|
+
knownNonPatched.has(port) ? Promise.resolve(null) : httpGet(probeHostname, port, "/__soot/"),
|
|
10349
|
+
httpGet(probeHostname, port, "/status"),
|
|
10350
|
+
knownOne.has(port) ? Promise.resolve(null) : httpGet(probeHostname, port, "/", "GET", MANIFEST_TIMEOUT_MS, {
|
|
10351
|
+
"expo-platform": "ios"
|
|
10352
|
+
}),
|
|
10353
|
+
knownNonExpo.has(port) ? Promise.resolve(null) : httpGet(probeHostname, port, "/_expo/status")
|
|
10286
10354
|
]);
|
|
10287
10355
|
if (expoRes && expoRes.statusCode === 200) {
|
|
10288
10356
|
knownNonExpo.delete(port);
|
|
@@ -10294,7 +10362,7 @@ async function probePort(port, buildIconProxyUrl, listeningProcess) {
|
|
|
10294
10362
|
const manifestClient = manifestParsed?.extra?.expoClient || manifestParsed?.extra || {};
|
|
10295
10363
|
if (manifestParsed && (manifestLaunchUrl || typeof manifestClient.name === "string")) {
|
|
10296
10364
|
knownNonPatched.add(port);
|
|
10297
|
-
const launchUrl2 = manifestLaunchUrl ||
|
|
10365
|
+
const launchUrl2 = manifestLaunchUrl || `${buildLoopbackProbeBaseUrl("http:", probeHostname, port)}/index.bundle?platform=ios&dev=true&hot=true&minify=false`;
|
|
10298
10366
|
const framework = launchUrl2.includes(
|
|
10299
10367
|
"/one/metro-entry.bundle"
|
|
10300
10368
|
) ? "one" : "expo";
|
|
@@ -10303,7 +10371,7 @@ async function probePort(port, buildIconProxyUrl, listeningProcess) {
|
|
|
10303
10371
|
port,
|
|
10304
10372
|
framework,
|
|
10305
10373
|
bundleUrl: withRuntimeConfig(port, launchUrl2, owner.cwd),
|
|
10306
|
-
hmrUrl:
|
|
10374
|
+
hmrUrl: `${buildLoopbackProbeBaseUrl("ws:", probeHostname, port)}/hot`,
|
|
10307
10375
|
lastSeen: Date.now(),
|
|
10308
10376
|
...owner
|
|
10309
10377
|
},
|
|
@@ -10315,7 +10383,12 @@ async function probePort(port, buildIconProxyUrl, listeningProcess) {
|
|
|
10315
10383
|
knownNonPatched.add(port);
|
|
10316
10384
|
return enrichWithManifest(
|
|
10317
10385
|
applyManifest(
|
|
10318
|
-
makeResult(
|
|
10386
|
+
makeResult(
|
|
10387
|
+
probeHostname,
|
|
10388
|
+
port,
|
|
10389
|
+
expoRes && expoRes.statusCode === 200 ? "expo" : "metro",
|
|
10390
|
+
owner
|
|
10391
|
+
),
|
|
10319
10392
|
manifestRes,
|
|
10320
10393
|
buildIconProxyUrl
|
|
10321
10394
|
),
|
|
@@ -10331,10 +10404,10 @@ async function probePort(port, buildIconProxyUrl, listeningProcess) {
|
|
|
10331
10404
|
framework: "one",
|
|
10332
10405
|
bundleUrl: withRuntimeConfig(
|
|
10333
10406
|
port,
|
|
10334
|
-
|
|
10407
|
+
`${buildLoopbackProbeBaseUrl("http:", probeHostname, port)}/__soot/bundle.js`,
|
|
10335
10408
|
owner.cwd
|
|
10336
10409
|
),
|
|
10337
|
-
hmrUrl:
|
|
10410
|
+
hmrUrl: `${buildLoopbackProbeBaseUrl("ws:", probeHostname, port)}/hot`,
|
|
10338
10411
|
lastSeen: Date.now(),
|
|
10339
10412
|
patched: true,
|
|
10340
10413
|
...owner
|
|
@@ -10349,7 +10422,7 @@ async function probePort(port, buildIconProxyUrl, listeningProcess) {
|
|
|
10349
10422
|
if (looksLikeMetroPackager) {
|
|
10350
10423
|
return null;
|
|
10351
10424
|
}
|
|
10352
|
-
const oneRes = await httpGet(port, onePath, "HEAD");
|
|
10425
|
+
const oneRes = await httpGet(probeHostname, port, onePath, "HEAD");
|
|
10353
10426
|
if (oneRes && oneRes.statusCode > 0 && oneRes.statusCode < 400 && /application\/javascript/i.test(oneRes.contentType || "")) {
|
|
10354
10427
|
knownNonPatched.add(port);
|
|
10355
10428
|
knownOne.add(port);
|
|
@@ -10360,10 +10433,10 @@ async function probePort(port, buildIconProxyUrl, listeningProcess) {
|
|
|
10360
10433
|
framework: "one",
|
|
10361
10434
|
bundleUrl: withRuntimeConfig(
|
|
10362
10435
|
port,
|
|
10363
|
-
|
|
10436
|
+
`${buildLoopbackProbeBaseUrl("http:", probeHostname, port)}${onePath}&minify=false`,
|
|
10364
10437
|
owner.cwd
|
|
10365
10438
|
),
|
|
10366
|
-
hmrUrl:
|
|
10439
|
+
hmrUrl: `${buildLoopbackProbeBaseUrl("ws:", probeHostname, port)}/hot`,
|
|
10367
10440
|
lastSeen: Date.now(),
|
|
10368
10441
|
...owner
|
|
10369
10442
|
},
|
|
@@ -10485,6 +10558,7 @@ var init_dev_server_scanner = __esm({
|
|
|
10485
10558
|
import_net = __toESM(require("net"), 1);
|
|
10486
10559
|
import_node_path3 = require("node:path");
|
|
10487
10560
|
import_util = require("util");
|
|
10561
|
+
init_backend_origin();
|
|
10488
10562
|
init_config();
|
|
10489
10563
|
init_native_dev_bundle_url();
|
|
10490
10564
|
init_settings_bundle();
|
|
@@ -10724,8 +10798,8 @@ function readPrivacyPreferences() {
|
|
|
10724
10798
|
const productAnalytics = settings?.productAnalytics;
|
|
10725
10799
|
const crashReports = settings?.crashReports;
|
|
10726
10800
|
return {
|
|
10727
|
-
productAnalytics: typeof productAnalytics === "boolean" ? productAnalytics :
|
|
10728
|
-
crashReports: typeof crashReports === "boolean" ? crashReports :
|
|
10801
|
+
productAnalytics: typeof productAnalytics === "boolean" ? productAnalytics : false,
|
|
10802
|
+
crashReports: typeof crashReports === "boolean" ? crashReports : false,
|
|
10729
10803
|
configured: typeof productAnalytics === "boolean" && typeof crashReports === "boolean"
|
|
10730
10804
|
};
|
|
10731
10805
|
}
|
|
@@ -10894,10 +10968,30 @@ function readLiveRuntimeVersions() {
|
|
|
10894
10968
|
}
|
|
10895
10969
|
function writeDaemonLockfile(data) {
|
|
10896
10970
|
ensureSootsimHome();
|
|
10897
|
-
const
|
|
10971
|
+
const lockfilePath = daemonLockfilePath();
|
|
10972
|
+
const existing = readDaemonLockfile();
|
|
10973
|
+
if (!existing) {
|
|
10974
|
+
if (createDaemonLockfileExclusive(data)) return;
|
|
10975
|
+
throw new Error("another rnx daemon claimed the lockfile before this write");
|
|
10976
|
+
}
|
|
10977
|
+
if (!sameDaemonOwner(existing, data)) {
|
|
10978
|
+
throw new Error("refusing to overwrite another rnx daemon lockfile");
|
|
10979
|
+
}
|
|
10980
|
+
const tmp = `${lockfilePath}.${data.pid}.${(0, import_node_crypto.randomUUID)()}.tmp`;
|
|
10898
10981
|
import_node_fs3.default.writeFileSync(tmp, `${JSON.stringify(data, null, 2)}
|
|
10899
10982
|
`, "utf8");
|
|
10900
|
-
|
|
10983
|
+
try {
|
|
10984
|
+
const current = readDaemonLockfile();
|
|
10985
|
+
if (!current || !sameDaemonOwner(current, data)) {
|
|
10986
|
+
throw new Error("rnx daemon lock ownership changed during heartbeat");
|
|
10987
|
+
}
|
|
10988
|
+
import_node_fs3.default.renameSync(tmp, lockfilePath);
|
|
10989
|
+
} finally {
|
|
10990
|
+
try {
|
|
10991
|
+
import_node_fs3.default.unlinkSync(tmp);
|
|
10992
|
+
} catch {
|
|
10993
|
+
}
|
|
10994
|
+
}
|
|
10901
10995
|
}
|
|
10902
10996
|
function writeDevBridgeLockfile(data) {
|
|
10903
10997
|
import_node_fs3.default.mkdirSync(devBridgesDir(), { recursive: true });
|
|
@@ -10907,17 +11001,130 @@ function writeDevBridgeLockfile(data) {
|
|
|
10907
11001
|
`, "utf8");
|
|
10908
11002
|
import_node_fs3.default.renameSync(tmp, lockfilePath);
|
|
10909
11003
|
}
|
|
11004
|
+
function sameDaemonOwner(left, right) {
|
|
11005
|
+
return left.pid === right.pid && left.startedAt === right.startedAt;
|
|
11006
|
+
}
|
|
11007
|
+
function isAlreadyExists(error) {
|
|
11008
|
+
return error instanceof Error && "code" in error && Reflect.get(error, "code") === "EEXIST";
|
|
11009
|
+
}
|
|
11010
|
+
function createDaemonLockfileExclusive(data) {
|
|
11011
|
+
const lockfilePath = daemonLockfilePath();
|
|
11012
|
+
const tmp = `${lockfilePath}.${data.pid}.${(0, import_node_crypto.randomUUID)()}.claim`;
|
|
11013
|
+
import_node_fs3.default.writeFileSync(tmp, `${JSON.stringify(data, null, 2)}
|
|
11014
|
+
`, "utf8");
|
|
11015
|
+
try {
|
|
11016
|
+
import_node_fs3.default.linkSync(tmp, lockfilePath);
|
|
11017
|
+
return true;
|
|
11018
|
+
} catch (error) {
|
|
11019
|
+
if (isAlreadyExists(error)) return false;
|
|
11020
|
+
throw error;
|
|
11021
|
+
} finally {
|
|
11022
|
+
try {
|
|
11023
|
+
import_node_fs3.default.unlinkSync(tmp);
|
|
11024
|
+
} catch {
|
|
11025
|
+
}
|
|
11026
|
+
}
|
|
11027
|
+
}
|
|
11028
|
+
function daemonClaimPath() {
|
|
11029
|
+
return `${daemonLockfilePath()}.claim`;
|
|
11030
|
+
}
|
|
11031
|
+
function parseDaemonClaim(raw) {
|
|
11032
|
+
try {
|
|
11033
|
+
const value = JSON.parse(raw);
|
|
11034
|
+
if (value !== null && typeof value === "object" && typeof Reflect.get(value, "pid") === "number" && typeof Reflect.get(value, "startedAt") === "number" && typeof Reflect.get(value, "createdAt") === "number") {
|
|
11035
|
+
return {
|
|
11036
|
+
pid: Reflect.get(value, "pid"),
|
|
11037
|
+
startedAt: Reflect.get(value, "startedAt"),
|
|
11038
|
+
createdAt: Reflect.get(value, "createdAt")
|
|
11039
|
+
};
|
|
11040
|
+
}
|
|
11041
|
+
} catch {
|
|
11042
|
+
}
|
|
11043
|
+
return null;
|
|
11044
|
+
}
|
|
11045
|
+
function readDaemonClaim() {
|
|
11046
|
+
try {
|
|
11047
|
+
return parseDaemonClaim(import_node_fs3.default.readFileSync(daemonClaimPath(), "utf8"));
|
|
11048
|
+
} catch {
|
|
11049
|
+
return null;
|
|
11050
|
+
}
|
|
11051
|
+
}
|
|
11052
|
+
function isDaemonClaimFresh(claim, now = Date.now()) {
|
|
11053
|
+
if (now - claim.createdAt > DAEMON_CLAIM_STALE_MS) return false;
|
|
11054
|
+
try {
|
|
11055
|
+
process.kill(claim.pid, 0);
|
|
11056
|
+
return true;
|
|
11057
|
+
} catch {
|
|
11058
|
+
return false;
|
|
11059
|
+
}
|
|
11060
|
+
}
|
|
11061
|
+
function acquireDaemonClaim(data) {
|
|
11062
|
+
const claim = {
|
|
11063
|
+
pid: data.pid,
|
|
11064
|
+
startedAt: data.startedAt,
|
|
11065
|
+
createdAt: Date.now()
|
|
11066
|
+
};
|
|
11067
|
+
const serialized = `${JSON.stringify(claim)}
|
|
11068
|
+
`;
|
|
11069
|
+
for (let attempt = 0; attempt < 8; attempt++) {
|
|
11070
|
+
try {
|
|
11071
|
+
import_node_fs3.default.writeFileSync(daemonClaimPath(), serialized, { encoding: "utf8", flag: "wx" });
|
|
11072
|
+
return true;
|
|
11073
|
+
} catch (error) {
|
|
11074
|
+
if (!isAlreadyExists(error)) throw error;
|
|
11075
|
+
}
|
|
11076
|
+
const existing = readDaemonClaim();
|
|
11077
|
+
if (existing && sameDaemonOwner(existing, claim)) return true;
|
|
11078
|
+
if (existing && isDaemonClaimFresh(existing)) return false;
|
|
11079
|
+
let before;
|
|
11080
|
+
try {
|
|
11081
|
+
before = import_node_fs3.default.readFileSync(daemonClaimPath(), "utf8");
|
|
11082
|
+
const latest = parseDaemonClaim(before);
|
|
11083
|
+
if (latest && isDaemonClaimFresh(latest)) return false;
|
|
11084
|
+
if (import_node_fs3.default.readFileSync(daemonClaimPath(), "utf8") !== before) continue;
|
|
11085
|
+
import_node_fs3.default.unlinkSync(daemonClaimPath());
|
|
11086
|
+
} catch {
|
|
11087
|
+
}
|
|
11088
|
+
}
|
|
11089
|
+
return false;
|
|
11090
|
+
}
|
|
11091
|
+
function releaseDaemonClaim(owner) {
|
|
11092
|
+
try {
|
|
11093
|
+
const claim = readDaemonClaim();
|
|
11094
|
+
if (!claim || !sameDaemonOwner(claim, owner)) return;
|
|
11095
|
+
import_node_fs3.default.unlinkSync(daemonClaimPath());
|
|
11096
|
+
} catch {
|
|
11097
|
+
}
|
|
11098
|
+
}
|
|
10910
11099
|
function claimDaemonLockfile(data) {
|
|
10911
11100
|
ensureSootsimHome();
|
|
10912
|
-
|
|
10913
|
-
|
|
10914
|
-
|
|
11101
|
+
if (!acquireDaemonClaim(data)) return false;
|
|
11102
|
+
try {
|
|
11103
|
+
const existing = readDaemonLockfile();
|
|
11104
|
+
if (existing && sameDaemonOwner(existing, data)) {
|
|
11105
|
+
writeDaemonLockfile(data);
|
|
11106
|
+
return true;
|
|
11107
|
+
}
|
|
11108
|
+
if (existing && isDaemonLockfileFresh(existing)) return false;
|
|
11109
|
+
if (existing) {
|
|
11110
|
+
const latest = readDaemonLockfile();
|
|
11111
|
+
if (!latest || !sameDaemonOwner(latest, existing)) return false;
|
|
11112
|
+
if (isDaemonLockfileFresh(latest)) return false;
|
|
11113
|
+
try {
|
|
11114
|
+
import_node_fs3.default.unlinkSync(daemonLockfilePath());
|
|
11115
|
+
} catch {
|
|
11116
|
+
return false;
|
|
11117
|
+
}
|
|
11118
|
+
}
|
|
11119
|
+
return createDaemonLockfileExclusive(data);
|
|
11120
|
+
} finally {
|
|
11121
|
+
releaseDaemonClaim(data);
|
|
10915
11122
|
}
|
|
10916
|
-
writeDaemonLockfile(data);
|
|
10917
|
-
return true;
|
|
10918
11123
|
}
|
|
10919
|
-
function removeDaemonLockfile() {
|
|
11124
|
+
function removeDaemonLockfile(owner) {
|
|
10920
11125
|
try {
|
|
11126
|
+
const lockfile = readDaemonLockfile();
|
|
11127
|
+
if (!lockfile || !sameDaemonOwner(lockfile, owner)) return;
|
|
10921
11128
|
import_node_fs3.default.unlinkSync(daemonLockfilePath());
|
|
10922
11129
|
} catch {
|
|
10923
11130
|
}
|
|
@@ -10931,7 +11138,7 @@ function removeDevBridgeLockfile(owner) {
|
|
|
10931
11138
|
} catch {
|
|
10932
11139
|
}
|
|
10933
11140
|
}
|
|
10934
|
-
var import_node_crypto, import_node_fs3, import_node_os, import_node_path4, SOOTSIM_HOME_ENV, ACTIVE_RUNTIME_FILE, DAEMON_LOCKFILE, DEV_BRIDGES_DIR, CONFIG_FILE, DAEMON_HEARTBEAT_STALE_MS, DAEMON_LOCKFILE_MAX_BYTES;
|
|
11141
|
+
var import_node_crypto, import_node_fs3, import_node_os, import_node_path4, SOOTSIM_HOME_ENV, ACTIVE_RUNTIME_FILE, DAEMON_LOCKFILE, DEV_BRIDGES_DIR, CONFIG_FILE, DAEMON_HEARTBEAT_STALE_MS, DAEMON_LOCKFILE_MAX_BYTES, DAEMON_CLAIM_STALE_MS;
|
|
10935
11142
|
var init_home_paths = __esm({
|
|
10936
11143
|
"src/home-paths.ts"() {
|
|
10937
11144
|
"use strict";
|
|
@@ -10946,6 +11153,7 @@ var init_home_paths = __esm({
|
|
|
10946
11153
|
CONFIG_FILE = "config.json";
|
|
10947
11154
|
DAEMON_HEARTBEAT_STALE_MS = 3e4;
|
|
10948
11155
|
DAEMON_LOCKFILE_MAX_BYTES = 16 * 1024;
|
|
11156
|
+
DAEMON_CLAIM_STALE_MS = 3e4;
|
|
10949
11157
|
}
|
|
10950
11158
|
});
|
|
10951
11159
|
|
|
@@ -12870,20 +13078,6 @@ var init_agent_host = __esm({
|
|
|
12870
13078
|
}
|
|
12871
13079
|
});
|
|
12872
13080
|
|
|
12873
|
-
// src/backend-origin.ts
|
|
12874
|
-
function normalizeHostname(hostname) {
|
|
12875
|
-
return hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
12876
|
-
}
|
|
12877
|
-
function isLoopbackHost(hostname) {
|
|
12878
|
-
const normalized = normalizeHostname(hostname);
|
|
12879
|
-
return normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "0.0.0.0" || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
|
|
12880
|
-
}
|
|
12881
|
-
var init_backend_origin = __esm({
|
|
12882
|
-
"src/backend-origin.ts"() {
|
|
12883
|
-
"use strict";
|
|
12884
|
-
}
|
|
12885
|
-
});
|
|
12886
|
-
|
|
12887
13081
|
// src/host/fetch-proxy-overrides.ts
|
|
12888
13082
|
function headerOverridesFor(hostname) {
|
|
12889
13083
|
const host = hostname.toLowerCase();
|
|
@@ -13367,9 +13561,18 @@ export const Appearance = rn.Appearance
|
|
|
13367
13561
|
`;
|
|
13368
13562
|
}
|
|
13369
13563
|
function sendJavaScript(req, res, source) {
|
|
13564
|
+
const origin = req.headers.origin;
|
|
13565
|
+
let allowedOrigin;
|
|
13566
|
+
if (origin) {
|
|
13567
|
+
try {
|
|
13568
|
+
if (isLoopbackHost(new URL(origin).hostname)) allowedOrigin = origin;
|
|
13569
|
+
} catch {
|
|
13570
|
+
}
|
|
13571
|
+
}
|
|
13370
13572
|
res.writeHead(200, {
|
|
13371
13573
|
"Content-Type": "application/javascript; charset=utf-8",
|
|
13372
|
-
"Cache-Control": "no-cache"
|
|
13574
|
+
"Cache-Control": "no-cache",
|
|
13575
|
+
...allowedOrigin ? { "Access-Control-Allow-Origin": allowedOrigin, Vary: "Origin" } : {}
|
|
13373
13576
|
});
|
|
13374
13577
|
res.end(req.method === "HEAD" ? void 0 : source);
|
|
13375
13578
|
}
|
|
@@ -13390,6 +13593,23 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
|
|
|
13390
13593
|
} catch {
|
|
13391
13594
|
return false;
|
|
13392
13595
|
}
|
|
13596
|
+
if (options.requireLoopbackOrigin) {
|
|
13597
|
+
const origin = req.headers.origin;
|
|
13598
|
+
const remoteAddress = req.socket.remoteAddress?.replace(/^::ffff:/, "");
|
|
13599
|
+
let allowed = Boolean(remoteAddress && isLoopbackHost(remoteAddress));
|
|
13600
|
+
if (allowed && origin) {
|
|
13601
|
+
try {
|
|
13602
|
+
allowed = isLoopbackHost(new URL(origin).hostname);
|
|
13603
|
+
} catch {
|
|
13604
|
+
allowed = false;
|
|
13605
|
+
}
|
|
13606
|
+
}
|
|
13607
|
+
if (!allowed) {
|
|
13608
|
+
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
13609
|
+
res.end("replacement modules are available only to loopback origins");
|
|
13610
|
+
return true;
|
|
13611
|
+
}
|
|
13612
|
+
}
|
|
13393
13613
|
if (url.pathname === `${REPLACEMENT_RUNTIME_PREFIX}/react`) {
|
|
13394
13614
|
sendJavaScript(req, res, reactRuntimeSource(options.reactBridgeUrl));
|
|
13395
13615
|
return true;
|
|
@@ -13399,6 +13619,11 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
|
|
|
13399
13619
|
return true;
|
|
13400
13620
|
}
|
|
13401
13621
|
if (url.pathname !== REPLACEMENT_MODULE_ROUTE) return false;
|
|
13622
|
+
if (options.requestToken && url.searchParams.get("token") !== options.requestToken) {
|
|
13623
|
+
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
13624
|
+
res.end("replacement module request token is invalid");
|
|
13625
|
+
return true;
|
|
13626
|
+
}
|
|
13402
13627
|
const targetPath = url.searchParams.get("path");
|
|
13403
13628
|
if (!targetPath) {
|
|
13404
13629
|
res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
|
|
@@ -13411,17 +13636,42 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
|
|
|
13411
13636
|
res.end("replacement files must be .js, .jsx, .ts, or .tsx");
|
|
13412
13637
|
return true;
|
|
13413
13638
|
}
|
|
13639
|
+
if (!import_node_path10.default.isAbsolute(targetPath)) {
|
|
13640
|
+
res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
|
|
13641
|
+
res.end("replacement file path must be absolute");
|
|
13642
|
+
return true;
|
|
13643
|
+
}
|
|
13644
|
+
let resolvedProjectRoot;
|
|
13645
|
+
if (options.projectRoot) {
|
|
13646
|
+
const lexicalProjectRoot = import_node_path10.default.resolve(options.projectRoot);
|
|
13647
|
+
resolvedProjectRoot = await import_promises5.default.realpath(options.projectRoot);
|
|
13648
|
+
const lexicalTarget = import_node_path10.default.relative(lexicalProjectRoot, targetPath);
|
|
13649
|
+
if (lexicalTarget.startsWith("..") || import_node_path10.default.isAbsolute(lexicalTarget)) {
|
|
13650
|
+
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
13651
|
+
res.end("replacement file must be inside the project root");
|
|
13652
|
+
return true;
|
|
13653
|
+
}
|
|
13654
|
+
}
|
|
13655
|
+
let resolvedTargetPath;
|
|
13414
13656
|
try {
|
|
13415
|
-
await import_promises5.default.
|
|
13657
|
+
resolvedTargetPath = await import_promises5.default.realpath(targetPath);
|
|
13416
13658
|
} catch (error) {
|
|
13417
13659
|
const message = error instanceof Error ? error.message : String(error);
|
|
13418
13660
|
res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
|
13419
13661
|
res.end(`replacement file not found: ${message}`);
|
|
13420
13662
|
return true;
|
|
13421
13663
|
}
|
|
13664
|
+
if (resolvedProjectRoot) {
|
|
13665
|
+
const relativeTarget = import_node_path10.default.relative(resolvedProjectRoot, resolvedTargetPath);
|
|
13666
|
+
if (relativeTarget.startsWith("..") || import_node_path10.default.isAbsolute(relativeTarget)) {
|
|
13667
|
+
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
13668
|
+
res.end("replacement file must be inside the project root");
|
|
13669
|
+
return true;
|
|
13670
|
+
}
|
|
13671
|
+
}
|
|
13422
13672
|
try {
|
|
13423
13673
|
const result = await (0, import_esbuild.build)({
|
|
13424
|
-
entryPoints: [
|
|
13674
|
+
entryPoints: [resolvedTargetPath],
|
|
13425
13675
|
bundle: true,
|
|
13426
13676
|
write: false,
|
|
13427
13677
|
format: "esm",
|
|
@@ -13460,6 +13710,7 @@ var init_replacement_module_handler = __esm({
|
|
|
13460
13710
|
import_promises5 = __toESM(require("node:fs/promises"), 1);
|
|
13461
13711
|
import_node_path10 = __toESM(require("node:path"), 1);
|
|
13462
13712
|
import_esbuild = require("esbuild");
|
|
13713
|
+
init_backend_origin();
|
|
13463
13714
|
REPLACEMENT_MODULE_ROUTE = "/__sootsim-replacement-module";
|
|
13464
13715
|
REPLACEMENT_RUNTIME_PREFIX = "/__sootsim-replacement-runtime";
|
|
13465
13716
|
}
|
|
@@ -14726,7 +14977,7 @@ var init_bridge_host = __esm({
|
|
|
14726
14977
|
removeLockfile() {
|
|
14727
14978
|
if (!this.shouldWriteLockfile) return;
|
|
14728
14979
|
try {
|
|
14729
|
-
removeDaemonLockfile();
|
|
14980
|
+
removeDaemonLockfile({ pid: process.pid, startedAt: this.startedAt });
|
|
14730
14981
|
} catch {
|
|
14731
14982
|
}
|
|
14732
14983
|
}
|
|
@@ -15285,7 +15536,7 @@ var init_bridge_host = __esm({
|
|
|
15285
15536
|
}
|
|
15286
15537
|
if (this.shouldWriteLockfile) {
|
|
15287
15538
|
try {
|
|
15288
|
-
removeDaemonLockfile();
|
|
15539
|
+
removeDaemonLockfile({ pid: process.pid, startedAt: this.startedAt });
|
|
15289
15540
|
} catch {
|
|
15290
15541
|
}
|
|
15291
15542
|
}
|
|
@@ -16487,11 +16738,11 @@ async function evalInBridge(bridge, code, opts = {}) {
|
|
|
16487
16738
|
if (opts.acquireLock) payload.acquireLock = true;
|
|
16488
16739
|
return bridge.send(payload);
|
|
16489
16740
|
}
|
|
16490
|
-
async function callInBridge(bridge,
|
|
16491
|
-
return bridge.send({ type: "call", path:
|
|
16741
|
+
async function callInBridge(bridge, path18, ...args) {
|
|
16742
|
+
return bridge.send({ type: "call", path: path18, args });
|
|
16492
16743
|
}
|
|
16493
|
-
async function callInBridgeWrite(bridge,
|
|
16494
|
-
return bridge.send({ type: "call", path:
|
|
16744
|
+
async function callInBridgeWrite(bridge, path18, ...args) {
|
|
16745
|
+
return bridge.send({ type: "call", path: path18, args, acquireLock: true });
|
|
16495
16746
|
}
|
|
16496
16747
|
var import_node_fs9, import_node_path11, import_ws3, resolvedWorld, BridgeSimLockedError;
|
|
16497
16748
|
var init_ws_bridge = __esm({
|
|
@@ -16553,8 +16804,8 @@ function getDefaultPortForProtocol(protocol) {
|
|
|
16553
16804
|
return protocol === "https:" ? 443 : 80;
|
|
16554
16805
|
}
|
|
16555
16806
|
function isBaseServerUrl(url) {
|
|
16556
|
-
const
|
|
16557
|
-
return (
|
|
16807
|
+
const path18 = url.pathname || "/";
|
|
16808
|
+
return (path18 === "/" || path18 === "") && !url.search && !url.hash;
|
|
16558
16809
|
}
|
|
16559
16810
|
async function resolvePortViaServerScan(port) {
|
|
16560
16811
|
try {
|
|
@@ -16570,8 +16821,8 @@ async function resolvePortViaServerScan(port) {
|
|
|
16570
16821
|
if (!match) return null;
|
|
16571
16822
|
return {
|
|
16572
16823
|
// normalize exactly like the manifest-probe branch below — the scan
|
|
16573
|
-
// returns metro's
|
|
16574
|
-
// apps), but sootsim loads ONE self-contained bundle into the tenant
|
|
16824
|
+
// returns metro's manifest launchAsset url (lazy=true for code-split
|
|
16825
|
+
// one/vxrn apps), but sootsim loads ONE self-contained bundle into the tenant
|
|
16575
16826
|
// worker, so a deferred React.lazy chunk throws "Requiring unknown module
|
|
16576
16827
|
// <id>". normalizeNativeDevBundleUrl forces lazy=false + strips bytecode.
|
|
16577
16828
|
bundleUrl: normalizeNativeDevBundleUrl(match.bundleUrl),
|
|
@@ -16583,15 +16834,8 @@ async function resolvePortViaServerScan(port) {
|
|
|
16583
16834
|
return null;
|
|
16584
16835
|
}
|
|
16585
16836
|
}
|
|
16586
|
-
async function
|
|
16837
|
+
async function probeBaseUrlBundleDirect(baseUrl, port) {
|
|
16587
16838
|
const normalizedBaseUrl = baseUrl.replace(/\/+$/, "");
|
|
16588
|
-
try {
|
|
16589
|
-
if (isLoopbackHost(new URL(normalizedBaseUrl).hostname)) {
|
|
16590
|
-
const viaScan = await resolvePortViaServerScan(port);
|
|
16591
|
-
if (viaScan) return viaScan;
|
|
16592
|
-
}
|
|
16593
|
-
} catch {
|
|
16594
|
-
}
|
|
16595
16839
|
try {
|
|
16596
16840
|
const manifestRes = await fetchDevProbe(`${normalizedBaseUrl}/`, {
|
|
16597
16841
|
headers: { "expo-platform": "ios" }
|
|
@@ -16599,7 +16843,8 @@ async function probeBaseUrlBundle(baseUrl, port) {
|
|
|
16599
16843
|
if (manifestRes.ok) {
|
|
16600
16844
|
const manifest = await manifestRes.json();
|
|
16601
16845
|
const client = manifest?.extra?.expoClient || manifest?.extra || {};
|
|
16602
|
-
const
|
|
16846
|
+
const rawLaunchUrl = typeof manifest?.launchAsset?.url === "string" ? manifest.launchAsset.url : void 0;
|
|
16847
|
+
const launchUrl2 = rawLaunchUrl ? alignLoopbackBundleUrlWithProbe(rawLaunchUrl, normalizedBaseUrl) : void 0;
|
|
16603
16848
|
if (launchUrl2 || client.name) {
|
|
16604
16849
|
return {
|
|
16605
16850
|
bundleUrl: normalizeNativeDevBundleUrl(
|
|
@@ -16629,8 +16874,25 @@ async function probeBaseUrlBundle(baseUrl, port) {
|
|
|
16629
16874
|
}
|
|
16630
16875
|
return null;
|
|
16631
16876
|
}
|
|
16877
|
+
async function probeBaseUrlBundle(baseUrl, port) {
|
|
16878
|
+
try {
|
|
16879
|
+
if (isLoopbackHost(new URL(baseUrl).hostname)) {
|
|
16880
|
+
const viaScan = await resolvePortViaServerScan(port);
|
|
16881
|
+
if (viaScan) return viaScan;
|
|
16882
|
+
}
|
|
16883
|
+
} catch {
|
|
16884
|
+
}
|
|
16885
|
+
return probeBaseUrlBundleDirect(baseUrl, port);
|
|
16886
|
+
}
|
|
16632
16887
|
async function probePortBundle(port) {
|
|
16633
|
-
|
|
16888
|
+
const viaScan = await resolvePortViaServerScan(port);
|
|
16889
|
+
if (viaScan) return viaScan;
|
|
16890
|
+
const candidates = await Promise.all(
|
|
16891
|
+
LOOPBACK_PROBE_HOSTNAMES.map(
|
|
16892
|
+
(hostname) => probeBaseUrlBundleDirect(buildLoopbackProbeBaseUrl("http:", hostname, port), port)
|
|
16893
|
+
)
|
|
16894
|
+
);
|
|
16895
|
+
return candidates.find((candidate) => candidate !== null) ?? null;
|
|
16634
16896
|
}
|
|
16635
16897
|
async function resolveConnectionInput(input) {
|
|
16636
16898
|
const trimmed = input.trim();
|
|
@@ -16788,150 +17050,20 @@ function findExpoAppConfig(dir) {
|
|
|
16788
17050
|
function findSootSimAppConfig(dir) {
|
|
16789
17051
|
return firstNamedFile(dir, SOOTSIM_APP_CONFIG_NAMES);
|
|
16790
17052
|
}
|
|
16791
|
-
function
|
|
17053
|
+
function resolveAppProject(projectRoot) {
|
|
17054
|
+
const appDir = import_node_path12.default.resolve(projectRoot);
|
|
16792
17055
|
try {
|
|
16793
|
-
|
|
16794
|
-
if (!value || typeof value !== "object") return [];
|
|
16795
|
-
const workspaces = Reflect.get(value, "workspaces");
|
|
16796
|
-
if (Array.isArray(workspaces)) {
|
|
16797
|
-
return workspaces.filter((entry) => typeof entry === "string");
|
|
16798
|
-
}
|
|
16799
|
-
if (!workspaces || typeof workspaces !== "object") return [];
|
|
16800
|
-
const packages = Reflect.get(workspaces, "packages");
|
|
16801
|
-
return Array.isArray(packages) ? packages.filter((entry) => typeof entry === "string") : [];
|
|
17056
|
+
if (!import_node_fs10.default.statSync(appDir).isDirectory()) return null;
|
|
16802
17057
|
} catch {
|
|
16803
|
-
return
|
|
16804
|
-
}
|
|
16805
|
-
}
|
|
16806
|
-
function workspaceDirectories(rootDir) {
|
|
16807
|
-
const directories = /* @__PURE__ */ new Set();
|
|
16808
|
-
let expanded = 0;
|
|
16809
|
-
let complete = true;
|
|
16810
|
-
for (const pattern of readWorkspacePatterns(rootDir)) {
|
|
16811
|
-
if (expanded >= MAX_SCANNED_DIRECTORIES) {
|
|
16812
|
-
complete = false;
|
|
16813
|
-
break;
|
|
16814
|
-
}
|
|
16815
|
-
if (!pattern || import_node_path12.default.isAbsolute(pattern)) continue;
|
|
16816
|
-
const segments = pattern.split(/[\\/]+/).filter(Boolean);
|
|
16817
|
-
if (segments.length === 0 || segments.length > MAX_SCAN_DEPTH) continue;
|
|
16818
|
-
if (segments.some((segment) => segment === ".." || segment === "**")) continue;
|
|
16819
|
-
let current = [rootDir];
|
|
16820
|
-
for (const segment of segments) {
|
|
16821
|
-
const next = [];
|
|
16822
|
-
for (const parent of current) {
|
|
16823
|
-
if (expanded >= MAX_SCANNED_DIRECTORIES) {
|
|
16824
|
-
complete = false;
|
|
16825
|
-
break;
|
|
16826
|
-
}
|
|
16827
|
-
expanded++;
|
|
16828
|
-
if (segment === "*") {
|
|
16829
|
-
let entries;
|
|
16830
|
-
try {
|
|
16831
|
-
entries = import_node_fs10.default.readdirSync(parent, { withFileTypes: true });
|
|
16832
|
-
} catch {
|
|
16833
|
-
continue;
|
|
16834
|
-
}
|
|
16835
|
-
for (const entry of entries) {
|
|
16836
|
-
if (!entry.isDirectory() || entry.isSymbolicLink()) continue;
|
|
16837
|
-
if (entry.name.startsWith(".") || SKIP_DIR_NAMES.has(entry.name)) continue;
|
|
16838
|
-
next.push(import_node_path12.default.join(parent, entry.name));
|
|
16839
|
-
}
|
|
16840
|
-
} else if (!segment.includes("*")) {
|
|
16841
|
-
const candidate = import_node_path12.default.join(parent, segment);
|
|
16842
|
-
try {
|
|
16843
|
-
const stat2 = import_node_fs10.default.lstatSync(candidate);
|
|
16844
|
-
if (stat2.isDirectory() && !stat2.isSymbolicLink()) next.push(candidate);
|
|
16845
|
-
} catch {
|
|
16846
|
-
}
|
|
16847
|
-
}
|
|
16848
|
-
}
|
|
16849
|
-
current = next;
|
|
16850
|
-
if (current.length > MAX_SCANNED_DIRECTORIES) {
|
|
16851
|
-
current.length = MAX_SCANNED_DIRECTORIES;
|
|
16852
|
-
complete = false;
|
|
16853
|
-
}
|
|
16854
|
-
}
|
|
16855
|
-
for (const directory of current) directories.add(directory);
|
|
16856
|
-
}
|
|
16857
|
-
return { directories: [...directories], complete };
|
|
16858
|
-
}
|
|
16859
|
-
function boundedConfigDirectories(rootDir) {
|
|
16860
|
-
const queue = [{ dir: rootDir, depth: 0 }];
|
|
16861
|
-
const matches = [];
|
|
16862
|
-
let visited = 0;
|
|
16863
|
-
let nextIndex = 0;
|
|
16864
|
-
let complete = true;
|
|
16865
|
-
while (nextIndex < queue.length && visited < MAX_SCANNED_DIRECTORIES) {
|
|
16866
|
-
const current = queue[nextIndex++];
|
|
16867
|
-
if (!current) break;
|
|
16868
|
-
visited++;
|
|
16869
|
-
if (current.depth > 0 && findExpoAppConfig(current.dir)) {
|
|
16870
|
-
matches.push(current.dir);
|
|
16871
|
-
if (matches.length > 1) return { directories: matches, complete: true };
|
|
16872
|
-
}
|
|
16873
|
-
if (current.depth >= MAX_SCAN_DEPTH) continue;
|
|
16874
|
-
let entries;
|
|
16875
|
-
try {
|
|
16876
|
-
entries = import_node_fs10.default.readdirSync(current.dir, { withFileTypes: true });
|
|
16877
|
-
} catch {
|
|
16878
|
-
continue;
|
|
16879
|
-
}
|
|
16880
|
-
for (const entry of entries) {
|
|
16881
|
-
if (!entry.isDirectory() || entry.isSymbolicLink()) continue;
|
|
16882
|
-
if (entry.name.startsWith(".") || SKIP_DIR_NAMES.has(entry.name)) continue;
|
|
16883
|
-
if (queue.length >= MAX_SCANNED_DIRECTORIES) {
|
|
16884
|
-
complete = false;
|
|
16885
|
-
break;
|
|
16886
|
-
}
|
|
16887
|
-
queue.push({ dir: import_node_path12.default.join(current.dir, entry.name), depth: current.depth + 1 });
|
|
16888
|
-
}
|
|
16889
|
-
}
|
|
16890
|
-
return { directories: matches, complete: complete && nextIndex === queue.length };
|
|
16891
|
-
}
|
|
16892
|
-
function resolveAppProject(startDir, opts = {}) {
|
|
16893
|
-
const rootDir = import_node_path12.default.resolve(startDir);
|
|
16894
|
-
const rootConfigPath = findSootSimAppConfig(rootDir);
|
|
16895
|
-
if (findExpoAppConfig(rootDir) || opts.trustStart && import_node_fs10.default.existsSync(rootDir)) {
|
|
16896
|
-
let configPath = rootConfigPath;
|
|
16897
|
-
if (!configPath && opts.trustStart) {
|
|
16898
|
-
let parent = import_node_path12.default.dirname(rootDir);
|
|
16899
|
-
for (let depth = 0; depth < MAX_SCAN_DEPTH && parent !== import_node_path12.default.dirname(parent); depth++) {
|
|
16900
|
-
configPath = findSootSimAppConfig(parent);
|
|
16901
|
-
if (configPath) break;
|
|
16902
|
-
parent = import_node_path12.default.dirname(parent);
|
|
16903
|
-
}
|
|
16904
|
-
}
|
|
16905
|
-
return { appDir: rootDir, configPath };
|
|
16906
|
-
}
|
|
16907
|
-
const workspaceScan = workspaceDirectories(rootDir);
|
|
16908
|
-
const workspaceApps = workspaceScan.directories.filter(
|
|
16909
|
-
(directory) => findExpoAppConfig(directory)
|
|
16910
|
-
);
|
|
16911
|
-
if (workspaceApps.length > 1) return null;
|
|
16912
|
-
if (!workspaceScan.complete) return null;
|
|
16913
|
-
if (workspaceApps.length === 1) {
|
|
16914
|
-
const workspaceAppDir = workspaceApps[0];
|
|
16915
|
-
return {
|
|
16916
|
-
appDir: workspaceAppDir,
|
|
16917
|
-
configPath: rootConfigPath ?? findSootSimAppConfig(workspaceAppDir)
|
|
16918
|
-
};
|
|
17058
|
+
return null;
|
|
16919
17059
|
}
|
|
16920
|
-
const
|
|
16921
|
-
|
|
16922
|
-
|
|
16923
|
-
if (!fallbackScan.complete) return null;
|
|
16924
|
-
if (scannedApps.length === 1) {
|
|
16925
|
-
const scannedAppDir = scannedApps[0];
|
|
16926
|
-
return {
|
|
16927
|
-
appDir: scannedAppDir,
|
|
16928
|
-
configPath: rootConfigPath ?? findSootSimAppConfig(scannedAppDir)
|
|
16929
|
-
};
|
|
17060
|
+
const configPath = findSootSimAppConfig(appDir);
|
|
17061
|
+
if (!configPath && !findExpoAppConfig(appDir) && !import_node_fs10.default.existsSync(import_node_path12.default.join(appDir, "package.json"))) {
|
|
17062
|
+
return null;
|
|
16930
17063
|
}
|
|
16931
|
-
|
|
16932
|
-
return null;
|
|
17064
|
+
return { appDir, configPath };
|
|
16933
17065
|
}
|
|
16934
|
-
var import_node_fs10, import_node_path12, EXPO_APP_CONFIG_NAMES, SOOTSIM_APP_CONFIG_NAMES
|
|
17066
|
+
var import_node_fs10, import_node_path12, EXPO_APP_CONFIG_NAMES, SOOTSIM_APP_CONFIG_NAMES;
|
|
16935
17067
|
var init_app_project = __esm({
|
|
16936
17068
|
"cli/app-project.ts"() {
|
|
16937
17069
|
"use strict";
|
|
@@ -16950,28 +17082,6 @@ var init_app_project = __esm({
|
|
|
16950
17082
|
"sootsim.config.mjs",
|
|
16951
17083
|
"sootsim.config.cjs"
|
|
16952
17084
|
];
|
|
16953
|
-
SKIP_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
16954
|
-
"node_modules",
|
|
16955
|
-
"artifacts",
|
|
16956
|
-
"dist",
|
|
16957
|
-
"build",
|
|
16958
|
-
"out",
|
|
16959
|
-
"coverage",
|
|
16960
|
-
"tmp",
|
|
16961
|
-
"public",
|
|
16962
|
-
"ios",
|
|
16963
|
-
"android",
|
|
16964
|
-
"macos",
|
|
16965
|
-
"windows",
|
|
16966
|
-
"__fixtures__",
|
|
16967
|
-
"__tests__",
|
|
16968
|
-
"fixtures",
|
|
16969
|
-
"fixture",
|
|
16970
|
-
"examples",
|
|
16971
|
-
"example"
|
|
16972
|
-
]);
|
|
16973
|
-
MAX_SCANNED_DIRECTORIES = 256;
|
|
16974
|
-
MAX_SCAN_DEPTH = 4;
|
|
16975
17085
|
}
|
|
16976
17086
|
});
|
|
16977
17087
|
|
|
@@ -17049,28 +17159,18 @@ function localOriginOf(value) {
|
|
|
17049
17159
|
}
|
|
17050
17160
|
return null;
|
|
17051
17161
|
}
|
|
17052
|
-
function hasPackageJson(dir) {
|
|
17053
|
-
try {
|
|
17054
|
-
return import_node_fs11.default.statSync(import_node_path14.default.join(dir, "package.json")).isFile();
|
|
17055
|
-
} catch {
|
|
17056
|
-
return false;
|
|
17057
|
-
}
|
|
17058
|
-
}
|
|
17059
17162
|
function discoverNativeLinkedAppFonts(opts) {
|
|
17060
17163
|
const metroOrigin = localOriginOf(opts.bundleUrl);
|
|
17061
17164
|
if (!metroOrigin) return [];
|
|
17062
|
-
const
|
|
17063
|
-
const startDir = explicit ? import_node_path14.default.resolve(explicit) : process.cwd();
|
|
17064
|
-
if (!explicit && !hasPackageJson(startDir)) return [];
|
|
17065
|
-
const project = resolveAppProject(startDir, { trustStart: opts.exactProjectDir });
|
|
17165
|
+
const project = resolveAppProject(opts.projectDir);
|
|
17066
17166
|
const selectedAppDir = project?.appDir ?? null;
|
|
17067
17167
|
if (!selectedAppDir) return [];
|
|
17068
17168
|
const platform = (opts.platform || process.env.CONTRAST_PLATFORM || "ios").toLowerCase();
|
|
17069
17169
|
let getConfig = null;
|
|
17070
|
-
if (
|
|
17170
|
+
if (project) {
|
|
17071
17171
|
try {
|
|
17072
17172
|
const modulePath = require3.resolve("@expo/config", {
|
|
17073
|
-
paths: [selectedAppDir
|
|
17173
|
+
paths: [selectedAppDir]
|
|
17074
17174
|
});
|
|
17075
17175
|
const mod = require3(modulePath);
|
|
17076
17176
|
if (typeof mod.getConfig === "function") {
|
|
@@ -17289,27 +17389,17 @@ function localOriginOf2(value) {
|
|
|
17289
17389
|
}
|
|
17290
17390
|
return null;
|
|
17291
17391
|
}
|
|
17292
|
-
function hasPackageJson2(dir) {
|
|
17293
|
-
try {
|
|
17294
|
-
return import_node_fs12.default.statSync(import_node_path15.default.join(dir, "package.json")).isFile();
|
|
17295
|
-
} catch {
|
|
17296
|
-
return false;
|
|
17297
|
-
}
|
|
17298
|
-
}
|
|
17299
17392
|
function discoverConfigPluginAppSplash(opts) {
|
|
17300
17393
|
const metroOrigin = localOriginOf2(opts.bundleUrl);
|
|
17301
17394
|
if (!metroOrigin) return null;
|
|
17302
|
-
const
|
|
17303
|
-
const startDir = explicit ? import_node_path15.default.resolve(explicit) : process.cwd();
|
|
17304
|
-
if (!explicit && !hasPackageJson2(startDir)) return null;
|
|
17305
|
-
const project = resolveAppProject(startDir, { trustStart: opts.exactProjectDir });
|
|
17395
|
+
const project = resolveAppProject(opts.projectDir);
|
|
17306
17396
|
const selectedAppDir = project?.appDir ?? null;
|
|
17307
17397
|
if (!selectedAppDir) return null;
|
|
17308
17398
|
const platform = (opts.platform || process.env.CONTRAST_PLATFORM || "ios").toLowerCase();
|
|
17309
17399
|
let getConfig = null;
|
|
17310
17400
|
try {
|
|
17311
17401
|
const modulePath = require4.resolve("@expo/config", {
|
|
17312
|
-
paths: [selectedAppDir
|
|
17402
|
+
paths: [selectedAppDir]
|
|
17313
17403
|
});
|
|
17314
17404
|
const mod = require4(modulePath);
|
|
17315
17405
|
if (typeof mod.getConfig === "function") {
|
|
@@ -17334,13 +17424,11 @@ function discoverConfigPluginAppSplash(opts) {
|
|
|
17334
17424
|
function encodeAppSplashWire(spec) {
|
|
17335
17425
|
return encodeURIComponent(JSON.stringify(spec));
|
|
17336
17426
|
}
|
|
17337
|
-
var
|
|
17427
|
+
var import_node_module3, import_config_plugin_splash, require4;
|
|
17338
17428
|
var init_app_splash = __esm({
|
|
17339
17429
|
"cli/app-splash.ts"() {
|
|
17340
17430
|
"use strict";
|
|
17341
|
-
import_node_fs12 = __toESM(require("node:fs"), 1);
|
|
17342
17431
|
import_node_module3 = require("node:module");
|
|
17343
|
-
import_node_path15 = __toESM(require("node:path"), 1);
|
|
17344
17432
|
import_config_plugin_splash = require("sootsim-engine/engine/config-plugin-splash");
|
|
17345
17433
|
init_app_project();
|
|
17346
17434
|
require4 = (0, import_node_module3.createRequire)(__sootsim_import_meta_url);
|
|
@@ -18358,7 +18446,7 @@ function resolvePlaywright() {
|
|
|
18358
18446
|
try {
|
|
18359
18447
|
const modulePath = requireFromRoot.resolve(spec);
|
|
18360
18448
|
const packageJsonPath = requireFromRoot.resolve(`${spec}/package.json`);
|
|
18361
|
-
const parsed = JSON.parse((0,
|
|
18449
|
+
const parsed = JSON.parse((0, import_node_fs12.readFileSync)(packageJsonPath, "utf8"));
|
|
18362
18450
|
if (!isRecord3(parsed) || typeof parsed.version !== "string") continue;
|
|
18363
18451
|
const bin = parsed.bin;
|
|
18364
18452
|
let binPath = null;
|
|
@@ -18370,8 +18458,8 @@ function resolvePlaywright() {
|
|
|
18370
18458
|
binPath = typeof named === "string" ? named : typeof first === "string" ? first : null;
|
|
18371
18459
|
}
|
|
18372
18460
|
if (!binPath) continue;
|
|
18373
|
-
const cliPath = (0,
|
|
18374
|
-
if (!(0,
|
|
18461
|
+
const cliPath = (0, import_node_path15.join)((0, import_node_path15.dirname)(packageJsonPath), binPath);
|
|
18462
|
+
if (!(0, import_node_fs12.existsSync)(cliPath)) continue;
|
|
18375
18463
|
return {
|
|
18376
18464
|
spec,
|
|
18377
18465
|
modulePath,
|
|
@@ -18410,7 +18498,7 @@ function probeBrowser(resolved, env) {
|
|
|
18410
18498
|
return {
|
|
18411
18499
|
ok: true,
|
|
18412
18500
|
executablePath: parsed.executablePath,
|
|
18413
|
-
exists: parsed.exists && (0,
|
|
18501
|
+
exists: parsed.exists && (0, import_node_fs12.existsSync)(parsed.executablePath)
|
|
18414
18502
|
};
|
|
18415
18503
|
} catch (error) {
|
|
18416
18504
|
return {
|
|
@@ -18449,14 +18537,14 @@ ${detail}` : ""}`
|
|
|
18449
18537
|
}
|
|
18450
18538
|
return { ok: true, executablePath: after.executablePath, installed: true };
|
|
18451
18539
|
}
|
|
18452
|
-
var import_node_child_process5,
|
|
18540
|
+
var import_node_child_process5, import_node_fs12, import_node_module4, import_node_path15, PLAYWRIGHT_BROWSER_PROBE;
|
|
18453
18541
|
var init_playwright_provisioning = __esm({
|
|
18454
18542
|
"cli/drivers/playwright-provisioning.ts"() {
|
|
18455
18543
|
"use strict";
|
|
18456
18544
|
import_node_child_process5 = require("node:child_process");
|
|
18457
|
-
|
|
18545
|
+
import_node_fs12 = require("node:fs");
|
|
18458
18546
|
import_node_module4 = require("node:module");
|
|
18459
|
-
|
|
18547
|
+
import_node_path15 = require("node:path");
|
|
18460
18548
|
PLAYWRIGHT_BROWSER_PROBE = `
|
|
18461
18549
|
const { existsSync } = require('node:fs');
|
|
18462
18550
|
const modulePath = process.env.SOOTSIM_PW_MODULE;
|
|
@@ -19142,11 +19230,11 @@ function isChangelogEntry(value) {
|
|
|
19142
19230
|
)
|
|
19143
19231
|
);
|
|
19144
19232
|
}
|
|
19145
|
-
async function fetchRuntimeReleaseNotes(version,
|
|
19233
|
+
async function fetchRuntimeReleaseNotes(version, fetchImpl = fetch) {
|
|
19146
19234
|
try {
|
|
19147
19235
|
const url = new URL(SOOTSIM_CHANGELOG_API_URL);
|
|
19148
19236
|
url.searchParams.set("version", version);
|
|
19149
|
-
const response = await
|
|
19237
|
+
const response = await fetchImpl(url, {
|
|
19150
19238
|
headers: { accept: "application/json" },
|
|
19151
19239
|
signal: AbortSignal.timeout(5e3)
|
|
19152
19240
|
});
|
|
@@ -19551,9 +19639,12 @@ function shouldOpenAsDeepLink(target) {
|
|
|
19551
19639
|
return !/^https?:\/\//i.test(trimmed);
|
|
19552
19640
|
}
|
|
19553
19641
|
async function ensureBridgeForOpen(preferredPort, explicitPort = false) {
|
|
19554
|
-
if (await canConnectToBridge(preferredPort, 250)) return preferredPort;
|
|
19555
19642
|
const lock = readDaemonLockfile();
|
|
19556
19643
|
assertExplicitBridgeLock(preferredPort, explicitPort, lock);
|
|
19644
|
+
const preferredWorld = worldForBridgePort(preferredPort);
|
|
19645
|
+
if ((explicitPort || preferredWorld !== null) && await canConnectToBridge(preferredPort, 250)) {
|
|
19646
|
+
return preferredPort;
|
|
19647
|
+
}
|
|
19557
19648
|
if (lock && isDaemonLockfileFresh(lock) && await canConnectToBridge(lock.bridgePort, 500)) {
|
|
19558
19649
|
return lock.bridgePort;
|
|
19559
19650
|
}
|
|
@@ -19579,12 +19670,6 @@ async function ensureBridgeForOpen(preferredPort, explicitPort = false) {
|
|
|
19579
19670
|
);
|
|
19580
19671
|
return nextLock.bridgePort;
|
|
19581
19672
|
}
|
|
19582
|
-
if (await canConnectToBridge(preferredPort, 250)) {
|
|
19583
|
-
console.error(
|
|
19584
|
-
` started local bridge on port ${preferredPort}; run \`sootsim setup\` to install the background daemon`
|
|
19585
|
-
);
|
|
19586
|
-
return preferredPort;
|
|
19587
|
-
}
|
|
19588
19673
|
if (childExit) {
|
|
19589
19674
|
throw new Error(`rnx bridge exited before becoming ready (exit ${childExit})`);
|
|
19590
19675
|
}
|
|
@@ -19604,14 +19689,14 @@ function assertExplicitBridgeLock(preferredPort, explicitPort, lock) {
|
|
|
19604
19689
|
}
|
|
19605
19690
|
async function ensureRuntimeForOpen() {
|
|
19606
19691
|
const active = readActiveRuntime();
|
|
19607
|
-
if (active &&
|
|
19692
|
+
if (active && import_node_fs13.default.existsSync(runtimeDir(active))) return;
|
|
19608
19693
|
console.error(" installing rnx engine runtime...");
|
|
19609
19694
|
const { runRuntime: runRuntime2 } = await Promise.resolve().then(() => (init_runtime(), runtime_exports));
|
|
19610
19695
|
await runRuntime2(["install"], {});
|
|
19611
19696
|
}
|
|
19612
19697
|
function spawnSootsim(args) {
|
|
19613
19698
|
const entry = process.argv[1];
|
|
19614
|
-
if (entry &&
|
|
19699
|
+
if (entry && import_node_fs13.default.existsSync(entry)) {
|
|
19615
19700
|
return (0, import_node_child_process6.spawn)(process.execPath, [entry, ...args], {
|
|
19616
19701
|
detached: true,
|
|
19617
19702
|
stdio: "ignore",
|
|
@@ -19758,10 +19843,10 @@ async function buildResolvedBundleOpenUrl(target, baseUrl, opts = {}) {
|
|
|
19758
19843
|
}
|
|
19759
19844
|
function normalizeReplacementPath(filePath) {
|
|
19760
19845
|
if (filePath.startsWith("~/")) {
|
|
19761
|
-
return
|
|
19846
|
+
return import_node_path16.default.join(import_node_os3.default.homedir(), filePath.slice(2));
|
|
19762
19847
|
}
|
|
19763
|
-
if (
|
|
19764
|
-
return
|
|
19848
|
+
if (import_node_path16.default.isAbsolute(filePath)) return filePath;
|
|
19849
|
+
return import_node_path16.default.resolve(process.cwd(), filePath);
|
|
19765
19850
|
}
|
|
19766
19851
|
function parseOpenRuntimeConfig(args) {
|
|
19767
19852
|
const modules = {};
|
|
@@ -19780,7 +19865,7 @@ function parseOpenRuntimeConfig(args) {
|
|
|
19780
19865
|
}
|
|
19781
19866
|
const moduleName = raw.slice(0, eqIndex).trim();
|
|
19782
19867
|
const filePath = normalizeReplacementPath(raw.slice(eqIndex + 1).trim());
|
|
19783
|
-
if (!
|
|
19868
|
+
if (!import_node_fs13.default.existsSync(filePath)) {
|
|
19784
19869
|
console.error(` rnx open: replacement file not found: ${filePath}`);
|
|
19785
19870
|
process.exit(1);
|
|
19786
19871
|
}
|
|
@@ -19806,16 +19891,12 @@ function parseOpenRuntimeConfig(args) {
|
|
|
19806
19891
|
return config.modules || config.network ? config : void 0;
|
|
19807
19892
|
}
|
|
19808
19893
|
async function resolveOpenAppProject(resolvedBundle) {
|
|
19809
|
-
if (resolvedBundle)
|
|
19810
|
-
|
|
19811
|
-
|
|
19812
|
-
return resolveAppProject(advertisedRoot, { trustStart: true });
|
|
19813
|
-
}
|
|
19814
|
-
}
|
|
19815
|
-
return resolveAppProject(process.env.CONTRAST_REPO_DIR || process.cwd());
|
|
19894
|
+
if (!resolvedBundle) return null;
|
|
19895
|
+
const advertisedRoot = await resolveMetroProjectRoot(resolvedBundle.bundleUrl);
|
|
19896
|
+
return advertisedRoot ? resolveAppProject(advertisedRoot) : null;
|
|
19816
19897
|
}
|
|
19817
19898
|
async function ensureConfiguredRuntime(version) {
|
|
19818
|
-
if (
|
|
19899
|
+
if (import_node_fs13.default.existsSync(import_node_path16.default.join(runtimeDir(version), "index.html"))) return;
|
|
19819
19900
|
console.error(` installing configured engine runtime ${version}...`);
|
|
19820
19901
|
const result = await sootsimRuntime.install({
|
|
19821
19902
|
version,
|
|
@@ -19847,12 +19928,10 @@ async function stampAppFonts(urlStr, project) {
|
|
|
19847
19928
|
try {
|
|
19848
19929
|
const url = new URL(urlStr);
|
|
19849
19930
|
const bundleUrl = url.searchParams.get("bundle") || "";
|
|
19850
|
-
if (!bundleUrl) return urlStr;
|
|
19851
|
-
const repoDir = project?.appDir ?? await resolveMetroProjectRoot(bundleUrl) ?? void 0;
|
|
19931
|
+
if (!bundleUrl || !project) return urlStr;
|
|
19852
19932
|
const specs = discoverNativeLinkedAppFonts({
|
|
19853
19933
|
bundleUrl,
|
|
19854
|
-
|
|
19855
|
-
exactProjectDir: !!project || !!repoDir
|
|
19934
|
+
projectDir: project.appDir
|
|
19856
19935
|
});
|
|
19857
19936
|
if (specs.length === 0) return urlStr;
|
|
19858
19937
|
const reachable = await filterReachableAppFonts(specs);
|
|
@@ -19914,12 +19993,10 @@ async function stampAppSplash(urlStr, project) {
|
|
|
19914
19993
|
try {
|
|
19915
19994
|
const url = new URL(urlStr);
|
|
19916
19995
|
const bundleUrl = url.searchParams.get("bundle") || "";
|
|
19917
|
-
if (!bundleUrl) return urlStr;
|
|
19918
|
-
const repoDir = project?.appDir ?? await resolveMetroProjectRoot(bundleUrl) ?? void 0;
|
|
19996
|
+
if (!bundleUrl || !project) return urlStr;
|
|
19919
19997
|
const spec = discoverConfigPluginAppSplash({
|
|
19920
19998
|
bundleUrl,
|
|
19921
|
-
|
|
19922
|
-
exactProjectDir: !!project || !!repoDir
|
|
19999
|
+
projectDir: project.appDir
|
|
19923
20000
|
});
|
|
19924
20001
|
if (!spec) return urlStr;
|
|
19925
20002
|
if (spec.imageUrl) {
|
|
@@ -20179,7 +20256,7 @@ function playwrightHostPidForSim(sim) {
|
|
|
20179
20256
|
function signalDriverLaunchConnected(result) {
|
|
20180
20257
|
if (!result.connectAckFile) return false;
|
|
20181
20258
|
try {
|
|
20182
|
-
|
|
20259
|
+
import_node_fs13.default.writeFileSync(
|
|
20183
20260
|
result.connectAckFile,
|
|
20184
20261
|
`${JSON.stringify({ connectedAt: Date.now(), pid: result.pid ?? null })}
|
|
20185
20262
|
`,
|
|
@@ -20193,19 +20270,19 @@ function signalDriverLaunchConnected(result) {
|
|
|
20193
20270
|
function printDriverDiagnosticLogTail(result) {
|
|
20194
20271
|
if (!result.diagnosticLogPath) return;
|
|
20195
20272
|
try {
|
|
20196
|
-
const detail =
|
|
20273
|
+
const detail = import_node_fs13.default.readFileSync(result.diagnosticLogPath, "utf8").trim();
|
|
20197
20274
|
if (!detail) {
|
|
20198
|
-
console.error(` ${
|
|
20275
|
+
console.error(` ${import_node_path16.default.basename(result.diagnosticLogPath)} was empty`);
|
|
20199
20276
|
return;
|
|
20200
20277
|
}
|
|
20201
20278
|
const shown = detail.length > 4e3 ? `\u2026
|
|
20202
20279
|
${detail.slice(-4e3)}` : detail;
|
|
20203
|
-
console.error(` ${
|
|
20280
|
+
console.error(` ${import_node_path16.default.basename(result.diagnosticLogPath)}:`);
|
|
20204
20281
|
console.error(shown);
|
|
20205
20282
|
} catch (err) {
|
|
20206
20283
|
const message = err instanceof Error ? err.message : String(err);
|
|
20207
20284
|
console.error(
|
|
20208
|
-
` failed to read ${
|
|
20285
|
+
` failed to read ${import_node_path16.default.basename(result.diagnosticLogPath)}: ${message}`
|
|
20209
20286
|
);
|
|
20210
20287
|
}
|
|
20211
20288
|
}
|
|
@@ -20687,7 +20764,7 @@ async function runOpenCommand(args, opts = {}) {
|
|
|
20687
20764
|
);
|
|
20688
20765
|
printOpenedSim(shellUrl, { ...targetSim, url: shellUrl }, "current sim");
|
|
20689
20766
|
await maybeDescribeAfterOpen(parsed.wsPort, targetSim.id, args);
|
|
20690
|
-
return;
|
|
20767
|
+
return parsed.wsPort;
|
|
20691
20768
|
}
|
|
20692
20769
|
} finally {
|
|
20693
20770
|
bridge.close();
|
|
@@ -20760,6 +20837,7 @@ async function runOpenCommand(args, opts = {}) {
|
|
|
20760
20837
|
signalDriverLaunchConnected(result);
|
|
20761
20838
|
printOpenedSim(openUrl2, match, `${driver.name} driver`);
|
|
20762
20839
|
await maybeDescribeAfterOpen(parsed.wsPort, match.id, args);
|
|
20840
|
+
return parsed.wsPort;
|
|
20763
20841
|
}
|
|
20764
20842
|
async function runUseLikeCommand(args, opts = {}) {
|
|
20765
20843
|
const parsed = parseBridgeCliArgs(args, {
|
|
@@ -21022,14 +21100,14 @@ async function runCloseCommand(args, opts = {}) {
|
|
|
21022
21100
|
bridge.close();
|
|
21023
21101
|
}
|
|
21024
21102
|
}
|
|
21025
|
-
var import_node_child_process6,
|
|
21103
|
+
var import_node_child_process6, import_node_fs13, import_node_os3, import_node_path16, import_settings, import_ws5, DEFAULT_DRIVER_CONNECT_TIMEOUT_MS, DRIVER_CONNECT_INTERVAL_MS, DRIVER_CONNECT_HOST_GRACE_MS, OPEN_BRIDGE_SPAWN_TIMEOUT_MS, SHELL_APPS, DEEP_LINK_SCHEME_RE;
|
|
21026
21104
|
var init_control = __esm({
|
|
21027
21105
|
"cli/commands/control.ts"() {
|
|
21028
21106
|
"use strict";
|
|
21029
21107
|
import_node_child_process6 = require("node:child_process");
|
|
21030
|
-
|
|
21108
|
+
import_node_fs13 = __toESM(require("node:fs"), 1);
|
|
21031
21109
|
import_node_os3 = __toESM(require("node:os"), 1);
|
|
21032
|
-
|
|
21110
|
+
import_node_path16 = __toESM(require("node:path"), 1);
|
|
21033
21111
|
import_settings = require("sootsim-engine/settings");
|
|
21034
21112
|
import_ws5 = require("ws");
|
|
21035
21113
|
init_dev_server_scanner();
|
|
@@ -21811,14 +21889,14 @@ process.stdin.on('end', async () => {
|
|
|
21811
21889
|
function getBaseDir() {
|
|
21812
21890
|
const explicit = process.env[SESSION_FILE_ENV];
|
|
21813
21891
|
if (explicit?.trim()) {
|
|
21814
|
-
return (0,
|
|
21892
|
+
return (0, import_node_path17.dirname)((0, import_node_path17.resolve)(explicit));
|
|
21815
21893
|
}
|
|
21816
21894
|
return electronUserDataDir();
|
|
21817
21895
|
}
|
|
21818
21896
|
function getSharedDesktopAuthFilePath() {
|
|
21819
21897
|
const explicit = process.env[SESSION_FILE_ENV];
|
|
21820
|
-
if (explicit?.trim()) return (0,
|
|
21821
|
-
return (0,
|
|
21898
|
+
if (explicit?.trim()) return (0, import_node_path17.resolve)(explicit);
|
|
21899
|
+
return (0, import_node_path17.join)(getBaseDir(), "desktop-auth.json");
|
|
21822
21900
|
}
|
|
21823
21901
|
function normalizeUser(input) {
|
|
21824
21902
|
if (!input || typeof input !== "object") return null;
|
|
@@ -21865,26 +21943,26 @@ function normalizeSession(input) {
|
|
|
21865
21943
|
}
|
|
21866
21944
|
function readSharedDesktopAuthSession() {
|
|
21867
21945
|
const filepath = getSharedDesktopAuthFilePath();
|
|
21868
|
-
if (!(0,
|
|
21946
|
+
if (!(0, import_node_fs14.existsSync)(filepath)) return null;
|
|
21869
21947
|
try {
|
|
21870
|
-
const parsed = JSON.parse((0,
|
|
21948
|
+
const parsed = JSON.parse((0, import_node_fs14.readFileSync)(filepath, "utf8"));
|
|
21871
21949
|
const normalized = normalizeSession(parsed);
|
|
21872
21950
|
if (!normalized) {
|
|
21873
|
-
(0,
|
|
21951
|
+
(0, import_node_fs14.rmSync)(filepath, { force: true });
|
|
21874
21952
|
return null;
|
|
21875
21953
|
}
|
|
21876
21954
|
return normalized;
|
|
21877
21955
|
} catch {
|
|
21878
|
-
(0,
|
|
21956
|
+
(0, import_node_fs14.rmSync)(filepath, { force: true });
|
|
21879
21957
|
return null;
|
|
21880
21958
|
}
|
|
21881
21959
|
}
|
|
21882
|
-
var
|
|
21960
|
+
var import_node_fs14, import_node_path17, SESSION_VERSION, SESSION_FILE_ENV, DEFAULT_ORIGIN;
|
|
21883
21961
|
var init_shared_session = __esm({
|
|
21884
21962
|
"src/auth/shared-session.ts"() {
|
|
21885
21963
|
"use strict";
|
|
21886
|
-
|
|
21887
|
-
|
|
21964
|
+
import_node_fs14 = require("node:fs");
|
|
21965
|
+
import_node_path17 = require("node:path");
|
|
21888
21966
|
init_home_paths();
|
|
21889
21967
|
SESSION_VERSION = 1;
|
|
21890
21968
|
SESSION_FILE_ENV = "SOOTSIM_SHARED_AUTH_FILE";
|
|
@@ -21967,33 +22045,13 @@ var init_run_registry = __esm({
|
|
|
21967
22045
|
}
|
|
21968
22046
|
});
|
|
21969
22047
|
|
|
21970
|
-
// cli/telemetry.ts
|
|
21971
|
-
var init_telemetry = __esm({
|
|
21972
|
-
"cli/telemetry.ts"() {
|
|
21973
|
-
"use strict";
|
|
21974
|
-
init_agent_identity();
|
|
21975
|
-
init_shared_session();
|
|
21976
|
-
init_home_paths();
|
|
21977
|
-
}
|
|
21978
|
-
});
|
|
21979
|
-
|
|
21980
22048
|
// cli/commands/upload.ts
|
|
21981
22049
|
async function resolveDefaultUploadOrigin(explicitOrigin) {
|
|
21982
22050
|
if (explicitOrigin) return explicitOrigin;
|
|
21983
22051
|
if (process.env.SOOTSIM_UPLOAD_ORIGIN) return process.env.SOOTSIM_UPLOAD_ORIGIN;
|
|
21984
|
-
try {
|
|
21985
|
-
const res = await fetch(`${LOCAL_DEFAULT_ORIGIN}/api/preview/upload/init`, {
|
|
21986
|
-
method: "OPTIONS",
|
|
21987
|
-
signal: AbortSignal.timeout(LOCAL_UPLOAD_PROBE_TIMEOUT_MS)
|
|
21988
|
-
});
|
|
21989
|
-
if (res.ok || res.status === 204 || res.status === 405) {
|
|
21990
|
-
return LOCAL_DEFAULT_ORIGIN;
|
|
21991
|
-
}
|
|
21992
|
-
} catch {
|
|
21993
|
-
}
|
|
21994
22052
|
return REMOTE_DEFAULT_ORIGIN;
|
|
21995
22053
|
}
|
|
21996
|
-
var import_compress, import_compress_node, import_presigned_upload, import_trace, REMOTE_DEFAULT_ORIGIN, REMOTE_DEFAULT_PUBLIC_PREVIEW_ORIGIN
|
|
22054
|
+
var import_compress, import_compress_node, import_presigned_upload, import_trace, REMOTE_DEFAULT_ORIGIN, REMOTE_DEFAULT_PUBLIC_PREVIEW_ORIGIN;
|
|
21997
22055
|
var init_upload = __esm({
|
|
21998
22056
|
"cli/commands/upload.ts"() {
|
|
21999
22057
|
"use strict";
|
|
@@ -22001,19 +22059,15 @@ var init_upload = __esm({
|
|
|
22001
22059
|
import_compress_node = require("sootsim-engine/preview/compress-node");
|
|
22002
22060
|
import_presigned_upload = require("sootsim-engine/preview/presigned-upload");
|
|
22003
22061
|
import_trace = require("sootsim-engine/preview/trace");
|
|
22004
|
-
init_shared_session();
|
|
22005
22062
|
init_public_brand();
|
|
22006
22063
|
init_app_fonts();
|
|
22007
22064
|
init_app_splash();
|
|
22008
22065
|
init_auth();
|
|
22009
22066
|
init_open_url2();
|
|
22010
22067
|
init_run_registry();
|
|
22011
|
-
init_telemetry();
|
|
22012
22068
|
init_ws_bridge();
|
|
22013
22069
|
REMOTE_DEFAULT_ORIGIN = process.env.SOOTSIM_UPLOAD_ORIGIN || "https://contrast.dev";
|
|
22014
22070
|
REMOTE_DEFAULT_PUBLIC_PREVIEW_ORIGIN = process.env.SOOTSIM_PREVIEW_ORIGIN || rnxPublicBrand.origin;
|
|
22015
|
-
LOCAL_DEFAULT_ORIGIN = "https://contrast.localhost:3000";
|
|
22016
|
-
LOCAL_UPLOAD_PROBE_TIMEOUT_MS = 2e3;
|
|
22017
22071
|
}
|
|
22018
22072
|
});
|
|
22019
22073
|
|
|
@@ -22147,16 +22201,16 @@ function resolveFlowScreenshotPath(screenshotDir, name2) {
|
|
|
22147
22201
|
}
|
|
22148
22202
|
function resolveProjectRelativeFlowBase(flowDir) {
|
|
22149
22203
|
if (!flowDir) return process.cwd();
|
|
22150
|
-
return
|
|
22204
|
+
return path16.basename(flowDir) === ".maestro" ? path16.dirname(flowDir) : flowDir;
|
|
22151
22205
|
}
|
|
22152
22206
|
function resolveFlowScreenshotPathWithMode(screenshotDir, name2, opts) {
|
|
22153
22207
|
const normalizedName = name2.endsWith(".png") ? name2 : `${name2}.png`;
|
|
22154
|
-
if (
|
|
22208
|
+
if (path16.isAbsolute(normalizedName)) return normalizedName;
|
|
22155
22209
|
if (opts.mode === "flow" && /[\\/]/.test(normalizedName)) {
|
|
22156
22210
|
const baseDir = normalizedName.startsWith("./") || normalizedName.startsWith("../") ? opts.flowDir ?? process.cwd() : resolveProjectRelativeFlowBase(opts.flowDir);
|
|
22157
|
-
return
|
|
22211
|
+
return path16.resolve(baseDir, normalizedName);
|
|
22158
22212
|
}
|
|
22159
|
-
return
|
|
22213
|
+
return path16.join(screenshotDir, normalizedName);
|
|
22160
22214
|
}
|
|
22161
22215
|
function normalizeFlowScreenshotSpec(step) {
|
|
22162
22216
|
if (typeof step === "string") {
|
|
@@ -22213,12 +22267,12 @@ function parseFlowSteps(content) {
|
|
|
22213
22267
|
const parsed = import_yaml.default.parse(candidate);
|
|
22214
22268
|
return Array.isArray(parsed) ? parsed : [];
|
|
22215
22269
|
}
|
|
22216
|
-
var
|
|
22270
|
+
var fs16, path16, import_settings3, import_yaml, DEFAULT_TIMEOUT, FLOW_TIMEOUT_SCALE, scaledTimeout, SCREEN_W, SCREEN_H, SootSimBridgeFlowRunner;
|
|
22217
22271
|
var init_bridge_flow_runner = __esm({
|
|
22218
22272
|
"cli/bridge-flow-runner.ts"() {
|
|
22219
22273
|
"use strict";
|
|
22220
|
-
|
|
22221
|
-
|
|
22274
|
+
fs16 = __toESM(require("fs"), 1);
|
|
22275
|
+
path16 = __toESM(require("path"), 1);
|
|
22222
22276
|
import_settings3 = require("sootsim-engine/settings");
|
|
22223
22277
|
import_yaml = __toESM(require("yaml"), 1);
|
|
22224
22278
|
init_frame_compose();
|
|
@@ -22515,14 +22569,14 @@ var init_bridge_flow_runner = __esm({
|
|
|
22515
22569
|
if (chunks.length === 0) {
|
|
22516
22570
|
throw new Error("recording requested but no video buffer was produced");
|
|
22517
22571
|
}
|
|
22518
|
-
|
|
22572
|
+
fs16.mkdirSync(this.opts.recordingOutputDir, { recursive: true });
|
|
22519
22573
|
const videoMime = stopped.mime || this.opts.recordingFormat || "video/webm";
|
|
22520
22574
|
const extension = videoMime.includes("mp4") ? "mp4" : "webm";
|
|
22521
|
-
const outputPath =
|
|
22575
|
+
const outputPath = path16.join(
|
|
22522
22576
|
this.opts.recordingOutputDir,
|
|
22523
22577
|
`sootsim-${Date.now()}.${extension}`
|
|
22524
22578
|
);
|
|
22525
|
-
|
|
22579
|
+
fs16.writeFileSync(outputPath, Buffer.concat(chunks));
|
|
22526
22580
|
return outputPath;
|
|
22527
22581
|
}
|
|
22528
22582
|
async waitForRecordingTail(opts) {
|
|
@@ -23025,7 +23079,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
23025
23079
|
flowDir: this.opts.flowDir
|
|
23026
23080
|
}
|
|
23027
23081
|
);
|
|
23028
|
-
|
|
23082
|
+
fs16.mkdirSync(path16.dirname(outputPath), { recursive: true });
|
|
23029
23083
|
const layers = spec.layers ?? this.opts.screenshotLayers;
|
|
23030
23084
|
const screenshotRequest = {
|
|
23031
23085
|
type: "screenshot",
|
|
@@ -23041,11 +23095,11 @@ var init_bridge_flow_runner = __esm({
|
|
|
23041
23095
|
throw new Error("could not read current device model for framed screenshot");
|
|
23042
23096
|
}
|
|
23043
23097
|
const framed = await composeFramedScreenshot(rawBuffer, model);
|
|
23044
|
-
|
|
23098
|
+
fs16.writeFileSync(outputPath, framed);
|
|
23045
23099
|
console.log(`[flow] screenshot: ${outputPath} (frame: ${model})`);
|
|
23046
23100
|
return outputPath;
|
|
23047
23101
|
}
|
|
23048
|
-
|
|
23102
|
+
fs16.writeFileSync(outputPath, rawBuffer);
|
|
23049
23103
|
console.log(`[flow] screenshot: ${outputPath}`);
|
|
23050
23104
|
return outputPath;
|
|
23051
23105
|
}
|
|
@@ -23061,22 +23115,22 @@ var init_bridge_flow_runner = __esm({
|
|
|
23061
23115
|
return model;
|
|
23062
23116
|
}
|
|
23063
23117
|
async captureScreenshot(outputPath) {
|
|
23064
|
-
|
|
23118
|
+
fs16.mkdirSync(path16.dirname(outputPath), { recursive: true });
|
|
23065
23119
|
const dataUrl = await this.bridge.send({
|
|
23066
23120
|
type: "screenshot",
|
|
23067
23121
|
simId: this.opts.simId
|
|
23068
23122
|
});
|
|
23069
23123
|
const base64 = dataUrl.replace(/^data:image\/png;base64,/, "");
|
|
23070
|
-
|
|
23124
|
+
fs16.writeFileSync(outputPath, Buffer.from(base64, "base64"));
|
|
23071
23125
|
}
|
|
23072
23126
|
// writes a per-failure debug bundle: screenshot + structured describe
|
|
23073
23127
|
// + a11y tree + console errors/warnings + failed network requests +
|
|
23074
23128
|
// shell state, all under one directory so post-mortem is one grep away.
|
|
23075
23129
|
async captureFailureBundle(outputDir, context) {
|
|
23076
|
-
|
|
23130
|
+
fs16.mkdirSync(outputDir, { recursive: true });
|
|
23077
23131
|
const write = (name2, content) => {
|
|
23078
23132
|
try {
|
|
23079
|
-
|
|
23133
|
+
fs16.writeFileSync(path16.join(outputDir, name2), content);
|
|
23080
23134
|
} catch {
|
|
23081
23135
|
}
|
|
23082
23136
|
};
|
|
@@ -23595,8 +23649,8 @@ var init_bridge_flow_runner = __esm({
|
|
|
23595
23649
|
runScript(target) {
|
|
23596
23650
|
const spec = typeof target === "string" ? { file: target } : target;
|
|
23597
23651
|
if (!spec.file) throw new Error("runScript requires a file");
|
|
23598
|
-
const scriptPath =
|
|
23599
|
-
const source =
|
|
23652
|
+
const scriptPath = path16.resolve(this.opts.flowDir, spec.file);
|
|
23653
|
+
const source = fs16.readFileSync(scriptPath, "utf8");
|
|
23600
23654
|
this.js.evaluate(source, { env: spec.env });
|
|
23601
23655
|
console.log(`[flow] runScript: ${spec.file} done`);
|
|
23602
23656
|
}
|
|
@@ -23890,10 +23944,10 @@ var init_bridge_flow_runner = __esm({
|
|
|
23890
23944
|
for (const [k, v] of Object.entries(env)) this.js.putEnv(k, v);
|
|
23891
23945
|
}
|
|
23892
23946
|
if (file) {
|
|
23893
|
-
const flowPath =
|
|
23894
|
-
const flowContent =
|
|
23947
|
+
const flowPath = path16.resolve(this.opts.flowDir, file);
|
|
23948
|
+
const flowContent = fs16.readFileSync(flowPath, "utf8");
|
|
23895
23949
|
const previousDir = this.opts.flowDir;
|
|
23896
|
-
this.opts.flowDir =
|
|
23950
|
+
this.opts.flowDir = path16.dirname(flowPath);
|
|
23897
23951
|
try {
|
|
23898
23952
|
await this.runFlow(parseFlowSteps(flowContent));
|
|
23899
23953
|
} finally {
|
|
@@ -24048,8 +24102,8 @@ __export(registry_exports, {
|
|
|
24048
24102
|
skillRegistry: () => skillRegistry
|
|
24049
24103
|
});
|
|
24050
24104
|
module.exports = __toCommonJS(registry_exports);
|
|
24051
|
-
var
|
|
24052
|
-
var
|
|
24105
|
+
var fs17 = __toESM(require("fs"), 1);
|
|
24106
|
+
var path17 = __toESM(require("path"), 1);
|
|
24053
24107
|
|
|
24054
24108
|
// src/skills/builtin/a11y-review.ts
|
|
24055
24109
|
init_reap_browser();
|
|
@@ -24068,8 +24122,8 @@ var skill = {
|
|
|
24068
24122
|
},
|
|
24069
24123
|
async execute(params, context) {
|
|
24070
24124
|
const { chromium } = await import("playwright");
|
|
24071
|
-
const
|
|
24072
|
-
const
|
|
24125
|
+
const path18 = await import("path");
|
|
24126
|
+
const fs18 = await import("fs");
|
|
24073
24127
|
const browser = await launchReapedChrome((options) => chromium.launch(options), {
|
|
24074
24128
|
headless: true
|
|
24075
24129
|
});
|
|
@@ -24124,9 +24178,9 @@ var skill = {
|
|
|
24124
24178
|
warnings: issues.filter((i) => i.severity === "warning").length,
|
|
24125
24179
|
tree: typeof tree === "string" ? tree : JSON.stringify(tree)
|
|
24126
24180
|
};
|
|
24127
|
-
const reportPath =
|
|
24128
|
-
|
|
24129
|
-
|
|
24181
|
+
const reportPath = path18.join(context.outputDir, "a11y-report.json");
|
|
24182
|
+
fs18.mkdirSync(path18.dirname(reportPath), { recursive: true });
|
|
24183
|
+
fs18.writeFileSync(reportPath, JSON.stringify(report, null, 2));
|
|
24130
24184
|
return {
|
|
24131
24185
|
success: issues.filter((i) => i.severity === "error").length === 0,
|
|
24132
24186
|
message: `${report.errors} errors, ${report.warnings} warnings across ${report.nodeCount} nodes`,
|
|
@@ -24159,14 +24213,14 @@ var skill2 = {
|
|
|
24159
24213
|
}
|
|
24160
24214
|
},
|
|
24161
24215
|
async execute(params, context) {
|
|
24162
|
-
const
|
|
24163
|
-
const
|
|
24216
|
+
const fs18 = await import("node:fs");
|
|
24217
|
+
const path18 = await import("node:path");
|
|
24164
24218
|
const { COMPAT_RESULT_CAVEAT: COMPAT_RESULT_CAVEAT2, formatPackageStatus: formatPackageStatus2, formatScanCounts: formatScanCounts2, scanDeps: scanDeps2 } = await Promise.resolve().then(() => (init_web(), web_exports));
|
|
24165
|
-
const packagePath =
|
|
24166
|
-
if (!
|
|
24219
|
+
const packagePath = path18.join(context.projectDir, "package.json");
|
|
24220
|
+
if (!fs18.existsSync(packagePath)) {
|
|
24167
24221
|
return { success: false, message: "No package.json found" };
|
|
24168
24222
|
}
|
|
24169
|
-
const parsed = JSON.parse(
|
|
24223
|
+
const parsed = JSON.parse(fs18.readFileSync(packagePath, "utf8"));
|
|
24170
24224
|
if (!parsed || typeof parsed !== "object") {
|
|
24171
24225
|
return { success: false, message: "package.json is not an object" };
|
|
24172
24226
|
}
|
|
@@ -24178,9 +24232,9 @@ var skill2 = {
|
|
|
24178
24232
|
}) : scanDeps2(parsed);
|
|
24179
24233
|
const packageResult = params.packageName ? scan.packages[0] : void 0;
|
|
24180
24234
|
const message = packageResult ? `${params.packageName}: ${formatPackageStatus2(packageResult)}. ${COMPAT_RESULT_CAVEAT2}` : `${formatScanCounts2(scan)}. ${COMPAT_RESULT_CAVEAT2}`;
|
|
24181
|
-
const reportPath =
|
|
24182
|
-
|
|
24183
|
-
|
|
24235
|
+
const reportPath = path18.join(context.outputDir, "compat-report.json");
|
|
24236
|
+
fs18.mkdirSync(path18.dirname(reportPath), { recursive: true });
|
|
24237
|
+
fs18.writeFileSync(reportPath, `${JSON.stringify(scan, null, 2)}
|
|
24184
24238
|
`);
|
|
24185
24239
|
return {
|
|
24186
24240
|
success: true,
|
|
@@ -24224,8 +24278,8 @@ var skill3 = {
|
|
|
24224
24278
|
record: { type: "boolean", description: "Record video of the flow" }
|
|
24225
24279
|
},
|
|
24226
24280
|
async execute(params, context) {
|
|
24227
|
-
const
|
|
24228
|
-
const
|
|
24281
|
+
const fs18 = await import("fs");
|
|
24282
|
+
const path18 = await import("path");
|
|
24229
24283
|
const yaml2 = await import("yaml");
|
|
24230
24284
|
const { DEFAULT_SOOTSIM_BRIDGE_PORT: DEFAULT_SOOTSIM_BRIDGE_PORT2 } = await Promise.resolve().then(() => (init_bridge_constants(), bridge_constants_exports));
|
|
24231
24285
|
const { SootSimBridgeHost: SootSimBridgeHost2 } = await Promise.resolve().then(() => (init_bridge_host(), bridge_host_exports));
|
|
@@ -24235,7 +24289,7 @@ var skill3 = {
|
|
|
24235
24289
|
const host = new SootSimBridgeHost2({ port: DEFAULT_SOOTSIM_BRIDGE_PORT2 });
|
|
24236
24290
|
host.start({ silent: true });
|
|
24237
24291
|
try {
|
|
24238
|
-
const flowContent =
|
|
24292
|
+
const flowContent = fs18.readFileSync(params.flowPath, "utf8");
|
|
24239
24293
|
const fmMatch = flowContent.match(/^---\n([\s\S]*?)\n---\n?/);
|
|
24240
24294
|
const stepsBody = fmMatch ? flowContent.slice(fmMatch[0].length) : flowContent;
|
|
24241
24295
|
const steps = yaml2.parse(stepsBody);
|
|
@@ -24262,7 +24316,7 @@ var skill3 = {
|
|
|
24262
24316
|
});
|
|
24263
24317
|
const driver = new SootSimBridgeFlowRunner2(bridge, {
|
|
24264
24318
|
screenshotDir: context.outputDir,
|
|
24265
|
-
flowDir:
|
|
24319
|
+
flowDir: path18.dirname(path18.resolve(params.flowPath)),
|
|
24266
24320
|
simId,
|
|
24267
24321
|
recordingOutputDir: params.record ? context.outputDir : void 0
|
|
24268
24322
|
});
|
|
@@ -24284,7 +24338,7 @@ var skill3 = {
|
|
|
24284
24338
|
simId,
|
|
24285
24339
|
videoPath: videoPath || void 0
|
|
24286
24340
|
},
|
|
24287
|
-
artifacts: videoPath ? [{ type: "video", name:
|
|
24341
|
+
artifacts: videoPath ? [{ type: "video", name: path18.basename(videoPath), path: videoPath }] : void 0
|
|
24288
24342
|
};
|
|
24289
24343
|
} finally {
|
|
24290
24344
|
try {
|
|
@@ -24331,8 +24385,8 @@ var skill4 = {
|
|
|
24331
24385
|
},
|
|
24332
24386
|
async execute(params, context) {
|
|
24333
24387
|
const { chromium } = await import("playwright");
|
|
24334
|
-
const
|
|
24335
|
-
const
|
|
24388
|
+
const path18 = await import("path");
|
|
24389
|
+
const fs18 = await import("fs");
|
|
24336
24390
|
const browser = await launchReapedChrome((options) => chromium.launch(options), {
|
|
24337
24391
|
headless: true
|
|
24338
24392
|
});
|
|
@@ -24358,9 +24412,9 @@ var skill4 = {
|
|
|
24358
24412
|
...profile,
|
|
24359
24413
|
fps: syncCount > 0 ? (syncCount / (duration / 1e3)).toFixed(1) : "0"
|
|
24360
24414
|
};
|
|
24361
|
-
const reportPath =
|
|
24362
|
-
|
|
24363
|
-
|
|
24415
|
+
const reportPath = path18.join(context.outputDir, "perf-report.json");
|
|
24416
|
+
fs18.mkdirSync(path18.dirname(reportPath), { recursive: true });
|
|
24417
|
+
fs18.writeFileSync(reportPath, JSON.stringify(report, null, 2));
|
|
24364
24418
|
return {
|
|
24365
24419
|
success: true,
|
|
24366
24420
|
message: `${report.fps} fps, ${profile.avgSyncMs?.toFixed(1)}ms avg sync, ${nodeCount} nodes`,
|
|
@@ -24393,8 +24447,8 @@ var skill5 = {
|
|
|
24393
24447
|
},
|
|
24394
24448
|
async execute(params, context) {
|
|
24395
24449
|
const { chromium } = await import("playwright");
|
|
24396
|
-
const
|
|
24397
|
-
const
|
|
24450
|
+
const path18 = await import("path");
|
|
24451
|
+
const fs18 = await import("fs");
|
|
24398
24452
|
const browser = await launchReapedChrome((options) => chromium.launch(options), {
|
|
24399
24453
|
headless: true
|
|
24400
24454
|
});
|
|
@@ -24402,8 +24456,8 @@ var skill5 = {
|
|
|
24402
24456
|
try {
|
|
24403
24457
|
await page.goto(context.url, { waitUntil: "networkidle" });
|
|
24404
24458
|
await page.waitForTimeout(2e3);
|
|
24405
|
-
const outputPath =
|
|
24406
|
-
|
|
24459
|
+
const outputPath = path18.join(context.outputDir, `${params.name}.png`);
|
|
24460
|
+
fs18.mkdirSync(path18.dirname(outputPath), { recursive: true });
|
|
24407
24461
|
await page.screenshot({ path: outputPath });
|
|
24408
24462
|
return {
|
|
24409
24463
|
success: true,
|
|
@@ -24444,8 +24498,8 @@ var skill6 = {
|
|
|
24444
24498
|
},
|
|
24445
24499
|
async execute(params, context) {
|
|
24446
24500
|
const { chromium } = await import("playwright");
|
|
24447
|
-
const
|
|
24448
|
-
const
|
|
24501
|
+
const path18 = await import("path");
|
|
24502
|
+
const fs18 = await import("fs");
|
|
24449
24503
|
const browser = await launchReapedChrome((options) => chromium.launch(options), {
|
|
24450
24504
|
headless: true
|
|
24451
24505
|
});
|
|
@@ -24453,14 +24507,14 @@ var skill6 = {
|
|
|
24453
24507
|
try {
|
|
24454
24508
|
await page.goto(context.url, { waitUntil: "networkidle" });
|
|
24455
24509
|
await page.waitForTimeout(2e3);
|
|
24456
|
-
const currentPath =
|
|
24457
|
-
|
|
24510
|
+
const currentPath = path18.join(context.outputDir, `${params.name}-current.png`);
|
|
24511
|
+
fs18.mkdirSync(path18.dirname(currentPath), { recursive: true });
|
|
24458
24512
|
await page.screenshot({ path: currentPath });
|
|
24459
24513
|
try {
|
|
24460
24514
|
const { PNG } = await import("pngjs");
|
|
24461
24515
|
const pixelmatch = (await import("pixelmatch")).default;
|
|
24462
|
-
const baseline = PNG.sync.read(
|
|
24463
|
-
const current = PNG.sync.read(
|
|
24516
|
+
const baseline = PNG.sync.read(fs18.readFileSync(params.baseline));
|
|
24517
|
+
const current = PNG.sync.read(fs18.readFileSync(currentPath));
|
|
24464
24518
|
const { width, height } = baseline;
|
|
24465
24519
|
const diff = new PNG({ width, height });
|
|
24466
24520
|
const numDiffPixels = pixelmatch(
|
|
@@ -24471,8 +24525,8 @@ var skill6 = {
|
|
|
24471
24525
|
height,
|
|
24472
24526
|
{ threshold: params.threshold || 0.1 }
|
|
24473
24527
|
);
|
|
24474
|
-
const diffPath =
|
|
24475
|
-
|
|
24528
|
+
const diffPath = path18.join(context.outputDir, `${params.name}-diff.png`);
|
|
24529
|
+
fs18.writeFileSync(diffPath, PNG.sync.write(diff));
|
|
24476
24530
|
const totalPixels = width * height;
|
|
24477
24531
|
const diffPercent = (numDiffPixels / totalPixels * 100).toFixed(2);
|
|
24478
24532
|
return {
|
|
@@ -24536,10 +24590,10 @@ var skillRegistry = {
|
|
|
24536
24590
|
},
|
|
24537
24591
|
// load skills from a project manifest (sootsim-skills.json)
|
|
24538
24592
|
async loadFromManifest(projectDir) {
|
|
24539
|
-
const manifestPath =
|
|
24540
|
-
if (!
|
|
24593
|
+
const manifestPath = path17.join(projectDir, "sootsim-skills.json");
|
|
24594
|
+
if (!fs17.existsSync(manifestPath)) return;
|
|
24541
24595
|
try {
|
|
24542
|
-
const manifest = JSON.parse(
|
|
24596
|
+
const manifest = JSON.parse(fs17.readFileSync(manifestPath, "utf8"));
|
|
24543
24597
|
if (Array.isArray(manifest.skills)) {
|
|
24544
24598
|
for (const entry of manifest.skills) {
|
|
24545
24599
|
if (typeof entry === "string") {
|
|
@@ -24550,7 +24604,7 @@ var skillRegistry = {
|
|
|
24550
24604
|
}
|
|
24551
24605
|
} else if (entry.file) {
|
|
24552
24606
|
try {
|
|
24553
|
-
const mod = await import(
|
|
24607
|
+
const mod = await import(path17.resolve(projectDir, entry.file));
|
|
24554
24608
|
if (mod.skill) this.register(mod.skill);
|
|
24555
24609
|
} catch {
|
|
24556
24610
|
}
|
|
@@ -24563,10 +24617,10 @@ var skillRegistry = {
|
|
|
24563
24617
|
// auto-discover skills based on project dependencies
|
|
24564
24618
|
suggestSkills(projectDir) {
|
|
24565
24619
|
const suggestions = [];
|
|
24566
|
-
const pkgPath =
|
|
24567
|
-
if (!
|
|
24620
|
+
const pkgPath = path17.join(projectDir, "package.json");
|
|
24621
|
+
if (!fs17.existsSync(pkgPath)) return suggestions;
|
|
24568
24622
|
try {
|
|
24569
|
-
const pkg = JSON.parse(
|
|
24623
|
+
const pkg = JSON.parse(fs17.readFileSync(pkgPath, "utf8"));
|
|
24570
24624
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
24571
24625
|
if (deps["detox"] || deps["maestro"]) {
|
|
24572
24626
|
suggestions.push("maestro-test");
|