peachsim 0.1.664 → 0.1.665

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.
Files changed (81) hide show
  1. package/cli/app-fonts.ts +6 -3
  2. package/cli/commands/control.ts +18 -2
  3. package/cli/commands/inspect/core.ts +19 -6
  4. package/cli/commands/inspect/settling.ts +1 -5
  5. package/dist-lib/agent-daemon-client.cjs +1 -1
  6. package/dist-lib/agent-events.cjs +1 -1
  7. package/dist-lib/agent-identity.cjs +1 -1
  8. package/dist-lib/agent-sessions.cjs +1 -1
  9. package/dist-lib/attached-projects.cjs +1 -1
  10. package/dist-lib/auth/shared-session.cjs +1 -1
  11. package/dist-lib/backend-origin.cjs +1 -1
  12. package/dist-lib/beta.cjs +1 -1
  13. package/dist-lib/beta.mjs +1 -1
  14. package/dist-lib/bridge-constants.cjs +1 -1
  15. package/dist-lib/bridge-contract-input.cjs +1 -1
  16. package/dist-lib/bridge-contract-input.mjs +1 -1
  17. package/dist-lib/bridge-contract.cjs +1 -1
  18. package/dist-lib/bridge-contract.mjs +1 -1
  19. package/dist-lib/capture-contract.cjs +1 -1
  20. package/dist-lib/capture-contract.mjs +1 -1
  21. package/dist-lib/cli-constants.cjs +1 -1
  22. package/dist-lib/cloud-contract.cjs +1 -1
  23. package/dist-lib/cloud-contract.mjs +1 -1
  24. package/dist-lib/cloud-test-args.cjs +1 -1
  25. package/dist-lib/cloud-test-args.mjs +1 -1
  26. package/dist-lib/cloud.cjs +1 -1
  27. package/dist-lib/cloud.mjs +1 -1
  28. package/dist-lib/config.cjs +1 -1
  29. package/dist-lib/detox/index.cjs +1 -1
  30. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  31. package/dist-lib/home-paths.cjs +1 -1
  32. package/dist-lib/host/bridge-host.cjs +2191 -335
  33. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  34. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  35. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  36. package/dist-lib/host/replacement-module-handler.cjs +7 -7
  37. package/dist-lib/host/websocket-proxy.cjs +1 -1
  38. package/dist-lib/index.cjs +7 -7
  39. package/dist-lib/jump-to-source-babel.cjs +1 -1
  40. package/dist-lib/jump-to-source-native.cjs +1 -1
  41. package/dist-lib/kotlin-host.cjs +1 -1
  42. package/dist-lib/menu.cjs +1 -1
  43. package/dist-lib/menu.mjs +1 -1
  44. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  45. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  46. package/dist-lib/metro-production-bundle.cjs +1 -1
  47. package/dist-lib/metro-production-bundle.mjs +1 -1
  48. package/dist-lib/metro.cjs +7 -7
  49. package/dist-lib/native-app-identity.cjs +1 -1
  50. package/dist-lib/native-app-identity.mjs +1 -1
  51. package/dist-lib/plist.cjs +1 -1
  52. package/dist-lib/plist.mjs +1 -1
  53. package/dist-lib/profiles.cjs +1 -1
  54. package/dist-lib/public-brand.cjs +1 -1
  55. package/dist-lib/react-native-host-modules.cjs +1 -1
  56. package/dist-lib/react-native-host-modules.mjs +1 -1
  57. package/dist-lib/render-mode.cjs +1 -1
  58. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  59. package/dist-lib/sdk.cjs +13 -9
  60. package/dist-lib/sdk.mjs +13 -9
  61. package/dist-lib/skills.cjs +2769 -944
  62. package/dist-lib/swift-compile.cjs +1 -1
  63. package/dist-lib/swift-compile.mjs +1 -1
  64. package/dist-lib/swift-package.cjs +1 -1
  65. package/dist-lib/swift-package.mjs +1 -1
  66. package/dist-lib/swift-submit.cjs +1 -1
  67. package/dist-lib/swift-submit.mjs +1 -1
  68. package/dist-lib/swift.cjs +1 -1
  69. package/dist-lib/vite-swift.cjs +1 -1
  70. package/dist-lib/vite.cjs +7 -7
  71. package/kotlin/ComposeSources/PeachComposeHost.kt +6 -3
  72. package/kotlin/fixtures/kotlin-app-variants/Overlays.kt +56 -0
  73. package/kotlin/fixtures/kotlin-app-variants/Scroll.kt +63 -0
  74. package/kotlin/fixtures/kotlin-app-variants/Sheet.kt +43 -0
  75. package/kotlin/fixtures/kotlin-app-variants/Tabs.kt +47 -0
  76. package/kotlin/fixtures/kotlin-app-variants/Widgets.kt +13 -2
  77. package/package.json +2 -2
  78. package/skills/peach-setup/SKILL.md +1 -1
  79. package/src/expo-swift-host.ts +248 -0
  80. package/src/host/bridge-host.ts +19 -0
  81. package/src/vite-plugin.ts +3 -3
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.664 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.665 | (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
- var LOOPBACK_PROBE_HOSTNAMES;
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 raw = import_node_fs3.default.readFileSync(configFilePath(), "utf8");
185
- const parsed = JSON.parse(raw);
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 raw = buf.subarray(0, bytesRead).toString("utf8");
254
- const parsed = JSON.parse(raw);
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(raw) {
283
+ function parseDevBridgeLockfile(raw2) {
267
284
  try {
268
- const parsed = JSON.parse(raw);
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(raw) {
366
+ function parseDaemonClaim(raw2) {
350
367
  try {
351
- const value = JSON.parse(raw);
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, import_node_path15.dirname)((0, import_node_path15.resolve)(explicit));
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, import_node_path15.resolve)(explicit);
512
- return (0, import_node_path15.join)(getBaseDir(), "desktop-auth.json");
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, import_node_fs15.existsSync)(filepath)) return null;
579
+ if (!(0, import_node_fs6.existsSync)(filepath)) return null;
563
580
  try {
564
- const parsed = JSON.parse((0, import_node_fs15.readFileSync)(filepath, "utf8"));
581
+ const parsed = JSON.parse((0, import_node_fs6.readFileSync)(filepath, "utf8"));
565
582
  const normalized = normalizeSession(parsed);
566
583
  if (!normalized) {
567
- (0, import_node_fs15.rmSync)(filepath, { force: true });
584
+ (0, import_node_fs6.rmSync)(filepath, { force: true });
568
585
  return null;
569
586
  }
570
587
  return normalized;
571
588
  } catch {
572
- (0, import_node_fs15.rmSync)(filepath, { force: true });
589
+ (0, import_node_fs6.rmSync)(filepath, { force: true });
573
590
  return null;
574
591
  }
575
592
  }
576
- var import_node_fs15, import_node_path15, SESSION_VERSION, SESSION_FILE_ENV, DEFAULT_ORIGIN;
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
- import_node_fs15 = require("node:fs");
581
- import_node_path15 = require("node:path");
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 isRecord3(value) {
746
+ function isRecord4(value) {
730
747
  return !!value && typeof value === "object" && !Array.isArray(value);
731
748
  }
732
749
  function isStorageSnapshotEntry(value) {
733
- return isRecord3(value) && typeof value.key === "string" && typeof value.value === "string";
750
+ return isRecord4(value) && typeof value.key === "string" && typeof value.value === "string";
734
751
  }
735
752
  function isSecureStoreSnapshotEntry(value) {
736
- return isRecord3(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");
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 isRecord3(value) && typeof value.currentPath === "string" && (value.routeNames == null || Array.isArray(value.routeNames) && value.routeNames.every((routeName) => typeof routeName === "string"));
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 (!isRecord3(value) || typeof value.type !== "string") return false;
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 isRecord3(value.value) && Object.values(value.value).every(isSerializedIndexedDBValue);
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 isRecord3(value) && typeof value.key === "string" && isSerializedIndexedDBValue(value.value);
780
+ return isRecord4(value) && typeof value.key === "string" && isSerializedIndexedDBValue(value.value);
764
781
  }
765
782
  function isIndexedDBStoreSnapshot(value) {
766
- return isRecord3(value) && typeof value.name === "string" && Array.isArray(value.entries) && value.entries.every(isIndexedDBSnapshotEntry);
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 isRecord3(value) && isIndexedDBSnapshotKind(value.kind) && Array.isArray(value.stores) && value.stores.every(isIndexedDBStoreSnapshot);
786
+ return isRecord4(value) && isIndexedDBSnapshotKind(value.kind) && Array.isArray(value.stores) && value.stores.every(isIndexedDBStoreSnapshot);
770
787
  }
771
788
  function isStorageSnapshot(value) {
772
- return isRecord3(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));
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 path12 = `${dir}/${filename}`;
2387
- if (!out.includes(path12)) out.push(path12);
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 assets = await assertSelfContainedMetroArtifactAssets(code);
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: { ...assets, encodedBytes: artifactEncoded },
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 path12 = literal.replaceAll("\\\\", "/").replaceAll("\\/", "/");
3354
+ const path16 = literal.replaceAll("\\\\", "/").replaceAll("\\/", "/");
3338
3355
  const nodeModulesMarker = "/node_modules/";
3339
- const nodeModulesIndex = path12.lastIndexOf(nodeModulesMarker);
3356
+ const nodeModulesIndex = path16.lastIndexOf(nodeModulesMarker);
3340
3357
  if (nodeModulesIndex >= 0) {
3341
- return `node_modules/${path12.slice(nodeModulesIndex + nodeModulesMarker.length)}`;
3358
+ return `node_modules/${path16.slice(nodeModulesIndex + nodeModulesMarker.length)}`;
3342
3359
  }
3343
- if ((path12.startsWith("/") || /^[A-Za-z]:\//.test(path12) || path12.startsWith("file:/")) && /\.[cm]?[jt]sx?(?::\d+(?::\d+)?)?$/.test(path12)) {
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 path12 = node.landmarkPath ?? `node_modules/${template.packageName}/__rnx_inferred__/${moduleId}.js`;
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 !== path12) return null;
3584
- pathsByModuleId.set(moduleId, path12);
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 path12 = assignment2.pathsByModuleId.get(moduleId);
3747
- return path12 !== void 0 && !path12.includes("/__rnx_inferred__/");
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 path12 = assignment2.pathsByModuleId.get(moduleId);
3753
- return path12 ? [metroFingerprintModuleClaimRoute(assignment2.packageName, path12)] : [];
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, import_node_path16.join)(dir, "package.json");
3953
- if (!(0, import_node_fs16.existsSync)(pkgPath)) return null;
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, import_node_path16.basename)(dir),
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, import_node_fs16.existsSync)((0, import_node_path16.join)(dir, `vite.config.${ext}`))
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, import_node_fs16.existsSync)((0, import_node_path16.join)(dir, `metro.config.${ext}`))
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(path12) {
3996
+ function readProjectMetadata(path16) {
3980
3997
  try {
3981
- const info = (0, import_node_fs16.lstatSync)(path12);
3998
+ const info = (0, import_node_fs20.lstatSync)(path16);
3982
3999
  if (!info.isFile() || info.size > 4 * 1024 * 1024) return null;
3983
- return (0, import_node_fs16.readFileSync)(path12, "utf8");
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(path12) {
3993
- const text = readProjectMetadata(path12);
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, import_node_path16.join)(dir, "package.json"));
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 import_node_fs16, import_node_path16, import_json5, import_yaml, CONFIG_EXTENSIONS;
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
- import_node_fs16 = require("node:fs");
4025
- import_node_path16 = require("node:path");
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, import_node_path17.resolve)(bundlePath);
4063
- if ((0, import_node_path17.extname)(filepath) !== ".js") {
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, import_node_fs17.openSync)(filepath, "r");
4083
+ const descriptor = (0, import_node_fs21.openSync)(filepath, "r");
4067
4084
  try {
4068
- const before = (0, import_node_fs17.fstatSync)(descriptor, { bigint: true });
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, import_node_fs17.readFileSync)(descriptor);
4076
- const after = (0, import_node_fs17.fstatSync)(descriptor, { bigint: true });
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, import_node_fs17.closeSync)(descriptor);
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, import_node_path17.resolve)(assetsPath);
4139
- if (!(0, import_node_fs17.existsSync)(directory)) return { directory, files: [], truncated: false };
4140
- const skipNested = (0, import_node_fs17.existsSync)((0, import_node_path17.join)(directory, "package.json"));
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, import_node_fs17.readdirSync)(dir, { withFileTypes: true });
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, import_node_path17.join)(dir, entry.name), prefix ? `${prefix}/${entry.name}` : entry.name);
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, import_node_crypto6.createHash)("md5");
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, import_node_fs17.readFileSync)((0, import_node_path17.join)(directory, relative2));
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, import_node_crypto6.createHash)("md5").update(bytes).digest("hex");
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, import_node_fs17.readFileSync)((0, import_node_path17.join)(listing.directory, relative2))
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, import_node_crypto6.createHash)("md5").update(file).digest("hex");
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, import_node_path17.join)(dest.directory, relative2))
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, import_node_path17.dirname)((0, import_node_path17.resolve)(bundlePath));
4272
+ const bundleDirectory = (0, import_node_path21.dirname)((0, import_node_path21.resolve)(bundlePath));
4256
4273
  const candidates = [
4257
- (0, import_node_path17.join)(bundleDirectory, "assets"),
4274
+ (0, import_node_path21.join)(bundleDirectory, "assets"),
4258
4275
  bundleDirectory,
4259
- (0, import_node_path17.resolve)(bundleDirectory, "..", "assets")
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, import_node_path17.resolve)(start);
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, import_node_path17.dirname)(directory);
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, import_node_path17.join)(projectDirectory, "assets"),
4279
- (0, import_node_path17.join)(projectDirectory, "dist"),
4280
- (0, import_node_path17.join)(projectDirectory, "dist", "assets"),
4281
- (0, import_node_path17.join)(projectDirectory, "build"),
4282
- (0, import_node_path17.join)(projectDirectory, "build", "assets")
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, import_node_path17.resolve)(candidate);
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, import_node_fs17.readFileSync)((0, import_node_path17.join)(dest.directory, relative2));
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, import_node_path17.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\`.`
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 assets = artifact.receipt.assets;
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 ${assets.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(assets.sizes, 10)}`
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(assets.sizes, 5)}`
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, import_node_crypto6.createHash)("sha256").update(bytes).digest("hex"),
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 import_node_crypto6, import_node_fs17, import_node_path17, DEFAULT_RNX_CLOUD_ORIGIN, MAX_RNX_CLOUD_BUNDLE_BYTES, REMOTE_COMMAND, MAX_ASSET_DEST_FILES, ACCOUNT_CHOICE_REFUSALS, PROJECT_ONLY_DIRECTORIES, MAX_PLACEMENT_COMBINATIONS;
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
- import_node_crypto6 = require("node:crypto");
4576
- import_node_fs17 = require("node:fs");
4577
- import_node_path17 = require("node:path");
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(path12) {
5038
+ async function readableSettingsBundle(path16) {
5022
5039
  try {
5023
- const root = await (0, import_promises.stat)((0, import_node_path.join)(path12, "Root.plist"));
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(path12) {
5085
+ async function parsePlistRecord(path16) {
5069
5086
  try {
5070
- const metadata = await (0, import_promises.stat)(path12);
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)(path12, "utf8");
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(raw, key, title) {
5080
- if (!Array.isArray(raw.Values) || !Array.isArray(raw.Titles)) return null;
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(raw.Values.length, raw.Titles.length);
5101
+ const pairCount = Math.min(raw2.Values.length, raw2.Titles.length);
5085
5102
  for (let index = 0; index < pairCount; index++) {
5086
- const value = preferenceValue(raw.Values[index]);
5087
- const optionTitle = optionalString(raw.Titles[index]);
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(raw.DefaultValue);
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(raw, context) {
5110
- if (!isRecord2(raw)) return null;
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(raw.Type);
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(raw.Title);
5117
- const footer = optionalString(raw.FooterText);
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(raw.Key);
5141
+ const key = requiredString(raw2.Key);
5125
5142
  if (type === "PSSliderSpecifier") {
5126
5143
  if (!key) return null;
5127
- const minimumValue = finiteNumber(raw.MinimumValue);
5128
- const maximumValue = finiteNumber(raw.MaximumValue);
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(raw.DefaultValue);
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(raw.Title);
5138
- const minimumValueImage = optionalString(raw.MinimumValueImage);
5139
- const maximumValueImage = optionalString(raw.MaximumValueImage);
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(raw.Title);
5154
- const child = safeChildPlistName(raw.File);
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(raw.Title) ?? key;
5186
+ const title = requiredString(raw2.Title) ?? key;
5170
5187
  if (type === "PSToggleSwitchSpecifier") {
5171
- const defaultValue = typeof raw.DefaultValue === "boolean" ? raw.DefaultValue : false;
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(raw.DefaultValue) ?? "";
5182
- const placeholder = optionalString(raw.Placeholder);
5183
- const resolvedKeyboardType = keyboardType(raw.KeyboardType);
5184
- const resolvedAutocapitalization = autocapitalization(raw.AutocapitalizationType);
5185
- const resolvedAutocorrection = autocorrection(raw.AutocorrectionType);
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 raw.IsSecure === "boolean" ? { secure: raw.IsSecure } : null,
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(raw, key, title);
5217
+ return normalizeMultiValue(raw2, key, title);
5201
5218
  }
5202
5219
  if (type === "PSTitleValueSpecifier") {
5203
- const defaultValue = preferenceValue(raw.DefaultValue) ?? "";
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 raw of root.PreferenceSpecifiers) {
5246
+ for (const raw2 of root.PreferenceSpecifiers) {
5230
5247
  if (context.budget.specifiers >= MAX_SPECIFIERS) break;
5231
- const specifier = await normalizeSpecifier(raw, { ...context, stack });
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, path12, method = "GET", timeout = TIMEOUT_MS, headers = {}) {
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: path12, method, headers }, (res) => {
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 raw = res.headers["content-type"];
5348
- if (typeof raw === "string") return raw;
5349
- if (Array.isArray(raw)) return raw[0];
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 import_node_child_process2 = require("node:child_process");
6030
- var import_node_crypto2 = __toESM(require("node:crypto"), 1);
6031
- var import_node_fs7 = __toESM(require("node:fs"), 1);
6032
- var import_node_os2 = __toESM(require("node:os"), 1);
6033
- var import_node_path7 = __toESM(require("node:path"), 1);
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 import_node_fs6 = __toESM(require("node:fs"), 1);
6039
- var import_node_path6 = __toESM(require("node:path"), 1);
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 import_node_fs6.default.readdirSync(product.runtimesDir(), { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort(compareSemver);
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 import_node_path6.default.posix.basename(product.tarballPath(version));
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
- import_node_fs7.default.readFileSync(product.configFile(), "utf8")
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 && import_node_fs7.default.existsSync(import_node_path7.default.join(destDir, product.installedMarker))) {
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 = import_node_fs7.default.existsSync(
6198
- import_node_path7.default.join(product.runtimeDir(pin), product.installedMarker)
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 ? import_node_fs7.default.existsSync(import_node_path7.default.join(activeDir, product.installedMarker)) : false;
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 = import_node_fs7.default.readdirSync(product.cacheDir(), { withFileTypes: true }).filter((entry) => {
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) => import_node_path7.default.join(product.cacheDir(), entry.name)).sort();
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
- import_node_fs7.default.rmSync(product.runtimeDir(version), { recursive: true, force: true });
8186
+ import_node_fs12.default.rmSync(product.runtimeDir(version), { recursive: true, force: true });
6343
8187
  }
6344
8188
  for (const cacheFile of plan.removeCacheFiles) {
6345
- import_node_fs7.default.rmSync(cacheFile, { force: true });
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 = import_node_fs7.default.mkdtempSync(import_node_path7.default.join(import_node_os2.default.tmpdir(), "runtime-delivery-download-"));
6369
- const archivePath = import_node_path7.default.join(downloadDir, "archive.tar.gz");
6370
- import_node_fs7.default.mkdirSync(import_node_path7.default.dirname(destDir), { recursive: true });
6371
- const tmpDir = import_node_fs7.default.mkdtempSync(
6372
- import_node_path7.default.join(import_node_path7.default.dirname(destDir), `.installing-${import_node_path7.default.basename(destDir)}-`)
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 (!import_node_fs7.default.existsSync(import_node_path7.default.join(tmpDir, installedMarker))) {
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
- import_node_fs7.default.renameSync(tmpDir, destDir);
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
- import_node_fs7.default.renameSync(destDir, aside);
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
- import_node_fs7.default.renameSync(tmpDir, destDir);
8241
+ import_node_fs12.default.renameSync(tmpDir, destDir);
6398
8242
  } catch (landErr) {
6399
- if (!isErrnoCode(landErr, "ENOTEMPTY", "EEXIST") || !import_node_fs7.default.existsSync(import_node_path7.default.join(destDir, installedMarker))) {
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
- import_node_fs7.default.rmSync(aside, { recursive: true, force: true });
8247
+ import_node_fs12.default.rmSync(aside, { recursive: true, force: true });
6404
8248
  }
6405
8249
  }
6406
8250
  } finally {
6407
- import_node_fs7.default.rmSync(tmpDir, { recursive: true, force: true });
6408
- import_node_fs7.default.rmSync(downloadDir, { recursive: true, force: true });
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
- import_node_fs7.default.mkdirSync(import_node_path7.default.dirname(destPath), { recursive: true });
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
- import_node_fs7.default.createWriteStream(tmp)
8268
+ import_node_fs12.default.createWriteStream(tmp)
6425
8269
  );
6426
- import_node_fs7.default.renameSync(tmp, destPath);
8270
+ import_node_fs12.default.renameSync(tmp, destPath);
6427
8271
  } catch (err) {
6428
8272
  try {
6429
- import_node_fs7.default.unlinkSync(tmp);
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 = import_node_crypto2.default.createHash(algorithm);
6438
- const stream = import_node_fs7.default.createReadStream(filePath);
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, import_node_child_process2.spawn)("tar", args, {
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 import_node_crypto5 = require("node:crypto");
6589
- var import_node_fs11 = __toESM(require("node:fs"), 1);
6590
- var import_node_path11 = __toESM(require("node:path"), 1);
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 import_node_child_process3 = require("node:child_process");
6594
- var import_node_crypto4 = require("node:crypto");
6595
- var import_node_fs10 = __toESM(require("node:fs"), 1);
6596
- var import_node_path10 = __toESM(require("node:path"), 1);
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 import_node_fs8 = require("node:fs");
6601
- var import_node_path8 = require("node:path");
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, import_node_path8.join)((0, import_node_path8.dirname)((0, import_node_url3.fileURLToPath)(__sootsim_import_meta_url)), "bin.ts");
6612
- return (0, import_node_fs8.existsSync)(candidate) ? candidate : null;
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(path12) {
6618
- const name2 = (0, import_node_path8.basename)(path12);
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 import_node_crypto3 = require("node:crypto");
6678
- var import_node_fs9 = __toESM(require("node:fs"), 1);
6679
- var import_node_path9 = __toESM(require("node:path"), 1);
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 import_node_path9.default.join(userDataDir(), "attached-projects.json");
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 raw;
8548
+ let raw2;
6705
8549
  try {
6706
- raw = import_node_fs9.default.readFileSync(file, "utf8");
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(raw);
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
- import_node_fs9.default.renameSync(file, quarantine);
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
- import_node_fs9.default.mkdirSync(import_node_path9.default.dirname(file), { recursive: true });
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 = import_node_fs9.default.openSync(tmp, "w", 384);
8580
+ const fd = import_node_fs14.default.openSync(tmp, "w", 384);
6737
8581
  try {
6738
- import_node_fs9.default.writeFileSync(fd, JSON.stringify(store, null, 2));
6739
- import_node_fs9.default.fsyncSync(fd);
8582
+ import_node_fs14.default.writeFileSync(fd, JSON.stringify(store, null, 2));
8583
+ import_node_fs14.default.fsyncSync(fd);
6740
8584
  } finally {
6741
- import_node_fs9.default.closeSync(fd);
8585
+ import_node_fs14.default.closeSync(fd);
6742
8586
  }
6743
- import_node_fs9.default.renameSync(tmp, file);
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, import_node_crypto3.createHash)("sha256").update(import_node_path9.default.resolve(cwd)).digest("hex").slice(0, 16);
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, import_node_crypto3.randomBytes)(10).toString("hex")}`;
8599
+ return `s_${(0, import_node_crypto7.randomBytes)(10).toString("hex")}`;
6756
8600
  }
6757
8601
  function upsertProject(input) {
6758
- const cwd = import_node_path9.default.resolve(input.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 ?? import_node_path9.default.basename(cwd),
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 (!import_node_fs9.default.existsSync(app.dir)) continue;
6931
- const cwd = import_node_path9.default.resolve(app.dir);
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 import_node_path10.default.join(getUserDataDir(), "sessions", sessionId);
8800
+ return import_node_path15.default.join(getUserDataDir(), "sessions", sessionId);
6957
8801
  }
6958
8802
  function promptFifoPath(sessionId) {
6959
- return import_node_path10.default.join(sessionDir(sessionId), "prompt.in");
8803
+ return import_node_path15.default.join(sessionDir(sessionId), "prompt.in");
6960
8804
  }
6961
8805
  function eventsFifoPath(sessionId) {
6962
- return import_node_path10.default.join(sessionDir(sessionId), "events.out");
8806
+ return import_node_path15.default.join(sessionDir(sessionId), "events.out");
6963
8807
  }
6964
8808
  function transcriptPath(sessionId) {
6965
- return import_node_path10.default.join(getUserDataDir(), "transcripts", `${sessionId}.log`);
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 (!import_node_fs10.default.existsSync(sessionDir(sessionId))) return false;
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
- import_node_path10.default.join(resourcesPath, "bin", "sootsim"),
6989
- import_node_path10.default.join(resourcesPath, "bin", `sootsim-${process.platform}-${process.arch}`)
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 (import_node_fs10.default.existsSync(c)) return { executable: c, prefixArgs: [] };
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 = import_node_path10.default.join(sootsimDir, "dist-bin", binaryName);
7012
- if (import_node_fs10.default.existsSync(distBinary)) return { executable: distBinary, prefixArgs: [] };
7013
- const distBin = import_node_path10.default.join(sootsimDir, "dist-cli", "bin.js");
7014
- if (import_node_fs10.default.existsSync(distBin)) {
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 = import_node_path10.default.join(sootsimDir, "cli", "commands", "agent-wrapper.ts");
7017
- if (import_node_fs10.default.existsSync(src)) {
7018
- const srcMtime = import_node_fs10.default.statSync(src).mtimeMs;
7019
- const buildMtime = import_node_fs10.default.statSync(distBin).mtimeMs;
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 import_node_path10.default.dirname(resolved);
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 = import_node_path10.default.dirname(here);
8887
+ let cur = import_node_path15.default.dirname(here);
7044
8888
  for (let i = 0; i < 8; i++) {
7045
- const pkg = import_node_path10.default.join(cur, "package.json");
8889
+ const pkg = import_node_path15.default.join(cur, "package.json");
7046
8890
  try {
7047
- if (import_node_fs10.default.existsSync(pkg)) {
7048
- const parsed = JSON.parse(import_node_fs10.default.readFileSync(pkg, "utf8"));
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 = import_node_path10.default.dirname(cur);
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 = import_node_path10.default.join(getUserDataDir(), "locks");
7070
- import_node_fs10.default.mkdirSync(lockDir, { recursive: true });
8913
+ const lockDir = import_node_path15.default.join(getUserDataDir(), "locks");
8914
+ import_node_fs15.default.mkdirSync(lockDir, { recursive: true });
7071
8915
  try {
7072
- import_node_fs10.default.chmodSync(lockDir, 448);
8916
+ import_node_fs15.default.chmodSync(lockDir, 448);
7073
8917
  } catch {
7074
8918
  }
7075
- const lockPath = import_node_path10.default.join(lockDir, `start-${projectId}-${provider}.lock`);
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 = import_node_fs10.default.openSync(
8924
+ fd = import_node_fs15.default.openSync(
7081
8925
  lockPath,
7082
- import_node_fs10.constants.O_WRONLY | import_node_fs10.constants.O_CREAT | import_node_fs10.constants.O_EXCL,
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(import_node_fs10.default.readFileSync(lockPath, "utf8").trim());
8932
+ const stale = Number(import_node_fs15.default.readFileSync(lockPath, "utf8").trim());
7089
8933
  if (stale && !isProcessAlive(stale)) {
7090
- import_node_fs10.default.unlinkSync(lockPath);
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
- import_node_fs10.default.writeFileSync(fd, String(process.pid));
8948
+ import_node_fs15.default.writeFileSync(fd, String(process.pid));
7105
8949
  return await fn();
7106
8950
  } finally {
7107
8951
  try {
7108
- import_node_fs10.default.closeSync(fd);
8952
+ import_node_fs15.default.closeSync(fd);
7109
8953
  } catch {
7110
8954
  }
7111
8955
  try {
7112
- import_node_fs10.default.unlinkSync(lockPath);
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 = import_node_path10.default.dirname(p);
7127
- import_node_fs10.default.mkdirSync(parent, { recursive: true });
8970
+ const parent = import_node_path15.default.dirname(p);
8971
+ import_node_fs15.default.mkdirSync(parent, { recursive: true });
7128
8972
  try {
7129
- import_node_fs10.default.chmodSync(parent, 448);
8973
+ import_node_fs15.default.chmodSync(parent, 448);
7130
8974
  } catch {
7131
8975
  }
7132
- if (import_node_fs10.default.existsSync(p)) {
8976
+ if (import_node_fs15.default.existsSync(p)) {
7133
8977
  try {
7134
- const stat2 = import_node_fs10.default.statSync(p);
8978
+ const stat2 = import_node_fs15.default.statSync(p);
7135
8979
  if (stat2.isFIFO()) {
7136
8980
  try {
7137
- import_node_fs10.default.chmodSync(p, 384);
8981
+ import_node_fs15.default.chmodSync(p, 384);
7138
8982
  } catch {
7139
8983
  }
7140
8984
  return;
7141
8985
  }
7142
- import_node_fs10.default.unlinkSync(p);
8986
+ import_node_fs15.default.unlinkSync(p);
7143
8987
  } catch {
7144
- import_node_fs10.default.unlinkSync(p);
8988
+ import_node_fs15.default.unlinkSync(p);
7145
8989
  }
7146
8990
  }
7147
- const result = (0, import_node_child_process3.spawnSync)("mkfifo", ["-m", "600", p]);
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, import_node_crypto4.randomUUID)() : void 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 = import_node_path10.default.dirname(transcript);
7192
- import_node_fs10.default.mkdirSync(transcriptDir, { recursive: true });
9035
+ const transcriptDir = import_node_path15.default.dirname(transcript);
9036
+ import_node_fs15.default.mkdirSync(transcriptDir, { recursive: true });
7193
9037
  try {
7194
- import_node_fs10.default.chmodSync(transcriptDir, 448);
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, import_node_child_process3.spawn)(executable, wrapperArgs, {
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
- import_node_fs10.default.rmSync(sessionDir(session.id), { recursive: true, force: true });
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 (!import_node_fs10.default.existsSync(fifo)) {
9117
+ if (!import_node_fs15.default.existsSync(fifo)) {
7274
9118
  throw new AgentSessionError("NO_FIFO", `prompt FIFO missing: ${fifo}`);
7275
9119
  }
7276
- const fd = import_node_fs10.default.openSync(fifo, import_node_fs10.constants.O_WRONLY);
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
- import_node_fs10.default.writeSync(fd, wireText + "\n");
9126
+ import_node_fs15.default.writeSync(fd, wireText + "\n");
7283
9127
  } finally {
7284
- import_node_fs10.default.closeSync(fd);
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
- import_node_fs10.default.rmSync(dir, { recursive: true, force: true });
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 (!import_node_fs10.default.existsSync(fifo)) {
9158
+ if (!import_node_fs15.default.existsSync(fifo)) {
7315
9159
  throw new AgentSessionError("NO_FIFO", `events FIFO missing: ${fifo}`);
7316
9160
  }
7317
- const fd = import_node_fs10.default.openSync(fifo, import_node_fs10.constants.O_RDWR);
7318
- const stream = import_node_fs10.default.createReadStream("", { fd, autoClose: true });
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
- import_node_fs10.default.writeSync(fd, "\n");
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 = import_node_fs10.default.openSync(fifo, import_node_fs10.constants.O_RDWR | import_node_fs10.constants.O_NONBLOCK);
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 = import_node_fs10.default.readSync(fd, buf, 0, buf.length, null);
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
- import_node_fs10.default.closeSync(fd);
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, import_node_crypto5.randomUUID)()}`,
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 ?? import_node_path11.default.basename(match.cwd),
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 (!import_node_fs11.default.existsSync(p)) {
9480
+ if (!import_node_fs16.default.existsSync(p)) {
7637
9481
  return { error: "transcript not found", code: "NO_TRANSCRIPT" };
7638
9482
  }
7639
- return import_node_fs11.default.readFileSync(p, "utf8");
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: import_node_path11.default.join(dir, "attached-projects.json"),
7646
- sessionsDir: import_node_path11.default.join(dir, "sessions"),
7647
- transcriptsDir: import_node_path11.default.join(dir, "transcripts")
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 host = hostname.toLowerCase();
9807
+ const host2 = hostname.toLowerCase();
7964
9808
  for (const override of HOST_HEADER_OVERRIDES) {
7965
- if (host === override.hostSuffix || host.endsWith(`.${override.hostSuffix}`)) {
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 host = requested.hostname.toLowerCase();
7988
- if (!host.endsWith(QUICKNODE_HOST_SUFFIX)) return requested;
7989
- const tenant = host.slice(0, -QUICKNODE_HOST_SUFFIX.length);
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 import_node_fs13 = __toESM(require("node:fs"), 1);
8355
- var import_node_path13 = __toESM(require("node:path"), 1);
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 import_node_child_process4 = require("node:child_process");
8435
- var import_node_fs12 = __toESM(require("node:fs"), 1);
8436
- var import_node_path12 = __toESM(require("node:path"), 1);
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 = import_node_fs12.default.openSync(filePath, "r");
10291
+ fd = import_node_fs17.default.openSync(filePath, "r");
8448
10292
  const buffer = Buffer.alloc(Math.min(BINARY_SNIFF_BYTES, size));
8449
- const read = import_node_fs12.default.readSync(fd, buffer, 0, buffer.length, 0);
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) import_node_fs12.default.closeSync(fd);
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 = import_node_path12.default.resolve(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, import_node_child_process4.execFileSync)("git", args, {
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 = import_node_fs12.default.statSync(import_node_path12.default.join(this.root, relative2));
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(import_node_path12.default.join(this.root, relative2), stat2.size);
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 = import_node_path12.default.resolve(this.root, planePath);
8550
- if (resolved !== this.root && !resolved.startsWith(`${this.root}${import_node_path12.default.sep}`)) {
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 import_node_fs12.default.promises.readFile(this.absolute(planePath), "utf8");
10400
+ return import_node_fs17.default.promises.readFile(this.absolute(planePath), "utf8");
8557
10401
  }
8558
10402
  async readBytes(planePath) {
8559
- return import_node_fs12.default.promises.readFile(this.absolute(planePath));
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 import_node_fs12.default.promises.mkdir(import_node_path12.default.dirname(absolute), { recursive: true });
8564
- await import_node_fs12.default.promises.writeFile(absolute, content);
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 import_node_fs12.default.promises.rm(this.absolute(planePath), { force: true });
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 = import_node_path13.default.resolve(root);
10543
+ const resolved = import_node_path18.default.resolve(root);
8700
10544
  let real;
8701
10545
  try {
8702
- real = import_node_fs13.default.realpathSync(resolved);
10546
+ real = import_node_fs18.default.realpathSync(resolved);
8703
10547
  } catch {
8704
10548
  throw new Error(`no such directory: ${resolved}`);
8705
10549
  }
8706
- if (!import_node_fs13.default.statSync(real).isDirectory()) throw new Error(`not a directory: ${real}`);
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 import_node_fs14 = require("node:fs");
10570
+ var import_node_fs19 = require("node:fs");
8727
10571
  var import_promises5 = __toESM(require("node:fs/promises"), 1);
8728
- var import_node_path14 = __toESM(require("node:path"), 1);
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 join5(...parts) {
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 resolve2(...parts) {
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 dirname3(p) {
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: join5,
8825
- resolve: resolve2,
8826
- dirname: dirname3,
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 isContrastKitSpecifier(specifier) {
8860
- return specifier === "contrast-kit" || specifier.startsWith("contrast-kit/");
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, contrast-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.`
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 (isContrastKitSpecifier(specifier)) {
8876
- return `const ${name2} = (globalThis.__contrast_kit_modules && globalThis.__contrast_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`)});`;
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) && !isContrastKitSpecifier(specifier) && !input.runtimePackages.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 = import_node_path14.default.resolve(import_node_path14.default.dirname(fromFile), specifier);
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 === import_node_path14.default.extname(base).toLowerCase()
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) => import_node_path14.default.join(base, `index${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, import_node_fs14.statSync)(candidate, { throwIfNoEntry: false })?.isFile()
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 = import_node_path14.default.extname(targetPath).toLowerCase();
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 (!import_node_path14.default.isAbsolute(targetPath)) {
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 = import_node_path14.default.resolve(options.projectRoot);
10975
+ const lexicalProjectRoot = import_node_path19.default.resolve(options.projectRoot);
9132
10976
  resolvedProjectRoot = await import_promises5.default.realpath(options.projectRoot);
9133
- const lexicalTarget = import_node_path14.default.relative(lexicalProjectRoot, targetPath);
9134
- if (lexicalTarget.startsWith("..") || import_node_path14.default.isAbsolute(lexicalTarget)) {
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 = import_node_path14.default.relative(resolvedProjectRoot, resolvedTargetPath);
9151
- if (relativeTarget.startsWith("..") || import_node_path14.default.isAbsolute(relativeTarget)) {
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 host = req.headers.host;
9265
- if (!origin || !host) return false;
11108
+ const host2 = req.headers.host;
11109
+ if (!origin || !host2) return false;
9266
11110
  try {
9267
- return new URL(origin).host === 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 raw = Number(process.env[RUNTIME_UPDATE_INTERVAL_ENV]);
10324
- if (Number.isFinite(raw) && raw > 0) return Math.max(100, Math.round(raw));
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;