peachsim 0.1.664 → 0.1.666
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/app-fonts.ts +6 -3
- package/cli/commands/control.ts +18 -2
- package/cli/commands/inspect/core.ts +19 -6
- package/cli/commands/inspect/settling.ts +1 -5
- package/detox/index.ts +1 -1
- package/detox/navigation.ts +1 -0
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +2 -2
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +2191 -335
- 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 +7 -7
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +7 -7
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/kotlin-host.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +7 -7
- package/dist-lib/native-app-identity.cjs +1 -1
- package/dist-lib/native-app-identity.mjs +1 -1
- package/dist-lib/plist.cjs +1 -1
- package/dist-lib/plist.mjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +13 -9
- package/dist-lib/sdk.mjs +13 -9
- package/dist-lib/skills.cjs +2777 -948
- package/dist-lib/swift-compile.cjs +1 -1
- package/dist-lib/swift-compile.mjs +1 -1
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +1 -1
- package/dist-lib/swift-submit.mjs +1 -1
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite-swift.cjs +1 -1
- package/dist-lib/vite.cjs +7 -7
- package/kotlin/ComposeSources/PeachComposeHost.kt +6 -3
- package/kotlin/fixtures/kotlin-app-variants/Overlays.kt +56 -0
- package/kotlin/fixtures/kotlin-app-variants/Scroll.kt +63 -0
- package/kotlin/fixtures/kotlin-app-variants/Sheet.kt +43 -0
- package/kotlin/fixtures/kotlin-app-variants/Tabs.kt +47 -0
- package/kotlin/fixtures/kotlin-app-variants/Widgets.kt +13 -2
- package/package.json +2 -2
- package/skills/peach-setup/SKILL.md +1 -1
- package/src/assetCatalogContract.ts +23 -0
- package/src/expo-swift-host.ts +248 -0
- package/src/host/bridge-host.ts +19 -0
- package/src/skills/builtin/a11y-review.ts +3 -1
- package/src/skills/builtin/perf-profile.ts +5 -3
- package/src/vite-plugin.ts +3 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.666 | (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;
|
|
@@ -49,10 +49,27 @@ function buildBrowserAssetProxyUrl(targetUrl) {
|
|
|
49
49
|
const proxyPath = isLoopbackHost(new URL(targetUrl).hostname) ? "/__bundle-proxy" : "/__fetch-proxy";
|
|
50
50
|
return `${proxyPath}?url=${encodeURIComponent(targetUrl)}`;
|
|
51
51
|
}
|
|
52
|
-
|
|
52
|
+
function isContrastBackendHost(hostname) {
|
|
53
|
+
const normalized = normalizeHostname(hostname);
|
|
54
|
+
return isLoopbackHost(normalized) || normalized === "contrast.dev" || normalized.endsWith(".contrast.dev");
|
|
55
|
+
}
|
|
56
|
+
function resolveContrastBackendOrigin(currentOrigin) {
|
|
57
|
+
const origin = currentOrigin?.trim();
|
|
58
|
+
if (!origin) return DEFAULT_CONTRAST_BACKEND_ORIGIN;
|
|
59
|
+
try {
|
|
60
|
+
const parsed = new URL(origin);
|
|
61
|
+
if (isLoopbackHost(parsed.hostname) || isContrastBackendHost(parsed.hostname)) {
|
|
62
|
+
return parsed.origin;
|
|
63
|
+
}
|
|
64
|
+
} catch {
|
|
65
|
+
}
|
|
66
|
+
return DEFAULT_CONTRAST_BACKEND_ORIGIN;
|
|
67
|
+
}
|
|
68
|
+
var DEFAULT_CONTRAST_BACKEND_ORIGIN, LOOPBACK_PROBE_HOSTNAMES;
|
|
53
69
|
var init_backend_origin = __esm({
|
|
54
70
|
"src/backend-origin.ts"() {
|
|
55
71
|
"use strict";
|
|
72
|
+
DEFAULT_CONTRAST_BACKEND_ORIGIN = "https://contrast.dev";
|
|
56
73
|
LOOPBACK_PROBE_HOSTNAMES = ["127.0.0.1", "::1"];
|
|
57
74
|
}
|
|
58
75
|
});
|
|
@@ -181,8 +198,8 @@ function configFilePath() {
|
|
|
181
198
|
}
|
|
182
199
|
function readSharedConfig() {
|
|
183
200
|
try {
|
|
184
|
-
const
|
|
185
|
-
const parsed = JSON.parse(
|
|
201
|
+
const raw2 = import_node_fs3.default.readFileSync(configFilePath(), "utf8");
|
|
202
|
+
const parsed = JSON.parse(raw2);
|
|
186
203
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
187
204
|
} catch {
|
|
188
205
|
return {};
|
|
@@ -250,8 +267,8 @@ function readDaemonLockfile() {
|
|
|
250
267
|
try {
|
|
251
268
|
const buf = Buffer.alloc(DAEMON_LOCKFILE_MAX_BYTES);
|
|
252
269
|
const bytesRead = import_node_fs3.default.readSync(fd, buf, 0, DAEMON_LOCKFILE_MAX_BYTES, 0);
|
|
253
|
-
const
|
|
254
|
-
const parsed = JSON.parse(
|
|
270
|
+
const raw2 = buf.subarray(0, bytesRead).toString("utf8");
|
|
271
|
+
const parsed = JSON.parse(raw2);
|
|
255
272
|
if (parsed && parsed.schema === 1 && typeof parsed.pid === "number" && typeof parsed.bridgePort === "number" && typeof parsed.runtimePort === "number" && typeof parsed.startedAt === "number" && typeof parsed.heartbeatAt === "number" && (parsed.servedRuntimes === void 0 || Array.isArray(parsed.servedRuntimes) && parsed.servedRuntimes.every((version) => typeof version === "string"))) {
|
|
256
273
|
return parsed;
|
|
257
274
|
}
|
|
@@ -263,9 +280,9 @@ function readDaemonLockfile() {
|
|
|
263
280
|
return null;
|
|
264
281
|
}
|
|
265
282
|
}
|
|
266
|
-
function parseDevBridgeLockfile(
|
|
283
|
+
function parseDevBridgeLockfile(raw2) {
|
|
267
284
|
try {
|
|
268
|
-
const parsed = JSON.parse(
|
|
285
|
+
const parsed = JSON.parse(raw2);
|
|
269
286
|
if (parsed && parsed.schema === 1 && parsed.source === "vite-dev" && typeof parsed.pid === "number" && typeof parsed.bridgePort === "number" && typeof parsed.runtimePort === "number" && typeof parsed.cwd === "string" && typeof parsed.startedAt === "number" && typeof parsed.heartbeatAt === "number" && (parsed.shellPort === void 0 || typeof parsed.shellPort === "number") && (parsed.servedRuntimes === void 0 || Array.isArray(parsed.servedRuntimes) && parsed.servedRuntimes.every((version) => typeof version === "string"))) {
|
|
270
287
|
return parsed;
|
|
271
288
|
}
|
|
@@ -346,9 +363,9 @@ function createDaemonLockfileExclusive(data) {
|
|
|
346
363
|
function daemonClaimPath() {
|
|
347
364
|
return `${daemonLockfilePath()}.claim`;
|
|
348
365
|
}
|
|
349
|
-
function parseDaemonClaim(
|
|
366
|
+
function parseDaemonClaim(raw2) {
|
|
350
367
|
try {
|
|
351
|
-
const value = JSON.parse(
|
|
368
|
+
const value = JSON.parse(raw2);
|
|
352
369
|
if (value !== null && typeof value === "object" && typeof Reflect.get(value, "pid") === "number" && typeof Reflect.get(value, "startedAt") === "number" && typeof Reflect.get(value, "createdAt") === "number") {
|
|
353
370
|
return {
|
|
354
371
|
pid: Reflect.get(value, "pid"),
|
|
@@ -502,14 +519,14 @@ function sharedDesktopAuthAccounts(user) {
|
|
|
502
519
|
function getBaseDir() {
|
|
503
520
|
const explicit = process.env[SESSION_FILE_ENV];
|
|
504
521
|
if (explicit?.trim()) {
|
|
505
|
-
return (0,
|
|
522
|
+
return (0, import_node_path6.dirname)((0, import_node_path6.resolve)(explicit));
|
|
506
523
|
}
|
|
507
524
|
return electronUserDataDir();
|
|
508
525
|
}
|
|
509
526
|
function getSharedDesktopAuthFilePath() {
|
|
510
527
|
const explicit = process.env[SESSION_FILE_ENV];
|
|
511
|
-
if (explicit?.trim()) return (0,
|
|
512
|
-
return (0,
|
|
528
|
+
if (explicit?.trim()) return (0, import_node_path6.resolve)(explicit);
|
|
529
|
+
return (0, import_node_path6.join)(getBaseDir(), "desktop-auth.json");
|
|
513
530
|
}
|
|
514
531
|
function normalizeUser(input) {
|
|
515
532
|
if (!input || typeof input !== "object") return null;
|
|
@@ -559,26 +576,26 @@ function normalizeSession(input) {
|
|
|
559
576
|
}
|
|
560
577
|
function readSharedDesktopAuthSession() {
|
|
561
578
|
const filepath = getSharedDesktopAuthFilePath();
|
|
562
|
-
if (!(0,
|
|
579
|
+
if (!(0, import_node_fs6.existsSync)(filepath)) return null;
|
|
563
580
|
try {
|
|
564
|
-
const parsed = JSON.parse((0,
|
|
581
|
+
const parsed = JSON.parse((0, import_node_fs6.readFileSync)(filepath, "utf8"));
|
|
565
582
|
const normalized = normalizeSession(parsed);
|
|
566
583
|
if (!normalized) {
|
|
567
|
-
(0,
|
|
584
|
+
(0, import_node_fs6.rmSync)(filepath, { force: true });
|
|
568
585
|
return null;
|
|
569
586
|
}
|
|
570
587
|
return normalized;
|
|
571
588
|
} catch {
|
|
572
|
-
(0,
|
|
589
|
+
(0, import_node_fs6.rmSync)(filepath, { force: true });
|
|
573
590
|
return null;
|
|
574
591
|
}
|
|
575
592
|
}
|
|
576
|
-
var
|
|
593
|
+
var import_node_fs6, import_node_path6, SESSION_VERSION, SESSION_FILE_ENV, DEFAULT_ORIGIN;
|
|
577
594
|
var init_shared_session = __esm({
|
|
578
595
|
"src/auth/shared-session.ts"() {
|
|
579
596
|
"use strict";
|
|
580
|
-
|
|
581
|
-
|
|
597
|
+
import_node_fs6 = require("node:fs");
|
|
598
|
+
import_node_path6 = require("node:path");
|
|
582
599
|
init_home_paths();
|
|
583
600
|
SESSION_VERSION = 1;
|
|
584
601
|
SESSION_FILE_ENV = "SOOTSIM_SHARED_AUTH_FILE";
|
|
@@ -726,20 +743,20 @@ var init_auth = __esm({
|
|
|
726
743
|
});
|
|
727
744
|
|
|
728
745
|
// ../peach-engine/src/preview/storage-snapshot-contract.ts
|
|
729
|
-
function
|
|
746
|
+
function isRecord4(value) {
|
|
730
747
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
731
748
|
}
|
|
732
749
|
function isStorageSnapshotEntry(value) {
|
|
733
|
-
return
|
|
750
|
+
return isRecord4(value) && typeof value.key === "string" && typeof value.value === "string";
|
|
734
751
|
}
|
|
735
752
|
function isSecureStoreSnapshotEntry(value) {
|
|
736
|
-
return
|
|
753
|
+
return isRecord4(value) && typeof value.key === "string" && typeof value.value === "string" && (value.keychainService == null || typeof value.keychainService === "string") && (value.accessGroup == null || typeof value.accessGroup === "string") && (value.requireAuthentication == null || typeof value.requireAuthentication === "boolean");
|
|
737
754
|
}
|
|
738
755
|
function isPreviewRouteSnapshot(value) {
|
|
739
|
-
return
|
|
756
|
+
return isRecord4(value) && typeof value.currentPath === "string" && (value.routeNames == null || Array.isArray(value.routeNames) && value.routeNames.every((routeName) => typeof routeName === "string"));
|
|
740
757
|
}
|
|
741
758
|
function isSerializedIndexedDBValue(value) {
|
|
742
|
-
if (!
|
|
759
|
+
if (!isRecord4(value) || typeof value.type !== "string") return false;
|
|
743
760
|
switch (value.type) {
|
|
744
761
|
case "array":
|
|
745
762
|
return Array.isArray(value.value) && value.value.every(isSerializedIndexedDBValue);
|
|
@@ -749,7 +766,7 @@ function isSerializedIndexedDBValue(value) {
|
|
|
749
766
|
case "null":
|
|
750
767
|
return value.value === null;
|
|
751
768
|
case "object":
|
|
752
|
-
return
|
|
769
|
+
return isRecord4(value.value) && Object.values(value.value).every(isSerializedIndexedDBValue);
|
|
753
770
|
case "primitive":
|
|
754
771
|
return typeof value.value === "boolean" || typeof value.value === "number" || typeof value.value === "string";
|
|
755
772
|
default:
|
|
@@ -760,16 +777,16 @@ function isIndexedDBSnapshotKind(value) {
|
|
|
760
777
|
return value === "bedrock-memfs" || value === "blob-util-fs" || value === "react-native-keychain" || value === "sootsim-system-permissions";
|
|
761
778
|
}
|
|
762
779
|
function isIndexedDBSnapshotEntry(value) {
|
|
763
|
-
return
|
|
780
|
+
return isRecord4(value) && typeof value.key === "string" && isSerializedIndexedDBValue(value.value);
|
|
764
781
|
}
|
|
765
782
|
function isIndexedDBStoreSnapshot(value) {
|
|
766
|
-
return
|
|
783
|
+
return isRecord4(value) && typeof value.name === "string" && Array.isArray(value.entries) && value.entries.every(isIndexedDBSnapshotEntry);
|
|
767
784
|
}
|
|
768
785
|
function isIndexedDBSnapshot(value) {
|
|
769
|
-
return
|
|
786
|
+
return isRecord4(value) && isIndexedDBSnapshotKind(value.kind) && Array.isArray(value.stores) && value.stores.every(isIndexedDBStoreSnapshot);
|
|
770
787
|
}
|
|
771
788
|
function isStorageSnapshot(value) {
|
|
772
|
-
return
|
|
789
|
+
return isRecord4(value) && Array.isArray(value.entries) && value.entries.every(isStorageSnapshotEntry) && (value.secureStore == null || Array.isArray(value.secureStore) && value.secureStore.every(isSecureStoreSnapshotEntry)) && (value.indexedDB == null || Array.isArray(value.indexedDB) && value.indexedDB.every(isIndexedDBSnapshot)) && (value.route == null || isPreviewRouteSnapshot(value.route));
|
|
773
790
|
}
|
|
774
791
|
var init_storage_snapshot_contract = __esm({
|
|
775
792
|
"../peach-engine/src/preview/storage-snapshot-contract.ts"() {
|
|
@@ -2383,8 +2400,8 @@ function metroIosAssetDestRelatives(httpServerLocation, filename) {
|
|
|
2383
2400
|
}
|
|
2384
2401
|
const out = [];
|
|
2385
2402
|
for (const dir of dirs) {
|
|
2386
|
-
const
|
|
2387
|
-
if (!out.includes(
|
|
2403
|
+
const path16 = `${dir}/${filename}`;
|
|
2404
|
+
if (!out.includes(path16)) out.push(path16);
|
|
2388
2405
|
}
|
|
2389
2406
|
if (!out.includes(filename)) out.push(filename);
|
|
2390
2407
|
return out;
|
|
@@ -2788,7 +2805,7 @@ async function buildRnxCloudArtifact(bundle, options = {}) {
|
|
|
2788
2805
|
unresolved: composed.unresolved
|
|
2789
2806
|
};
|
|
2790
2807
|
}
|
|
2791
|
-
const
|
|
2808
|
+
const assets2 = await assertSelfContainedMetroArtifactAssets(code);
|
|
2792
2809
|
const sourceEncoded = encodedAssetBytes(bundle);
|
|
2793
2810
|
const artifactEncoded = encodedAssetBytes(code);
|
|
2794
2811
|
const sourceBytes = Buffer.byteLength((0, import_metro_production_bundle.detachRNXMetroSourceMapUrl)(bundle).source, "utf8");
|
|
@@ -2808,7 +2825,7 @@ async function buildRnxCloudArtifact(bundle, options = {}) {
|
|
|
2808
2825
|
sourceBytes: sourceBytes - sourceEncoded,
|
|
2809
2826
|
minifiedBytes: artifactBytes - artifactEncoded
|
|
2810
2827
|
},
|
|
2811
|
-
assets: { ...
|
|
2828
|
+
assets: { ...assets2, encodedBytes: artifactEncoded },
|
|
2812
2829
|
debug: sourceMap ? { sourceMap: { id: sourceMap.id, bytes: sourceMap.bytes } } : null,
|
|
2813
2830
|
artifact: {
|
|
2814
2831
|
sha256: await sha256HexBytes(new TextEncoder().encode(code)),
|
|
@@ -3334,13 +3351,13 @@ function readFactoryStringLiterals(factory) {
|
|
|
3334
3351
|
return literals;
|
|
3335
3352
|
}
|
|
3336
3353
|
function normalizeFingerprintLiteral(literal) {
|
|
3337
|
-
const
|
|
3354
|
+
const path16 = literal.replaceAll("\\\\", "/").replaceAll("\\/", "/");
|
|
3338
3355
|
const nodeModulesMarker = "/node_modules/";
|
|
3339
|
-
const nodeModulesIndex =
|
|
3356
|
+
const nodeModulesIndex = path16.lastIndexOf(nodeModulesMarker);
|
|
3340
3357
|
if (nodeModulesIndex >= 0) {
|
|
3341
|
-
return `node_modules/${
|
|
3358
|
+
return `node_modules/${path16.slice(nodeModulesIndex + nodeModulesMarker.length)}`;
|
|
3342
3359
|
}
|
|
3343
|
-
if ((
|
|
3360
|
+
if ((path16.startsWith("/") || /^[A-Za-z]:\//.test(path16) || path16.startsWith("file:/")) && /\.[cm]?[jt]sx?(?::\d+(?::\d+)?)?$/.test(path16)) {
|
|
3344
3361
|
return null;
|
|
3345
3362
|
}
|
|
3346
3363
|
return literal;
|
|
@@ -3578,10 +3595,10 @@ function templateAssignment(template, embeddings) {
|
|
|
3578
3595
|
if (existingNode !== void 0 && existingNode !== nodeIndex) return null;
|
|
3579
3596
|
nodesByModuleId.set(moduleId, nodeIndex);
|
|
3580
3597
|
const node = template.nodes[nodeIndex];
|
|
3581
|
-
const
|
|
3598
|
+
const path16 = node.landmarkPath ?? `node_modules/${template.packageName}/__rnx_inferred__/${moduleId}.js`;
|
|
3582
3599
|
const existingPath = pathsByModuleId.get(moduleId);
|
|
3583
|
-
if (existingPath !== void 0 && existingPath !==
|
|
3584
|
-
pathsByModuleId.set(moduleId,
|
|
3600
|
+
if (existingPath !== void 0 && existingPath !== path16) return null;
|
|
3601
|
+
pathsByModuleId.set(moduleId, path16);
|
|
3585
3602
|
}
|
|
3586
3603
|
}
|
|
3587
3604
|
return {
|
|
@@ -3743,14 +3760,14 @@ async function inferMetroModuleIdentity(args) {
|
|
|
3743
3760
|
const packageClaims = claimsByPackage.values().next().value;
|
|
3744
3761
|
if (!packageClaims) continue;
|
|
3745
3762
|
const exactClaims = packageClaims.filter((assignment2) => {
|
|
3746
|
-
const
|
|
3747
|
-
return
|
|
3763
|
+
const path16 = assignment2.pathsByModuleId.get(moduleId);
|
|
3764
|
+
return path16 !== void 0 && !path16.includes("/__rnx_inferred__/");
|
|
3748
3765
|
});
|
|
3749
3766
|
const preferredClaims = exactClaims.length > 0 ? exactClaims : packageClaims;
|
|
3750
3767
|
const routes = new Set(
|
|
3751
3768
|
preferredClaims.flatMap((assignment2) => {
|
|
3752
|
-
const
|
|
3753
|
-
return
|
|
3769
|
+
const path16 = assignment2.pathsByModuleId.get(moduleId);
|
|
3770
|
+
return path16 ? [metroFingerprintModuleClaimRoute(assignment2.packageName, path16)] : [];
|
|
3754
3771
|
})
|
|
3755
3772
|
);
|
|
3756
3773
|
if (routes.size !== 1) continue;
|
|
@@ -3949,8 +3966,8 @@ function detectFramework(deps) {
|
|
|
3949
3966
|
return "unknown";
|
|
3950
3967
|
}
|
|
3951
3968
|
function detectProject(dir) {
|
|
3952
|
-
const pkgPath = (0,
|
|
3953
|
-
if (!(0,
|
|
3969
|
+
const pkgPath = (0, import_node_path20.join)(dir, "package.json");
|
|
3970
|
+
if (!(0, import_node_fs20.existsSync)(pkgPath)) return null;
|
|
3954
3971
|
const pkg = readProjectManifest(dir);
|
|
3955
3972
|
if (!pkg) return null;
|
|
3956
3973
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
@@ -3962,25 +3979,25 @@ function detectProject(dir) {
|
|
|
3962
3979
|
if (framework === "unknown") return null;
|
|
3963
3980
|
return {
|
|
3964
3981
|
dir,
|
|
3965
|
-
name: pkg.name || (0,
|
|
3982
|
+
name: pkg.name || (0, import_node_path20.basename)(dir),
|
|
3966
3983
|
framework,
|
|
3967
3984
|
// a config file is a config file whatever module system it declares. real
|
|
3968
3985
|
// apps write .cjs as often as .js, and missing one reads as "this project
|
|
3969
3986
|
// has no bundler config" and sends the user to create a second one.
|
|
3970
3987
|
hasViteConfig: CONFIG_EXTENSIONS.some(
|
|
3971
|
-
(ext) => (0,
|
|
3988
|
+
(ext) => (0, import_node_fs20.existsSync)((0, import_node_path20.join)(dir, `vite.config.${ext}`))
|
|
3972
3989
|
),
|
|
3973
3990
|
hasMetroConfig: CONFIG_EXTENSIONS.some(
|
|
3974
|
-
(ext) => (0,
|
|
3991
|
+
(ext) => (0, import_node_fs20.existsSync)((0, import_node_path20.join)(dir, `metro.config.${ext}`))
|
|
3975
3992
|
),
|
|
3976
3993
|
devCommand: typeof devCommand === "string" ? devCommand : null
|
|
3977
3994
|
};
|
|
3978
3995
|
}
|
|
3979
|
-
function readProjectMetadata(
|
|
3996
|
+
function readProjectMetadata(path16) {
|
|
3980
3997
|
try {
|
|
3981
|
-
const info = (0,
|
|
3998
|
+
const info = (0, import_node_fs20.lstatSync)(path16);
|
|
3982
3999
|
if (!info.isFile() || info.size > 4 * 1024 * 1024) return null;
|
|
3983
|
-
return (0,
|
|
4000
|
+
return (0, import_node_fs20.readFileSync)(path16, "utf8");
|
|
3984
4001
|
} catch {
|
|
3985
4002
|
return null;
|
|
3986
4003
|
}
|
|
@@ -3989,8 +4006,8 @@ function metadataValue(value, key) {
|
|
|
3989
4006
|
if (!value || typeof value !== "object") return void 0;
|
|
3990
4007
|
return Object.getOwnPropertyDescriptor(value, key)?.value;
|
|
3991
4008
|
}
|
|
3992
|
-
function readProjectJson(
|
|
3993
|
-
const text = readProjectMetadata(
|
|
4009
|
+
function readProjectJson(path16) {
|
|
4010
|
+
const text = readProjectMetadata(path16);
|
|
3994
4011
|
if (text === null) return null;
|
|
3995
4012
|
try {
|
|
3996
4013
|
const value = JSON.parse(text);
|
|
@@ -4000,7 +4017,7 @@ function readProjectJson(path12) {
|
|
|
4000
4017
|
}
|
|
4001
4018
|
}
|
|
4002
4019
|
function readProjectManifest(dir) {
|
|
4003
|
-
const parsed = readProjectJson((0,
|
|
4020
|
+
const parsed = readProjectJson((0, import_node_path20.join)(dir, "package.json"));
|
|
4004
4021
|
if (!parsed || typeof parsed !== "object") return null;
|
|
4005
4022
|
const record = (value) => {
|
|
4006
4023
|
if (!value || typeof value !== "object") return {};
|
|
@@ -4017,12 +4034,12 @@ function readProjectManifest(dir) {
|
|
|
4017
4034
|
devDependencies: record(metadataValue(parsed, "devDependencies"))
|
|
4018
4035
|
};
|
|
4019
4036
|
}
|
|
4020
|
-
var
|
|
4037
|
+
var import_node_fs20, import_node_path20, import_json5, import_yaml, CONFIG_EXTENSIONS;
|
|
4021
4038
|
var init_detect = __esm({
|
|
4022
4039
|
"cli/commands/detect.ts"() {
|
|
4023
4040
|
"use strict";
|
|
4024
|
-
|
|
4025
|
-
|
|
4041
|
+
import_node_fs20 = require("node:fs");
|
|
4042
|
+
import_node_path20 = require("node:path");
|
|
4026
4043
|
import_json5 = __toESM(require("json5"), 1);
|
|
4027
4044
|
import_yaml = require("yaml");
|
|
4028
4045
|
CONFIG_EXTENSIONS = ["ts", "js", "cjs", "mjs", "mts", "cts"];
|
|
@@ -4059,21 +4076,21 @@ function resolveCloudOrigin(value) {
|
|
|
4059
4076
|
return normalizeCloudOrigin(source);
|
|
4060
4077
|
}
|
|
4061
4078
|
function readImmutableBundleSource(bundlePath) {
|
|
4062
|
-
const filepath = (0,
|
|
4063
|
-
if ((0,
|
|
4079
|
+
const filepath = (0, import_node_path21.resolve)(bundlePath);
|
|
4080
|
+
if ((0, import_node_path21.extname)(filepath) !== ".js") {
|
|
4064
4081
|
throw new Error(`${REMOTE_COMMAND} requires one local Metro .js bundle`);
|
|
4065
4082
|
}
|
|
4066
|
-
const descriptor = (0,
|
|
4083
|
+
const descriptor = (0, import_node_fs21.openSync)(filepath, "r");
|
|
4067
4084
|
try {
|
|
4068
|
-
const before = (0,
|
|
4085
|
+
const before = (0, import_node_fs21.fstatSync)(descriptor, { bigint: true });
|
|
4069
4086
|
if (!before.isFile()) {
|
|
4070
4087
|
throw new Error(`${REMOTE_COMMAND} bundle must be a regular local file`);
|
|
4071
4088
|
}
|
|
4072
4089
|
if (before.size <= 0n) {
|
|
4073
4090
|
throw new Error(`${REMOTE_COMMAND} bundle is empty`);
|
|
4074
4091
|
}
|
|
4075
|
-
const bytes = (0,
|
|
4076
|
-
const after = (0,
|
|
4092
|
+
const bytes = (0, import_node_fs21.readFileSync)(descriptor);
|
|
4093
|
+
const after = (0, import_node_fs21.fstatSync)(descriptor, { bigint: true });
|
|
4077
4094
|
if (before.dev !== after.dev || before.ino !== after.ino || before.size !== after.size || before.mtimeNs !== after.mtimeNs || bytes.length !== Number(before.size)) {
|
|
4078
4095
|
throw new Error(`${REMOTE_COMMAND} bundle changed while it was being read`);
|
|
4079
4096
|
}
|
|
@@ -4088,7 +4105,7 @@ function readImmutableBundleSource(bundlePath) {
|
|
|
4088
4105
|
}
|
|
4089
4106
|
return source;
|
|
4090
4107
|
} finally {
|
|
4091
|
-
(0,
|
|
4108
|
+
(0, import_node_fs21.closeSync)(descriptor);
|
|
4092
4109
|
}
|
|
4093
4110
|
}
|
|
4094
4111
|
async function fetchBundleSource(bundleUrl) {
|
|
@@ -4135,15 +4152,15 @@ async function loadBundleSource(bundleInput) {
|
|
|
4135
4152
|
return readImmutableBundleSource(bundleInput);
|
|
4136
4153
|
}
|
|
4137
4154
|
function listMetroAssetDest(assetsPath) {
|
|
4138
|
-
const directory = (0,
|
|
4139
|
-
if (!(0,
|
|
4140
|
-
const skipNested = (0,
|
|
4155
|
+
const directory = (0, import_node_path21.resolve)(assetsPath);
|
|
4156
|
+
if (!(0, import_node_fs21.existsSync)(directory)) return { directory, files: [], truncated: false };
|
|
4157
|
+
const skipNested = (0, import_node_fs21.existsSync)((0, import_node_path21.join)(directory, "package.json"));
|
|
4141
4158
|
const files = [];
|
|
4142
4159
|
let truncated = false;
|
|
4143
4160
|
const walk = (dir, prefix) => {
|
|
4144
4161
|
let entries;
|
|
4145
4162
|
try {
|
|
4146
|
-
entries = (0,
|
|
4163
|
+
entries = (0, import_node_fs21.readdirSync)(dir, { withFileTypes: true });
|
|
4147
4164
|
} catch {
|
|
4148
4165
|
return;
|
|
4149
4166
|
}
|
|
@@ -4155,7 +4172,7 @@ function listMetroAssetDest(assetsPath) {
|
|
|
4155
4172
|
if (entry.isDirectory()) {
|
|
4156
4173
|
if (entry.name === ".git") continue;
|
|
4157
4174
|
if (skipNested && PROJECT_ONLY_DIRECTORIES.has(entry.name)) continue;
|
|
4158
|
-
walk((0,
|
|
4175
|
+
walk((0, import_node_path21.join)(dir, entry.name), prefix ? `${prefix}/${entry.name}` : entry.name);
|
|
4159
4176
|
} else if (entry.isFile()) {
|
|
4160
4177
|
files.push(prefix ? `${prefix}/${entry.name}` : entry.name);
|
|
4161
4178
|
}
|
|
@@ -4165,7 +4182,7 @@ function listMetroAssetDest(assetsPath) {
|
|
|
4165
4182
|
return { directory, files, truncated };
|
|
4166
4183
|
}
|
|
4167
4184
|
function metroDescriptorHash(scaleBytes) {
|
|
4168
|
-
const hasher = (0,
|
|
4185
|
+
const hasher = (0, import_node_crypto10.createHash)("md5");
|
|
4169
4186
|
for (const bytes of scaleBytes) hasher.update(bytes);
|
|
4170
4187
|
return hasher.digest("hex");
|
|
4171
4188
|
}
|
|
@@ -4190,11 +4207,11 @@ function distinctByContent(directory, options) {
|
|
|
4190
4207
|
for (const relative2 of options) {
|
|
4191
4208
|
let bytes;
|
|
4192
4209
|
try {
|
|
4193
|
-
bytes = (0,
|
|
4210
|
+
bytes = (0, import_node_fs21.readFileSync)((0, import_node_path21.join)(directory, relative2));
|
|
4194
4211
|
} catch {
|
|
4195
4212
|
continue;
|
|
4196
4213
|
}
|
|
4197
|
-
const digest = (0,
|
|
4214
|
+
const digest = (0, import_node_crypto10.createHash)("md5").update(bytes).digest("hex");
|
|
4198
4215
|
if (!byContent.has(digest)) byContent.set(digest, relative2);
|
|
4199
4216
|
}
|
|
4200
4217
|
return [...byContent.values()];
|
|
@@ -4222,13 +4239,13 @@ function placeMetroDescriptor(listing, descriptor) {
|
|
|
4222
4239
|
let bytes;
|
|
4223
4240
|
try {
|
|
4224
4241
|
bytes = combination.map(
|
|
4225
|
-
(relative2) => (0,
|
|
4242
|
+
(relative2) => (0, import_node_fs21.readFileSync)((0, import_node_path21.join)(listing.directory, relative2))
|
|
4226
4243
|
);
|
|
4227
4244
|
} catch {
|
|
4228
4245
|
continue;
|
|
4229
4246
|
}
|
|
4230
4247
|
const identical = fileHashes ? bytes.every((file, index) => {
|
|
4231
|
-
const digest = (0,
|
|
4248
|
+
const digest = (0, import_node_crypto10.createHash)("md5").update(file).digest("hex");
|
|
4232
4249
|
return descriptor.scales.some(
|
|
4233
4250
|
(scale, declared) => scale === scales[index] && fileHashes[declared] === digest
|
|
4234
4251
|
);
|
|
@@ -4248,26 +4265,26 @@ function placeMetroDescriptor(listing, descriptor) {
|
|
|
4248
4265
|
}
|
|
4249
4266
|
function unverifiedFileKey(dest) {
|
|
4250
4267
|
return dest.placements.filter((placement) => !placement.verified).flatMap(
|
|
4251
|
-
(placement) => [...placement.files.values()].map((relative2) => (0,
|
|
4268
|
+
(placement) => [...placement.files.values()].map((relative2) => (0, import_node_path21.join)(dest.directory, relative2))
|
|
4252
4269
|
).sort().join("\n");
|
|
4253
4270
|
}
|
|
4254
4271
|
function searchMetroAssetDest(bundlePath, descriptors) {
|
|
4255
|
-
const bundleDirectory = (0,
|
|
4272
|
+
const bundleDirectory = (0, import_node_path21.dirname)((0, import_node_path21.resolve)(bundlePath));
|
|
4256
4273
|
const candidates = [
|
|
4257
|
-
(0,
|
|
4274
|
+
(0, import_node_path21.join)(bundleDirectory, "assets"),
|
|
4258
4275
|
bundleDirectory,
|
|
4259
|
-
(0,
|
|
4276
|
+
(0, import_node_path21.resolve)(bundleDirectory, "..", "assets")
|
|
4260
4277
|
];
|
|
4261
4278
|
const cwd = process.cwd();
|
|
4262
4279
|
let projectDirectory = null;
|
|
4263
4280
|
for (const start of [bundleDirectory, cwd]) {
|
|
4264
|
-
let directory = (0,
|
|
4281
|
+
let directory = (0, import_node_path21.resolve)(start);
|
|
4265
4282
|
while (true) {
|
|
4266
4283
|
if (detectProject(directory)?.hasMetroConfig) {
|
|
4267
4284
|
projectDirectory = directory;
|
|
4268
4285
|
break;
|
|
4269
4286
|
}
|
|
4270
|
-
const parent = (0,
|
|
4287
|
+
const parent = (0, import_node_path21.dirname)(directory);
|
|
4271
4288
|
if (parent === directory) break;
|
|
4272
4289
|
directory = parent;
|
|
4273
4290
|
}
|
|
@@ -4275,11 +4292,11 @@ function searchMetroAssetDest(bundlePath, descriptors) {
|
|
|
4275
4292
|
}
|
|
4276
4293
|
if (projectDirectory) {
|
|
4277
4294
|
candidates.push(
|
|
4278
|
-
(0,
|
|
4279
|
-
(0,
|
|
4280
|
-
(0,
|
|
4281
|
-
(0,
|
|
4282
|
-
(0,
|
|
4295
|
+
(0, import_node_path21.join)(projectDirectory, "assets"),
|
|
4296
|
+
(0, import_node_path21.join)(projectDirectory, "dist"),
|
|
4297
|
+
(0, import_node_path21.join)(projectDirectory, "dist", "assets"),
|
|
4298
|
+
(0, import_node_path21.join)(projectDirectory, "build"),
|
|
4299
|
+
(0, import_node_path21.join)(projectDirectory, "build", "assets")
|
|
4283
4300
|
);
|
|
4284
4301
|
}
|
|
4285
4302
|
const searched = [];
|
|
@@ -4287,7 +4304,7 @@ function searchMetroAssetDest(bundlePath, descriptors) {
|
|
|
4287
4304
|
const stale = [];
|
|
4288
4305
|
let truncated = false;
|
|
4289
4306
|
for (const candidate of candidates) {
|
|
4290
|
-
const directory = (0,
|
|
4307
|
+
const directory = (0, import_node_path21.resolve)(candidate);
|
|
4291
4308
|
if (searched.includes(directory)) continue;
|
|
4292
4309
|
searched.push(directory);
|
|
4293
4310
|
const listing = listMetroAssetDest(directory);
|
|
@@ -4393,7 +4410,7 @@ async function embedBundleAssets(bundlePath, command, assetPolicy) {
|
|
|
4393
4410
|
);
|
|
4394
4411
|
}
|
|
4395
4412
|
const relative2 = placement?.files.get(variant.scale);
|
|
4396
|
-
if (relative2 && dest) return (0,
|
|
4413
|
+
if (relative2 && dest) return (0, import_node_fs21.readFileSync)((0, import_node_path21.join)(dest.directory, relative2));
|
|
4397
4414
|
if (placement && placement.files.size > 0) return null;
|
|
4398
4415
|
if (placement && placement.ambiguous.length > 0 && dest) {
|
|
4399
4416
|
throw new Error(
|
|
@@ -4422,7 +4439,7 @@ async function embedBundleAssets(bundlePath, command, assetPolicy) {
|
|
|
4422
4439
|
);
|
|
4423
4440
|
const classic = metroIosAssetDestRelatives(variant.descriptor.httpServerLocation, filename)[0] ?? filename;
|
|
4424
4441
|
throw new Error(
|
|
4425
|
-
`${command} could not read ${(0,
|
|
4442
|
+
`${command} could not read ${(0, import_node_path21.join)(dest?.directory ?? ".", classic)} for ${variant.descriptor.name}.${variant.descriptor.type} at scale ${variant.scale}, and has no stand-in for a .${variant.descriptor.type} asset. Rebuild with \`react-native bundle --assets-dest\`.`
|
|
4426
4443
|
);
|
|
4427
4444
|
});
|
|
4428
4445
|
return {
|
|
@@ -4439,10 +4456,10 @@ async function produceArtifact(bundlePath, maxBytes, command, assetPolicy) {
|
|
|
4439
4456
|
inferModuleIdentity: inferCloudModuleIdentity
|
|
4440
4457
|
});
|
|
4441
4458
|
const bytes = Buffer.from(artifact.code, "utf8");
|
|
4442
|
-
const
|
|
4459
|
+
const assets2 = artifact.receipt.assets;
|
|
4443
4460
|
if (bytes.length > maxBytes) {
|
|
4444
4461
|
throw new Error(
|
|
4445
|
-
`${REMOTE_COMMAND} artifact is ${bytes.length} bytes and exceeds the ${maxBytes}-byte limit. Embedded assets weigh ${
|
|
4462
|
+
`${REMOTE_COMMAND} artifact is ${bytes.length} bytes and exceeds the ${maxBytes}-byte limit. Embedded assets weigh ${assets2.bytes} bytes on disk, and base64 embedding costs about a third on top of that, so the practical asset budget is roughly ${Math.round(maxBytes * 0.75 / 1e6)} MB.${largestEmbeddedAssets(assets2.sizes, 10)}`
|
|
4446
4463
|
);
|
|
4447
4464
|
}
|
|
4448
4465
|
const warnings = [];
|
|
@@ -4458,12 +4475,12 @@ async function produceArtifact(bundlePath, maxBytes, command, assetPolicy) {
|
|
|
4458
4475
|
}
|
|
4459
4476
|
if (bytes.length >= Math.floor(maxBytes * 0.8)) {
|
|
4460
4477
|
warnings.push(
|
|
4461
|
-
`${command} artifact is ${bytes.length} bytes, ${Math.round(bytes.length / maxBytes * 100)}% of the ${maxBytes}-byte limit.${largestEmbeddedAssets(
|
|
4478
|
+
`${command} artifact is ${bytes.length} bytes, ${Math.round(bytes.length / maxBytes * 100)}% of the ${maxBytes}-byte limit.${largestEmbeddedAssets(assets2.sizes, 5)}`
|
|
4462
4479
|
);
|
|
4463
4480
|
}
|
|
4464
4481
|
return {
|
|
4465
4482
|
bytes,
|
|
4466
|
-
sha256: (0,
|
|
4483
|
+
sha256: (0, import_node_crypto10.createHash)("sha256").update(bytes).digest("hex"),
|
|
4467
4484
|
receipt: artifact.receipt,
|
|
4468
4485
|
assetsDirectory: prepared.dest?.directory ?? null,
|
|
4469
4486
|
warnings
|
|
@@ -4568,13 +4585,13 @@ async function createCloudBox(options) {
|
|
|
4568
4585
|
warnings: artifact.warnings
|
|
4569
4586
|
};
|
|
4570
4587
|
}
|
|
4571
|
-
var
|
|
4588
|
+
var import_node_crypto10, import_node_fs21, import_node_path21, DEFAULT_RNX_CLOUD_ORIGIN, MAX_RNX_CLOUD_BUNDLE_BYTES, REMOTE_COMMAND, MAX_ASSET_DEST_FILES, ACCOUNT_CHOICE_REFUSALS, PROJECT_ONLY_DIRECTORIES, MAX_PLACEMENT_COMBINATIONS;
|
|
4572
4589
|
var init_cloud_client = __esm({
|
|
4573
4590
|
"cli/cloud-client.ts"() {
|
|
4574
4591
|
"use strict";
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4592
|
+
import_node_crypto10 = require("node:crypto");
|
|
4593
|
+
import_node_fs21 = require("node:fs");
|
|
4594
|
+
import_node_path21 = require("node:path");
|
|
4578
4595
|
init_metroAssetArtifact();
|
|
4579
4596
|
init_metroCloudArtifact();
|
|
4580
4597
|
init_metro_fingerprint_registry_client();
|
|
@@ -5018,9 +5035,9 @@ function safeChildPlistName(value) {
|
|
|
5018
5035
|
name: file.toLowerCase().endsWith(".plist") ? file : `${file}.plist`
|
|
5019
5036
|
};
|
|
5020
5037
|
}
|
|
5021
|
-
async function readableSettingsBundle(
|
|
5038
|
+
async function readableSettingsBundle(path16) {
|
|
5022
5039
|
try {
|
|
5023
|
-
const root = await (0, import_promises.stat)((0, import_node_path.join)(
|
|
5040
|
+
const root = await (0, import_promises.stat)((0, import_node_path.join)(path16, "Root.plist"));
|
|
5024
5041
|
return root.isFile() && root.size <= MAX_PLIST_BYTES;
|
|
5025
5042
|
} catch {
|
|
5026
5043
|
return false;
|
|
@@ -5065,26 +5082,26 @@ async function settingsBundleFingerprint(bundlePath) {
|
|
|
5065
5082
|
return null;
|
|
5066
5083
|
}
|
|
5067
5084
|
}
|
|
5068
|
-
async function parsePlistRecord(
|
|
5085
|
+
async function parsePlistRecord(path16) {
|
|
5069
5086
|
try {
|
|
5070
|
-
const metadata = await (0, import_promises.stat)(
|
|
5087
|
+
const metadata = await (0, import_promises.stat)(path16);
|
|
5071
5088
|
if (!metadata.isFile() || metadata.size > MAX_PLIST_BYTES) return null;
|
|
5072
|
-
const source = await (0, import_promises.readFile)(
|
|
5089
|
+
const source = await (0, import_promises.readFile)(path16, "utf8");
|
|
5073
5090
|
const parsed = parsePlistSource(source);
|
|
5074
5091
|
return isRecord2(parsed) ? parsed : null;
|
|
5075
5092
|
} catch {
|
|
5076
5093
|
return null;
|
|
5077
5094
|
}
|
|
5078
5095
|
}
|
|
5079
|
-
function normalizeMultiValue(
|
|
5080
|
-
if (!Array.isArray(
|
|
5096
|
+
function normalizeMultiValue(raw2, key, title) {
|
|
5097
|
+
if (!Array.isArray(raw2.Values) || !Array.isArray(raw2.Titles)) return null;
|
|
5081
5098
|
const values = [];
|
|
5082
5099
|
const titles = [];
|
|
5083
5100
|
let optionType;
|
|
5084
|
-
const pairCount = Math.min(
|
|
5101
|
+
const pairCount = Math.min(raw2.Values.length, raw2.Titles.length);
|
|
5085
5102
|
for (let index = 0; index < pairCount; index++) {
|
|
5086
|
-
const value = preferenceValue(
|
|
5087
|
-
const optionTitle = optionalString(
|
|
5103
|
+
const value = preferenceValue(raw2.Values[index]);
|
|
5104
|
+
const optionTitle = optionalString(raw2.Titles[index]);
|
|
5088
5105
|
if (value === null || optionTitle === void 0) continue;
|
|
5089
5106
|
const valueType = typeof value === "string" ? "string" : typeof value === "number" ? "number" : "boolean";
|
|
5090
5107
|
if (optionType !== void 0 && valueType !== optionType) continue;
|
|
@@ -5094,7 +5111,7 @@ function normalizeMultiValue(raw, key, title) {
|
|
|
5094
5111
|
}
|
|
5095
5112
|
const firstValue = values[0];
|
|
5096
5113
|
if (firstValue === void 0) return null;
|
|
5097
|
-
const declaredDefault = preferenceValue(
|
|
5114
|
+
const declaredDefault = preferenceValue(raw2.DefaultValue);
|
|
5098
5115
|
const defaultValue = declaredDefault !== null && values.includes(declaredDefault) ? declaredDefault : firstValue;
|
|
5099
5116
|
return {
|
|
5100
5117
|
type: "multi-value",
|
|
@@ -5106,37 +5123,37 @@ function normalizeMultiValue(raw, key, title) {
|
|
|
5106
5123
|
titles
|
|
5107
5124
|
};
|
|
5108
5125
|
}
|
|
5109
|
-
async function normalizeSpecifier(
|
|
5110
|
-
if (!isRecord2(
|
|
5126
|
+
async function normalizeSpecifier(raw2, context) {
|
|
5127
|
+
if (!isRecord2(raw2)) return null;
|
|
5111
5128
|
if (context.budget.specifiers >= MAX_SPECIFIERS) return null;
|
|
5112
|
-
const type = requiredString(
|
|
5129
|
+
const type = requiredString(raw2.Type);
|
|
5113
5130
|
if (!type) return null;
|
|
5114
5131
|
context.budget.specifiers += 1;
|
|
5115
5132
|
if (type === "PSGroupSpecifier") {
|
|
5116
|
-
const title2 = optionalString(
|
|
5117
|
-
const footer = optionalString(
|
|
5133
|
+
const title2 = optionalString(raw2.Title);
|
|
5134
|
+
const footer = optionalString(raw2.FooterText);
|
|
5118
5135
|
return {
|
|
5119
5136
|
type: "group",
|
|
5120
5137
|
...title2 !== void 0 ? { title: title2 } : null,
|
|
5121
5138
|
...footer !== void 0 ? { footer } : null
|
|
5122
5139
|
};
|
|
5123
5140
|
}
|
|
5124
|
-
const key = requiredString(
|
|
5141
|
+
const key = requiredString(raw2.Key);
|
|
5125
5142
|
if (type === "PSSliderSpecifier") {
|
|
5126
5143
|
if (!key) return null;
|
|
5127
|
-
const minimumValue = finiteNumber(
|
|
5128
|
-
const maximumValue = finiteNumber(
|
|
5144
|
+
const minimumValue = finiteNumber(raw2.MinimumValue);
|
|
5145
|
+
const maximumValue = finiteNumber(raw2.MaximumValue);
|
|
5129
5146
|
if (minimumValue === null || maximumValue === null || maximumValue <= minimumValue) {
|
|
5130
5147
|
return null;
|
|
5131
5148
|
}
|
|
5132
|
-
const declaredDefault = finiteNumber(
|
|
5149
|
+
const declaredDefault = finiteNumber(raw2.DefaultValue);
|
|
5133
5150
|
const defaultValue = Math.min(
|
|
5134
5151
|
maximumValue,
|
|
5135
5152
|
Math.max(minimumValue, declaredDefault ?? minimumValue)
|
|
5136
5153
|
);
|
|
5137
|
-
const title2 = optionalString(
|
|
5138
|
-
const minimumValueImage = optionalString(
|
|
5139
|
-
const maximumValueImage = optionalString(
|
|
5154
|
+
const title2 = optionalString(raw2.Title);
|
|
5155
|
+
const minimumValueImage = optionalString(raw2.MinimumValueImage);
|
|
5156
|
+
const maximumValueImage = optionalString(raw2.MaximumValueImage);
|
|
5140
5157
|
return {
|
|
5141
5158
|
type: "slider",
|
|
5142
5159
|
key,
|
|
@@ -5150,8 +5167,8 @@ async function normalizeSpecifier(raw, context) {
|
|
|
5150
5167
|
};
|
|
5151
5168
|
}
|
|
5152
5169
|
if (type === "PSChildPaneSpecifier") {
|
|
5153
|
-
const title2 = requiredString(
|
|
5154
|
-
const child = safeChildPlistName(
|
|
5170
|
+
const title2 = requiredString(raw2.Title);
|
|
5171
|
+
const child = safeChildPlistName(raw2.File);
|
|
5155
5172
|
if (!title2 || !child || context.depth >= MAX_CHILD_DEPTH) return null;
|
|
5156
5173
|
const childSpecifiers = await parseSpecifierFile(child.name, {
|
|
5157
5174
|
...context,
|
|
@@ -5166,9 +5183,9 @@ async function normalizeSpecifier(raw, context) {
|
|
|
5166
5183
|
};
|
|
5167
5184
|
}
|
|
5168
5185
|
if (!key) return null;
|
|
5169
|
-
const title = requiredString(
|
|
5186
|
+
const title = requiredString(raw2.Title) ?? key;
|
|
5170
5187
|
if (type === "PSToggleSwitchSpecifier") {
|
|
5171
|
-
const defaultValue = typeof
|
|
5188
|
+
const defaultValue = typeof raw2.DefaultValue === "boolean" ? raw2.DefaultValue : false;
|
|
5172
5189
|
return {
|
|
5173
5190
|
type: "toggle",
|
|
5174
5191
|
key,
|
|
@@ -5178,11 +5195,11 @@ async function normalizeSpecifier(raw, context) {
|
|
|
5178
5195
|
};
|
|
5179
5196
|
}
|
|
5180
5197
|
if (type === "PSTextFieldSpecifier") {
|
|
5181
|
-
const defaultValue = optionalString(
|
|
5182
|
-
const placeholder = optionalString(
|
|
5183
|
-
const resolvedKeyboardType = keyboardType(
|
|
5184
|
-
const resolvedAutocapitalization = autocapitalization(
|
|
5185
|
-
const resolvedAutocorrection = autocorrection(
|
|
5198
|
+
const defaultValue = optionalString(raw2.DefaultValue) ?? "";
|
|
5199
|
+
const placeholder = optionalString(raw2.Placeholder);
|
|
5200
|
+
const resolvedKeyboardType = keyboardType(raw2.KeyboardType);
|
|
5201
|
+
const resolvedAutocapitalization = autocapitalization(raw2.AutocapitalizationType);
|
|
5202
|
+
const resolvedAutocorrection = autocorrection(raw2.AutocorrectionType);
|
|
5186
5203
|
return {
|
|
5187
5204
|
type: "text",
|
|
5188
5205
|
key,
|
|
@@ -5190,17 +5207,17 @@ async function normalizeSpecifier(raw, context) {
|
|
|
5190
5207
|
defaultValue,
|
|
5191
5208
|
currentValue: defaultValue,
|
|
5192
5209
|
...placeholder !== void 0 ? { placeholder } : null,
|
|
5193
|
-
...typeof
|
|
5210
|
+
...typeof raw2.IsSecure === "boolean" ? { secure: raw2.IsSecure } : null,
|
|
5194
5211
|
...resolvedKeyboardType ? { keyboardType: resolvedKeyboardType } : null,
|
|
5195
5212
|
...resolvedAutocapitalization ? { autocapitalization: resolvedAutocapitalization } : null,
|
|
5196
5213
|
...resolvedAutocorrection !== void 0 ? { autocorrection: resolvedAutocorrection } : null
|
|
5197
5214
|
};
|
|
5198
5215
|
}
|
|
5199
5216
|
if (type === "PSMultiValueSpecifier" || type === "PSRadioGroupSpecifier") {
|
|
5200
|
-
return normalizeMultiValue(
|
|
5217
|
+
return normalizeMultiValue(raw2, key, title);
|
|
5201
5218
|
}
|
|
5202
5219
|
if (type === "PSTitleValueSpecifier") {
|
|
5203
|
-
const defaultValue = preferenceValue(
|
|
5220
|
+
const defaultValue = preferenceValue(raw2.DefaultValue) ?? "";
|
|
5204
5221
|
return {
|
|
5205
5222
|
type: "title-value",
|
|
5206
5223
|
key,
|
|
@@ -5226,9 +5243,9 @@ async function parseSpecifierFile(fileName, context) {
|
|
|
5226
5243
|
const stack = new Set(context.stack);
|
|
5227
5244
|
stack.add(fileName);
|
|
5228
5245
|
const specifiers = [];
|
|
5229
|
-
for (const
|
|
5246
|
+
for (const raw2 of root.PreferenceSpecifiers) {
|
|
5230
5247
|
if (context.budget.specifiers >= MAX_SPECIFIERS) break;
|
|
5231
|
-
const specifier = await normalizeSpecifier(
|
|
5248
|
+
const specifier = await normalizeSpecifier(raw2, { ...context, stack });
|
|
5232
5249
|
if (specifier) specifiers.push(specifier);
|
|
5233
5250
|
}
|
|
5234
5251
|
context.fileCache.set(fileName, specifiers);
|
|
@@ -5331,7 +5348,7 @@ async function tcpPing(port, timeout = TCP_GATE_MS) {
|
|
|
5331
5348
|
return null;
|
|
5332
5349
|
}
|
|
5333
5350
|
}
|
|
5334
|
-
function httpGet(hostname, port,
|
|
5351
|
+
function httpGet(hostname, port, path16, method = "GET", timeout = TIMEOUT_MS, headers = {}) {
|
|
5335
5352
|
return new Promise((resolve5) => {
|
|
5336
5353
|
let settled = false;
|
|
5337
5354
|
let killing = false;
|
|
@@ -5340,13 +5357,13 @@ function httpGet(hostname, port, path12, method = "GET", timeout = TIMEOUT_MS, h
|
|
|
5340
5357
|
settled = true;
|
|
5341
5358
|
resolve5(value);
|
|
5342
5359
|
};
|
|
5343
|
-
const req = import_http.default.request({ hostname, port, path:
|
|
5360
|
+
const req = import_http.default.request({ hostname, port, path: path16, method, headers }, (res) => {
|
|
5344
5361
|
let body = "";
|
|
5345
5362
|
res.on("data", (c) => body += c.toString());
|
|
5346
5363
|
const contentType = (() => {
|
|
5347
|
-
const
|
|
5348
|
-
if (typeof
|
|
5349
|
-
if (Array.isArray(
|
|
5364
|
+
const raw2 = res.headers["content-type"];
|
|
5365
|
+
if (typeof raw2 === "string") return raw2;
|
|
5366
|
+
if (Array.isArray(raw2)) return raw2[0];
|
|
5350
5367
|
return void 0;
|
|
5351
5368
|
})();
|
|
5352
5369
|
res.on(
|
|
@@ -6016,6 +6033,1833 @@ function getCliVersion() {
|
|
|
6016
6033
|
return cached2;
|
|
6017
6034
|
}
|
|
6018
6035
|
|
|
6036
|
+
// src/expo-swift-host.ts
|
|
6037
|
+
var import_node_child_process4 = require("node:child_process");
|
|
6038
|
+
var import_node_crypto5 = require("node:crypto");
|
|
6039
|
+
var import_node_fs10 = __toESM(require("node:fs"), 1);
|
|
6040
|
+
var import_node_module = require("node:module");
|
|
6041
|
+
var import_node_os4 = __toESM(require("node:os"), 1);
|
|
6042
|
+
var import_node_path10 = __toESM(require("node:path"), 1);
|
|
6043
|
+
var import_node_util3 = require("node:util");
|
|
6044
|
+
init_backend_origin();
|
|
6045
|
+
|
|
6046
|
+
// src/swift-host.ts
|
|
6047
|
+
var import_node_crypto4 = require("node:crypto");
|
|
6048
|
+
var import_node_fs9 = __toESM(require("node:fs"), 1);
|
|
6049
|
+
var import_node_os3 = __toESM(require("node:os"), 1);
|
|
6050
|
+
var import_node_path9 = __toESM(require("node:path"), 1);
|
|
6051
|
+
|
|
6052
|
+
// ../sootsim-swift/src/bundleAssets.ts
|
|
6053
|
+
var import_svgpath = __toESM(require("svgpath"), 1);
|
|
6054
|
+
var RASTER_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
6055
|
+
".avif",
|
|
6056
|
+
".bmp",
|
|
6057
|
+
".gif",
|
|
6058
|
+
".ico",
|
|
6059
|
+
".jpeg",
|
|
6060
|
+
".jpg",
|
|
6061
|
+
".png",
|
|
6062
|
+
".webp"
|
|
6063
|
+
]);
|
|
6064
|
+
function extOf(file) {
|
|
6065
|
+
const dot = file.lastIndexOf(".");
|
|
6066
|
+
return dot < 0 ? "" : file.slice(dot).toLowerCase();
|
|
6067
|
+
}
|
|
6068
|
+
function baseOf(file) {
|
|
6069
|
+
const slash = file.lastIndexOf("/");
|
|
6070
|
+
return slash < 0 ? file : file.slice(slash + 1);
|
|
6071
|
+
}
|
|
6072
|
+
function pickImagesetFile(images) {
|
|
6073
|
+
const rasters = images.filter(
|
|
6074
|
+
(image) => typeof image.filename === "string" && RASTER_EXTENSIONS.has(extOf(image.filename))
|
|
6075
|
+
);
|
|
6076
|
+
if (rasters.length === 0) return null;
|
|
6077
|
+
const rank = (scale) => scale === "2x" ? 0 : scale === "3x" ? 1 : scale === "1x" ? 2 : 3;
|
|
6078
|
+
const pick = [...rasters].sort((a, b) => rank(a.scale) - rank(b.scale))[0];
|
|
6079
|
+
return {
|
|
6080
|
+
filename: pick.filename,
|
|
6081
|
+
scale: pick.scale === "2x" ? 2 : pick.scale === "3x" ? 3 : 1
|
|
6082
|
+
};
|
|
6083
|
+
}
|
|
6084
|
+
function flatScale(path16) {
|
|
6085
|
+
const match = /@([23])x\.[^./]+$/.exec(path16);
|
|
6086
|
+
return match ? Number(match[1]) : 1;
|
|
6087
|
+
}
|
|
6088
|
+
function providesNamespace(text) {
|
|
6089
|
+
if (text === null) return false;
|
|
6090
|
+
try {
|
|
6091
|
+
const parsed = JSON.parse(text);
|
|
6092
|
+
return parsed?.properties?.["provides-namespace"] === true;
|
|
6093
|
+
} catch {
|
|
6094
|
+
return false;
|
|
6095
|
+
}
|
|
6096
|
+
}
|
|
6097
|
+
function catalogEntryName(contentsPath, kind, readText) {
|
|
6098
|
+
const parts = contentsPath.split("/");
|
|
6099
|
+
const leaf = parts[parts.length - 2] ?? "";
|
|
6100
|
+
if (!leaf.endsWith(kind)) return null;
|
|
6101
|
+
const short = leaf.slice(0, -kind.length) || null;
|
|
6102
|
+
if (short === null) return null;
|
|
6103
|
+
const segments = [short];
|
|
6104
|
+
for (let depth = parts.length - 3; depth >= 0; depth -= 1) {
|
|
6105
|
+
const dir = parts[depth] ?? "";
|
|
6106
|
+
if (dir.endsWith(".xcassets") || dir === "" || dir === "." || dir === "..") break;
|
|
6107
|
+
const folderContents = [...parts.slice(0, depth + 1), "Contents.json"].join("/");
|
|
6108
|
+
if (providesNamespace(readText(folderContents))) segments.unshift(dir);
|
|
6109
|
+
}
|
|
6110
|
+
return segments.join("/");
|
|
6111
|
+
}
|
|
6112
|
+
function isFlatResourceImage(path16) {
|
|
6113
|
+
return path16.split("/").includes("Resources") && RASTER_EXTENSIONS.has(extOf(path16));
|
|
6114
|
+
}
|
|
6115
|
+
function enumerateBundleImages(paths, readText) {
|
|
6116
|
+
const table = [];
|
|
6117
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6118
|
+
const catalogs = paths.filter((path16) => baseOf(path16) === "Contents.json");
|
|
6119
|
+
for (const contentsPath of catalogs) {
|
|
6120
|
+
const name2 = catalogEntryName(contentsPath, ".imageset", readText);
|
|
6121
|
+
if (name2 === null || seen.has(name2)) continue;
|
|
6122
|
+
let parsed;
|
|
6123
|
+
try {
|
|
6124
|
+
const text = readText(contentsPath);
|
|
6125
|
+
if (text === null) continue;
|
|
6126
|
+
parsed = JSON.parse(text);
|
|
6127
|
+
} catch {
|
|
6128
|
+
continue;
|
|
6129
|
+
}
|
|
6130
|
+
const images = parsed?.images;
|
|
6131
|
+
if (!Array.isArray(images)) continue;
|
|
6132
|
+
const dir = contentsPath.split("/").slice(0, -1).join("/");
|
|
6133
|
+
const pick = pickImagesetFile(images);
|
|
6134
|
+
if (pick === null || pick.filename.includes("/") || pick.filename.includes("\\"))
|
|
6135
|
+
continue;
|
|
6136
|
+
seen.add(name2);
|
|
6137
|
+
table.push({ name: name2, file: `${dir}/${pick.filename}`, scale: pick.scale });
|
|
6138
|
+
}
|
|
6139
|
+
for (const path16 of paths) {
|
|
6140
|
+
if (!isFlatResourceImage(path16)) continue;
|
|
6141
|
+
const name2 = baseOf(path16).slice(0, -extOf(path16).length);
|
|
6142
|
+
if (name2 === "" || seen.has(name2)) continue;
|
|
6143
|
+
seen.add(name2);
|
|
6144
|
+
table.push({ name: name2, file: path16, scale: flatScale(path16) });
|
|
6145
|
+
}
|
|
6146
|
+
return table;
|
|
6147
|
+
}
|
|
6148
|
+
function colorComponent(value) {
|
|
6149
|
+
if (typeof value !== "string") return null;
|
|
6150
|
+
const parsed = value.startsWith("0x") ? Number.parseInt(value.slice(2), 16) / 255 : value.includes(".") ? Number.parseFloat(value) : Number.parseInt(value, 10) / 255;
|
|
6151
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
6152
|
+
}
|
|
6153
|
+
function colorsetValue(color) {
|
|
6154
|
+
if (typeof color !== "object" || color === null) return null;
|
|
6155
|
+
const reference = Reflect.get(color, "reference");
|
|
6156
|
+
if (typeof reference === "string") {
|
|
6157
|
+
return { system: reference.replace(/Color$/, "") };
|
|
6158
|
+
}
|
|
6159
|
+
const space = Reflect.get(color, "color-space");
|
|
6160
|
+
if (space !== "srgb" && space !== "extended-srgb") return null;
|
|
6161
|
+
const components = Reflect.get(color, "components");
|
|
6162
|
+
if (typeof components !== "object" || components === null) return null;
|
|
6163
|
+
const [red, green, blue, alpha] = ["red", "green", "blue", "alpha"].map(
|
|
6164
|
+
(key) => colorComponent(Reflect.get(components, key))
|
|
6165
|
+
);
|
|
6166
|
+
if (red === null || green === null || blue === null || alpha === null) return null;
|
|
6167
|
+
if (![red, green, blue].every((value) => value >= 0 && value <= 1)) return null;
|
|
6168
|
+
const byte = (value) => Math.round(value * 255);
|
|
6169
|
+
return `rgba(${byte(red)}, ${byte(green)}, ${byte(blue)}, ${alpha})`;
|
|
6170
|
+
}
|
|
6171
|
+
function enumerateBundleColors(paths, readText) {
|
|
6172
|
+
const table = {};
|
|
6173
|
+
for (const contentsPath of paths.filter((path16) => baseOf(path16) === "Contents.json")) {
|
|
6174
|
+
const name2 = catalogEntryName(contentsPath, ".colorset", readText);
|
|
6175
|
+
if (name2 === null || name2 in table) continue;
|
|
6176
|
+
let colors;
|
|
6177
|
+
try {
|
|
6178
|
+
const text = readText(contentsPath);
|
|
6179
|
+
if (text === null) continue;
|
|
6180
|
+
colors = Reflect.get(JSON.parse(text), "colors");
|
|
6181
|
+
} catch {
|
|
6182
|
+
continue;
|
|
6183
|
+
}
|
|
6184
|
+
if (!Array.isArray(colors)) continue;
|
|
6185
|
+
let light = null;
|
|
6186
|
+
let dark = null;
|
|
6187
|
+
for (const entry of colors) {
|
|
6188
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
6189
|
+
const idiom = Reflect.get(entry, "idiom");
|
|
6190
|
+
if (idiom !== "universal" && idiom !== "iphone") continue;
|
|
6191
|
+
const appearances = Reflect.get(entry, "appearances");
|
|
6192
|
+
const list = Array.isArray(appearances) ? appearances : [];
|
|
6193
|
+
if (list.some((item) => Reflect.get(item, "appearance") === "contrast")) continue;
|
|
6194
|
+
const isDark = list.some(
|
|
6195
|
+
(item) => Reflect.get(item, "appearance") === "luminosity" && Reflect.get(item, "value") === "dark"
|
|
6196
|
+
);
|
|
6197
|
+
if (list.length > 0 && !isDark) continue;
|
|
6198
|
+
const value = colorsetValue(Reflect.get(entry, "color"));
|
|
6199
|
+
if (value === null) continue;
|
|
6200
|
+
if (isDark) dark = value;
|
|
6201
|
+
else light = value;
|
|
6202
|
+
}
|
|
6203
|
+
if (light === null) continue;
|
|
6204
|
+
if (typeof light === "object") table[name2] = light;
|
|
6205
|
+
else table[name2] = { light, dark: typeof dark === "string" ? dark : light };
|
|
6206
|
+
}
|
|
6207
|
+
return table;
|
|
6208
|
+
}
|
|
6209
|
+
var SYMBOL_CAP_HEIGHT_EM = 1443 / 2048;
|
|
6210
|
+
function axisExtremes(points) {
|
|
6211
|
+
const [a = 0, b = 0, c = 0, d] = points;
|
|
6212
|
+
const out = [a, d ?? c];
|
|
6213
|
+
const within = (t) => t > 0 && t < 1;
|
|
6214
|
+
if (d === void 0) {
|
|
6215
|
+
const denom = a - 2 * b + c;
|
|
6216
|
+
const t = denom === 0 ? -1 : (a - b) / denom;
|
|
6217
|
+
if (within(t)) out.push((1 - t) ** 2 * a + 2 * (1 - t) * t * b + t ** 2 * c);
|
|
6218
|
+
return out;
|
|
6219
|
+
}
|
|
6220
|
+
const qa = 3 * (-a + 3 * b - 3 * c + d);
|
|
6221
|
+
const qb = 6 * (a - 2 * b + c);
|
|
6222
|
+
const qc = 3 * (b - a);
|
|
6223
|
+
const roots = Math.abs(qa) < 1e-12 ? qb === 0 ? [] : [-qc / qb] : (() => {
|
|
6224
|
+
const disc = qb * qb - 4 * qa * qc;
|
|
6225
|
+
if (disc < 0) return [];
|
|
6226
|
+
const root = Math.sqrt(disc);
|
|
6227
|
+
return [(-qb + root) / (2 * qa), (-qb - root) / (2 * qa)];
|
|
6228
|
+
})();
|
|
6229
|
+
for (const t of roots.filter(within))
|
|
6230
|
+
out.push(
|
|
6231
|
+
(1 - t) ** 3 * a + 3 * (1 - t) ** 2 * t * b + 3 * (1 - t) * t ** 2 * c + t ** 3 * d
|
|
6232
|
+
);
|
|
6233
|
+
return out;
|
|
6234
|
+
}
|
|
6235
|
+
function pathBounds(d) {
|
|
6236
|
+
const xs = [];
|
|
6237
|
+
const ys = [];
|
|
6238
|
+
for (const path16 of d)
|
|
6239
|
+
(0, import_svgpath.default)(path16).abs().unshort().unarc().iterate((segment, _index, x, y) => {
|
|
6240
|
+
const [command, ...args] = segment;
|
|
6241
|
+
if (command === "M" || command === "L") {
|
|
6242
|
+
xs.push(Number(args[0]));
|
|
6243
|
+
ys.push(Number(args[1]));
|
|
6244
|
+
} else if (command === "H") xs.push(Number(args[0]));
|
|
6245
|
+
else if (command === "V") ys.push(Number(args[0]));
|
|
6246
|
+
else if (command === "Q" || command === "C") {
|
|
6247
|
+
const n = args.map(Number);
|
|
6248
|
+
xs.push(...axisExtremes([x, ...n.filter((_, i) => i % 2 === 0)]));
|
|
6249
|
+
ys.push(...axisExtremes([y, ...n.filter((_, i) => i % 2 === 1)]));
|
|
6250
|
+
}
|
|
6251
|
+
});
|
|
6252
|
+
return {
|
|
6253
|
+
minX: Math.min(...xs),
|
|
6254
|
+
maxX: Math.max(...xs),
|
|
6255
|
+
minY: Math.min(...ys),
|
|
6256
|
+
maxY: Math.max(...ys)
|
|
6257
|
+
};
|
|
6258
|
+
}
|
|
6259
|
+
function guide(svg, id, axis) {
|
|
6260
|
+
const line = new RegExp(`<line[^>]*id="${id}"[^>]*>`).exec(svg)?.[0];
|
|
6261
|
+
const value = line === void 0 ? void 0 : new RegExp(`${axis}="([-0-9.]+)"`).exec(line)?.[1];
|
|
6262
|
+
return value === void 0 ? null : Number(value);
|
|
6263
|
+
}
|
|
6264
|
+
function enumerateBundleSymbols(paths, readText) {
|
|
6265
|
+
const table = {};
|
|
6266
|
+
for (const contentsPath of paths.filter((path16) => baseOf(path16) === "Contents.json")) {
|
|
6267
|
+
const name2 = catalogEntryName(contentsPath, ".symbolset", readText);
|
|
6268
|
+
if (name2 === null || name2 in table) continue;
|
|
6269
|
+
let symbols;
|
|
6270
|
+
try {
|
|
6271
|
+
symbols = Reflect.get(JSON.parse(readText(contentsPath) ?? "null") ?? {}, "symbols");
|
|
6272
|
+
} catch {
|
|
6273
|
+
continue;
|
|
6274
|
+
}
|
|
6275
|
+
const file = Array.isArray(symbols) ? symbols.map((entry) => Reflect.get(entry ?? {}, "filename")).find((f) => typeof f === "string") : void 0;
|
|
6276
|
+
if (typeof file !== "string") continue;
|
|
6277
|
+
if (file.includes("/") || file.includes("\\")) continue;
|
|
6278
|
+
const svg = readText(`${contentsPath.split("/").slice(0, -1).join("/")}/${file}`);
|
|
6279
|
+
if (svg === null) continue;
|
|
6280
|
+
const group = /<g id="Regular-M"[^>]*>([\s\S]*?)<\/g>/.exec(svg)?.[1];
|
|
6281
|
+
const baseline = guide(svg, "Baseline-M", "y1");
|
|
6282
|
+
const capline = guide(svg, "Capline-M", "y1");
|
|
6283
|
+
const left = guide(svg, "left-margin-Regular-M", "x1") ?? guide(svg, "left-margin", "x1");
|
|
6284
|
+
const right = guide(svg, "right-margin-Regular-M", "x1") ?? guide(svg, "right-margin", "x1");
|
|
6285
|
+
if (group === void 0 || baseline === null || capline === null || left === null || right === null)
|
|
6286
|
+
continue;
|
|
6287
|
+
const d = [...group.matchAll(/ d="([^"]+)"/g)].map((match) => match[1] ?? "");
|
|
6288
|
+
if (d.length === 0 || baseline <= capline) continue;
|
|
6289
|
+
const scale = 24 * SYMBOL_CAP_HEIGHT_EM / (baseline - capline);
|
|
6290
|
+
const box = pathBounds(d);
|
|
6291
|
+
const translateX = 12 - (box.minX + box.maxX) * scale / 2;
|
|
6292
|
+
const translateY = 12 - (box.minY + box.maxY) * scale / 2;
|
|
6293
|
+
const advance = Math.round((right - left) * scale * 1e3) / 1e3;
|
|
6294
|
+
const tall = (box.maxY - box.minY) * scale + 0.175 * 24;
|
|
6295
|
+
table[name2] = {
|
|
6296
|
+
viewBox: "0 0 24 24",
|
|
6297
|
+
advance,
|
|
6298
|
+
box: [12 - advance / 2, 12 - tall / 2, advance, tall],
|
|
6299
|
+
layers: d.map((path16) => ({
|
|
6300
|
+
d: (0, import_svgpath.default)(path16).abs().scale(scale).translate(translateX, translateY).round(3).toString()
|
|
6301
|
+
}))
|
|
6302
|
+
};
|
|
6303
|
+
}
|
|
6304
|
+
return table;
|
|
6305
|
+
}
|
|
6306
|
+
function enumerateBundleJson(paths) {
|
|
6307
|
+
const found = [];
|
|
6308
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6309
|
+
const ordered = [...paths].filter(
|
|
6310
|
+
(path16) => path16.split("/").includes("Resources") && path16.split("/").every((segment) => segment !== "" && segment !== "..") && (extOf(path16) === ".json" || extOf(path16) === ".xcstrings")
|
|
6311
|
+
).sort((a, b) => {
|
|
6312
|
+
const aDepth = a.split("/").length;
|
|
6313
|
+
const bDepth = b.split("/").length;
|
|
6314
|
+
return aDepth - bDepth || (a < b ? -1 : a > b ? 1 : 0);
|
|
6315
|
+
});
|
|
6316
|
+
for (const file of ordered) {
|
|
6317
|
+
const base = baseOf(file);
|
|
6318
|
+
if (seen.has(base)) continue;
|
|
6319
|
+
seen.add(base);
|
|
6320
|
+
found.push({ base, file });
|
|
6321
|
+
}
|
|
6322
|
+
return found;
|
|
6323
|
+
}
|
|
6324
|
+
|
|
6325
|
+
// src/swift-host.ts
|
|
6326
|
+
init_auth();
|
|
6327
|
+
init_backend_origin();
|
|
6328
|
+
|
|
6329
|
+
// src/swift-compile.ts
|
|
6330
|
+
var import_node_child_process3 = require("node:child_process");
|
|
6331
|
+
var import_node_crypto3 = require("node:crypto");
|
|
6332
|
+
var import_node_fs8 = require("node:fs");
|
|
6333
|
+
var import_node_os2 = __toESM(require("node:os"), 1);
|
|
6334
|
+
var import_node_path8 = __toESM(require("node:path"), 1);
|
|
6335
|
+
var import_node_util2 = require("node:util");
|
|
6336
|
+
|
|
6337
|
+
// src/swift-icu.ts
|
|
6338
|
+
var import_node_child_process2 = require("node:child_process");
|
|
6339
|
+
var import_node_crypto2 = require("node:crypto");
|
|
6340
|
+
var import_node_fs7 = require("node:fs");
|
|
6341
|
+
var import_node_path7 = __toESM(require("node:path"), 1);
|
|
6342
|
+
var import_node_util = require("node:util");
|
|
6343
|
+
var import_node_zlib = require("node:zlib");
|
|
6344
|
+
var run = (0, import_node_util.promisify)(import_node_child_process2.execFile);
|
|
6345
|
+
var deflate = (0, import_node_util.promisify)(import_node_zlib.gzip);
|
|
6346
|
+
var ARCHIVE = "wasi/lib_FoundationICU.a";
|
|
6347
|
+
var MEMBER = "icu_packaged_data.cpp.obj";
|
|
6348
|
+
var raw = /* @__PURE__ */ new Map();
|
|
6349
|
+
var assets = /* @__PURE__ */ new Map();
|
|
6350
|
+
function memo(cache, key, load2) {
|
|
6351
|
+
let pending = cache.get(key);
|
|
6352
|
+
if (!pending) {
|
|
6353
|
+
pending = load2();
|
|
6354
|
+
pending.catch(() => cache.delete(key));
|
|
6355
|
+
cache.set(key, pending);
|
|
6356
|
+
}
|
|
6357
|
+
return pending;
|
|
6358
|
+
}
|
|
6359
|
+
function swiftIcuData(toolchainBin, release) {
|
|
6360
|
+
return memo(raw, `${toolchainBin}\0${release}`, () => load(toolchainBin, release));
|
|
6361
|
+
}
|
|
6362
|
+
function swiftIcuAsset(toolchainBin, release) {
|
|
6363
|
+
return memo(assets, `${toolchainBin}\0${release}`, async () => {
|
|
6364
|
+
const zipped = await deflate(await swiftIcuData(toolchainBin, release));
|
|
6365
|
+
return { sha256: (0, import_node_crypto2.createHash)("sha256").update(zipped).digest("hex"), gzip: zipped };
|
|
6366
|
+
});
|
|
6367
|
+
}
|
|
6368
|
+
async function load(toolchainBin, release) {
|
|
6369
|
+
const { stdout } = await run(import_node_path7.default.join(toolchainBin, "swift"), [
|
|
6370
|
+
"sdk",
|
|
6371
|
+
"configure",
|
|
6372
|
+
"--show-configuration",
|
|
6373
|
+
`${release}_wasm`,
|
|
6374
|
+
"wasm32-unknown-wasip1"
|
|
6375
|
+
]);
|
|
6376
|
+
const resources = /^swiftStaticResourcesPath: (.+)$/m.exec(stdout)?.[1]?.trim();
|
|
6377
|
+
if (!resources) throw new Error(`swift-icu: ${release}_wasm names no static resources`);
|
|
6378
|
+
return Buffer.from(
|
|
6379
|
+
icuSegment(archiveMember((0, import_node_fs7.readFileSync)(import_node_path7.default.join(resources, ARCHIVE)), MEMBER))
|
|
6380
|
+
);
|
|
6381
|
+
}
|
|
6382
|
+
function archiveMember(archive, name2) {
|
|
6383
|
+
if (archive.toString("latin1", 0, 8) !== "!<arch>\n")
|
|
6384
|
+
throw new Error("swift-icu: not an ar archive");
|
|
6385
|
+
let names = "";
|
|
6386
|
+
for (let at = 8; at + 60 <= archive.length; ) {
|
|
6387
|
+
const raw2 = archive.toString("latin1", at, at + 16).trimEnd();
|
|
6388
|
+
const size = Number(archive.toString("latin1", at + 48, at + 58).trim());
|
|
6389
|
+
const body = archive.subarray(at + 60, at + 60 + size);
|
|
6390
|
+
if (raw2 === "//") names = body.toString("latin1");
|
|
6391
|
+
const member = /^\/\d+$/.test(raw2) ? names.slice(Number(raw2.slice(1)), names.indexOf("/\n", Number(raw2.slice(1)))) : raw2.replace(/\/$/, "");
|
|
6392
|
+
if (member === name2) return body;
|
|
6393
|
+
at += 60 + size + size % 2;
|
|
6394
|
+
}
|
|
6395
|
+
throw new Error(`swift-icu: ${name2} is not in the sdk's icu archive`);
|
|
6396
|
+
}
|
|
6397
|
+
function icuSegment(object) {
|
|
6398
|
+
let at = 8;
|
|
6399
|
+
const leb = () => {
|
|
6400
|
+
let result = 0;
|
|
6401
|
+
let shift = 0;
|
|
6402
|
+
let byte;
|
|
6403
|
+
do {
|
|
6404
|
+
byte = object[at++];
|
|
6405
|
+
result += (byte & 127) * 2 ** shift;
|
|
6406
|
+
shift += 7;
|
|
6407
|
+
} while (byte & 128);
|
|
6408
|
+
return result;
|
|
6409
|
+
};
|
|
6410
|
+
const found = [];
|
|
6411
|
+
while (at < object.length) {
|
|
6412
|
+
const id = object[at++];
|
|
6413
|
+
const size = leb();
|
|
6414
|
+
const end = at + size;
|
|
6415
|
+
if (id === 11) {
|
|
6416
|
+
for (let count = leb(); count > 0; count--) {
|
|
6417
|
+
if (leb() !== 0) throw new Error("swift-icu: unexpected data segment kind");
|
|
6418
|
+
at++;
|
|
6419
|
+
leb();
|
|
6420
|
+
at++;
|
|
6421
|
+
const length = leb();
|
|
6422
|
+
const bytes = object.subarray(at, at + length);
|
|
6423
|
+
if (bytes[2] === 218 && bytes[3] === 39) found.push(bytes);
|
|
6424
|
+
at += length;
|
|
6425
|
+
}
|
|
6426
|
+
}
|
|
6427
|
+
at = end;
|
|
6428
|
+
}
|
|
6429
|
+
if (found.length !== 1)
|
|
6430
|
+
throw new Error(`swift-icu: expected one icu data segment, found ${found.length}`);
|
|
6431
|
+
return found[0];
|
|
6432
|
+
}
|
|
6433
|
+
|
|
6434
|
+
// src/swift-package.ts
|
|
6435
|
+
function swiftManifestTargets(manifest) {
|
|
6436
|
+
const code = manifest.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/[^\n]*/g, "");
|
|
6437
|
+
const targets = [];
|
|
6438
|
+
const pattern = /\.(executableTarget|target)\s*\(/g;
|
|
6439
|
+
let match;
|
|
6440
|
+
while ((match = pattern.exec(code)) !== null) {
|
|
6441
|
+
const executable = match[1] === "executableTarget";
|
|
6442
|
+
let depth = 1;
|
|
6443
|
+
const start = pattern.lastIndex;
|
|
6444
|
+
let i = start;
|
|
6445
|
+
let inString = false;
|
|
6446
|
+
let escaped = false;
|
|
6447
|
+
let flat = "";
|
|
6448
|
+
while (i < code.length && depth > 0) {
|
|
6449
|
+
const ch = code[i];
|
|
6450
|
+
if (inString) {
|
|
6451
|
+
if (escaped) escaped = false;
|
|
6452
|
+
else if (ch === "\\") escaped = true;
|
|
6453
|
+
else if (ch === '"') inString = false;
|
|
6454
|
+
if (depth === 1) flat += ch;
|
|
6455
|
+
} else if (ch === '"') {
|
|
6456
|
+
inString = true;
|
|
6457
|
+
if (depth === 1) flat += ch;
|
|
6458
|
+
} else if (ch === "(") {
|
|
6459
|
+
depth++;
|
|
6460
|
+
if (depth === 1) flat += ch;
|
|
6461
|
+
} else if (ch === ")") {
|
|
6462
|
+
depth--;
|
|
6463
|
+
if (depth >= 1) flat += ch;
|
|
6464
|
+
} else if (depth === 1) {
|
|
6465
|
+
flat += ch;
|
|
6466
|
+
}
|
|
6467
|
+
i++;
|
|
6468
|
+
}
|
|
6469
|
+
const name2 = /\bname\s*:\s*"([^"]+)"/.exec(flat)?.[1];
|
|
6470
|
+
if (!name2) continue;
|
|
6471
|
+
const rawPath = /\bpath\s*:\s*"([^"]*)"/.exec(flat)?.[1];
|
|
6472
|
+
const targetPath = rawPath == null || rawPath === "" ? `Sources/${name2}` : rawPath.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
6473
|
+
const call = code.slice(start, i);
|
|
6474
|
+
const languageMode = Number(
|
|
6475
|
+
/\.swiftLanguageMode\(\s*\.v(\d+)\s*\)/.exec(call)?.[1] ?? "5"
|
|
6476
|
+
);
|
|
6477
|
+
const mainActorIsolation = /\.defaultIsolation\(\s*MainActor\.self\s*\)/.test(call);
|
|
6478
|
+
const resources = /\bresources\s*:/.test(flat);
|
|
6479
|
+
targets.push({
|
|
6480
|
+
name: name2,
|
|
6481
|
+
path: targetPath,
|
|
6482
|
+
executable,
|
|
6483
|
+
languageMode,
|
|
6484
|
+
mainActorIsolation,
|
|
6485
|
+
resources
|
|
6486
|
+
});
|
|
6487
|
+
}
|
|
6488
|
+
return targets;
|
|
6489
|
+
}
|
|
6490
|
+
function swiftPackagePartition(manifest) {
|
|
6491
|
+
const targets = swiftManifestTargets(manifest);
|
|
6492
|
+
return targets.length === 1 && targets[0].executable && targets[0].path === "." ? [] : targets;
|
|
6493
|
+
}
|
|
6494
|
+
|
|
6495
|
+
// src/swift-compile.ts
|
|
6496
|
+
var run2 = (0, import_node_util2.promisify)(import_node_child_process3.execFile);
|
|
6497
|
+
var WASM_TRIPLE = "wasm32-unknown-wasip1";
|
|
6498
|
+
var cores = import_node_os2.default.availableParallelism();
|
|
6499
|
+
var BUILD_ENV = { ...process.env, BINARYEN_CORES: String(Math.min(4, cores)) };
|
|
6500
|
+
var BUILD_JOBS = String(Math.max(1, Math.floor(cores / 2)));
|
|
6501
|
+
function swiftModuleInputFiles(root) {
|
|
6502
|
+
const files = [
|
|
6503
|
+
"Package.swift",
|
|
6504
|
+
"scripts/contrast-app-Package.swift",
|
|
6505
|
+
"toolchain.json"
|
|
6506
|
+
];
|
|
6507
|
+
const walk = (dir) => {
|
|
6508
|
+
for (const entry of (0, import_node_fs8.readdirSync)(import_node_path8.default.join(root, dir), { withFileTypes: true })) {
|
|
6509
|
+
const relative2 = `${dir}/${entry.name}`;
|
|
6510
|
+
if (entry.isDirectory()) walk(relative2);
|
|
6511
|
+
else if (/\.(swift|c|h)$/.test(entry.name)) files.push(relative2);
|
|
6512
|
+
}
|
|
6513
|
+
};
|
|
6514
|
+
walk("Sources");
|
|
6515
|
+
return files.sort();
|
|
6516
|
+
}
|
|
6517
|
+
async function ensureMacroPlugins(moduleRoot, toolchainBin) {
|
|
6518
|
+
const dir = import_node_path8.default.join(moduleRoot, ".build/host/RnxPreviewMacros");
|
|
6519
|
+
const ext = process.platform === "darwin" ? "dylib" : "so";
|
|
6520
|
+
const plugins = [
|
|
6521
|
+
{
|
|
6522
|
+
library: import_node_path8.default.join(dir, `libRnxPreviewMacros.${ext}`),
|
|
6523
|
+
source: import_node_path8.default.join(moduleRoot, "Sources/RnxPreviewMacros/PreviewMacro.swift")
|
|
6524
|
+
},
|
|
6525
|
+
{
|
|
6526
|
+
library: import_node_path8.default.join(dir, `libFoundationMacros.${ext}`),
|
|
6527
|
+
source: import_node_path8.default.join(moduleRoot, "Sources/FoundationMacros/PredicateMacro.swift")
|
|
6528
|
+
}
|
|
6529
|
+
];
|
|
6530
|
+
const stale = plugins.some(
|
|
6531
|
+
({ library, source }) => !(0, import_node_fs8.existsSync)(library) || (0, import_node_fs8.statSync)(source).mtimeMs > (0, import_node_fs8.statSync)(library).mtimeMs
|
|
6532
|
+
);
|
|
6533
|
+
if (stale) {
|
|
6534
|
+
await run2("sh", [
|
|
6535
|
+
import_node_path8.default.join(moduleRoot, "scripts/build-preview-plugin.sh"),
|
|
6536
|
+
toolchainBin,
|
|
6537
|
+
plugins[0].library
|
|
6538
|
+
]);
|
|
6539
|
+
}
|
|
6540
|
+
return plugins.map(({ library }) => library);
|
|
6541
|
+
}
|
|
6542
|
+
var linkedModuleDigests = /* @__PURE__ */ new Map();
|
|
6543
|
+
function linkedModuleDigest(root) {
|
|
6544
|
+
const files = swiftModuleInputFiles(root);
|
|
6545
|
+
const stampHash = (0, import_node_crypto3.createHash)("sha256");
|
|
6546
|
+
for (const file of files) {
|
|
6547
|
+
const stat2 = (0, import_node_fs8.statSync)(import_node_path8.default.join(root, file), { bigint: true });
|
|
6548
|
+
stampHash.update(file);
|
|
6549
|
+
stampHash.update(
|
|
6550
|
+
`${stat2.dev}:${stat2.ino}:${stat2.size}:${stat2.mtimeNs}:${stat2.ctimeNs}
|
|
6551
|
+
`
|
|
6552
|
+
);
|
|
6553
|
+
}
|
|
6554
|
+
const stamp = stampHash.digest("hex");
|
|
6555
|
+
const cached3 = linkedModuleDigests.get(root);
|
|
6556
|
+
if (cached3?.stamp === stamp) return cached3.digest;
|
|
6557
|
+
const hash = (0, import_node_crypto3.createHash)("sha256");
|
|
6558
|
+
for (const file of files) {
|
|
6559
|
+
hash.update((0, import_node_crypto3.createHash)("sha256").update(file).digest());
|
|
6560
|
+
hash.update(
|
|
6561
|
+
(0, import_node_crypto3.createHash)("sha256").update((0, import_node_fs8.readFileSync)(import_node_path8.default.join(root, file))).digest()
|
|
6562
|
+
);
|
|
6563
|
+
}
|
|
6564
|
+
const digest = hash.digest();
|
|
6565
|
+
linkedModuleDigests.set(root, { stamp, digest });
|
|
6566
|
+
return digest;
|
|
6567
|
+
}
|
|
6568
|
+
function compileTargets(input) {
|
|
6569
|
+
const manifest = input.files["Package.swift"];
|
|
6570
|
+
return manifest === void 0 ? [] : swiftPackagePartition(manifest);
|
|
6571
|
+
}
|
|
6572
|
+
function withNativeSourceGlue(input, glue) {
|
|
6573
|
+
const targets = compileTargets(input);
|
|
6574
|
+
if (targets.length > 1) {
|
|
6575
|
+
throw new Error("swift native modules need one SwiftPM target");
|
|
6576
|
+
}
|
|
6577
|
+
const targetPath = targets[0]?.path === "." ? "" : targets[0]?.path ?? "";
|
|
6578
|
+
return {
|
|
6579
|
+
...input,
|
|
6580
|
+
files: {
|
|
6581
|
+
...input.files,
|
|
6582
|
+
[import_node_path8.default.posix.join(targetPath, "OneNativeSource.generated.swift")]: glue
|
|
6583
|
+
},
|
|
6584
|
+
oneModule: true
|
|
6585
|
+
};
|
|
6586
|
+
}
|
|
6587
|
+
function swiftSiblingDependencies(files, targets) {
|
|
6588
|
+
const names = new Set(targets.map((target) => target.name));
|
|
6589
|
+
const siblings = /* @__PURE__ */ new Map();
|
|
6590
|
+
for (const target of targets) {
|
|
6591
|
+
const prefix = `${target.path}/`;
|
|
6592
|
+
const deps = /* @__PURE__ */ new Set();
|
|
6593
|
+
for (const [file, contents] of Object.entries(files)) {
|
|
6594
|
+
if (file === "Package.swift" || !file.startsWith(prefix)) continue;
|
|
6595
|
+
for (const match of contents.matchAll(
|
|
6596
|
+
/^\s*(?:@\w+(?:\([^)]*\))?\s+)*import\s+(?:(?:typealias|struct|class|enum|protocol|let|var|func)\s+)?([A-Za-z_][A-Za-z0-9_]*)/gm
|
|
6597
|
+
)) {
|
|
6598
|
+
if (names.has(match[1]) && match[1] !== target.name) deps.add(match[1]);
|
|
6599
|
+
}
|
|
6600
|
+
}
|
|
6601
|
+
siblings.set(target.name, [...deps].sort());
|
|
6602
|
+
}
|
|
6603
|
+
return siblings;
|
|
6604
|
+
}
|
|
6605
|
+
var ONE_PRODUCT = '.product(name: "One", package: "sootsim-swift")';
|
|
6606
|
+
var OBJC_IMPLICIT_FLAGS = ', "-Xfrontend", "-import-module", "-Xfrontend", "PeachObjC"';
|
|
6607
|
+
var ONE_IMPLICIT_FLAGS = ', "-Xfrontend", "-import-module", "-Xfrontend", "One"';
|
|
6608
|
+
var MULTI_MANIFEST_VERSION = 6;
|
|
6609
|
+
function swiftArtifactHash(input, release, moduleRoot) {
|
|
6610
|
+
const hash = (0, import_node_crypto3.createHash)("sha256");
|
|
6611
|
+
hash.update(`swift-compile/v6
|
|
6612
|
+
${release}
|
|
6613
|
+
`);
|
|
6614
|
+
if (input.oneModule) hash.update("one-module\n");
|
|
6615
|
+
hash.update(linkedModuleDigest(moduleRoot));
|
|
6616
|
+
for (const file of Object.keys(input.files).sort()) {
|
|
6617
|
+
hash.update((0, import_node_crypto3.createHash)("sha256").update(file).digest());
|
|
6618
|
+
hash.update((0, import_node_crypto3.createHash)("sha256").update(input.files[file]).digest());
|
|
6619
|
+
}
|
|
6620
|
+
for (const base of Object.keys(input.resources ?? {}).sort()) {
|
|
6621
|
+
hash.update((0, import_node_crypto3.createHash)("sha256").update(base).digest());
|
|
6622
|
+
hash.update(
|
|
6623
|
+
(0, import_node_crypto3.createHash)("sha256").update(input.resources?.[base] ?? "").digest()
|
|
6624
|
+
);
|
|
6625
|
+
}
|
|
6626
|
+
for (const name2 of Object.keys(input.images ?? {}).sort()) {
|
|
6627
|
+
const image = input.images?.[name2];
|
|
6628
|
+
if (!image) continue;
|
|
6629
|
+
hash.update((0, import_node_crypto3.createHash)("sha256").update(name2).digest());
|
|
6630
|
+
hash.update((0, import_node_crypto3.createHash)("sha256").update(image.file).digest());
|
|
6631
|
+
hash.update((0, import_node_crypto3.createHash)("sha256").update(image.data).digest());
|
|
6632
|
+
}
|
|
6633
|
+
const targets = compileTargets(input);
|
|
6634
|
+
if (targets.length > 0) {
|
|
6635
|
+
hash.update(`swift-multi/v${MULTI_MANIFEST_VERSION}
|
|
6636
|
+
`);
|
|
6637
|
+
hash.update(
|
|
6638
|
+
JSON.stringify({
|
|
6639
|
+
targets,
|
|
6640
|
+
siblings: [...swiftSiblingDependencies(input.files, targets)].sort(
|
|
6641
|
+
(a, b) => String(a) < String(b) ? -1 : String(a) > String(b) ? 1 : 0
|
|
6642
|
+
)
|
|
6643
|
+
})
|
|
6644
|
+
);
|
|
6645
|
+
}
|
|
6646
|
+
return hash.digest("hex");
|
|
6647
|
+
}
|
|
6648
|
+
function emitSwiftPackageManifest(args) {
|
|
6649
|
+
const { targets, siblings, moduleRoot, oneModule } = args;
|
|
6650
|
+
const executable = targets.find((target) => target.executable);
|
|
6651
|
+
if (!executable) throw new Error("swift-compile: no executable target to emit");
|
|
6652
|
+
const stanza = (target) => {
|
|
6653
|
+
const isolation = target.mainActorIsolation ? " .defaultIsolation(MainActor.self)," : "";
|
|
6654
|
+
const swiftSettings = `swiftSettings: [.swiftLanguageMode(.v${target.languageMode}),${isolation} .unsafeFlags(["-Osize"${OBJC_IMPLICIT_FLAGS}${oneModule ? ONE_IMPLICIT_FLAGS : ""}])]`;
|
|
6655
|
+
const deps = [
|
|
6656
|
+
'.product(name: "SwiftUI", package: "sootsim-swift")',
|
|
6657
|
+
...oneModule ? [ONE_PRODUCT] : [],
|
|
6658
|
+
...(siblings.get(target.name) ?? []).map((sibling) => `"${sibling}"`)
|
|
6659
|
+
].join(", ");
|
|
6660
|
+
const kind = target.executable ? ".executableTarget" : ".target";
|
|
6661
|
+
const link = target.executable ? `,
|
|
6662
|
+
linkerSettings: [
|
|
6663
|
+
.unsafeFlags([
|
|
6664
|
+
"-Xclang-linker", "-mexec-model=reactor",
|
|
6665
|
+
"-Xlinker", "--export-if-defined=__main_argc_argv",
|
|
6666
|
+
]),
|
|
6667
|
+
.unsafeFlags(["-Xlinker", "--strip-all"], .when(configuration: .release)),
|
|
6668
|
+
]` : "";
|
|
6669
|
+
return [
|
|
6670
|
+
` ${kind}(`,
|
|
6671
|
+
` name: "${target.name}",`,
|
|
6672
|
+
` dependencies: [${deps}],`,
|
|
6673
|
+
` path: "${target.path}",`,
|
|
6674
|
+
` ${swiftSettings}${link}`,
|
|
6675
|
+
` ),`
|
|
6676
|
+
].join("\n");
|
|
6677
|
+
};
|
|
6678
|
+
return [
|
|
6679
|
+
"// swift-tools-version: 6.2",
|
|
6680
|
+
"import PackageDescription",
|
|
6681
|
+
"",
|
|
6682
|
+
"// generated by swift-compile from the project package partition.",
|
|
6683
|
+
"let package = Package(",
|
|
6684
|
+
' name: "app",',
|
|
6685
|
+
` products: [.executable(name: "${executable.name}", targets: ["${executable.name}"])],`,
|
|
6686
|
+
` dependencies: [.package(path: "${moduleRoot}")],`,
|
|
6687
|
+
" targets: [",
|
|
6688
|
+
...targets.map(stanza),
|
|
6689
|
+
" ]",
|
|
6690
|
+
")",
|
|
6691
|
+
""
|
|
6692
|
+
].join("\n");
|
|
6693
|
+
}
|
|
6694
|
+
function syncSwiftTree(base, files) {
|
|
6695
|
+
(0, import_node_fs8.mkdirSync)(base, { recursive: true });
|
|
6696
|
+
const walk = (dir) => {
|
|
6697
|
+
for (const entry of (0, import_node_fs8.readdirSync)(dir, { withFileTypes: true })) {
|
|
6698
|
+
const full = import_node_path8.default.join(dir, entry.name);
|
|
6699
|
+
if (dir === base && entry.name === ".build") continue;
|
|
6700
|
+
if (entry.isDirectory()) walk(full);
|
|
6701
|
+
else if (!files.has(full)) (0, import_node_fs8.rmSync)(full, { force: true });
|
|
6702
|
+
}
|
|
6703
|
+
};
|
|
6704
|
+
walk(base);
|
|
6705
|
+
for (const [full, contents] of files) {
|
|
6706
|
+
if ((0, import_node_fs8.existsSync)(full) && (0, import_node_fs8.readFileSync)(full, "utf8") === contents) continue;
|
|
6707
|
+
(0, import_node_fs8.mkdirSync)(import_node_path8.default.dirname(full), { recursive: true });
|
|
6708
|
+
(0, import_node_fs8.writeFileSync)(full, contents, "utf8");
|
|
6709
|
+
}
|
|
6710
|
+
}
|
|
6711
|
+
var DIRECTIVE = /^[ \t]*#(?:if|elseif)\b/;
|
|
6712
|
+
var OS_IOS = /\bos\(\s*iOS\s*\)/g;
|
|
6713
|
+
var OBJC_ATTRIBUTE = /^@(?:objcMembers\b|objc\b(?:(\s*)\(([^()]*)\))?|IBAction\b)/;
|
|
6714
|
+
var SELECTOR = /^#selector\b/;
|
|
6715
|
+
var DELEGATE_CLASS = /^class\s+[A-Za-z_]\w*\s*(?:<[^>{]*>)?\s*:[^{]*\b(?:UIApplicationDelegate|UISceneDelegate|UIWindowSceneDelegate)\b[^{]*\{/;
|
|
6716
|
+
function swiftSourceAsIOS(source) {
|
|
6717
|
+
const { lineStarts, tokens } = swiftCodeScan(source);
|
|
6718
|
+
let offset = 0;
|
|
6719
|
+
const conditioned = source.split("\n").map((line) => {
|
|
6720
|
+
const start = offset;
|
|
6721
|
+
offset += line.length + 1;
|
|
6722
|
+
if (!lineStarts.has(start) || !DIRECTIVE.test(line)) return line;
|
|
6723
|
+
return line.replace(OS_IOS, (match) => "true".padEnd(match.length));
|
|
6724
|
+
}).join("\n");
|
|
6725
|
+
let out = "";
|
|
6726
|
+
let copied = 0;
|
|
6727
|
+
for (const at of tokens) {
|
|
6728
|
+
const rest = conditioned.slice(at, at + 400);
|
|
6729
|
+
if (rest.startsWith("class")) {
|
|
6730
|
+
const modifiers = conditioned.slice(conditioned.lastIndexOf("\n", at - 1) + 1, at);
|
|
6731
|
+
if (DELEGATE_CLASS.test(rest) && !/\b(?:final|open)\b/.test(modifiers)) {
|
|
6732
|
+
out += `${conditioned.slice(copied, at)}final `;
|
|
6733
|
+
copied = at;
|
|
6734
|
+
}
|
|
6735
|
+
continue;
|
|
6736
|
+
}
|
|
6737
|
+
const selector = SELECTOR.exec(rest);
|
|
6738
|
+
const match = selector ?? OBJC_ATTRIBUTE.exec(rest);
|
|
6739
|
+
if (!match) continue;
|
|
6740
|
+
let replacement = "@ObjC";
|
|
6741
|
+
if (selector) replacement = "#Selector";
|
|
6742
|
+
else if (match[0] === "@objcMembers") replacement = "@ObjCMembers";
|
|
6743
|
+
else if (match[0] === "@IBAction") replacement = "@ObjC".padEnd(match[0].length);
|
|
6744
|
+
else if (match[2] !== void 0)
|
|
6745
|
+
replacement = `@ObjC${match[1]}("${match[2].trim()}")`;
|
|
6746
|
+
out += conditioned.slice(copied, at) + replacement;
|
|
6747
|
+
copied = at + match[0].length;
|
|
6748
|
+
}
|
|
6749
|
+
return out + conditioned.slice(copied);
|
|
6750
|
+
}
|
|
6751
|
+
function swiftCodeScan(source) {
|
|
6752
|
+
const starts = /* @__PURE__ */ new Set();
|
|
6753
|
+
const tokens = [];
|
|
6754
|
+
const stack = [{ kind: "code", parens: 0 }];
|
|
6755
|
+
const hashesAt = (at) => {
|
|
6756
|
+
let end = at;
|
|
6757
|
+
while (source[end] === "#") end++;
|
|
6758
|
+
return end - at;
|
|
6759
|
+
};
|
|
6760
|
+
const closes = (at, hashes) => source.startsWith("#".repeat(hashes), at);
|
|
6761
|
+
let i = 0;
|
|
6762
|
+
while (i < source.length) {
|
|
6763
|
+
const top = stack[stack.length - 1];
|
|
6764
|
+
if ((i === 0 || source[i - 1] === "\n") && top.kind === "code" && stack.length === 1)
|
|
6765
|
+
starts.add(i);
|
|
6766
|
+
const char = source[i];
|
|
6767
|
+
if (top.kind === "block") {
|
|
6768
|
+
if (source.startsWith("/*", i)) {
|
|
6769
|
+
top.depth++;
|
|
6770
|
+
i += 2;
|
|
6771
|
+
} else if (source.startsWith("*/", i)) {
|
|
6772
|
+
if (--top.depth === 0) stack.pop();
|
|
6773
|
+
i += 2;
|
|
6774
|
+
} else i++;
|
|
6775
|
+
continue;
|
|
6776
|
+
}
|
|
6777
|
+
if (top.kind === "string") {
|
|
6778
|
+
if (char === "\\" && closes(i + 1, top.hashes)) {
|
|
6779
|
+
const after = i + 1 + top.hashes;
|
|
6780
|
+
if (source[after] === "(") {
|
|
6781
|
+
stack.push({ kind: "code", parens: 0 });
|
|
6782
|
+
i = after + 1;
|
|
6783
|
+
} else i = after + 1;
|
|
6784
|
+
continue;
|
|
6785
|
+
}
|
|
6786
|
+
const quote = top.multiline ? '"""' : '"';
|
|
6787
|
+
if (source.startsWith(quote, i) && closes(i + quote.length, top.hashes)) {
|
|
6788
|
+
stack.pop();
|
|
6789
|
+
i += quote.length + top.hashes;
|
|
6790
|
+
} else i++;
|
|
6791
|
+
continue;
|
|
6792
|
+
}
|
|
6793
|
+
if (top.kind === "regex") {
|
|
6794
|
+
if (char === "/" && closes(i + 1, top.hashes)) {
|
|
6795
|
+
stack.pop();
|
|
6796
|
+
i += 1 + top.hashes;
|
|
6797
|
+
} else i++;
|
|
6798
|
+
continue;
|
|
6799
|
+
}
|
|
6800
|
+
if (source.startsWith("//", i)) {
|
|
6801
|
+
const end = source.indexOf("\n", i);
|
|
6802
|
+
i = end === -1 ? source.length : end;
|
|
6803
|
+
} else if (source.startsWith("/*", i)) {
|
|
6804
|
+
stack.push({ kind: "block", depth: 1 });
|
|
6805
|
+
i += 2;
|
|
6806
|
+
} else if (char === '"' || char === "#") {
|
|
6807
|
+
const hashes = hashesAt(i);
|
|
6808
|
+
const at = i + hashes;
|
|
6809
|
+
if (source.startsWith('"""', at)) {
|
|
6810
|
+
stack.push({ kind: "string", hashes, multiline: true });
|
|
6811
|
+
i = at + 3;
|
|
6812
|
+
} else if (source[at] === '"') {
|
|
6813
|
+
stack.push({ kind: "string", hashes, multiline: false });
|
|
6814
|
+
i = at + 1;
|
|
6815
|
+
} else if (hashes > 0 && source[at] === "/") {
|
|
6816
|
+
stack.push({ kind: "regex", hashes });
|
|
6817
|
+
i = at + 1;
|
|
6818
|
+
} else {
|
|
6819
|
+
if (hashes > 0) tokens.push(at - 1);
|
|
6820
|
+
i = Math.max(at, i + 1);
|
|
6821
|
+
}
|
|
6822
|
+
} else if (char === "(") {
|
|
6823
|
+
top.parens++;
|
|
6824
|
+
i++;
|
|
6825
|
+
} else if (char === ")") {
|
|
6826
|
+
if (top.parens === 0 && stack.length > 1) stack.pop();
|
|
6827
|
+
else top.parens--;
|
|
6828
|
+
i++;
|
|
6829
|
+
} else if (source.startsWith("class", i) && !/[\w$]/.test(source[i - 1] ?? "") && !/[\w$]/.test(source[i + 5] ?? "")) {
|
|
6830
|
+
tokens.push(i);
|
|
6831
|
+
i += 5;
|
|
6832
|
+
} else {
|
|
6833
|
+
if (char === "@") tokens.push(i);
|
|
6834
|
+
i++;
|
|
6835
|
+
}
|
|
6836
|
+
}
|
|
6837
|
+
return { lineStarts: starts, tokens };
|
|
6838
|
+
}
|
|
6839
|
+
var compiledSource = (file, contents) => file.endsWith(".swift") ? swiftSourceAsIOS(contents) : contents;
|
|
6840
|
+
function writeSwiftProject(layout, input, moduleRoot) {
|
|
6841
|
+
const targets = compileTargets(input);
|
|
6842
|
+
const files = /* @__PURE__ */ new Map();
|
|
6843
|
+
const moduleFiles = `
|
|
6844
|
+
// sootsim-swift files ${(0, import_node_crypto3.createHash)("sha256").update(swiftModuleInputFiles(moduleRoot).join("\n")).digest("hex").slice(0, 16)}
|
|
6845
|
+
`;
|
|
6846
|
+
if (targets.length === 0) {
|
|
6847
|
+
for (const [file, contents] of Object.entries(input.files)) {
|
|
6848
|
+
if (file === "Package.swift") continue;
|
|
6849
|
+
files.set(import_node_path8.default.join(layout.sources, file), compiledSource(file, contents));
|
|
6850
|
+
}
|
|
6851
|
+
let manifest = (0, import_node_fs8.readFileSync)(
|
|
6852
|
+
import_node_path8.default.join(moduleRoot, "scripts/contrast-app-Package.swift"),
|
|
6853
|
+
"utf8"
|
|
6854
|
+
).replaceAll("__SOOTSIM_SWIFT_PACKAGE__", moduleRoot);
|
|
6855
|
+
if (input.oneModule) {
|
|
6856
|
+
const product = '.product(name: "CoreLocation", package: "sootsim-swift"),';
|
|
6857
|
+
const flags = `"-Osize"${OBJC_IMPLICIT_FLAGS}`;
|
|
6858
|
+
if (!manifest.includes(product) || !manifest.includes(flags)) {
|
|
6859
|
+
throw new Error(
|
|
6860
|
+
"scripts/contrast-app-Package.swift lost the lines the One module links at"
|
|
6861
|
+
);
|
|
6862
|
+
}
|
|
6863
|
+
manifest = manifest.replace(product, `${product}
|
|
6864
|
+
${ONE_PRODUCT},`).replace(flags, `${flags}${ONE_IMPLICIT_FLAGS}`);
|
|
6865
|
+
}
|
|
6866
|
+
files.set(import_node_path8.default.join(layout.root, "Package.swift"), manifest + moduleFiles);
|
|
6867
|
+
} else {
|
|
6868
|
+
for (const [file, contents] of Object.entries(input.files)) {
|
|
6869
|
+
if (file === "Package.swift") continue;
|
|
6870
|
+
files.set(import_node_path8.default.join(layout.root, file), compiledSource(file, contents));
|
|
6871
|
+
}
|
|
6872
|
+
for (const target of targets) {
|
|
6873
|
+
if (!target.resources) continue;
|
|
6874
|
+
files.set(
|
|
6875
|
+
import_node_path8.default.join(layout.root, target.path, "ResourceBundleAccessor.generated.swift"),
|
|
6876
|
+
[
|
|
6877
|
+
"import Foundation",
|
|
6878
|
+
"",
|
|
6879
|
+
"extension Foundation.Bundle {",
|
|
6880
|
+
" static let module: Bundle = Bundle.main",
|
|
6881
|
+
"}",
|
|
6882
|
+
""
|
|
6883
|
+
].join("\n")
|
|
6884
|
+
);
|
|
6885
|
+
}
|
|
6886
|
+
files.set(
|
|
6887
|
+
import_node_path8.default.join(layout.root, "Package.swift"),
|
|
6888
|
+
emitSwiftPackageManifest({
|
|
6889
|
+
targets,
|
|
6890
|
+
siblings: swiftSiblingDependencies(input.files, targets),
|
|
6891
|
+
moduleRoot,
|
|
6892
|
+
oneModule: input.oneModule
|
|
6893
|
+
}) + moduleFiles
|
|
6894
|
+
);
|
|
6895
|
+
}
|
|
6896
|
+
syncSwiftTree(layout.root, files);
|
|
6897
|
+
}
|
|
6898
|
+
function streamText(value) {
|
|
6899
|
+
if (typeof value === "string") return value.trim();
|
|
6900
|
+
if (Buffer.isBuffer(value)) return value.toString("utf8").trim();
|
|
6901
|
+
return "";
|
|
6902
|
+
}
|
|
6903
|
+
function outputOf(error) {
|
|
6904
|
+
if (error && typeof error === "object") {
|
|
6905
|
+
const streams = [
|
|
6906
|
+
streamText(Reflect.get(error, "stdout")),
|
|
6907
|
+
streamText(Reflect.get(error, "stderr"))
|
|
6908
|
+
].filter(Boolean);
|
|
6909
|
+
if (streams.length > 0) return streams.join("\n");
|
|
6910
|
+
}
|
|
6911
|
+
return error instanceof Error ? error.message : String(error);
|
|
6912
|
+
}
|
|
6913
|
+
function builtArtifact(layout) {
|
|
6914
|
+
const binDir = import_node_path8.default.join(layout.root, ".build", WASM_TRIPLE, "release");
|
|
6915
|
+
const manifest = (0, import_node_fs8.readFileSync)(import_node_path8.default.join(layout.root, "Package.swift"), "utf8");
|
|
6916
|
+
const executable = swiftManifestTargets(manifest).find((target) => target.executable);
|
|
6917
|
+
if (executable === void 0) {
|
|
6918
|
+
throw new Error("swift-compile: the written manifest names no executable target");
|
|
6919
|
+
}
|
|
6920
|
+
const file = import_node_path8.default.join(binDir, `${executable.name}.wasm`);
|
|
6921
|
+
if (!(0, import_node_fs8.existsSync)(file)) {
|
|
6922
|
+
const found = (0, import_node_fs8.existsSync)(binDir) ? (0, import_node_fs8.readdirSync)(binDir).filter((name2) => name2.endsWith(".wasm")).sort() : [];
|
|
6923
|
+
throw new Error(
|
|
6924
|
+
`swift-compile: the build produced no ${executable.name}.wasm (found: ${found.join(", ") || "none"})`
|
|
6925
|
+
);
|
|
6926
|
+
}
|
|
6927
|
+
return file;
|
|
6928
|
+
}
|
|
6929
|
+
function projectDiagnostic(output, layout) {
|
|
6930
|
+
const base = layout.multi ? layout.root : layout.sources;
|
|
6931
|
+
const prefix = `${base}${import_node_path8.default.sep}`;
|
|
6932
|
+
return output.split("\n").map((line) => line.startsWith(prefix) ? line.slice(prefix.length) : line).join("\n").trim();
|
|
6933
|
+
}
|
|
6934
|
+
var ROOT_LOCKS = Symbol.for("peachsim.swiftCompile.rootLocks");
|
|
6935
|
+
var host = globalThis;
|
|
6936
|
+
var rootLocks = host[ROOT_LOCKS] ??= /* @__PURE__ */ new Map();
|
|
6937
|
+
function serialize(root, work) {
|
|
6938
|
+
const current = rootLocks.get(root) ?? Promise.resolve();
|
|
6939
|
+
const next = current.then(work, work);
|
|
6940
|
+
rootLocks.set(
|
|
6941
|
+
root,
|
|
6942
|
+
next.catch(() => {
|
|
6943
|
+
})
|
|
6944
|
+
);
|
|
6945
|
+
return next;
|
|
6946
|
+
}
|
|
6947
|
+
function compileSwiftProjectUnit(input, options) {
|
|
6948
|
+
(0, import_node_fs8.mkdirSync)(options.buildRoot, { recursive: true });
|
|
6949
|
+
const root = (0, import_node_fs8.realpathSync)(options.buildRoot);
|
|
6950
|
+
const moduleRoot = import_node_path8.default.resolve(options.moduleRoot);
|
|
6951
|
+
const layout = {
|
|
6952
|
+
root,
|
|
6953
|
+
sources: import_node_path8.default.join(root, "Sources", "App"),
|
|
6954
|
+
multi: compileTargets(input).length > 0
|
|
6955
|
+
};
|
|
6956
|
+
const hash = swiftArtifactHash(input, options.release, moduleRoot);
|
|
6957
|
+
return serialize(root, async () => {
|
|
6958
|
+
writeSwiftProject(layout, input, moduleRoot);
|
|
6959
|
+
const swift = import_node_path8.default.join(options.toolchainBin, "swift");
|
|
6960
|
+
if (!(0, import_node_fs8.existsSync)(swift)) {
|
|
6961
|
+
throw new Error(
|
|
6962
|
+
`swift-compile: no swift.org toolchain at ${options.toolchainBin}; install ${options.release} and its matching wasm sdk`
|
|
6963
|
+
);
|
|
6964
|
+
}
|
|
6965
|
+
const macroPlugins = await ensureMacroPlugins(moduleRoot, options.toolchainBin);
|
|
6966
|
+
const icu = swiftIcuAsset(options.toolchainBin, options.release);
|
|
6967
|
+
try {
|
|
6968
|
+
await run2(
|
|
6969
|
+
swift,
|
|
6970
|
+
[
|
|
6971
|
+
"build",
|
|
6972
|
+
"-j",
|
|
6973
|
+
BUILD_JOBS,
|
|
6974
|
+
"--package-path",
|
|
6975
|
+
root,
|
|
6976
|
+
"--swift-sdk",
|
|
6977
|
+
`${options.release}_wasm`,
|
|
6978
|
+
"-c",
|
|
6979
|
+
"release",
|
|
6980
|
+
"-Xswiftc",
|
|
6981
|
+
"-Osize",
|
|
6982
|
+
...macroPlugins.flatMap((plugin) => [
|
|
6983
|
+
"-Xswiftc",
|
|
6984
|
+
"-load-plugin-library",
|
|
6985
|
+
"-Xswiftc",
|
|
6986
|
+
plugin
|
|
6987
|
+
])
|
|
6988
|
+
],
|
|
6989
|
+
{ env: BUILD_ENV, maxBuffer: 64 * 1024 * 1024, timeout: options.timeoutMs }
|
|
6990
|
+
);
|
|
6991
|
+
} catch (error) {
|
|
6992
|
+
throw new Error(projectDiagnostic(outputOf(error), layout), { cause: error });
|
|
6993
|
+
}
|
|
6994
|
+
return {
|
|
6995
|
+
hash,
|
|
6996
|
+
bytes: (0, import_node_fs8.readFileSync)(builtArtifact(layout)),
|
|
6997
|
+
icu: await icu
|
|
6998
|
+
};
|
|
6999
|
+
});
|
|
7000
|
+
}
|
|
7001
|
+
|
|
7002
|
+
// src/swift-submit.ts
|
|
7003
|
+
var SWIFT_COMPILE_PATH = "/api/swift-compile";
|
|
7004
|
+
var MAX_SWIFT_COMPILE_FILES = 256;
|
|
7005
|
+
var MAX_SWIFT_COMPILE_SOURCE_BYTES = 2 * 1024 * 1024;
|
|
7006
|
+
var MAX_SWIFT_COMPILE_RESOURCES = 128;
|
|
7007
|
+
var MAX_SWIFT_COMPILE_RESOURCE_BYTES = 2 * 1024 * 1024;
|
|
7008
|
+
var MAX_SWIFT_COMPILE_RESOURCE_TOTAL_BYTES = 8 * 1024 * 1024;
|
|
7009
|
+
var MAX_SWIFT_COMPILE_IMAGES = 128;
|
|
7010
|
+
var MAX_SWIFT_COMPILE_IMAGE_BYTES = 4 * 1024 * 1024;
|
|
7011
|
+
var MAX_SWIFT_COMPILE_IMAGE_TOTAL_BYTES = 16 * 1024 * 1024;
|
|
7012
|
+
var SWIFT_HOST_ABI = 3;
|
|
7013
|
+
var POLL_INTERVAL_MS = 1500;
|
|
7014
|
+
function httpSwiftCompileSubmit(context) {
|
|
7015
|
+
const { assetReadToken, authorization, endpoint } = context;
|
|
7016
|
+
if (!assetReadToken && !authorization) return void 0;
|
|
7017
|
+
const url = endpoint ? `${endpoint.replace(/\/+$/, "")}${SWIFT_COMPILE_PATH}` : SWIFT_COMPILE_PATH;
|
|
7018
|
+
return async (work) => {
|
|
7019
|
+
let response;
|
|
7020
|
+
try {
|
|
7021
|
+
response = await fetch(url, {
|
|
7022
|
+
method: "POST",
|
|
7023
|
+
signal: context.signal,
|
|
7024
|
+
headers: {
|
|
7025
|
+
"content-type": "application/json",
|
|
7026
|
+
...authorization ? { authorization } : {}
|
|
7027
|
+
},
|
|
7028
|
+
body: JSON.stringify({
|
|
7029
|
+
...work,
|
|
7030
|
+
hostAbi: SWIFT_HOST_ABI,
|
|
7031
|
+
...assetReadToken ? { token: assetReadToken } : {}
|
|
7032
|
+
})
|
|
7033
|
+
});
|
|
7034
|
+
} catch (error) {
|
|
7035
|
+
throw new Error(
|
|
7036
|
+
`contrast-bundler: fetch failed for ${url} while compiling ${work.entry}: ${error instanceof Error ? error.message : String(error)}`,
|
|
7037
|
+
{ cause: error }
|
|
7038
|
+
);
|
|
7039
|
+
}
|
|
7040
|
+
if (!response.ok) {
|
|
7041
|
+
const detail = (await response.text()).trim();
|
|
7042
|
+
throw new Error(
|
|
7043
|
+
`contrast-bundler: the swift compile for ${work.entry} answered ${response.status}${detail ? `: ${detail}` : ""}`
|
|
7044
|
+
);
|
|
7045
|
+
}
|
|
7046
|
+
const outcome = await response.json();
|
|
7047
|
+
if (!isSwiftCompileOutcome(outcome)) {
|
|
7048
|
+
throw new Error("swift compile: the service returned invalid artifact metadata");
|
|
7049
|
+
}
|
|
7050
|
+
return outcome;
|
|
7051
|
+
};
|
|
7052
|
+
}
|
|
7053
|
+
function isRecord3(value) {
|
|
7054
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7055
|
+
}
|
|
7056
|
+
function isSwiftNativeModules(value) {
|
|
7057
|
+
return isRecord3(value) && typeof value.packageId === "string" && typeof value.hash === "string" && isRecord3(value.files) && isRecord3(value.modules) && [...Object.values(value.files), ...Object.values(value.modules)].every(
|
|
7058
|
+
(names) => Array.isArray(names) && names.every((name2) => typeof name2 === "string")
|
|
7059
|
+
) && Array.isArray(value.defaultViewFiles) && value.defaultViewFiles.every((file) => typeof file === "string");
|
|
7060
|
+
}
|
|
7061
|
+
function isSwiftCompileOutcome(value) {
|
|
7062
|
+
if (!isRecord3(value)) return false;
|
|
7063
|
+
switch (value.status) {
|
|
7064
|
+
case "published":
|
|
7065
|
+
return typeof value.artifactUrl === "string" && typeof value.icuUrl === "string" && typeof value.hash === "string" && /^[a-f0-9]{64}$/.test(value.hash) && (value.imageUrls === void 0 || isRecord3(value.imageUrls) && Object.values(value.imageUrls).every((url) => typeof url === "string")) && (value.native === void 0 || isSwiftNativeModules(value.native));
|
|
7066
|
+
case "compiling":
|
|
7067
|
+
return typeof value.hash === "string" && /^[a-f0-9]{64}$/.test(value.hash);
|
|
7068
|
+
case "refused":
|
|
7069
|
+
case "failed":
|
|
7070
|
+
return typeof value.detail === "string";
|
|
7071
|
+
default:
|
|
7072
|
+
return false;
|
|
7073
|
+
}
|
|
7074
|
+
}
|
|
7075
|
+
function compileAssetUrl(value, origin) {
|
|
7076
|
+
const url = new URL(value, origin);
|
|
7077
|
+
if (url.protocol !== "http:" && url.protocol !== "https:" || url.username || url.password || url.origin !== new URL(origin).origin) {
|
|
7078
|
+
throw new Error("swift compile: artifact address escapes the compile origin");
|
|
7079
|
+
}
|
|
7080
|
+
return url.href;
|
|
7081
|
+
}
|
|
7082
|
+
function resolveImageUrls(urls, origin) {
|
|
7083
|
+
const resolved = {};
|
|
7084
|
+
for (const [name2, url] of Object.entries(urls)) {
|
|
7085
|
+
resolved[name2] = compileAssetUrl(url, origin);
|
|
7086
|
+
}
|
|
7087
|
+
return resolved;
|
|
7088
|
+
}
|
|
7089
|
+
async function compileSwiftProject(submit, work, origin, signal) {
|
|
7090
|
+
while (true) {
|
|
7091
|
+
signal?.throwIfAborted();
|
|
7092
|
+
const outcome = await submit(work);
|
|
7093
|
+
switch (outcome.status) {
|
|
7094
|
+
case "published":
|
|
7095
|
+
return {
|
|
7096
|
+
url: compileAssetUrl(outcome.artifactUrl, origin),
|
|
7097
|
+
hash: outcome.hash,
|
|
7098
|
+
icuUrl: compileAssetUrl(outcome.icuUrl, origin),
|
|
7099
|
+
...outcome.imageUrls === void 0 ? {} : { imageUrls: resolveImageUrls(outcome.imageUrls, origin) },
|
|
7100
|
+
...outcome.native === void 0 ? {} : { native: outcome.native }
|
|
7101
|
+
};
|
|
7102
|
+
case "compiling":
|
|
7103
|
+
await new Promise((resolve5, reject) => {
|
|
7104
|
+
const finish = () => {
|
|
7105
|
+
signal?.removeEventListener("abort", abort);
|
|
7106
|
+
resolve5();
|
|
7107
|
+
};
|
|
7108
|
+
const timer = setTimeout(finish, POLL_INTERVAL_MS);
|
|
7109
|
+
const abort = () => {
|
|
7110
|
+
clearTimeout(timer);
|
|
7111
|
+
signal?.removeEventListener("abort", abort);
|
|
7112
|
+
const reason = signal?.reason;
|
|
7113
|
+
reject(reason instanceof Error ? reason : new Error(String(reason)));
|
|
7114
|
+
};
|
|
7115
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
7116
|
+
if (signal?.aborted) abort();
|
|
7117
|
+
});
|
|
7118
|
+
continue;
|
|
7119
|
+
case "refused":
|
|
7120
|
+
case "failed":
|
|
7121
|
+
throw new Error(
|
|
7122
|
+
`contrast-bundler: the swift sources for ${work.entry} cannot be compiled: ${outcome.detail}`
|
|
7123
|
+
);
|
|
7124
|
+
}
|
|
7125
|
+
}
|
|
7126
|
+
}
|
|
7127
|
+
|
|
7128
|
+
// src/swift-host.ts
|
|
7129
|
+
var ARTIFACT_PATH = "/__peach/swift/";
|
|
7130
|
+
var RESOURCE_PATH = "/__peach/swift-res/";
|
|
7131
|
+
var ICU_PATH = "/__peach/swift-icu/";
|
|
7132
|
+
var SKIP_SOURCE_DIRS = /* @__PURE__ */ new Set([
|
|
7133
|
+
"node_modules",
|
|
7134
|
+
"ios",
|
|
7135
|
+
"android",
|
|
7136
|
+
"dist",
|
|
7137
|
+
"types",
|
|
7138
|
+
"build"
|
|
7139
|
+
]);
|
|
7140
|
+
var NATIVE_DESCRIPTOR = ".one-native-source.json";
|
|
7141
|
+
var NATIVE_GLUE = ".one-native-source.swift.txt";
|
|
7142
|
+
function swiftPackageId(packagePath) {
|
|
7143
|
+
return import_node_path9.default.basename(packagePath).replace(/[^A-Za-z0-9_]/g, "_").replace(/^(\d)/, "_$1");
|
|
7144
|
+
}
|
|
7145
|
+
function nativeSourceDescriptor(packagePath) {
|
|
7146
|
+
packagePath = import_node_fs9.default.realpathSync(packagePath);
|
|
7147
|
+
const file = import_node_path9.default.join(packagePath, NATIVE_DESCRIPTOR);
|
|
7148
|
+
if (!import_node_fs9.default.existsSync(file)) return null;
|
|
7149
|
+
const value = JSON.parse(
|
|
7150
|
+
readPackageFile(packagePath, file, MAX_SWIFT_COMPILE_SOURCE_BYTES).toString("utf8")
|
|
7151
|
+
);
|
|
7152
|
+
const invalid = () => new Error(`${file}: invalid One native source descriptor; run one typegen`);
|
|
7153
|
+
if (!value || typeof value !== "object" || Reflect.get(value, "generatedBy") !== "one typegen" || !import_node_fs9.default.existsSync(import_node_path9.default.join(packagePath, NATIVE_GLUE))) {
|
|
7154
|
+
throw invalid();
|
|
7155
|
+
}
|
|
7156
|
+
if (!isSwiftNativeModules(value) || value.packageId !== swiftPackageId(packagePath)) {
|
|
7157
|
+
throw invalid();
|
|
7158
|
+
}
|
|
7159
|
+
return value;
|
|
7160
|
+
}
|
|
7161
|
+
var projects = /* @__PURE__ */ new Map();
|
|
7162
|
+
function projectFor(packagePath, hosted) {
|
|
7163
|
+
packagePath = import_node_fs9.default.realpathSync(packagePath);
|
|
7164
|
+
const existing = projects.get(packagePath);
|
|
7165
|
+
if (existing) {
|
|
7166
|
+
if (hosted && !existing.hosted) {
|
|
7167
|
+
throw new Error("a Swift package cannot share local and hosted compile ownership");
|
|
7168
|
+
}
|
|
7169
|
+
return existing;
|
|
7170
|
+
}
|
|
7171
|
+
const created = {
|
|
7172
|
+
packagePath,
|
|
7173
|
+
artifact: null,
|
|
7174
|
+
building: null,
|
|
7175
|
+
resourceFiles: /* @__PURE__ */ new Map(),
|
|
7176
|
+
resourcesPrevious: /* @__PURE__ */ new Map(),
|
|
7177
|
+
artifacts: [],
|
|
7178
|
+
hosted
|
|
7179
|
+
};
|
|
7180
|
+
projects.set(packagePath, created);
|
|
7181
|
+
return created;
|
|
7182
|
+
}
|
|
7183
|
+
function packageFiles(root) {
|
|
7184
|
+
const canonicalRoot = import_node_fs9.default.realpathSync(root);
|
|
7185
|
+
const found = [];
|
|
7186
|
+
const walk = (dir) => {
|
|
7187
|
+
for (const entry of import_node_fs9.default.readdirSync(dir, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name))) {
|
|
7188
|
+
if (entry.name.startsWith(".") && entry.name !== NATIVE_DESCRIPTOR && entry.name !== NATIVE_GLUE || SKIP_SOURCE_DIRS.has(entry.name))
|
|
7189
|
+
continue;
|
|
7190
|
+
const full = import_node_path9.default.join(dir, entry.name);
|
|
7191
|
+
if (entry.isSymbolicLink()) throw new Error(`swift input is a symlink: ${full}`);
|
|
7192
|
+
const real = import_node_fs9.default.realpathSync(full);
|
|
7193
|
+
const relative2 = import_node_path9.default.relative(canonicalRoot, real);
|
|
7194
|
+
if (relative2.startsWith(`..${import_node_path9.default.sep}`) || relative2 === ".." || import_node_path9.default.isAbsolute(relative2)) {
|
|
7195
|
+
throw new Error(`swift input escapes the selected package: ${full}`);
|
|
7196
|
+
}
|
|
7197
|
+
if (entry.isDirectory()) {
|
|
7198
|
+
if (import_node_fs9.default.existsSync(import_node_path9.default.join(full, "Package.swift"))) continue;
|
|
7199
|
+
walk(full);
|
|
7200
|
+
} else if (entry.isFile()) {
|
|
7201
|
+
found.push(full);
|
|
7202
|
+
if (found.length > 4096) throw new Error("swift package exceeds 4096 input files");
|
|
7203
|
+
}
|
|
7204
|
+
}
|
|
7205
|
+
};
|
|
7206
|
+
walk(canonicalRoot);
|
|
7207
|
+
return found;
|
|
7208
|
+
}
|
|
7209
|
+
function readPackageFile(root, file, maxBytes) {
|
|
7210
|
+
const canonicalRoot = import_node_fs9.default.realpathSync(root);
|
|
7211
|
+
const relative2 = import_node_path9.default.relative(canonicalRoot, import_node_fs9.default.realpathSync(file));
|
|
7212
|
+
if (relative2 === ".." || relative2.startsWith(`..${import_node_path9.default.sep}`) || import_node_path9.default.isAbsolute(relative2)) {
|
|
7213
|
+
throw new Error(`swift input escapes the selected package: ${file}`);
|
|
7214
|
+
}
|
|
7215
|
+
let ancestor = import_node_path9.default.resolve(file);
|
|
7216
|
+
while (ancestor !== canonicalRoot) {
|
|
7217
|
+
if (import_node_fs9.default.lstatSync(ancestor).isSymbolicLink()) {
|
|
7218
|
+
throw new Error(`swift input is a symlink: ${ancestor}`);
|
|
7219
|
+
}
|
|
7220
|
+
const parent = import_node_path9.default.dirname(ancestor);
|
|
7221
|
+
if (parent === ancestor)
|
|
7222
|
+
throw new Error(`swift input escapes the selected package: ${file}`);
|
|
7223
|
+
ancestor = parent;
|
|
7224
|
+
}
|
|
7225
|
+
const expected = import_node_fs9.default.statSync(file);
|
|
7226
|
+
const fd = import_node_fs9.default.openSync(file, import_node_fs9.default.constants.O_RDONLY | import_node_fs9.default.constants.O_NOFOLLOW);
|
|
7227
|
+
try {
|
|
7228
|
+
const stat2 = import_node_fs9.default.fstatSync(fd);
|
|
7229
|
+
if (stat2.dev !== expected.dev || stat2.ino !== expected.ino) {
|
|
7230
|
+
throw new Error(`swift input changed while opening: ${file}`);
|
|
7231
|
+
}
|
|
7232
|
+
if (!stat2.isFile() || stat2.size > maxBytes) {
|
|
7233
|
+
throw new Error(`swift input exceeds ${maxBytes} bytes: ${file}`);
|
|
7234
|
+
}
|
|
7235
|
+
const bytes = Buffer.alloc(stat2.size + 1);
|
|
7236
|
+
let offset = 0;
|
|
7237
|
+
while (offset < bytes.length) {
|
|
7238
|
+
const count = import_node_fs9.default.readSync(fd, bytes, offset, bytes.length - offset, null);
|
|
7239
|
+
if (count === 0) break;
|
|
7240
|
+
offset += count;
|
|
7241
|
+
}
|
|
7242
|
+
if (offset !== stat2.size || import_node_fs9.default.fstatSync(fd).size !== stat2.size) {
|
|
7243
|
+
throw new Error(`swift input changed while reading: ${file}`);
|
|
7244
|
+
}
|
|
7245
|
+
return bytes.subarray(0, offset);
|
|
7246
|
+
} finally {
|
|
7247
|
+
import_node_fs9.default.closeSync(fd);
|
|
7248
|
+
}
|
|
7249
|
+
}
|
|
7250
|
+
function sourceFiles(root) {
|
|
7251
|
+
const files = packageFiles(root).filter((file) => file.endsWith(".swift"));
|
|
7252
|
+
if (files.length > MAX_SWIFT_COMPILE_FILES || files.reduce((total, file) => total + import_node_fs9.default.statSync(file).size, 0) > MAX_SWIFT_COMPILE_SOURCE_BYTES) {
|
|
7253
|
+
throw new Error("swift sources exceed the compile service caps");
|
|
7254
|
+
}
|
|
7255
|
+
return files;
|
|
7256
|
+
}
|
|
7257
|
+
function resourceCandidateFiles(root) {
|
|
7258
|
+
return packageFiles(root).filter((file) => !file.endsWith(".swift"));
|
|
7259
|
+
}
|
|
7260
|
+
var RESOURCE_CONTENT_TYPES = {
|
|
7261
|
+
".avif": "image/avif",
|
|
7262
|
+
".bmp": "image/bmp",
|
|
7263
|
+
".gif": "image/gif",
|
|
7264
|
+
".ico": "image/x-icon",
|
|
7265
|
+
".jpeg": "image/jpeg",
|
|
7266
|
+
".jpg": "image/jpeg",
|
|
7267
|
+
".png": "image/png",
|
|
7268
|
+
".webp": "image/webp"
|
|
7269
|
+
};
|
|
7270
|
+
function buildSwiftResourceTable(project, baseUrl) {
|
|
7271
|
+
const absolute = resourceCandidateFiles(project.packagePath);
|
|
7272
|
+
const relative2 = absolute.map(
|
|
7273
|
+
(file) => import_node_path9.default.relative(project.packagePath, file).split(import_node_path9.default.sep).join(import_node_path9.default.posix.sep)
|
|
7274
|
+
);
|
|
7275
|
+
const byRelative = new Map(absolute.map((file, index) => [relative2[index], file]));
|
|
7276
|
+
const readContents = (candidate) => {
|
|
7277
|
+
const file = byRelative.get(candidate);
|
|
7278
|
+
if (!file || !/(^|\/)Contents\.json$|\.symbolset\/[^/]+\.svg$/.test(candidate))
|
|
7279
|
+
return null;
|
|
7280
|
+
return readPackageFile(
|
|
7281
|
+
project.packagePath,
|
|
7282
|
+
file,
|
|
7283
|
+
MAX_SWIFT_COMPILE_RESOURCE_BYTES
|
|
7284
|
+
).toString("utf8");
|
|
7285
|
+
};
|
|
7286
|
+
const found = enumerateBundleImages(relative2, readContents);
|
|
7287
|
+
const colors = enumerateBundleColors(relative2, readContents);
|
|
7288
|
+
const symbols = enumerateBundleSymbols(relative2, readContents);
|
|
7289
|
+
const table = {};
|
|
7290
|
+
const images = {};
|
|
7291
|
+
const watched = [];
|
|
7292
|
+
const registered = /* @__PURE__ */ new Map();
|
|
7293
|
+
let imageBytes = 0;
|
|
7294
|
+
for (const { name: name2, file, scale } of found) {
|
|
7295
|
+
const disk = byRelative.get(file);
|
|
7296
|
+
if (!disk) continue;
|
|
7297
|
+
if (Object.keys(images).length >= MAX_SWIFT_COMPILE_IMAGES || imageBytes + import_node_fs9.default.statSync(disk).size > MAX_SWIFT_COMPILE_IMAGE_TOTAL_BYTES) {
|
|
7298
|
+
throw new Error("swift image pack exceeds the compile service caps");
|
|
7299
|
+
}
|
|
7300
|
+
const bytes = readPackageFile(
|
|
7301
|
+
project.packagePath,
|
|
7302
|
+
disk,
|
|
7303
|
+
MAX_SWIFT_COMPILE_IMAGE_BYTES
|
|
7304
|
+
);
|
|
7305
|
+
imageBytes += bytes.length;
|
|
7306
|
+
const hash = (0, import_node_crypto4.createHash)("sha256").update(bytes).digest("hex").slice(0, 16);
|
|
7307
|
+
const ext = import_node_path9.default.posix.extname(file).toLowerCase();
|
|
7308
|
+
table[name2] = { uri: `${baseUrl}${RESOURCE_PATH}${hash}${ext}`, scale };
|
|
7309
|
+
images[name2] = {
|
|
7310
|
+
file: import_node_path9.default.posix.basename(file),
|
|
7311
|
+
data: bytes.toString("base64")
|
|
7312
|
+
};
|
|
7313
|
+
watched.push(file);
|
|
7314
|
+
const contents = file.replace(/\/[^/]+$/, "/Contents.json");
|
|
7315
|
+
if (byRelative.has(contents)) watched.push(contents);
|
|
7316
|
+
registered.set(`${hash}${ext}`, {
|
|
7317
|
+
bytes,
|
|
7318
|
+
contentType: RESOURCE_CONTENT_TYPES[ext] ?? "application/octet-stream"
|
|
7319
|
+
});
|
|
7320
|
+
}
|
|
7321
|
+
for (const file of relative2) {
|
|
7322
|
+
if (file.endsWith(".colorset/Contents.json") || file.includes(".symbolset/"))
|
|
7323
|
+
watched.push(file);
|
|
7324
|
+
}
|
|
7325
|
+
if (registered.size !== project.resourceFiles.size || [...registered].some(
|
|
7326
|
+
([key, value]) => !project.resourceFiles.get(key)?.bytes.equals(value.bytes)
|
|
7327
|
+
)) {
|
|
7328
|
+
project.resourcesPrevious = project.resourceFiles;
|
|
7329
|
+
project.resourceFiles = registered;
|
|
7330
|
+
}
|
|
7331
|
+
return { table, images, colors, symbols, watched };
|
|
7332
|
+
}
|
|
7333
|
+
var BUNDLE_MAX_FILES = MAX_SWIFT_COMPILE_RESOURCES;
|
|
7334
|
+
var BUNDLE_MAX_FILE_BYTES = MAX_SWIFT_COMPILE_RESOURCE_BYTES;
|
|
7335
|
+
var BUNDLE_MAX_TOTAL_BYTES = MAX_SWIFT_COMPILE_RESOURCE_TOTAL_BYTES;
|
|
7336
|
+
function buildSwiftBundleFiles(packagePath) {
|
|
7337
|
+
packagePath = import_node_fs9.default.realpathSync(packagePath);
|
|
7338
|
+
const relative2 = resourceCandidateFiles(packagePath).map(
|
|
7339
|
+
(file) => import_node_path9.default.relative(packagePath, file).split(import_node_path9.default.sep).join(import_node_path9.default.posix.sep)
|
|
7340
|
+
);
|
|
7341
|
+
const files = {};
|
|
7342
|
+
const watched = [];
|
|
7343
|
+
let total = 0;
|
|
7344
|
+
for (const { base, file } of enumerateBundleJson(relative2)) {
|
|
7345
|
+
watched.push(file);
|
|
7346
|
+
const disk = import_node_path9.default.join(packagePath, ...file.split("/"));
|
|
7347
|
+
if (Object.keys(files).length >= BUNDLE_MAX_FILES || total + import_node_fs9.default.statSync(disk).size > BUNDLE_MAX_TOTAL_BYTES) {
|
|
7348
|
+
throw new Error(
|
|
7349
|
+
`swift bundle pack exceeds ${BUNDLE_MAX_FILES} files / ${BUNDLE_MAX_TOTAL_BYTES} bytes`
|
|
7350
|
+
);
|
|
7351
|
+
}
|
|
7352
|
+
const bytes = readPackageFile(packagePath, disk, BUNDLE_MAX_FILE_BYTES);
|
|
7353
|
+
files[base] = bytes.toString("base64");
|
|
7354
|
+
total += bytes.length;
|
|
7355
|
+
}
|
|
7356
|
+
return { files, watched };
|
|
7357
|
+
}
|
|
7358
|
+
function serveSwiftResource(project, key) {
|
|
7359
|
+
return project.resourceFiles.get(key) ?? project.resourcesPrevious.get(key) ?? null;
|
|
7360
|
+
}
|
|
7361
|
+
function linkedModuleRoots(packagePath) {
|
|
7362
|
+
packagePath = import_node_fs9.default.realpathSync(packagePath);
|
|
7363
|
+
let manifest;
|
|
7364
|
+
try {
|
|
7365
|
+
manifest = readPackageFile(
|
|
7366
|
+
packagePath,
|
|
7367
|
+
import_node_path9.default.join(packagePath, "Package.swift"),
|
|
7368
|
+
MAX_SWIFT_COMPILE_SOURCE_BYTES
|
|
7369
|
+
).toString("utf8");
|
|
7370
|
+
} catch {
|
|
7371
|
+
return [];
|
|
7372
|
+
}
|
|
7373
|
+
const roots = /* @__PURE__ */ new Set();
|
|
7374
|
+
const dependency = /\.package\(\s*path:\s*"([^"]+)"\s*\)/g;
|
|
7375
|
+
for (const match of manifest.replace(/^\s*\/\/.*$/gm, "").matchAll(dependency)) {
|
|
7376
|
+
const root = import_node_path9.default.resolve(packagePath, match[1]);
|
|
7377
|
+
if (import_node_fs9.default.existsSync(import_node_path9.default.join(root, "Package.swift"))) roots.add(root);
|
|
7378
|
+
}
|
|
7379
|
+
return [...roots].sort();
|
|
7380
|
+
}
|
|
7381
|
+
function sourceStamp(packagePath, moduleRootOverride, hosted = false) {
|
|
7382
|
+
const hash = (0, import_node_crypto4.createHash)("sha256");
|
|
7383
|
+
hash.update(packagePath);
|
|
7384
|
+
const projectInputs = new Set(packageFiles(packagePath));
|
|
7385
|
+
for (const file of [...projectInputs].sort()) {
|
|
7386
|
+
hash.update(import_node_path9.default.relative(packagePath, file));
|
|
7387
|
+
const stat2 = import_node_fs9.default.statSync(file);
|
|
7388
|
+
hash.update(`${stat2.mtimeMs}/${stat2.ctimeMs}/${stat2.size}`);
|
|
7389
|
+
}
|
|
7390
|
+
const moduleRoot = hosted ? void 0 : moduleRootOverride ?? linkedModuleRoots(packagePath).find(
|
|
7391
|
+
(root) => import_node_fs9.default.existsSync(import_node_path9.default.join(root, "toolchain.json"))
|
|
7392
|
+
);
|
|
7393
|
+
if (moduleRoot) {
|
|
7394
|
+
hash.update(moduleRoot);
|
|
7395
|
+
for (const relative2 of swiftModuleInputFiles(moduleRoot)) {
|
|
7396
|
+
hash.update(relative2);
|
|
7397
|
+
hash.update(String(import_node_fs9.default.statSync(import_node_path9.default.join(moduleRoot, relative2)).mtimeMs));
|
|
7398
|
+
}
|
|
7399
|
+
}
|
|
7400
|
+
return hash.digest("hex").slice(0, 16);
|
|
7401
|
+
}
|
|
7402
|
+
function icuUrl(origin, artifact) {
|
|
7403
|
+
return "url" in artifact.icu ? artifact.icu.url : `${origin}${ICU_PATH}${artifact.icu.sha256}`;
|
|
7404
|
+
}
|
|
7405
|
+
function packageSources(packagePath) {
|
|
7406
|
+
const sources = sourceFiles(packagePath);
|
|
7407
|
+
if (sources.length > MAX_SWIFT_COMPILE_FILES)
|
|
7408
|
+
throw new Error("swift source file cap exceeded");
|
|
7409
|
+
let total = 0;
|
|
7410
|
+
for (const file of sources) total += import_node_fs9.default.statSync(file).size;
|
|
7411
|
+
if (total > MAX_SWIFT_COMPILE_SOURCE_BYTES)
|
|
7412
|
+
throw new Error("swift source byte cap exceeded");
|
|
7413
|
+
const files = {};
|
|
7414
|
+
for (const file of sources) {
|
|
7415
|
+
const relative2 = import_node_path9.default.relative(packagePath, file).split(import_node_path9.default.sep).join(import_node_path9.default.posix.sep);
|
|
7416
|
+
files[relative2] = readPackageFile(
|
|
7417
|
+
packagePath,
|
|
7418
|
+
file,
|
|
7419
|
+
MAX_SWIFT_COMPILE_SOURCE_BYTES
|
|
7420
|
+
).toString("utf8");
|
|
7421
|
+
}
|
|
7422
|
+
return files;
|
|
7423
|
+
}
|
|
7424
|
+
function packageSnapshot(project) {
|
|
7425
|
+
const files = packageSources(project.packagePath);
|
|
7426
|
+
const native = nativeSourceDescriptor(project.packagePath);
|
|
7427
|
+
return {
|
|
7428
|
+
files,
|
|
7429
|
+
resources: buildSwiftResourceTable(project, ""),
|
|
7430
|
+
bundleFiles: buildSwiftBundleFiles(project.packagePath),
|
|
7431
|
+
native,
|
|
7432
|
+
...native ? {
|
|
7433
|
+
glue: readPackageFile(
|
|
7434
|
+
project.packagePath,
|
|
7435
|
+
import_node_path9.default.join(project.packagePath, NATIVE_GLUE),
|
|
7436
|
+
MAX_SWIFT_COMPILE_SOURCE_BYTES
|
|
7437
|
+
).toString("utf8")
|
|
7438
|
+
} : {}
|
|
7439
|
+
};
|
|
7440
|
+
}
|
|
7441
|
+
function snapshotCompileInput(snapshot, entry) {
|
|
7442
|
+
const input = {
|
|
7443
|
+
files: snapshot.files,
|
|
7444
|
+
resources: snapshot.bundleFiles.files,
|
|
7445
|
+
images: snapshot.resources.images,
|
|
7446
|
+
entry,
|
|
7447
|
+
oneModule: true
|
|
7448
|
+
};
|
|
7449
|
+
return snapshot.glue ? withNativeSourceGlue(input, snapshot.glue) : input;
|
|
7450
|
+
}
|
|
7451
|
+
async function compile(packagePath, entry, stamp, moduleRootOverride, hosted, snapshot) {
|
|
7452
|
+
const resources = {
|
|
7453
|
+
table: snapshot.resources.table,
|
|
7454
|
+
colors: snapshot.resources.colors,
|
|
7455
|
+
symbols: snapshot.resources.symbols,
|
|
7456
|
+
watched: snapshot.resources.watched
|
|
7457
|
+
};
|
|
7458
|
+
const content = {
|
|
7459
|
+
resources,
|
|
7460
|
+
bundleFiles: snapshot.bundleFiles,
|
|
7461
|
+
native: snapshot.native
|
|
7462
|
+
};
|
|
7463
|
+
if (hosted)
|
|
7464
|
+
return {
|
|
7465
|
+
...await compileRemote(packagePath, entry, snapshot, hosted),
|
|
7466
|
+
stamp,
|
|
7467
|
+
package: content
|
|
7468
|
+
};
|
|
7469
|
+
const moduleRoot = moduleRootOverride ?? linkedModuleRoots(packagePath).find(
|
|
7470
|
+
(root) => import_node_fs9.default.existsSync(import_node_path9.default.join(root, "toolchain.json"))
|
|
7471
|
+
);
|
|
7472
|
+
if (!moduleRoot)
|
|
7473
|
+
return {
|
|
7474
|
+
...await compileRemote(packagePath, entry, snapshot),
|
|
7475
|
+
stamp,
|
|
7476
|
+
package: content
|
|
7477
|
+
};
|
|
7478
|
+
const toolchain = JSON.parse(
|
|
7479
|
+
import_node_fs9.default.readFileSync(import_node_path9.default.join(moduleRoot, "toolchain.json"), "utf8")
|
|
7480
|
+
);
|
|
7481
|
+
const release = toolchain && typeof toolchain === "object" ? Reflect.get(toolchain, "release") : void 0;
|
|
7482
|
+
if (typeof release !== "string") {
|
|
7483
|
+
throw new Error(`swift toolchain manifest at ${moduleRoot} has no release`);
|
|
7484
|
+
}
|
|
7485
|
+
const artifact = await compileSwiftProjectUnit(snapshotCompileInput(snapshot, entry), {
|
|
7486
|
+
// the compile rewrites Sources/App in its root before swiftpm builds, and
|
|
7487
|
+
// its lock orders one process only: two vites on one root (a lane's dev
|
|
7488
|
+
// server and a capture, or two checkouts) build each other's sources. so
|
|
7489
|
+
// each app and module checkout gets its own root, which keeps the same
|
|
7490
|
+
// app's incremental build across restarts.
|
|
7491
|
+
buildRoot: process.env.CONTRAST_SWIFT_BUILD_ROOT ?? import_node_path9.default.join(
|
|
7492
|
+
import_node_os3.default.tmpdir(),
|
|
7493
|
+
"contrast-swift-build",
|
|
7494
|
+
(0, import_node_crypto4.createHash)("sha256").update(`${moduleRoot}\0${import_node_path9.default.resolve(packagePath)}`).digest("hex").slice(0, 16)
|
|
7495
|
+
),
|
|
7496
|
+
moduleRoot,
|
|
7497
|
+
release,
|
|
7498
|
+
toolchainBin: import_node_path9.default.join(
|
|
7499
|
+
import_node_os3.default.homedir(),
|
|
7500
|
+
`Library/Developer/Toolchains/${release}.xctoolchain/usr/bin`
|
|
7501
|
+
)
|
|
7502
|
+
});
|
|
7503
|
+
return { ...artifact, stamp, package: content };
|
|
7504
|
+
}
|
|
7505
|
+
async function compileRemote(packagePath, entry, snapshot, hosted) {
|
|
7506
|
+
const auth = hosted ? null : resolveCliAuth();
|
|
7507
|
+
if (!hosted && (!auth || auth.kind === "github")) {
|
|
7508
|
+
throw new Error(
|
|
7509
|
+
`compiling ${import_node_path9.default.basename(packagePath)} for Peach needs \`peach login\` or PEACH_API_KEY: this peachsim has no local SwiftUI module, so Contrast compiles it`
|
|
7510
|
+
);
|
|
7511
|
+
}
|
|
7512
|
+
const origin = hosted?.origin ?? resolveContrastBackendOrigin(auth?.kind === "session" ? auth.origin : null);
|
|
7513
|
+
const authorization = hosted?.authorization ?? (auth ? authHeaderValue(auth) : void 0);
|
|
7514
|
+
const signal = AbortSignal.any([
|
|
7515
|
+
...hosted ? [hosted.signal] : [],
|
|
7516
|
+
AbortSignal.timeout(5 * 6e4)
|
|
7517
|
+
]);
|
|
7518
|
+
const submit = httpSwiftCompileSubmit({
|
|
7519
|
+
endpoint: origin,
|
|
7520
|
+
authorization,
|
|
7521
|
+
signal
|
|
7522
|
+
});
|
|
7523
|
+
if (!submit) throw new Error("swift compile: no credential to submit with");
|
|
7524
|
+
const descriptor = snapshot.native;
|
|
7525
|
+
const address = await compileSwiftProject(
|
|
7526
|
+
submit,
|
|
7527
|
+
{
|
|
7528
|
+
files: snapshot.files,
|
|
7529
|
+
resources: snapshot.bundleFiles.files,
|
|
7530
|
+
images: snapshot.resources.images,
|
|
7531
|
+
entry,
|
|
7532
|
+
packageId: descriptor?.packageId ?? swiftPackageId(packagePath)
|
|
7533
|
+
},
|
|
7534
|
+
origin,
|
|
7535
|
+
signal
|
|
7536
|
+
);
|
|
7537
|
+
if (descriptor && address.native?.hash !== descriptor.hash) {
|
|
7538
|
+
throw new Error(
|
|
7539
|
+
`${import_node_path9.default.basename(packagePath)}: Contrast compiled native contract ${address.native?.hash ?? "none"} but one typegen wrote ${descriptor.hash}; the app's One and the compile host's differ, or the compile host is older than this peachsim`
|
|
7540
|
+
);
|
|
7541
|
+
}
|
|
7542
|
+
const response = await fetch(address.url, { signal });
|
|
7543
|
+
if (!response.ok) {
|
|
7544
|
+
throw new Error(`swift compile: ${address.url} answered ${response.status}`);
|
|
7545
|
+
}
|
|
7546
|
+
const maxArtifactBytes = 64 * 1024 * 1024;
|
|
7547
|
+
if (Number(response.headers.get("content-length")) > maxArtifactBytes || !response.body) {
|
|
7548
|
+
throw new Error("swift compile: artifact exceeds 64 MiB or has no body");
|
|
7549
|
+
}
|
|
7550
|
+
const reader = response.body.getReader();
|
|
7551
|
+
const chunks = [];
|
|
7552
|
+
let total = 0;
|
|
7553
|
+
for (; ; ) {
|
|
7554
|
+
signal.throwIfAborted();
|
|
7555
|
+
const next = await reader.read();
|
|
7556
|
+
if (next.done) break;
|
|
7557
|
+
total += next.value.byteLength;
|
|
7558
|
+
if (total > maxArtifactBytes) {
|
|
7559
|
+
await reader.cancel();
|
|
7560
|
+
throw new Error("swift compile: artifact exceeds 64 MiB");
|
|
7561
|
+
}
|
|
7562
|
+
chunks.push(next.value);
|
|
7563
|
+
}
|
|
7564
|
+
return {
|
|
7565
|
+
hash: address.hash,
|
|
7566
|
+
bytes: Buffer.concat(chunks),
|
|
7567
|
+
icu: { url: address.icuUrl }
|
|
7568
|
+
};
|
|
7569
|
+
}
|
|
7570
|
+
function artifactFor(project, entry, moduleRoot) {
|
|
7571
|
+
const stamp = sourceStamp(project.packagePath, moduleRoot, Boolean(project.hosted));
|
|
7572
|
+
if (project.artifact?.stamp === stamp) return Promise.resolve(project.artifact);
|
|
7573
|
+
if (project.building) {
|
|
7574
|
+
const running = project.building;
|
|
7575
|
+
if (running.stamp === stamp) return running.promise;
|
|
7576
|
+
const again = () => artifactFor(project, entry, moduleRoot);
|
|
7577
|
+
return running.promise.then(again, again);
|
|
7578
|
+
}
|
|
7579
|
+
const snapshot = packageSnapshot(project);
|
|
7580
|
+
if (sourceStamp(project.packagePath, moduleRoot, Boolean(project.hosted)) !== stamp) {
|
|
7581
|
+
return artifactFor(project, entry, moduleRoot);
|
|
7582
|
+
}
|
|
7583
|
+
const promise = compile(
|
|
7584
|
+
project.packagePath,
|
|
7585
|
+
entry,
|
|
7586
|
+
stamp,
|
|
7587
|
+
moduleRoot,
|
|
7588
|
+
project.hosted,
|
|
7589
|
+
snapshot
|
|
7590
|
+
).then(
|
|
7591
|
+
(artifact) => {
|
|
7592
|
+
project.artifact = artifact;
|
|
7593
|
+
project.artifacts = [
|
|
7594
|
+
artifact,
|
|
7595
|
+
...project.artifacts.filter((old) => old.hash !== artifact.hash)
|
|
7596
|
+
].slice(0, 2);
|
|
7597
|
+
project.building = null;
|
|
7598
|
+
return artifact;
|
|
7599
|
+
},
|
|
7600
|
+
(error) => {
|
|
7601
|
+
project.building = null;
|
|
7602
|
+
throw error;
|
|
7603
|
+
}
|
|
7604
|
+
);
|
|
7605
|
+
const fresh = promise.then(
|
|
7606
|
+
(artifact) => sourceStamp(project.packagePath, moduleRoot, Boolean(project.hosted)) === artifact.stamp ? artifact : artifactFor(project, entry, moduleRoot)
|
|
7607
|
+
);
|
|
7608
|
+
project.building = { stamp, promise: fresh };
|
|
7609
|
+
return fresh;
|
|
7610
|
+
}
|
|
7611
|
+
function serveSwiftPackageAsset(pathname, res) {
|
|
7612
|
+
if (pathname.startsWith(RESOURCE_PATH)) {
|
|
7613
|
+
for (const project of projects.values()) {
|
|
7614
|
+
const served = serveSwiftResource(project, pathname.slice(RESOURCE_PATH.length));
|
|
7615
|
+
if (!served) continue;
|
|
7616
|
+
res.setHeader("access-control-allow-origin", "*");
|
|
7617
|
+
res.setHeader("content-type", served.contentType);
|
|
7618
|
+
res.end(served.bytes);
|
|
7619
|
+
return true;
|
|
7620
|
+
}
|
|
7621
|
+
res.statusCode = 404;
|
|
7622
|
+
res.end("swift resource is stale");
|
|
7623
|
+
return true;
|
|
7624
|
+
}
|
|
7625
|
+
if (pathname.startsWith(ICU_PATH)) {
|
|
7626
|
+
for (const project of projects.values()) {
|
|
7627
|
+
const icu = project.artifacts.find(
|
|
7628
|
+
(artifact) => "sha256" in artifact.icu && pathname === `${ICU_PATH}${artifact.icu.sha256}`
|
|
7629
|
+
)?.icu;
|
|
7630
|
+
if (!icu || "url" in icu || pathname !== `${ICU_PATH}${icu.sha256}`) continue;
|
|
7631
|
+
res.setHeader("access-control-allow-origin", "*");
|
|
7632
|
+
res.setHeader("content-type", "application/gzip");
|
|
7633
|
+
res.setHeader("cache-control", "public, max-age=31536000, immutable");
|
|
7634
|
+
res.end(icu.gzip);
|
|
7635
|
+
return true;
|
|
7636
|
+
}
|
|
7637
|
+
res.statusCode = 404;
|
|
7638
|
+
res.end("swift icu data is stale");
|
|
7639
|
+
return true;
|
|
7640
|
+
}
|
|
7641
|
+
if (!pathname.startsWith(ARTIFACT_PATH)) return false;
|
|
7642
|
+
for (const project of projects.values()) {
|
|
7643
|
+
const artifact = project.artifacts.find(
|
|
7644
|
+
(artifact2) => pathname === `${ARTIFACT_PATH}${artifact2.hash}.wasm`
|
|
7645
|
+
);
|
|
7646
|
+
if (!artifact || pathname !== `${ARTIFACT_PATH}${artifact.hash}.wasm`) continue;
|
|
7647
|
+
res.setHeader("access-control-allow-origin", "*");
|
|
7648
|
+
res.setHeader("content-type", "application/wasm");
|
|
7649
|
+
res.end(artifact.bytes);
|
|
7650
|
+
return true;
|
|
7651
|
+
}
|
|
7652
|
+
res.statusCode = 404;
|
|
7653
|
+
res.end("swift artifact is stale");
|
|
7654
|
+
return true;
|
|
7655
|
+
}
|
|
7656
|
+
|
|
7657
|
+
// src/expo-swift-host.ts
|
|
7658
|
+
var import_meta2 = {};
|
|
7659
|
+
var run3 = (0, import_node_util3.promisify)(import_node_child_process4.execFile);
|
|
7660
|
+
var EXPO_SWIFT_ROUTE = "/__peach/expo-swift";
|
|
7661
|
+
var EXPO_SWIFT_ENTRY = "Sources/PeachExpoApp/PeachExpoEntry.swift";
|
|
7662
|
+
async function collectExpoSwiftSources(appRoot) {
|
|
7663
|
+
appRoot = import_node_fs10.default.realpathSync(appRoot);
|
|
7664
|
+
const appRequire = (0, import_node_module.createRequire)(import_node_path10.default.join(appRoot, "package.json"));
|
|
7665
|
+
let autolinker;
|
|
7666
|
+
try {
|
|
7667
|
+
autolinker = appRequire.resolve("expo-modules-autolinking/package.json");
|
|
7668
|
+
} catch (error) {
|
|
7669
|
+
if (error && typeof error === "object" && Reflect.get(error, "code") === "MODULE_NOT_FOUND")
|
|
7670
|
+
return null;
|
|
7671
|
+
throw error;
|
|
7672
|
+
}
|
|
7673
|
+
const { stdout } = await run3(
|
|
7674
|
+
process.execPath,
|
|
7675
|
+
[
|
|
7676
|
+
import_node_path10.default.join(import_node_path10.default.dirname(autolinker), "bin/expo-modules-autolinking.js"),
|
|
7677
|
+
"search",
|
|
7678
|
+
"--platform",
|
|
7679
|
+
"apple",
|
|
7680
|
+
"--project-root",
|
|
7681
|
+
appRoot,
|
|
7682
|
+
"--json"
|
|
7683
|
+
],
|
|
7684
|
+
{ timeout: 3e4, maxBuffer: 8 * 1024 * 1024 }
|
|
7685
|
+
);
|
|
7686
|
+
const search = JSON.parse(stdout);
|
|
7687
|
+
if (!search || typeof search !== "object" || Array.isArray(search))
|
|
7688
|
+
throw new Error("invalid Expo autolinking result");
|
|
7689
|
+
const { stdout: resolvedText } = await run3(
|
|
7690
|
+
process.execPath,
|
|
7691
|
+
[
|
|
7692
|
+
import_node_path10.default.join(import_node_path10.default.dirname(autolinker), "bin/expo-modules-autolinking.js"),
|
|
7693
|
+
"resolve",
|
|
7694
|
+
"--platform",
|
|
7695
|
+
"apple",
|
|
7696
|
+
"--project-root",
|
|
7697
|
+
appRoot,
|
|
7698
|
+
"--json"
|
|
7699
|
+
],
|
|
7700
|
+
{ timeout: 3e4, maxBuffer: 8 * 1024 * 1024 }
|
|
7701
|
+
);
|
|
7702
|
+
const resolved = JSON.parse(resolvedText);
|
|
7703
|
+
const resolutions = resolved && typeof resolved === "object" ? Reflect.get(resolved, "modules") : null;
|
|
7704
|
+
if (!Array.isArray(resolutions)) throw new Error("invalid Expo Apple resolution");
|
|
7705
|
+
const files = {};
|
|
7706
|
+
const targets = [];
|
|
7707
|
+
const classes = [];
|
|
7708
|
+
let bytes = 0;
|
|
7709
|
+
for (const entry of Object.values(search)) {
|
|
7710
|
+
if (!entry || typeof entry !== "object")
|
|
7711
|
+
throw new Error("invalid Expo autolinking entry");
|
|
7712
|
+
const sourceRoot = Reflect.get(entry, "path");
|
|
7713
|
+
if (typeof sourceRoot !== "string")
|
|
7714
|
+
throw new Error("Expo autolinking entry has no path");
|
|
7715
|
+
const canonical = import_node_fs10.default.realpathSync(sourceRoot);
|
|
7716
|
+
if (canonical.split(import_node_path10.default.sep).includes("node_modules")) continue;
|
|
7717
|
+
const resolution = resolutions.find(
|
|
7718
|
+
(candidate) => candidate && typeof candidate === "object" && Reflect.get(candidate, "packageName") === Reflect.get(entry, "name")
|
|
7719
|
+
);
|
|
7720
|
+
const namespaces = resolution && typeof resolution === "object" ? Reflect.get(resolution, "swiftModuleNames") : null;
|
|
7721
|
+
const modules = resolution && typeof resolution === "object" ? Reflect.get(resolution, "modules") : null;
|
|
7722
|
+
if (!Array.isArray(modules) || modules.length === 0) continue;
|
|
7723
|
+
if (!Array.isArray(namespaces) || namespaces.length !== 1 || typeof namespaces[0] !== "string" || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(namespaces[0]))
|
|
7724
|
+
throw new Error(
|
|
7725
|
+
`${sourceRoot}: local Expo Swift modules need one Apple Swift module`
|
|
7726
|
+
);
|
|
7727
|
+
const namespace = namespaces[0];
|
|
7728
|
+
if (targets.includes(namespace))
|
|
7729
|
+
throw new Error(`duplicate local Expo Swift module ${namespace}`);
|
|
7730
|
+
targets.push(namespace);
|
|
7731
|
+
for (const module2 of modules) {
|
|
7732
|
+
const className = module2 && typeof module2 === "object" ? Reflect.get(module2, "class") : null;
|
|
7733
|
+
const name2 = module2 && typeof module2 === "object" ? Reflect.get(module2, "name") : null;
|
|
7734
|
+
if (typeof className !== "string" || !/^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$/.test(className) || name2 !== null && typeof name2 !== "string")
|
|
7735
|
+
throw new Error(`${sourceRoot}: invalid Expo Apple module descriptor`);
|
|
7736
|
+
classes.push(
|
|
7737
|
+
`(${className.includes(".") ? className : `${namespace}.${className}`}.self, ${name2 === null ? "nil" : JSON.stringify(name2)})`
|
|
7738
|
+
);
|
|
7739
|
+
}
|
|
7740
|
+
const ios = import_node_path10.default.join(canonical, "ios");
|
|
7741
|
+
if (import_node_fs10.default.lstatSync(ios).isSymbolicLink())
|
|
7742
|
+
throw new Error(`Expo Swift source directory is a symlink: ${ios}`);
|
|
7743
|
+
const walk = (dir) => {
|
|
7744
|
+
for (const child of import_node_fs10.default.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
7745
|
+
const file = import_node_path10.default.join(dir, child.name);
|
|
7746
|
+
if (child.isSymbolicLink())
|
|
7747
|
+
throw new Error(`Expo Swift source is a symlink: ${file}`);
|
|
7748
|
+
if (child.isDirectory()) {
|
|
7749
|
+
if (!child.name.startsWith(".") && child.name !== "build") walk(file);
|
|
7750
|
+
continue;
|
|
7751
|
+
}
|
|
7752
|
+
if (!child.name.endsWith(".swift")) continue;
|
|
7753
|
+
const size = import_node_fs10.default.statSync(file).size;
|
|
7754
|
+
bytes += size;
|
|
7755
|
+
if (Object.keys(files).length + 1 > MAX_SWIFT_COMPILE_FILES - 2 || bytes > MAX_SWIFT_COMPILE_SOURCE_BYTES)
|
|
7756
|
+
throw new Error("Expo Swift sources exceed compile service caps");
|
|
7757
|
+
files[`Sources/${namespace}/${import_node_path10.default.relative(ios, file).split(import_node_path10.default.sep).join("/")}`] = `#sourceLocation(file: ${JSON.stringify(file)}, line: 1)
|
|
7758
|
+
${import_node_fs10.default.readFileSync(file, "utf8")}`;
|
|
7759
|
+
}
|
|
7760
|
+
};
|
|
7761
|
+
walk(ios);
|
|
7762
|
+
}
|
|
7763
|
+
if (classes.length === 0) return null;
|
|
7764
|
+
files["Package.swift"] = `// swift-tools-version: 6.0
|
|
7765
|
+
import PackageDescription
|
|
7766
|
+
let package = Package(name: "PeachExpo", targets: [${targets.map((name2) => `.target(name: ${JSON.stringify(name2)}, path: ${JSON.stringify(`Sources/${name2}`)})`).join(", ")}, .executableTarget(name: "PeachExpoApp", path: "Sources/PeachExpoApp")])
|
|
7767
|
+
`;
|
|
7768
|
+
files[EXPO_SWIFT_ENTRY] = `import SwiftUI
|
|
7769
|
+
import ExpoModulesCore
|
|
7770
|
+
${targets.map((name2) => `import ${name2}
|
|
7771
|
+
`).join("")}
|
|
7772
|
+
@main struct PeachExpoApp: RNXPackage {
|
|
7773
|
+
init() { MainActor.assumeIsolated { PeachExpoRuntime.register([${classes.join(", ")}]) } }
|
|
7774
|
+
func view(props: JSON) -> PeachExpoNativeView { PeachExpoNativeView(props: props) }
|
|
7775
|
+
}
|
|
7776
|
+
|
|
7777
|
+
@_expose(wasm, "peach_expo_call")
|
|
7778
|
+
@_cdecl("peach_expo_call")
|
|
7779
|
+
@MainActor public func peachExpoCall(_ payload: UnsafePointer<UInt8>?, _ length: Int32) -> UnsafeMutablePointer<UInt8>? {
|
|
7780
|
+
PeachExpoRuntime.dispatch(payload, length)
|
|
7781
|
+
}
|
|
7782
|
+
`;
|
|
7783
|
+
return files;
|
|
7784
|
+
}
|
|
7785
|
+
var compiling = /* @__PURE__ */ new Map();
|
|
7786
|
+
async function handleExpoSwiftRequest(req, res) {
|
|
7787
|
+
const url = new URL(req.url ?? "/", "http://localhost");
|
|
7788
|
+
if (!url.pathname.startsWith("/__peach/swift") && url.pathname !== EXPO_SWIFT_ROUTE)
|
|
7789
|
+
return false;
|
|
7790
|
+
const remote = req.socket.remoteAddress?.replace(/^::ffff:/, "");
|
|
7791
|
+
const origin = req.headers.origin;
|
|
7792
|
+
if (!remote || !isLoopbackHost(remote) || origin && !isLoopbackHost(new URL(origin).hostname)) {
|
|
7793
|
+
res.writeHead(403);
|
|
7794
|
+
res.end("Expo Swift artifacts require a loopback client");
|
|
7795
|
+
return true;
|
|
7796
|
+
}
|
|
7797
|
+
res.setHeader("Access-Control-Allow-Origin", origin ?? "*");
|
|
7798
|
+
res.setHeader("Vary", "Origin");
|
|
7799
|
+
res.setHeader("Cross-Origin-Resource-Policy", "cross-origin");
|
|
7800
|
+
if (serveSwiftPackageAsset(url.pathname, res)) return true;
|
|
7801
|
+
if (url.pathname !== EXPO_SWIFT_ROUTE) return false;
|
|
7802
|
+
if (req.method !== "GET") {
|
|
7803
|
+
res.writeHead(405);
|
|
7804
|
+
res.end("GET required");
|
|
7805
|
+
return true;
|
|
7806
|
+
}
|
|
7807
|
+
const root = url.searchParams.get("root");
|
|
7808
|
+
if (!root || !import_node_path10.default.isAbsolute(root)) {
|
|
7809
|
+
res.writeHead(400);
|
|
7810
|
+
res.end("missing absolute app root");
|
|
7811
|
+
return true;
|
|
7812
|
+
}
|
|
7813
|
+
try {
|
|
7814
|
+
let pending = compiling.get(root);
|
|
7815
|
+
if (!pending) {
|
|
7816
|
+
pending = (async () => {
|
|
7817
|
+
const files = await collectExpoSwiftSources(root);
|
|
7818
|
+
if (!files) return null;
|
|
7819
|
+
const key = (0, import_node_crypto5.createHash)("sha256").update(import_node_fs10.default.realpathSync(root)).digest("hex");
|
|
7820
|
+
const packagePath = import_node_path10.default.join(import_node_os4.default.tmpdir(), "peach-expo-swift", key);
|
|
7821
|
+
const sources = import_node_path10.default.join(packagePath, "Sources");
|
|
7822
|
+
import_node_fs10.default.rmSync(sources, { recursive: true, force: true });
|
|
7823
|
+
import_node_fs10.default.mkdirSync(sources, { recursive: true });
|
|
7824
|
+
for (const [name2, content] of Object.entries(files)) {
|
|
7825
|
+
const target = import_node_path10.default.join(packagePath, name2);
|
|
7826
|
+
import_node_fs10.default.mkdirSync(import_node_path10.default.dirname(target), { recursive: true });
|
|
7827
|
+
import_node_fs10.default.writeFileSync(target, content);
|
|
7828
|
+
}
|
|
7829
|
+
const moduleRoot = import_node_path10.default.resolve(import_meta2.dirname, "../../sootsim-swift");
|
|
7830
|
+
const local = import_node_fs10.default.existsSync(import_node_path10.default.join(moduleRoot, "toolchain.json"));
|
|
7831
|
+
const artifact = await artifactFor(
|
|
7832
|
+
projectFor(packagePath),
|
|
7833
|
+
EXPO_SWIFT_ENTRY,
|
|
7834
|
+
local ? moduleRoot : void 0
|
|
7835
|
+
);
|
|
7836
|
+
const host2 = req.headers.host;
|
|
7837
|
+
if (!host2) throw new Error("Expo Swift request has no host");
|
|
7838
|
+
const base = `http://${host2}`;
|
|
7839
|
+
return {
|
|
7840
|
+
url: `${base}/__peach/swift/${artifact.hash}.wasm`,
|
|
7841
|
+
hash: artifact.hash,
|
|
7842
|
+
icuUrl: icuUrl(base, artifact),
|
|
7843
|
+
rootId: `${key}/Expo`
|
|
7844
|
+
};
|
|
7845
|
+
})();
|
|
7846
|
+
compiling.set(root, pending);
|
|
7847
|
+
}
|
|
7848
|
+
const metadata = await pending;
|
|
7849
|
+
res.writeHead(200, {
|
|
7850
|
+
"Content-Type": "application/json",
|
|
7851
|
+
"Cache-Control": "no-store"
|
|
7852
|
+
});
|
|
7853
|
+
res.end(JSON.stringify(metadata));
|
|
7854
|
+
} catch (error) {
|
|
7855
|
+
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
7856
|
+
res.end(error instanceof Error ? error.message : String(error));
|
|
7857
|
+
} finally {
|
|
7858
|
+
compiling.delete(root);
|
|
7859
|
+
}
|
|
7860
|
+
return true;
|
|
7861
|
+
}
|
|
7862
|
+
|
|
6019
7863
|
// src/host/bridge-host.ts
|
|
6020
7864
|
init_home_paths();
|
|
6021
7865
|
init_public_brand();
|
|
@@ -6026,29 +7870,29 @@ var import_path = __toESM(require("path"), 1);
|
|
|
6026
7870
|
var import_url = require("url");
|
|
6027
7871
|
|
|
6028
7872
|
// ../contrast-runtime-delivery/src/index.ts
|
|
6029
|
-
var
|
|
6030
|
-
var
|
|
6031
|
-
var
|
|
6032
|
-
var
|
|
6033
|
-
var
|
|
7873
|
+
var import_node_child_process5 = require("node:child_process");
|
|
7874
|
+
var import_node_crypto6 = __toESM(require("node:crypto"), 1);
|
|
7875
|
+
var import_node_fs12 = __toESM(require("node:fs"), 1);
|
|
7876
|
+
var import_node_os5 = __toESM(require("node:os"), 1);
|
|
7877
|
+
var import_node_path12 = __toESM(require("node:path"), 1);
|
|
6034
7878
|
var import_node_stream = require("node:stream");
|
|
6035
7879
|
var import_promises3 = require("node:stream/promises");
|
|
6036
7880
|
|
|
6037
7881
|
// ../contrast-runtime-delivery/src/product.ts
|
|
6038
|
-
var
|
|
6039
|
-
var
|
|
7882
|
+
var import_node_fs11 = __toESM(require("node:fs"), 1);
|
|
7883
|
+
var import_node_path11 = __toESM(require("node:path"), 1);
|
|
6040
7884
|
function isValidRuntimeVersion(value) {
|
|
6041
7885
|
return value.length <= 100 && /^[0-9A-Za-z][0-9A-Za-z._+-]*$/.test(value);
|
|
6042
7886
|
}
|
|
6043
7887
|
function listInstalledRuntimes(product) {
|
|
6044
7888
|
try {
|
|
6045
|
-
return
|
|
7889
|
+
return import_node_fs11.default.readdirSync(product.runtimesDir(), { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort(compareSemver);
|
|
6046
7890
|
} catch {
|
|
6047
7891
|
return [];
|
|
6048
7892
|
}
|
|
6049
7893
|
}
|
|
6050
7894
|
function runtimeTarballCacheName(product, version) {
|
|
6051
|
-
return
|
|
7895
|
+
return import_node_path11.default.posix.basename(product.tarballPath(version));
|
|
6052
7896
|
}
|
|
6053
7897
|
function compareSemver(a, b) {
|
|
6054
7898
|
const parse2 = (v) => {
|
|
@@ -6078,7 +7922,7 @@ function createRuntimeDelivery(product) {
|
|
|
6078
7922
|
function readConfig() {
|
|
6079
7923
|
try {
|
|
6080
7924
|
const parsed = JSON.parse(
|
|
6081
|
-
|
|
7925
|
+
import_node_fs12.default.readFileSync(product.configFile(), "utf8")
|
|
6082
7926
|
);
|
|
6083
7927
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
6084
7928
|
} catch {
|
|
@@ -6151,7 +7995,7 @@ function createRuntimeDelivery(product) {
|
|
|
6151
7995
|
const setActive = opts.setActive !== false;
|
|
6152
7996
|
const protectVersions = [version, ...opts.protectVersions ?? []];
|
|
6153
7997
|
pruneLocalRetention({ protectVersions });
|
|
6154
|
-
if (!opts.force &&
|
|
7998
|
+
if (!opts.force && import_node_fs12.default.existsSync(import_node_path12.default.join(destDir, product.installedMarker))) {
|
|
6155
7999
|
if (setActive) product.writeActiveRuntime(version);
|
|
6156
8000
|
pruneLocalRetention({ protectVersions });
|
|
6157
8001
|
return {
|
|
@@ -6194,8 +8038,8 @@ function createRuntimeDelivery(product) {
|
|
|
6194
8038
|
const pin = resolvePin();
|
|
6195
8039
|
if (pin) {
|
|
6196
8040
|
const activeVersion2 = product.readActiveRuntime();
|
|
6197
|
-
const pinInstalled =
|
|
6198
|
-
|
|
8041
|
+
const pinInstalled = import_node_fs12.default.existsSync(
|
|
8042
|
+
import_node_path12.default.join(product.runtimeDir(pin), product.installedMarker)
|
|
6199
8043
|
);
|
|
6200
8044
|
if (activeVersion2 === pin && pinInstalled) {
|
|
6201
8045
|
return {
|
|
@@ -6244,7 +8088,7 @@ function createRuntimeDelivery(product) {
|
|
|
6244
8088
|
}
|
|
6245
8089
|
const activeVersion = product.readActiveRuntime();
|
|
6246
8090
|
const activeDir = activeVersion ? product.runtimeDir(activeVersion) : null;
|
|
6247
|
-
const activeInstalled = activeDir ?
|
|
8091
|
+
const activeInstalled = activeDir ? import_node_fs12.default.existsSync(import_node_path12.default.join(activeDir, product.installedMarker)) : false;
|
|
6248
8092
|
const shouldInstall = !activeVersion || !activeInstalled || compareSemver(latestVersion, activeVersion) > 0;
|
|
6249
8093
|
if (!shouldInstall) {
|
|
6250
8094
|
return {
|
|
@@ -6319,12 +8163,12 @@ function createRuntimeDelivery(product) {
|
|
|
6319
8163
|
let removeCacheFiles = [];
|
|
6320
8164
|
if (markerOffset >= 0) {
|
|
6321
8165
|
try {
|
|
6322
|
-
removeCacheFiles =
|
|
8166
|
+
removeCacheFiles = import_node_fs12.default.readdirSync(product.cacheDir(), { withFileTypes: true }).filter((entry) => {
|
|
6323
8167
|
if (!entry.isFile()) return false;
|
|
6324
8168
|
const complete = entry.name.startsWith(cachePrefix) && entry.name.endsWith(cacheSuffix);
|
|
6325
8169
|
const partial = entry.name.startsWith(cachePrefix) && entry.name.endsWith(`${cacheSuffix}.partial`);
|
|
6326
8170
|
return complete || partial;
|
|
6327
|
-
}).map((entry) =>
|
|
8171
|
+
}).map((entry) => import_node_path12.default.join(product.cacheDir(), entry.name)).sort();
|
|
6328
8172
|
} catch {
|
|
6329
8173
|
}
|
|
6330
8174
|
}
|
|
@@ -6339,10 +8183,10 @@ function createRuntimeDelivery(product) {
|
|
|
6339
8183
|
function pruneLocalRetention(opts = {}) {
|
|
6340
8184
|
const plan = planLocalRetention(opts);
|
|
6341
8185
|
for (const version of plan.removeVersions) {
|
|
6342
|
-
|
|
8186
|
+
import_node_fs12.default.rmSync(product.runtimeDir(version), { recursive: true, force: true });
|
|
6343
8187
|
}
|
|
6344
8188
|
for (const cacheFile of plan.removeCacheFiles) {
|
|
6345
|
-
|
|
8189
|
+
import_node_fs12.default.rmSync(cacheFile, { force: true });
|
|
6346
8190
|
}
|
|
6347
8191
|
return plan;
|
|
6348
8192
|
}
|
|
@@ -6365,11 +8209,11 @@ function createRuntimeDelivery(product) {
|
|
|
6365
8209
|
}
|
|
6366
8210
|
async function installVerifiedTarball(tarball) {
|
|
6367
8211
|
const { url, digest, destDir, installedMarker, label } = tarball;
|
|
6368
|
-
const downloadDir =
|
|
6369
|
-
const archivePath =
|
|
6370
|
-
|
|
6371
|
-
const tmpDir =
|
|
6372
|
-
|
|
8212
|
+
const downloadDir = import_node_fs12.default.mkdtempSync(import_node_path12.default.join(import_node_os5.default.tmpdir(), "runtime-delivery-download-"));
|
|
8213
|
+
const archivePath = import_node_path12.default.join(downloadDir, "archive.tar.gz");
|
|
8214
|
+
import_node_fs12.default.mkdirSync(import_node_path12.default.dirname(destDir), { recursive: true });
|
|
8215
|
+
const tmpDir = import_node_fs12.default.mkdtempSync(
|
|
8216
|
+
import_node_path12.default.join(import_node_path12.default.dirname(destDir), `.installing-${import_node_path12.default.basename(destDir)}-`)
|
|
6373
8217
|
);
|
|
6374
8218
|
try {
|
|
6375
8219
|
await downloadToFile(url, archivePath);
|
|
@@ -6380,32 +8224,32 @@ async function installVerifiedTarball(tarball) {
|
|
|
6380
8224
|
);
|
|
6381
8225
|
}
|
|
6382
8226
|
await extractTarball(archivePath, tmpDir, tarball.stripComponents ?? 0);
|
|
6383
|
-
if (!
|
|
8227
|
+
if (!import_node_fs12.default.existsSync(import_node_path12.default.join(tmpDir, installedMarker))) {
|
|
6384
8228
|
throw new Error(`extracted tarball for ${label} is missing ${installedMarker}`);
|
|
6385
8229
|
}
|
|
6386
8230
|
try {
|
|
6387
|
-
|
|
8231
|
+
import_node_fs12.default.renameSync(tmpDir, destDir);
|
|
6388
8232
|
} catch (err) {
|
|
6389
8233
|
if (!isErrnoCode(err, "ENOTEMPTY", "EEXIST")) throw err;
|
|
6390
8234
|
const aside = `${tmpDir}-replaced`;
|
|
6391
8235
|
try {
|
|
6392
|
-
|
|
8236
|
+
import_node_fs12.default.renameSync(destDir, aside);
|
|
6393
8237
|
} catch (moveErr) {
|
|
6394
8238
|
if (!isErrnoCode(moveErr, "ENOENT")) throw moveErr;
|
|
6395
8239
|
}
|
|
6396
8240
|
try {
|
|
6397
|
-
|
|
8241
|
+
import_node_fs12.default.renameSync(tmpDir, destDir);
|
|
6398
8242
|
} catch (landErr) {
|
|
6399
|
-
if (!isErrnoCode(landErr, "ENOTEMPTY", "EEXIST") || !
|
|
8243
|
+
if (!isErrnoCode(landErr, "ENOTEMPTY", "EEXIST") || !import_node_fs12.default.existsSync(import_node_path12.default.join(destDir, installedMarker))) {
|
|
6400
8244
|
throw landErr;
|
|
6401
8245
|
}
|
|
6402
8246
|
} finally {
|
|
6403
|
-
|
|
8247
|
+
import_node_fs12.default.rmSync(aside, { recursive: true, force: true });
|
|
6404
8248
|
}
|
|
6405
8249
|
}
|
|
6406
8250
|
} finally {
|
|
6407
|
-
|
|
6408
|
-
|
|
8251
|
+
import_node_fs12.default.rmSync(tmpDir, { recursive: true, force: true });
|
|
8252
|
+
import_node_fs12.default.rmSync(downloadDir, { recursive: true, force: true });
|
|
6409
8253
|
}
|
|
6410
8254
|
}
|
|
6411
8255
|
function isErrnoCode(err, ...codes) {
|
|
@@ -6416,17 +8260,17 @@ async function downloadToFile(url, destPath) {
|
|
|
6416
8260
|
if (!res.ok || !res.body) {
|
|
6417
8261
|
throw new Error(`download failed: ${res.status} ${res.statusText} (${url})`);
|
|
6418
8262
|
}
|
|
6419
|
-
|
|
8263
|
+
import_node_fs12.default.mkdirSync(import_node_path12.default.dirname(destPath), { recursive: true });
|
|
6420
8264
|
const tmp = `${destPath}.partial`;
|
|
6421
8265
|
try {
|
|
6422
8266
|
await (0, import_promises3.pipeline)(
|
|
6423
8267
|
import_node_stream.Readable.fromWeb(res.body),
|
|
6424
|
-
|
|
8268
|
+
import_node_fs12.default.createWriteStream(tmp)
|
|
6425
8269
|
);
|
|
6426
|
-
|
|
8270
|
+
import_node_fs12.default.renameSync(tmp, destPath);
|
|
6427
8271
|
} catch (err) {
|
|
6428
8272
|
try {
|
|
6429
|
-
|
|
8273
|
+
import_node_fs12.default.unlinkSync(tmp);
|
|
6430
8274
|
} catch {
|
|
6431
8275
|
}
|
|
6432
8276
|
throw err;
|
|
@@ -6434,8 +8278,8 @@ async function downloadToFile(url, destPath) {
|
|
|
6434
8278
|
}
|
|
6435
8279
|
function digestFile(filePath, algorithm, encoding) {
|
|
6436
8280
|
return new Promise((resolve5, reject) => {
|
|
6437
|
-
const hash =
|
|
6438
|
-
const stream =
|
|
8281
|
+
const hash = import_node_crypto6.default.createHash(algorithm);
|
|
8282
|
+
const stream = import_node_fs12.default.createReadStream(filePath);
|
|
6439
8283
|
stream.on("data", (chunk) => hash.update(chunk));
|
|
6440
8284
|
stream.on("error", reject);
|
|
6441
8285
|
stream.on("end", () => resolve5(hash.digest(encoding)));
|
|
@@ -6445,7 +8289,7 @@ function extractTarball(tarPath, destDir, stripComponents) {
|
|
|
6445
8289
|
return new Promise((resolve5, reject) => {
|
|
6446
8290
|
const args = ["-xzf", tarPath, "-C", destDir];
|
|
6447
8291
|
if (stripComponents > 0) args.push(`--strip-components=${stripComponents}`);
|
|
6448
|
-
const child = (0,
|
|
8292
|
+
const child = (0, import_node_child_process5.spawn)("tar", args, {
|
|
6449
8293
|
stdio: ["ignore", "inherit", "inherit"]
|
|
6450
8294
|
});
|
|
6451
8295
|
child.on("error", reject);
|
|
@@ -6585,20 +8429,20 @@ var RNX_RUNTIME_PRODUCT = {
|
|
|
6585
8429
|
var rnxRuntime = createRuntimeDelivery(RNX_RUNTIME_PRODUCT);
|
|
6586
8430
|
|
|
6587
8431
|
// src/host/agent-host.ts
|
|
6588
|
-
var
|
|
6589
|
-
var
|
|
6590
|
-
var
|
|
8432
|
+
var import_node_crypto9 = require("node:crypto");
|
|
8433
|
+
var import_node_fs16 = __toESM(require("node:fs"), 1);
|
|
8434
|
+
var import_node_path16 = __toESM(require("node:path"), 1);
|
|
6591
8435
|
|
|
6592
8436
|
// src/agent-sessions.ts
|
|
6593
|
-
var
|
|
6594
|
-
var
|
|
6595
|
-
var
|
|
6596
|
-
var
|
|
8437
|
+
var import_node_child_process6 = require("node:child_process");
|
|
8438
|
+
var import_node_crypto8 = require("node:crypto");
|
|
8439
|
+
var import_node_fs15 = __toESM(require("node:fs"), 1);
|
|
8440
|
+
var import_node_path15 = __toESM(require("node:path"), 1);
|
|
6597
8441
|
var import_node_readline = __toESM(require("node:readline"), 1);
|
|
6598
8442
|
|
|
6599
8443
|
// cli/self-invocation.ts
|
|
6600
|
-
var
|
|
6601
|
-
var
|
|
8444
|
+
var import_node_fs13 = require("node:fs");
|
|
8445
|
+
var import_node_path13 = require("node:path");
|
|
6602
8446
|
var import_node_url3 = require("node:url");
|
|
6603
8447
|
init_public_brand();
|
|
6604
8448
|
|
|
@@ -6608,14 +8452,14 @@ var IS_STANDALONE = typeof __SOOTSIM_STANDALONE__ !== "undefined" && __SOOTSIM_S
|
|
|
6608
8452
|
// cli/self-invocation.ts
|
|
6609
8453
|
function sourceEntryPath() {
|
|
6610
8454
|
try {
|
|
6611
|
-
const candidate = (0,
|
|
6612
|
-
return (0,
|
|
8455
|
+
const candidate = (0, import_node_path13.join)((0, import_node_path13.dirname)((0, import_node_url3.fileURLToPath)(__sootsim_import_meta_url)), "bin.ts");
|
|
8456
|
+
return (0, import_node_fs13.existsSync)(candidate) ? candidate : null;
|
|
6613
8457
|
} catch {
|
|
6614
8458
|
return null;
|
|
6615
8459
|
}
|
|
6616
8460
|
}
|
|
6617
|
-
function isCliEntry(
|
|
6618
|
-
const name2 = (0,
|
|
8461
|
+
function isCliEntry(path16) {
|
|
8462
|
+
const name2 = (0, import_node_path13.basename)(path16);
|
|
6619
8463
|
return name2 === "bin.ts" || name2 === "bin.js";
|
|
6620
8464
|
}
|
|
6621
8465
|
function rnxSelfInvocation() {
|
|
@@ -6674,9 +8518,9 @@ function encodeAgentPromptEnvelope(input) {
|
|
|
6674
8518
|
}
|
|
6675
8519
|
|
|
6676
8520
|
// src/attached-projects.ts
|
|
6677
|
-
var
|
|
6678
|
-
var
|
|
6679
|
-
var
|
|
8521
|
+
var import_node_crypto7 = require("node:crypto");
|
|
8522
|
+
var import_node_fs14 = __toESM(require("node:fs"), 1);
|
|
8523
|
+
var import_node_path14 = __toESM(require("node:path"), 1);
|
|
6680
8524
|
init_home_paths();
|
|
6681
8525
|
var overrideDir = null;
|
|
6682
8526
|
function userDataDir() {
|
|
@@ -6689,7 +8533,7 @@ function getUserDataDir() {
|
|
|
6689
8533
|
return userDataDir();
|
|
6690
8534
|
}
|
|
6691
8535
|
function storeFile() {
|
|
6692
|
-
return
|
|
8536
|
+
return import_node_path14.default.join(userDataDir(), "attached-projects.json");
|
|
6693
8537
|
}
|
|
6694
8538
|
function cloneEmpty() {
|
|
6695
8539
|
return {
|
|
@@ -6701,15 +8545,15 @@ function cloneEmpty() {
|
|
|
6701
8545
|
}
|
|
6702
8546
|
function loadStore() {
|
|
6703
8547
|
const file = storeFile();
|
|
6704
|
-
let
|
|
8548
|
+
let raw2;
|
|
6705
8549
|
try {
|
|
6706
|
-
|
|
8550
|
+
raw2 = import_node_fs14.default.readFileSync(file, "utf8");
|
|
6707
8551
|
} catch (err) {
|
|
6708
8552
|
if (err.code === "ENOENT") return cloneEmpty();
|
|
6709
8553
|
throw err;
|
|
6710
8554
|
}
|
|
6711
8555
|
try {
|
|
6712
|
-
const parsed = JSON.parse(
|
|
8556
|
+
const parsed = JSON.parse(raw2);
|
|
6713
8557
|
if (!parsed || typeof parsed !== "object") throw new Error("not an object");
|
|
6714
8558
|
return {
|
|
6715
8559
|
version: 1,
|
|
@@ -6720,7 +8564,7 @@ function loadStore() {
|
|
|
6720
8564
|
} catch (err) {
|
|
6721
8565
|
const quarantine = `${file}.corrupt-${Date.now()}`;
|
|
6722
8566
|
try {
|
|
6723
|
-
|
|
8567
|
+
import_node_fs14.default.renameSync(file, quarantine);
|
|
6724
8568
|
console.warn(
|
|
6725
8569
|
`[sootsim] attached-projects.json was unparseable; quarantined to ${quarantine}. original error: ${err.message}`
|
|
6726
8570
|
);
|
|
@@ -6731,16 +8575,16 @@ function loadStore() {
|
|
|
6731
8575
|
}
|
|
6732
8576
|
function writeStore(store) {
|
|
6733
8577
|
const file = storeFile();
|
|
6734
|
-
|
|
8578
|
+
import_node_fs14.default.mkdirSync(import_node_path14.default.dirname(file), { recursive: true });
|
|
6735
8579
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
6736
|
-
const fd =
|
|
8580
|
+
const fd = import_node_fs14.default.openSync(tmp, "w", 384);
|
|
6737
8581
|
try {
|
|
6738
|
-
|
|
6739
|
-
|
|
8582
|
+
import_node_fs14.default.writeFileSync(fd, JSON.stringify(store, null, 2));
|
|
8583
|
+
import_node_fs14.default.fsyncSync(fd);
|
|
6740
8584
|
} finally {
|
|
6741
|
-
|
|
8585
|
+
import_node_fs14.default.closeSync(fd);
|
|
6742
8586
|
}
|
|
6743
|
-
|
|
8587
|
+
import_node_fs14.default.renameSync(tmp, file);
|
|
6744
8588
|
}
|
|
6745
8589
|
function mutateStore(fn) {
|
|
6746
8590
|
const store = loadStore();
|
|
@@ -6749,13 +8593,13 @@ function mutateStore(fn) {
|
|
|
6749
8593
|
return store;
|
|
6750
8594
|
}
|
|
6751
8595
|
function projectIdForCwd(cwd) {
|
|
6752
|
-
return (0,
|
|
8596
|
+
return (0, import_node_crypto7.createHash)("sha256").update(import_node_path14.default.resolve(cwd)).digest("hex").slice(0, 16);
|
|
6753
8597
|
}
|
|
6754
8598
|
function newSessionId() {
|
|
6755
|
-
return `s_${(0,
|
|
8599
|
+
return `s_${(0, import_node_crypto7.randomBytes)(10).toString("hex")}`;
|
|
6756
8600
|
}
|
|
6757
8601
|
function upsertProject(input) {
|
|
6758
|
-
const cwd =
|
|
8602
|
+
const cwd = import_node_path14.default.resolve(input.cwd);
|
|
6759
8603
|
const id = projectIdForCwd(cwd);
|
|
6760
8604
|
let result;
|
|
6761
8605
|
mutateStore((store) => {
|
|
@@ -6781,7 +8625,7 @@ function upsertProject(input) {
|
|
|
6781
8625
|
const now = Date.now();
|
|
6782
8626
|
const created = {
|
|
6783
8627
|
id,
|
|
6784
|
-
name: input.name ??
|
|
8628
|
+
name: input.name ?? import_node_path14.default.basename(cwd),
|
|
6785
8629
|
cwd,
|
|
6786
8630
|
repoRoot: input.repoRoot,
|
|
6787
8631
|
sourceRoots: input.sourceRoots ?? [cwd],
|
|
@@ -6927,8 +8771,8 @@ async function seedFromDemoAppRegistry() {
|
|
|
6927
8771
|
if (apps.length === 0) return;
|
|
6928
8772
|
mutateStore((store) => {
|
|
6929
8773
|
for (const app of apps) {
|
|
6930
|
-
if (!
|
|
6931
|
-
const cwd =
|
|
8774
|
+
if (!import_node_fs14.default.existsSync(app.dir)) continue;
|
|
8775
|
+
const cwd = import_node_path14.default.resolve(app.dir);
|
|
6932
8776
|
const id = projectIdForCwd(cwd);
|
|
6933
8777
|
if (store.attachedProjects.some((p) => p.id === id)) continue;
|
|
6934
8778
|
const now = Date.now();
|
|
@@ -6953,16 +8797,16 @@ async function seedFromDemoAppRegistry() {
|
|
|
6953
8797
|
// src/agent-sessions.ts
|
|
6954
8798
|
init_public_brand();
|
|
6955
8799
|
function sessionDir(sessionId) {
|
|
6956
|
-
return
|
|
8800
|
+
return import_node_path15.default.join(getUserDataDir(), "sessions", sessionId);
|
|
6957
8801
|
}
|
|
6958
8802
|
function promptFifoPath(sessionId) {
|
|
6959
|
-
return
|
|
8803
|
+
return import_node_path15.default.join(sessionDir(sessionId), "prompt.in");
|
|
6960
8804
|
}
|
|
6961
8805
|
function eventsFifoPath(sessionId) {
|
|
6962
|
-
return
|
|
8806
|
+
return import_node_path15.default.join(sessionDir(sessionId), "events.out");
|
|
6963
8807
|
}
|
|
6964
8808
|
function transcriptPath(sessionId) {
|
|
6965
|
-
return
|
|
8809
|
+
return import_node_path15.default.join(getUserDataDir(), "transcripts", `${sessionId}.log`);
|
|
6966
8810
|
}
|
|
6967
8811
|
function pidIsAlive(pid, sessionId) {
|
|
6968
8812
|
if (!pid) return false;
|
|
@@ -6972,7 +8816,7 @@ function pidIsAlive(pid, sessionId) {
|
|
|
6972
8816
|
return false;
|
|
6973
8817
|
}
|
|
6974
8818
|
if (sessionId) {
|
|
6975
|
-
if (!
|
|
8819
|
+
if (!import_node_fs15.default.existsSync(sessionDir(sessionId))) return false;
|
|
6976
8820
|
}
|
|
6977
8821
|
return true;
|
|
6978
8822
|
}
|
|
@@ -6985,11 +8829,11 @@ function resolveSootsimInvocation() {
|
|
|
6985
8829
|
const resourcesPath = process.resourcesPath;
|
|
6986
8830
|
if (resourcesPath) {
|
|
6987
8831
|
const candidates = [
|
|
6988
|
-
|
|
6989
|
-
|
|
8832
|
+
import_node_path15.default.join(resourcesPath, "bin", "sootsim"),
|
|
8833
|
+
import_node_path15.default.join(resourcesPath, "bin", `sootsim-${process.platform}-${process.arch}`)
|
|
6990
8834
|
];
|
|
6991
8835
|
for (const c of candidates) {
|
|
6992
|
-
if (
|
|
8836
|
+
if (import_node_fs15.default.existsSync(c)) return { executable: c, prefixArgs: [] };
|
|
6993
8837
|
}
|
|
6994
8838
|
}
|
|
6995
8839
|
}
|
|
@@ -7008,15 +8852,15 @@ function tryWorkspaceSootsim() {
|
|
|
7008
8852
|
const sootsimDir = resolveSootsimPackageDir();
|
|
7009
8853
|
if (!sootsimDir) return null;
|
|
7010
8854
|
const binaryName = `peach-${process.platform === "win32" ? "windows" : process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`;
|
|
7011
|
-
const distBinary =
|
|
7012
|
-
if (
|
|
7013
|
-
const distBin =
|
|
7014
|
-
if (
|
|
8855
|
+
const distBinary = import_node_path15.default.join(sootsimDir, "dist-bin", binaryName);
|
|
8856
|
+
if (import_node_fs15.default.existsSync(distBinary)) return { executable: distBinary, prefixArgs: [] };
|
|
8857
|
+
const distBin = import_node_path15.default.join(sootsimDir, "dist-cli", "bin.js");
|
|
8858
|
+
if (import_node_fs15.default.existsSync(distBin)) {
|
|
7015
8859
|
try {
|
|
7016
|
-
const src =
|
|
7017
|
-
if (
|
|
7018
|
-
const srcMtime =
|
|
7019
|
-
const buildMtime =
|
|
8860
|
+
const src = import_node_path15.default.join(sootsimDir, "cli", "commands", "agent-wrapper.ts");
|
|
8861
|
+
if (import_node_fs15.default.existsSync(src)) {
|
|
8862
|
+
const srcMtime = import_node_fs15.default.statSync(src).mtimeMs;
|
|
8863
|
+
const buildMtime = import_node_fs15.default.statSync(distBin).mtimeMs;
|
|
7020
8864
|
if (buildMtime < srcMtime) {
|
|
7021
8865
|
console.warn(
|
|
7022
8866
|
`[peach] dist-cli/bin.js is older than agent-wrapper.ts \u2014 rebuild with \`bun run --cwd packages/peachsim build:cli\`.`
|
|
@@ -7035,22 +8879,22 @@ function tryWorkspaceSootsim() {
|
|
|
7035
8879
|
function resolveSootsimPackageDir() {
|
|
7036
8880
|
try {
|
|
7037
8881
|
const resolved = require.resolve(`${rnxPublicBrand.packageName}/package.json`);
|
|
7038
|
-
return
|
|
8882
|
+
return import_node_path15.default.dirname(resolved);
|
|
7039
8883
|
} catch {
|
|
7040
8884
|
}
|
|
7041
8885
|
const here = fileFromImportMeta();
|
|
7042
8886
|
if (!here) return null;
|
|
7043
|
-
let cur =
|
|
8887
|
+
let cur = import_node_path15.default.dirname(here);
|
|
7044
8888
|
for (let i = 0; i < 8; i++) {
|
|
7045
|
-
const pkg =
|
|
8889
|
+
const pkg = import_node_path15.default.join(cur, "package.json");
|
|
7046
8890
|
try {
|
|
7047
|
-
if (
|
|
7048
|
-
const parsed = JSON.parse(
|
|
8891
|
+
if (import_node_fs15.default.existsSync(pkg)) {
|
|
8892
|
+
const parsed = JSON.parse(import_node_fs15.default.readFileSync(pkg, "utf8"));
|
|
7049
8893
|
if (parsed.name === rnxPublicBrand.packageName) return cur;
|
|
7050
8894
|
}
|
|
7051
8895
|
} catch {
|
|
7052
8896
|
}
|
|
7053
|
-
const parent =
|
|
8897
|
+
const parent = import_node_path15.default.dirname(cur);
|
|
7054
8898
|
if (parent === cur) break;
|
|
7055
8899
|
cur = parent;
|
|
7056
8900
|
}
|
|
@@ -7066,28 +8910,28 @@ function fileFromImportMeta() {
|
|
|
7066
8910
|
}
|
|
7067
8911
|
}
|
|
7068
8912
|
async function withStartLock(projectId, provider, fn) {
|
|
7069
|
-
const lockDir =
|
|
7070
|
-
|
|
8913
|
+
const lockDir = import_node_path15.default.join(getUserDataDir(), "locks");
|
|
8914
|
+
import_node_fs15.default.mkdirSync(lockDir, { recursive: true });
|
|
7071
8915
|
try {
|
|
7072
|
-
|
|
8916
|
+
import_node_fs15.default.chmodSync(lockDir, 448);
|
|
7073
8917
|
} catch {
|
|
7074
8918
|
}
|
|
7075
|
-
const lockPath =
|
|
8919
|
+
const lockPath = import_node_path15.default.join(lockDir, `start-${projectId}-${provider}.lock`);
|
|
7076
8920
|
const deadline = Date.now() + 4e3;
|
|
7077
8921
|
let fd = null;
|
|
7078
8922
|
while (fd === null) {
|
|
7079
8923
|
try {
|
|
7080
|
-
fd =
|
|
8924
|
+
fd = import_node_fs15.default.openSync(
|
|
7081
8925
|
lockPath,
|
|
7082
|
-
|
|
8926
|
+
import_node_fs15.constants.O_WRONLY | import_node_fs15.constants.O_CREAT | import_node_fs15.constants.O_EXCL,
|
|
7083
8927
|
384
|
|
7084
8928
|
);
|
|
7085
8929
|
} catch (err) {
|
|
7086
8930
|
if (err.code !== "EEXIST") throw err;
|
|
7087
8931
|
try {
|
|
7088
|
-
const stale = Number(
|
|
8932
|
+
const stale = Number(import_node_fs15.default.readFileSync(lockPath, "utf8").trim());
|
|
7089
8933
|
if (stale && !isProcessAlive(stale)) {
|
|
7090
|
-
|
|
8934
|
+
import_node_fs15.default.unlinkSync(lockPath);
|
|
7091
8935
|
continue;
|
|
7092
8936
|
}
|
|
7093
8937
|
} catch {
|
|
@@ -7101,15 +8945,15 @@ async function withStartLock(projectId, provider, fn) {
|
|
|
7101
8945
|
}
|
|
7102
8946
|
}
|
|
7103
8947
|
try {
|
|
7104
|
-
|
|
8948
|
+
import_node_fs15.default.writeFileSync(fd, String(process.pid));
|
|
7105
8949
|
return await fn();
|
|
7106
8950
|
} finally {
|
|
7107
8951
|
try {
|
|
7108
|
-
|
|
8952
|
+
import_node_fs15.default.closeSync(fd);
|
|
7109
8953
|
} catch {
|
|
7110
8954
|
}
|
|
7111
8955
|
try {
|
|
7112
|
-
|
|
8956
|
+
import_node_fs15.default.unlinkSync(lockPath);
|
|
7113
8957
|
} catch {
|
|
7114
8958
|
}
|
|
7115
8959
|
}
|
|
@@ -7123,28 +8967,28 @@ function isProcessAlive(pid) {
|
|
|
7123
8967
|
}
|
|
7124
8968
|
}
|
|
7125
8969
|
function mkfifoSync(p) {
|
|
7126
|
-
const parent =
|
|
7127
|
-
|
|
8970
|
+
const parent = import_node_path15.default.dirname(p);
|
|
8971
|
+
import_node_fs15.default.mkdirSync(parent, { recursive: true });
|
|
7128
8972
|
try {
|
|
7129
|
-
|
|
8973
|
+
import_node_fs15.default.chmodSync(parent, 448);
|
|
7130
8974
|
} catch {
|
|
7131
8975
|
}
|
|
7132
|
-
if (
|
|
8976
|
+
if (import_node_fs15.default.existsSync(p)) {
|
|
7133
8977
|
try {
|
|
7134
|
-
const stat2 =
|
|
8978
|
+
const stat2 = import_node_fs15.default.statSync(p);
|
|
7135
8979
|
if (stat2.isFIFO()) {
|
|
7136
8980
|
try {
|
|
7137
|
-
|
|
8981
|
+
import_node_fs15.default.chmodSync(p, 384);
|
|
7138
8982
|
} catch {
|
|
7139
8983
|
}
|
|
7140
8984
|
return;
|
|
7141
8985
|
}
|
|
7142
|
-
|
|
8986
|
+
import_node_fs15.default.unlinkSync(p);
|
|
7143
8987
|
} catch {
|
|
7144
|
-
|
|
8988
|
+
import_node_fs15.default.unlinkSync(p);
|
|
7145
8989
|
}
|
|
7146
8990
|
}
|
|
7147
|
-
const result = (0,
|
|
8991
|
+
const result = (0, import_node_child_process6.spawnSync)("mkfifo", ["-m", "600", p]);
|
|
7148
8992
|
if (result.status !== 0) {
|
|
7149
8993
|
throw new Error(
|
|
7150
8994
|
`mkfifo(${p}) failed: ${result.stderr?.toString().trim() || "unknown error"}`
|
|
@@ -7174,7 +9018,7 @@ async function startSession(opts) {
|
|
|
7174
9018
|
`session already running for project=${project.id} provider=${provider} (session ${existingLive.id}, pid ${existingLive.wrapperPid}). end it first with \`peach agent end <sessionId>\`.`
|
|
7175
9019
|
);
|
|
7176
9020
|
}
|
|
7177
|
-
const claudeSessionUuid = provider === "claude" ? (0,
|
|
9021
|
+
const claudeSessionUuid = provider === "claude" ? (0, import_node_crypto8.randomUUID)() : void 0;
|
|
7178
9022
|
const session = upsertSession({
|
|
7179
9023
|
projectId: project.id,
|
|
7180
9024
|
provider,
|
|
@@ -7188,10 +9032,10 @@ async function startSession(opts) {
|
|
|
7188
9032
|
const transcript = transcriptPath(session.id);
|
|
7189
9033
|
mkfifoSync(promptIn);
|
|
7190
9034
|
mkfifoSync(eventsOut);
|
|
7191
|
-
const transcriptDir =
|
|
7192
|
-
|
|
9035
|
+
const transcriptDir = import_node_path15.default.dirname(transcript);
|
|
9036
|
+
import_node_fs15.default.mkdirSync(transcriptDir, { recursive: true });
|
|
7193
9037
|
try {
|
|
7194
|
-
|
|
9038
|
+
import_node_fs15.default.chmodSync(transcriptDir, 448);
|
|
7195
9039
|
} catch {
|
|
7196
9040
|
}
|
|
7197
9041
|
const { executable, prefixArgs } = resolveSootsimInvocation();
|
|
@@ -7219,7 +9063,7 @@ async function startSession(opts) {
|
|
|
7219
9063
|
if (claudeSessionUuid) {
|
|
7220
9064
|
wrapperArgs.push("--claude-session-uuid", claudeSessionUuid);
|
|
7221
9065
|
}
|
|
7222
|
-
const child = (0,
|
|
9066
|
+
const child = (0, import_node_child_process6.spawn)(executable, wrapperArgs, {
|
|
7223
9067
|
detached: true,
|
|
7224
9068
|
stdio: "ignore",
|
|
7225
9069
|
env: {
|
|
@@ -7242,7 +9086,7 @@ async function startSession(opts) {
|
|
|
7242
9086
|
}
|
|
7243
9087
|
}
|
|
7244
9088
|
try {
|
|
7245
|
-
|
|
9089
|
+
import_node_fs15.default.rmSync(sessionDir(session.id), { recursive: true, force: true });
|
|
7246
9090
|
} catch {
|
|
7247
9091
|
}
|
|
7248
9092
|
updateSessionStatus(session.id, { status: "ended" });
|
|
@@ -7270,18 +9114,18 @@ async function sendPrompt(sessionId, prompt) {
|
|
|
7270
9114
|
);
|
|
7271
9115
|
}
|
|
7272
9116
|
const fifo = promptFifoPath(sessionId);
|
|
7273
|
-
if (!
|
|
9117
|
+
if (!import_node_fs15.default.existsSync(fifo)) {
|
|
7274
9118
|
throw new AgentSessionError("NO_FIFO", `prompt FIFO missing: ${fifo}`);
|
|
7275
9119
|
}
|
|
7276
|
-
const fd =
|
|
9120
|
+
const fd = import_node_fs15.default.openSync(fifo, import_node_fs15.constants.O_WRONLY);
|
|
7277
9121
|
try {
|
|
7278
9122
|
const wireText = encodeAgentPromptEnvelope(prompt);
|
|
7279
9123
|
if (!wireText) {
|
|
7280
9124
|
throw new AgentSessionError("EMPTY_PROMPT", "prompt text is empty");
|
|
7281
9125
|
}
|
|
7282
|
-
|
|
9126
|
+
import_node_fs15.default.writeSync(fd, wireText + "\n");
|
|
7283
9127
|
} finally {
|
|
7284
|
-
|
|
9128
|
+
import_node_fs15.default.closeSync(fd);
|
|
7285
9129
|
}
|
|
7286
9130
|
updateSessionStatus(sessionId, {
|
|
7287
9131
|
lastPrompt: prompt.displayText ?? prompt.text,
|
|
@@ -7303,7 +9147,7 @@ async function endSession(sessionId) {
|
|
|
7303
9147
|
const base = getUserDataDir();
|
|
7304
9148
|
if (dir.startsWith(base)) {
|
|
7305
9149
|
try {
|
|
7306
|
-
|
|
9150
|
+
import_node_fs15.default.rmSync(dir, { recursive: true, force: true });
|
|
7307
9151
|
} catch {
|
|
7308
9152
|
}
|
|
7309
9153
|
}
|
|
@@ -7311,11 +9155,11 @@ async function endSession(sessionId) {
|
|
|
7311
9155
|
}
|
|
7312
9156
|
function subscribeEvents(sessionId, onEvent) {
|
|
7313
9157
|
const fifo = eventsFifoPath(sessionId);
|
|
7314
|
-
if (!
|
|
9158
|
+
if (!import_node_fs15.default.existsSync(fifo)) {
|
|
7315
9159
|
throw new AgentSessionError("NO_FIFO", `events FIFO missing: ${fifo}`);
|
|
7316
9160
|
}
|
|
7317
|
-
const fd =
|
|
7318
|
-
const stream =
|
|
9161
|
+
const fd = import_node_fs15.default.openSync(fifo, import_node_fs15.constants.O_RDWR);
|
|
9162
|
+
const stream = import_node_fs15.default.createReadStream("", { fd, autoClose: true });
|
|
7319
9163
|
const rl = import_node_readline.default.createInterface({ input: stream, crlfDelay: Infinity });
|
|
7320
9164
|
rl.on("line", (line) => {
|
|
7321
9165
|
const event = parseAgentEventLine(line);
|
|
@@ -7326,7 +9170,7 @@ function subscribeEvents(sessionId, onEvent) {
|
|
|
7326
9170
|
if (closed) return;
|
|
7327
9171
|
closed = true;
|
|
7328
9172
|
try {
|
|
7329
|
-
|
|
9173
|
+
import_node_fs15.default.writeSync(fd, "\n");
|
|
7330
9174
|
} catch {
|
|
7331
9175
|
}
|
|
7332
9176
|
try {
|
|
@@ -7340,7 +9184,7 @@ function subscribeEvents(sessionId, onEvent) {
|
|
|
7340
9184
|
};
|
|
7341
9185
|
}
|
|
7342
9186
|
async function waitForFirstEvent(fifo, predicate, timeoutMs) {
|
|
7343
|
-
const fd =
|
|
9187
|
+
const fd = import_node_fs15.default.openSync(fifo, import_node_fs15.constants.O_RDWR | import_node_fs15.constants.O_NONBLOCK);
|
|
7344
9188
|
const buf = Buffer.alloc(8192);
|
|
7345
9189
|
let leftover = "";
|
|
7346
9190
|
const deadline = Date.now() + timeoutMs;
|
|
@@ -7348,7 +9192,7 @@ async function waitForFirstEvent(fifo, predicate, timeoutMs) {
|
|
|
7348
9192
|
while (Date.now() < deadline) {
|
|
7349
9193
|
let n = 0;
|
|
7350
9194
|
try {
|
|
7351
|
-
n =
|
|
9195
|
+
n = import_node_fs15.default.readSync(fd, buf, 0, buf.length, null);
|
|
7352
9196
|
} catch (err) {
|
|
7353
9197
|
if (err.code !== "EAGAIN") throw err;
|
|
7354
9198
|
n = 0;
|
|
@@ -7368,7 +9212,7 @@ async function waitForFirstEvent(fifo, predicate, timeoutMs) {
|
|
|
7368
9212
|
}
|
|
7369
9213
|
return null;
|
|
7370
9214
|
} finally {
|
|
7371
|
-
|
|
9215
|
+
import_node_fs15.default.closeSync(fd);
|
|
7372
9216
|
}
|
|
7373
9217
|
}
|
|
7374
9218
|
|
|
@@ -7576,7 +9420,7 @@ var AgentHost = class {
|
|
|
7576
9420
|
throw new AgentSessionError("EMPTY_PROMPT", "inspect message cannot be empty");
|
|
7577
9421
|
}
|
|
7578
9422
|
const message = {
|
|
7579
|
-
id: `inspect-${(0,
|
|
9423
|
+
id: `inspect-${(0, import_node_crypto9.randomUUID)()}`,
|
|
7580
9424
|
simId,
|
|
7581
9425
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7582
9426
|
prompt
|
|
@@ -7622,7 +9466,7 @@ var AgentHost = class {
|
|
|
7622
9466
|
);
|
|
7623
9467
|
const project = upsertProject({
|
|
7624
9468
|
cwd: match.cwd,
|
|
7625
|
-
name: match.projectName ??
|
|
9469
|
+
name: match.projectName ?? import_node_path16.default.basename(match.cwd),
|
|
7626
9470
|
preferredProvider: input.provider ?? existing?.preferredProvider,
|
|
7627
9471
|
sourceRoots: existing?.sourceRoots ?? [match.cwd],
|
|
7628
9472
|
knownBundleUrls,
|
|
@@ -7633,18 +9477,18 @@ var AgentHost = class {
|
|
|
7633
9477
|
}
|
|
7634
9478
|
getTranscript(sessionId) {
|
|
7635
9479
|
const p = transcriptPath(sessionId);
|
|
7636
|
-
if (!
|
|
9480
|
+
if (!import_node_fs16.default.existsSync(p)) {
|
|
7637
9481
|
return { error: "transcript not found", code: "NO_TRANSCRIPT" };
|
|
7638
9482
|
}
|
|
7639
|
-
return
|
|
9483
|
+
return import_node_fs16.default.readFileSync(p, "utf8");
|
|
7640
9484
|
}
|
|
7641
9485
|
getPaths() {
|
|
7642
9486
|
const dir = getUserDataDir();
|
|
7643
9487
|
return {
|
|
7644
9488
|
userDataDir: dir,
|
|
7645
|
-
storeFile:
|
|
7646
|
-
sessionsDir:
|
|
7647
|
-
transcriptsDir:
|
|
9489
|
+
storeFile: import_node_path16.default.join(dir, "attached-projects.json"),
|
|
9490
|
+
sessionsDir: import_node_path16.default.join(dir, "sessions"),
|
|
9491
|
+
transcriptsDir: import_node_path16.default.join(dir, "transcripts")
|
|
7648
9492
|
};
|
|
7649
9493
|
}
|
|
7650
9494
|
// --- subscription management ---
|
|
@@ -7960,9 +9804,9 @@ var HOST_HEADER_OVERRIDES = [
|
|
|
7960
9804
|
}
|
|
7961
9805
|
];
|
|
7962
9806
|
function headerOverridesFor(hostname) {
|
|
7963
|
-
const
|
|
9807
|
+
const host2 = hostname.toLowerCase();
|
|
7964
9808
|
for (const override of HOST_HEADER_OVERRIDES) {
|
|
7965
|
-
if (
|
|
9809
|
+
if (host2 === override.hostSuffix || host2.endsWith(`.${override.hostSuffix}`)) {
|
|
7966
9810
|
return override;
|
|
7967
9811
|
}
|
|
7968
9812
|
}
|
|
@@ -7984,9 +9828,9 @@ var PUBLIC_RPC_BY_QUICKNODE_CHAIN = {
|
|
|
7984
9828
|
"unichain-mainnet": "https://unichain-rpc.publicnode.com"
|
|
7985
9829
|
};
|
|
7986
9830
|
function resolveFetchProxyTargetUrl(requested) {
|
|
7987
|
-
const
|
|
7988
|
-
if (!
|
|
7989
|
-
const tenant =
|
|
9831
|
+
const host2 = requested.hostname.toLowerCase();
|
|
9832
|
+
if (!host2.endsWith(QUICKNODE_HOST_SUFFIX)) return requested;
|
|
9833
|
+
const tenant = host2.slice(0, -QUICKNODE_HOST_SUFFIX.length);
|
|
7990
9834
|
if (tenant !== PUBLIC_RPC_TENANT && !tenant.startsWith(`${PUBLIC_RPC_TENANT}.`)) {
|
|
7991
9835
|
return requested;
|
|
7992
9836
|
}
|
|
@@ -8351,8 +10195,8 @@ async function openUrl(url, options = {}) {
|
|
|
8351
10195
|
}
|
|
8352
10196
|
|
|
8353
10197
|
// src/host/plane-host.ts
|
|
8354
|
-
var
|
|
8355
|
-
var
|
|
10198
|
+
var import_node_fs18 = __toESM(require("node:fs"), 1);
|
|
10199
|
+
var import_node_path18 = __toESM(require("node:path"), 1);
|
|
8356
10200
|
|
|
8357
10201
|
// ../peach-box/src/planeProtocol.ts
|
|
8358
10202
|
var PLANE_FLAG_READ_ONLY = 1;
|
|
@@ -8431,9 +10275,9 @@ async function dispatchPlaneCommand(plane, type, msg, mutationOptions) {
|
|
|
8431
10275
|
}
|
|
8432
10276
|
|
|
8433
10277
|
// cli/commands/box/checkout-plane.ts
|
|
8434
|
-
var
|
|
8435
|
-
var
|
|
8436
|
-
var
|
|
10278
|
+
var import_node_child_process7 = require("node:child_process");
|
|
10279
|
+
var import_node_fs17 = __toESM(require("node:fs"), 1);
|
|
10280
|
+
var import_node_path17 = __toESM(require("node:path"), 1);
|
|
8437
10281
|
var CheckoutRequiresGitError = class extends Error {
|
|
8438
10282
|
};
|
|
8439
10283
|
var BINARY_SNIFF_BYTES = 8192;
|
|
@@ -8444,14 +10288,14 @@ function looksBinary(filePath, size) {
|
|
|
8444
10288
|
if (size === 0) return false;
|
|
8445
10289
|
let fd;
|
|
8446
10290
|
try {
|
|
8447
|
-
fd =
|
|
10291
|
+
fd = import_node_fs17.default.openSync(filePath, "r");
|
|
8448
10292
|
const buffer = Buffer.alloc(Math.min(BINARY_SNIFF_BYTES, size));
|
|
8449
|
-
const read =
|
|
10293
|
+
const read = import_node_fs17.default.readSync(fd, buffer, 0, buffer.length, 0);
|
|
8450
10294
|
return buffer.subarray(0, read).includes(0);
|
|
8451
10295
|
} catch {
|
|
8452
10296
|
return false;
|
|
8453
10297
|
} finally {
|
|
8454
|
-
if (fd !== void 0)
|
|
10298
|
+
if (fd !== void 0) import_node_fs17.default.closeSync(fd);
|
|
8455
10299
|
}
|
|
8456
10300
|
}
|
|
8457
10301
|
var CheckoutFilePlane = class {
|
|
@@ -8464,7 +10308,7 @@ var CheckoutFilePlane = class {
|
|
|
8464
10308
|
listTimeoutMs;
|
|
8465
10309
|
trackedOnly;
|
|
8466
10310
|
constructor(root, options = {}) {
|
|
8467
|
-
this.root =
|
|
10311
|
+
this.root = import_node_path17.default.resolve(root);
|
|
8468
10312
|
this.listTimeoutMs = options.listTimeoutMs ?? LIST_FILES_TIMEOUT_MS;
|
|
8469
10313
|
this.trackedOnly = options.trackedOnly ?? false;
|
|
8470
10314
|
}
|
|
@@ -8473,7 +10317,7 @@ var CheckoutFilePlane = class {
|
|
|
8473
10317
|
}
|
|
8474
10318
|
listFiles() {
|
|
8475
10319
|
const args = this.trackedOnly ? ["ls-files", "-z"] : ["ls-files", "-co", "--exclude-standard", "-z"];
|
|
8476
|
-
const stdout = (0,
|
|
10320
|
+
const stdout = (0, import_node_child_process7.execFileSync)("git", args, {
|
|
8477
10321
|
cwd: this.root,
|
|
8478
10322
|
encoding: "utf8",
|
|
8479
10323
|
maxBuffer: 64 * 1024 * 1024,
|
|
@@ -8526,13 +10370,13 @@ var CheckoutFilePlane = class {
|
|
|
8526
10370
|
if (!relative2) continue;
|
|
8527
10371
|
let stat2;
|
|
8528
10372
|
try {
|
|
8529
|
-
stat2 =
|
|
10373
|
+
stat2 = import_node_fs17.default.statSync(import_node_path17.default.join(this.root, relative2));
|
|
8530
10374
|
} catch {
|
|
8531
10375
|
continue;
|
|
8532
10376
|
}
|
|
8533
10377
|
if (!stat2.isFile()) continue;
|
|
8534
10378
|
const seen = this.sniffed.get(relative2);
|
|
8535
|
-
const binary = seen && seen.size === stat2.size && seen.mtimeMs === stat2.mtimeMs ? seen.binary : looksBinary(
|
|
10379
|
+
const binary = seen && seen.size === stat2.size && seen.mtimeMs === stat2.mtimeMs ? seen.binary : looksBinary(import_node_path17.default.join(this.root, relative2), stat2.size);
|
|
8536
10380
|
nextSniffed.set(relative2, { size: stat2.size, mtimeMs: stat2.mtimeMs, binary });
|
|
8537
10381
|
next.set(relative2, {
|
|
8538
10382
|
size: stat2.size,
|
|
@@ -8546,22 +10390,22 @@ var CheckoutFilePlane = class {
|
|
|
8546
10390
|
this.sniffed = nextSniffed;
|
|
8547
10391
|
}
|
|
8548
10392
|
absolute(planePath) {
|
|
8549
|
-
const resolved =
|
|
8550
|
-
if (resolved !== this.root && !resolved.startsWith(`${this.root}${
|
|
10393
|
+
const resolved = import_node_path17.default.resolve(this.root, planePath);
|
|
10394
|
+
if (resolved !== this.root && !resolved.startsWith(`${this.root}${import_node_path17.default.sep}`)) {
|
|
8551
10395
|
throw new Error(`path escapes the project: ${planePath}`);
|
|
8552
10396
|
}
|
|
8553
10397
|
return resolved;
|
|
8554
10398
|
}
|
|
8555
10399
|
async read(planePath) {
|
|
8556
|
-
return
|
|
10400
|
+
return import_node_fs17.default.promises.readFile(this.absolute(planePath), "utf8");
|
|
8557
10401
|
}
|
|
8558
10402
|
async readBytes(planePath) {
|
|
8559
|
-
return
|
|
10403
|
+
return import_node_fs17.default.promises.readFile(this.absolute(planePath));
|
|
8560
10404
|
}
|
|
8561
10405
|
async write(planePath, content) {
|
|
8562
10406
|
const absolute = this.absolute(planePath);
|
|
8563
|
-
await
|
|
8564
|
-
await
|
|
10407
|
+
await import_node_fs17.default.promises.mkdir(import_node_path17.default.dirname(absolute), { recursive: true });
|
|
10408
|
+
await import_node_fs17.default.promises.writeFile(absolute, content);
|
|
8565
10409
|
this.entries.set(planePath, {
|
|
8566
10410
|
size: content.byteLength,
|
|
8567
10411
|
readOnly: false,
|
|
@@ -8570,7 +10414,7 @@ var CheckoutFilePlane = class {
|
|
|
8570
10414
|
});
|
|
8571
10415
|
}
|
|
8572
10416
|
async delete(planePath) {
|
|
8573
|
-
await
|
|
10417
|
+
await import_node_fs17.default.promises.rm(this.absolute(planePath), { force: true });
|
|
8574
10418
|
this.entries.delete(planePath);
|
|
8575
10419
|
}
|
|
8576
10420
|
};
|
|
@@ -8696,14 +10540,14 @@ var PlaneHost = class {
|
|
|
8696
10540
|
// root and an opened one cannot disagree about the same directory.
|
|
8697
10541
|
realRoot(root) {
|
|
8698
10542
|
if (!root) throw new Error("root is required");
|
|
8699
|
-
const resolved =
|
|
10543
|
+
const resolved = import_node_path18.default.resolve(root);
|
|
8700
10544
|
let real;
|
|
8701
10545
|
try {
|
|
8702
|
-
real =
|
|
10546
|
+
real = import_node_fs18.default.realpathSync(resolved);
|
|
8703
10547
|
} catch {
|
|
8704
10548
|
throw new Error(`no such directory: ${resolved}`);
|
|
8705
10549
|
}
|
|
8706
|
-
if (!
|
|
10550
|
+
if (!import_node_fs18.default.statSync(real).isDirectory()) throw new Error(`not a directory: ${real}`);
|
|
8707
10551
|
return real;
|
|
8708
10552
|
}
|
|
8709
10553
|
respond(ws, id, result) {
|
|
@@ -8723,9 +10567,9 @@ var PlaneHost = class {
|
|
|
8723
10567
|
};
|
|
8724
10568
|
|
|
8725
10569
|
// src/host/replacement-module-handler.ts
|
|
8726
|
-
var
|
|
10570
|
+
var import_node_fs19 = require("node:fs");
|
|
8727
10571
|
var import_promises5 = __toESM(require("node:fs/promises"), 1);
|
|
8728
|
-
var
|
|
10572
|
+
var import_node_path19 = __toESM(require("node:path"), 1);
|
|
8729
10573
|
|
|
8730
10574
|
// ../contrast-bundler/src/replacementModule.ts
|
|
8731
10575
|
var import_dist = require("sucrase/dist/index.js");
|
|
@@ -8764,12 +10608,12 @@ function normalize(p) {
|
|
|
8764
10608
|
if (trailingSlash) joined += "/";
|
|
8765
10609
|
return absolute ? "/" + joined : joined;
|
|
8766
10610
|
}
|
|
8767
|
-
function
|
|
10611
|
+
function join6(...parts) {
|
|
8768
10612
|
const present = parts.filter((part) => part.length > 0);
|
|
8769
10613
|
if (present.length === 0) return ".";
|
|
8770
10614
|
return normalize(present.join("/"));
|
|
8771
10615
|
}
|
|
8772
|
-
function
|
|
10616
|
+
function resolve3(...parts) {
|
|
8773
10617
|
let resolved = "";
|
|
8774
10618
|
let absolute = false;
|
|
8775
10619
|
for (let i = parts.length - 1; i >= 0 && !absolute; i--) {
|
|
@@ -8785,7 +10629,7 @@ function resolve2(...parts) {
|
|
|
8785
10629
|
const normalized = normalizeSegments(resolved.split("/"), false).join("/");
|
|
8786
10630
|
return normalized.length > 0 ? "/" + normalized : "/";
|
|
8787
10631
|
}
|
|
8788
|
-
function
|
|
10632
|
+
function dirname4(p) {
|
|
8789
10633
|
const idx = p.lastIndexOf("/");
|
|
8790
10634
|
if (idx < 0) return ".";
|
|
8791
10635
|
if (idx === 0) return "/";
|
|
@@ -8821,9 +10665,9 @@ var posix = {
|
|
|
8821
10665
|
delimiter,
|
|
8822
10666
|
isAbsolute,
|
|
8823
10667
|
normalize,
|
|
8824
|
-
join:
|
|
8825
|
-
resolve:
|
|
8826
|
-
dirname:
|
|
10668
|
+
join: join6,
|
|
10669
|
+
resolve: resolve3,
|
|
10670
|
+
dirname: dirname4,
|
|
8827
10671
|
basename: basename3,
|
|
8828
10672
|
extname,
|
|
8829
10673
|
relative
|
|
@@ -8856,12 +10700,12 @@ function transformsFor(filePath) {
|
|
|
8856
10700
|
function isLocalSpecifier(specifier) {
|
|
8857
10701
|
return specifier.startsWith("./") || specifier.startsWith("../");
|
|
8858
10702
|
}
|
|
8859
|
-
function
|
|
8860
|
-
return specifier === "
|
|
10703
|
+
function isPeachKitSpecifier(specifier) {
|
|
10704
|
+
return specifier === "peach-kit" || specifier.startsWith("peach-kit/");
|
|
8861
10705
|
}
|
|
8862
10706
|
function unsupportedSpecifier(specifier) {
|
|
8863
10707
|
return new Error(
|
|
8864
|
-
`replacement modules may only import react, react-native,
|
|
10708
|
+
`replacement modules may only import react, react-native, peach-kit, the packages rnx stubs for this app, and other project files by relative path; '${specifier}' is none of those. vendor the code into a project file, or add the package to peach.config so the simulator bridges it.`
|
|
8865
10709
|
);
|
|
8866
10710
|
}
|
|
8867
10711
|
function bridgeDeclaration(name2, specifier) {
|
|
@@ -8872,8 +10716,8 @@ function bridgeDeclaration(name2, specifier) {
|
|
|
8872
10716
|
if (specifier === "react-native") {
|
|
8873
10717
|
return `const ${name2} = ${REACT_NATIVE_BRIDGE}; if (!${name2}) throw new Error(${notReady("React Native")});`;
|
|
8874
10718
|
}
|
|
8875
|
-
if (
|
|
8876
|
-
return `const ${name2} = (globalThis.
|
|
10719
|
+
if (isPeachKitSpecifier(specifier)) {
|
|
10720
|
+
return `const ${name2} = (globalThis.__peach_kit_modules && globalThis.__peach_kit_modules[${JSON.stringify(specifier)}]) || (${PACKAGE_BRIDGES} || {})[${JSON.stringify(specifier)}]; if (!${name2}) throw new Error(${JSON.stringify(`[peach] replacement package bridge ${specifier} is not ready`)});`;
|
|
8877
10721
|
}
|
|
8878
10722
|
if (JSX_RUNTIME_SPECIFIERS.has(specifier)) {
|
|
8879
10723
|
return `const ${name2} = (() => { const react = ${REACT_BRIDGE}; if (!react) throw new Error(${notReady("React")}); const jsx = (type, props, key) => react.createElement(type, key === undefined ? props : { ...props, key }); return { Fragment: react.Fragment, jsx, jsxs: jsx, jsxDEV: jsx }; })();`;
|
|
@@ -9001,7 +10845,7 @@ function compileReplacementModule(input) {
|
|
|
9001
10845
|
pointAtLocalModule(specifierToken, specifier);
|
|
9002
10846
|
continue;
|
|
9003
10847
|
}
|
|
9004
|
-
if (specifier !== "react" && specifier !== "react-native" && !JSX_RUNTIME_SPECIFIERS.has(specifier) && !
|
|
10848
|
+
if (specifier !== "react" && specifier !== "react-native" && !JSX_RUNTIME_SPECIFIERS.has(specifier) && !isPeachKitSpecifier(specifier) && !input.runtimePackages.has(specifier)) {
|
|
9005
10849
|
throw unsupportedSpecifier(specifier);
|
|
9006
10850
|
}
|
|
9007
10851
|
const bridge = bindings.length > 0 ? bridgeFor(specifier) : null;
|
|
@@ -9050,16 +10894,16 @@ function sendJavaScript(req, res, source) {
|
|
|
9050
10894
|
res.end(req.method === "HEAD" ? void 0 : source);
|
|
9051
10895
|
}
|
|
9052
10896
|
function resolveLocalImport(fromFile, specifier) {
|
|
9053
|
-
const base =
|
|
10897
|
+
const base = import_node_path19.default.resolve(import_node_path19.default.dirname(fromFile), specifier);
|
|
9054
10898
|
const candidates = [
|
|
9055
10899
|
...REPLACEMENT_MODULE_EXTENSIONS.some(
|
|
9056
|
-
(ext) => ext ===
|
|
10900
|
+
(ext) => ext === import_node_path19.default.extname(base).toLowerCase()
|
|
9057
10901
|
) ? [base] : [],
|
|
9058
10902
|
...REPLACEMENT_MODULE_EXTENSIONS.map((ext) => base + ext),
|
|
9059
|
-
...REPLACEMENT_MODULE_EXTENSIONS.map((ext) =>
|
|
10903
|
+
...REPLACEMENT_MODULE_EXTENSIONS.map((ext) => import_node_path19.default.join(base, `index${ext}`))
|
|
9060
10904
|
];
|
|
9061
10905
|
const found = candidates.find(
|
|
9062
|
-
(candidate) => (0,
|
|
10906
|
+
(candidate) => (0, import_node_fs19.statSync)(candidate, { throwIfNoEntry: false })?.isFile()
|
|
9063
10907
|
);
|
|
9064
10908
|
if (!found) {
|
|
9065
10909
|
throw new Error(
|
|
@@ -9114,13 +10958,13 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
|
|
|
9114
10958
|
res.end("missing path param");
|
|
9115
10959
|
return true;
|
|
9116
10960
|
}
|
|
9117
|
-
const extension =
|
|
10961
|
+
const extension = import_node_path19.default.extname(targetPath).toLowerCase();
|
|
9118
10962
|
if (!REPLACEMENT_MODULE_EXTENSIONS.some((allowed) => allowed === extension)) {
|
|
9119
10963
|
res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
|
|
9120
10964
|
res.end(`replacement files must be ${REPLACEMENT_MODULE_EXTENSIONS.join(", ")}`);
|
|
9121
10965
|
return true;
|
|
9122
10966
|
}
|
|
9123
|
-
if (!
|
|
10967
|
+
if (!import_node_path19.default.isAbsolute(targetPath)) {
|
|
9124
10968
|
res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
|
|
9125
10969
|
res.end("replacement file path must be absolute");
|
|
9126
10970
|
return true;
|
|
@@ -9128,10 +10972,10 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
|
|
|
9128
10972
|
const runtimePackages = new Set(url.searchParams.getAll("runtimePackage"));
|
|
9129
10973
|
let resolvedProjectRoot;
|
|
9130
10974
|
if (options.projectRoot) {
|
|
9131
|
-
const lexicalProjectRoot =
|
|
10975
|
+
const lexicalProjectRoot = import_node_path19.default.resolve(options.projectRoot);
|
|
9132
10976
|
resolvedProjectRoot = await import_promises5.default.realpath(options.projectRoot);
|
|
9133
|
-
const lexicalTarget =
|
|
9134
|
-
if (lexicalTarget.startsWith("..") ||
|
|
10977
|
+
const lexicalTarget = import_node_path19.default.relative(lexicalProjectRoot, targetPath);
|
|
10978
|
+
if (lexicalTarget.startsWith("..") || import_node_path19.default.isAbsolute(lexicalTarget)) {
|
|
9135
10979
|
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
9136
10980
|
res.end("replacement file must be inside the project root");
|
|
9137
10981
|
return true;
|
|
@@ -9147,8 +10991,8 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
|
|
|
9147
10991
|
return true;
|
|
9148
10992
|
}
|
|
9149
10993
|
if (resolvedProjectRoot) {
|
|
9150
|
-
const relativeTarget =
|
|
9151
|
-
if (relativeTarget.startsWith("..") ||
|
|
10994
|
+
const relativeTarget = import_node_path19.default.relative(resolvedProjectRoot, resolvedTargetPath);
|
|
10995
|
+
if (relativeTarget.startsWith("..") || import_node_path19.default.isAbsolute(relativeTarget)) {
|
|
9152
10996
|
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
9153
10997
|
res.end("replacement file must be inside the project root");
|
|
9154
10998
|
return true;
|
|
@@ -9261,10 +11105,10 @@ function validateUpgradeRequest(req) {
|
|
|
9261
11105
|
}
|
|
9262
11106
|
function isSameOriginUpgrade(req) {
|
|
9263
11107
|
const origin = req.headers.origin;
|
|
9264
|
-
const
|
|
9265
|
-
if (!origin || !
|
|
11108
|
+
const host2 = req.headers.host;
|
|
11109
|
+
if (!origin || !host2) return false;
|
|
9266
11110
|
try {
|
|
9267
|
-
return new URL(origin).host ===
|
|
11111
|
+
return new URL(origin).host === host2;
|
|
9268
11112
|
} catch {
|
|
9269
11113
|
return false;
|
|
9270
11114
|
}
|
|
@@ -10320,8 +12164,8 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
|
|
|
10320
12164
|
void this.runServerScan().then((results) => sendJson(results));
|
|
10321
12165
|
}
|
|
10322
12166
|
resolveRuntimeUpdateIntervalMs() {
|
|
10323
|
-
const
|
|
10324
|
-
if (Number.isFinite(
|
|
12167
|
+
const raw2 = Number(process.env[RUNTIME_UPDATE_INTERVAL_ENV]);
|
|
12168
|
+
if (Number.isFinite(raw2) && raw2 > 0) return Math.max(100, Math.round(raw2));
|
|
10325
12169
|
return DEFAULT_RUNTIME_UPDATE_INTERVAL_MS;
|
|
10326
12170
|
}
|
|
10327
12171
|
startRuntimeUpdater() {
|
|
@@ -10452,6 +12296,18 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
|
|
|
10452
12296
|
res.setHeader("Cross-Origin-Embedder-Policy", SOOTSIM_CROSS_ORIGIN_EMBEDDER_POLICY);
|
|
10453
12297
|
res.setHeader("Cross-Origin-Resource-Policy", "cross-origin");
|
|
10454
12298
|
res.setHeader("Document-Policy", "js-profiling");
|
|
12299
|
+
if (req.url?.startsWith("/__peach/expo-swift") || req.url?.startsWith("/__peach/swift")) {
|
|
12300
|
+
void handleExpoSwiftRequest(req, res).then((handled) => {
|
|
12301
|
+
if (!handled) {
|
|
12302
|
+
res.writeHead(404);
|
|
12303
|
+
res.end("Swift artifact not found");
|
|
12304
|
+
}
|
|
12305
|
+
}).catch((error) => {
|
|
12306
|
+
res.writeHead(500);
|
|
12307
|
+
res.end(String(error));
|
|
12308
|
+
});
|
|
12309
|
+
return;
|
|
12310
|
+
}
|
|
10455
12311
|
if (isFetchProxyRequestUrl(req.url)) {
|
|
10456
12312
|
void handleFetchProxyRequest(req, res);
|
|
10457
12313
|
return;
|