@absolutejs/absolute 0.20.0-beta.2 → 0.20.0-beta.3

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.
@@ -617,7 +617,7 @@ var verifyAbsoluteMobileCompatibilityProducer = async (release, maxProducerBytes
617
617
  // src/mobile/androidRelease.ts
618
618
  import { createHash as createHash4 } from "crypto";
619
619
  import {
620
- access as access3,
620
+ access as access4,
621
621
  copyFile as copyFile2,
622
622
  mkdir as mkdir3,
623
623
  mkdtemp as mkdtemp2,
@@ -630,6 +630,7 @@ import {
630
630
  import { dirname as dirname2, isAbsolute as isAbsolute2, join as join4, relative as relative3, resolve as resolve3, sep as sep2 } from "path";
631
631
 
632
632
  // src/mobile/emulatorDoctor.ts
633
+ import { access } from "fs/promises";
633
634
  import { homedir } from "os";
634
635
  import { join as join2 } from "path";
635
636
 
@@ -647,6 +648,34 @@ var isWSLEnvironment = () => {
647
648
  };
648
649
 
649
650
  // src/mobile/emulatorDoctor.ts
651
+ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36";
652
+ var captureCommand = (command) => {
653
+ try {
654
+ const result = Bun.spawnSync(command, {
655
+ stderr: "ignore",
656
+ stdout: "pipe"
657
+ });
658
+ return {
659
+ exitCode: result.exitCode,
660
+ stdout: result.stdout.toString()
661
+ };
662
+ } catch {
663
+ return { exitCode: 1, stdout: "" };
664
+ }
665
+ };
666
+ var hasAvailableIosRuntime = (output) => {
667
+ try {
668
+ const parsed = JSON.parse(output);
669
+ if (typeof parsed !== "object" || parsed === null)
670
+ return false;
671
+ const runtimes = Reflect.get(parsed, "runtimes");
672
+ if (!Array.isArray(runtimes))
673
+ return false;
674
+ return runtimes.some((runtime) => typeof runtime === "object" && runtime !== null && Reflect.get(runtime, "isAvailable") === true && typeof Reflect.get(runtime, "identifier") === "string" && String(Reflect.get(runtime, "identifier")).includes("iOS"));
675
+ } catch {
676
+ return false;
677
+ }
678
+ };
650
679
  var windowsPathToWsl = (path) => {
651
680
  const match = /^([a-z]):[\\/](.*)$/i.exec(path.trim());
652
681
  if (!match)
@@ -678,6 +707,14 @@ var absoluteManagedAndroidSdkRoot = (host, env = process.env) => {
678
707
  }
679
708
  return join2(homedir(), ".absolutejs", "android-sdk");
680
709
  };
710
+ var pathExists = async (path) => {
711
+ try {
712
+ await access(path);
713
+ return true;
714
+ } catch {
715
+ return false;
716
+ }
717
+ };
681
718
  var detectAbsoluteMobileHost = (platform = process.platform, wsl = isWSLEnvironment()) => {
682
719
  if (platform === "darwin")
683
720
  return "macos";
@@ -687,10 +724,151 @@ var detectAbsoluteMobileHost = (platform = process.platform, wsl = isWSLEnvironm
687
724
  return "wsl";
688
725
  return "linux";
689
726
  };
727
+ var executableNames = (host, name) => {
728
+ if (host === "wsl")
729
+ return [`${name}.exe`, `${name}.bat`, name];
730
+ if (host === "windows")
731
+ return [name, `${name}.exe`, `${name}.bat`];
732
+ return [name];
733
+ };
734
+ var findExecutable = async (name, paths, options, host) => {
735
+ const existing = await Promise.all(paths.map(async (path) => await options.exists(path) ? path : undefined));
736
+ const configured = existing.find((path) => path !== undefined);
737
+ if (configured)
738
+ return configured;
739
+ for (const candidate of executableNames(host, name)) {
740
+ const path = options.which(candidate);
741
+ if (path)
742
+ return path;
743
+ }
744
+ return;
745
+ };
746
+ var toolCheck = (id, label, platform, path, remediation) => path ? {
747
+ id,
748
+ label,
749
+ path,
750
+ platform,
751
+ status: "pass"
752
+ } : {
753
+ id,
754
+ label,
755
+ platform,
756
+ remediation,
757
+ status: "fail"
758
+ };
759
+ var inspectAbsoluteMobileToolchain = async (input = {}) => {
760
+ const env = input.env ?? process.env;
761
+ const host = input.host ?? detectAbsoluteMobileHost();
762
+ const exists = input.exists ?? pathExists;
763
+ const which = input.which ?? ((command) => Bun.which(command));
764
+ const capture = input.capture ?? captureCommand;
765
+ const androidRoot = input.androidRoot === null ? undefined : input.androidRoot ?? env.ANDROID_HOME ?? env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(host, env);
766
+ const windowsAndroidTools = host === "windows" || host === "wsl";
767
+ const android = (segments) => androidRoot ? join2(androidRoot, ...segments) : undefined;
768
+ const paths = (values) => values.filter((value) => Boolean(value));
769
+ const adb = await findExecutable("adb", paths([
770
+ android(["platform-tools", windowsAndroidTools ? "adb.exe" : "adb"])
771
+ ]), { exists, which }, host);
772
+ const emulator = await findExecutable("emulator", paths([
773
+ android([
774
+ "emulator",
775
+ windowsAndroidTools ? "emulator.exe" : "emulator"
776
+ ])
777
+ ]), { exists, which }, host);
778
+ const sdkmanager = await findExecutable("sdkmanager", paths([
779
+ android([
780
+ "cmdline-tools",
781
+ "latest",
782
+ "bin",
783
+ windowsAndroidTools ? "sdkmanager.bat" : "sdkmanager"
784
+ ])
785
+ ]), { exists, which }, host);
786
+ const avdmanager = await findExecutable("avdmanager", paths([
787
+ android([
788
+ "cmdline-tools",
789
+ "latest",
790
+ "bin",
791
+ windowsAndroidTools ? "avdmanager.bat" : "avdmanager"
792
+ ])
793
+ ]), { exists, which }, host);
794
+ const java = await findExecutable("java", [], { exists, which }, host);
795
+ const checks = [
796
+ {
797
+ id: "host",
798
+ label: `Development host: ${host}`,
799
+ platform: "host",
800
+ status: "pass"
801
+ },
802
+ toolCheck("android.adb", "Android Debug Bridge", "android", adb, "Install Android SDK Platform Tools or expose adb on PATH."),
803
+ toolCheck("android.emulator", "Android Emulator", "android", emulator, "Install the Android Emulator from Android Studio SDK Manager."),
804
+ toolCheck("android.sdkmanager", "Android SDK Manager", "android", sdkmanager, "Install Android SDK Command-line Tools (latest)."),
805
+ toolCheck("android.avdmanager", "Android Virtual Device Manager", "android", avdmanager, "Install Android SDK Command-line Tools (latest)."),
806
+ toolCheck("android.java", "Java runtime", "android", java, "Install the JDK required by the configured Android Gradle plugin.")
807
+ ];
808
+ if (emulator) {
809
+ const avds = capture([emulator, "-list-avds"]);
810
+ const hasManagedAvd = avds.exitCode === 0 && avds.stdout.split(/\r?\n/).includes(ABSOLUTE_ANDROID_AVD_NAME);
811
+ checks.push({
812
+ id: "android.avd",
813
+ label: `AbsoluteJS Android emulator (${ABSOLUTE_ANDROID_AVD_NAME})`,
814
+ platform: "android",
815
+ remediation: hasManagedAvd ? undefined : "Run absolute mobile doctor android --fix to provision the managed emulator.",
816
+ status: hasManagedAvd ? "pass" : "fail"
817
+ });
818
+ }
819
+ if (host === "wsl") {
820
+ checks.push({
821
+ id: "android.virtualization",
822
+ label: adb?.endsWith(".exe") ? "Windows-host Android bridge available to WSL" : "WSL requires a Windows-host emulator bridge or Linux KVM",
823
+ platform: "android",
824
+ remediation: adb?.endsWith(".exe") ? undefined : "Expose the Windows Android SDK adb.exe to WSL, or enable /dev/kvm for a Linux SDK.",
825
+ status: adb?.endsWith(".exe") ? "pass" : "warn"
826
+ });
827
+ } else if (host === "linux") {
828
+ const hasKvm = await exists("/dev/kvm");
829
+ checks.push({
830
+ id: "android.virtualization",
831
+ label: "Linux KVM acceleration",
832
+ platform: "android",
833
+ remediation: hasKvm ? undefined : "Enable KVM and grant the current user access to /dev/kvm.",
834
+ status: hasKvm ? "pass" : "warn"
835
+ });
836
+ }
837
+ if (host !== "macos") {
838
+ checks.push({
839
+ id: "ios.simulator",
840
+ label: "iOS Simulator requires macOS and Xcode",
841
+ platform: "ios",
842
+ status: "skip"
843
+ });
844
+ return checks;
845
+ }
846
+ const xcrun = await findExecutable("xcrun", [], { exists, which }, host);
847
+ const xcodebuild = await findExecutable("xcodebuild", [], { exists, which }, host);
848
+ checks.push(toolCheck("ios.xcrun", "Xcode command runner", "ios", xcrun, "Install Xcode and select it with xcode-select."), toolCheck("ios.xcodebuild", "Xcode build system", "ios", xcodebuild, "Install Xcode and select it with xcode-select."));
849
+ if (xcrun) {
850
+ const runtimes = capture([
851
+ xcrun,
852
+ "simctl",
853
+ "list",
854
+ "runtimes",
855
+ "--json"
856
+ ]);
857
+ const hasRuntime = runtimes.exitCode === 0 && hasAvailableIosRuntime(runtimes.stdout);
858
+ checks.push({
859
+ id: "ios.runtime",
860
+ label: "iOS Simulator runtime",
861
+ platform: "ios",
862
+ remediation: hasRuntime ? undefined : "Run absolute mobile doctor ios --fix to download an iOS Simulator runtime.",
863
+ status: hasRuntime ? "pass" : "fail"
864
+ });
865
+ }
866
+ return checks;
867
+ };
690
868
 
691
869
  // src/mobile/androidEmulatorController.ts
692
870
  import {
693
- access as access2,
871
+ access as access3,
694
872
  copyFile,
695
873
  lstat,
696
874
  mkdir as mkdir2,
@@ -714,7 +892,7 @@ import {
714
892
  } from "path";
715
893
 
716
894
  // src/mobile/capacitorProject.ts
717
- import { access, readFile as readFile2, rename as rename2, writeFile as writeFile2 } from "fs/promises";
895
+ import { access as access2, readFile as readFile2, rename as rename2, writeFile as writeFile2 } from "fs/promises";
718
896
  import { relative, resolve } from "path";
719
897
  var CONFIG_FILE = "capacitor.config.ts";
720
898
  var portableRelative = (root, path) => relative(root, path).replaceAll("\\", "/");
@@ -736,7 +914,7 @@ export default config;
736
914
  `;
737
915
  var exists = async (path) => {
738
916
  try {
739
- await access(path);
917
+ await access2(path);
740
918
  return true;
741
919
  } catch {
742
920
  return false;
@@ -766,9 +944,9 @@ var HASH_RADIX = 16;
766
944
  var EXECUTABLE_MODE_MASK = 73;
767
945
  var NATIVE_PUBLIC_PATH_SEGMENTS = 5;
768
946
  var CAPACITOR_PROJECT_DIRECTORY_PATTERN = /project\(['"](:[^'"]+)['"]\)\.projectDir\s*=\s*new File\(['"]([^'"]+)['"]\)/gu;
769
- var pathExists = async (path) => {
947
+ var pathExists2 = async (path) => {
770
948
  try {
771
- await access2(path);
949
+ await access3(path);
772
950
  return true;
773
951
  } catch {
774
952
  return false;
@@ -795,7 +973,7 @@ var runCommand = async (command, options = {}) => {
795
973
  ]);
796
974
  return exitCode;
797
975
  };
798
- var captureCommand = (command, options = {}) => {
976
+ var captureCommand2 = (command, options = {}) => {
799
977
  try {
800
978
  const result = Bun.spawnSync(command, {
801
979
  cwd: options.cwd,
@@ -965,14 +1143,14 @@ var gradleArtifactPath = (nativeDirectory, task, windows = false) => {
965
1143
  };
966
1144
  var resolveGradleArtifactPath = async (nativeDirectory, task) => {
967
1145
  const primary = gradleArtifactPath(nativeDirectory, task);
968
- if (task !== "assembleRelease" || await pathExists(primary)) {
1146
+ if (task !== "assembleRelease" || await pathExists2(primary)) {
969
1147
  return primary;
970
1148
  }
971
1149
  return join3(nativeDirectory, "app", "build", "outputs", "apk", "release", "app-release-unsigned.apk");
972
1150
  };
973
1151
  var buildAbsoluteAndroidGradleArtifact = async (options) => {
974
1152
  const { project, task } = options;
975
- const capture = options.capture ?? captureCommand;
1153
+ const capture = options.capture ?? captureCommand2;
976
1154
  const run = options.run ?? runCommand;
977
1155
  const env = options.env ?? process.env;
978
1156
  const gradleArguments = options.gradleArguments ?? [];
@@ -1015,9 +1193,9 @@ var requireManifest = (value) => {
1015
1193
  runtime: value.runtime
1016
1194
  };
1017
1195
  };
1018
- var pathExists2 = async (path) => {
1196
+ var pathExists3 = async (path) => {
1019
1197
  try {
1020
- await access3(path);
1198
+ await access4(path);
1021
1199
  return true;
1022
1200
  } catch {
1023
1201
  return false;
@@ -1072,7 +1250,7 @@ var installRelease = async (artifactPath, metadata, outputRoot) => {
1072
1250
  const releaseRoot = join4(outputRoot, metadata.releaseId);
1073
1251
  const artifactName = "app-release.aab";
1074
1252
  const destination = join4(releaseRoot, artifactName);
1075
- if (await pathExists2(releaseRoot)) {
1253
+ if (await pathExists3(releaseRoot)) {
1076
1254
  const existing = requireManifestIdentity(JSON.parse(await readFile4(join4(releaseRoot, "release.json"), "utf8")), metadata);
1077
1255
  const [installedBytes, installedSha256] = await Promise.all([
1078
1256
  stat(destination).then(({ size }) => size),
@@ -1148,7 +1326,7 @@ var buildAbsoluteAndroidRelease = async (options) => {
1148
1326
  run: options.run,
1149
1327
  task: "bundleRelease"
1150
1328
  });
1151
- if (!await pathExists2(artifactPath)) {
1329
+ if (!await pathExists3(artifactPath)) {
1152
1330
  throw new TypeError(`Android Gradle did not produce the expected App Bundle: ${artifactPath}`);
1153
1331
  }
1154
1332
  const capture = options.capture ?? defaultCapture;
@@ -1183,7 +1361,7 @@ var buildAbsoluteAndroidRelease = async (options) => {
1183
1361
  // src/mobile/iosRelease.ts
1184
1362
  import { createHash as createHash5 } from "crypto";
1185
1363
  import {
1186
- access as access4,
1364
+ access as access5,
1187
1365
  copyFile as copyFile3,
1188
1366
  mkdir as mkdir4,
1189
1367
  mkdtemp as mkdtemp3,
@@ -1207,9 +1385,9 @@ var requireManifest2 = (value) => {
1207
1385
  runtime: value.runtime
1208
1386
  };
1209
1387
  };
1210
- var pathExists3 = async (path) => {
1388
+ var pathExists4 = async (path) => {
1211
1389
  try {
1212
- await access4(path);
1390
+ await access5(path);
1213
1391
  return true;
1214
1392
  } catch {
1215
1393
  return false;
@@ -1290,7 +1468,7 @@ var safeOutputDirectory2 = (projectRoot, requested) => {
1290
1468
  };
1291
1469
  var sha256File2 = async (path) => createHash5("sha256").update(await readFile5(path)).digest("hex");
1292
1470
  var findByExtension = async (root, extension) => {
1293
- if (!await pathExists3(root))
1471
+ if (!await pathExists4(root))
1294
1472
  return;
1295
1473
  const entries = await readdir3(root, { withFileTypes: true });
1296
1474
  const matches = await Promise.all(entries.map(async (entry) => {
@@ -1322,7 +1500,7 @@ var requireBuildNumber = (value) => {
1322
1500
  var installRelease2 = async (artifactPath, metadata, outputRoot) => {
1323
1501
  const releaseRoot = join5(outputRoot, metadata.releaseId);
1324
1502
  const destination = join5(releaseRoot, "App.ipa");
1325
- if (await pathExists3(releaseRoot)) {
1503
+ if (await pathExists4(releaseRoot)) {
1326
1504
  const value = JSON.parse(await readFile5(join5(releaseRoot, "release.json"), "utf8"));
1327
1505
  if (!isRecord2(value) || value.artifact !== "App.ipa" || Object.entries(metadata).some(([key, expected]) => Reflect.get(value, key) !== expected)) {
1328
1506
  throw new TypeError(`Immutable iOS release ${metadata.releaseId} does not match its content.`);
@@ -1461,28 +1639,922 @@ var buildAbsoluteIosRelease = async (options) => {
1461
1639
  });
1462
1640
  }
1463
1641
  };
1464
- // src/mobile/associationFiles.ts
1642
+ // src/mobile/iosConformance.ts
1643
+ import { readFile as readFile6, stat as stat3 } from "fs/promises";
1644
+ var HMR_LINE = new RegExp(String.raw`\[hmr:ios\]\s+([^\n]*?)\s+(applied in|falling back to reload after|failed after)\s+(\d+)ms(?:; server\s+(\d+)ms, client\s+(\d+)ms)?`, "u");
1645
+ var parseAbsoluteIosHmrLog = (line) => {
1646
+ const match = HMR_LINE.exec(line);
1647
+ if (!match)
1648
+ return null;
1649
+ const [, , action, durationValue, serverValue, clientValue] = match;
1650
+ let outcome = "reloaded";
1651
+ if (action === "applied in")
1652
+ outcome = "applied";
1653
+ if (action === "failed after")
1654
+ outcome = "failed";
1655
+ const serverMs = serverValue === undefined ? undefined : Number(serverValue);
1656
+ const clientMs = clientValue === undefined ? undefined : Number(clientValue);
1657
+ return {
1658
+ ...clientMs === undefined ? {} : { clientMs },
1659
+ duration: Number(durationValue),
1660
+ line: match[0],
1661
+ outcome,
1662
+ ...serverMs === undefined ? {} : { serverMs }
1663
+ };
1664
+ };
1665
+ var findHmrApply = (lines) => {
1666
+ const apply = lines.map((line) => parseAbsoluteIosHmrLog(line)).find((candidate) => candidate !== null);
1667
+ if (apply?.outcome === "failed")
1668
+ throw new Error(`iOS HMR client reported a failed apply: ${apply.line}`);
1669
+ return apply;
1670
+ };
1671
+ var waitForAbsoluteIosHmrLog = async (options) => {
1672
+ const sleep = options.sleep ?? Bun.sleep;
1673
+ const timeoutMs = options.timeoutMs ?? 30000;
1674
+ const deadline = Date.now() + timeoutMs;
1675
+ let offset = options.startOffset ?? await stat3(options.logPath).then(({ size }) => size).catch(() => 0);
1676
+ let buffered = "";
1677
+ const poll = async () => {
1678
+ if (Date.now() > deadline)
1679
+ throw new Error(`No iOS native HMR acknowledgement was observed within ${timeoutMs}ms.`);
1680
+ options.signal?.throwIfAborted();
1681
+ const contents = await readFile6(options.logPath).catch(() => Buffer.alloc(0));
1682
+ if (contents.byteLength < offset) {
1683
+ offset = 0;
1684
+ buffered = "";
1685
+ }
1686
+ if (contents.byteLength > offset) {
1687
+ buffered += contents.subarray(offset).toString("utf8");
1688
+ offset = contents.byteLength;
1689
+ const lines = buffered.split(/\r?\n/u);
1690
+ buffered = lines.pop() ?? "";
1691
+ const apply = findHmrApply(lines);
1692
+ if (apply)
1693
+ return apply;
1694
+ }
1695
+ await sleep(100);
1696
+ return poll();
1697
+ };
1698
+ return poll();
1699
+ };
1700
+ // src/mobile/iosSimulatorController.ts
1701
+ import { createHash as createHash6, randomUUID as randomUUID2 } from "crypto";
1465
1702
  import {
1466
- access as access5,
1703
+ access as access6,
1704
+ copyFile as copyFile4,
1467
1705
  mkdir as mkdir5,
1468
- readFile as readFile6,
1706
+ readFile as readFile7,
1469
1707
  rename as rename6,
1470
1708
  rm as rm5,
1471
1709
  writeFile as writeFile6
1472
1710
  } from "fs/promises";
1473
- import { resolve as resolve6 } from "path";
1711
+ import { dirname as dirname4, isAbsolute as isAbsolute4, join as join6, relative as relative5, resolve as resolve5, sep as sep4 } from "path";
1712
+ init_getDurationString();
1713
+ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone";
1714
+ var BOOT_TIMEOUT_MS = 180000;
1715
+ var BOOT_POLL_MS = 1000;
1716
+ var DEV_JOURNAL_FORMAT = 1;
1717
+ var NATIVE_CACHE_FORMAT = 1;
1718
+ var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1719
+ var pathExists5 = async (path) => {
1720
+ try {
1721
+ await access6(path);
1722
+ return true;
1723
+ } catch {
1724
+ return false;
1725
+ }
1726
+ };
1727
+ var throwIfAborted2 = (signal) => signal?.throwIfAborted();
1728
+ var defaultCapture3 = (command, options = {}) => {
1729
+ try {
1730
+ const result = Bun.spawnSync(command, {
1731
+ cwd: options.cwd,
1732
+ env: options.env,
1733
+ stderr: "pipe",
1734
+ stdin: "ignore",
1735
+ stdout: "pipe"
1736
+ });
1737
+ return {
1738
+ exitCode: result.exitCode,
1739
+ stderr: result.stderr.toString(),
1740
+ stdout: result.stdout.toString()
1741
+ };
1742
+ } catch (error) {
1743
+ return {
1744
+ exitCode: 1,
1745
+ stderr: error instanceof Error ? error.message : String(error),
1746
+ stdout: ""
1747
+ };
1748
+ }
1749
+ };
1750
+ var defaultRun2 = async (command, options = {}) => {
1751
+ const process2 = Bun.spawn(command, {
1752
+ cwd: options.cwd,
1753
+ env: options.env,
1754
+ signal: options.signal,
1755
+ stderr: "inherit",
1756
+ stdin: "inherit",
1757
+ stdout: "inherit"
1758
+ });
1759
+ return process2.exited;
1760
+ };
1761
+ var defaultSpawn = (command, options = {}) => {
1762
+ Bun.spawn(command, {
1763
+ cwd: options.cwd,
1764
+ env: options.env,
1765
+ signal: options.signal,
1766
+ stderr: "ignore",
1767
+ stdin: "ignore",
1768
+ stdout: "ignore"
1769
+ });
1770
+ };
1771
+ var consumeLines = async (stream, onLine) => {
1772
+ const reader = stream.getReader();
1773
+ const decoder = new TextDecoder;
1774
+ let buffered = "";
1775
+ const pump = async () => {
1776
+ const { done, value } = await reader.read();
1777
+ if (done)
1778
+ return;
1779
+ buffered += decoder.decode(value, { stream: true });
1780
+ const lines = buffered.split(/\r?\n/u);
1781
+ buffered = lines.pop() ?? "";
1782
+ lines.forEach(onLine);
1783
+ await pump();
1784
+ };
1785
+ try {
1786
+ await pump();
1787
+ buffered += decoder.decode();
1788
+ if (buffered)
1789
+ onLine(buffered);
1790
+ } finally {
1791
+ reader.releaseLock();
1792
+ }
1793
+ };
1794
+ var defaultStartNativeLogs = (command, options, onLine) => {
1795
+ const process2 = Bun.spawn(command, {
1796
+ cwd: options.cwd,
1797
+ env: options.env,
1798
+ signal: options.signal,
1799
+ stderr: "pipe",
1800
+ stdin: "ignore",
1801
+ stdout: "pipe"
1802
+ });
1803
+ consumeLines(process2.stdout, onLine);
1804
+ consumeLines(process2.stderr, onLine);
1805
+ return {
1806
+ close: async () => {
1807
+ try {
1808
+ process2.kill();
1809
+ } catch {}
1810
+ await process2.exited.catch(() => {
1811
+ return;
1812
+ });
1813
+ }
1814
+ };
1815
+ };
1816
+ var requireSuccess2 = async (command, label, run, options) => {
1817
+ const exitCode = await run(command, options);
1818
+ if (exitCode !== 0)
1819
+ throw new Error(`${label} failed with status ${exitCode}.`);
1820
+ };
1821
+ var requireCapturedSuccess = (result, label) => {
1822
+ if (result.exitCode !== 0) {
1823
+ throw new Error(`${label} failed: ${result.stderr.trim() || result.stdout.trim() || `status ${result.exitCode}`}`);
1824
+ }
1825
+ return result.stdout.trim();
1826
+ };
1827
+ var parseJson = (source, label) => {
1828
+ try {
1829
+ const parsed = JSON.parse(source);
1830
+ if (isRecord3(parsed))
1831
+ return parsed;
1832
+ } catch {}
1833
+ throw new Error(`Invalid ${label} JSON from simctl.`);
1834
+ };
1835
+ var parseIosDeviceTypes = (source) => {
1836
+ const parsed = parseJson(source, "device type");
1837
+ const types = parsed.devicetypes;
1838
+ if (!Array.isArray(types))
1839
+ return [];
1840
+ return types.flatMap((type) => {
1841
+ if (!isRecord3(type))
1842
+ return [];
1843
+ const { identifier } = type;
1844
+ const { name } = type;
1845
+ return typeof identifier === "string" && typeof name === "string" ? [{ identifier, name }] : [];
1846
+ });
1847
+ };
1848
+ var parseIosRuntimes = (source) => {
1849
+ const parsed = parseJson(source, "runtime");
1850
+ const { runtimes } = parsed;
1851
+ if (!Array.isArray(runtimes))
1852
+ return [];
1853
+ return runtimes.flatMap((runtime) => {
1854
+ if (!isRecord3(runtime))
1855
+ return [];
1856
+ const { identifier } = runtime;
1857
+ const { name } = runtime;
1858
+ const { version } = runtime;
1859
+ if (typeof identifier !== "string" || typeof name !== "string" || typeof version !== "string")
1860
+ return [];
1861
+ return [
1862
+ {
1863
+ identifier,
1864
+ isAvailable: runtime.isAvailable !== false,
1865
+ name,
1866
+ version
1867
+ }
1868
+ ];
1869
+ });
1870
+ };
1871
+ var parseIosSimulators = (source) => {
1872
+ const parsed = parseJson(source, "device");
1873
+ const { devices } = parsed;
1874
+ if (!isRecord3(devices))
1875
+ return [];
1876
+ return Object.entries(devices).flatMap(([runtime, values]) => {
1877
+ if (!Array.isArray(values))
1878
+ return [];
1879
+ return values.flatMap((device) => {
1880
+ if (!isRecord3(device))
1881
+ return [];
1882
+ const { name } = device;
1883
+ const { state } = device;
1884
+ const { udid } = device;
1885
+ if (typeof name !== "string" || typeof state !== "string" || typeof udid !== "string")
1886
+ return [];
1887
+ return [
1888
+ {
1889
+ isAvailable: device.isAvailable !== false,
1890
+ name,
1891
+ runtime,
1892
+ state,
1893
+ udid
1894
+ }
1895
+ ];
1896
+ });
1897
+ });
1898
+ };
1899
+ var versionParts = (version) => version.split(".").map((part) => Number(part));
1900
+ var compareVersions = (left, right) => {
1901
+ const leftParts = versionParts(left);
1902
+ const rightParts = versionParts(right);
1903
+ const length = Math.max(leftParts.length, rightParts.length);
1904
+ for (let index = 0;index < length; index++) {
1905
+ const difference = (leftParts[index] ?? 0) - (rightParts[index] ?? 0);
1906
+ if (difference !== 0)
1907
+ return difference;
1908
+ }
1909
+ return 0;
1910
+ };
1911
+ var latestIosRuntime = (runtimes) => runtimes.filter((runtime) => runtime.isAvailable && runtime.identifier.includes("SimRuntime.iOS-")).sort((left, right) => compareVersions(right.version, left.version))[0];
1912
+ var iphoneGeneration = (name) => Number(/iPhone\s+(\d+)/u.exec(name)?.[1] ?? 0);
1913
+ var preferredIphoneType = (types) => types.filter((type) => type.name.startsWith("iPhone")).sort((left, right) => {
1914
+ const generation = iphoneGeneration(right.name) - iphoneGeneration(left.name);
1915
+ if (generation !== 0)
1916
+ return generation;
1917
+ const rightPro = right.name.includes("Pro") ? 1 : 0;
1918
+ const leftPro = left.name.includes("Pro") ? 1 : 0;
1919
+ return rightPro - leftPro;
1920
+ })[0];
1921
+ var journalPaths = (projectRoot) => {
1922
+ const root = join6(projectRoot, ".absolutejs", "mobile", "ios-dev-session");
1923
+ return {
1924
+ configBackup: join6(root, "capacitor-config.backup"),
1925
+ infoBackup: join6(root, "Info.plist.backup"),
1926
+ journal: join6(root, "journal.json"),
1927
+ root
1928
+ };
1929
+ };
1930
+ var nativeCachePath = (projectRoot) => join6(projectRoot, ".absolutejs", "mobile", "ios-native-cache.json");
1931
+ var isInside = (root, path) => {
1932
+ const value = relative5(resolve5(root), resolve5(path));
1933
+ return value === "" || !value.startsWith(`..${sep4}`) && value !== ".." && !isAbsolute4(value);
1934
+ };
1935
+ var parseJournal = (value) => {
1936
+ if (!isRecord3(value) || value.format !== DEV_JOURNAL_FORMAT)
1937
+ return null;
1938
+ const { configBackupPath } = value;
1939
+ const { infoBackupPath } = value;
1940
+ const { infoPath } = value;
1941
+ const { nativeConfigPath } = value;
1942
+ if (typeof configBackupPath !== "string" || typeof infoBackupPath !== "string" || typeof infoPath !== "string" || typeof nativeConfigPath !== "string")
1943
+ return null;
1944
+ return {
1945
+ configBackupPath,
1946
+ format: DEV_JOURNAL_FORMAT,
1947
+ infoBackupPath,
1948
+ infoPath,
1949
+ nativeConfigPath
1950
+ };
1951
+ };
1952
+ var repairAbsoluteIosDevSession = async (projectRoot) => {
1953
+ const paths = journalPaths(projectRoot);
1954
+ if (!await pathExists5(paths.journal)) {
1955
+ await rm5(paths.root, { force: true, recursive: true });
1956
+ return false;
1957
+ }
1958
+ const journal = await readFile7(paths.journal, "utf8").then((source) => parseJournal(JSON.parse(source))).catch(() => null);
1959
+ if (!journal || !isInside(projectRoot, journal.nativeConfigPath) || !isInside(projectRoot, journal.infoPath) || !isInside(paths.root, journal.configBackupPath) || !isInside(paths.root, journal.infoBackupPath)) {
1960
+ throw new Error(`Refusing unsafe or invalid iOS dev journal at ${paths.journal}.`);
1961
+ }
1962
+ if (await pathExists5(journal.configBackupPath))
1963
+ await copyFile4(journal.configBackupPath, journal.nativeConfigPath);
1964
+ if (await pathExists5(journal.infoBackupPath))
1965
+ await copyFile4(journal.infoBackupPath, journal.infoPath);
1966
+ await rm5(paths.root, { force: true, recursive: true });
1967
+ return true;
1968
+ };
1969
+ var iosDevelopmentInfoPlist = (source, cleartext) => {
1970
+ if (!cleartext)
1971
+ return source;
1972
+ const arbitraryLoads = /(<key>NSAllowsArbitraryLoads<\/key>\s*)<false\s*\/>/u;
1973
+ if (arbitraryLoads.test(source))
1974
+ return source.replace(arbitraryLoads, "$1<true/>");
1975
+ if (/<key>NSAllowsArbitraryLoads<\/key>\s*<true\s*\/>/u.test(source))
1976
+ return source;
1977
+ const transport = /(<key>NSAppTransportSecurity<\/key>\s*<dict>)/u;
1978
+ if (transport.test(source))
1979
+ return source.replace(transport, `$1
1980
+ <key>NSAllowsArbitraryLoads</key>
1981
+ <true/>`);
1982
+ return source.replace(/<dict>/u, `<dict>
1983
+ <key>NSAppTransportSecurity</key>
1984
+ <dict>
1985
+ <key>NSAllowsArbitraryLoads</key>
1986
+ <true/>
1987
+ </dict>`);
1988
+ };
1989
+ var writeDevProjection = async (project, port, https) => {
1990
+ const paths = journalPaths(project.projectRoot);
1991
+ await repairAbsoluteIosDevSession(project.projectRoot);
1992
+ const nativeConfigPath = join6(project.nativeDirectory, "App", "App", "capacitor.config.json");
1993
+ const infoPath = join6(project.nativeDirectory, "App", "App", "Info.plist");
1994
+ const [configSource, infoSource] = await Promise.all([
1995
+ readFile7(nativeConfigPath, "utf8"),
1996
+ readFile7(infoPath, "utf8")
1997
+ ]);
1998
+ const parsed = JSON.parse(configSource);
1999
+ if (!isRecord3(parsed))
2000
+ throw new Error(`Invalid Capacitor native config at ${nativeConfigPath}.`);
2001
+ await mkdir5(paths.root, { recursive: true });
2002
+ await Promise.all([
2003
+ writeFile6(paths.configBackup, configSource, { flag: "wx" }),
2004
+ writeFile6(paths.infoBackup, infoSource, { flag: "wx" })
2005
+ ]);
2006
+ const journal = {
2007
+ configBackupPath: paths.configBackup,
2008
+ format: DEV_JOURNAL_FORMAT,
2009
+ infoBackupPath: paths.infoBackup,
2010
+ infoPath,
2011
+ nativeConfigPath
2012
+ };
2013
+ await writeFile6(paths.journal, `${JSON.stringify(journal, null, "\t")}
2014
+ `, {
2015
+ flag: "wx"
2016
+ });
2017
+ const developmentUrl = new URL(`${https ? "https" : "http"}://localhost:${port}${project.config.entry}`);
2018
+ developmentUrl.searchParams.set("__absolute_target", "capacitor-ios");
2019
+ const existingServer = parsed.server;
2020
+ parsed.server = {
2021
+ ...isRecord3(existingServer) ? existingServer : {},
2022
+ cleartext: !https,
2023
+ url: developmentUrl.href
2024
+ };
2025
+ await Promise.all([
2026
+ writeFile6(nativeConfigPath, `${JSON.stringify(parsed, null, "\t")}
2027
+ `),
2028
+ writeFile6(infoPath, iosDevelopmentInfoPlist(infoSource, !https))
2029
+ ]);
2030
+ };
2031
+ var parseNativeCache = (value) => {
2032
+ if (!isRecord3(value))
2033
+ return null;
2034
+ const { appId, fingerprint, format, installations } = value;
2035
+ if (format !== NATIVE_CACHE_FORMAT || typeof appId !== "string" || typeof fingerprint !== "string" || !isRecord3(installations) || !Object.values(installations).every((identity) => typeof identity === "string"))
2036
+ return null;
2037
+ return {
2038
+ appId,
2039
+ fingerprint,
2040
+ format,
2041
+ installations: Object.fromEntries(Object.entries(installations).map(([udid, identity]) => [
2042
+ udid,
2043
+ String(identity)
2044
+ ]))
2045
+ };
2046
+ };
2047
+ var readNativeCache = (projectRoot) => readFile7(nativeCachePath(projectRoot), "utf8").then((source) => parseNativeCache(JSON.parse(source))).catch(() => null);
2048
+ var writeNativeCache = async (projectRoot, cache) => {
2049
+ const destination = nativeCachePath(projectRoot);
2050
+ const temporary = `${destination}.${process.pid}.${randomUUID2()}.tmp`;
2051
+ await mkdir5(dirname4(destination), { recursive: true });
2052
+ try {
2053
+ await writeFile6(temporary, `${JSON.stringify(cache, null, "\t")}
2054
+ `, {
2055
+ flag: "wx"
2056
+ });
2057
+ await rename6(temporary, destination);
2058
+ } finally {
2059
+ await rm5(temporary, { force: true }).catch(() => {
2060
+ return;
2061
+ });
2062
+ }
2063
+ };
2064
+ var fingerprintAbsoluteIosDevProject = async (project) => fingerprintAbsoluteIosNativeProject(project.nativeDirectory);
2065
+ var simulatorInventory = (xcrun, capture) => {
2066
+ const result = capture([
2067
+ xcrun,
2068
+ "simctl",
2069
+ "list",
2070
+ "devices",
2071
+ "available",
2072
+ "-j"
2073
+ ]);
2074
+ return parseIosSimulators(requireCapturedSuccess(result, "iOS simulator discovery"));
2075
+ };
2076
+ var ensureManagedSimulator = async (project, capture) => {
2077
+ const runtimes = parseIosRuntimes(requireCapturedSuccess(capture([project.xcrun, "simctl", "list", "runtimes", "-j"]), "iOS runtime discovery"));
2078
+ const runtime = latestIosRuntime(runtimes);
2079
+ if (!runtime)
2080
+ throw new Error("No available iOS Simulator runtime. Run absolute mobile doctor ios --fix.");
2081
+ const [existing] = simulatorInventory(project.xcrun, capture).filter((device) => device.isAvailable && device.name === ABSOLUTE_IOS_SIMULATOR_NAME && device.runtime === runtime.identifier).sort((left, right) => Number(right.state === "Booted") - Number(left.state === "Booted"));
2082
+ if (existing)
2083
+ return { created: false, device: existing };
2084
+ const types = parseIosDeviceTypes(requireCapturedSuccess(capture([project.xcrun, "simctl", "list", "devicetypes", "-j"]), "iOS device-type discovery"));
2085
+ const type = preferredIphoneType(types);
2086
+ if (!type)
2087
+ throw new Error("Xcode did not report an iPhone simulator type.");
2088
+ const [udid] = requireCapturedSuccess(capture([
2089
+ project.xcrun,
2090
+ "simctl",
2091
+ "create",
2092
+ ABSOLUTE_IOS_SIMULATOR_NAME,
2093
+ type.identifier,
2094
+ runtime.identifier
2095
+ ]), "iOS simulator creation").split(/\s/u);
2096
+ if (!udid)
2097
+ throw new Error("simctl did not return the created simulator UDID.");
2098
+ return {
2099
+ created: true,
2100
+ device: {
2101
+ isAvailable: true,
2102
+ name: ABSOLUTE_IOS_SIMULATOR_NAME,
2103
+ runtime: runtime.identifier,
2104
+ state: "Shutdown",
2105
+ udid
2106
+ }
2107
+ };
2108
+ };
2109
+ var waitForBootedSimulator = async (project, udid, capture, sleep, signal) => {
2110
+ const deadline = Date.now() + BOOT_TIMEOUT_MS;
2111
+ const poll = async () => {
2112
+ throwIfAborted2(signal);
2113
+ const device = simulatorInventory(project.xcrun, capture).find((candidate) => candidate.udid === udid);
2114
+ if (device?.state === "Booted")
2115
+ return;
2116
+ if (Date.now() > deadline)
2117
+ throw new Error(`iOS simulator ${udid} did not finish booting within ${BOOT_TIMEOUT_MS / 1000}s.`);
2118
+ await sleep(BOOT_POLL_MS);
2119
+ await poll();
2120
+ };
2121
+ return poll();
2122
+ };
2123
+ var bootSimulator = (project, device, capture) => {
2124
+ if (device.state === "Booted")
2125
+ return;
2126
+ requireCapturedSuccess(capture([project.xcrun, "simctl", "boot", device.udid]), "iOS simulator boot");
2127
+ };
2128
+ var installedAppIdentity = (project, udid, capture) => {
2129
+ const result = capture([
2130
+ project.xcrun,
2131
+ "simctl",
2132
+ "get_app_container",
2133
+ udid,
2134
+ project.config.appId,
2135
+ "app"
2136
+ ]);
2137
+ return result.exitCode === 0 && result.stdout.trim() ? result.stdout.trim() : undefined;
2138
+ };
2139
+ var buildIosDebugApp = async (project, udid, fingerprint, run, signal) => {
2140
+ const derivedDataPath = join6(project.projectRoot, ".absolutejs", "mobile", "ios-derived-data", createHash6("sha256").update(project.config.appId).digest("hex").slice(0, 16));
2141
+ await mkdir5(derivedDataPath, { recursive: true });
2142
+ await requireSuccess2([
2143
+ project.xcodebuild,
2144
+ "-workspace",
2145
+ join6(project.nativeDirectory, "App", "App.xcworkspace"),
2146
+ "-scheme",
2147
+ "App",
2148
+ "-configuration",
2149
+ "Debug",
2150
+ "-destination",
2151
+ `platform=iOS Simulator,id=${udid}`,
2152
+ "-derivedDataPath",
2153
+ derivedDataPath,
2154
+ "build"
2155
+ ], "iOS simulator build", run, { cwd: project.nativeDirectory, signal });
2156
+ const appPath = join6(derivedDataPath, "Build", "Products", "Debug-iphonesimulator", "App.app");
2157
+ if (!await pathExists5(appPath))
2158
+ throw new Error(`Xcode did not produce the simulator app at ${appPath}.`);
2159
+ return appPath;
2160
+ };
2161
+ var ensureIosDebugApp = async (options) => {
2162
+ const installed = installedAppIdentity(options.project, options.udid, options.capture);
2163
+ const cacheHit = options.cache?.appId === options.project.config.appId && options.cache.fingerprint === options.fingerprint && installed !== undefined && options.cache.installations[options.udid] === installed;
2164
+ if (cacheHit) {
2165
+ options.log(`iOS native app is unchanged on ${options.udid}; skipped Xcode build and install.`);
2166
+ return true;
2167
+ }
2168
+ options.log("iOS native inputs changed or the installed app is stale; rebuilding.");
2169
+ options.transition("building");
2170
+ const appPath = await buildIosDebugApp(options.project, options.udid, options.fingerprint, options.run, options.signal);
2171
+ throwIfAborted2(options.signal);
2172
+ options.transition("installing");
2173
+ await requireSuccess2([options.project.xcrun, "simctl", "install", options.udid, appPath], "iOS simulator app installation", options.run, { signal: options.signal });
2174
+ const updated = installedAppIdentity(options.project, options.udid, options.capture);
2175
+ if (updated) {
2176
+ await writeNativeCache(options.project.projectRoot, {
2177
+ appId: options.project.config.appId,
2178
+ fingerprint: options.fingerprint,
2179
+ format: NATIVE_CACHE_FORMAT,
2180
+ installations: { [options.udid]: updated }
2181
+ }).catch((error) => options.log(`iOS native cache could not be saved: ${error instanceof Error ? error.message : String(error)}`));
2182
+ }
2183
+ return false;
2184
+ };
2185
+ var SECRET_VALUE = /((?:authorization|cookie|password|secret|token|oauth[_-]?code)\s*[:=]\s*)([^\s,;]+)/giu;
2186
+ var BEARER_VALUE = new RegExp(String.raw`\bBearer\s+[A-Za-z0-9._~+/-]+=*`, "giu");
2187
+ var JWT_VALUE = /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/gu;
2188
+ var IOS_LOG_PATTERN = new RegExp(String.raw`\s(Debug|Info|Notice|Error|Fault)\s+.*?\[[^\]]+\]\s+\[([^\]]+)\]\s*(.*)$`, "iu");
2189
+ var parseAbsoluteIosLogLine = (line) => {
2190
+ const sanitized = redactAbsoluteIosLog(line).trim();
2191
+ if (!sanitized)
2192
+ return null;
2193
+ const match = IOS_LOG_PATTERN.exec(sanitized);
2194
+ const candidate = match?.[1]?.toLowerCase();
2195
+ const level = candidate === "debug" || candidate === "error" || candidate === "fault" || candidate === "notice" ? candidate : "info";
2196
+ return {
2197
+ level,
2198
+ message: match?.[3]?.trim() || sanitized,
2199
+ tag: match?.[2]?.trim() || "App"
2200
+ };
2201
+ };
2202
+ var redactAbsoluteIosLog = (value) => value.replaceAll(BEARER_VALUE, "Bearer [REDACTED]").replaceAll(JWT_VALUE, "[REDACTED_JWT]").replaceAll(SECRET_VALUE, "$1[REDACTED]").replaceAll(/\p{C}/gu, "");
2203
+ var attachNativeLogs = (project, udid, options) => {
2204
+ if (!options.nativeLog)
2205
+ return null;
2206
+ const start = options.startNativeLogs ?? defaultStartNativeLogs;
2207
+ return start([
2208
+ project.xcrun,
2209
+ "simctl",
2210
+ "spawn",
2211
+ udid,
2212
+ "log",
2213
+ "stream",
2214
+ "--style",
2215
+ "compact",
2216
+ "--level",
2217
+ "debug",
2218
+ "--predicate",
2219
+ 'process == "App"'
2220
+ ], { signal: options.signal }, (line) => {
2221
+ const entry = parseAbsoluteIosLogLine(line);
2222
+ if (entry)
2223
+ options.nativeLog?.(entry);
2224
+ });
2225
+ };
2226
+ var IOS_TIMING_PHASES = [
2227
+ ["syncing", "Capacitor sync"],
2228
+ ["configuring", "dev config"],
2229
+ ["fingerprinting", "fingerprint"],
2230
+ ["booting", "simulator"],
2231
+ ["connecting", "device ready"],
2232
+ ["checking-native", "app check"],
2233
+ ["building", "Xcode"],
2234
+ ["installing", "install"],
2235
+ ["launching", "launch"],
2236
+ ["streaming-logs", "logs"]
2237
+ ];
2238
+ var timingSummary = (timings) => IOS_TIMING_PHASES.map(([phase, label]) => {
2239
+ const duration = timings[phase];
2240
+ return duration === undefined ? null : `${label} ${getDurationString(duration)}`;
2241
+ }).filter((value) => value !== null).join(", ");
2242
+ var prepareAbsoluteIosDevProject = async (config, options) => {
2243
+ if (detectAbsoluteMobileHost() !== "macos")
2244
+ throw new Error("iOS simulation requires macOS and Xcode.");
2245
+ const projectRoot = resolve5(options.projectRoot);
2246
+ const checks = await inspectAbsoluteMobileToolchain({ host: "macos" });
2247
+ const failed = checks.filter((check) => check.platform === "ios" && (check.status === "fail" || check.status === "warn"));
2248
+ if (failed.length > 0)
2249
+ throw new Error(`iOS simulation is not ready: ${failed.map(({ label }) => label).join(", ")}.`);
2250
+ const xcrun = checks.find((check) => check.id === "ios.xcrun")?.path;
2251
+ const xcodebuild = checks.find((check) => check.id === "ios.xcodebuild")?.path;
2252
+ if (!xcrun || !xcodebuild)
2253
+ throw new Error("Xcode tools disappeared after readiness checks.");
2254
+ const cap = join6(projectRoot, "node_modules", ".bin", "cap");
2255
+ if (!await pathExists5(cap))
2256
+ throw new Error("Capacitor CLI is not installed. Run absolute mobile init first.");
2257
+ await writeAbsoluteCapacitorConfig(config, { projectRoot });
2258
+ await mkdir5(config.bundleDirectory, { recursive: true });
2259
+ const placeholder = join6(config.bundleDirectory, "index.html");
2260
+ if (!await pathExists5(placeholder))
2261
+ await writeFile6(placeholder, `<!doctype html><title>AbsoluteJS mobile development</title>
2262
+ `);
2263
+ const nativeDirectory = join6(config.nativeProjectDirectory, "ios");
2264
+ if (!await pathExists5(nativeDirectory)) {
2265
+ if (!options.createNativeProject)
2266
+ throw new Error("iOS native project has not been created.");
2267
+ const run = options.run ?? defaultRun2;
2268
+ if (await run([cap, "add", "ios"], { cwd: projectRoot }) !== 0)
2269
+ throw new Error("Capacitor iOS project creation failed.");
2270
+ }
2271
+ return {
2272
+ cap,
2273
+ config,
2274
+ nativeDirectory,
2275
+ projectRoot,
2276
+ xcodebuild,
2277
+ xcrun
2278
+ };
2279
+ };
2280
+ var startAbsoluteIosDevSession = async (options) => {
2281
+ const { project } = options;
2282
+ const capture = options.capture ?? defaultCapture3;
2283
+ const run = options.run ?? defaultRun2;
2284
+ const sleep = options.sleep ?? Bun.sleep;
2285
+ const spawn = options.spawn ?? defaultSpawn;
2286
+ const log = options.log ?? console.log;
2287
+ const startedAt = performance.now();
2288
+ let phaseStartedAt = performance.now();
2289
+ const timings = {};
2290
+ let state = "syncing";
2291
+ const transition = (next) => {
2292
+ if (next === state) {
2293
+ options.onStateChange?.(next);
2294
+ return;
2295
+ }
2296
+ const now = performance.now();
2297
+ const durationMs = now - phaseStartedAt;
2298
+ timings[state] = (timings[state] ?? 0) + durationMs;
2299
+ options.onPhaseTiming?.({
2300
+ durationMs,
2301
+ phase: state,
2302
+ totalMs: now - startedAt
2303
+ });
2304
+ state = next;
2305
+ phaseStartedAt = now;
2306
+ options.onStateChange?.(next);
2307
+ };
2308
+ let nativeLogs = null;
2309
+ const closeLogs = async () => {
2310
+ const stream = nativeLogs;
2311
+ nativeLogs = null;
2312
+ await stream?.close().catch(() => {
2313
+ return;
2314
+ });
2315
+ };
2316
+ try {
2317
+ await repairAbsoluteIosDevSession(project.projectRoot);
2318
+ throwIfAborted2(options.signal);
2319
+ transition("syncing");
2320
+ await requireSuccess2([project.cap, "sync", "ios"], "Capacitor iOS synchronization", run, { cwd: project.projectRoot, signal: options.signal });
2321
+ transition("configuring");
2322
+ await writeDevProjection(project, options.port, options.https === true);
2323
+ throwIfAborted2(options.signal);
2324
+ const fingerprintStartedAt = performance.now();
2325
+ const fingerprintPromise = fingerprintAbsoluteIosDevProject(project).then((fingerprint2) => {
2326
+ timings.fingerprinting = performance.now() - fingerprintStartedAt;
2327
+ return fingerprint2;
2328
+ });
2329
+ transition("booting");
2330
+ const { created, device } = await ensureManagedSimulator(project, capture);
2331
+ const startedSimulator = created || device.state !== "Booted";
2332
+ bootSimulator(project, device, capture);
2333
+ spawn([
2334
+ "open",
2335
+ "-a",
2336
+ "Simulator",
2337
+ "--args",
2338
+ "-CurrentDeviceUDID",
2339
+ device.udid
2340
+ ]);
2341
+ transition("connecting");
2342
+ await waitForBootedSimulator(project, device.udid, capture, sleep, options.signal);
2343
+ await requireSuccess2([project.xcrun, "simctl", "bootstatus", device.udid, "-b"], "iOS simulator boot readiness", run, { signal: options.signal });
2344
+ const fingerprint = await fingerprintPromise;
2345
+ transition("checking-native");
2346
+ const nativeCacheHit = await ensureIosDebugApp({
2347
+ cache: await readNativeCache(project.projectRoot),
2348
+ capture,
2349
+ fingerprint,
2350
+ log,
2351
+ project,
2352
+ run,
2353
+ signal: options.signal,
2354
+ transition,
2355
+ udid: device.udid
2356
+ });
2357
+ throwIfAborted2(options.signal);
2358
+ if (options.nativeLog)
2359
+ transition("streaming-logs");
2360
+ nativeLogs = attachNativeLogs(project, device.udid, options);
2361
+ transition("launching");
2362
+ await requireSuccess2([
2363
+ project.xcrun,
2364
+ "simctl",
2365
+ "launch",
2366
+ "--terminate-running-process",
2367
+ device.udid,
2368
+ project.config.appId
2369
+ ], "iOS app launch", run, { signal: options.signal });
2370
+ transition("ready");
2371
+ timings.total = performance.now() - startedAt;
2372
+ log(`iOS simulator connected (${device.udid}) with HMR on port ${options.port} in ${getDurationString(timings.total)} (${nativeCacheHit ? "native cache hit" : "native build installed"}).`);
2373
+ log(`iOS startup: ${timingSummary(timings)}.`);
2374
+ let closed = false;
2375
+ const close = async () => {
2376
+ if (closed)
2377
+ return;
2378
+ closed = true;
2379
+ transition("closing");
2380
+ await closeLogs();
2381
+ await repairAbsoluteIosDevSession(project.projectRoot);
2382
+ transition("closed");
2383
+ };
2384
+ return {
2385
+ close,
2386
+ nativeCacheHit,
2387
+ startedSimulator,
2388
+ timings: { ...timings },
2389
+ udid: device.udid,
2390
+ rebuild: async () => {
2391
+ if (closed)
2392
+ throw new Error("iOS development session is closed.");
2393
+ log("iOS native inputs changed; rebuilding without restarting the dev server.");
2394
+ await close();
2395
+ return startAbsoluteIosDevSession(options);
2396
+ },
2397
+ relaunch: async () => {
2398
+ if (closed)
2399
+ throw new Error("iOS development session is closed.");
2400
+ transition("launching");
2401
+ try {
2402
+ await requireSuccess2([
2403
+ project.xcrun,
2404
+ "simctl",
2405
+ "launch",
2406
+ "--terminate-running-process",
2407
+ device.udid,
2408
+ project.config.appId
2409
+ ], "iOS app relaunch", run, { signal: options.signal });
2410
+ transition("ready");
2411
+ log(`iOS app relaunched on ${device.udid}.`);
2412
+ } catch (error) {
2413
+ transition("failed");
2414
+ throw error;
2415
+ }
2416
+ },
2417
+ screenshot: async (destination) => {
2418
+ const resolved = resolve5(project.projectRoot, destination);
2419
+ if (!isInside(project.projectRoot, resolved))
2420
+ throw new Error("iOS screenshot destination must remain inside the project.");
2421
+ await mkdir5(dirname4(resolved), { recursive: true });
2422
+ await requireSuccess2([
2423
+ project.xcrun,
2424
+ "simctl",
2425
+ "io",
2426
+ device.udid,
2427
+ "screenshot",
2428
+ resolved
2429
+ ], "iOS simulator screenshot", run, { signal: options.signal });
2430
+ return resolved;
2431
+ },
2432
+ get state() {
2433
+ return state;
2434
+ }
2435
+ };
2436
+ } catch (error) {
2437
+ transition("failed");
2438
+ await closeLogs();
2439
+ await repairAbsoluteIosDevSession(project.projectRoot);
2440
+ throw error;
2441
+ }
2442
+ };
2443
+ // src/mobile/iosNativeWatcher.ts
2444
+ import { watch } from "fs";
2445
+ import { basename } from "path";
2446
+ var NATIVE_CHANGE_DEBOUNCE_MS = 500;
2447
+ var ROOT_NATIVE_INPUTS = new Set([
2448
+ "absolute.config.js",
2449
+ "absolute.config.mjs",
2450
+ "absolute.config.ts",
2451
+ "absolutejs.config.js",
2452
+ "absolutejs.config.mjs",
2453
+ "absolutejs.config.ts",
2454
+ "bun.lock",
2455
+ "bun.lockb",
2456
+ "capacitor.config.js",
2457
+ "capacitor.config.ts",
2458
+ "package.json"
2459
+ ]);
2460
+ var createAbsoluteIosNativeWatcher = async (options) => {
2461
+ let fingerprint = await fingerprintAbsoluteIosDevProject(options.project);
2462
+ let closed = false;
2463
+ let running = false;
2464
+ let timer;
2465
+ let rootInputChanged = false;
2466
+ const changedPaths = new Set;
2467
+ const watchers = [];
2468
+ const debounceMs = options.debounceMs ?? NATIVE_CHANGE_DEBOUNCE_MS;
2469
+ const close = () => {
2470
+ if (closed)
2471
+ return;
2472
+ closed = true;
2473
+ if (timer)
2474
+ clearTimeout(timer);
2475
+ watchers.forEach((watcher) => watcher.close());
2476
+ options.signal?.removeEventListener("abort", close);
2477
+ };
2478
+ const schedule = () => {
2479
+ if (closed || running)
2480
+ return;
2481
+ if (timer)
2482
+ clearTimeout(timer);
2483
+ timer = setTimeout(() => void flush(), debounceMs);
2484
+ };
2485
+ const flush = async () => {
2486
+ timer = undefined;
2487
+ if (closed || running || changedPaths.size === 0)
2488
+ return;
2489
+ running = true;
2490
+ const paths = [...changedPaths].sort();
2491
+ const forced = rootInputChanged;
2492
+ changedPaths.clear();
2493
+ rootInputChanged = false;
2494
+ try {
2495
+ const next = await fingerprintAbsoluteIosDevProject(options.project);
2496
+ if (!forced && next === fingerprint)
2497
+ return;
2498
+ await options.onChange({
2499
+ afterFingerprint: next,
2500
+ beforeFingerprint: fingerprint,
2501
+ paths,
2502
+ rootInputChanged: forced
2503
+ });
2504
+ fingerprint = await fingerprintAbsoluteIosDevProject(options.project);
2505
+ } catch (error) {
2506
+ options.onError?.(error);
2507
+ } finally {
2508
+ running = false;
2509
+ if (changedPaths.size > 0)
2510
+ schedule();
2511
+ }
2512
+ };
2513
+ const record = (path, force) => {
2514
+ if (closed)
2515
+ return;
2516
+ changedPaths.add(path);
2517
+ rootInputChanged ||= force;
2518
+ schedule();
2519
+ };
2520
+ watchers.push(watch(options.project.nativeDirectory, { recursive: true }, (_event, filename) => {
2521
+ if (filename)
2522
+ record(String(filename), false);
2523
+ }));
2524
+ watchers.push(watch(options.project.projectRoot, (_event, filename) => {
2525
+ if (!filename)
2526
+ return;
2527
+ const path = String(filename);
2528
+ if (isAbsoluteIosNativeRootInput(path))
2529
+ record(path, true);
2530
+ }));
2531
+ watchers.forEach((watcher) => watcher.on("error", (error) => options.onError?.(error)));
2532
+ options.signal?.addEventListener("abort", close, { once: true });
2533
+ return { close };
2534
+ };
2535
+ var isAbsoluteIosNativeRootInput = (path) => ROOT_NATIVE_INPUTS.has(basename(path));
2536
+ // src/mobile/associationFiles.ts
2537
+ import {
2538
+ access as access7,
2539
+ mkdir as mkdir6,
2540
+ readFile as readFile8,
2541
+ rename as rename7,
2542
+ rm as rm6,
2543
+ writeFile as writeFile7
2544
+ } from "fs/promises";
2545
+ import { resolve as resolve7 } from "path";
1474
2546
  import { Elysia } from "elysia";
1475
2547
 
1476
2548
  // src/mobile/config.ts
1477
- import { resolve as resolve5 } from "path";
2549
+ import { resolve as resolve6 } from "path";
1478
2550
  var APP_ID_PATTERN = /^[A-Za-z][\w]*(?:\.[A-Za-z][\w]*)+$/;
1479
2551
  var SCHEME_PATTERN = /^[a-z][a-z0-9+.-]*$/;
1480
2552
  var APPLE_APP_ID_PREFIX_PATTERN = /^[A-Z0-9]{10}$/;
1481
2553
  var CERTIFICATE_FINGERPRINT_PATTERN = /^[0-9A-F]{64}$/;
1482
2554
  var HOSTNAME_PATTERN = /^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\.(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?))*$/;
1483
2555
  var resolveProjectPath = (projectRoot, value, field) => {
1484
- const root = resolve5(projectRoot);
1485
- const path = resolve5(root, value);
2556
+ const root = resolve6(projectRoot);
2557
+ const path = resolve6(root, value);
1486
2558
  if (path !== root && !path.startsWith(`${root}/`)) {
1487
2559
  throw new TypeError(`${field} must remain inside the project root.`);
1488
2560
  }
@@ -1670,7 +2742,7 @@ var createAbsoluteMobileAssociationPlugin = (mobile, projectRoot, options = {})
1670
2742
  var writeAtomic = async (path, source) => {
1671
2743
  let current;
1672
2744
  try {
1673
- current = await readFile6(path, "utf8");
2745
+ current = await readFile8(path, "utf8");
1674
2746
  } catch (error) {
1675
2747
  if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
1676
2748
  throw error;
@@ -1679,23 +2751,23 @@ var writeAtomic = async (path, source) => {
1679
2751
  if (current === source)
1680
2752
  return false;
1681
2753
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
1682
- await writeFile6(temporary, source, { flag: "wx" });
1683
- await rename6(temporary, path);
2754
+ await writeFile7(temporary, source, { flag: "wx" });
2755
+ await rename7(temporary, path);
1684
2756
  return true;
1685
2757
  };
1686
2758
  var exists2 = async (path) => {
1687
2759
  try {
1688
- await access5(path);
2760
+ await access7(path);
1689
2761
  return true;
1690
2762
  } catch {
1691
2763
  return false;
1692
2764
  }
1693
2765
  };
1694
2766
  var assertOwnedOutput = async (root) => {
1695
- const path = resolve6(root, OWNERSHIP_FILE);
2767
+ const path = resolve7(root, OWNERSHIP_FILE);
1696
2768
  let ownership;
1697
2769
  try {
1698
- ownership = JSON.parse(await readFile6(path, "utf8"));
2770
+ ownership = JSON.parse(await readFile8(path, "utf8"));
1699
2771
  } catch {
1700
2772
  throw new TypeError(`Association output ${root} already exists and is not owned by AbsoluteJS.`);
1701
2773
  }
@@ -1709,22 +2781,22 @@ var publishGeneratedDirectory = async (temporary, root) => {
1709
2781
  await assertOwnedOutput(root);
1710
2782
  const backup = `${root}.${crypto.randomUUID()}.previous`;
1711
2783
  if (hasCurrent)
1712
- await rename6(root, backup);
2784
+ await rename7(root, backup);
1713
2785
  try {
1714
- await rename6(temporary, root);
2786
+ await rename7(temporary, root);
1715
2787
  } catch (error) {
1716
2788
  if (hasCurrent)
1717
- await rename6(backup, root);
2789
+ await rename7(backup, root);
1718
2790
  throw error;
1719
2791
  }
1720
2792
  if (hasCurrent)
1721
- await rm5(backup, { force: true, recursive: true });
2793
+ await rm6(backup, { force: true, recursive: true });
1722
2794
  };
1723
2795
  var materializeHost = async (root, host, files) => {
1724
- const directory = resolve6(root, host, ".well-known");
1725
- await mkdir5(directory, { recursive: true });
2796
+ const directory = resolve7(root, host, ".well-known");
2797
+ await mkdir6(directory, { recursive: true });
1726
2798
  return Promise.all(files.map(async ([name, document]) => {
1727
- const path = resolve6(directory, name);
2799
+ const path = resolve7(directory, name);
1728
2800
  await writeAtomic(path, `${JSON.stringify(document, null, 2)}
1729
2801
  `);
1730
2802
  return path;
@@ -1749,7 +2821,7 @@ var associationEndpoints = (config, documents) => config.deepLinkHosts.flatMap((
1749
2821
  return endpoints;
1750
2822
  });
1751
2823
  var materializeAbsoluteMobileAssociationFiles = async (config, outputDirectory) => {
1752
- const root = resolve6(outputDirectory);
2824
+ const root = resolve7(outputDirectory);
1753
2825
  const temporary = `${root}.${crypto.randomUUID()}.tmp`;
1754
2826
  const documents = createAbsoluteMobileAssociationDocuments(config, {
1755
2827
  requireAll: true
@@ -1760,16 +2832,16 @@ var materializeAbsoluteMobileAssociationFiles = async (config, outputDirectory)
1760
2832
  if (documents.apple) {
1761
2833
  files.push(["apple-app-site-association", documents.apple]);
1762
2834
  }
1763
- await mkdir5(temporary, { recursive: true });
2835
+ await mkdir6(temporary, { recursive: true });
1764
2836
  try {
1765
2837
  const temporaryPaths = (await Promise.all(config.deepLinkHosts.map((host) => materializeHost(temporary, host, files)))).flat();
1766
- await writeAtomic(resolve6(temporary, OWNERSHIP_FILE), `${JSON.stringify({ format: 1, hosts: config.deepLinkHosts }, null, 2)}
2838
+ await writeAtomic(resolve7(temporary, OWNERSHIP_FILE), `${JSON.stringify({ format: 1, hosts: config.deepLinkHosts }, null, 2)}
1767
2839
  `);
1768
2840
  await publishGeneratedDirectory(temporary, root);
1769
- const written = temporaryPaths.map((path) => resolve6(root, path.slice(temporary.length + 1)));
2841
+ const written = temporaryPaths.map((path) => resolve7(root, path.slice(temporary.length + 1)));
1770
2842
  return { root, written };
1771
2843
  } catch (error) {
1772
- await rm5(temporary, { force: true, recursive: true });
2844
+ await rm6(temporary, { force: true, recursive: true });
1773
2845
  throw error;
1774
2846
  }
1775
2847
  };
@@ -1814,10 +2886,10 @@ var frameworks2 = new Set([
1814
2886
  "svelte",
1815
2887
  "vue"
1816
2888
  ]);
1817
- var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2889
+ var isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1818
2890
  var isPageFramework2 = (value) => typeof value === "string" && frameworks2.has(value);
1819
2891
  var parseAbsoluteMobileBuildPageMetadata = (value) => {
1820
- if (!isRecord3(value))
2892
+ if (!isRecord4(value))
1821
2893
  return;
1822
2894
  if (typeof value.bundleKey !== "string" || typeof value.contract !== "string" || !isPageFramework2(value.framework) || typeof value.pageId !== "string" || typeof value.propsSchemaHash !== "string") {
1823
2895
  return;
@@ -1831,23 +2903,23 @@ var parseAbsoluteMobileBuildPageMetadata = (value) => {
1831
2903
  };
1832
2904
  };
1833
2905
  // src/mobile/buildPipeline.ts
1834
- import { readFile as readFile10 } from "fs/promises";
1835
- import { join as join9, resolve as resolve9 } from "path";
2906
+ import { readFile as readFile12 } from "fs/promises";
2907
+ import { join as join10, resolve as resolve10 } from "path";
1836
2908
  import { pathToFileURL as pathToFileURL2 } from "url";
1837
2909
 
1838
2910
  // src/mobile/buildRelease.ts
1839
- import { createHash as createHash6 } from "crypto";
1840
- import { readFile as readFile7 } from "fs/promises";
1841
- import { join as join6, relative as relative5, resolve as resolve7 } from "path";
1842
- var sha256 = (bytes) => createHash6("sha256").update(bytes).digest("hex");
2911
+ import { createHash as createHash7 } from "crypto";
2912
+ import { readFile as readFile9 } from "fs/promises";
2913
+ import { join as join7, relative as relative6, resolve as resolve8 } from "path";
2914
+ var sha256 = (bytes) => createHash7("sha256").update(bytes).digest("hex");
1843
2915
  var readPageMetadata = (route) => parseAbsoluteMobileBuildPageMetadata(route.hooks?.detail?.[ABSOLUTE_MOBILE_ROUTE_DETAIL]);
1844
2916
  var resolveAssetPath = (buildDirectory, assetPath) => {
1845
- const resolvedBuildDirectory = resolve7(buildDirectory);
1846
- const resolvedAsset = resolve7(assetPath);
2917
+ const resolvedBuildDirectory = resolve8(buildDirectory);
2918
+ const resolvedAsset = resolve8(assetPath);
1847
2919
  if (resolvedAsset.startsWith(`${resolvedBuildDirectory}/`)) {
1848
2920
  return resolvedAsset;
1849
2921
  }
1850
- return join6(buildDirectory, assetPath.replace(/^\/+/, ""));
2922
+ return join7(buildDirectory, assetPath.replace(/^\/+/, ""));
1851
2923
  };
1852
2924
  var pageFor = async (metadata, manifest, buildDirectory) => {
1853
2925
  const assetPath = manifest[metadata.bundleKey];
@@ -1855,8 +2927,8 @@ var pageFor = async (metadata, manifest, buildDirectory) => {
1855
2927
  throw new TypeError(`Mobile page ${metadata.pageId} references missing manifest asset ${metadata.bundleKey}.`);
1856
2928
  }
1857
2929
  const resolvedAssetPath = resolveAssetPath(buildDirectory, assetPath);
1858
- const bytes = await readFile7(resolvedAssetPath);
1859
- const bundlePath = `/${relative5(resolve7(buildDirectory), resolvedAssetPath).replaceAll("\\", "/")}`;
2930
+ const bytes = await readFile9(resolvedAssetPath);
2931
+ const bundlePath = `/${relative6(resolve8(buildDirectory), resolvedAssetPath).replaceAll("\\", "/")}`;
1860
2932
  return {
1861
2933
  bundleHash: sha256(bytes),
1862
2934
  bundlePath,
@@ -1869,7 +2941,7 @@ var pageFor = async (metadata, manifest, buildDirectory) => {
1869
2941
  var buildAbsoluteMobileCompatibilityRelease = async (options) => {
1870
2942
  const [captured, producerBytes] = await Promise.all([
1871
2943
  captureAbsoluteMobileRouteGraph(options.app),
1872
- readFile7(options.producerPath)
2944
+ readFile9(options.producerPath)
1873
2945
  ]);
1874
2946
  if (captured.length === 0) {
1875
2947
  throw new TypeError("No instrumented AbsoluteJS mobile page routes were found in the finalized Elysia route graph.");
@@ -1949,16 +3021,16 @@ var captureAbsoluteMobileRouteGraph = async (app) => {
1949
3021
 
1950
3022
  // src/mobile/capacitorBundle.ts
1951
3023
  import {
1952
- copyFile as copyFile4,
1953
- mkdir as mkdir6,
3024
+ copyFile as copyFile5,
3025
+ mkdir as mkdir7,
1954
3026
  mkdtemp as mkdtemp4,
1955
- readFile as readFile8,
1956
- rename as rename7,
1957
- rm as rm6,
1958
- writeFile as writeFile7
3027
+ readFile as readFile10,
3028
+ rename as rename8,
3029
+ rm as rm7,
3030
+ writeFile as writeFile8
1959
3031
  } from "fs/promises";
1960
3032
  import { existsSync as existsSync2 } from "fs";
1961
- import { basename, dirname as dirname4, extname, join as join7, resolve as resolve8 } from "path";
3033
+ import { basename as basename2, dirname as dirname5, extname, join as join8, resolve as resolve9 } from "path";
1962
3034
 
1963
3035
  // src/mobile/routeMatcher.ts
1964
3036
  var REGEXP_SPECIAL_CHARACTERS = /[.*+?^${}()|[\]\\]/g;
@@ -2114,14 +3186,14 @@ var envelopeResponse = (response, status) => new Response(JSON.stringify({
2114
3186
  protocol: ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION,
2115
3187
  response
2116
3188
  }), { headers: responseHeaders(), status });
2117
- var isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
3189
+ var isRecord5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2118
3190
  var normalizeJsonValue = (value) => {
2119
3191
  const serialized = JSON.stringify(value);
2120
3192
  if (serialized === undefined) {
2121
3193
  throw new TypeError("Mobile page props must be JSON-serializable.");
2122
3194
  }
2123
3195
  const parsed = JSON.parse(serialized);
2124
- if (!isRecord4(parsed)) {
3196
+ if (!isRecord5(parsed)) {
2125
3197
  throw new TypeError("Mobile page props must serialize to an object.");
2126
3198
  }
2127
3199
  return parsed;
@@ -2246,14 +3318,14 @@ var upgradeReasons = new Set([
2246
3318
  "protocol",
2247
3319
  "runtime"
2248
3320
  ]);
2249
- var isRecord5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
3321
+ var isRecord6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2250
3322
  var isFramework = (value) => typeof value === "string" && frameworks4.has(value);
2251
3323
  var isUpgradeReason = (value) => typeof value === "string" && upgradeReasons.has(value);
2252
3324
  var parsePageResult = (value) => {
2253
3325
  if (typeof value.contract !== "string" || !isFramework(value.framework) || typeof value.pageId !== "string" || typeof value.status !== "number") {
2254
3326
  throw new AbsoluteMobilePageProtocolError("invalid-envelope", "The mobile page response is missing required page metadata.");
2255
3327
  }
2256
- if (!isRecord5(value.props)) {
3328
+ if (!isRecord6(value.props)) {
2257
3329
  throw new AbsoluteMobilePageProtocolError("invalid-props", "The mobile page response must contain an object props value.");
2258
3330
  }
2259
3331
  return {
@@ -2299,7 +3371,7 @@ var activateAbsoluteMobilePage = async (value, options) => {
2299
3371
  };
2300
3372
  };
2301
3373
  var parseAbsoluteMobilePageEnvelope = (value) => {
2302
- if (!isRecord5(value) || !isRecord5(value.response)) {
3374
+ if (!isRecord6(value) || !isRecord6(value.response)) {
2303
3375
  throw new AbsoluteMobilePageProtocolError("invalid-envelope", "The server did not return an AbsoluteJS mobile page envelope.");
2304
3376
  }
2305
3377
  if (value.protocol !== ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION) {
@@ -2392,7 +3464,7 @@ var INDEX_FILE = "index.html";
2392
3464
  var CLIENT_IMPORT_PATTERN = /(?:\bfrom\s*|\bimport\s*\(\s*|\bimport\s*)["'](\/[^"']+)["']/gu;
2393
3465
  var errorHasCode2 = (error, code) => typeof error === "object" && error !== null && Reflect.get(error, "code") === code;
2394
3466
  var shellBootstrapModule = () => {
2395
- const candidate = ["js", "ts"].map((extension) => join7(import.meta.dir, `shellBootstrap.${extension}`)).find(existsSync2);
3467
+ const candidate = ["js", "ts"].map((extension) => join8(import.meta.dir, `shellBootstrap.${extension}`)).find(existsSync2);
2396
3468
  if (candidate)
2397
3469
  return candidate;
2398
3470
  throw new TypeError("AbsoluteJS mobile shell bootstrap module is missing.");
@@ -2413,8 +3485,8 @@ var indexHtml = (appName) => `<!doctype html>
2413
3485
  </html>
2414
3486
  `;
2415
3487
  var sourceAssetPath = (buildDirectory, bundlePath) => {
2416
- const root = resolve8(buildDirectory);
2417
- const asset = resolve8(root, bundlePath.replace(/^\/+/, ""));
3488
+ const root = resolve9(buildDirectory);
3489
+ const asset = resolve9(root, bundlePath.replace(/^\/+/, ""));
2418
3490
  if (!asset.startsWith(`${root}/`)) {
2419
3491
  throw new TypeError("Mobile page bundle escaped the build directory.");
2420
3492
  }
@@ -2422,8 +3494,8 @@ var sourceAssetPath = (buildDirectory, bundlePath) => {
2422
3494
  };
2423
3495
  var buildShellBootstrap = async (staging) => {
2424
3496
  const modulePath = shellBootstrapModule();
2425
- const entryPath = join7(staging, ".absolute-mobile-entry.ts");
2426
- await writeFile7(entryPath, `import { startAbsoluteMobileShell } from ${JSON.stringify(modulePath)};
3497
+ const entryPath = join8(staging, ".absolute-mobile-entry.ts");
3498
+ await writeFile8(entryPath, `import { startAbsoluteMobileShell } from ${JSON.stringify(modulePath)};
2427
3499
  void startAbsoluteMobileShell();
2428
3500
  `);
2429
3501
  const build = await Bun.build({
@@ -2435,31 +3507,31 @@ void startAbsoluteMobileShell();
2435
3507
  if (!build.success || build.outputs.length !== 1) {
2436
3508
  throw new AggregateError(build.logs, "Failed to build the AbsoluteJS Capacitor shell.");
2437
3509
  }
2438
- await rename7(build.outputs[0]?.path ?? "", join7(staging, BOOTSTRAP_FILE));
2439
- await rm6(entryPath, { force: true });
3510
+ await rename8(build.outputs[0]?.path ?? "", join8(staging, BOOTSTRAP_FILE));
3511
+ await rm7(entryPath, { force: true });
2440
3512
  };
2441
3513
  var removePreviousBundle = async (backup, moved) => {
2442
3514
  if (!moved)
2443
3515
  return;
2444
- await rm6(backup, { force: true, recursive: true });
3516
+ await rm7(backup, { force: true, recursive: true });
2445
3517
  };
2446
3518
  var restorePreviousBundle = async (backup, destination, moved) => {
2447
3519
  if (!moved)
2448
3520
  return;
2449
- await rename7(backup, destination);
3521
+ await rename8(backup, destination);
2450
3522
  };
2451
3523
  var installBundle = async (staging, destination) => {
2452
3524
  const backup = `${destination}.previous-${crypto.randomUUID()}`;
2453
3525
  let movedPrevious = false;
2454
3526
  try {
2455
- await rename7(destination, backup);
3527
+ await rename8(destination, backup);
2456
3528
  movedPrevious = true;
2457
3529
  } catch (error) {
2458
3530
  if (!errorHasCode2(error, "ENOENT"))
2459
3531
  throw error;
2460
3532
  }
2461
3533
  try {
2462
- await rename7(staging, destination);
3534
+ await rename8(staging, destination);
2463
3535
  await removePreviousBundle(backup, movedPrevious);
2464
3536
  } catch (error) {
2465
3537
  await restorePreviousBundle(backup, destination, movedPrevious);
@@ -2473,12 +3545,12 @@ var copyClientPage = async (page, buildDirectory, staging, copiedDependencies) =
2473
3545
  const extension = extname(page.bundlePath) || ".js";
2474
3546
  const localBundlePath = `./pages/${page.bundleHash}${extension}`;
2475
3547
  const source = sourceAssetPath(buildDirectory, page.bundlePath);
2476
- await copyFile4(source, join7(staging, localBundlePath));
3548
+ await copyFile5(source, join8(staging, localBundlePath));
2477
3549
  await copyAbsoluteClientDependencies(source, buildDirectory, staging, copiedDependencies);
2478
3550
  return { ...page, localBundlePath };
2479
3551
  };
2480
3552
  var absoluteClientImports = async (sourcePath) => {
2481
- const source = await readFile8(sourcePath, "utf8");
3553
+ const source = await readFile10(sourcePath, "utf8");
2482
3554
  return [...source.matchAll(CLIENT_IMPORT_PATTERN)].flatMap((match) => {
2483
3555
  const [specifier] = match.slice(1);
2484
3556
  return specifier ? [specifier.split(/[?#]/u, 1)[0] ?? specifier] : [];
@@ -2489,9 +3561,9 @@ var copyAbsoluteClientDependency = async (specifier, buildDirectory, staging, co
2489
3561
  return;
2490
3562
  copied.add(specifier);
2491
3563
  const source = sourceAssetPath(buildDirectory, specifier);
2492
- const destination = join7(staging, specifier.replace(/^\/+/, ""));
2493
- await mkdir6(dirname4(destination), { recursive: true });
2494
- await copyFile4(source, destination);
3564
+ const destination = join8(staging, specifier.replace(/^\/+/, ""));
3565
+ await mkdir7(dirname5(destination), { recursive: true });
3566
+ await copyFile5(source, destination);
2495
3567
  await copyAbsoluteClientDependencies(source, buildDirectory, staging, copied);
2496
3568
  };
2497
3569
  var copyAbsoluteClientDependencies = async (sourcePath, buildDirectory, staging, copied) => {
@@ -2503,11 +3575,11 @@ var materializeAbsoluteCapacitorWebBundle = async (options) => {
2503
3575
  throw new TypeError(`mobile.entry ${options.config.entry} is not a captured mobile page route.`);
2504
3576
  }
2505
3577
  const destination = options.config.bundleDirectory;
2506
- await mkdir6(dirname4(destination), { recursive: true });
2507
- const staging = await mkdtemp4(join7(dirname4(destination), `.${basename(destination)}.stage-`));
3578
+ await mkdir7(dirname5(destination), { recursive: true });
3579
+ const staging = await mkdtemp4(join8(dirname5(destination), `.${basename2(destination)}.stage-`));
2508
3580
  try {
2509
- const pageDirectory = join7(staging, "pages");
2510
- await mkdir6(pageDirectory, { recursive: true });
3581
+ const pageDirectory = join8(staging, "pages");
3582
+ await mkdir7(pageDirectory, { recursive: true });
2511
3583
  const copiedDependencies = new Set;
2512
3584
  const pages = await Promise.all(options.artifact.pages.map((page) => copyClientPage(page, options.buildDirectory, staging, copiedDependencies)));
2513
3585
  const manifest = {
@@ -2524,48 +3596,48 @@ var materializeAbsoluteCapacitorWebBundle = async (options) => {
2524
3596
  runtime: options.artifact.runtime
2525
3597
  };
2526
3598
  await Promise.all([
2527
- writeFile7(join7(staging, MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
3599
+ writeFile8(join8(staging, MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
2528
3600
  `),
2529
- writeFile7(join7(staging, INDEX_FILE), indexHtml(options.config.appName)),
3601
+ writeFile8(join8(staging, INDEX_FILE), indexHtml(options.config.appName)),
2530
3602
  buildShellBootstrap(staging)
2531
3603
  ]);
2532
3604
  await installBundle(staging, destination);
2533
3605
  return manifest;
2534
3606
  } catch (error) {
2535
- await rm6(staging, { force: true, recursive: true });
3607
+ await rm7(staging, { force: true, recursive: true });
2536
3608
  throw error;
2537
3609
  }
2538
3610
  };
2539
3611
 
2540
3612
  // src/mobile/materializedBundle.ts
2541
- import { createHash as createHash7 } from "crypto";
3613
+ import { createHash as createHash8 } from "crypto";
2542
3614
  import {
2543
- access as access6,
2544
- mkdir as mkdir7,
3615
+ access as access8,
3616
+ mkdir as mkdir8,
2545
3617
  mkdtemp as mkdtemp5,
2546
- readFile as readFile9,
2547
- rename as rename8,
2548
- rm as rm7,
2549
- writeFile as writeFile8
3618
+ readFile as readFile11,
3619
+ rename as rename9,
3620
+ rm as rm8,
3621
+ writeFile as writeFile9
2550
3622
  } from "fs/promises";
2551
- import { dirname as dirname5, join as join8, resolve as resolvePath2 } from "path";
3623
+ import { dirname as dirname6, join as join9, resolve as resolvePath2 } from "path";
2552
3624
  import { pathToFileURL } from "url";
2553
3625
  var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1;
2554
3626
  var CURRENT_BUNDLE_FILE = "current.json";
2555
3627
  var BUNDLES_DIRECTORY = "bundles";
2556
3628
  var ARTIFACT_FILE2 = "artifact.json";
2557
3629
  var BUNDLE_ID_PATTERN = /^amb_[a-f0-9]{64}$/;
2558
- var isRecord6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
3630
+ var isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2559
3631
  var errorHasCode3 = (error, code) => typeof error === "object" && error !== null && Reflect.get(error, "code") === code;
2560
3632
  var bundleIdFor = (currentReleaseId, releases) => {
2561
3633
  const identity = JSON.stringify({
2562
3634
  currentReleaseId,
2563
3635
  releases: releases.map(({ releaseId }) => releaseId)
2564
3636
  });
2565
- return `amb_${createHash7("sha256").update(identity).digest("hex")}`;
3637
+ return `amb_${createHash8("sha256").update(identity).digest("hex")}`;
2566
3638
  };
2567
3639
  var parseBundleIndex = (value) => {
2568
- if (!isRecord6(value) || value.format !== ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT || typeof value.bundleId !== "string" || !BUNDLE_ID_PATTERN.test(value.bundleId) || typeof value.currentReleaseId !== "string" || !Array.isArray(value.releases)) {
3640
+ if (!isRecord7(value) || value.format !== ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT || typeof value.bundleId !== "string" || !BUNDLE_ID_PATTERN.test(value.bundleId) || typeof value.currentReleaseId !== "string" || !Array.isArray(value.releases)) {
2569
3641
  throw new TypeError("Invalid materialized mobile compatibility bundle.");
2570
3642
  }
2571
3643
  const releases = value.releases.map(parseAbsoluteMobileCompatibilityArtifact);
@@ -2588,30 +3660,30 @@ var parseBundleIndex = (value) => {
2588
3660
  };
2589
3661
  };
2590
3662
  var writeRelease = async (root, release) => {
2591
- const directory = join8(root, release.artifact.releaseId);
2592
- const producerPath = join8(directory, release.artifact.producer.module);
2593
- await mkdir7(dirname5(producerPath), { recursive: true });
3663
+ const directory = join9(root, release.artifact.releaseId);
3664
+ const producerPath = join9(directory, release.artifact.producer.module);
3665
+ await mkdir8(dirname6(producerPath), { recursive: true });
2594
3666
  await Promise.all([
2595
- writeFile8(join8(directory, ARTIFACT_FILE2), `${JSON.stringify(release.artifact, null, "\t")}
3667
+ writeFile9(join9(directory, ARTIFACT_FILE2), `${JSON.stringify(release.artifact, null, "\t")}
2596
3668
  `),
2597
- writeFile8(producerPath, new Uint8Array(await release.producer.arrayBuffer()))
3669
+ writeFile9(producerPath, new Uint8Array(await release.producer.arrayBuffer()))
2598
3670
  ]);
2599
3671
  };
2600
3672
  var installImmutableBundle = async (bundlesRoot, bundleId, releases) => {
2601
- const destination = join8(bundlesRoot, bundleId);
3673
+ const destination = join9(bundlesRoot, bundleId);
2602
3674
  try {
2603
- await access6(destination);
3675
+ await access8(destination);
2604
3676
  return destination;
2605
3677
  } catch (error) {
2606
3678
  if (!errorHasCode3(error, "ENOENT"))
2607
3679
  throw error;
2608
3680
  }
2609
- const staging = await mkdtemp5(join8(bundlesRoot, ".stage-"));
3681
+ const staging = await mkdtemp5(join9(bundlesRoot, ".stage-"));
2610
3682
  try {
2611
3683
  await Promise.all(releases.map((release) => writeRelease(staging, release)));
2612
- await rename8(staging, destination);
3684
+ await rename9(staging, destination);
2613
3685
  } catch (error) {
2614
- await rm7(staging, { force: true, recursive: true });
3686
+ await rm8(staging, { force: true, recursive: true });
2615
3687
  if (errorHasCode3(error, "EEXIST") || errorHasCode3(error, "ENOTEMPTY")) {
2616
3688
  return destination;
2617
3689
  }
@@ -2622,7 +3694,7 @@ var installImmutableBundle = async (bundlesRoot, bundleId, releases) => {
2622
3694
  var readCompatibilityModule = (modulePath) => import(pathToFileURL(modulePath).href);
2623
3695
  var resolveProducerHandler = (loaded, exportName) => {
2624
3696
  const value = loaded[exportName];
2625
- if (!isRecord6(value) || typeof value.handle !== "function") {
3697
+ if (!isRecord7(value) || typeof value.handle !== "function") {
2626
3698
  throw new TypeError(`Compatibility producer export ${exportName} must expose handle(request).`);
2627
3699
  }
2628
3700
  const { handle } = value;
@@ -2640,15 +3712,15 @@ var resolveProducerHandler = (loaded, exportName) => {
2640
3712
  };
2641
3713
  var loadAbsoluteMobileMaterializedBundle = async (root) => {
2642
3714
  const resolvedRoot = resolvePath2(root);
2643
- const serialized = await readFile9(join8(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
3715
+ const serialized = await readFile11(join9(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
2644
3716
  const parsed = JSON.parse(serialized);
2645
3717
  const index = parseBundleIndex(parsed);
2646
- const bundleRoot = join8(resolvedRoot, BUNDLES_DIRECTORY, index.bundleId);
3718
+ const bundleRoot = join9(resolvedRoot, BUNDLES_DIRECTORY, index.bundleId);
2647
3719
  return {
2648
3720
  artifacts: index.releases,
2649
3721
  currentReleaseId: index.currentReleaseId,
2650
3722
  loadProducer: async (artifact) => {
2651
- const modulePath = join8(bundleRoot, artifact.releaseId, artifact.producer.module);
3723
+ const modulePath = join9(bundleRoot, artifact.releaseId, artifact.producer.module);
2652
3724
  await verifyAbsoluteMobileCompatibilityProducer({
2653
3725
  artifact,
2654
3726
  producer: Bun.file(modulePath)
@@ -2675,8 +3747,8 @@ var materializeAbsoluteMobileCompatibilityBundle = async (input) => {
2675
3747
  return release;
2676
3748
  });
2677
3749
  const root = resolvePath2(input.root);
2678
- const bundlesRoot = join8(root, BUNDLES_DIRECTORY);
2679
- await mkdir7(bundlesRoot, { recursive: true });
3750
+ const bundlesRoot = join9(root, BUNDLES_DIRECTORY);
3751
+ await mkdir8(bundlesRoot, { recursive: true });
2680
3752
  const bundleId = bundleIdFor(input.currentReleaseId, artifacts);
2681
3753
  await installImmutableBundle(bundlesRoot, bundleId, orderedReleases);
2682
3754
  const index = {
@@ -2685,22 +3757,22 @@ var materializeAbsoluteMobileCompatibilityBundle = async (input) => {
2685
3757
  format: ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT,
2686
3758
  releases: artifacts
2687
3759
  };
2688
- const pointerPath = join8(root, CURRENT_BUNDLE_FILE);
2689
- const temporaryPointerPath = join8(root, `.current-${crypto.randomUUID()}.json`);
2690
- await writeFile8(temporaryPointerPath, `${JSON.stringify(index, null, "\t")}
3760
+ const pointerPath = join9(root, CURRENT_BUNDLE_FILE);
3761
+ const temporaryPointerPath = join9(root, `.current-${crypto.randomUUID()}.json`);
3762
+ await writeFile9(temporaryPointerPath, `${JSON.stringify(index, null, "\t")}
2691
3763
  `, { flag: "wx" });
2692
- await rename8(temporaryPointerPath, pointerPath);
3764
+ await rename9(temporaryPointerPath, pointerPath);
2693
3765
  return index;
2694
3766
  };
2695
3767
  var readAbsoluteMobileMaterializedReleases = async (root) => {
2696
3768
  const resolvedRoot = resolvePath2(root);
2697
3769
  try {
2698
- const serialized = await readFile9(join8(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
3770
+ const serialized = await readFile11(join9(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
2699
3771
  const parsed = JSON.parse(serialized);
2700
3772
  const index = parseBundleIndex(parsed);
2701
- const bundleRoot = join8(resolvedRoot, BUNDLES_DIRECTORY, index.bundleId);
3773
+ const bundleRoot = join9(resolvedRoot, BUNDLES_DIRECTORY, index.bundleId);
2702
3774
  return Promise.all(index.releases.map(async (artifact) => {
2703
- const producer = Bun.file(join8(bundleRoot, artifact.releaseId, artifact.producer.module));
3775
+ const producer = Bun.file(join9(bundleRoot, artifact.releaseId, artifact.producer.module));
2704
3776
  await verifyAbsoluteMobileCompatibilityProducer({
2705
3777
  artifact,
2706
3778
  producer
@@ -2749,11 +3821,11 @@ var loadServerApp = async (producerPath) => {
2749
3821
  return { app, exportName };
2750
3822
  };
2751
3823
  var finalizeAbsoluteMobileCompatibilityBuild = async (options) => {
2752
- const buildDirectory = resolve9(options.buildDirectory);
3824
+ const buildDirectory = resolve10(options.buildDirectory);
2753
3825
  const mobile = normalizeAbsoluteMobileConfig(options.mobile, options.projectRoot);
2754
- const root = join9(buildDirectory, ".absolutejs", "mobile-compatibility");
3826
+ const root = join10(buildDirectory, ".absolutejs", "mobile-compatibility");
2755
3827
  const [manifestSource, previous] = await Promise.all([
2756
- readFile10(join9(buildDirectory, "manifest.json"), "utf8"),
3828
+ readFile12(join10(buildDirectory, "manifest.json"), "utf8"),
2757
3829
  readAbsoluteMobileMaterializedReleases(root)
2758
3830
  ]);
2759
3831
  const manifest = JSON.parse(manifestSource);
@@ -2764,7 +3836,7 @@ var finalizeAbsoluteMobileCompatibilityBuild = async (options) => {
2764
3836
  process.env.ABSOLUTE_BUILD_DIR = buildDirectory;
2765
3837
  let loaded;
2766
3838
  try {
2767
- loaded = await loadServerApp(resolve9(options.producerPath));
3839
+ loaded = await loadServerApp(resolve10(options.producerPath));
2768
3840
  } finally {
2769
3841
  restoreBuildDirectory(previousBuildDirectory);
2770
3842
  }
@@ -2775,7 +3847,7 @@ var finalizeAbsoluteMobileCompatibilityBuild = async (options) => {
2775
3847
  manifest,
2776
3848
  previousArtifacts: previous.map(({ artifact }) => artifact),
2777
3849
  producerExport: loaded.exportName,
2778
- producerPath: resolve9(options.producerPath),
3850
+ producerPath: resolve10(options.producerPath),
2779
3851
  runtime: String(ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION)
2780
3852
  });
2781
3853
  const releasesById = new Map([current, ...previous].map((release) => [
@@ -2869,20 +3941,20 @@ var createAbsoluteMobileCompatibilityDispatcher = (options) => {
2869
3941
  }).as("global");
2870
3942
  };
2871
3943
  // src/mobile/nativeDeepLinks.ts
2872
- import { readFile as readFile11, rename as rename9, writeFile as writeFile9 } from "fs/promises";
2873
- import { join as join10 } from "path";
3944
+ import { readFile as readFile13, rename as rename10, writeFile as writeFile10 } from "fs/promises";
3945
+ import { join as join11 } from "path";
2874
3946
  var START_MARKER = "<!-- absolutejs:deep-links:start -->";
2875
3947
  var END_MARKER = "<!-- absolutejs:deep-links:end -->";
2876
3948
  var IOS_ENTITLEMENTS = "App/AbsoluteJS.entitlements";
2877
3949
  var NOT_FOUND = -1;
2878
3950
  var escapeXml = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
2879
3951
  var writeChangedFile = async (path, source) => {
2880
- const current = await readFile11(path, "utf8");
3952
+ const current = await readFile13(path, "utf8");
2881
3953
  if (current === source)
2882
3954
  return false;
2883
3955
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
2884
- await writeFile9(temporary, source, { flag: "wx" });
2885
- await rename9(temporary, path);
3956
+ await writeFile10(temporary, source, { flag: "wx" });
3957
+ await rename10(temporary, path);
2886
3958
  return true;
2887
3959
  };
2888
3960
  var replaceManagedRegion = (source, region, insertAt) => {
@@ -2927,8 +3999,8 @@ ${hosts}
2927
3999
  `;
2928
4000
  };
2929
4001
  var configureAndroid = async (config) => {
2930
- const path = join10(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
2931
- const source = await readFile11(path, "utf8");
4002
+ const path = join11(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
4003
+ const source = await readFile13(path, "utf8");
2932
4004
  const mainActivity = source.indexOf('android:name=".MainActivity"');
2933
4005
  if (mainActivity === NOT_FOUND) {
2934
4006
  throw new TypeError("Android MainActivity was not found.");
@@ -2953,8 +4025,8 @@ var iosSchemeRegion = (scheme) => ` ${START_MARKER}
2953
4025
  ${END_MARKER}
2954
4026
  `;
2955
4027
  var configureIosInfo = async (config) => {
2956
- const path = join10(config.nativeProjectDirectory, "ios/App/App/Info.plist");
2957
- const source = await readFile11(path, "utf8");
4028
+ const path = join11(config.nativeProjectDirectory, "ios/App/App/Info.plist");
4029
+ const source = await readFile13(path, "utf8");
2958
4030
  const region = config.deepLinkScheme ? iosSchemeRegion(config.deepLinkScheme) : ` ${START_MARKER}
2959
4031
  ${END_MARKER}
2960
4032
  `;
@@ -2977,10 +4049,10 @@ ${domains}
2977
4049
  `;
2978
4050
  };
2979
4051
  var configureIosEntitlements = async (config) => {
2980
- const path = join10(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
4052
+ const path = join11(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
2981
4053
  let current = "";
2982
4054
  try {
2983
- current = await readFile11(path, "utf8");
4055
+ current = await readFile13(path, "utf8");
2984
4056
  } catch (error) {
2985
4057
  if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
2986
4058
  throw error;
@@ -2990,13 +4062,13 @@ var configureIosEntitlements = async (config) => {
2990
4062
  if (current === source)
2991
4063
  return false;
2992
4064
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
2993
- await writeFile9(temporary, source, { flag: "wx" });
2994
- await rename9(temporary, path);
4065
+ await writeFile10(temporary, source, { flag: "wx" });
4066
+ await rename10(temporary, path);
2995
4067
  return true;
2996
4068
  };
2997
4069
  var configureIosProject = async (config) => {
2998
- const path = join10(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
2999
- const source = await readFile11(path, "utf8");
4070
+ const path = join11(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
4071
+ const source = await readFile13(path, "utf8");
3000
4072
  const declarations = [
3001
4073
  ...source.matchAll(/CODE_SIGN_ENTITLEMENTS = ([^;]+);/g)
3002
4074
  ].map((match) => match[1]);
@@ -3034,8 +4106,8 @@ var applyAbsoluteNativeDeepLinks = async (config, platforms = config.platforms)
3034
4106
  };
3035
4107
  };
3036
4108
  // src/mobile/releasePublisher.ts
3037
- import { access as access7 } from "fs/promises";
3038
- import { isAbsolute as isAbsolute4, relative as relative6, resolve as resolve10, sep as sep4 } from "path";
4109
+ import { access as access9 } from "fs/promises";
4110
+ import { isAbsolute as isAbsolute5, relative as relative7, resolve as resolve11, sep as sep5 } from "path";
3039
4111
  import { pathToFileURL as pathToFileURL3 } from "url";
3040
4112
  var prepareAbsoluteIosRelease = async (publisher, options) => {
3041
4113
  if (typeof publisher.prepareIosRelease !== "function") {
@@ -3058,24 +4130,24 @@ var prepareAbsoluteAndroidRelease = async (publisher, options) => {
3058
4130
  }
3059
4131
  return versionCode;
3060
4132
  };
3061
- var isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
3062
- var isPublisher = (value) => isRecord7(value) && typeof value.publish === "function";
4133
+ var isRecord8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
4134
+ var isPublisher = (value) => isRecord8(value) && typeof value.publish === "function";
3063
4135
  var publisherModulePath = (projectRoot, requested) => {
3064
- const root = resolve10(projectRoot);
3065
- const path = resolve10(root, requested);
3066
- const projectRelative = relative6(root, path);
3067
- if (projectRelative === ".." || projectRelative.startsWith(`..${sep4}`) || isAbsolute4(projectRelative)) {
4136
+ const root = resolve11(projectRoot);
4137
+ const path = resolve11(root, requested);
4138
+ const projectRelative = relative7(root, path);
4139
+ if (projectRelative === ".." || projectRelative.startsWith(`..${sep5}`) || isAbsolute5(projectRelative)) {
3068
4140
  throw new TypeError("mobile publish --registry must remain inside the project.");
3069
4141
  }
3070
4142
  return path;
3071
4143
  };
3072
4144
  var loadAbsoluteNativeReleasePublisher = async (projectRoot, requestedModulePath) => {
3073
4145
  const modulePath = publisherModulePath(projectRoot, requestedModulePath);
3074
- await access7(modulePath).catch(() => {
4146
+ await access9(modulePath).catch(() => {
3075
4147
  throw new TypeError(`Native release registry module does not exist: ${modulePath}`);
3076
4148
  });
3077
4149
  const loaded = await import(pathToFileURL3(modulePath).href);
3078
- const publisher = isRecord7(loaded) ? loaded.default ?? loaded.registry : undefined;
4150
+ const publisher = isRecord8(loaded) ? loaded.default ?? loaded.registry : undefined;
3079
4151
  if (!isPublisher(publisher)) {
3080
4152
  throw new TypeError("Native release registry module must default-export a registry with publish(options).");
3081
4153
  }
@@ -3133,13 +4205,13 @@ var publishAbsoluteIosRelease = async (options) => {
3133
4205
  };
3134
4206
  // src/mobile/routeMetadataTransform.ts
3135
4207
  import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
3136
- import { dirname as dirname6, extname as extname2, relative as relative7, resolve as resolve11 } from "path";
4208
+ import { dirname as dirname7, extname as extname2, relative as relative8, resolve as resolve12 } from "path";
3137
4209
  import ts from "typescript";
3138
4210
  var ROUTE_METHODS = new Set(["get", "head"]);
3139
4211
  var SOURCE_FILTER = /\.[cm]?[jt]sx?$/;
3140
4212
  var PAGE_HANDLER = "handleReactPageRequest";
3141
4213
  var posixPath = (value) => value.replace(/\\/g, "/");
3142
- var findTsconfig = (entry, projectRoot) => ts.findConfigFile(dirname6(entry), existsSync3, "tsconfig.json") ?? ts.findConfigFile(projectRoot, existsSync3, "tsconfig.json");
4214
+ var findTsconfig = (entry, projectRoot) => ts.findConfigFile(dirname7(entry), existsSync3, "tsconfig.json") ?? ts.findConfigFile(projectRoot, existsSync3, "tsconfig.json");
3143
4215
  var createProgram = (entry, projectRoot) => {
3144
4216
  const configPath = findTsconfig(entry, projectRoot);
3145
4217
  if (!configPath) {
@@ -3151,7 +4223,7 @@ var createProgram = (entry, projectRoot) => {
3151
4223
  target: ts.ScriptTarget.ESNext
3152
4224
  });
3153
4225
  }
3154
- const parsed = ts.parseJsonConfigFileContent(ts.readConfigFile(configPath, (path) => readFileSync2(path, "utf8")).config, ts.sys, dirname6(configPath));
4226
+ const parsed = ts.parseJsonConfigFileContent(ts.readConfigFile(configPath, (path) => readFileSync2(path, "utf8")).config, ts.sys, dirname7(configPath));
3155
4227
  if (!parsed.fileNames.includes(entry))
3156
4228
  parsed.fileNames.push(entry);
3157
4229
  return ts.createProgram(parsed.fileNames, parsed.options);
@@ -3257,7 +4329,7 @@ var resolvePageIdentity = (expression, sourceFile, checker, projectRoot) => {
3257
4329
  const declaration = symbol?.declarations?.[0];
3258
4330
  const file = declaration?.getSourceFile().fileName ?? sourceFile.fileName;
3259
4331
  const exportedName = symbol?.name ?? expression.getText(sourceFile);
3260
- const source = posixPath(relative7(projectRoot, file));
4332
+ const source = posixPath(relative8(projectRoot, file));
3261
4333
  return `${source}#${exportedName}`;
3262
4334
  };
3263
4335
  var resolveAlias = (symbol, checker) => {
@@ -3364,7 +4436,7 @@ var analyzeProgram = (program, projectRoot) => {
3364
4436
  const checker = program.getTypeChecker();
3365
4437
  const analyzed = new Map;
3366
4438
  for (const sourceFile of program.getSourceFiles()) {
3367
- const resolvedFile = resolve11(sourceFile.fileName);
4439
+ const resolvedFile = resolve12(sourceFile.fileName);
3368
4440
  if (!isProjectSource(sourceFile, resolvedFile, projectRoot))
3369
4441
  continue;
3370
4442
  const analysis = analyzeSourceFile(sourceFile, checker, projectRoot);
@@ -3447,14 +4519,14 @@ var transformFile = (source, fileName, analysis) => {
3447
4519
  };
3448
4520
  var ABSOLUTE_MOBILE_TRANSFORM_PROTOCOL = ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION;
3449
4521
  var createAbsoluteMobileRouteMetadataPlugin = (options) => {
3450
- const projectRoot = resolve11(options.projectRoot ?? process.cwd());
3451
- const entry = resolve11(options.entry);
4522
+ const projectRoot = resolve12(options.projectRoot ?? process.cwd());
4523
+ const entry = resolve12(options.entry);
3452
4524
  const analyzed = analyzeProgram(createProgram(entry, projectRoot), projectRoot);
3453
4525
  return {
3454
4526
  name: "absolute-mobile-route-metadata",
3455
4527
  setup(build) {
3456
4528
  build.onLoad({ filter: SOURCE_FILTER }, async ({ path }) => {
3457
- const analysis = analyzed.get(resolve11(path));
4529
+ const analysis = analyzed.get(resolve12(path));
3458
4530
  if (!analysis)
3459
4531
  return;
3460
4532
  const source = await Bun.file(path).text();
@@ -3467,32 +4539,42 @@ var createAbsoluteMobileRouteMetadataPlugin = (options) => {
3467
4539
  };
3468
4540
  };
3469
4541
  var inspectAbsoluteMobileRouteMetadata = (options) => {
3470
- const projectRoot = resolve11(options.projectRoot ?? process.cwd());
3471
- const entry = resolve11(options.entry);
4542
+ const projectRoot = resolve12(options.projectRoot ?? process.cwd());
4543
+ const entry = resolve12(options.entry);
3472
4544
  const analyzed = analyzeProgram(createProgram(entry, projectRoot), projectRoot);
3473
4545
  return [...analyzed.entries()].flatMap(([file, analysis]) => [...analysis.byRouteCall.values()].map(({ metadata }) => ({
3474
- file: posixPath(relative7(projectRoot, file)),
4546
+ file: posixPath(relative8(projectRoot, file)),
3475
4547
  metadata
3476
4548
  })));
3477
4549
  };
3478
4550
  export {
3479
4551
  writeAbsoluteCapacitorConfig,
4552
+ waitForAbsoluteIosHmrLog,
3480
4553
  verifyAbsoluteMobileCompatibilityProducer,
3481
4554
  verifyAbsoluteMobileAssociationFiles,
4555
+ startAbsoluteIosDevSession,
3482
4556
  runWithAbsoluteMobileProducer,
3483
4557
  retainAbsoluteMobileCompatibilityArtifacts,
3484
4558
  resolveAbsoluteMobileRoute,
3485
4559
  resolveAbsoluteMobileDeepLink,
3486
4560
  resolveAbsoluteMobileCompatibilityRelease,
4561
+ repairAbsoluteIosDevSession,
4562
+ redactAbsoluteIosLog,
3487
4563
  readAbsoluteMobileMaterializedReleases,
3488
4564
  publishAbsoluteIosRelease,
3489
4565
  publishAbsoluteAndroidRelease,
3490
4566
  prepareAbsoluteIosRelease,
4567
+ prepareAbsoluteIosDevProject,
3491
4568
  prepareAbsoluteAndroidRelease,
4569
+ parseIosSimulators,
4570
+ parseIosRuntimes,
4571
+ parseIosDeviceTypes,
3492
4572
  parseAbsoluteMobilePageRequest,
3493
4573
  parseAbsoluteMobilePageEnvelope,
3494
4574
  parseAbsoluteMobileCompatibilityArtifact,
3495
4575
  parseAbsoluteMobileBuildPageMetadata,
4576
+ parseAbsoluteIosLogLine,
4577
+ parseAbsoluteIosHmrLog,
3496
4578
  normalizeAbsoluteMobileConfig,
3497
4579
  navigateAbsoluteMobilePage,
3498
4580
  materializeAbsoluteMobileCompatibilityBundle,
@@ -3501,10 +4583,12 @@ export {
3501
4583
  matchesAbsoluteMobileRoutePattern,
3502
4584
  loadAbsoluteNativeReleasePublisher,
3503
4585
  loadAbsoluteMobileMaterializedBundle,
4586
+ isAbsoluteIosNativeRootInput,
3504
4587
  inspectAbsoluteMobileRouteMetadata,
3505
4588
  hashAbsoluteMobilePropsSchema,
3506
4589
  getCurrentAbsoluteMobileProducerContext,
3507
4590
  fingerprintAbsoluteIosNativeProject,
4591
+ fingerprintAbsoluteIosDevProject,
3508
4592
  finalizeAbsoluteMobilePage,
3509
4593
  finalizeAbsoluteMobileCompatibilityBuild,
3510
4594
  fetchAbsoluteMobilePage,
@@ -3519,6 +4603,7 @@ export {
3519
4603
  createAbsoluteMobileBlobArtifactStore,
3520
4604
  createAbsoluteMobileAssociationPlugin,
3521
4605
  createAbsoluteMobileAssociationDocuments,
4606
+ createAbsoluteIosNativeWatcher,
3522
4607
  carryForwardAbsoluteMobileCompatibilityReleases,
3523
4608
  captureAbsoluteMobileRouteGraph,
3524
4609
  buildAbsoluteMobileCompatibilityRelease,
@@ -3539,9 +4624,10 @@ export {
3539
4624
  ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT,
3540
4625
  ABSOLUTE_MOBILE_COMPATIBILITY_FORMAT,
3541
4626
  ABSOLUTE_MOBILE_CLIENT_MANIFEST_FORMAT,
4627
+ ABSOLUTE_IOS_SIMULATOR_NAME,
3542
4628
  ABSOLUTE_IOS_RELEASE_FORMAT,
3543
4629
  ABSOLUTE_ANDROID_RELEASE_FORMAT
3544
4630
  };
3545
4631
 
3546
- //# debugId=8F6E00755BF98A2E64756E2164756E21
4632
+ //# debugId=048422942BB9C32864756E2164756E21
3547
4633
  //# sourceMappingURL=index.js.map