peachsim 0.1.577 → 0.1.579
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/LICENSE +1 -1
- package/README.md +11 -9
- package/cli/app-catalog.ts +77 -0
- package/cli/app-fonts.ts +4 -20
- package/cli/app-splash.ts +2 -18
- package/cli/bridge-flow-runner.ts +505 -139
- package/cli/cloud-client.ts +1 -4
- package/cli/cloud-session.ts +1 -4
- package/cli/cloud-test-result-files.ts +3 -0
- package/cli/cloud-test-tunnel.ts +2 -5
- package/cli/command-registry.ts +2 -0
- package/cli/commands/agent.ts +149 -23
- package/cli/commands/assert.ts +1 -4
- package/cli/commands/box/peach-command.ts +62 -0
- package/cli/commands/box/plane-share.ts +0 -70
- package/cli/commands/box/rnx-command.ts +1 -60
- package/cli/commands/box/search-command.ts +14 -0
- package/cli/commands/box.ts +2 -2
- package/cli/commands/control.ts +121 -27
- package/cli/commands/cpu-profile.ts +23 -10
- package/cli/commands/daemon.ts +1 -9
- package/cli/commands/detox.ts +26 -18
- package/cli/commands/device.ts +129 -1
- package/cli/commands/film.ts +25 -16
- package/cli/commands/flow.ts +9 -2
- package/cli/commands/inspect/actions.ts +75 -1
- package/cli/commands/inspect/core.ts +81 -2
- package/cli/commands/inspect/describe.ts +2 -6
- package/cli/commands/inspect/env.ts +1 -1
- package/cli/commands/inspect/settling.ts +20 -3
- package/cli/commands/inspect/shared.ts +1 -4
- package/cli/commands/inspect/sleep.ts +1 -1
- package/cli/commands/inspect.ts +16 -49
- package/cli/commands/install-desktop.ts +8 -6
- package/cli/commands/login.ts +3 -5
- package/cli/commands/maestro-generate.ts +1 -4
- package/cli/commands/maestro.ts +38 -21
- package/cli/commands/no-bridge-hint.ts +0 -14
- package/cli/commands/permissions.ts +2 -2
- package/cli/commands/platform.ts +13 -6
- package/cli/commands/screenshot.ts +6 -1
- package/cli/commands/skills.ts +1 -1
- package/cli/commands/test.ts +6 -2
- package/cli/commands/three-mode.ts +162 -19
- package/cli/commands/upload.ts +3 -18
- package/cli/current-sim.ts +0 -1
- package/cli/desktop-companion.ts +40 -8
- package/cli/drivers/playwright-provisioning.ts +1 -4
- package/cli/flow-export.ts +1 -8
- package/cli/flow-session.ts +0 -4
- package/cli/hints.ts +1 -16
- package/cli/inspect-notice-state.ts +0 -4
- package/cli/main.ts +2 -4
- package/cli/outbound-endpoints.ts +1 -24
- package/cli/parse-args.ts +1 -2
- package/cli/rnx-in-process.ts +3 -1
- package/cli/run-rnx-core.ts +4 -2
- package/cli/run-rnx.ts +18 -10
- package/cli/send-to-box.ts +1 -4
- package/cli/telemetry.ts +1 -1
- package/cli/ws-bridge.ts +1 -5
- package/detox/gestures.ts +20 -6
- package/detox/index.ts +379 -123
- package/detox/navigation-lifecycle.ts +22 -13
- package/dist-lib/agent-daemon-client.cjs +21 -15
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +3 -17
- package/dist-lib/agent-sessions.cjs +5 -4
- package/dist-lib/attached-projects.cjs +1 -77
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +11 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +7 -5
- package/dist-lib/bridge-contract-input.mjs +7 -5
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/capture-contract.cjs +30 -7
- package/dist-lib/capture-contract.mjs +30 -7
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +17 -11
- package/dist-lib/cloud.mjs +17 -11
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +321 -122
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +427 -212
- package/dist-lib/host/fetch-proxy-handler.cjs +5 -28
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +315 -58
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/menu.cjs +67 -31
- package/dist-lib/menu.mjs +64 -28
- package/dist-lib/metro-fingerprint-registry.cjs +8 -4
- package/dist-lib/metro-fingerprint-registry.mjs +6 -4
- package/dist-lib/metro-production-bundle.cjs +2 -2
- package/dist-lib/metro-production-bundle.mjs +2 -2
- package/dist-lib/metro.cjs +8 -4
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +7 -4
- 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 +3 -13
- package/dist-lib/scripts/dev-server-scanner.cjs +5 -17
- package/dist-lib/sdk.cjs +129 -10
- package/dist-lib/sdk.mjs +127 -10
- package/dist-lib/skills.cjs +1635 -1121
- package/dist-lib/swift-compile.cjs +277 -70
- package/dist-lib/swift-compile.mjs +275 -70
- package/dist-lib/swift-package.cjs +17 -5
- package/dist-lib/swift-package.mjs +15 -4
- package/dist-lib/swift-submit.cjs +32 -8
- package/dist-lib/swift-submit.mjs +29 -7
- package/dist-lib/swift.cjs +30912 -577
- package/dist-lib/vite-kotlin.cjs +356 -0
- package/dist-lib/vite-swift.cjs +1743 -0
- package/dist-lib/vite.cjs +208 -1039
- package/kotlin/README.md +18 -0
- package/kotlin/Sources/androidx/annotation/Keep.kt +4 -0
- package/kotlin/Sources/dev/onejs/one/OneNativeSourceDispatch.kt +7 -0
- package/kotlin/Sources/dev/onejs/one/source/OneModule.kt +4 -0
- package/kotlin/Sources/org/json/JSON.kt +244 -0
- package/kotlin/toolchain.json +19 -0
- package/package.json +14 -2
- package/scripts/dev-server-scanner.ts +0 -18
- package/scripts/optional-demo-registry.ts +0 -17
- package/skills/contrast/SKILL.md +2 -2
- package/skills/peach-setup/SKILL.md +16 -0
- package/src/agent-daemon-client.ts +36 -22
- package/src/agent-identity.ts +0 -15
- package/src/agent-prompt.ts +12 -0
- package/src/attached-projects.ts +0 -72
- package/src/backend-origin.ts +10 -0
- package/src/bridge-contract-input.ts +2 -5
- package/src/bridge-contract.ts +2 -0
- package/src/capture-contract.ts +53 -11
- package/src/cloud.ts +4 -9
- package/src/dev-server-open.ts +0 -99
- package/src/home-paths.ts +2 -3
- package/src/host/agent-host.ts +82 -36
- package/src/host/bridge-host.ts +5 -11
- package/src/host/fetch-proxy-handler.ts +19 -43
- package/src/is-record.ts +4 -0
- package/src/menu.ts +82 -37
- package/src/metro-fingerprint-registry.ts +1 -4
- package/src/metro-production-bundle.ts +1 -1
- package/src/plist.ts +1 -4
- package/src/public-brand.ts +5 -3
- package/src/render-mode.ts +0 -12
- package/src/runtime-assets.ts +9 -2
- package/src/screenshots/compose.ts +7 -1
- package/src/screenshots/frame-compose.ts +21 -10
- package/src/screenshots/schema.ts +1 -4
- package/src/sim-client.ts +2 -4
- package/src/skills/builtin/maestro-test.ts +1 -4
- package/src/sleep.ts +4 -0
- package/src/swift-compile.ts +209 -47
- package/src/swift-icu.ts +140 -0
- package/src/swift-package.ts +26 -2
- package/src/swift-submit.ts +84 -4
- package/src/swift.ts +2 -0
- package/src/vite-plugin-kotlin.ts +376 -0
- package/src/vite-plugin-one.ts +224 -36
- package/src/vite-plugin-swift.ts +382 -96
- package/src/vite-plugin.ts +121 -134
- package/src/vite.d.ts +10 -0
- package/cli/resolve-assets.ts +0 -63
- package/src/rolldown-plugin-swift.ts +0 -244
- package/src/team-machine-prompt.ts +0 -73
package/dist-lib/vite.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.579 | (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;
|
|
@@ -34,14 +34,15 @@ var vite_plugin_one_exports = {};
|
|
|
34
34
|
__export(vite_plugin_one_exports, {
|
|
35
35
|
default: () => vite_plugin_one_default,
|
|
36
36
|
rnxPlugin: () => rnxPlugin,
|
|
37
|
-
sootsimPlugin: () => sootsimPlugin
|
|
38
|
-
swiftPlugin: () => swiftPlugin,
|
|
39
|
-
swiftRemotePlugin: () => swiftRemotePlugin
|
|
37
|
+
sootsimPlugin: () => sootsimPlugin
|
|
40
38
|
});
|
|
41
39
|
module.exports = __toCommonJS(vite_plugin_one_exports);
|
|
42
40
|
var import_fs2 = __toESM(require("fs"), 1);
|
|
43
|
-
var
|
|
41
|
+
var import_node_crypto2 = require("node:crypto");
|
|
42
|
+
var import_node_module = require("node:module");
|
|
44
43
|
var import_path2 = __toESM(require("path"), 1);
|
|
44
|
+
var import_vxrn = require("vxrn");
|
|
45
|
+
var import_ws = require("ws");
|
|
45
46
|
|
|
46
47
|
// src/bridge-constants.ts
|
|
47
48
|
var DEFAULT_SOOTSIM_BRIDGE_PORT = 7668;
|
|
@@ -673,7 +674,10 @@ var ROOT_RUNTIME_PATHS = [
|
|
|
673
674
|
"/spike/",
|
|
674
675
|
"/test-wallpaper.jpg",
|
|
675
676
|
"/preview-sw.js",
|
|
676
|
-
"/sootsim.svg"
|
|
677
|
+
"/sootsim.svg",
|
|
678
|
+
"/bedrock-sqlite.wasm",
|
|
679
|
+
"/bedrock-sqlite.js",
|
|
680
|
+
"/sootsim/"
|
|
677
681
|
];
|
|
678
682
|
function resolveActiveRuntimeRoot() {
|
|
679
683
|
const devRoot = resolveDevCheckoutRuntimeRoot();
|
|
@@ -713,10 +717,10 @@ function resolveRuntimeRootForHostname(hostname) {
|
|
|
713
717
|
const version = runtimeVersionFromHostname(hostname);
|
|
714
718
|
return version ? resolveInstalledRuntimeRoot(version) : null;
|
|
715
719
|
}
|
|
716
|
-
function resolveRuntimeRootForRequestHost(
|
|
717
|
-
if (!
|
|
720
|
+
function resolveRuntimeRootForRequestHost(host) {
|
|
721
|
+
if (!host) return resolveActiveRuntimeRoot();
|
|
718
722
|
try {
|
|
719
|
-
return resolveRuntimeRootForHostname(new URL(`http://${
|
|
723
|
+
return resolveRuntimeRootForHostname(new URL(`http://${host}`).hostname);
|
|
720
724
|
} catch {
|
|
721
725
|
return null;
|
|
722
726
|
}
|
|
@@ -730,7 +734,8 @@ function resolveRuntimeFilePath(runtimeRoot, pathname) {
|
|
|
730
734
|
for (const segment of pathname.split("/")) {
|
|
731
735
|
if (segment === "..") return null;
|
|
732
736
|
}
|
|
733
|
-
const
|
|
737
|
+
const normalized = pathname.startsWith("/sootsim/") ? pathname.slice("/sootsim".length) : pathname;
|
|
738
|
+
const fullPath = import_path.default.resolve(runtimeRoot, normalized.replace(/^\/+/, ""));
|
|
734
739
|
const rootWithSep = runtimeRoot.endsWith(import_path.default.sep) ? runtimeRoot : runtimeRoot + import_path.default.sep;
|
|
735
740
|
if (!fullPath.startsWith(rootWithSep) && fullPath !== runtimeRoot) return null;
|
|
736
741
|
if (!import_fs.default.existsSync(fullPath) || !import_fs.default.statSync(fullPath).isFile()) return null;
|
|
@@ -756,1023 +761,14 @@ function serveRuntimeFile(req, res, fullPath) {
|
|
|
756
761
|
import_fs.default.createReadStream(fullPath).pipe(res);
|
|
757
762
|
}
|
|
758
763
|
|
|
759
|
-
// src/vite-plugin-swift.ts
|
|
760
|
-
var import_node_crypto3 = require("node:crypto");
|
|
761
|
-
var import_node_fs4 = __toESM(require("node:fs"), 1);
|
|
762
|
-
var import_node_os2 = __toESM(require("node:os"), 1);
|
|
763
|
-
var import_node_path5 = __toESM(require("node:path"), 1);
|
|
764
|
-
|
|
765
|
-
// ../sootsim-swift/src/bundleAssets.ts
|
|
766
|
-
var RASTER_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
767
|
-
".avif",
|
|
768
|
-
".bmp",
|
|
769
|
-
".gif",
|
|
770
|
-
".ico",
|
|
771
|
-
".jpeg",
|
|
772
|
-
".jpg",
|
|
773
|
-
".png",
|
|
774
|
-
".webp"
|
|
775
|
-
]);
|
|
776
|
-
function extOf(file) {
|
|
777
|
-
const dot = file.lastIndexOf(".");
|
|
778
|
-
return dot < 0 ? "" : file.slice(dot).toLowerCase();
|
|
779
|
-
}
|
|
780
|
-
function baseOf(file) {
|
|
781
|
-
const slash = file.lastIndexOf("/");
|
|
782
|
-
return slash < 0 ? file : file.slice(slash + 1);
|
|
783
|
-
}
|
|
784
|
-
function pickImagesetFile(images) {
|
|
785
|
-
const rasters = images.filter(
|
|
786
|
-
(image) => typeof image.filename === "string" && RASTER_EXTENSIONS.has(extOf(image.filename))
|
|
787
|
-
);
|
|
788
|
-
if (rasters.length === 0) return null;
|
|
789
|
-
const rank = (scale) => scale === "2x" ? 0 : scale === "3x" ? 1 : scale === "1x" ? 2 : 3;
|
|
790
|
-
return [...rasters].sort((a, b) => rank(a.scale) - rank(b.scale))[0].filename;
|
|
791
|
-
}
|
|
792
|
-
function imagesetName(contentsPath) {
|
|
793
|
-
const dir = contentsPath.split("/").slice(0, -1).join("/");
|
|
794
|
-
const leaf = baseOf(dir);
|
|
795
|
-
if (!leaf.endsWith(".imageset")) return null;
|
|
796
|
-
return leaf.slice(0, -".imageset".length) || null;
|
|
797
|
-
}
|
|
798
|
-
function isFlatResourceImage(path9) {
|
|
799
|
-
return path9.split("/").includes("Resources") && RASTER_EXTENSIONS.has(extOf(path9));
|
|
800
|
-
}
|
|
801
|
-
function enumerateBundleImages(paths, readText) {
|
|
802
|
-
const table = [];
|
|
803
|
-
const seen = /* @__PURE__ */ new Set();
|
|
804
|
-
const catalogs = paths.filter((path9) => baseOf(path9) === "Contents.json");
|
|
805
|
-
for (const contentsPath of catalogs) {
|
|
806
|
-
const name = imagesetName(contentsPath);
|
|
807
|
-
if (name === null || seen.has(name)) continue;
|
|
808
|
-
let parsed;
|
|
809
|
-
try {
|
|
810
|
-
const text = readText(contentsPath);
|
|
811
|
-
if (text === null) continue;
|
|
812
|
-
parsed = JSON.parse(text);
|
|
813
|
-
} catch {
|
|
814
|
-
continue;
|
|
815
|
-
}
|
|
816
|
-
const images = parsed?.images;
|
|
817
|
-
if (!Array.isArray(images)) continue;
|
|
818
|
-
const dir = contentsPath.split("/").slice(0, -1).join("/");
|
|
819
|
-
const file = pickImagesetFile(images);
|
|
820
|
-
if (file === null || file.includes("/") || file.includes("\\")) continue;
|
|
821
|
-
seen.add(name);
|
|
822
|
-
table.push({ name, file: `${dir}/${file}` });
|
|
823
|
-
}
|
|
824
|
-
for (const path9 of paths) {
|
|
825
|
-
if (!isFlatResourceImage(path9)) continue;
|
|
826
|
-
const name = baseOf(path9).slice(0, -extOf(path9).length);
|
|
827
|
-
if (name === "" || seen.has(name)) continue;
|
|
828
|
-
seen.add(name);
|
|
829
|
-
table.push({ name, file: path9 });
|
|
830
|
-
}
|
|
831
|
-
return table;
|
|
832
|
-
}
|
|
833
|
-
function enumerateBundleJson(paths) {
|
|
834
|
-
const found = [];
|
|
835
|
-
const seen = /* @__PURE__ */ new Set();
|
|
836
|
-
const ordered = [...paths].filter(
|
|
837
|
-
(path9) => path9.split("/").includes("Resources") && path9.split("/").every((segment) => segment !== "" && segment !== "..") && extOf(path9) === ".json"
|
|
838
|
-
).sort((a, b) => {
|
|
839
|
-
const aDepth = a.split("/").length;
|
|
840
|
-
const bDepth = b.split("/").length;
|
|
841
|
-
return aDepth - bDepth || (a < b ? -1 : a > b ? 1 : 0);
|
|
842
|
-
});
|
|
843
|
-
for (const file of ordered) {
|
|
844
|
-
const base = baseOf(file);
|
|
845
|
-
if (seen.has(base)) continue;
|
|
846
|
-
seen.add(base);
|
|
847
|
-
found.push({ base, file });
|
|
848
|
-
}
|
|
849
|
-
return found;
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
// ../sootsim-swift/src/entryModule.ts
|
|
853
|
-
function swiftEntryModuleEsm(args) {
|
|
854
|
-
return [
|
|
855
|
-
`import { createSwiftEntry } from 'peachsim/swift'`,
|
|
856
|
-
`export default createSwiftEntry({ url: ${JSON.stringify(args.url)}, hash: ${JSON.stringify(args.hash)}, rootId: ${JSON.stringify(args.rootId)}, resources: ${JSON.stringify(args.resources)}, bundleFiles: ${JSON.stringify(args.bundleFiles)} })`,
|
|
857
|
-
""
|
|
858
|
-
].join("\n");
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
// src/swift-compile.ts
|
|
862
|
-
var import_node_child_process2 = require("node:child_process");
|
|
863
|
-
var import_node_crypto2 = require("node:crypto");
|
|
864
|
-
var import_node_fs3 = require("node:fs");
|
|
865
|
-
var import_node_path4 = __toESM(require("node:path"), 1);
|
|
866
|
-
var import_node_util = require("node:util");
|
|
867
|
-
|
|
868
|
-
// src/swift-package.ts
|
|
869
|
-
function swiftManifestTargets(manifest) {
|
|
870
|
-
const code = manifest.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/[^\n]*/g, "");
|
|
871
|
-
const targets = [];
|
|
872
|
-
const pattern = /\.(executableTarget|target)\s*\(/g;
|
|
873
|
-
let match;
|
|
874
|
-
while ((match = pattern.exec(code)) !== null) {
|
|
875
|
-
const executable = match[1] === "executableTarget";
|
|
876
|
-
let depth = 1;
|
|
877
|
-
let i = pattern.lastIndex;
|
|
878
|
-
let inString = false;
|
|
879
|
-
let escaped = false;
|
|
880
|
-
let flat = "";
|
|
881
|
-
while (i < code.length && depth > 0) {
|
|
882
|
-
const ch = code[i];
|
|
883
|
-
if (inString) {
|
|
884
|
-
if (escaped) escaped = false;
|
|
885
|
-
else if (ch === "\\") escaped = true;
|
|
886
|
-
else if (ch === '"') inString = false;
|
|
887
|
-
if (depth === 1) flat += ch;
|
|
888
|
-
} else if (ch === '"') {
|
|
889
|
-
inString = true;
|
|
890
|
-
if (depth === 1) flat += ch;
|
|
891
|
-
} else if (ch === "(") {
|
|
892
|
-
depth++;
|
|
893
|
-
if (depth === 1) flat += ch;
|
|
894
|
-
} else if (ch === ")") {
|
|
895
|
-
depth--;
|
|
896
|
-
if (depth >= 1) flat += ch;
|
|
897
|
-
} else if (depth === 1) {
|
|
898
|
-
flat += ch;
|
|
899
|
-
}
|
|
900
|
-
i++;
|
|
901
|
-
}
|
|
902
|
-
const name = /\bname\s*:\s*"([^"]+)"/.exec(flat)?.[1];
|
|
903
|
-
if (!name) continue;
|
|
904
|
-
const rawPath = /\bpath\s*:\s*"([^"]*)"/.exec(flat)?.[1];
|
|
905
|
-
const targetPath = rawPath == null || rawPath === "" ? `Sources/${name}` : rawPath.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
906
|
-
targets.push({ name, path: targetPath, executable });
|
|
907
|
-
}
|
|
908
|
-
return targets;
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
// src/swift-compile.ts
|
|
912
|
-
var run = (0, import_node_util.promisify)(import_node_child_process2.execFile);
|
|
913
|
-
var WASM_TRIPLE = "wasm32-unknown-wasip1";
|
|
914
|
-
function swiftModuleInputFiles(root) {
|
|
915
|
-
const files = ["Package.swift", "scripts/contrast-app-Package.swift"];
|
|
916
|
-
const walk = (dir) => {
|
|
917
|
-
for (const entry of (0, import_node_fs3.readdirSync)(import_node_path4.default.join(root, dir), { withFileTypes: true })) {
|
|
918
|
-
const relative2 = `${dir}/${entry.name}`;
|
|
919
|
-
if (entry.isDirectory()) walk(relative2);
|
|
920
|
-
else if (entry.name.endsWith(".swift")) files.push(relative2);
|
|
921
|
-
}
|
|
922
|
-
};
|
|
923
|
-
walk("Sources");
|
|
924
|
-
return files.sort();
|
|
925
|
-
}
|
|
926
|
-
var linkedModuleDigests = /* @__PURE__ */ new Map();
|
|
927
|
-
function linkedModuleDigest(root) {
|
|
928
|
-
const files = swiftModuleInputFiles(root);
|
|
929
|
-
const stampHash = (0, import_node_crypto2.createHash)("sha256");
|
|
930
|
-
for (const file of files) {
|
|
931
|
-
const stat = (0, import_node_fs3.statSync)(import_node_path4.default.join(root, file), { bigint: true });
|
|
932
|
-
stampHash.update(file);
|
|
933
|
-
stampHash.update(
|
|
934
|
-
`${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}
|
|
935
|
-
`
|
|
936
|
-
);
|
|
937
|
-
}
|
|
938
|
-
const stamp = stampHash.digest("hex");
|
|
939
|
-
const cached = linkedModuleDigests.get(root);
|
|
940
|
-
if (cached?.stamp === stamp) return cached.digest;
|
|
941
|
-
const hash = (0, import_node_crypto2.createHash)("sha256");
|
|
942
|
-
for (const file of files) {
|
|
943
|
-
hash.update((0, import_node_crypto2.createHash)("sha256").update(file).digest());
|
|
944
|
-
hash.update(
|
|
945
|
-
(0, import_node_crypto2.createHash)("sha256").update((0, import_node_fs3.readFileSync)(import_node_path4.default.join(root, file))).digest()
|
|
946
|
-
);
|
|
947
|
-
}
|
|
948
|
-
const digest = hash.digest();
|
|
949
|
-
linkedModuleDigests.set(root, { stamp, digest });
|
|
950
|
-
return digest;
|
|
951
|
-
}
|
|
952
|
-
function compileTargets(input) {
|
|
953
|
-
const manifest = input.files["Package.swift"];
|
|
954
|
-
return manifest === void 0 ? [] : swiftManifestTargets(manifest);
|
|
955
|
-
}
|
|
956
|
-
function swiftSiblingDependencies(files, targets) {
|
|
957
|
-
const names = new Set(targets.map((target) => target.name));
|
|
958
|
-
const siblings = /* @__PURE__ */ new Map();
|
|
959
|
-
for (const target of targets) {
|
|
960
|
-
const prefix = `${target.path}/`;
|
|
961
|
-
const deps = /* @__PURE__ */ new Set();
|
|
962
|
-
for (const [file, contents] of Object.entries(files)) {
|
|
963
|
-
if (file === "Package.swift" || !file.startsWith(prefix)) continue;
|
|
964
|
-
for (const match of contents.matchAll(/^\s*import\s+([A-Za-z_][A-Za-z0-9_]*)/gm)) {
|
|
965
|
-
if (names.has(match[1]) && match[1] !== target.name) deps.add(match[1]);
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
siblings.set(target.name, [...deps].sort());
|
|
969
|
-
}
|
|
970
|
-
return siblings;
|
|
971
|
-
}
|
|
972
|
-
var MULTI_MANIFEST_VERSION = 1;
|
|
973
|
-
function swiftArtifactHash(input, release, moduleRoot) {
|
|
974
|
-
const hash = (0, import_node_crypto2.createHash)("sha256");
|
|
975
|
-
hash.update(`swift-compile/v1
|
|
976
|
-
${release}
|
|
977
|
-
`);
|
|
978
|
-
hash.update(linkedModuleDigest(moduleRoot));
|
|
979
|
-
for (const file of Object.keys(input.files).sort()) {
|
|
980
|
-
hash.update((0, import_node_crypto2.createHash)("sha256").update(file).digest());
|
|
981
|
-
hash.update((0, import_node_crypto2.createHash)("sha256").update(input.files[file]).digest());
|
|
982
|
-
}
|
|
983
|
-
for (const base of Object.keys(input.resources ?? {}).sort()) {
|
|
984
|
-
hash.update((0, import_node_crypto2.createHash)("sha256").update(base).digest());
|
|
985
|
-
hash.update(
|
|
986
|
-
(0, import_node_crypto2.createHash)("sha256").update(input.resources?.[base] ?? "").digest()
|
|
987
|
-
);
|
|
988
|
-
}
|
|
989
|
-
for (const name of Object.keys(input.images ?? {}).sort()) {
|
|
990
|
-
const image = input.images?.[name];
|
|
991
|
-
if (!image) continue;
|
|
992
|
-
hash.update((0, import_node_crypto2.createHash)("sha256").update(name).digest());
|
|
993
|
-
hash.update((0, import_node_crypto2.createHash)("sha256").update(image.file).digest());
|
|
994
|
-
hash.update((0, import_node_crypto2.createHash)("sha256").update(image.data).digest());
|
|
995
|
-
}
|
|
996
|
-
const targets = compileTargets(input);
|
|
997
|
-
if (targets.length > 0) {
|
|
998
|
-
hash.update(`swift-multi/v${MULTI_MANIFEST_VERSION}
|
|
999
|
-
`);
|
|
1000
|
-
hash.update(
|
|
1001
|
-
JSON.stringify({
|
|
1002
|
-
targets,
|
|
1003
|
-
siblings: [...swiftSiblingDependencies(input.files, targets)].sort(
|
|
1004
|
-
(a, b) => String(a) < String(b) ? -1 : String(a) > String(b) ? 1 : 0
|
|
1005
|
-
)
|
|
1006
|
-
})
|
|
1007
|
-
);
|
|
1008
|
-
}
|
|
1009
|
-
return hash.digest("hex");
|
|
1010
|
-
}
|
|
1011
|
-
function emitSwiftPackageManifest(args) {
|
|
1012
|
-
const { targets, siblings, moduleRoot } = args;
|
|
1013
|
-
const executable = targets.find((target) => target.executable);
|
|
1014
|
-
if (!executable) throw new Error("swift-compile: no executable target to emit");
|
|
1015
|
-
const swiftSettings = 'swiftSettings: [.swiftLanguageMode(.v5), .unsafeFlags(["-Osize"])]';
|
|
1016
|
-
const stanza = (target) => {
|
|
1017
|
-
const deps = [
|
|
1018
|
-
'.product(name: "SwiftUI", package: "sootsim-swift")',
|
|
1019
|
-
...(siblings.get(target.name) ?? []).map((sibling) => `"${sibling}"`)
|
|
1020
|
-
].join(", ");
|
|
1021
|
-
const kind = target.executable ? ".executableTarget" : ".target";
|
|
1022
|
-
const link = target.executable ? `,
|
|
1023
|
-
linkerSettings: [
|
|
1024
|
-
.unsafeFlags([
|
|
1025
|
-
"-Xclang-linker", "-mexec-model=reactor",
|
|
1026
|
-
"-Xlinker", "--export-if-defined=__main_argc_argv",
|
|
1027
|
-
]),
|
|
1028
|
-
.unsafeFlags(["-Xlinker", "--strip-all"], .when(configuration: .release)),
|
|
1029
|
-
]` : "";
|
|
1030
|
-
return [
|
|
1031
|
-
` ${kind}(`,
|
|
1032
|
-
` name: "${target.name}",`,
|
|
1033
|
-
` dependencies: [${deps}],`,
|
|
1034
|
-
` path: "${target.path}",`,
|
|
1035
|
-
` ${swiftSettings}${link}`,
|
|
1036
|
-
` ),`
|
|
1037
|
-
].join("\n");
|
|
1038
|
-
};
|
|
1039
|
-
return [
|
|
1040
|
-
"// swift-tools-version: 6.0",
|
|
1041
|
-
"import PackageDescription",
|
|
1042
|
-
"",
|
|
1043
|
-
"// generated by swift-compile from the project package partition.",
|
|
1044
|
-
"let package = Package(",
|
|
1045
|
-
' name: "app",',
|
|
1046
|
-
` products: [.executable(name: "${executable.name}", targets: ["${executable.name}"])],`,
|
|
1047
|
-
` dependencies: [.package(path: "${moduleRoot}")],`,
|
|
1048
|
-
" targets: [",
|
|
1049
|
-
...targets.map(stanza),
|
|
1050
|
-
" ]",
|
|
1051
|
-
")",
|
|
1052
|
-
""
|
|
1053
|
-
].join("\n");
|
|
1054
|
-
}
|
|
1055
|
-
function writeSwiftProject(layout, input, moduleRoot) {
|
|
1056
|
-
const targets = compileTargets(input);
|
|
1057
|
-
if (targets.length === 0) {
|
|
1058
|
-
(0, import_node_fs3.rmSync)(layout.sources, { recursive: true, force: true });
|
|
1059
|
-
for (const [file, contents] of Object.entries(input.files)) {
|
|
1060
|
-
const target = import_node_path4.default.join(layout.sources, file);
|
|
1061
|
-
(0, import_node_fs3.mkdirSync)(import_node_path4.default.dirname(target), { recursive: true });
|
|
1062
|
-
(0, import_node_fs3.writeFileSync)(target, contents, "utf8");
|
|
1063
|
-
}
|
|
1064
|
-
const manifest = (0, import_node_fs3.readFileSync)(
|
|
1065
|
-
import_node_path4.default.join(moduleRoot, "scripts/contrast-app-Package.swift"),
|
|
1066
|
-
"utf8"
|
|
1067
|
-
).replaceAll("__SOOTSIM_SWIFT_PACKAGE__", moduleRoot);
|
|
1068
|
-
(0, import_node_fs3.writeFileSync)(import_node_path4.default.join(layout.root, "Package.swift"), manifest, "utf8");
|
|
1069
|
-
return;
|
|
1070
|
-
}
|
|
1071
|
-
(0, import_node_fs3.mkdirSync)(layout.root, { recursive: true });
|
|
1072
|
-
for (const child of (0, import_node_fs3.readdirSync)(layout.root)) {
|
|
1073
|
-
if (child === ".build") continue;
|
|
1074
|
-
(0, import_node_fs3.rmSync)(import_node_path4.default.join(layout.root, child), { recursive: true, force: true });
|
|
1075
|
-
}
|
|
1076
|
-
for (const [file, contents] of Object.entries(input.files)) {
|
|
1077
|
-
if (file === "Package.swift") continue;
|
|
1078
|
-
const target = import_node_path4.default.join(layout.root, file);
|
|
1079
|
-
(0, import_node_fs3.mkdirSync)(import_node_path4.default.dirname(target), { recursive: true });
|
|
1080
|
-
(0, import_node_fs3.writeFileSync)(target, contents, "utf8");
|
|
1081
|
-
}
|
|
1082
|
-
(0, import_node_fs3.writeFileSync)(
|
|
1083
|
-
import_node_path4.default.join(layout.root, "Package.swift"),
|
|
1084
|
-
emitSwiftPackageManifest({
|
|
1085
|
-
targets,
|
|
1086
|
-
siblings: swiftSiblingDependencies(input.files, targets),
|
|
1087
|
-
moduleRoot
|
|
1088
|
-
}),
|
|
1089
|
-
"utf8"
|
|
1090
|
-
);
|
|
1091
|
-
}
|
|
1092
|
-
function streamText(value) {
|
|
1093
|
-
if (typeof value === "string") return value.trim();
|
|
1094
|
-
if (Buffer.isBuffer(value)) return value.toString("utf8").trim();
|
|
1095
|
-
return "";
|
|
1096
|
-
}
|
|
1097
|
-
function outputOf(error) {
|
|
1098
|
-
if (error && typeof error === "object") {
|
|
1099
|
-
const streams = [
|
|
1100
|
-
streamText(Reflect.get(error, "stdout")),
|
|
1101
|
-
streamText(Reflect.get(error, "stderr"))
|
|
1102
|
-
].filter(Boolean);
|
|
1103
|
-
if (streams.length > 0) return streams.join("\n");
|
|
1104
|
-
}
|
|
1105
|
-
return error instanceof Error ? error.message : String(error);
|
|
1106
|
-
}
|
|
1107
|
-
function builtArtifact(layout) {
|
|
1108
|
-
const binDir = import_node_path4.default.join(layout.root, ".build", WASM_TRIPLE, "release");
|
|
1109
|
-
const artifacts = (0, import_node_fs3.existsSync)(binDir) ? (0, import_node_fs3.readdirSync)(binDir).filter((name) => name.endsWith(".wasm")).sort() : [];
|
|
1110
|
-
if (artifacts.length !== 1) {
|
|
1111
|
-
throw new Error(
|
|
1112
|
-
`swift-compile: the build produced ${artifacts.length} wasm artifacts; exactly one executable is the app`
|
|
1113
|
-
);
|
|
1114
|
-
}
|
|
1115
|
-
return import_node_path4.default.join(binDir, artifacts[0]);
|
|
1116
|
-
}
|
|
1117
|
-
function projectDiagnostic(output, layout) {
|
|
1118
|
-
const base = layout.multi ? layout.root : layout.sources;
|
|
1119
|
-
const prefix = `${base}${import_node_path4.default.sep}`;
|
|
1120
|
-
return output.split("\n").map((line) => line.startsWith(prefix) ? line.slice(prefix.length) : line).join("\n").trim();
|
|
1121
|
-
}
|
|
1122
|
-
var ROOT_LOCKS = Symbol.for("peachsim.swiftCompile.rootLocks");
|
|
1123
|
-
var host = globalThis;
|
|
1124
|
-
var rootLocks = host[ROOT_LOCKS] ??= /* @__PURE__ */ new Map();
|
|
1125
|
-
function serialize(root, work) {
|
|
1126
|
-
const current = rootLocks.get(root) ?? Promise.resolve();
|
|
1127
|
-
const next = current.then(work, work);
|
|
1128
|
-
rootLocks.set(
|
|
1129
|
-
root,
|
|
1130
|
-
next.catch(() => {
|
|
1131
|
-
})
|
|
1132
|
-
);
|
|
1133
|
-
return next;
|
|
1134
|
-
}
|
|
1135
|
-
function compileSwiftProjectUnit(input, options) {
|
|
1136
|
-
(0, import_node_fs3.mkdirSync)(options.buildRoot, { recursive: true });
|
|
1137
|
-
const root = (0, import_node_fs3.realpathSync)(options.buildRoot);
|
|
1138
|
-
const moduleRoot = import_node_path4.default.resolve(options.moduleRoot);
|
|
1139
|
-
const layout = {
|
|
1140
|
-
root,
|
|
1141
|
-
sources: import_node_path4.default.join(root, "Sources", "App"),
|
|
1142
|
-
multi: compileTargets(input).length > 0
|
|
1143
|
-
};
|
|
1144
|
-
const hash = swiftArtifactHash(input, options.release, moduleRoot);
|
|
1145
|
-
return serialize(root, async () => {
|
|
1146
|
-
writeSwiftProject(layout, input, moduleRoot);
|
|
1147
|
-
const swift = import_node_path4.default.join(options.toolchainBin, "swift");
|
|
1148
|
-
if (!(0, import_node_fs3.existsSync)(swift)) {
|
|
1149
|
-
throw new Error(
|
|
1150
|
-
`swift-compile: no swift.org toolchain at ${options.toolchainBin}; install ${options.release} and its matching wasm sdk`
|
|
1151
|
-
);
|
|
1152
|
-
}
|
|
1153
|
-
try {
|
|
1154
|
-
await run(
|
|
1155
|
-
swift,
|
|
1156
|
-
[
|
|
1157
|
-
"build",
|
|
1158
|
-
"--package-path",
|
|
1159
|
-
root,
|
|
1160
|
-
"--swift-sdk",
|
|
1161
|
-
`${options.release}_wasm`,
|
|
1162
|
-
"-c",
|
|
1163
|
-
"release",
|
|
1164
|
-
"-Xswiftc",
|
|
1165
|
-
"-Osize"
|
|
1166
|
-
],
|
|
1167
|
-
{ maxBuffer: 64 * 1024 * 1024, timeout: options.timeoutMs }
|
|
1168
|
-
);
|
|
1169
|
-
} catch (error) {
|
|
1170
|
-
throw new Error(projectDiagnostic(outputOf(error), layout), { cause: error });
|
|
1171
|
-
}
|
|
1172
|
-
return { hash, bytes: (0, import_node_fs3.readFileSync)(builtArtifact(layout)) };
|
|
1173
|
-
});
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
// src/vite-plugin-swift.ts
|
|
1177
|
-
var ARTIFACT_PATH = "/__peach/swift/";
|
|
1178
|
-
var RESOURCE_PATH = "/__peach/swift-res/";
|
|
1179
|
-
var VIRTUAL_PREFIX = "\0peach-swift:";
|
|
1180
|
-
var projects = /* @__PURE__ */ new Map();
|
|
1181
|
-
var devServer;
|
|
1182
|
-
function projectFor(packagePath) {
|
|
1183
|
-
const existing = projects.get(packagePath);
|
|
1184
|
-
if (existing) return existing;
|
|
1185
|
-
const created = {
|
|
1186
|
-
packagePath,
|
|
1187
|
-
artifact: null,
|
|
1188
|
-
building: null,
|
|
1189
|
-
resourceFiles: /* @__PURE__ */ new Map()
|
|
1190
|
-
};
|
|
1191
|
-
projects.set(packagePath, created);
|
|
1192
|
-
return created;
|
|
1193
|
-
}
|
|
1194
|
-
function sourceFiles(root) {
|
|
1195
|
-
const found = [];
|
|
1196
|
-
const walk = (dir) => {
|
|
1197
|
-
for (const entry of import_node_fs4.default.readdirSync(dir, { withFileTypes: true })) {
|
|
1198
|
-
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
1199
|
-
const full = import_node_path5.default.join(dir, entry.name);
|
|
1200
|
-
if (entry.isDirectory()) {
|
|
1201
|
-
if (full !== root && import_node_fs4.default.existsSync(import_node_path5.default.join(full, "Package.swift"))) continue;
|
|
1202
|
-
walk(full);
|
|
1203
|
-
} else if (entry.name.endsWith(".swift")) found.push(full);
|
|
1204
|
-
}
|
|
1205
|
-
};
|
|
1206
|
-
walk(root);
|
|
1207
|
-
return found;
|
|
1208
|
-
}
|
|
1209
|
-
function resourceCandidateFiles(root) {
|
|
1210
|
-
const found = [];
|
|
1211
|
-
const walk = (dir) => {
|
|
1212
|
-
for (const entry of import_node_fs4.default.readdirSync(dir, { withFileTypes: true })) {
|
|
1213
|
-
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === ".build")
|
|
1214
|
-
continue;
|
|
1215
|
-
const full = import_node_path5.default.join(dir, entry.name);
|
|
1216
|
-
if (entry.isDirectory()) {
|
|
1217
|
-
if (full !== root && import_node_fs4.default.existsSync(import_node_path5.default.join(full, "Package.swift"))) continue;
|
|
1218
|
-
walk(full);
|
|
1219
|
-
} else {
|
|
1220
|
-
found.push(full);
|
|
1221
|
-
}
|
|
1222
|
-
}
|
|
1223
|
-
};
|
|
1224
|
-
walk(root);
|
|
1225
|
-
return found;
|
|
1226
|
-
}
|
|
1227
|
-
var RESOURCE_CONTENT_TYPES = {
|
|
1228
|
-
".avif": "image/avif",
|
|
1229
|
-
".bmp": "image/bmp",
|
|
1230
|
-
".gif": "image/gif",
|
|
1231
|
-
".ico": "image/x-icon",
|
|
1232
|
-
".jpeg": "image/jpeg",
|
|
1233
|
-
".jpg": "image/jpeg",
|
|
1234
|
-
".png": "image/png",
|
|
1235
|
-
".webp": "image/webp"
|
|
1236
|
-
};
|
|
1237
|
-
function buildSwiftResourceTable(project, baseUrl) {
|
|
1238
|
-
const absolute = resourceCandidateFiles(project.packagePath);
|
|
1239
|
-
const relative2 = absolute.map(
|
|
1240
|
-
(file) => import_node_path5.default.relative(project.packagePath, file).split(import_node_path5.default.sep).join(import_node_path5.default.posix.sep)
|
|
1241
|
-
);
|
|
1242
|
-
const byRelative = new Map(absolute.map((file, index) => [relative2[index], file]));
|
|
1243
|
-
const found = enumerateBundleImages(relative2, (candidate) => {
|
|
1244
|
-
const file = byRelative.get(candidate);
|
|
1245
|
-
if (!file || import_node_path5.default.basename(file) !== "Contents.json") return null;
|
|
1246
|
-
try {
|
|
1247
|
-
return import_node_fs4.default.readFileSync(file, "utf8");
|
|
1248
|
-
} catch {
|
|
1249
|
-
return null;
|
|
1250
|
-
}
|
|
1251
|
-
});
|
|
1252
|
-
const table = {};
|
|
1253
|
-
const images = {};
|
|
1254
|
-
const watched = [];
|
|
1255
|
-
const registered = /* @__PURE__ */ new Map();
|
|
1256
|
-
for (const { name, file } of found) {
|
|
1257
|
-
const disk = byRelative.get(file);
|
|
1258
|
-
if (!disk) continue;
|
|
1259
|
-
let bytes;
|
|
1260
|
-
try {
|
|
1261
|
-
bytes = import_node_fs4.default.readFileSync(disk);
|
|
1262
|
-
} catch {
|
|
1263
|
-
continue;
|
|
1264
|
-
}
|
|
1265
|
-
const hash = (0, import_node_crypto3.createHash)("sha256").update(bytes).digest("hex").slice(0, 16);
|
|
1266
|
-
const ext = import_node_path5.default.posix.extname(file).toLowerCase();
|
|
1267
|
-
table[name] = `${baseUrl}${RESOURCE_PATH}${hash}${ext}`;
|
|
1268
|
-
images[name] = {
|
|
1269
|
-
file: import_node_path5.default.posix.basename(file),
|
|
1270
|
-
data: bytes.toString("base64")
|
|
1271
|
-
};
|
|
1272
|
-
watched.push(file);
|
|
1273
|
-
const contents = file.replace(/\/[^/]+$/, "/Contents.json");
|
|
1274
|
-
if (byRelative.has(contents)) watched.push(contents);
|
|
1275
|
-
registered.set(`${hash}${ext}`, disk);
|
|
1276
|
-
}
|
|
1277
|
-
project.resourceFiles = registered;
|
|
1278
|
-
return { table, images, watched };
|
|
1279
|
-
}
|
|
1280
|
-
var BUNDLE_MAX_FILES = 128;
|
|
1281
|
-
var BUNDLE_MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
1282
|
-
var BUNDLE_MAX_TOTAL_BYTES = 8 * 1024 * 1024;
|
|
1283
|
-
function buildSwiftBundleFiles(packagePath) {
|
|
1284
|
-
const relative2 = resourceCandidateFiles(packagePath).map(
|
|
1285
|
-
(file) => import_node_path5.default.relative(packagePath, file).split(import_node_path5.default.sep).join(import_node_path5.default.posix.sep)
|
|
1286
|
-
);
|
|
1287
|
-
const files = {};
|
|
1288
|
-
const watched = [];
|
|
1289
|
-
const skipped = [];
|
|
1290
|
-
let total = 0;
|
|
1291
|
-
for (const { base, file } of enumerateBundleJson(relative2)) {
|
|
1292
|
-
watched.push(file);
|
|
1293
|
-
let bytes;
|
|
1294
|
-
try {
|
|
1295
|
-
bytes = import_node_fs4.default.readFileSync(import_node_path5.default.join(packagePath, ...file.split("/")));
|
|
1296
|
-
} catch {
|
|
1297
|
-
continue;
|
|
1298
|
-
}
|
|
1299
|
-
if (bytes.length > BUNDLE_MAX_FILE_BYTES) {
|
|
1300
|
-
skipped.push(`${file} (${bytes.length} bytes past the per-file cap)`);
|
|
1301
|
-
continue;
|
|
1302
|
-
}
|
|
1303
|
-
if (Object.keys(files).length >= BUNDLE_MAX_FILES || total + bytes.length > BUNDLE_MAX_TOTAL_BYTES) {
|
|
1304
|
-
skipped.push(
|
|
1305
|
-
`${file} (pack caps: ${BUNDLE_MAX_FILES} files / ${BUNDLE_MAX_TOTAL_BYTES} bytes)`
|
|
1306
|
-
);
|
|
1307
|
-
continue;
|
|
1308
|
-
}
|
|
1309
|
-
files[base] = bytes.toString("base64");
|
|
1310
|
-
total += bytes.length;
|
|
1311
|
-
}
|
|
1312
|
-
return { files, watched, skipped };
|
|
1313
|
-
}
|
|
1314
|
-
function serveSwiftResource(project, key) {
|
|
1315
|
-
const disk = project.resourceFiles.get(key);
|
|
1316
|
-
if (!disk) return null;
|
|
1317
|
-
try {
|
|
1318
|
-
return {
|
|
1319
|
-
bytes: import_node_fs4.default.readFileSync(disk),
|
|
1320
|
-
contentType: RESOURCE_CONTENT_TYPES[import_node_path5.default.extname(disk).toLowerCase()] ?? "application/octet-stream"
|
|
1321
|
-
};
|
|
1322
|
-
} catch {
|
|
1323
|
-
return null;
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
function linkedModuleRoots(packagePath) {
|
|
1327
|
-
let manifest;
|
|
1328
|
-
try {
|
|
1329
|
-
manifest = import_node_fs4.default.readFileSync(import_node_path5.default.join(packagePath, "Package.swift"), "utf8");
|
|
1330
|
-
} catch {
|
|
1331
|
-
return [];
|
|
1332
|
-
}
|
|
1333
|
-
const roots = /* @__PURE__ */ new Set();
|
|
1334
|
-
const dependency = /\.package\(\s*path:\s*"([^"]+)"\s*\)/g;
|
|
1335
|
-
for (const match of manifest.replace(/^\s*\/\/.*$/gm, "").matchAll(dependency)) {
|
|
1336
|
-
const root = import_node_path5.default.resolve(packagePath, match[1]);
|
|
1337
|
-
if (import_node_fs4.default.existsSync(import_node_path5.default.join(root, "Package.swift"))) roots.add(root);
|
|
1338
|
-
}
|
|
1339
|
-
return [...roots].sort();
|
|
1340
|
-
}
|
|
1341
|
-
function sourceStamp(packagePath) {
|
|
1342
|
-
const hash = (0, import_node_crypto3.createHash)("sha256");
|
|
1343
|
-
hash.update(packagePath);
|
|
1344
|
-
const projectInputs = /* @__PURE__ */ new Set([
|
|
1345
|
-
import_node_path5.default.join(packagePath, "Package.swift"),
|
|
1346
|
-
...sourceFiles(packagePath),
|
|
1347
|
-
...buildSwiftBundleFiles(packagePath).watched.map(
|
|
1348
|
-
(file) => import_node_path5.default.join(packagePath, ...file.split(import_node_path5.default.posix.sep))
|
|
1349
|
-
),
|
|
1350
|
-
...buildSwiftResourceTable(projectFor(packagePath), "").watched.map(
|
|
1351
|
-
(file) => import_node_path5.default.join(packagePath, ...file.split(import_node_path5.default.posix.sep))
|
|
1352
|
-
)
|
|
1353
|
-
]);
|
|
1354
|
-
for (const file of [...projectInputs].sort()) {
|
|
1355
|
-
hash.update(import_node_path5.default.relative(packagePath, file));
|
|
1356
|
-
hash.update(String(import_node_fs4.default.statSync(file).mtimeMs));
|
|
1357
|
-
}
|
|
1358
|
-
const moduleRoot = linkedModuleRoots(packagePath).find(
|
|
1359
|
-
(root) => import_node_fs4.default.existsSync(import_node_path5.default.join(root, "toolchain.json"))
|
|
1360
|
-
);
|
|
1361
|
-
if (moduleRoot) {
|
|
1362
|
-
hash.update(moduleRoot);
|
|
1363
|
-
for (const relative2 of [
|
|
1364
|
-
...swiftModuleInputFiles(moduleRoot),
|
|
1365
|
-
"toolchain.json"
|
|
1366
|
-
].sort()) {
|
|
1367
|
-
hash.update(relative2);
|
|
1368
|
-
hash.update(String(import_node_fs4.default.statSync(import_node_path5.default.join(moduleRoot, relative2)).mtimeMs));
|
|
1369
|
-
}
|
|
1370
|
-
}
|
|
1371
|
-
return hash.digest("hex").slice(0, 16);
|
|
1372
|
-
}
|
|
1373
|
-
function entryRootId(packagePath, file) {
|
|
1374
|
-
const relative2 = import_node_path5.default.relative(packagePath, file).split(import_node_path5.default.sep).join(import_node_path5.default.posix.sep);
|
|
1375
|
-
return `${import_node_path5.default.basename(packagePath)}${import_node_path5.default.posix.sep}${relative2}`;
|
|
1376
|
-
}
|
|
1377
|
-
function serverOrigin() {
|
|
1378
|
-
const address = devServer?.httpServer?.address();
|
|
1379
|
-
const port = address && typeof address === "object" ? address.port : devServer?.config.server.port;
|
|
1380
|
-
if (!port) throw new Error("the swift urls need the dev server port");
|
|
1381
|
-
return `http://localhost:${port}`;
|
|
1382
|
-
}
|
|
1383
|
-
function artifactUrl(project, artifact) {
|
|
1384
|
-
return `${serverOrigin()}${ARTIFACT_PATH}${artifact.hash}.wasm`;
|
|
1385
|
-
}
|
|
1386
|
-
function compileInput(packagePath, entry) {
|
|
1387
|
-
const files = {};
|
|
1388
|
-
for (const file of sourceFiles(packagePath)) {
|
|
1389
|
-
const relative2 = import_node_path5.default.relative(packagePath, file).split(import_node_path5.default.sep).join(import_node_path5.default.posix.sep);
|
|
1390
|
-
files[relative2] = import_node_fs4.default.readFileSync(file, "utf8");
|
|
1391
|
-
}
|
|
1392
|
-
const manifest = import_node_path5.default.join(packagePath, "Package.swift");
|
|
1393
|
-
if (import_node_fs4.default.existsSync(manifest)) files["Package.swift"] = import_node_fs4.default.readFileSync(manifest, "utf8");
|
|
1394
|
-
const resources = buildSwiftBundleFiles(packagePath).files;
|
|
1395
|
-
const images = buildSwiftResourceTable(projectFor(packagePath), "").images;
|
|
1396
|
-
return {
|
|
1397
|
-
files,
|
|
1398
|
-
resources,
|
|
1399
|
-
images,
|
|
1400
|
-
entry
|
|
1401
|
-
};
|
|
1402
|
-
}
|
|
1403
|
-
async function compile(packagePath, entry, stamp) {
|
|
1404
|
-
const moduleRoot = linkedModuleRoots(packagePath).find(
|
|
1405
|
-
(root) => import_node_fs4.default.existsSync(import_node_path5.default.join(root, "toolchain.json"))
|
|
1406
|
-
);
|
|
1407
|
-
if (!moduleRoot) {
|
|
1408
|
-
throw new Error(
|
|
1409
|
-
`swift project ${packagePath} has no linked rnx SwiftUI package with toolchain.json`
|
|
1410
|
-
);
|
|
1411
|
-
}
|
|
1412
|
-
const toolchain = JSON.parse(
|
|
1413
|
-
import_node_fs4.default.readFileSync(import_node_path5.default.join(moduleRoot, "toolchain.json"), "utf8")
|
|
1414
|
-
);
|
|
1415
|
-
const release = toolchain && typeof toolchain === "object" ? Reflect.get(toolchain, "release") : void 0;
|
|
1416
|
-
if (typeof release !== "string") {
|
|
1417
|
-
throw new Error(`swift toolchain manifest at ${moduleRoot} has no release`);
|
|
1418
|
-
}
|
|
1419
|
-
const artifact = await compileSwiftProjectUnit(compileInput(packagePath, entry), {
|
|
1420
|
-
buildRoot: process.env.CONTRAST_SWIFT_BUILD_ROOT ?? import_node_path5.default.join(import_node_os2.default.tmpdir(), "contrast-swift-build"),
|
|
1421
|
-
moduleRoot,
|
|
1422
|
-
release,
|
|
1423
|
-
toolchainBin: import_node_path5.default.join(
|
|
1424
|
-
import_node_os2.default.homedir(),
|
|
1425
|
-
`Library/Developer/Toolchains/${release}.xctoolchain/usr/bin`
|
|
1426
|
-
)
|
|
1427
|
-
});
|
|
1428
|
-
return { ...artifact, stamp };
|
|
1429
|
-
}
|
|
1430
|
-
function artifactFor(project, entry) {
|
|
1431
|
-
const stamp = sourceStamp(project.packagePath);
|
|
1432
|
-
if (project.artifact?.stamp === stamp) return Promise.resolve(project.artifact);
|
|
1433
|
-
if (project.building) {
|
|
1434
|
-
const running = project.building;
|
|
1435
|
-
if (running.stamp === stamp) return running.promise;
|
|
1436
|
-
const again = () => artifactFor(project, entry);
|
|
1437
|
-
return running.promise.then(again, again);
|
|
1438
|
-
}
|
|
1439
|
-
const promise = compile(project.packagePath, entry, stamp).then(
|
|
1440
|
-
(artifact) => {
|
|
1441
|
-
project.artifact = artifact;
|
|
1442
|
-
project.building = null;
|
|
1443
|
-
return artifact;
|
|
1444
|
-
},
|
|
1445
|
-
(error) => {
|
|
1446
|
-
project.building = null;
|
|
1447
|
-
throw error;
|
|
1448
|
-
}
|
|
1449
|
-
);
|
|
1450
|
-
project.building = { stamp, promise };
|
|
1451
|
-
return promise;
|
|
1452
|
-
}
|
|
1453
|
-
function packageFor(file) {
|
|
1454
|
-
let dir = import_node_path5.default.dirname(file);
|
|
1455
|
-
const stop = devServer?.config.root;
|
|
1456
|
-
for (; ; ) {
|
|
1457
|
-
if (import_node_fs4.default.existsSync(import_node_path5.default.join(dir, "Package.swift"))) return dir;
|
|
1458
|
-
if (stop !== void 0 && dir === stop || import_node_path5.default.dirname(dir) === dir) break;
|
|
1459
|
-
dir = import_node_path5.default.dirname(dir);
|
|
1460
|
-
}
|
|
1461
|
-
throw new Error(
|
|
1462
|
-
`no Package.swift above ${file}${stop === void 0 ? "" : ` (searched up to ${stop})`}; a .swift import needs a swiftpm package like the one in packages/sootsim-swift/example`
|
|
1463
|
-
);
|
|
1464
|
-
}
|
|
1465
|
-
function swiftPlugin(options = {}) {
|
|
1466
|
-
return {
|
|
1467
|
-
name: "rnx-swift",
|
|
1468
|
-
enforce: "pre",
|
|
1469
|
-
async resolveId(source, importer) {
|
|
1470
|
-
if (source.startsWith(VIRTUAL_PREFIX)) return source;
|
|
1471
|
-
if (source.startsWith("/@id/")) {
|
|
1472
|
-
const decoded = source.slice("/@id/".length).replace(/^__x00__/, "\0");
|
|
1473
|
-
return decoded.startsWith(VIRTUAL_PREFIX) ? decoded : null;
|
|
1474
|
-
}
|
|
1475
|
-
if (!source.endsWith(".swift")) return null;
|
|
1476
|
-
const resolved = await this.resolve(source, importer, { skipSelf: true });
|
|
1477
|
-
if (!resolved) throw new Error(`cannot resolve swift source ${source}`);
|
|
1478
|
-
return VIRTUAL_PREFIX + resolved.id;
|
|
1479
|
-
},
|
|
1480
|
-
async load(id) {
|
|
1481
|
-
if (!id.startsWith(VIRTUAL_PREFIX)) return null;
|
|
1482
|
-
const file = id.slice(VIRTUAL_PREFIX.length);
|
|
1483
|
-
if (!import_node_fs4.default.existsSync(file)) throw new Error(`swift source ${file} no longer exists`);
|
|
1484
|
-
const packagePath = options.packagePath ?? packageFor(file);
|
|
1485
|
-
const project = projectFor(packagePath);
|
|
1486
|
-
const entry = import_node_path5.default.relative(packagePath, file).split(import_node_path5.default.sep).join(import_node_path5.default.posix.sep);
|
|
1487
|
-
for (const source of sourceFiles(packagePath)) this.addWatchFile(source);
|
|
1488
|
-
this.addWatchFile(import_node_path5.default.join(packagePath, "Package.swift"));
|
|
1489
|
-
for (const root of linkedModuleRoots(packagePath)) {
|
|
1490
|
-
for (const source of sourceFiles(root)) this.addWatchFile(source);
|
|
1491
|
-
}
|
|
1492
|
-
let artifact;
|
|
1493
|
-
try {
|
|
1494
|
-
artifact = await artifactFor(project, entry);
|
|
1495
|
-
} catch (error) {
|
|
1496
|
-
if (!project.artifact) throw error;
|
|
1497
|
-
this.warn(error instanceof Error ? error.message : String(error));
|
|
1498
|
-
artifact = project.artifact;
|
|
1499
|
-
}
|
|
1500
|
-
let resources = {};
|
|
1501
|
-
try {
|
|
1502
|
-
const built = buildSwiftResourceTable(project, serverOrigin());
|
|
1503
|
-
resources = built.table;
|
|
1504
|
-
for (const watched of built.watched) {
|
|
1505
|
-
this.addWatchFile(import_node_path5.default.join(packagePath, ...watched.split(import_node_path5.default.posix.sep)));
|
|
1506
|
-
}
|
|
1507
|
-
} catch (error) {
|
|
1508
|
-
this.warn(
|
|
1509
|
-
`swift resources for ${packagePath}: ${error instanceof Error ? error.message : String(error)}`
|
|
1510
|
-
);
|
|
1511
|
-
}
|
|
1512
|
-
let bundleFiles = {};
|
|
1513
|
-
try {
|
|
1514
|
-
const packed = buildSwiftBundleFiles(packagePath);
|
|
1515
|
-
bundleFiles = packed.files;
|
|
1516
|
-
for (const watched of packed.watched) {
|
|
1517
|
-
this.addWatchFile(import_node_path5.default.join(packagePath, ...watched.split(import_node_path5.default.posix.sep)));
|
|
1518
|
-
}
|
|
1519
|
-
if (packed.skipped.length > 0) {
|
|
1520
|
-
this.warn(
|
|
1521
|
-
`swift bundle files skipped for ${packagePath}: ${packed.skipped.join("; ")}`
|
|
1522
|
-
);
|
|
1523
|
-
}
|
|
1524
|
-
} catch (error) {
|
|
1525
|
-
this.warn(
|
|
1526
|
-
`swift bundle files for ${packagePath}: ${error instanceof Error ? error.message : String(error)}`
|
|
1527
|
-
);
|
|
1528
|
-
}
|
|
1529
|
-
return swiftEntryModuleEsm({
|
|
1530
|
-
url: artifactUrl(project, artifact),
|
|
1531
|
-
hash: artifact.hash,
|
|
1532
|
-
rootId: entryRootId(packagePath, file),
|
|
1533
|
-
resources,
|
|
1534
|
-
bundleFiles
|
|
1535
|
-
});
|
|
1536
|
-
},
|
|
1537
|
-
configureServer(server) {
|
|
1538
|
-
devServer = server;
|
|
1539
|
-
server.middlewares.use((req, res, next) => {
|
|
1540
|
-
const url = (req.url ?? "").split("?")[0];
|
|
1541
|
-
if (url.startsWith(RESOURCE_PATH)) {
|
|
1542
|
-
for (const project of projects.values()) {
|
|
1543
|
-
const served = serveSwiftResource(project, url.slice(RESOURCE_PATH.length));
|
|
1544
|
-
if (served) {
|
|
1545
|
-
res.setHeader("access-control-allow-origin", "*");
|
|
1546
|
-
res.setHeader("content-type", served.contentType);
|
|
1547
|
-
res.end(served.bytes);
|
|
1548
|
-
return;
|
|
1549
|
-
}
|
|
1550
|
-
}
|
|
1551
|
-
res.statusCode = 404;
|
|
1552
|
-
res.end("swift resource is stale");
|
|
1553
|
-
return;
|
|
1554
|
-
}
|
|
1555
|
-
if (!url.startsWith(ARTIFACT_PATH)) {
|
|
1556
|
-
next();
|
|
1557
|
-
return;
|
|
1558
|
-
}
|
|
1559
|
-
for (const project of projects.values()) {
|
|
1560
|
-
const artifact = project.artifact;
|
|
1561
|
-
if (artifact && url === `${ARTIFACT_PATH}${artifact.hash}.wasm`) {
|
|
1562
|
-
res.setHeader("access-control-allow-origin", "*");
|
|
1563
|
-
res.setHeader("content-type", "application/wasm");
|
|
1564
|
-
res.end(artifact.bytes);
|
|
1565
|
-
return;
|
|
1566
|
-
}
|
|
1567
|
-
}
|
|
1568
|
-
res.statusCode = 404;
|
|
1569
|
-
res.end("swift artifact is stale");
|
|
1570
|
-
});
|
|
1571
|
-
}
|
|
1572
|
-
};
|
|
1573
|
-
}
|
|
1574
|
-
|
|
1575
|
-
// src/rolldown-plugin-swift.ts
|
|
1576
|
-
var import_node_fs5 = __toESM(require("node:fs"), 1);
|
|
1577
|
-
var import_node_path6 = __toESM(require("node:path"), 1);
|
|
1578
|
-
|
|
1579
|
-
// src/swift-submit.ts
|
|
1580
|
-
var SWIFT_COMPILE_PATH = "/api/swift-compile";
|
|
1581
|
-
var POLL_INTERVAL_MS = 1500;
|
|
1582
|
-
function httpSwiftCompileSubmit(context) {
|
|
1583
|
-
const { assetReadToken, endpoint } = context;
|
|
1584
|
-
if (!assetReadToken) return void 0;
|
|
1585
|
-
const url = endpoint ? `${endpoint.replace(/\/+$/, "")}${SWIFT_COMPILE_PATH}` : SWIFT_COMPILE_PATH;
|
|
1586
|
-
return async (work) => {
|
|
1587
|
-
let response;
|
|
1588
|
-
try {
|
|
1589
|
-
response = await fetch(url, {
|
|
1590
|
-
method: "POST",
|
|
1591
|
-
headers: { "content-type": "application/json" },
|
|
1592
|
-
body: JSON.stringify({ ...work, token: assetReadToken })
|
|
1593
|
-
});
|
|
1594
|
-
} catch (error) {
|
|
1595
|
-
throw new Error(
|
|
1596
|
-
`contrast-bundler: fetch failed for ${url} while compiling ${work.entry}: ${error instanceof Error ? error.message : String(error)}`,
|
|
1597
|
-
{ cause: error }
|
|
1598
|
-
);
|
|
1599
|
-
}
|
|
1600
|
-
if (!response.ok) {
|
|
1601
|
-
const detail = (await response.text()).trim();
|
|
1602
|
-
throw new Error(
|
|
1603
|
-
`contrast-bundler: the swift compile for ${work.entry} answered ${response.status}${detail ? `: ${detail}` : ""}`
|
|
1604
|
-
);
|
|
1605
|
-
}
|
|
1606
|
-
return await response.json();
|
|
1607
|
-
};
|
|
1608
|
-
}
|
|
1609
|
-
function resolveImageUrls(urls, origin) {
|
|
1610
|
-
const resolved = {};
|
|
1611
|
-
for (const [name, url] of Object.entries(urls)) {
|
|
1612
|
-
resolved[name] = new URL(url, origin).href;
|
|
1613
|
-
}
|
|
1614
|
-
return resolved;
|
|
1615
|
-
}
|
|
1616
|
-
async function compileSwiftProject(submit, work, origin) {
|
|
1617
|
-
while (true) {
|
|
1618
|
-
const outcome = await submit(work);
|
|
1619
|
-
switch (outcome.status) {
|
|
1620
|
-
case "published":
|
|
1621
|
-
return {
|
|
1622
|
-
url: new URL(outcome.artifactUrl, origin).href,
|
|
1623
|
-
hash: outcome.hash,
|
|
1624
|
-
...outcome.imageUrls === void 0 ? {} : { imageUrls: resolveImageUrls(outcome.imageUrls, origin) }
|
|
1625
|
-
};
|
|
1626
|
-
case "compiling":
|
|
1627
|
-
await new Promise((resolve2) => setTimeout(resolve2, POLL_INTERVAL_MS));
|
|
1628
|
-
continue;
|
|
1629
|
-
case "refused":
|
|
1630
|
-
case "failed":
|
|
1631
|
-
throw new Error(
|
|
1632
|
-
`contrast-bundler: the swift sources for ${work.entry} cannot be compiled: ${outcome.detail}`
|
|
1633
|
-
);
|
|
1634
|
-
}
|
|
1635
|
-
}
|
|
1636
|
-
}
|
|
1637
|
-
|
|
1638
|
-
// src/rolldown-plugin-swift.ts
|
|
1639
|
-
var VIRTUAL_PREFIX2 = "\0peach-swift-remote:";
|
|
1640
|
-
var projects2 = /* @__PURE__ */ new Map();
|
|
1641
|
-
function projectFor2(packagePath) {
|
|
1642
|
-
const existing = projects2.get(packagePath);
|
|
1643
|
-
if (existing) return existing;
|
|
1644
|
-
const created = { packagePath, address: null };
|
|
1645
|
-
projects2.set(packagePath, created);
|
|
1646
|
-
return created;
|
|
1647
|
-
}
|
|
1648
|
-
function packageFiles(root) {
|
|
1649
|
-
const found = [];
|
|
1650
|
-
const walk = (dir) => {
|
|
1651
|
-
for (const entry of import_node_fs5.default.readdirSync(dir, { withFileTypes: true })) {
|
|
1652
|
-
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === ".build")
|
|
1653
|
-
continue;
|
|
1654
|
-
const full = import_node_path6.default.join(dir, entry.name);
|
|
1655
|
-
if (entry.isDirectory()) {
|
|
1656
|
-
if (full !== root && import_node_fs5.default.existsSync(import_node_path6.default.join(full, "Package.swift"))) continue;
|
|
1657
|
-
walk(full);
|
|
1658
|
-
} else {
|
|
1659
|
-
found.push(import_node_path6.default.relative(root, full).split(import_node_path6.default.sep).join(import_node_path6.default.posix.sep));
|
|
1660
|
-
}
|
|
1661
|
-
}
|
|
1662
|
-
};
|
|
1663
|
-
walk(root);
|
|
1664
|
-
return found;
|
|
1665
|
-
}
|
|
1666
|
-
function sourceFiles2(packagePath) {
|
|
1667
|
-
const files = {};
|
|
1668
|
-
for (const relative2 of packageFiles(packagePath)) {
|
|
1669
|
-
if (!relative2.endsWith(".swift")) continue;
|
|
1670
|
-
files[relative2] = import_node_fs5.default.readFileSync(
|
|
1671
|
-
import_node_path6.default.join(packagePath, ...relative2.split("/")),
|
|
1672
|
-
"utf8"
|
|
1673
|
-
);
|
|
1674
|
-
}
|
|
1675
|
-
return files;
|
|
1676
|
-
}
|
|
1677
|
-
function bundlePack(packagePath) {
|
|
1678
|
-
const relative2 = packageFiles(packagePath);
|
|
1679
|
-
const disk = (file) => import_node_path6.default.join(packagePath, ...file.split("/"));
|
|
1680
|
-
const resources = {};
|
|
1681
|
-
const watched = [];
|
|
1682
|
-
for (const { base, file } of enumerateBundleJson(relative2)) {
|
|
1683
|
-
resources[base] = import_node_fs5.default.readFileSync(disk(file)).toString("base64");
|
|
1684
|
-
watched.push(file);
|
|
1685
|
-
}
|
|
1686
|
-
const images = {};
|
|
1687
|
-
const byRelative = new Map(relative2.map((file) => [file, disk(file)]));
|
|
1688
|
-
for (const { name, file } of enumerateBundleImages(relative2, (candidate) => {
|
|
1689
|
-
const absolute = byRelative.get(candidate);
|
|
1690
|
-
if (!absolute || import_node_path6.default.basename(absolute) !== "Contents.json") return null;
|
|
1691
|
-
try {
|
|
1692
|
-
return import_node_fs5.default.readFileSync(absolute, "utf8");
|
|
1693
|
-
} catch {
|
|
1694
|
-
return null;
|
|
1695
|
-
}
|
|
1696
|
-
})) {
|
|
1697
|
-
const absolute = byRelative.get(file);
|
|
1698
|
-
if (!absolute) continue;
|
|
1699
|
-
images[name] = {
|
|
1700
|
-
file: import_node_path6.default.posix.basename(file),
|
|
1701
|
-
data: import_node_fs5.default.readFileSync(absolute).toString("base64")
|
|
1702
|
-
};
|
|
1703
|
-
watched.push(file);
|
|
1704
|
-
}
|
|
1705
|
-
return { resources, images, watched };
|
|
1706
|
-
}
|
|
1707
|
-
function packageFor2(file, stop) {
|
|
1708
|
-
let dir = import_node_path6.default.dirname(file);
|
|
1709
|
-
for (; ; ) {
|
|
1710
|
-
if (import_node_fs5.default.existsSync(import_node_path6.default.join(dir, "Package.swift"))) return dir;
|
|
1711
|
-
if (stop !== void 0 && dir === stop || import_node_path6.default.dirname(dir) === dir) break;
|
|
1712
|
-
dir = import_node_path6.default.dirname(dir);
|
|
1713
|
-
}
|
|
1714
|
-
throw new Error(
|
|
1715
|
-
`no Package.swift above ${file}; a .swift import needs a swiftpm package like the one in packages/sootsim-swift/example`
|
|
1716
|
-
);
|
|
1717
|
-
}
|
|
1718
|
-
function swiftRemotePlugin(options) {
|
|
1719
|
-
const submit = httpSwiftCompileSubmit({
|
|
1720
|
-
assetReadToken: options.assetReadToken,
|
|
1721
|
-
endpoint: options.endpoint
|
|
1722
|
-
});
|
|
1723
|
-
if (!submit) {
|
|
1724
|
-
throw new Error(
|
|
1725
|
-
"swiftRemotePlugin needs an assetReadToken: a build without a compile credential cannot compile .swift sources"
|
|
1726
|
-
);
|
|
1727
|
-
}
|
|
1728
|
-
return {
|
|
1729
|
-
name: "peach-swift-remote",
|
|
1730
|
-
enforce: "pre",
|
|
1731
|
-
async resolveId(source, importer) {
|
|
1732
|
-
if (source.startsWith(VIRTUAL_PREFIX2)) return source;
|
|
1733
|
-
if (!source.endsWith(".swift")) return null;
|
|
1734
|
-
const resolved = await this.resolve(source, importer, { skipSelf: true });
|
|
1735
|
-
if (!resolved) throw new Error(`cannot resolve swift source ${source}`);
|
|
1736
|
-
return VIRTUAL_PREFIX2 + resolved.id;
|
|
1737
|
-
},
|
|
1738
|
-
async load(id) {
|
|
1739
|
-
if (!id.startsWith(VIRTUAL_PREFIX2)) return null;
|
|
1740
|
-
const file = id.slice(VIRTUAL_PREFIX2.length);
|
|
1741
|
-
if (!import_node_fs5.default.existsSync(file)) throw new Error(`swift source ${file} no longer exists`);
|
|
1742
|
-
const packagePath = options.packagePath ?? packageFor2(file);
|
|
1743
|
-
const project = projectFor2(packagePath);
|
|
1744
|
-
const files = sourceFiles2(packagePath);
|
|
1745
|
-
const entry = import_node_path6.default.relative(packagePath, file).split(import_node_path6.default.sep).join(import_node_path6.default.posix.sep);
|
|
1746
|
-
for (const source of Object.keys(files)) {
|
|
1747
|
-
this.addWatchFile(import_node_path6.default.join(packagePath, ...source.split("/")));
|
|
1748
|
-
}
|
|
1749
|
-
const pack = bundlePack(packagePath);
|
|
1750
|
-
for (const watched of pack.watched) {
|
|
1751
|
-
this.addWatchFile(import_node_path6.default.join(packagePath, ...watched.split("/")));
|
|
1752
|
-
}
|
|
1753
|
-
try {
|
|
1754
|
-
project.address = await compileSwiftProject(
|
|
1755
|
-
submit,
|
|
1756
|
-
{ files, resources: pack.resources, images: pack.images, entry },
|
|
1757
|
-
options.endpoint
|
|
1758
|
-
);
|
|
1759
|
-
} catch (error) {
|
|
1760
|
-
if (!project.address) throw error;
|
|
1761
|
-
this.warn(error instanceof Error ? error.message : String(error));
|
|
1762
|
-
}
|
|
1763
|
-
const address = project.address;
|
|
1764
|
-
return swiftEntryModuleEsm({
|
|
1765
|
-
url: address.url,
|
|
1766
|
-
hash: address.hash,
|
|
1767
|
-
rootId: entryRootId(packagePath, file),
|
|
1768
|
-
resources: address.imageUrls ?? {},
|
|
1769
|
-
bundleFiles: pack.resources
|
|
1770
|
-
});
|
|
1771
|
-
}
|
|
1772
|
-
};
|
|
1773
|
-
}
|
|
1774
|
-
|
|
1775
764
|
// src/vite-plugin-one.ts
|
|
765
|
+
var SWIFT_HMR_PATH = "/__peach/swift-hmr";
|
|
766
|
+
var SWIFT_ROUTE_PREFIX = "/__peach/swift";
|
|
767
|
+
var swiftHost;
|
|
768
|
+
var loadSwiftHost = () => swiftHost ??= import("peachsim/vite-swift");
|
|
769
|
+
var KOTLIN_ROUTE_PREFIX = "/__peach/kotlin";
|
|
770
|
+
var kotlinHost;
|
|
771
|
+
var loadKotlinHost = () => kotlinHost ??= import("peachsim/vite-kotlin");
|
|
1776
772
|
function rnxPlugin(options = {}) {
|
|
1777
773
|
const prefix = options.prefix || "/__soot";
|
|
1778
774
|
return {
|
|
@@ -1790,21 +786,196 @@ function rnxPlugin(options = {}) {
|
|
|
1790
786
|
},
|
|
1791
787
|
configureServer(server) {
|
|
1792
788
|
if (options.enabled === false) return;
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
const
|
|
789
|
+
let swiftPackages;
|
|
790
|
+
let swiftModuleRoot;
|
|
791
|
+
const moduleRootFor = () => {
|
|
792
|
+
if (swiftModuleRoot === void 0) {
|
|
793
|
+
const peachsimPackage = (0, import_node_module.createRequire)(
|
|
794
|
+
import_path2.default.join(server.config.root, "package.json")
|
|
795
|
+
).resolve("peachsim/package.json");
|
|
796
|
+
const moduleRoot = import_path2.default.resolve(
|
|
797
|
+
import_path2.default.dirname(peachsimPackage),
|
|
798
|
+
"../sootsim-swift"
|
|
799
|
+
);
|
|
800
|
+
swiftModuleRoot = import_fs2.default.existsSync(import_path2.default.join(moduleRoot, "toolchain.json")) ? moduleRoot : null;
|
|
801
|
+
}
|
|
802
|
+
return swiftModuleRoot ?? void 0;
|
|
803
|
+
};
|
|
804
|
+
const activeSwiftPackages = /* @__PURE__ */ new Set();
|
|
805
|
+
const packageMap = () => {
|
|
806
|
+
swiftPackages ??= (0, import_vxrn.swiftPackageDirectories)(server.config.root);
|
|
807
|
+
return swiftPackages;
|
|
808
|
+
};
|
|
809
|
+
const wsOptions = server.config.server.ws;
|
|
810
|
+
const httpServer = server.httpServer ?? (wsOptions && typeof wsOptions === "object" ? wsOptions.server : void 0);
|
|
811
|
+
const swiftSockets = httpServer ? new import_ws.WebSocketServer({ noServer: true }) : void 0;
|
|
812
|
+
const hmrPath = SWIFT_HMR_PATH;
|
|
1796
813
|
const configuredPort = server.config.server.port || 8081;
|
|
1797
814
|
const listeningPort = () => {
|
|
1798
815
|
const address = server.httpServer?.address();
|
|
1799
816
|
return address && typeof address === "object" ? address.port : configuredPort;
|
|
1800
817
|
};
|
|
1801
|
-
const
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
818
|
+
const devOrigin = () => `http://localhost:${listeningPort()}`;
|
|
819
|
+
const sendSwiftChange = (change) => {
|
|
820
|
+
const message = JSON.stringify(change);
|
|
821
|
+
for (const client of swiftSockets?.clients ?? []) {
|
|
822
|
+
if (client.readyState === import_ws.WebSocket.OPEN) client.send(message);
|
|
823
|
+
}
|
|
824
|
+
};
|
|
825
|
+
if (httpServer && swiftSockets) {
|
|
826
|
+
httpServer.on("upgrade", (req, socket, head) => {
|
|
827
|
+
if (new URL(req.url ?? "/", "http://localhost").pathname !== SWIFT_HMR_PATH)
|
|
828
|
+
return;
|
|
829
|
+
swiftSockets.handleUpgrade(req, socket, head, (client) => {
|
|
830
|
+
swiftSockets.emit("connection", client, req);
|
|
831
|
+
});
|
|
832
|
+
});
|
|
833
|
+
httpServer.once("close", () => {
|
|
834
|
+
for (const client of swiftSockets.clients) client.terminate();
|
|
835
|
+
swiftSockets.close();
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
server.watcher.on("add", (file) => {
|
|
839
|
+
if (import_path2.default.basename(file) === "Package.swift") swiftPackages = void 0;
|
|
840
|
+
});
|
|
841
|
+
server.watcher.on("unlink", (file) => {
|
|
842
|
+
if (import_path2.default.basename(file) === "Package.swift") swiftPackages = void 0;
|
|
843
|
+
});
|
|
844
|
+
let kotlinModuleRoot;
|
|
845
|
+
server.watcher.on("all", (_event, file) => {
|
|
846
|
+
if (!kotlinModuleRoot) return;
|
|
847
|
+
if (file.endsWith(".kt") || file.startsWith(`${kotlinModuleRoot}${import_path2.default.sep}`))
|
|
848
|
+
sendSwiftChange({ type: "kotlin", packageName: "kotlin" });
|
|
849
|
+
});
|
|
850
|
+
server.middlewares.use((req, res, next) => {
|
|
851
|
+
const pathname = (req.url ?? "").split("?")[0];
|
|
852
|
+
if (!pathname.startsWith(KOTLIN_ROUTE_PREFIX)) return next();
|
|
853
|
+
loadKotlinHost().then(async (host) => {
|
|
854
|
+
if (host.serveKotlinArtifact(pathname, res)) return;
|
|
855
|
+
if (pathname !== "/__peach/kotlin-package") return next();
|
|
856
|
+
if (!kotlinModuleRoot) {
|
|
857
|
+
const moduleRoot = import_path2.default.join(
|
|
858
|
+
import_path2.default.dirname(
|
|
859
|
+
(0, import_node_module.createRequire)(import_path2.default.join(server.config.root, "package.json")).resolve(
|
|
860
|
+
"peachsim/package.json"
|
|
861
|
+
)
|
|
862
|
+
),
|
|
863
|
+
"kotlin"
|
|
864
|
+
);
|
|
865
|
+
kotlinModuleRoot = moduleRoot;
|
|
866
|
+
server.watcher.add(import_path2.default.join(moduleRoot, "Sources"));
|
|
867
|
+
}
|
|
868
|
+
try {
|
|
869
|
+
const artifact = await host.kotlinArtifact(
|
|
870
|
+
server.config.root,
|
|
871
|
+
kotlinModuleRoot,
|
|
872
|
+
devOrigin()
|
|
873
|
+
);
|
|
874
|
+
res.setHeader("access-control-allow-origin", "*");
|
|
875
|
+
res.setHeader("content-type", "application/json");
|
|
876
|
+
res.end(JSON.stringify({ ...artifact, hmrPath }));
|
|
877
|
+
} catch (error) {
|
|
878
|
+
res.statusCode = 500;
|
|
879
|
+
res.setHeader("access-control-allow-origin", "*");
|
|
880
|
+
res.end(error instanceof Error ? error.message : String(error));
|
|
881
|
+
}
|
|
882
|
+
}).catch(next);
|
|
883
|
+
});
|
|
884
|
+
server.watcher.on("change", (file) => {
|
|
885
|
+
if (activeSwiftPackages.size === 0) return;
|
|
886
|
+
const moduleRoot = moduleRootFor();
|
|
887
|
+
let packages;
|
|
888
|
+
try {
|
|
889
|
+
packages = packageMap();
|
|
890
|
+
} catch (error) {
|
|
891
|
+
for (const packageName of activeSwiftPackages) {
|
|
892
|
+
sendSwiftChange({
|
|
893
|
+
type: "error",
|
|
894
|
+
packageName,
|
|
895
|
+
message: error instanceof Error ? error.message : String(error)
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
for (const packageName of activeSwiftPackages) {
|
|
901
|
+
const packagePath = packages.get(packageName);
|
|
902
|
+
if (!packagePath) continue;
|
|
903
|
+
if (!file.startsWith(`${packagePath}${import_path2.default.sep}`) && !(moduleRoot && file.startsWith(`${moduleRoot}${import_path2.default.sep}`)))
|
|
904
|
+
continue;
|
|
905
|
+
void loadSwiftHost().then(
|
|
906
|
+
(host) => host.swiftPackageMetadata(
|
|
907
|
+
packagePath,
|
|
908
|
+
packageName,
|
|
909
|
+
moduleRoot,
|
|
910
|
+
devOrigin()
|
|
911
|
+
)
|
|
912
|
+
).then((metadata) => {
|
|
913
|
+
sendSwiftChange({
|
|
914
|
+
type: "package",
|
|
915
|
+
packageName,
|
|
916
|
+
metadata: { ...metadata, hmrPath }
|
|
917
|
+
});
|
|
918
|
+
}).catch((error) => {
|
|
919
|
+
sendSwiftChange({
|
|
920
|
+
type: "error",
|
|
921
|
+
packageName,
|
|
922
|
+
message: error instanceof Error ? error.message : String(error)
|
|
923
|
+
});
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
});
|
|
927
|
+
server.middlewares.use((req, res, next) => {
|
|
928
|
+
const pathname = (req.url ?? "").split("?")[0];
|
|
929
|
+
if (!pathname.startsWith(SWIFT_ROUTE_PREFIX)) return next();
|
|
930
|
+
loadSwiftHost().then((host) => {
|
|
931
|
+
if (host.serveSwiftPackageAsset(pathname, res)) return;
|
|
932
|
+
const prefix2 = "/__peach/swift-package/";
|
|
933
|
+
if (!pathname.startsWith(prefix2)) return next();
|
|
934
|
+
if (!swiftSockets) {
|
|
935
|
+
res.statusCode = 501;
|
|
936
|
+
res.end("Peach Swift hot reload requires a Vite HTTP server");
|
|
937
|
+
return;
|
|
938
|
+
}
|
|
939
|
+
const packageName = pathname.slice(prefix2.length);
|
|
940
|
+
let packagePath;
|
|
941
|
+
try {
|
|
942
|
+
packagePath = packageMap().get(packageName);
|
|
943
|
+
} catch (error) {
|
|
944
|
+
res.statusCode = 500;
|
|
945
|
+
res.end(error instanceof Error ? error.message : String(error));
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
if (!packagePath) {
|
|
949
|
+
res.statusCode = 404;
|
|
950
|
+
res.end(`swift package ${packageName} was not found`);
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
const moduleRoot = moduleRootFor();
|
|
954
|
+
activeSwiftPackages.add(packageName);
|
|
955
|
+
server.watcher.add(host.swiftPackageWatchFiles(packagePath, moduleRoot));
|
|
956
|
+
void host.swiftPackageMetadata(packagePath, packageName, moduleRoot, devOrigin()).then((metadata) => {
|
|
957
|
+
res.setHeader("access-control-allow-origin", "*");
|
|
958
|
+
res.setHeader("content-type", "application/json");
|
|
959
|
+
res.end(JSON.stringify({ ...metadata, hmrPath }));
|
|
960
|
+
}).catch((error) => {
|
|
961
|
+
res.statusCode = 500;
|
|
962
|
+
res.end(error instanceof Error ? error.message : String(error));
|
|
963
|
+
});
|
|
964
|
+
}).catch(next);
|
|
965
|
+
});
|
|
966
|
+
const bundleUrl = options.bundleUrl || "/node_modules/one/metro-entry.bundle?platform=ios&dev=true&minify=false";
|
|
967
|
+
const appName = resolveRnxDesktopAppName(options.open, server.config.root);
|
|
968
|
+
const replacementToken = (0, import_node_crypto2.randomUUID)();
|
|
969
|
+
const bundleForPort = (port2) => {
|
|
970
|
+
const fullBundleUrl = bundleUrl.startsWith("http") ? bundleUrl : `http://localhost:${port2}${bundleUrl.startsWith("/") ? "" : "/"}${bundleUrl}`;
|
|
971
|
+
return tagRnxBundleForPlugin(
|
|
972
|
+
fullBundleUrl,
|
|
973
|
+
`http://localhost:${port2}`,
|
|
974
|
+
replacementToken,
|
|
975
|
+
server.config.root,
|
|
976
|
+
appName
|
|
977
|
+
);
|
|
978
|
+
};
|
|
1808
979
|
const buildShellHtml = (runtimeRoot) => {
|
|
1809
980
|
const html = import_fs2.default.readFileSync(import_path2.default.join(runtimeRoot, "index.html"), "utf8");
|
|
1810
981
|
const lock = readDaemonLockfile();
|
|
@@ -1918,7 +1089,5 @@ var vite_plugin_one_default = rnxPlugin;
|
|
|
1918
1089
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1919
1090
|
0 && (module.exports = {
|
|
1920
1091
|
rnxPlugin,
|
|
1921
|
-
sootsimPlugin
|
|
1922
|
-
swiftPlugin,
|
|
1923
|
-
swiftRemotePlugin
|
|
1092
|
+
sootsimPlugin
|
|
1924
1093
|
});
|