@absolutejs/absolute 0.20.0-beta.100 → 0.20.0-beta.102

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.
@@ -611,11 +611,11 @@ __export(exports_config, {
611
611
  normalizeAbsoluteMobileConfig: () => normalizeAbsoluteMobileConfig
612
612
  });
613
613
  import { readFileSync as readFileSync2 } from "fs";
614
- import { resolve as resolve6 } from "path";
615
- import { createHash as createHash8, createPublicKey, X509Certificate as X509Certificate2 } from "crypto";
614
+ import { resolve as resolve7 } from "path";
615
+ import { createHash as createHash9, createPublicKey, X509Certificate as X509Certificate2 } from "crypto";
616
616
  var APP_ID_PATTERN, SCHEME_PATTERN, APPLE_APP_ID_PREFIX_PATTERN, CERTIFICATE_FINGERPRINT_PATTERN, UPDATE_NAME_PATTERN, UPDATE_PUBLIC_KEY_PATTERN, ENVIRONMENT_NAME_PATTERN, DEFAULT_UPDATE_BOOT_TIMEOUT_MS = 20000, DEFAULT_UPDATE_HEALTH_FAILURE_RATE = 0.2, DEFAULT_UPDATE_HEALTH_MINIMUM_REPORTS = 20, DEFAULT_UPDATE_ROLLOUT_FAILURE_RATE = 0.05, DEFAULT_UPDATE_ROLLOUT_OBSERVATION_MINUTES = 60, MINUTE_MS, DEFAULT_UPDATE_ROLLOUT_STAGES, MINIMUM_UPDATE_BOOT_TIMEOUT_MS = 5000, MAXIMUM_UPDATE_BOOT_TIMEOUT_MS = 120000, HOSTNAME_PATTERN, EXPO_RESERVED_ROUTE_PREFIXES, resolveProjectPath = (projectRoot, value, field2) => {
617
- const root = resolve6(projectRoot);
618
- const path = resolve6(root, value);
617
+ const root = resolve7(projectRoot);
618
+ const path = resolve7(root, value);
619
619
  if (path !== root && !path.startsWith(`${root}/`)) {
620
620
  throw new TypeError(`${field2} must remain inside the project root.`);
621
621
  }
@@ -787,7 +787,7 @@ var APP_ID_PATTERN, SCHEME_PATTERN, APPLE_APP_ID_PREFIX_PATTERN, CERTIFICATE_FIN
787
787
  expoCodeSigning = {
788
788
  algorithm: "rsa-v1_5-sha256",
789
789
  certificatePem,
790
- certificateSha256: createHash8("sha256").update(certificate.raw).digest("hex"),
790
+ certificateSha256: createHash9("sha256").update(certificate.raw).digest("hex"),
791
791
  keyId
792
792
  };
793
793
  }
@@ -1017,14 +1017,14 @@ __export(exports_associationFiles, {
1017
1017
  verifyAbsoluteMobileAssociationFiles: () => verifyAbsoluteMobileAssociationFiles
1018
1018
  });
1019
1019
  import {
1020
- access as access8,
1021
- mkdir as mkdir7,
1022
- readFile as readFile10,
1023
- rename as rename8,
1024
- rm as rm7,
1025
- writeFile as writeFile8
1020
+ access as access9,
1021
+ mkdir as mkdir8,
1022
+ readFile as readFile11,
1023
+ rename as rename9,
1024
+ rm as rm8,
1025
+ writeFile as writeFile9
1026
1026
  } from "fs/promises";
1027
- import { resolve as resolve7 } from "path";
1027
+ import { resolve as resolve8 } from "path";
1028
1028
  import { Elysia } from "elysia";
1029
1029
  var JSON_HEADERS, OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_OK = 200, VERIFY_TIMEOUT_MS = 1e4, ANDROID_ASSOCIATION_PATH = "/.well-known/assetlinks.json", APPLE_ASSOCIATION_PATH = "/.well-known/apple-app-site-association", missingIdentity = (field2, platform2) => new TypeError(`${field2} is required to publish ${platform2} deep-link association files.`), createAppleDocument = (config, requireAll) => {
1030
1030
  if (!config.platforms.includes("ios"))
@@ -1091,7 +1091,7 @@ var JSON_HEADERS, OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_
1091
1091
  }, writeAtomic = async (path, source) => {
1092
1092
  let current;
1093
1093
  try {
1094
- current = await readFile10(path, "utf8");
1094
+ current = await readFile11(path, "utf8");
1095
1095
  } catch (error) {
1096
1096
  if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
1097
1097
  throw error;
@@ -1100,21 +1100,21 @@ var JSON_HEADERS, OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_
1100
1100
  if (current === source)
1101
1101
  return false;
1102
1102
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
1103
- await writeFile8(temporary, source, { flag: "wx" });
1104
- await rename8(temporary, path);
1103
+ await writeFile9(temporary, source, { flag: "wx" });
1104
+ await rename9(temporary, path);
1105
1105
  return true;
1106
- }, exists2 = async (path) => {
1106
+ }, exists3 = async (path) => {
1107
1107
  try {
1108
- await access8(path);
1108
+ await access9(path);
1109
1109
  return true;
1110
1110
  } catch {
1111
1111
  return false;
1112
1112
  }
1113
1113
  }, assertOwnedOutput = async (root) => {
1114
- const path = resolve7(root, OWNERSHIP_FILE);
1114
+ const path = resolve8(root, OWNERSHIP_FILE);
1115
1115
  let ownership;
1116
1116
  try {
1117
- ownership = JSON.parse(await readFile10(path, "utf8"));
1117
+ ownership = JSON.parse(await readFile11(path, "utf8"));
1118
1118
  } catch {
1119
1119
  throw new TypeError(`Association output ${root} already exists and is not owned by AbsoluteJS.`);
1120
1120
  }
@@ -1122,26 +1122,26 @@ var JSON_HEADERS, OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_
1122
1122
  throw new TypeError(`Association output ${root} has an unsupported ownership manifest.`);
1123
1123
  }
1124
1124
  }, publishGeneratedDirectory = async (temporary, root) => {
1125
- const hasCurrent = await exists2(root);
1125
+ const hasCurrent = await exists3(root);
1126
1126
  if (hasCurrent)
1127
1127
  await assertOwnedOutput(root);
1128
1128
  const backup = `${root}.${crypto.randomUUID()}.previous`;
1129
1129
  if (hasCurrent)
1130
- await rename8(root, backup);
1130
+ await rename9(root, backup);
1131
1131
  try {
1132
- await rename8(temporary, root);
1132
+ await rename9(temporary, root);
1133
1133
  } catch (error) {
1134
1134
  if (hasCurrent)
1135
- await rename8(backup, root);
1135
+ await rename9(backup, root);
1136
1136
  throw error;
1137
1137
  }
1138
1138
  if (hasCurrent)
1139
- await rm7(backup, { force: true, recursive: true });
1139
+ await rm8(backup, { force: true, recursive: true });
1140
1140
  }, materializeHost = async (root, host, files) => {
1141
- const directory = resolve7(root, host, ".well-known");
1142
- await mkdir7(directory, { recursive: true });
1141
+ const directory = resolve8(root, host, ".well-known");
1142
+ await mkdir8(directory, { recursive: true });
1143
1143
  return Promise.all(files.map(async ([name, document2]) => {
1144
- const path = resolve7(directory, name);
1144
+ const path = resolve8(directory, name);
1145
1145
  await writeAtomic(path, `${JSON.stringify(document2, null, 2)}
1146
1146
  `);
1147
1147
  return path;
@@ -1164,7 +1164,7 @@ var JSON_HEADERS, OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_
1164
1164
  });
1165
1165
  return endpoints;
1166
1166
  }), materializeAbsoluteMobileAssociationFiles = async (config, outputDirectory) => {
1167
- const root = resolve7(outputDirectory);
1167
+ const root = resolve8(outputDirectory);
1168
1168
  const temporary = `${root}.${crypto.randomUUID()}.tmp`;
1169
1169
  const documents = createAbsoluteMobileAssociationDocuments(config, {
1170
1170
  requireAll: true
@@ -1175,16 +1175,16 @@ var JSON_HEADERS, OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_
1175
1175
  if (documents.apple) {
1176
1176
  files.push(["apple-app-site-association", documents.apple]);
1177
1177
  }
1178
- await mkdir7(temporary, { recursive: true });
1178
+ await mkdir8(temporary, { recursive: true });
1179
1179
  try {
1180
1180
  const temporaryPaths = (await Promise.all(config.deepLinkHosts.map((host) => materializeHost(temporary, host, files)))).flat();
1181
- await writeAtomic(resolve7(temporary, OWNERSHIP_FILE), `${JSON.stringify({ format: 1, hosts: config.deepLinkHosts }, null, 2)}
1181
+ await writeAtomic(resolve8(temporary, OWNERSHIP_FILE), `${JSON.stringify({ format: 1, hosts: config.deepLinkHosts }, null, 2)}
1182
1182
  `);
1183
1183
  await publishGeneratedDirectory(temporary, root);
1184
- const written = temporaryPaths.map((path) => resolve7(root, path.slice(temporary.length + 1)));
1184
+ const written = temporaryPaths.map((path) => resolve8(root, path.slice(temporary.length + 1)));
1185
1185
  return { root, written };
1186
1186
  } catch (error) {
1187
- await rm7(temporary, { force: true, recursive: true });
1187
+ await rm8(temporary, { force: true, recursive: true });
1188
1188
  throw error;
1189
1189
  }
1190
1190
  }, verifyAbsoluteMobileAssociationFiles = async (config, request = globalThis.fetch) => {
@@ -1367,13 +1367,13 @@ var ABSOLUTE_MOBILE_PAGE_MEDIA_TYPE = "application/vnd.absolute.page+json", ABSO
1367
1367
  }, headerVaryValues, envelopeResponse = (response, status) => new Response(JSON.stringify({
1368
1368
  protocol: ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION,
1369
1369
  response
1370
- }), { headers: responseHeaders(), status }), isRecord5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), normalizeJsonValue = (value) => {
1370
+ }), { headers: responseHeaders(), status }), isRecord6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), normalizeJsonValue = (value) => {
1371
1371
  const serialized = JSON.stringify(value);
1372
1372
  if (serialized === undefined) {
1373
1373
  throw new TypeError("Mobile page props must be JSON-serializable.");
1374
1374
  }
1375
1375
  const parsed = JSON.parse(serialized);
1376
- if (!isRecord5(parsed)) {
1376
+ if (!isRecord6(parsed)) {
1377
1377
  throw new TypeError("Mobile page props must serialize to an object.");
1378
1378
  }
1379
1379
  return parsed;
@@ -1607,26 +1607,26 @@ __export(exports_materializedBundle, {
1607
1607
  materializeAbsoluteMobileCompatibilityBundle: () => materializeAbsoluteMobileCompatibilityBundle,
1608
1608
  readAbsoluteMobileMaterializedReleases: () => readAbsoluteMobileMaterializedReleases
1609
1609
  });
1610
- import { createHash as createHash10 } from "crypto";
1610
+ import { createHash as createHash11 } from "crypto";
1611
1611
  import {
1612
- access as access9,
1613
- mkdir as mkdir10,
1614
- mkdtemp as mkdtemp6,
1615
- readFile as readFile13,
1616
- rename as rename10,
1617
- rm as rm9,
1618
- writeFile as writeFile11
1612
+ access as access10,
1613
+ mkdir as mkdir11,
1614
+ mkdtemp as mkdtemp7,
1615
+ readFile as readFile14,
1616
+ rename as rename11,
1617
+ rm as rm10,
1618
+ writeFile as writeFile12
1619
1619
  } from "fs/promises";
1620
- import { dirname as dirname8, join as join11, resolve as resolvePath4 } from "path";
1620
+ import { dirname as dirname9, join as join12, resolve as resolvePath4 } from "path";
1621
1621
  import { pathToFileURL } from "url";
1622
- var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "current.json", BUNDLES_DIRECTORY = "bundles", ARTIFACT_FILE2 = "artifact.json", BUNDLE_ID_PATTERN, isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), errorHasCode3 = (error, code) => typeof error === "object" && error !== null && Reflect.get(error, "code") === code, bundleIdFor = (currentReleaseId, releases) => {
1622
+ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "current.json", BUNDLES_DIRECTORY = "bundles", ARTIFACT_FILE2 = "artifact.json", BUNDLE_ID_PATTERN, isRecord8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), errorHasCode3 = (error, code) => typeof error === "object" && error !== null && Reflect.get(error, "code") === code, bundleIdFor = (currentReleaseId, releases) => {
1623
1623
  const identity = JSON.stringify({
1624
1624
  currentReleaseId,
1625
1625
  releases: releases.map(({ releaseId }) => releaseId)
1626
1626
  });
1627
- return `amb_${createHash10("sha256").update(identity).digest("hex")}`;
1627
+ return `amb_${createHash11("sha256").update(identity).digest("hex")}`;
1628
1628
  }, parseBundleIndex = (value) => {
1629
- 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)) {
1629
+ if (!isRecord8(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)) {
1630
1630
  throw new TypeError("Invalid materialized mobile compatibility bundle.");
1631
1631
  }
1632
1632
  const releases = value.releases.map(parseAbsoluteMobileCompatibilityArtifact);
@@ -1648,29 +1648,29 @@ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "curre
1648
1648
  releases
1649
1649
  };
1650
1650
  }, writeRelease = async (root, release) => {
1651
- const directory = join11(root, release.artifact.releaseId);
1652
- const producerPath = join11(directory, release.artifact.producer.module);
1653
- await mkdir10(dirname8(producerPath), { recursive: true });
1651
+ const directory = join12(root, release.artifact.releaseId);
1652
+ const producerPath = join12(directory, release.artifact.producer.module);
1653
+ await mkdir11(dirname9(producerPath), { recursive: true });
1654
1654
  await Promise.all([
1655
- writeFile11(join11(directory, ARTIFACT_FILE2), `${JSON.stringify(release.artifact, null, "\t")}
1655
+ writeFile12(join12(directory, ARTIFACT_FILE2), `${JSON.stringify(release.artifact, null, "\t")}
1656
1656
  `),
1657
- writeFile11(producerPath, new Uint8Array(await release.producer.arrayBuffer()))
1657
+ writeFile12(producerPath, new Uint8Array(await release.producer.arrayBuffer()))
1658
1658
  ]);
1659
1659
  }, installImmutableBundle = async (bundlesRoot, bundleId, releases) => {
1660
- const destination = join11(bundlesRoot, bundleId);
1660
+ const destination = join12(bundlesRoot, bundleId);
1661
1661
  try {
1662
- await access9(destination);
1662
+ await access10(destination);
1663
1663
  return destination;
1664
1664
  } catch (error) {
1665
1665
  if (!errorHasCode3(error, "ENOENT"))
1666
1666
  throw error;
1667
1667
  }
1668
- const staging = await mkdtemp6(join11(bundlesRoot, ".stage-"));
1668
+ const staging = await mkdtemp7(join12(bundlesRoot, ".stage-"));
1669
1669
  try {
1670
1670
  await Promise.all(releases.map((release) => writeRelease(staging, release)));
1671
- await rename10(staging, destination);
1671
+ await rename11(staging, destination);
1672
1672
  } catch (error) {
1673
- await rm9(staging, { force: true, recursive: true });
1673
+ await rm10(staging, { force: true, recursive: true });
1674
1674
  if (errorHasCode3(error, "EEXIST") || errorHasCode3(error, "ENOTEMPTY")) {
1675
1675
  return destination;
1676
1676
  }
@@ -1679,7 +1679,7 @@ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "curre
1679
1679
  return destination;
1680
1680
  }, readCompatibilityModule = (modulePath) => import(pathToFileURL(modulePath).href), resolveProducerHandler = (loaded, exportName) => {
1681
1681
  const value = loaded[exportName];
1682
- if (!isRecord7(value) || typeof value.handle !== "function") {
1682
+ if (!isRecord8(value) || typeof value.handle !== "function") {
1683
1683
  throw new TypeError(`Compatibility producer export ${exportName} must expose handle(request).`);
1684
1684
  }
1685
1685
  const { handle } = value;
@@ -1696,15 +1696,15 @@ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "curre
1696
1696
  };
1697
1697
  }, loadAbsoluteMobileMaterializedBundle = async (root) => {
1698
1698
  const resolvedRoot = resolvePath4(root);
1699
- const serialized = await readFile13(join11(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
1699
+ const serialized = await readFile14(join12(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
1700
1700
  const parsed = JSON.parse(serialized);
1701
1701
  const index = parseBundleIndex(parsed);
1702
- const bundleRoot = join11(resolvedRoot, BUNDLES_DIRECTORY, index.bundleId);
1702
+ const bundleRoot = join12(resolvedRoot, BUNDLES_DIRECTORY, index.bundleId);
1703
1703
  return {
1704
1704
  artifacts: index.releases,
1705
1705
  currentReleaseId: index.currentReleaseId,
1706
1706
  loadProducer: async (artifact) => {
1707
- const modulePath = join11(bundleRoot, artifact.releaseId, artifact.producer.module);
1707
+ const modulePath = join12(bundleRoot, artifact.releaseId, artifact.producer.module);
1708
1708
  await verifyAbsoluteMobileCompatibilityProducer({
1709
1709
  artifact,
1710
1710
  producer: Bun.file(modulePath)
@@ -1730,8 +1730,8 @@ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "curre
1730
1730
  return release;
1731
1731
  });
1732
1732
  const root = resolvePath4(input.root);
1733
- const bundlesRoot = join11(root, BUNDLES_DIRECTORY);
1734
- await mkdir10(bundlesRoot, { recursive: true });
1733
+ const bundlesRoot = join12(root, BUNDLES_DIRECTORY);
1734
+ await mkdir11(bundlesRoot, { recursive: true });
1735
1735
  const bundleId = bundleIdFor(input.currentReleaseId, artifacts);
1736
1736
  await installImmutableBundle(bundlesRoot, bundleId, orderedReleases);
1737
1737
  const index = {
@@ -1740,21 +1740,21 @@ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "curre
1740
1740
  format: ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT,
1741
1741
  releases: artifacts
1742
1742
  };
1743
- const pointerPath = join11(root, CURRENT_BUNDLE_FILE);
1744
- const temporaryPointerPath = join11(root, `.current-${crypto.randomUUID()}.json`);
1745
- await writeFile11(temporaryPointerPath, `${JSON.stringify(index, null, "\t")}
1743
+ const pointerPath = join12(root, CURRENT_BUNDLE_FILE);
1744
+ const temporaryPointerPath = join12(root, `.current-${crypto.randomUUID()}.json`);
1745
+ await writeFile12(temporaryPointerPath, `${JSON.stringify(index, null, "\t")}
1746
1746
  `, { flag: "wx" });
1747
- await rename10(temporaryPointerPath, pointerPath);
1747
+ await rename11(temporaryPointerPath, pointerPath);
1748
1748
  return index;
1749
1749
  }, readAbsoluteMobileMaterializedReleases = async (root) => {
1750
1750
  const resolvedRoot = resolvePath4(root);
1751
1751
  try {
1752
- const serialized = await readFile13(join11(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
1752
+ const serialized = await readFile14(join12(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
1753
1753
  const parsed = JSON.parse(serialized);
1754
1754
  const index = parseBundleIndex(parsed);
1755
- const bundleRoot = join11(resolvedRoot, BUNDLES_DIRECTORY, index.bundleId);
1755
+ const bundleRoot = join12(resolvedRoot, BUNDLES_DIRECTORY, index.bundleId);
1756
1756
  return Promise.all(index.releases.map(async (artifact) => {
1757
- const producer = Bun.file(join11(bundleRoot, artifact.releaseId, artifact.producer.module));
1757
+ const producer = Bun.file(join12(bundleRoot, artifact.releaseId, artifact.producer.module));
1758
1758
  await verifyAbsoluteMobileCompatibilityProducer({
1759
1759
  artifact,
1760
1760
  producer
@@ -1775,7 +1775,7 @@ var init_materializedBundle = __esm(() => {
1775
1775
 
1776
1776
  // src/mobile/deviceCapabilities.ts
1777
1777
  import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
1778
- import { extname as extname3, join as join12, relative as relative9, resolve as resolve10 } from "path";
1778
+ import { extname as extname3, join as join13, relative as relative10, resolve as resolve11 } from "path";
1779
1779
  import { fileURLToPath } from "url";
1780
1780
  import ts from "typescript";
1781
1781
  var DEVICES_PACKAGE = "@absolutejs/devices", ABSOLUTE_MOBILE_SHELL_DEVICE_CAPABILITIES, ADAPTERS, SOURCE_GLOB, IGNORED_DIRECTORIES, IDENTIFIER_PATTERN, providerModulePattern = (provider) => new RegExp(`^@absolutejs/devices-${provider}/[a-z][a-z0-9-]*$`, "u"), providerPackagePattern = (provider) => provider === "capacitor" ? /^@capacitor\/[a-z][a-z0-9-]*@\d+\.\d+\.\d+$/u : /^(?:expo-[a-z][a-z0-9-]*|@react-native-[a-z0-9-]+\/[a-z][a-z0-9-]*)@\d+\.\d+\.\d+$/u, providerLabel = (provider) => provider === "capacitor" ? "Capacitor" : "Expo", ANDROID_PERMISSION_PATTERN, IOS_USAGE_DESCRIPTIONS, IOS_PRIVACY_ACCESSED_API_REASONS, IOS_PRIVACY_ACCESSED_APIS, object = (value) => typeof value === "object" && value !== null && !Array.isArray(value), readJson = (path) => {
@@ -1903,7 +1903,7 @@ var DEVICES_PACKAGE = "@absolutejs/devices", ABSOLUTE_MOBILE_SHELL_DEVICE_CAPABI
1903
1903
  };
1904
1904
  }, loadAbsoluteDeviceCapabilityProviders = (projectRoot, provider = "capacitor") => {
1905
1905
  const adapter = ADAPTERS[provider];
1906
- let path = join12(resolve10(projectRoot), "node_modules", adapter, "package.json");
1906
+ let path = join13(resolve11(projectRoot), "node_modules", adapter, "package.json");
1907
1907
  try {
1908
1908
  readFileSync3(path, "utf8");
1909
1909
  } catch {
@@ -1958,7 +1958,7 @@ var DEVICES_PACKAGE = "@absolutejs/devices", ABSOLUTE_MOBILE_SHELL_DEVICE_CAPABI
1958
1958
  if (missing.includes(spec))
1959
1959
  return false;
1960
1960
  try {
1961
- return readJson(join12(resolve10(projectRoot), "node_modules", packageName, "package.json")).version !== spec.slice(separator + 1);
1961
+ return readJson(join13(resolve11(projectRoot), "node_modules", packageName, "package.json")).version !== spec.slice(separator + 1);
1962
1962
  } catch {
1963
1963
  return true;
1964
1964
  }
@@ -1967,7 +1967,7 @@ var DEVICES_PACKAGE = "@absolutejs/devices", ABSOLUTE_MOBILE_SHELL_DEVICE_CAPABI
1967
1967
  if (unmet.length > 0)
1968
1968
  throw new TypeError(`Device capabilities ${plan.capabilities.join(", ")} require ${unmet.join(", ")}. Run absolute mobile sync and approve the detected capability plugins.`);
1969
1969
  }, directAbsoluteProjectPackages = (projectRoot) => {
1970
- const manifest = readJson(join12(resolve10(projectRoot), "package.json"));
1970
+ const manifest = readJson(join13(resolve11(projectRoot), "package.json"));
1971
1971
  const packages = new Set;
1972
1972
  for (const field2 of ["dependencies", "devDependencies"]) {
1973
1973
  const dependencies = manifest[field2];
@@ -1977,16 +1977,16 @@ var DEVICES_PACKAGE = "@absolutejs/devices", ABSOLUTE_MOBILE_SHELL_DEVICE_CAPABI
1977
1977
  }
1978
1978
  return packages;
1979
1979
  }, discoverAbsoluteDeviceCapabilities = (projectRoot, providers = loadAbsoluteDeviceCapabilityProviders(projectRoot)) => {
1980
- const root = resolve10(projectRoot);
1980
+ const root = resolve11(projectRoot);
1981
1981
  if (!existsSync3(root))
1982
1982
  return [];
1983
1983
  const known = new Set(Object.keys(providers));
1984
1984
  const capabilities = new Set;
1985
1985
  for (const path of SOURCE_GLOB.scanSync({ cwd: root })) {
1986
- const portable = relative9(root, resolve10(root, path)).replaceAll("\\", "/");
1986
+ const portable = relative10(root, resolve11(root, path)).replaceAll("\\", "/");
1987
1987
  if (isIgnored(portable))
1988
1988
  continue;
1989
- const source = readFileSync3(resolve10(root, portable), "utf8");
1989
+ const source = readFileSync3(resolve11(root, portable), "utf8");
1990
1990
  for (const name of importedCapabilities(source, portable))
1991
1991
  if (known.has(name))
1992
1992
  capabilities.add(name);
@@ -1996,12 +1996,12 @@ var DEVICES_PACKAGE = "@absolutejs/devices", ABSOLUTE_MOBILE_SHELL_DEVICE_CAPABI
1996
1996
  const packageName = spec.slice(0, spec.lastIndexOf("@"));
1997
1997
  return !directPackages.has(packageName);
1998
1998
  }), projectImportsAbsoluteDeviceCapability = (projectRoot, capability) => {
1999
- const root = resolve10(projectRoot);
1999
+ const root = resolve11(projectRoot);
2000
2000
  for (const path of SOURCE_GLOB.scanSync({ cwd: root })) {
2001
- const portable = relative9(root, resolve10(root, path)).replaceAll("\\", "/");
2001
+ const portable = relative10(root, resolve11(root, path)).replaceAll("\\", "/");
2002
2002
  if (isIgnored(portable))
2003
2003
  continue;
2004
- const source = readFileSync3(resolve10(root, portable), "utf8");
2004
+ const source = readFileSync3(resolve11(root, portable), "utf8");
2005
2005
  if (importedCapabilities(source, portable).has(capability))
2006
2006
  return true;
2007
2007
  }
@@ -2068,10 +2068,10 @@ var init_deviceCapabilities = __esm(() => {
2068
2068
 
2069
2069
  // src/mobile/nativeAuth.ts
2070
2070
  import { readFileSync as readFileSync4 } from "fs";
2071
- import { join as join13 } from "path";
2071
+ import { join as join14 } from "path";
2072
2072
  var ABSOLUTE_AUTH_PACKAGE = "@absolutejs/auth", ABSOLUTE_EXPO_AUTH_CORE_VERSION = "0.76.3", ABSOLUTE_EXPO_AUTH_PACKAGE = "@absolutejs/auth-expo", ABSOLUTE_EXPO_AUTH_VERSION = "0.0.6", ABSOLUTE_EXPO_SYNC_CORE_VERSION = "2.31.0", ABSOLUTE_EXPO_SYNC_PACKAGE = "@absolutejs/sync-expo", ABSOLUTE_EXPO_SYNC_VERSION = "0.0.4", ABSOLUTE_NATIVE_AUTH_CLIENTS_ENV = "ABSOLUTE_AUTH_NATIVE_CLIENTS", ABSOLUTE_NATIVE_AUTH_SCOPES, ABSOLUTE_SYNC_PACKAGE = "@absolutejs/sync", readPackageManifest = (projectRoot) => {
2073
2073
  try {
2074
- return JSON.parse(readFileSync4(join13(projectRoot, "package.json"), "utf8"));
2074
+ return JSON.parse(readFileSync4(join14(projectRoot, "package.json"), "utf8"));
2075
2075
  } catch {
2076
2076
  return;
2077
2077
  }
@@ -2241,7 +2241,7 @@ var init_client = __esm(() => {
2241
2241
 
2242
2242
  // src/mobile/syncSchema.ts
2243
2243
  import { readFileSync as readFileSync5 } from "fs";
2244
- import { dirname as dirname9, join as join14, resolve as resolve11 } from "path";
2244
+ import { dirname as dirname10, join as join15, resolve as resolve12 } from "path";
2245
2245
  var object2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), manifestAt = (path) => {
2246
2246
  try {
2247
2247
  const value = JSON.parse(readFileSync5(path, "utf8"));
@@ -2258,13 +2258,13 @@ var object2 = (value) => typeof value === "object" && value !== null && !Array.i
2258
2258
  return;
2259
2259
  return Reflect.get(sync, "localSchema");
2260
2260
  }, packageManifestPath = (projectRoot, packageName) => {
2261
- let directory = resolve11(projectRoot);
2261
+ let directory = resolve12(projectRoot);
2262
2262
  while (true) {
2263
- const candidate = join14(directory, "node_modules", packageName, "package.json");
2263
+ const candidate = join15(directory, "node_modules", packageName, "package.json");
2264
2264
  const manifest = manifestAt(candidate);
2265
2265
  if (manifest && Reflect.get(manifest, "name") === packageName)
2266
2266
  return candidate;
2267
- const parent = dirname9(directory);
2267
+ const parent = dirname10(directory);
2268
2268
  if (parent === directory)
2269
2269
  return;
2270
2270
  directory = parent;
@@ -2491,7 +2491,7 @@ var object2 = (value) => typeof value === "object" && value !== null && !Array.i
2491
2491
  Reflect.get(manifest, "devDependencies"),
2492
2492
  Reflect.get(manifest, "peerDependencies")
2493
2493
  ].flatMap((dependencies) => object2(dependencies) ? Object.keys(dependencies) : []).filter((name, index, names) => names.indexOf(name) === index).sort(), discoverAbsoluteSyncSchema = (projectRoot) => {
2494
- const appManifestPath = join14(resolve11(projectRoot), "package.json");
2494
+ const appManifestPath = join15(resolve12(projectRoot), "package.json");
2495
2495
  const appManifest = manifestAt(appManifestPath);
2496
2496
  if (!appManifest)
2497
2497
  return {
@@ -6838,9 +6838,9 @@ var require_sha256 = __commonJS(function(exports, module) {
6838
6838
  var forge = require_forge();
6839
6839
  require_md();
6840
6840
  require_util();
6841
- var sha2562 = module.exports = forge.sha256 = forge.sha256 || {};
6842
- forge.md.sha256 = forge.md.algorithms.sha256 = sha2562;
6843
- sha2562.create = function() {
6841
+ var sha2563 = module.exports = forge.sha256 = forge.sha256 || {};
6842
+ forge.md.sha256 = forge.md.algorithms.sha256 = sha2563;
6843
+ sha2563.create = function() {
6844
6844
  if (!_initialized) {
6845
6845
  _init();
6846
6846
  }
@@ -19350,8 +19350,8 @@ var init_compatibilityDispatcher = __esm(() => {
19350
19350
 
19351
19351
  // src/cli/scripts/telemetry.ts
19352
19352
  import { existsSync as existsSync5, mkdirSync, readFileSync as readFileSync6, writeFileSync } from "fs";
19353
- import { homedir as homedir3 } from "os";
19354
- import { join as join21 } from "path";
19353
+ import { homedir as homedir4 } from "os";
19354
+ import { join as join22 } from "path";
19355
19355
  var configDir, configPath, getTelemetryConfig = () => {
19356
19356
  try {
19357
19357
  if (!existsSync5(configPath))
@@ -19364,14 +19364,14 @@ var configDir, configPath, getTelemetryConfig = () => {
19364
19364
  }
19365
19365
  };
19366
19366
  var init_telemetry = __esm(() => {
19367
- configDir = join21(homedir3(), ".absolutejs");
19368
- configPath = join21(configDir, "telemetry.json");
19367
+ configDir = join22(homedir4(), ".absolutejs");
19368
+ configPath = join22(configDir, "telemetry.json");
19369
19369
  });
19370
19370
 
19371
19371
  // src/cli/telemetryEvent.ts
19372
19372
  import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
19373
19373
  import { arch, platform as platform3 } from "os";
19374
- import { dirname as dirname14, join as join22, parse } from "path";
19374
+ import { dirname as dirname15, join as join23, parse } from "path";
19375
19375
  var checkCandidate = (candidate) => {
19376
19376
  if (!existsSync6(candidate)) {
19377
19377
  return null;
@@ -19391,12 +19391,12 @@ var checkCandidate = (candidate) => {
19391
19391
  }, findPackageVersion = () => {
19392
19392
  let { dir } = import.meta;
19393
19393
  while (dir !== parse(dir).root) {
19394
- const candidate = join22(dir, "package.json");
19394
+ const candidate = join23(dir, "package.json");
19395
19395
  const version = checkCandidate(candidate);
19396
19396
  if (version) {
19397
19397
  return version;
19398
19398
  }
19399
- dir = dirname14(dir);
19399
+ dir = dirname15(dir);
19400
19400
  }
19401
19401
  return "unknown";
19402
19402
  }, sendTelemetryEvent = (event, payload) => {
@@ -19437,7 +19437,7 @@ __export(exports_mobilePreview, {
19437
19437
  createAbsoluteMobilePreviewPlugin: () => createAbsoluteMobilePreviewPlugin
19438
19438
  });
19439
19439
  import { Elysia as Elysia3 } from "elysia";
19440
- var ABSOLUTE_MOBILE_PREVIEW_PATH = "/__absolute/mobile-preview", escapeHtml2 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;"), isRecord10 = (value) => typeof value === "object" && value !== null, normalizeEntry2 = (entry) => {
19440
+ var ABSOLUTE_MOBILE_PREVIEW_PATH = "/__absolute/mobile-preview", escapeHtml2 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;"), isRecord11 = (value) => typeof value === "object" && value !== null, normalizeEntry2 = (entry) => {
19441
19441
  const parsed = new URL(entry ?? "/", "https://absolute.invalid");
19442
19442
  return `${parsed.pathname}${parsed.search}${parsed.hash}`;
19443
19443
  }, absoluteMobilePreviewDocument = (mobile) => {
@@ -19485,7 +19485,7 @@ var ABSOLUTE_MOBILE_PREVIEW_PATH = "/__absolute/mobile-preview", escapeHtml2 = (
19485
19485
  "X-Robots-Tag": "noindex, nofollow"
19486
19486
  }
19487
19487
  })).post("/__absolute/mobile-preview-telemetry", ({ body, status }) => {
19488
- const value = isRecord10(body) ? body : undefined;
19488
+ const value = isRecord11(body) ? body : undefined;
19489
19489
  const durationMs = value?.durationMs;
19490
19490
  const platform4 = value?.platform;
19491
19491
  if (typeof durationMs !== "number" || !Number.isFinite(durationMs) || durationMs < 0 || durationMs > 300000 || platform4 !== "android" && platform4 !== "ios") {
@@ -20032,7 +20032,7 @@ __export(exports_mobileUpdate, {
20032
20032
  parseMobileUpdateManifest: () => parseMobileUpdateManifest
20033
20033
  });
20034
20034
  import {
20035
- createHash as createHash16,
20035
+ createHash as createHash17,
20036
20036
  createHmac,
20037
20037
  createPrivateKey,
20038
20038
  createPublicKey as createPublicKey2,
@@ -20042,7 +20042,7 @@ import {
20042
20042
  verify as verify2,
20043
20043
  X509Certificate as X509Certificate3
20044
20044
  } from "crypto";
20045
- import { readFile as readFile24, stat as stat5 } from "fs/promises";
20045
+ import { readFile as readFile25, stat as stat6 } from "fs/promises";
20046
20046
  import path from "path";
20047
20047
  var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updates", MAX_FILE_BYTES, MAX_TOTAL_BYTES, DAY_MS, DEFAULT_MIN_AGE_MS, DEFAULT_GRACE_PERIOD_MS, DEFAULT_RETAIN_RECENT = 5, HASH, RELEASE, APP_ID, NAME, EXPO_DESCRIPTOR = "_absolute/expo-update.json", EXPO_CODE_SIGNING_ALGORITHM = "rsa-v1_5-sha256", HEALTH_TOKEN_VERSION = 1, HEALTH_KINDS, FAILURE_HEALTH_KINDS, MobileUpdateRegistryError, object6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), text2 = (value, field2) => {
20048
20048
  if (typeof value !== "string" || value.length === 0)
@@ -20192,7 +20192,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
20192
20192
  if (!prefix || prefix.split("/").some((segment) => segment === "." || segment === ".."))
20193
20193
  throw new MobileUpdateRegistryError("Mobile update prefix is invalid");
20194
20194
  return prefix;
20195
- }, appHash = (appId) => createHash16("sha256").update(appId).digest("hex"), digest = (bytes) => createHash16("sha256").update(bytes).digest("hex"), json = (value) => new TextEncoder().encode(`${JSON.stringify(value, null, 2)}
20195
+ }, appHash = (appId) => createHash17("sha256").update(appId).digest("hex"), digest = (bytes) => createHash17("sha256").update(bytes).digest("hex"), json = (value) => new TextEncoder().encode(`${JSON.stringify(value, null, 2)}
20196
20196
  `), decode2 = (value) => JSON.parse(new TextDecoder().decode(value)), fileDigest = async (file) => {
20197
20197
  const hasher = new Bun.CryptoHasher("sha256");
20198
20198
  for await (const chunk of file.stream())
@@ -20203,7 +20203,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
20203
20203
  return false;
20204
20204
  if (input.rollout === 1)
20205
20205
  return true;
20206
- const value = createHash16("sha256").update(`${input.appId}\x00${input.channel}\x00${input.releaseId}\x00${input.installationId}`).digest().readUInt32BE(0);
20206
+ const value = createHash17("sha256").update(`${input.appId}\x00${input.channel}\x00${input.releaseId}\x00${input.installationId}`).digest().readUInt32BE(0);
20207
20207
  return value / 4294967296 < input.rollout;
20208
20208
  }, base64Url = (value) => Buffer.from(value).toString("base64url"), healthPromotionId = (channel) => channel.promotionId ?? digest(new TextEncoder().encode(`${channel.appId}\x00${channel.channel}\x00${channel.releaseId ?? "embedded"}\x00${channel.promotedAt}`)), finiteMetric = (value, field2) => {
20209
20209
  if (typeof value !== "number" || !Number.isFinite(value) || value < 0)
@@ -20243,7 +20243,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
20243
20243
  const releaseRoot = (manifest) => `${root(manifest.appId)}/releases/${manifest.releaseId}`;
20244
20244
  const manifestKey = (manifest) => `${releaseRoot(manifest)}/update.json`;
20245
20245
  const fileKey = (manifest, file) => `${releaseRoot(manifest)}/files/${file.path}`;
20246
- const contentBlobKey = (appId, sha2563) => `${root(appId)}/blobs/${sha2563}`;
20246
+ const contentBlobKey = (appId, sha2564) => `${root(appId)}/blobs/${sha2564}`;
20247
20247
  const tombstoneKey = (appId, releaseId) => `${root(appId)}/gc/${releaseId}.json`;
20248
20248
  const healthRoot = (appId, promotionId, releaseId) => `${root(appId)}/health/${promotionId}/${releaseId}`;
20249
20249
  const pauseKey = (appId, promotionId, releaseId) => `${healthRoot(appId, promotionId, releaseId)}/paused.json`;
@@ -20864,10 +20864,10 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
20864
20864
  const objectBytesByDigest = new Map;
20865
20865
  for (const blobObject of objects) {
20866
20866
  if (blobObject.key.startsWith(blobPrefix)) {
20867
- const sha2563 = blobObject.key.slice(blobPrefix.length);
20868
- if (HASH.test(sha2563)) {
20869
- objectKeysByDigest.set(sha2563, blobObject.key);
20870
- objectBytesByDigest.set(sha2563, blobObject.size);
20867
+ const sha2564 = blobObject.key.slice(blobPrefix.length);
20868
+ if (HASH.test(sha2564)) {
20869
+ objectKeysByDigest.set(sha2564, blobObject.key);
20870
+ objectBytesByDigest.set(sha2564, blobObject.size);
20871
20871
  }
20872
20872
  }
20873
20873
  if (!blobObject.key.startsWith(releasePrefix))
@@ -20950,7 +20950,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
20950
20950
  }).toSorted((left, right) => right.createdAt.localeCompare(left.createdAt));
20951
20951
  const protectedReleaseIds = new Set(releases.filter((release) => release.protectedBy.length > 0).map((release) => release.releaseId));
20952
20952
  const protectedDigests = new Set(manifests.filter((manifest) => protectedReleaseIds.has(manifest.releaseId)).flatMap((manifest) => manifest.files.map((file) => file.sha256)));
20953
- const reclaimableContentBytes = [...objectBytesByDigest].filter(([sha2563]) => !protectedDigests.has(sha2563)).reduce((total, [, bytes]) => total + bytes, 0);
20953
+ const reclaimableContentBytes = [...objectBytesByDigest].filter(([sha2564]) => !protectedDigests.has(sha2564)).reduce((total, [, bytes]) => total + bytes, 0);
20954
20954
  const contentBlobBytes = [...objectBytesByDigest.values()].reduce((total, bytes) => total + bytes, 0);
20955
20955
  const releaseBytes = releases.reduce((total, release) => total + release.bytes, 0);
20956
20956
  const totalBytes = objects.reduce((total, object22) => total + object22.size, 0);
@@ -21047,13 +21047,13 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
21047
21047
  for (const file of manifest?.manifest.files ?? [])
21048
21048
  referencedDigests.add(file.sha256);
21049
21049
  }
21050
- for (const [sha2563, key] of afterReleaseSweep.objectKeysByDigest) {
21051
- if (referencedDigests.has(sha2563))
21050
+ for (const [sha2564, key] of afterReleaseSweep.objectKeysByDigest) {
21051
+ if (referencedDigests.has(sha2564))
21052
21052
  continue;
21053
21053
  const head = await options.store.head(key);
21054
21054
  await remove(key);
21055
21055
  result.reclaimedBytes += head?.size ?? 0;
21056
- result.sweptContentBlobs.push(sha2563);
21056
+ result.sweptContentBlobs.push(sha2564);
21057
21057
  }
21058
21058
  return result;
21059
21059
  };
@@ -21075,7 +21075,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
21075
21075
  verifyManifestSignature(manifest, options.publicKeys);
21076
21076
  await assertNotMarked(manifest.appId, manifest.releaseId);
21077
21077
  const localRoot = path.resolve(input.releaseDirectory);
21078
- const localManifest = parseMobileUpdateManifest(JSON.parse(await readFile24(path.join(localRoot, "update.json"), "utf8")));
21078
+ const localManifest = parseMobileUpdateManifest(JSON.parse(await readFile25(path.join(localRoot, "update.json"), "utf8")));
21079
21079
  if (JSON.stringify(localManifest) !== JSON.stringify(manifest))
21080
21080
  throw new MobileUpdateRegistryError("Local mobile update manifest changed");
21081
21081
  const existing = await readManifest(manifest.appId, manifest.releaseId);
@@ -21093,7 +21093,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
21093
21093
  if (!existing) {
21094
21094
  for (const file of manifest.files) {
21095
21095
  const local = path.join(localRoot, "files", file.path);
21096
- const metadata = await stat5(local).catch(() => null);
21096
+ const metadata = await stat6(local).catch(() => null);
21097
21097
  if (!metadata?.isFile() || metadata.size !== file.bytes)
21098
21098
  throw new MobileUpdateRegistryError(`Mobile update file ${file.path} size changed`);
21099
21099
  if (await fileDigest(Bun.file(local)) !== file.sha256)
@@ -21208,10 +21208,10 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
21208
21208
  }
21209
21209
  };
21210
21210
  }, expoUpdateId = (releaseId) => {
21211
- const hash = RELEASE.test(releaseId) ? releaseId.slice("amu_".length, "amu_".length + 32) : createHash16("sha256").update(releaseId).digest("hex").slice(0, 32);
21211
+ const hash = RELEASE.test(releaseId) ? releaseId.slice("amu_".length, "amu_".length + 32) : createHash17("sha256").update(releaseId).digest("hex").slice(0, 32);
21212
21212
  return `${hash.slice(0, 8)}-${hash.slice(8, 12)}-${hash.slice(12, 16)}-${hash.slice(16, 20)}-${hash.slice(20)}`;
21213
- }, expoContentType = (extension2, launch) => {
21214
- if (launch)
21213
+ }, expoContentType = (extension2, launch2) => {
21214
+ if (launch2)
21215
21215
  return "application/javascript";
21216
21216
  const normalized = extension2?.toLowerCase();
21217
21217
  if (normalized === "png")
@@ -21361,8 +21361,8 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
21361
21361
  });
21362
21362
  }
21363
21363
  const pathname = new URL(request.url).pathname.replace(/^\/+/, "");
21364
- const relative18 = pathname.startsWith(`${route}/`) ? pathname.slice(route.length + 1) : "";
21365
- if (request.method === "POST" && relative18 === "health") {
21364
+ const relative19 = pathname.startsWith(`${route}/`) ? pathname.slice(route.length + 1) : "";
21365
+ if (request.method === "POST" && relative19 === "health") {
21366
21366
  if (!options.registry.recordUpdateHealth)
21367
21367
  return new Response(null, { status: 404 });
21368
21368
  const appId = request.headers.get("x-absolute-mobile-app");
@@ -21405,7 +21405,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
21405
21405
  }
21406
21406
  if (request.method !== "GET")
21407
21407
  return new Response(null, { status: 405 });
21408
- if (relative18 === "update.json") {
21408
+ if (relative19 === "update.json") {
21409
21409
  const expoProtocolVersion = request.headers.get("expo-protocol-version");
21410
21410
  const expoProtocol = expoProtocolVersion !== null;
21411
21411
  if (expoProtocol && expoProtocolVersion !== "1")
@@ -21472,12 +21472,12 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
21472
21472
  return new Response(null, { status: 204 });
21473
21473
  const origin2 = new URL(request.url).origin;
21474
21474
  const releaseRoute = `${origin2}/${route}/${selected.manifest.releaseId}/files`;
21475
- const protocolAsset = (asset2, launch = false) => {
21475
+ const protocolAsset = (asset2, launch2 = false) => {
21476
21476
  const file2 = selected.manifest.files.find((candidate) => candidate.path === asset2.path);
21477
21477
  if (!file2)
21478
21478
  throw new MobileUpdateRegistryError(`Expo update references missing signed asset ${asset2.path}`);
21479
21479
  return {
21480
- contentType: expoContentType(asset2.extension, launch),
21480
+ contentType: expoContentType(asset2.extension, launch2),
21481
21481
  ...asset2.extension ? { fileExtension: `.${asset2.extension}` } : {},
21482
21482
  key: file2.sha256,
21483
21483
  hash: Buffer.from(file2.sha256, "hex").toString("base64url"),
@@ -21523,7 +21523,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
21523
21523
  }
21524
21524
  });
21525
21525
  }
21526
- const match = /^(amu_[a-f0-9]{64})\/files\/(.+)$/.exec(relative18);
21526
+ const match = /^(amu_[a-f0-9]{64})\/files\/(.+)$/.exec(relative19);
21527
21527
  if (!match?.[1] || !match[2])
21528
21528
  return new Response(null, { status: 404 });
21529
21529
  const file = await options.registry.readUpdateFile({
@@ -21616,15 +21616,15 @@ import {
21616
21616
  createPublicKey as createPublicKey3,
21617
21617
  X509Certificate as X509Certificate4
21618
21618
  } from "crypto";
21619
- import { access as access17, mkdir as mkdir18 } from "fs/promises";
21620
- import { dirname as dirname19, isAbsolute as isAbsolute9, relative as relative18, resolve as resolve20, sep as sep11 } from "path";
21619
+ import { access as access18, mkdir as mkdir19 } from "fs/promises";
21620
+ import { dirname as dirname20, isAbsolute as isAbsolute10, relative as relative19, resolve as resolve21, sep as sep12 } from "path";
21621
21621
  import { pathToFileURL as pathToFileURL5 } from "url";
21622
21622
  import { Elysia as Elysia4 } from "elysia";
21623
21623
  var ABSOLUTE_MOBILE_UPDATE_SERVER_FORMAT = 1, DEFAULT_MOBILE_UPDATE_REGISTRY_MODULE = "mobile.update.ts", object7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), projectPath3 = (projectRoot, requested) => {
21624
- const root = resolve20(projectRoot);
21625
- const path2 = resolve20(root, requested);
21626
- const projectRelative = relative18(root, path2);
21627
- if (projectRelative === ".." || projectRelative.startsWith(`..${sep11}`) || isAbsolute9(projectRelative))
21624
+ const root = resolve21(projectRoot);
21625
+ const path2 = resolve21(root, requested);
21626
+ const projectRelative = relative19(root, path2);
21627
+ if (projectRelative === ".." || projectRelative.startsWith(`..${sep12}`) || isAbsolute10(projectRelative))
21628
21628
  throw new TypeError("mobile.updates.server.registry must remain inside the project.");
21629
21629
  return path2;
21630
21630
  }, isRegistry4 = (value) => object7(value) && [
@@ -21647,7 +21647,7 @@ var ABSOLUTE_MOBILE_UPDATE_SERVER_FORMAT = 1, DEFAULT_MOBILE_UPDATE_REGISTRY_MOD
21647
21647
  return metadata;
21648
21648
  }, loadAbsoluteMobileUpdateServerModule = async (projectRoot, requestedModulePath = DEFAULT_MOBILE_UPDATE_REGISTRY_MODULE) => {
21649
21649
  const modulePath = projectPath3(projectRoot, requestedModulePath);
21650
- await access17(modulePath).catch(() => {
21650
+ await access18(modulePath).catch(() => {
21651
21651
  throw new TypeError(`Mobile update server registry does not exist: ${modulePath}. Run \`absolute mobile update provision\`.`);
21652
21652
  });
21653
21653
  const loaded = await import(pathToFileURL5(modulePath).href);
@@ -21836,13 +21836,13 @@ ${generated}`);
21836
21836
  }, writeAbsoluteMobileUpdateRegistry = async (options) => {
21837
21837
  const path2 = projectPath3(options.projectRoot, options.modulePath ?? DEFAULT_MOBILE_UPDATE_REGISTRY_MODULE);
21838
21838
  if (!options.force) {
21839
- await access17(path2).then(() => {
21839
+ await access18(path2).then(() => {
21840
21840
  throw new TypeError(`Mobile update registry already exists: ${path2}. Pass --force to replace it.`);
21841
21841
  }, () => {
21842
21842
  return;
21843
21843
  });
21844
21844
  }
21845
- await mkdir18(dirname19(path2), { recursive: true });
21845
+ await mkdir19(dirname20(path2), { recursive: true });
21846
21846
  await Bun.write(path2, renderAbsoluteMobileUpdateRegistry({
21847
21847
  ...options.health ? { health: options.health } : {},
21848
21848
  ...options.rollout ? { rollout: options.rollout } : {},
@@ -24000,6 +24000,8 @@ var encodedWindowsExpoAndroidCommand = (project, androidRoot, appId, args, captu
24000
24000
  "$env:GRADLE_OPTS = (($env:GRADLE_OPTS + ' -Dorg.gradle.daemon=false').Trim())",
24001
24001
  "$autolinkingCache = Join-Path $mappedProject 'android\\build\\generated\\autolinking'",
24002
24002
  "if ([IO.Directory]::Exists($autolinkingCache)) { [IO.Directory]::Delete($autolinkingCache, $true) }",
24003
+ "$reactGeneratedResources = Join-Path $mappedProject 'android\\app\\build\\generated\\res\\react'",
24004
+ "if ([IO.Directory]::Exists($reactGeneratedResources)) { [IO.Directory]::Delete($reactGeneratedResources, $true) }",
24003
24005
  ...mode === "development" ? [
24004
24006
  "$expo = Join-Path $mappedProject 'node_modules\\.bin\\expo.exe'",
24005
24007
  "& $expo @expoArguments",
@@ -24719,6 +24721,14 @@ var signAab = (artifactPath, capture, jarsigner, signing) => {
24719
24721
  if (result.exitCode !== 0)
24720
24722
  throw new TypeError("jarsigner could not sign the Android App Bundle with the configured CI identity.");
24721
24723
  };
24724
+ var windowsJarsignerPath = (path, capture) => {
24725
+ const result = capture(["wslpath", "-w", path]);
24726
+ const translated = result.stdout.trim();
24727
+ if (result.exitCode !== 0 || !translated) {
24728
+ throw new TypeError(`Could not translate an Android signing path for the Windows JDK: ${path}`);
24729
+ }
24730
+ return translated;
24731
+ };
24722
24732
  var sha256File = async (path) => createHash4("sha256").update(await readFile5(path)).digest("hex");
24723
24733
  var fingerprintExpoAndroidProject = async (nativeDirectory) => {
24724
24734
  const root = await realpath2(nativeDirectory);
@@ -24836,13 +24846,19 @@ var buildAbsoluteAndroidRelease = async (options) => {
24836
24846
  throw new TypeError(`Android Gradle did not produce the expected App Bundle: ${artifactPath}`);
24837
24847
  }
24838
24848
  const capture = options.capture ?? defaultCapture;
24839
- const jarsigner = options.jarsigner === undefined ? Bun.which("jarsigner") : options.jarsigner;
24840
- let signed = verifyAabSignature(artifactPath, capture, jarsigner);
24841
- if (signed === false && options.signing) {
24849
+ const jarsigner = options.jarsigner === undefined ? Bun.which("jarsigner") ?? (host === "wsl" || host === "windows" ? Bun.which("jarsigner.exe") : null) : options.jarsigner;
24850
+ const usesWindowsJarsigner = host === "wsl" && jarsigner?.toLowerCase().endsWith(".exe");
24851
+ const signerArtifactPath = usesWindowsJarsigner ? windowsJarsignerPath(artifactPath, capture) : artifactPath;
24852
+ const signing = usesWindowsJarsigner && options.signing ? {
24853
+ ...options.signing,
24854
+ keystorePath: windowsJarsignerPath(options.signing.keystorePath, capture)
24855
+ } : options.signing;
24856
+ let signed = verifyAabSignature(signerArtifactPath, capture, jarsigner);
24857
+ if (signed === false && signing) {
24842
24858
  if (!jarsigner)
24843
24859
  throw new TypeError("Could not sign the Android App Bundle because jarsigner is unavailable.");
24844
- signAab(artifactPath, capture, jarsigner, options.signing);
24845
- signed = verifyAabSignature(artifactPath, capture, jarsigner);
24860
+ signAab(signerArtifactPath, capture, jarsigner, signing);
24861
+ signed = verifyAabSignature(signerArtifactPath, capture, jarsigner);
24846
24862
  if (!signed)
24847
24863
  throw new TypeError("Android App Bundle signature verification failed after CI signing.");
24848
24864
  }
@@ -24873,6 +24889,29 @@ var buildAbsoluteAndroidRelease = async (options) => {
24873
24889
  };
24874
24890
  return installRelease(artifactPath, metadata, safeOutputDirectory(projectRoot, options.outputDirectory));
24875
24891
  };
24892
+ // src/mobile/androidReleaseAcceptance.ts
24893
+ import { createHash as createHash5 } from "crypto";
24894
+ import {
24895
+ access as access6,
24896
+ mkdir as mkdir4,
24897
+ mkdtemp as mkdtemp3,
24898
+ readFile as readFile6,
24899
+ rename as rename5,
24900
+ rm as rm4,
24901
+ stat as stat2,
24902
+ writeFile as writeFile5
24903
+ } from "fs/promises";
24904
+ import { homedir as homedir2 } from "os";
24905
+ import {
24906
+ basename,
24907
+ dirname as dirname3,
24908
+ isAbsolute as isAbsolute3,
24909
+ join as join6,
24910
+ relative as relative4,
24911
+ resolve as resolve4,
24912
+ sep as sep3
24913
+ } from "path";
24914
+
24876
24915
  // src/mobile/androidUpgradeConformance.ts
24877
24916
  import { performance as performance2 } from "perf_hooks";
24878
24917
  var captureCommand4 = async (command) => {
@@ -24966,21 +25005,291 @@ var runAbsoluteAndroidUpgradeConformance = async (options) => {
24966
25005
  state
24967
25006
  };
24968
25007
  };
25008
+
25009
+ // src/mobile/androidReleaseAcceptance.ts
25010
+ var ABSOLUTE_BUNDLETOOL_VERSION = "1.18.3";
25011
+ var ABSOLUTE_BUNDLETOOL_SHA256 = "a099cfa1543f55593bc2ed16a70a7c67fe54b1747bb7301f37fdfd6d91028e29";
25012
+ var ABSOLUTE_BUNDLETOOL_URL = `https://github.com/google/bundletool/releases/download/${ABSOLUTE_BUNDLETOOL_VERSION}/bundletool-all-${ABSOLUTE_BUNDLETOOL_VERSION}.jar`;
25013
+ var EMBEDDED_READY_MARKER = "Expo embedded web content ready";
25014
+ var RELEASE_READY_POLL_MS = 250;
25015
+ var RELEASE_READY_TIMEOUT_MS = 30000;
25016
+ var RELEASE_STABILITY_MS = 2000;
25017
+ var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
25018
+ var exists2 = async (path) => {
25019
+ try {
25020
+ await access6(path);
25021
+ return true;
25022
+ } catch {
25023
+ return false;
25024
+ }
25025
+ };
25026
+ var sha256 = async (path) => createHash5("sha256").update(await readFile6(path)).digest("hex");
25027
+ var inside = (root, candidate) => {
25028
+ const path = relative4(resolve4(root), resolve4(candidate));
25029
+ return path === "" || !isAbsolute3(path) && path !== ".." && !path.startsWith(`..${sep3}`);
25030
+ };
25031
+ var requireString = (value, name) => {
25032
+ if (typeof value !== "string" || !value)
25033
+ throw new TypeError(`Android release ${name} is invalid.`);
25034
+ return value;
25035
+ };
25036
+ var parseMetadata = (value) => {
25037
+ if (!isRecord2(value))
25038
+ throw new TypeError("Android release metadata must contain an object.");
25039
+ const { bytes } = value;
25040
+ const { versionCode } = value;
25041
+ if (!Number.isSafeInteger(bytes) || Number(bytes) < 1)
25042
+ throw new TypeError("Android release bytes is invalid.");
25043
+ if (versionCode !== undefined && (!Number.isSafeInteger(versionCode) || Number(versionCode) < 1))
25044
+ throw new TypeError("Android release versionCode is invalid.");
25045
+ if (value.format !== 1 || value.platform !== "android" || value.type !== "aab" || value.engine !== "capacitor" && value.engine !== "expo" || typeof value.signed !== "boolean")
25046
+ throw new TypeError("Android release metadata contract is invalid.");
25047
+ const metadata = {
25048
+ appBuild: requireString(value.appBuild, "appBuild"),
25049
+ appId: requireString(value.appId, "appId"),
25050
+ artifact: requireString(value.artifact, "artifact"),
25051
+ bytes: Number(bytes),
25052
+ engine: value.engine,
25053
+ format: 1,
25054
+ platform: "android",
25055
+ releaseId: requireString(value.releaseId, "releaseId"),
25056
+ runtime: requireString(value.runtime, "runtime"),
25057
+ sha256: requireString(value.sha256, "sha256"),
25058
+ signed: value.signed,
25059
+ type: "aab",
25060
+ ...versionCode === undefined ? {} : { versionCode: Number(versionCode) }
25061
+ };
25062
+ if (!/^[a-f0-9]{64}$/u.test(metadata.sha256))
25063
+ throw new TypeError("Android release sha256 is invalid.");
25064
+ if (metadata.releaseId !== `amobile_android_${metadata.sha256}`)
25065
+ throw new TypeError("Android release ID does not match its artifact digest.");
25066
+ return metadata;
25067
+ };
25068
+ var absoluteBundletoolPath = (root = process.env.ABSOLUTE_BUNDLETOOL_ROOT ?? join6(homedir2(), ".absolutejs", "tools", "bundletool")) => join6(root, ABSOLUTE_BUNDLETOOL_VERSION, "bundletool.jar");
25069
+ var inspectAbsoluteBundletool = async (root) => {
25070
+ const path = absoluteBundletoolPath(root);
25071
+ if (!await exists2(path))
25072
+ return { path, ready: false };
25073
+ if (await sha256(path) !== ABSOLUTE_BUNDLETOOL_SHA256)
25074
+ throw new TypeError(`Managed Bundletool ${ABSOLUTE_BUNDLETOOL_VERSION} failed checksum verification. Remove ${path} and rerun the command.`);
25075
+ return { path, ready: true };
25076
+ };
25077
+ var readAbsoluteAndroidRelease = async (projectRoot, requested) => {
25078
+ const root = resolve4(projectRoot);
25079
+ const selected = resolve4(root, requested);
25080
+ if (!inside(root, selected))
25081
+ throw new TypeError("mobile test android --release must remain inside the project.");
25082
+ const metadataPath = basename(selected) === "release.json" ? selected : join6(selected, "release.json");
25083
+ const releaseRoot = dirname3(metadataPath);
25084
+ const metadata = parseMetadata(JSON.parse(await readFile6(metadataPath, "utf8")));
25085
+ const artifactPath = resolve4(releaseRoot, metadata.artifact);
25086
+ if (!inside(releaseRoot, artifactPath) || basename(artifactPath) !== metadata.artifact)
25087
+ throw new TypeError("Android release artifact path is invalid.");
25088
+ const [artifactStat, artifactSha256] = await Promise.all([
25089
+ stat2(artifactPath),
25090
+ sha256(artifactPath)
25091
+ ]);
25092
+ if (artifactStat.size !== metadata.bytes || artifactSha256 !== metadata.sha256)
25093
+ throw new TypeError(`Immutable Android release ${metadata.releaseId} is missing or modified.`);
25094
+ return { artifactPath, metadata, metadataPath, releaseRoot };
25095
+ };
25096
+ var defaultDownload = async (url) => {
25097
+ const response = await fetch(url);
25098
+ if (!response.ok)
25099
+ throw new Error(`Bundletool download failed (${response.status}).`);
25100
+ return new Uint8Array(await response.arrayBuffer());
25101
+ };
25102
+ var ensureAbsoluteBundletool = async (options) => {
25103
+ const inspected = await inspectAbsoluteBundletool(options.root);
25104
+ if (inspected.ready)
25105
+ return inspected.path;
25106
+ if (!options.approved)
25107
+ throw new TypeError(`Bundletool ${ABSOLUTE_BUNDLETOOL_VERSION} is required. Rerun with --yes to download the checksum-pinned official release.`);
25108
+ const bytes = await (options.download ?? defaultDownload)(ABSOLUTE_BUNDLETOOL_URL);
25109
+ const digest = createHash5("sha256").update(bytes).digest("hex");
25110
+ if (digest !== ABSOLUTE_BUNDLETOOL_SHA256)
25111
+ throw new TypeError("Downloaded Bundletool failed checksum verification.");
25112
+ await mkdir4(dirname3(inspected.path), { recursive: true });
25113
+ const staging = await mkdtemp3(join6(dirname3(inspected.path), ".install-"));
25114
+ const candidate = join6(staging, "bundletool.jar");
25115
+ try {
25116
+ await writeFile5(candidate, bytes, { flag: "wx" });
25117
+ await rename5(candidate, inspected.path).catch(async (error) => {
25118
+ if (await exists2(inspected.path))
25119
+ return;
25120
+ throw error;
25121
+ });
25122
+ } finally {
25123
+ await rm4(staging, { force: true, recursive: true });
25124
+ }
25125
+ if (await sha256(inspected.path) !== ABSOLUTE_BUNDLETOOL_SHA256)
25126
+ throw new TypeError("Installed Bundletool failed checksum verification.");
25127
+ return inspected.path;
25128
+ };
25129
+ var defaultRun = async (command) => {
25130
+ const process2 = Bun.spawn(command, {
25131
+ stderr: "pipe",
25132
+ stdin: "ignore",
25133
+ stdout: "pipe"
25134
+ });
25135
+ const [exitCode, stderr, stdout] = await Promise.all([
25136
+ process2.exited,
25137
+ new Response(process2.stderr).text(),
25138
+ new Response(process2.stdout).text()
25139
+ ]);
25140
+ return { exitCode, stderr, stdout };
25141
+ };
25142
+ var requireSuccess2 = async (run, command, label) => {
25143
+ const result = await run(command);
25144
+ if (result.exitCode !== 0)
25145
+ throw new Error(`${label} failed: ${result.stderr.trim() || result.stdout.trim()}`);
25146
+ return result;
25147
+ };
25148
+ var adb = (path, serial, ...args) => [
25149
+ path,
25150
+ "-s",
25151
+ serial,
25152
+ ...args
25153
+ ];
25154
+ var waitForMarker = async (run, adbPath, serial, appId, timeoutMs) => {
25155
+ const startedAt = performance.now();
25156
+ const inspect = async () => {
25157
+ if (performance.now() - startedAt >= timeoutMs)
25158
+ throw new Error("The installed release launched but its embedded web content did not become ready offline.");
25159
+ const [logs, process2] = await Promise.all([
25160
+ run(adb(adbPath, serial, "logcat", "-d", "-s", "AbsoluteJS:I", "*:S")),
25161
+ run(adb(adbPath, serial, "shell", "pidof", appId))
25162
+ ]);
25163
+ if (process2.exitCode !== 0 || !process2.stdout.trim())
25164
+ throw new Error("The installed Android release exited before becoming ready.");
25165
+ if (logs.stdout.includes(EMBEDDED_READY_MARKER))
25166
+ return;
25167
+ const failedPhase = /Expo embedded web phase: (assets-(?:root|directory|destination|module|source|download|copy|read|write|finalize|unexpected)|devices)-failed/u.exec(logs.stdout)?.[1];
25168
+ if (failedPhase)
25169
+ throw new Error(`The installed release could not initialize its embedded ${failedPhase} runtime offline.`);
25170
+ await Bun.sleep(RELEASE_READY_POLL_MS);
25171
+ await inspect();
25172
+ };
25173
+ return inspect();
25174
+ };
25175
+ var launch = async (run, adbPath, serial, appId, launchUrl) => {
25176
+ const resolved = await requireSuccess2(run, adb(adbPath, serial, "shell", "cmd", "package", "resolve-activity", "--brief", appId), "Android launch activity discovery");
25177
+ const activity = resolved.stdout.split(/\r?\n/u).map((line) => line.trim()).findLast((line) => line.includes("/"));
25178
+ if (!activity)
25179
+ throw new Error(`Android could not resolve a launch activity for ${appId}.`);
25180
+ const startedAt = performance.now();
25181
+ await requireSuccess2(run, adb(adbPath, serial, "shell", "am", "start", "-W", "-n", activity, ...launchUrl ? ["-a", "android.intent.action.VIEW", "-d", launchUrl] : []), "Android release launch");
25182
+ return Math.round(performance.now() - startedAt);
25183
+ };
25184
+ var runAbsoluteAndroidReleaseAcceptance = async (options) => {
25185
+ if (options.release.metadata.engine !== "expo")
25186
+ throw new TypeError("Installed AAB release acceptance currently requires the Expo engine.");
25187
+ if (!options.serial.startsWith("emulator-"))
25188
+ throw new TypeError("Installed release acceptance changes network state and therefore requires an Android emulator.");
25189
+ const run = options.run ?? defaultRun;
25190
+ const startedAt = performance.now();
25191
+ await mkdir4(options.artifactDirectory, { recursive: true });
25192
+ const apksPath = join6(options.artifactDirectory, "release.apks");
25193
+ const windowsJava = (options.host ?? detectAbsoluteMobileHost()) === "wsl" && options.java.toLowerCase().endsWith(".exe");
25194
+ const toolPath = async (path) => {
25195
+ if (!windowsJava)
25196
+ return path;
25197
+ const converted = await requireSuccess2(run, ["wslpath", "-w", path], "Bundletool Windows path translation");
25198
+ const translated = converted.stdout.trim();
25199
+ if (!translated)
25200
+ throw new Error(`Bundletool could not translate ${basename(path)} for the Windows JDK.`);
25201
+ return translated;
25202
+ };
25203
+ const [bundletoolPath, artifactPath, outputPath, adbPath] = await Promise.all([
25204
+ toolPath(options.bundletool),
25205
+ toolPath(options.release.artifactPath),
25206
+ toolPath(apksPath),
25207
+ toolPath(options.adb)
25208
+ ]);
25209
+ await requireSuccess2(run, [
25210
+ options.java,
25211
+ "-jar",
25212
+ bundletoolPath,
25213
+ "build-apks",
25214
+ `--bundle=${artifactPath}`,
25215
+ `--output=${outputPath}`,
25216
+ "--mode=universal",
25217
+ "--overwrite"
25218
+ ], "Bundletool APK generation");
25219
+ const installStartedAt = performance.now();
25220
+ await requireSuccess2(run, [
25221
+ options.java,
25222
+ "-jar",
25223
+ bundletoolPath,
25224
+ "install-apks",
25225
+ `--apks=${outputPath}`,
25226
+ `--adb=${adbPath}`,
25227
+ `--device-id=${options.serial}`
25228
+ ], "Bundletool release installation");
25229
+ const installMs = Math.round(performance.now() - installStartedAt);
25230
+ const installed = await inspectAbsoluteAndroidInstalledApp(options.adb, options.serial, options.release.metadata.appId, run);
25231
+ if (options.release.metadata.versionCode !== undefined && installed.versionCode !== options.release.metadata.versionCode)
25232
+ throw new Error(`Installed Android versionCode ${installed.versionCode ?? "unknown"} does not match release ${options.release.metadata.versionCode}.`);
25233
+ await requireSuccess2(run, adb(options.adb, options.serial, "logcat", "-c"), "Android release log isolation");
25234
+ const [wifi, mobile] = await Promise.all([
25235
+ requireSuccess2(run, adb(options.adb, options.serial, "shell", "settings", "get", "global", "wifi_on"), "Android Wi-Fi state inspection"),
25236
+ requireSuccess2(run, adb(options.adb, options.serial, "shell", "settings", "get", "global", "mobile_data"), "Android mobile-data state inspection")
25237
+ ]);
25238
+ let launchMs;
25239
+ let relaunchMs;
25240
+ try {
25241
+ await Promise.all([
25242
+ requireSuccess2(run, adb(options.adb, options.serial, "shell", "svc", "wifi", "disable"), "Android Wi-Fi disable"),
25243
+ requireSuccess2(run, adb(options.adb, options.serial, "shell", "svc", "data", "disable"), "Android mobile-data disable")
25244
+ ]);
25245
+ await requireSuccess2(run, adb(options.adb, options.serial, "shell", "am", "force-stop", options.release.metadata.appId), "Android release stop");
25246
+ launchMs = await launch(run, options.adb, options.serial, options.release.metadata.appId, options.launchUrl);
25247
+ await waitForMarker(run, options.adb, options.serial, options.release.metadata.appId, RELEASE_READY_TIMEOUT_MS);
25248
+ await Bun.sleep(options.stabilityMs ?? RELEASE_STABILITY_MS);
25249
+ await requireSuccess2(run, adb(options.adb, options.serial, "shell", "am", "force-stop", options.release.metadata.appId), "Android release relaunch stop");
25250
+ await requireSuccess2(run, adb(options.adb, options.serial, "logcat", "-c"), "Android release relaunch log isolation");
25251
+ relaunchMs = await launch(run, options.adb, options.serial, options.release.metadata.appId, options.launchUrl);
25252
+ await waitForMarker(run, options.adb, options.serial, options.release.metadata.appId, RELEASE_READY_TIMEOUT_MS);
25253
+ } finally {
25254
+ await Promise.all([
25255
+ requireSuccess2(run, adb(options.adb, options.serial, "shell", "svc", "wifi", wifi.stdout.trim() === "1" ? "enable" : "disable"), "Android Wi-Fi restore"),
25256
+ requireSuccess2(run, adb(options.adb, options.serial, "shell", "svc", "data", mobile.stdout.trim() === "1" ? "enable" : "disable"), "Android mobile-data restore")
25257
+ ]);
25258
+ }
25259
+ return {
25260
+ apksBytes: await stat2(apksPath).then(({ size }) => size),
25261
+ artifactBytes: options.release.metadata.bytes,
25262
+ artifactSha256: options.release.metadata.sha256,
25263
+ durationMs: Math.round(performance.now() - startedAt),
25264
+ embeddedOffline: true,
25265
+ engine: options.release.metadata.engine,
25266
+ installed: {
25267
+ ...installed.versionCode === undefined ? {} : { versionCode: installed.versionCode },
25268
+ ...installed.versionName === undefined ? {} : { versionName: installed.versionName }
25269
+ },
25270
+ installMs,
25271
+ launchMs,
25272
+ relaunchMs,
25273
+ releaseId: options.release.metadata.releaseId,
25274
+ signed: options.release.metadata.signed,
25275
+ status: "pass"
25276
+ };
25277
+ };
24969
25278
  // src/mobile/iosRelease.ts
24970
- import { createHash as createHash5 } from "crypto";
25279
+ import { createHash as createHash6 } from "crypto";
24971
25280
  import {
24972
- access as access6,
25281
+ access as access7,
24973
25282
  copyFile as copyFile3,
24974
- mkdir as mkdir4,
24975
- mkdtemp as mkdtemp3,
25283
+ mkdir as mkdir5,
25284
+ mkdtemp as mkdtemp4,
24976
25285
  readdir as readdir3,
24977
- readFile as readFile6,
24978
- rename as rename5,
24979
- rm as rm4,
24980
- stat as stat2,
24981
- writeFile as writeFile5
25286
+ readFile as readFile7,
25287
+ rename as rename6,
25288
+ rm as rm5,
25289
+ stat as stat3,
25290
+ writeFile as writeFile6
24982
25291
  } from "fs/promises";
24983
- import { dirname as dirname3, isAbsolute as isAbsolute3, join as join6, relative as relative4, resolve as resolve4, sep as sep3 } from "path";
25292
+ import { dirname as dirname4, isAbsolute as isAbsolute4, join as join7, relative as relative5, resolve as resolve5, sep as sep4 } from "path";
24984
25293
  var ABSOLUTE_IOS_RELEASE_FORMAT = 1;
24985
25294
  var developmentTeamArgument = (value) => {
24986
25295
  if (value === undefined)
@@ -24990,9 +25299,9 @@ var developmentTeamArgument = (value) => {
24990
25299
  throw new TypeError("iOS development team must contain ten letters or digits.");
24991
25300
  return `DEVELOPMENT_TEAM=${team}`;
24992
25301
  };
24993
- var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
25302
+ var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
24994
25303
  var requireManifest2 = (value) => {
24995
- if (!isRecord2(value) || typeof value.appBuild !== "string" || typeof value.appId !== "string" || typeof value.runtime !== "string") {
25304
+ if (!isRecord3(value) || typeof value.appBuild !== "string" || typeof value.appId !== "string" || typeof value.runtime !== "string") {
24996
25305
  throw new TypeError("Invalid embedded AbsoluteJS mobile manifest.");
24997
25306
  }
24998
25307
  return {
@@ -25003,13 +25312,13 @@ var requireManifest2 = (value) => {
25003
25312
  };
25004
25313
  var pathExists4 = async (path) => {
25005
25314
  try {
25006
- await access6(path);
25315
+ await access7(path);
25007
25316
  return true;
25008
25317
  } catch {
25009
25318
  return false;
25010
25319
  }
25011
25320
  };
25012
- var defaultRun = async (command, options = {}) => {
25321
+ var defaultRun2 = async (command, options = {}) => {
25013
25322
  const process2 = Bun.spawn(command, {
25014
25323
  cwd: options.cwd,
25015
25324
  env: options.env,
@@ -25050,8 +25359,8 @@ var ignoredFingerprintDirectories = new Set([
25050
25359
  var fingerprintFiles = async (root, current = root, options = {}) => {
25051
25360
  const entries = await readdir3(current, { withFileTypes: true });
25052
25361
  const nested = await Promise.all(entries.sort((left, right) => left.name.localeCompare(right.name)).map(async (entry) => {
25053
- const path = join6(current, entry.name);
25054
- const projectRelative = relative4(root, path).replaceAll("\\", "/");
25362
+ const path = join7(current, entry.name);
25363
+ const projectRelative = relative5(root, path).replaceAll("\\", "/");
25055
25364
  const ignored = entry.isDirectory() && (ignoredFingerprintDirectories.has(entry.name) || projectRelative === "App/App/public" && options.includePublicBundle !== true);
25056
25365
  if (ignored)
25057
25366
  return [];
@@ -25062,11 +25371,11 @@ var fingerprintFiles = async (root, current = root, options = {}) => {
25062
25371
  return nested.flat();
25063
25372
  };
25064
25373
  var fingerprintAbsoluteIosNativeProject = async (nativeDirectory, options = {}) => {
25065
- const hasher = createHash5("sha256");
25374
+ const hasher = createHash6("sha256");
25066
25375
  const files = await fingerprintFiles(nativeDirectory, nativeDirectory, options);
25067
- const contents = await Promise.all(files.map((file) => readFile6(file)));
25376
+ const contents = await Promise.all(files.map((file) => readFile7(file)));
25068
25377
  files.forEach((file, index) => {
25069
- hasher.update(relative4(nativeDirectory, file).replaceAll("\\", "/"));
25378
+ hasher.update(relative5(nativeDirectory, file).replaceAll("\\", "/"));
25070
25379
  hasher.update("\x00");
25071
25380
  hasher.update(contents[index] ?? new Uint8Array);
25072
25381
  hasher.update("\x00");
@@ -25074,21 +25383,21 @@ var fingerprintAbsoluteIosNativeProject = async (nativeDirectory, options = {})
25074
25383
  return hasher.digest("hex");
25075
25384
  };
25076
25385
  var safeOutputDirectory2 = (projectRoot, requested) => {
25077
- const root = resolve4(projectRoot);
25078
- const output = resolve4(root, requested ?? ".absolutejs/mobile/releases/ios");
25079
- const projectRelative = relative4(root, output);
25080
- if (projectRelative === ".." || projectRelative.startsWith(`..${sep3}`) || isAbsolute3(projectRelative)) {
25386
+ const root = resolve5(projectRoot);
25387
+ const output = resolve5(root, requested ?? ".absolutejs/mobile/releases/ios");
25388
+ const projectRelative = relative5(root, output);
25389
+ if (projectRelative === ".." || projectRelative.startsWith(`..${sep4}`) || isAbsolute4(projectRelative)) {
25081
25390
  throw new TypeError("mobile build --outdir must remain inside the project.");
25082
25391
  }
25083
25392
  return output;
25084
25393
  };
25085
- var sha256File2 = async (path) => createHash5("sha256").update(await readFile6(path)).digest("hex");
25394
+ var sha256File2 = async (path) => createHash6("sha256").update(await readFile7(path)).digest("hex");
25086
25395
  var findByExtension = async (root, extension) => {
25087
25396
  if (!await pathExists4(root))
25088
25397
  return;
25089
25398
  const entries = await readdir3(root, { withFileTypes: true });
25090
25399
  const matches2 = await Promise.all(entries.map(async (entry) => {
25091
- const path = join6(root, entry.name);
25400
+ const path = join7(root, entry.name);
25092
25401
  if (entry.isDirectory() && entry.name.endsWith(extension))
25093
25402
  return path;
25094
25403
  if (entry.isFile() && entry.name.endsWith(extension))
@@ -25102,7 +25411,7 @@ var findAllByExtension = async (root, extension, options = {}) => {
25102
25411
  return [];
25103
25412
  const entries = await readdir3(root, { withFileTypes: true });
25104
25413
  const matches2 = await Promise.all(entries.map(async (entry) => {
25105
- const path = join6(root, entry.name);
25414
+ const path = join7(root, entry.name);
25106
25415
  if (entry.name.endsWith(extension))
25107
25416
  return [path];
25108
25417
  if (!entry.isDirectory() || options.excludedDirectories?.has(entry.name))
@@ -25112,17 +25421,17 @@ var findAllByExtension = async (root, extension, options = {}) => {
25112
25421
  return matches2.flat().sort();
25113
25422
  };
25114
25423
  var resolveAbsoluteIosXcodeProject = async (nativeDirectory, options = {}) => {
25115
- const requestedWorkspace = options.workspacePath ? resolve4(nativeDirectory, options.workspacePath) : undefined;
25424
+ const requestedWorkspace = options.workspacePath ? resolve5(nativeDirectory, options.workspacePath) : undefined;
25116
25425
  if (requestedWorkspace) {
25117
- const requestedRelative = relative4(nativeDirectory, requestedWorkspace);
25118
- if (requestedRelative === ".." || requestedRelative.startsWith(`..${sep3}`) || isAbsolute3(requestedRelative))
25426
+ const requestedRelative = relative5(nativeDirectory, requestedWorkspace);
25427
+ if (requestedRelative === ".." || requestedRelative.startsWith(`..${sep4}`) || isAbsolute4(requestedRelative))
25119
25428
  throw new TypeError("iOS release workspacePath must remain inside the native iOS project.");
25120
25429
  }
25121
25430
  const workspaces = requestedWorkspace ? [requestedWorkspace] : await findAllByExtension(nativeDirectory, ".xcworkspace", {
25122
25431
  excludedDirectories: new Set(["Pods", "DerivedData", "build"])
25123
25432
  });
25124
25433
  if (workspaces.length !== 1)
25125
- throw new TypeError(workspaces.length > 1 ? `iOS release found multiple Xcode workspaces: ${workspaces.map((path) => relative4(nativeDirectory, path)).join(", ")}. Pass an explicit workspacePath.` : "iOS release could not find an Xcode workspace.");
25434
+ throw new TypeError(workspaces.length > 1 ? `iOS release found multiple Xcode workspaces: ${workspaces.map((path) => relative5(nativeDirectory, path)).join(", ")}. Pass an explicit workspacePath.` : "iOS release could not find an Xcode workspace.");
25126
25435
  const [workspacePath] = workspaces;
25127
25436
  if (!workspacePath || !await pathExists4(workspacePath))
25128
25437
  throw new TypeError("iOS release could not find an Xcode workspace.");
@@ -25132,7 +25441,7 @@ var resolveAbsoluteIosXcodeProject = async (nativeDirectory, options = {}) => {
25132
25441
  excludedDirectories: new Set(["Pods", "DerivedData", "build"])
25133
25442
  });
25134
25443
  const schemes = [
25135
- ...new Set(schemeFiles.map((path) => path.slice(path.lastIndexOf(sep3) + 1, -".xcscheme".length)))
25444
+ ...new Set(schemeFiles.map((path) => path.slice(path.lastIndexOf(sep4) + 1, -".xcscheme".length)))
25136
25445
  ];
25137
25446
  if (schemes.length !== 1 || !schemes[0])
25138
25447
  throw new TypeError(schemes.length > 1 ? `iOS release found multiple shared Xcode schemes: ${schemes.join(", ")}. Pass an explicit scheme.` : "iOS release could not find a shared Xcode scheme.");
@@ -25155,7 +25464,7 @@ var requireBuildNumber = (value) => {
25155
25464
  return value;
25156
25465
  };
25157
25466
  var requireAbsoluteIosReleaseMetadata = (value) => {
25158
- if (!isRecord2(value) || value.artifact !== "App.ipa" || typeof value.appBuild !== "string" || typeof value.appId !== "string" || typeof value.bytes !== "number" || !Number.isSafeInteger(value.bytes) || value.bytes < 1 || value.engine !== "capacitor" && value.engine !== "expo" || value.format !== ABSOLUTE_IOS_RELEASE_FORMAT || typeof value.marketingVersion !== "string" || value.platform !== "ios" || typeof value.releaseId !== "string" || typeof value.runtime !== "string" || typeof value.sha256 !== "string" || typeof value.signed !== "boolean" || value.type !== "ipa" || value.buildNumber !== undefined && (typeof value.buildNumber !== "number" || !Number.isSafeInteger(value.buildNumber) || value.buildNumber < 1) || !/^amobile_ios_[a-f0-9]{64}$/u.test(value.releaseId) || !/^[a-f0-9]{64}$/u.test(value.sha256) || value.releaseId !== `amobile_ios_${value.sha256}`) {
25467
+ if (!isRecord3(value) || value.artifact !== "App.ipa" || typeof value.appBuild !== "string" || typeof value.appId !== "string" || typeof value.bytes !== "number" || !Number.isSafeInteger(value.bytes) || value.bytes < 1 || value.engine !== "capacitor" && value.engine !== "expo" || value.format !== ABSOLUTE_IOS_RELEASE_FORMAT || typeof value.marketingVersion !== "string" || value.platform !== "ios" || typeof value.releaseId !== "string" || typeof value.runtime !== "string" || typeof value.sha256 !== "string" || typeof value.signed !== "boolean" || value.type !== "ipa" || value.buildNumber !== undefined && (typeof value.buildNumber !== "number" || !Number.isSafeInteger(value.buildNumber) || value.buildNumber < 1) || !/^amobile_ios_[a-f0-9]{64}$/u.test(value.releaseId) || !/^[a-f0-9]{64}$/u.test(value.sha256) || value.releaseId !== `amobile_ios_${value.sha256}`) {
25159
25468
  throw new TypeError("Invalid AbsoluteJS iOS release metadata.");
25160
25469
  }
25161
25470
  return {
@@ -25176,18 +25485,18 @@ var requireAbsoluteIosReleaseMetadata = (value) => {
25176
25485
  };
25177
25486
  };
25178
25487
  var installRelease2 = async (artifactPath, metadata, outputRoot) => {
25179
- const releaseRoot = join6(outputRoot, metadata.releaseId);
25180
- const destination = join6(releaseRoot, "App.ipa");
25488
+ const releaseRoot = join7(outputRoot, metadata.releaseId);
25489
+ const destination = join7(releaseRoot, "App.ipa");
25181
25490
  if (await pathExists4(releaseRoot)) {
25182
- const value = JSON.parse(await readFile6(join6(releaseRoot, "release.json"), "utf8"));
25183
- if (!isRecord2(value) || value.artifact !== "App.ipa" || Object.entries(metadata).some(([key, expected]) => Reflect.get(value, key) !== expected)) {
25491
+ const value = JSON.parse(await readFile7(join7(releaseRoot, "release.json"), "utf8"));
25492
+ if (!isRecord3(value) || value.artifact !== "App.ipa" || Object.entries(metadata).some(([key, expected]) => Reflect.get(value, key) !== expected)) {
25184
25493
  throw new TypeError(`Immutable iOS release ${metadata.releaseId} does not match its content.`);
25185
25494
  }
25186
- const [bytes, sha256] = await Promise.all([
25187
- stat2(destination).then(({ size }) => size),
25495
+ const [bytes, sha2562] = await Promise.all([
25496
+ stat3(destination).then(({ size }) => size),
25188
25497
  sha256File2(destination)
25189
25498
  ]);
25190
- if (bytes !== metadata.bytes || sha256 !== metadata.sha256)
25499
+ if (bytes !== metadata.bytes || sha2562 !== metadata.sha256)
25191
25500
  throw new TypeError(`Immutable iOS release ${metadata.releaseId} artifact is missing or modified.`);
25192
25501
  return {
25193
25502
  artifactPath: destination,
@@ -25198,20 +25507,20 @@ var installRelease2 = async (artifactPath, metadata, outputRoot) => {
25198
25507
  releaseRoot
25199
25508
  };
25200
25509
  }
25201
- await mkdir4(dirname3(releaseRoot), { recursive: true });
25202
- const staging = await mkdtemp3(join6(dirname3(releaseRoot), ".ios-stage-"));
25510
+ await mkdir5(dirname4(releaseRoot), { recursive: true });
25511
+ const staging = await mkdtemp4(join7(dirname4(releaseRoot), ".ios-stage-"));
25203
25512
  try {
25204
- await copyFile3(artifactPath, join6(staging, "App.ipa"));
25513
+ await copyFile3(artifactPath, join7(staging, "App.ipa"));
25205
25514
  const complete = {
25206
25515
  ...metadata,
25207
25516
  artifact: "App.ipa"
25208
25517
  };
25209
- await writeFile5(join6(staging, "release.json"), `${JSON.stringify(complete, null, "\t")}
25518
+ await writeFile6(join7(staging, "release.json"), `${JSON.stringify(complete, null, "\t")}
25210
25519
  `, { flag: "wx" });
25211
- await rename5(staging, releaseRoot);
25520
+ await rename6(staging, releaseRoot);
25212
25521
  return { artifactPath: destination, metadata: complete, releaseRoot };
25213
25522
  } finally {
25214
- await rm4(staging, { force: true, recursive: true }).catch(() => {
25523
+ await rm5(staging, { force: true, recursive: true }).catch(() => {
25215
25524
  return;
25216
25525
  });
25217
25526
  }
@@ -25224,10 +25533,10 @@ var buildAbsoluteIosRelease = async (options) => {
25224
25533
  const marketingVersion = options.config.iosVersion;
25225
25534
  if (!marketingVersion)
25226
25535
  throw new TypeError("iOS release builds require mobile.ios.version in absolutejs.config.ts.");
25227
- const manifest = requireManifest2(JSON.parse(await readFile6(join6(options.config.bundleDirectory, "absolute-mobile-manifest.json"), "utf8")));
25536
+ const manifest = requireManifest2(JSON.parse(await readFile7(join7(options.config.bundleDirectory, "absolute-mobile-manifest.json"), "utf8")));
25228
25537
  if (manifest.appId !== options.config.appId)
25229
25538
  throw new TypeError("Embedded mobile manifest appId does not match mobile.appId.");
25230
- const nativeDirectory = join6(options.config.nativeProjectDirectory, "ios");
25539
+ const nativeDirectory = join7(options.config.nativeProjectDirectory, "ios");
25231
25540
  const xcode = await resolveAbsoluteIosXcodeProject(nativeDirectory, {
25232
25541
  scheme: options.scheme,
25233
25542
  workspacePath: options.workspacePath
@@ -25235,18 +25544,18 @@ var buildAbsoluteIosRelease = async (options) => {
25235
25544
  let buildNumber = requireBuildNumber(options.buildNumber);
25236
25545
  if (options.prepareBuildNumber) {
25237
25546
  const nativeFingerprint = await fingerprintAbsoluteIosNativeProject(nativeDirectory);
25238
- const buildIdentity = createHash5("sha256").update(`${manifest.appBuild}\x00${nativeFingerprint}\x00${marketingVersion}`).digest("hex");
25547
+ const buildIdentity = createHash6("sha256").update(`${manifest.appBuild}\x00${nativeFingerprint}\x00${marketingVersion}`).digest("hex");
25239
25548
  buildNumber = requireBuildNumber(await options.prepareBuildNumber(buildIdentity));
25240
25549
  }
25241
- const stagingParent = resolve4(options.projectRoot, ".absolutejs/mobile");
25242
- await mkdir4(stagingParent, { recursive: true });
25243
- const staging = await mkdtemp3(join6(stagingParent, ".ios-build-"));
25244
- const archivePath = join6(staging, "App.xcarchive");
25245
- const exportPath = join6(staging, "export");
25246
- const exportPlist = join6(staging, "ExportOptions.plist");
25247
- await mkdir4(exportPath, { recursive: true });
25248
- await writeFile5(exportPlist, exportOptions());
25249
- const run = options.run ?? defaultRun;
25550
+ const stagingParent = resolve5(options.projectRoot, ".absolutejs/mobile");
25551
+ await mkdir5(stagingParent, { recursive: true });
25552
+ const staging = await mkdtemp4(join7(stagingParent, ".ios-build-"));
25553
+ const archivePath = join7(staging, "App.xcarchive");
25554
+ const exportPath = join7(staging, "export");
25555
+ const exportPlist = join7(staging, "ExportOptions.plist");
25556
+ await mkdir5(exportPath, { recursive: true });
25557
+ await writeFile6(exportPlist, exportOptions());
25558
+ const run = options.run ?? defaultRun2;
25250
25559
  try {
25251
25560
  const developmentTeam = developmentTeamArgument(options.developmentTeam);
25252
25561
  const versionArguments = [
@@ -25271,7 +25580,7 @@ var buildAbsoluteIosRelease = async (options) => {
25271
25580
  ], { cwd: nativeDirectory, env: options.env });
25272
25581
  if (archiveExit !== 0)
25273
25582
  throw new TypeError("Xcode failed to archive the iOS app.");
25274
- const archivedApp = await findByExtension(join6(archivePath, "Products", "Applications"), ".app");
25583
+ const archivedApp = await findByExtension(join7(archivePath, "Products", "Applications"), ".app");
25275
25584
  const capture = options.capture ?? defaultCapture2;
25276
25585
  const signed = archivedApp ? capture([
25277
25586
  "codesign",
@@ -25297,11 +25606,11 @@ var buildAbsoluteIosRelease = async (options) => {
25297
25606
  const artifactPath = await findByExtension(exportPath, ".ipa");
25298
25607
  if (!artifactPath)
25299
25608
  throw new TypeError("Xcode did not produce an exported IPA.");
25300
- const [bytes, sha256] = await Promise.all([
25301
- stat2(artifactPath).then(({ size }) => size),
25609
+ const [bytes, sha2562] = await Promise.all([
25610
+ stat3(artifactPath).then(({ size }) => size),
25302
25611
  sha256File2(artifactPath)
25303
25612
  ]);
25304
- const releaseId = `amobile_ios_${sha256}`;
25613
+ const releaseId = `amobile_ios_${sha2562}`;
25305
25614
  return await installRelease2(artifactPath, {
25306
25615
  appBuild: manifest.appBuild,
25307
25616
  appId: manifest.appId,
@@ -25313,23 +25622,23 @@ var buildAbsoluteIosRelease = async (options) => {
25313
25622
  platform: "ios",
25314
25623
  releaseId,
25315
25624
  runtime: manifest.runtime,
25316
- sha256,
25625
+ sha256: sha2562,
25317
25626
  signed,
25318
25627
  type: "ipa"
25319
25628
  }, safeOutputDirectory2(options.projectRoot, options.outputDirectory));
25320
25629
  } finally {
25321
- await rm4(staging, { force: true, recursive: true }).catch(() => {
25630
+ await rm5(staging, { force: true, recursive: true }).catch(() => {
25322
25631
  return;
25323
25632
  });
25324
25633
  }
25325
25634
  };
25326
25635
  var installAbsoluteIosRelease = async (options) => {
25327
25636
  const metadata = requireAbsoluteIosReleaseMetadata(options.metadata);
25328
- const [bytes, sha256] = await Promise.all([
25329
- stat2(options.artifactPath).then(({ size }) => size),
25637
+ const [bytes, sha2562] = await Promise.all([
25638
+ stat3(options.artifactPath).then(({ size }) => size),
25330
25639
  sha256File2(options.artifactPath)
25331
25640
  ]);
25332
- if (bytes !== metadata.bytes || sha256 !== metadata.sha256)
25641
+ if (bytes !== metadata.bytes || sha2562 !== metadata.sha256)
25333
25642
  throw new TypeError("Remote iOS release artifact does not match its signed metadata.");
25334
25643
  const { artifact: _artifact, ...releaseMetadata } = metadata;
25335
25644
  return installRelease2(options.artifactPath, releaseMetadata, safeOutputDirectory2(options.projectRoot, options.outputDirectory));
@@ -25405,7 +25714,7 @@ var assertAbsoluteIosInstalledAppUpgrade = (before, after) => {
25405
25714
  throw new Error(`iOS CFBundleVersion did not increase (${before.buildNumber} -> ${after.buildNumber}).`);
25406
25715
  };
25407
25716
  // src/mobile/iosConformance.ts
25408
- import { readFile as readFile7, stat as stat3 } from "fs/promises";
25717
+ import { readFile as readFile8, stat as stat4 } from "fs/promises";
25409
25718
  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");
25410
25719
  var parseAbsoluteIosHmrLog = (line) => {
25411
25720
  const match = HMR_LINE.exec(line);
@@ -25437,13 +25746,13 @@ var waitForAbsoluteIosHmrLog = async (options) => {
25437
25746
  const sleep = options.sleep ?? Bun.sleep;
25438
25747
  const timeoutMs = options.timeoutMs ?? 30000;
25439
25748
  const deadline = Date.now() + timeoutMs;
25440
- let offset = options.startOffset ?? await stat3(options.logPath).then(({ size }) => size).catch(() => 0);
25749
+ let offset = options.startOffset ?? await stat4(options.logPath).then(({ size }) => size).catch(() => 0);
25441
25750
  let buffered = "";
25442
25751
  const poll = async () => {
25443
25752
  if (Date.now() > deadline)
25444
25753
  throw new Error(`No iOS native HMR acknowledgement was observed within ${timeoutMs}ms.`);
25445
25754
  options.signal?.throwIfAborted();
25446
- const contents = await readFile7(options.logPath).catch(() => Buffer.alloc(0));
25755
+ const contents = await readFile8(options.logPath).catch(() => Buffer.alloc(0));
25447
25756
  if (contents.byteLength < offset) {
25448
25757
  offset = 0;
25449
25758
  buffered = "";
@@ -25463,28 +25772,28 @@ var waitForAbsoluteIosHmrLog = async (options) => {
25463
25772
  return poll();
25464
25773
  };
25465
25774
  // src/mobile/iosSimulatorController.ts
25466
- import { createHash as createHash6, randomUUID as randomUUID3 } from "crypto";
25775
+ import { createHash as createHash7, randomUUID as randomUUID3 } from "crypto";
25467
25776
  import {
25468
- access as access7,
25777
+ access as access8,
25469
25778
  copyFile as copyFile4,
25470
- mkdir as mkdir5,
25471
- readFile as readFile8,
25472
- rename as rename6,
25473
- rm as rm5,
25474
- writeFile as writeFile6
25779
+ mkdir as mkdir6,
25780
+ readFile as readFile9,
25781
+ rename as rename7,
25782
+ rm as rm6,
25783
+ writeFile as writeFile7
25475
25784
  } from "fs/promises";
25476
25785
  import { isIP as isIP2 } from "net";
25477
- import { dirname as dirname4, isAbsolute as isAbsolute4, join as join7, relative as relative5, resolve as resolve5, sep as sep4 } from "path";
25786
+ import { dirname as dirname5, isAbsolute as isAbsolute5, join as join8, relative as relative6, resolve as resolve6, sep as sep5 } from "path";
25478
25787
  init_getDurationString();
25479
25788
  var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone";
25480
25789
  var BOOT_TIMEOUT_MS = 180000;
25481
25790
  var BOOT_POLL_MS = 1000;
25482
25791
  var DEV_JOURNAL_FORMAT = 1;
25483
25792
  var NATIVE_CACHE_FORMAT = 1;
25484
- var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
25793
+ var isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
25485
25794
  var pathExists5 = async (path) => {
25486
25795
  try {
25487
- await access7(path);
25796
+ await access8(path);
25488
25797
  return true;
25489
25798
  } catch {
25490
25799
  return false;
@@ -25513,7 +25822,7 @@ var defaultCapture3 = (command, options = {}) => {
25513
25822
  };
25514
25823
  }
25515
25824
  };
25516
- var defaultRun2 = async (command, options = {}) => {
25825
+ var defaultRun3 = async (command, options = {}) => {
25517
25826
  const process2 = Bun.spawn(command, {
25518
25827
  cwd: options.cwd,
25519
25828
  env: options.env,
@@ -25579,7 +25888,7 @@ var defaultStartNativeLogs = (command, options, onLine) => {
25579
25888
  }
25580
25889
  };
25581
25890
  };
25582
- var requireSuccess2 = async (command, label, run, options) => {
25891
+ var requireSuccess3 = async (command, label, run, options) => {
25583
25892
  const exitCode = await run(command, options);
25584
25893
  if (exitCode !== 0)
25585
25894
  throw new Error(`${label} failed with status ${exitCode}.`);
@@ -25590,7 +25899,7 @@ var trustIosSimulatorDevelopmentCa = async (options, udid, run, log) => {
25590
25899
  if (!options.certificateAuthorityPath) {
25591
25900
  throw new Error("iOS Simulator HTTPS requires the AbsoluteJS development CA certificate.");
25592
25901
  }
25593
- await requireSuccess2([
25902
+ await requireSuccess3([
25594
25903
  options.project.xcrun,
25595
25904
  "simctl",
25596
25905
  "keychain",
@@ -25627,7 +25936,7 @@ var requireCapturedSuccess = (result, label) => {
25627
25936
  var parseJson = (source, label) => {
25628
25937
  try {
25629
25938
  const parsed = JSON.parse(source);
25630
- if (isRecord3(parsed))
25939
+ if (isRecord4(parsed))
25631
25940
  return parsed;
25632
25941
  } catch {}
25633
25942
  throw new Error(`Invalid ${label} JSON from simctl.`);
@@ -25638,7 +25947,7 @@ var parseIosDeviceTypes = (source) => {
25638
25947
  if (!Array.isArray(types))
25639
25948
  return [];
25640
25949
  return types.flatMap((type) => {
25641
- if (!isRecord3(type))
25950
+ if (!isRecord4(type))
25642
25951
  return [];
25643
25952
  const { identifier } = type;
25644
25953
  const { name } = type;
@@ -25651,7 +25960,7 @@ var parseIosRuntimes = (source) => {
25651
25960
  if (!Array.isArray(runtimes))
25652
25961
  return [];
25653
25962
  return runtimes.flatMap((runtime) => {
25654
- if (!isRecord3(runtime))
25963
+ if (!isRecord4(runtime))
25655
25964
  return [];
25656
25965
  const { identifier } = runtime;
25657
25966
  const { name } = runtime;
@@ -25671,13 +25980,13 @@ var parseIosRuntimes = (source) => {
25671
25980
  var parseIosSimulators = (source) => {
25672
25981
  const parsed = parseJson(source, "device");
25673
25982
  const { devices } = parsed;
25674
- if (!isRecord3(devices))
25983
+ if (!isRecord4(devices))
25675
25984
  return [];
25676
25985
  return Object.entries(devices).flatMap(([runtime, values]) => {
25677
25986
  if (!Array.isArray(values))
25678
25987
  return [];
25679
25988
  return values.flatMap((device) => {
25680
- if (!isRecord3(device))
25989
+ if (!isRecord4(device))
25681
25990
  return [];
25682
25991
  const { name } = device;
25683
25992
  const { state } = device;
@@ -25719,21 +26028,21 @@ var preferredIphoneType = (types) => types.filter((type) => type.name.startsWith
25719
26028
  return rightPro - leftPro;
25720
26029
  })[0];
25721
26030
  var journalPaths = (projectRoot) => {
25722
- const root = join7(projectRoot, ".absolutejs", "mobile", "ios-dev-session");
26031
+ const root = join8(projectRoot, ".absolutejs", "mobile", "ios-dev-session");
25723
26032
  return {
25724
- configBackup: join7(root, "capacitor-config.backup"),
25725
- infoBackup: join7(root, "Info.plist.backup"),
25726
- journal: join7(root, "journal.json"),
26033
+ configBackup: join8(root, "capacitor-config.backup"),
26034
+ infoBackup: join8(root, "Info.plist.backup"),
26035
+ journal: join8(root, "journal.json"),
25727
26036
  root
25728
26037
  };
25729
26038
  };
25730
- var nativeCachePath = (projectRoot) => join7(projectRoot, ".absolutejs", "mobile", "ios-native-cache.json");
26039
+ var nativeCachePath = (projectRoot) => join8(projectRoot, ".absolutejs", "mobile", "ios-native-cache.json");
25731
26040
  var isInside = (root, path) => {
25732
- const value = relative5(resolve5(root), resolve5(path));
25733
- return value === "" || !value.startsWith(`..${sep4}`) && value !== ".." && !isAbsolute4(value);
26041
+ const value = relative6(resolve6(root), resolve6(path));
26042
+ return value === "" || !value.startsWith(`..${sep5}`) && value !== ".." && !isAbsolute5(value);
25734
26043
  };
25735
26044
  var parseJournal = (value) => {
25736
- if (!isRecord3(value) || value.format !== DEV_JOURNAL_FORMAT)
26045
+ if (!isRecord4(value) || value.format !== DEV_JOURNAL_FORMAT)
25737
26046
  return null;
25738
26047
  const { configBackupPath } = value;
25739
26048
  const { infoBackupPath } = value;
@@ -25752,10 +26061,10 @@ var parseJournal = (value) => {
25752
26061
  var repairAbsoluteIosDevSession = async (projectRoot) => {
25753
26062
  const paths = journalPaths(projectRoot);
25754
26063
  if (!await pathExists5(paths.journal)) {
25755
- await rm5(paths.root, { force: true, recursive: true });
26064
+ await rm6(paths.root, { force: true, recursive: true });
25756
26065
  return false;
25757
26066
  }
25758
- const journal = await readFile8(paths.journal, "utf8").then((source) => parseJournal(JSON.parse(source))).catch(() => null);
26067
+ const journal = await readFile9(paths.journal, "utf8").then((source) => parseJournal(JSON.parse(source))).catch(() => null);
25759
26068
  if (!journal || !isInside(projectRoot, journal.nativeConfigPath) || !isInside(projectRoot, journal.infoPath) || !isInside(paths.root, journal.configBackupPath) || !isInside(paths.root, journal.infoBackupPath)) {
25760
26069
  throw new Error(`Refusing unsafe or invalid iOS dev journal at ${paths.journal}.`);
25761
26070
  }
@@ -25763,7 +26072,7 @@ var repairAbsoluteIosDevSession = async (projectRoot) => {
25763
26072
  await copyFile4(journal.configBackupPath, journal.nativeConfigPath);
25764
26073
  if (await pathExists5(journal.infoBackupPath))
25765
26074
  await copyFile4(journal.infoBackupPath, journal.infoPath);
25766
- await rm5(paths.root, { force: true, recursive: true });
26075
+ await rm6(paths.root, { force: true, recursive: true });
25767
26076
  return true;
25768
26077
  };
25769
26078
  var iosDevelopmentInfoPlist = (source, cleartext) => {
@@ -25789,19 +26098,19 @@ var iosDevelopmentInfoPlist = (source, cleartext) => {
25789
26098
  var writeDevProjection = async (project, port, https, serverHost = "localhost") => {
25790
26099
  const paths = journalPaths(project.projectRoot);
25791
26100
  await repairAbsoluteIosDevSession(project.projectRoot);
25792
- const nativeConfigPath = join7(project.nativeDirectory, "App", "App", "capacitor.config.json");
25793
- const infoPath = join7(project.nativeDirectory, "App", "App", "Info.plist");
26101
+ const nativeConfigPath = join8(project.nativeDirectory, "App", "App", "capacitor.config.json");
26102
+ const infoPath = join8(project.nativeDirectory, "App", "App", "Info.plist");
25794
26103
  const [configSource, infoSource] = await Promise.all([
25795
- readFile8(nativeConfigPath, "utf8"),
25796
- readFile8(infoPath, "utf8")
26104
+ readFile9(nativeConfigPath, "utf8"),
26105
+ readFile9(infoPath, "utf8")
25797
26106
  ]);
25798
26107
  const parsed = JSON.parse(configSource);
25799
- if (!isRecord3(parsed))
26108
+ if (!isRecord4(parsed))
25800
26109
  throw new Error(`Invalid Capacitor native config at ${nativeConfigPath}.`);
25801
- await mkdir5(paths.root, { recursive: true });
26110
+ await mkdir6(paths.root, { recursive: true });
25802
26111
  await Promise.all([
25803
- writeFile6(paths.configBackup, configSource, { flag: "wx" }),
25804
- writeFile6(paths.infoBackup, infoSource, { flag: "wx" })
26112
+ writeFile7(paths.configBackup, configSource, { flag: "wx" }),
26113
+ writeFile7(paths.infoBackup, infoSource, { flag: "wx" })
25805
26114
  ]);
25806
26115
  const journal = {
25807
26116
  configBackupPath: paths.configBackup,
@@ -25810,7 +26119,7 @@ var writeDevProjection = async (project, port, https, serverHost = "localhost")
25810
26119
  infoPath,
25811
26120
  nativeConfigPath
25812
26121
  };
25813
- await writeFile6(paths.journal, `${JSON.stringify(journal, null, "\t")}
26122
+ await writeFile7(paths.journal, `${JSON.stringify(journal, null, "\t")}
25814
26123
  `, {
25815
26124
  flag: "wx"
25816
26125
  });
@@ -25819,21 +26128,21 @@ var writeDevProjection = async (project, port, https, serverHost = "localhost")
25819
26128
  developmentUrl.searchParams.set("__absolute_target", "capacitor-ios");
25820
26129
  const existingServer = parsed.server;
25821
26130
  parsed.server = {
25822
- ...isRecord3(existingServer) ? existingServer : {},
26131
+ ...isRecord4(existingServer) ? existingServer : {},
25823
26132
  cleartext: !https,
25824
26133
  url: developmentUrl.href
25825
26134
  };
25826
26135
  await Promise.all([
25827
- writeFile6(nativeConfigPath, `${JSON.stringify(parsed, null, "\t")}
26136
+ writeFile7(nativeConfigPath, `${JSON.stringify(parsed, null, "\t")}
25828
26137
  `),
25829
- writeFile6(infoPath, iosDevelopmentInfoPlist(infoSource, !https))
26138
+ writeFile7(infoPath, iosDevelopmentInfoPlist(infoSource, !https))
25830
26139
  ]);
25831
26140
  };
25832
26141
  var parseNativeCache = (value) => {
25833
- if (!isRecord3(value))
26142
+ if (!isRecord4(value))
25834
26143
  return null;
25835
26144
  const { appId, fingerprint, format, installations } = value;
25836
- if (format !== NATIVE_CACHE_FORMAT || typeof appId !== "string" || typeof fingerprint !== "string" || !isRecord3(installations) || !Object.values(installations).every((identity) => typeof identity === "string"))
26145
+ if (format !== NATIVE_CACHE_FORMAT || typeof appId !== "string" || typeof fingerprint !== "string" || !isRecord4(installations) || !Object.values(installations).every((identity) => typeof identity === "string"))
25837
26146
  return null;
25838
26147
  return {
25839
26148
  appId,
@@ -25845,19 +26154,19 @@ var parseNativeCache = (value) => {
25845
26154
  ]))
25846
26155
  };
25847
26156
  };
25848
- var readNativeCache = (projectRoot) => readFile8(nativeCachePath(projectRoot), "utf8").then((source) => parseNativeCache(JSON.parse(source))).catch(() => null);
26157
+ var readNativeCache = (projectRoot) => readFile9(nativeCachePath(projectRoot), "utf8").then((source) => parseNativeCache(JSON.parse(source))).catch(() => null);
25849
26158
  var writeNativeCache = async (projectRoot, cache) => {
25850
26159
  const destination = nativeCachePath(projectRoot);
25851
26160
  const temporary = `${destination}.${process.pid}.${randomUUID3()}.tmp`;
25852
- await mkdir5(dirname4(destination), { recursive: true });
26161
+ await mkdir6(dirname5(destination), { recursive: true });
25853
26162
  try {
25854
- await writeFile6(temporary, `${JSON.stringify(cache, null, "\t")}
26163
+ await writeFile7(temporary, `${JSON.stringify(cache, null, "\t")}
25855
26164
  `, {
25856
26165
  flag: "wx"
25857
26166
  });
25858
- await rename6(temporary, destination);
26167
+ await rename7(temporary, destination);
25859
26168
  } finally {
25860
- await rm5(temporary, { force: true }).catch(() => {
26169
+ await rm6(temporary, { force: true }).catch(() => {
25861
26170
  return;
25862
26171
  });
25863
26172
  }
@@ -25963,12 +26272,12 @@ var physicalIosAppIsInstalled = (project, identifier, capture) => {
25963
26272
  return result.exitCode === 0 && result.stdout.includes(project.config.appId);
25964
26273
  };
25965
26274
  var buildIosDebugApp = async (project, udid, fingerprint, run, signal) => {
25966
- const derivedDataPath = join7(project.projectRoot, ".absolutejs", "mobile", "ios-derived-data", createHash6("sha256").update(project.config.appId).digest("hex").slice(0, 16));
25967
- await mkdir5(derivedDataPath, { recursive: true });
25968
- await requireSuccess2([
26275
+ const derivedDataPath = join8(project.projectRoot, ".absolutejs", "mobile", "ios-derived-data", createHash7("sha256").update(project.config.appId).digest("hex").slice(0, 16));
26276
+ await mkdir6(derivedDataPath, { recursive: true });
26277
+ await requireSuccess3([
25969
26278
  project.xcodebuild,
25970
26279
  "-workspace",
25971
- join7(project.nativeDirectory, "App", "App.xcworkspace"),
26280
+ join8(project.nativeDirectory, "App", "App.xcworkspace"),
25972
26281
  "-scheme",
25973
26282
  "App",
25974
26283
  "-configuration",
@@ -25979,18 +26288,18 @@ var buildIosDebugApp = async (project, udid, fingerprint, run, signal) => {
25979
26288
  derivedDataPath,
25980
26289
  "build"
25981
26290
  ], "iOS simulator build", run, { cwd: project.nativeDirectory, signal });
25982
- const appPath = join7(derivedDataPath, "Build", "Products", "Debug-iphonesimulator", "App.app");
26291
+ const appPath = join8(derivedDataPath, "Build", "Products", "Debug-iphonesimulator", "App.app");
25983
26292
  if (!await pathExists5(appPath))
25984
26293
  throw new Error(`Xcode did not produce the simulator app at ${appPath}.`);
25985
26294
  return appPath;
25986
26295
  };
25987
26296
  var buildPhysicalIosDebugApp = async (project, identifier, run, signal) => {
25988
- const derivedDataPath = join7(project.projectRoot, ".absolutejs", "mobile", "ios-derived-data", createHash6("sha256").update(project.config.appId).digest("hex").slice(0, 16));
25989
- await mkdir5(derivedDataPath, { recursive: true });
25990
- await requireSuccess2([
26297
+ const derivedDataPath = join8(project.projectRoot, ".absolutejs", "mobile", "ios-derived-data", createHash7("sha256").update(project.config.appId).digest("hex").slice(0, 16));
26298
+ await mkdir6(derivedDataPath, { recursive: true });
26299
+ await requireSuccess3([
25991
26300
  project.xcodebuild,
25992
26301
  "-workspace",
25993
- join7(project.nativeDirectory, "App", "App.xcworkspace"),
26302
+ join8(project.nativeDirectory, "App", "App.xcworkspace"),
25994
26303
  "-scheme",
25995
26304
  "App",
25996
26305
  "-configuration",
@@ -26002,7 +26311,7 @@ var buildPhysicalIosDebugApp = async (project, identifier, run, signal) => {
26002
26311
  "-allowProvisioningUpdates",
26003
26312
  "build"
26004
26313
  ], "iOS physical-device build (configure automatic signing and a Development Team in Xcode if this is the first run)", run, { cwd: project.nativeDirectory, signal });
26005
- const appPath = join7(derivedDataPath, "Build", "Products", "Debug-iphoneos", "App.app");
26314
+ const appPath = join8(derivedDataPath, "Build", "Products", "Debug-iphoneos", "App.app");
26006
26315
  if (!await pathExists5(appPath))
26007
26316
  throw new Error(`Xcode did not produce the physical-device app at ${appPath}.`);
26008
26317
  return appPath;
@@ -26018,7 +26327,7 @@ var ensurePhysicalIosDebugApp = async (options) => {
26018
26327
  const appPath = await buildPhysicalIosDebugApp(options.project, options.identifier, options.run, options.signal);
26019
26328
  throwIfAborted2(options.signal);
26020
26329
  options.transition("installing");
26021
- await requireSuccess2([
26330
+ await requireSuccess3([
26022
26331
  options.project.xcrun,
26023
26332
  "devicectl",
26024
26333
  "device",
@@ -26051,7 +26360,7 @@ var ensureIosDebugApp = async (options) => {
26051
26360
  const appPath = await buildIosDebugApp(options.project, options.udid, options.fingerprint, options.run, options.signal);
26052
26361
  throwIfAborted2(options.signal);
26053
26362
  options.transition("installing");
26054
- await requireSuccess2([options.project.xcrun, "simctl", "install", options.udid, appPath], "iOS simulator app installation", options.run, { signal: options.signal });
26363
+ await requireSuccess3([options.project.xcrun, "simctl", "install", options.udid, appPath], "iOS simulator app installation", options.run, { signal: options.signal });
26055
26364
  const updated = installedAppIdentity(options.project, options.udid, options.capture);
26056
26365
  if (updated) {
26057
26366
  await writeNativeCache(options.project.projectRoot, {
@@ -26137,7 +26446,7 @@ var prepareAbsoluteIosDevProject = async (config, options) => {
26137
26446
  if (detectAbsoluteMobileHost() !== "macos")
26138
26447
  throw new Error("iOS development requires macOS and Xcode.");
26139
26448
  const target = options.target ?? "simulator";
26140
- const projectRoot = resolve5(options.projectRoot);
26449
+ const projectRoot = resolve6(options.projectRoot);
26141
26450
  const checks = await inspectAbsoluteMobileToolchain({ host: "macos" });
26142
26451
  const failed = checks.filter((check) => check.platform === "ios" && !(target === "device" && check.id === "ios.runtime") && (check.status === "fail" || check.status === "warn"));
26143
26452
  if (failed.length > 0)
@@ -26146,20 +26455,20 @@ var prepareAbsoluteIosDevProject = async (config, options) => {
26146
26455
  const xcodebuild = checks.find((check) => check.id === "ios.xcodebuild")?.path;
26147
26456
  if (!xcrun || !xcodebuild)
26148
26457
  throw new Error("Xcode tools disappeared after readiness checks.");
26149
- const cap = join7(projectRoot, "node_modules", ".bin", "cap");
26458
+ const cap = join8(projectRoot, "node_modules", ".bin", "cap");
26150
26459
  if (!await pathExists5(cap))
26151
26460
  throw new Error("Capacitor CLI is not installed. Run absolute mobile init first.");
26152
26461
  await writeAbsoluteCapacitorConfig(config, { projectRoot });
26153
- await mkdir5(config.bundleDirectory, { recursive: true });
26154
- const placeholder = join7(config.bundleDirectory, "index.html");
26462
+ await mkdir6(config.bundleDirectory, { recursive: true });
26463
+ const placeholder = join8(config.bundleDirectory, "index.html");
26155
26464
  if (!await pathExists5(placeholder))
26156
- await writeFile6(placeholder, `<!doctype html><title>AbsoluteJS mobile development</title>
26465
+ await writeFile7(placeholder, `<!doctype html><title>AbsoluteJS mobile development</title>
26157
26466
  `);
26158
- const nativeDirectory = join7(config.nativeProjectDirectory, "ios");
26467
+ const nativeDirectory = join8(config.nativeProjectDirectory, "ios");
26159
26468
  if (!await pathExists5(nativeDirectory)) {
26160
26469
  if (!options.createNativeProject)
26161
26470
  throw new Error("iOS native project has not been created.");
26162
- const run = options.run ?? defaultRun2;
26471
+ const run = options.run ?? defaultRun3;
26163
26472
  if (await run([cap, "add", "ios"], { cwd: projectRoot }) !== 0)
26164
26473
  throw new Error("Capacitor iOS project creation failed.");
26165
26474
  }
@@ -26212,7 +26521,7 @@ var prepareIosSimulatorTarget = async (options) => {
26212
26521
  ]);
26213
26522
  options.transition("connecting");
26214
26523
  await waitForBootedSimulator(options.project, device.udid, options.capture, options.sleep, options.startOptions.signal);
26215
- await requireSuccess2([options.project.xcrun, "simctl", "bootstatus", device.udid, "-b"], "iOS simulator boot readiness", options.run, { signal: options.startOptions.signal });
26524
+ await requireSuccess3([options.project.xcrun, "simctl", "bootstatus", device.udid, "-b"], "iOS simulator boot readiness", options.run, { signal: options.startOptions.signal });
26216
26525
  await trustIosSimulatorDevelopmentCa(options.startOptions, device.udid, options.run, options.log);
26217
26526
  return { caEnrollmentServer: null, startedSimulator, udid: device.udid };
26218
26527
  };
@@ -26222,7 +26531,7 @@ var startAbsoluteIosDevSession = async (options) => {
26222
26531
  const targetKind = deviceIdentifier ? "device" : "simulator";
26223
26532
  const serverHost = deviceIdentifier ? normalizeAbsoluteIosDeviceHost(options.serverHost ?? "") : "localhost";
26224
26533
  const capture = options.capture ?? defaultCapture3;
26225
- const run = options.run ?? defaultRun2;
26534
+ const run = options.run ?? defaultRun3;
26226
26535
  const sleep = options.sleep ?? Bun.sleep;
26227
26536
  const spawn2 = options.spawn ?? defaultSpawn;
26228
26537
  const log = options.log ?? console.log;
@@ -26262,13 +26571,13 @@ var startAbsoluteIosDevSession = async (options) => {
26262
26571
  nativeLogs = attachNativeLogs(project, udid, options);
26263
26572
  return;
26264
26573
  }
26265
- await requireSuccess2(iosLaunchCommand(project, udid, deviceIdentifier !== undefined), "iOS app relaunch", run, { signal: options.signal });
26574
+ await requireSuccess3(iosLaunchCommand(project, udid, deviceIdentifier !== undefined), "iOS app relaunch", run, { signal: options.signal });
26266
26575
  };
26267
26576
  try {
26268
26577
  await repairAbsoluteIosDevSession(project.projectRoot);
26269
26578
  throwIfAborted2(options.signal);
26270
26579
  transition("syncing");
26271
- await requireSuccess2([project.cap, "sync", "ios"], "Capacitor iOS synchronization", run, { cwd: project.projectRoot, signal: options.signal });
26580
+ await requireSuccess3([project.cap, "sync", "ios"], "Capacitor iOS synchronization", run, { cwd: project.projectRoot, signal: options.signal });
26272
26581
  transition("configuring");
26273
26582
  if (options.embeddedBundle !== true)
26274
26583
  await writeDevProjection(project, options.port, options.https === true, serverHost);
@@ -26334,7 +26643,7 @@ var startAbsoluteIosDevSession = async (options) => {
26334
26643
  nativeLogs = attachNativeLogs(project, udid, options);
26335
26644
  transition("launching");
26336
26645
  if (!deviceIdentifier || !nativeLogs)
26337
- await requireSuccess2(iosLaunchCommand(project, udid, deviceIdentifier !== undefined), "iOS app launch", run, { signal: options.signal });
26646
+ await requireSuccess3(iosLaunchCommand(project, udid, deviceIdentifier !== undefined), "iOS app launch", run, { signal: options.signal });
26338
26647
  transition("ready");
26339
26648
  timings.total = performance.now() - startedAt;
26340
26649
  log(options.embeddedBundle === true ? `iOS ${targetKind} connected with the embedded bundle and backend on port ${options.port} in ${getDurationString(timings.total)} (${nativeCacheHit ? "native cache hit" : "native build installed"}).` : `iOS ${targetKind} connected with HMR on port ${options.port} in ${getDurationString(timings.total)} (${nativeCacheHit ? "native cache hit" : "native build installed"}).`);
@@ -26383,11 +26692,11 @@ var startAbsoluteIosDevSession = async (options) => {
26383
26692
  screenshot: async (destination) => {
26384
26693
  if (deviceIdentifier)
26385
26694
  throw new Error("Physical iOS screenshots are captured in Xcode Device Hub; the CLI never records a device screen automatically.");
26386
- const resolved = resolve5(project.projectRoot, destination);
26695
+ const resolved = resolve6(project.projectRoot, destination);
26387
26696
  if (!isInside(project.projectRoot, resolved))
26388
26697
  throw new Error("iOS screenshot destination must remain inside the project.");
26389
- await mkdir5(dirname4(resolved), { recursive: true });
26390
- await requireSuccess2([
26698
+ await mkdir6(dirname5(resolved), { recursive: true });
26699
+ await requireSuccess3([
26391
26700
  project.xcrun,
26392
26701
  "simctl",
26393
26702
  "io",
@@ -26413,7 +26722,7 @@ var startAbsoluteIosDevSession = async (options) => {
26413
26722
  };
26414
26723
  // src/mobile/iosNativeWatcher.ts
26415
26724
  import { watch } from "fs";
26416
- import { basename } from "path";
26725
+ import { basename as basename2 } from "path";
26417
26726
  var NATIVE_CHANGE_DEBOUNCE_MS = 500;
26418
26727
  var ROOT_NATIVE_INPUTS = new Set([
26419
26728
  "absolute.config.js",
@@ -26503,28 +26812,28 @@ var createAbsoluteIosNativeWatcher = async (options) => {
26503
26812
  options.signal?.addEventListener("abort", close, { once: true });
26504
26813
  return { close };
26505
26814
  };
26506
- var isAbsoluteIosNativeRootInput = (path) => ROOT_NATIVE_INPUTS.has(basename(path));
26815
+ var isAbsoluteIosNativeRootInput = (path) => ROOT_NATIVE_INPUTS.has(basename2(path));
26507
26816
  // src/mobile/remoteMacProtocol.ts
26508
- import { createHash as createHash7, randomUUID as randomUUID4 } from "crypto";
26817
+ import { createHash as createHash8, randomUUID as randomUUID4 } from "crypto";
26509
26818
  import {
26510
26819
  chmod,
26511
- mkdir as mkdir6,
26512
- mkdtemp as mkdtemp4,
26513
- readFile as readFile9,
26514
- rename as rename7,
26515
- rm as rm6,
26516
- writeFile as writeFile7
26820
+ mkdir as mkdir7,
26821
+ mkdtemp as mkdtemp5,
26822
+ readFile as readFile10,
26823
+ rename as rename8,
26824
+ rm as rm7,
26825
+ writeFile as writeFile8
26517
26826
  } from "fs/promises";
26518
- import { homedir as homedir2 } from "os";
26827
+ import { homedir as homedir3 } from "os";
26519
26828
  import { isIP as isIP3 } from "net";
26520
26829
  import {
26521
- dirname as dirname5,
26522
- isAbsolute as isAbsolute5,
26523
- join as join8,
26830
+ dirname as dirname6,
26831
+ isAbsolute as isAbsolute6,
26832
+ join as join9,
26524
26833
  posix,
26525
- relative as relative6,
26834
+ relative as relative7,
26526
26835
  resolve as resolvePath3,
26527
- sep as sep5
26836
+ sep as sep6
26528
26837
  } from "path";
26529
26838
 
26530
26839
  // src/mobile/remoteMacWire.ts
@@ -26539,14 +26848,14 @@ var REMOTE_RELEASE_LEASE_HEARTBEAT_MS = 15000;
26539
26848
  var REMOTE_RELEASE_LEASE_STALE_SECONDS = 120;
26540
26849
  var PROFILE_NAME = /^[a-z0-9](?:[a-z0-9._-]{0,62}[a-z0-9])?$/u;
26541
26850
  var SSH_DESTINATION = /^(?:[A-Za-z0-9._-]+@)?[A-Za-z0-9._:-]+$/u;
26542
- var defaultProfilePath = () => join8(homedir2(), ".absolutejs", "mobile", "remote-macs.json");
26851
+ var defaultProfilePath = () => join9(homedir3(), ".absolutejs", "mobile", "remote-macs.json");
26543
26852
  var emptyStore = () => ({
26544
26853
  format: PROFILE_FORMAT,
26545
26854
  profiles: {}
26546
26855
  });
26547
26856
  var loadStore = async (path = defaultProfilePath()) => {
26548
26857
  try {
26549
- const parsed = JSON.parse(await readFile9(path, "utf8"));
26858
+ const parsed = JSON.parse(await readFile10(path, "utf8"));
26550
26859
  if (parsed.format !== PROFILE_FORMAT || typeof parsed.profiles !== "object" || parsed.profiles === null || Array.isArray(parsed.profiles))
26551
26860
  throw new Error("Unsupported remote Mac profile format.");
26552
26861
  for (const [key, profile] of Object.entries(parsed.profiles)) {
@@ -26563,13 +26872,13 @@ var loadStore = async (path = defaultProfilePath()) => {
26563
26872
  }
26564
26873
  };
26565
26874
  var saveStore = async (store, path = defaultProfilePath()) => {
26566
- await mkdir6(dirname5(path), { recursive: true });
26875
+ await mkdir7(dirname6(path), { recursive: true });
26567
26876
  const temporary = `${path}.${randomUUID4()}.tmp`;
26568
- await writeFile7(temporary, `${JSON.stringify(store, null, 2)}
26877
+ await writeFile8(temporary, `${JSON.stringify(store, null, 2)}
26569
26878
  `, {
26570
26879
  mode: 384
26571
26880
  });
26572
- await rename7(temporary, path);
26881
+ await rename8(temporary, path);
26573
26882
  await chmod(path, 384);
26574
26883
  };
26575
26884
  var validateAbsoluteRemoteMacProfileName = (name) => {
@@ -26737,16 +27046,16 @@ var removeAbsoluteRemoteMacProfile = async (name, profilePath) => {
26737
27046
  await saveStore(store, profilePath);
26738
27047
  return true;
26739
27048
  };
26740
- var projectIdentity = (projectRoot, appId) => createHash7("sha256").update(`${resolvePath3(projectRoot)}\x00${appId}`).digest("hex").slice(0, 20);
27049
+ var projectIdentity = (projectRoot, appId) => createHash8("sha256").update(`${resolvePath3(projectRoot)}\x00${appId}`).digest("hex").slice(0, 20);
26741
27050
  var createAbsoluteRemoteExpoIosDevProject = (config, projectRoot, profile) => {
26742
27051
  if (config.engine !== "expo")
26743
27052
  throw new TypeError("Remote Expo execution requires mobile.engine: expo.");
26744
27053
  return createAbsoluteRemoteIosDevProject(config, projectRoot, profile);
26745
27054
  };
26746
27055
  var createAbsoluteRemoteIosDevProject = (config, projectRoot, profile) => ({
26747
- cap: join8(resolvePath3(projectRoot), "node_modules", ".bin", "cap"),
27056
+ cap: join9(resolvePath3(projectRoot), "node_modules", ".bin", "cap"),
26748
27057
  config,
26749
- nativeDirectory: join8(config.nativeProjectDirectory, "ios"),
27058
+ nativeDirectory: join9(config.nativeProjectDirectory, "ios"),
26750
27059
  profile,
26751
27060
  projectRoot: resolvePath3(projectRoot),
26752
27061
  remote: true,
@@ -26903,8 +27212,8 @@ var installAbsoluteRemoteMacAgent = async (project) => {
26903
27212
  };
26904
27213
  var materializeAbsoluteRemoteMacAgent = async (projectRoot) => {
26905
27214
  const shippedCandidates = [
26906
- join8(import.meta.dir, "remoteMacAgentEntry.js"),
26907
- join8(import.meta.dir, "..", "mobile", "remoteMacAgentEntry.js")
27215
+ join9(import.meta.dir, "remoteMacAgentEntry.js"),
27216
+ join9(import.meta.dir, "..", "mobile", "remoteMacAgentEntry.js")
26908
27217
  ];
26909
27218
  let path;
26910
27219
  for (const candidate of shippedCandidates) {
@@ -26915,14 +27224,14 @@ var materializeAbsoluteRemoteMacAgent = async (projectRoot) => {
26915
27224
  }
26916
27225
  if (!path) {
26917
27226
  const sourceCandidates = [
26918
- join8(import.meta.dir, "remoteMacAgentEntry.ts"),
26919
- join8(import.meta.dir, "..", "..", "src", "mobile", "remoteMacAgentEntry.ts")
27227
+ join9(import.meta.dir, "remoteMacAgentEntry.ts"),
27228
+ join9(import.meta.dir, "..", "..", "src", "mobile", "remoteMacAgentEntry.ts")
26920
27229
  ];
26921
27230
  const source = await sourceCandidates.reduce(async (found, candidate) => await found ?? (await Bun.file(candidate).exists() ? candidate : undefined), Promise.resolve(undefined));
26922
27231
  if (!source)
26923
27232
  throw new Error("The AbsoluteJS installation does not contain its remote Mac agent artifact.");
26924
- const outdir = join8(resolvePath3(projectRoot), ".absolutejs", "mobile", "remote-agent");
26925
- await mkdir6(outdir, { recursive: true });
27233
+ const outdir = join9(resolvePath3(projectRoot), ".absolutejs", "mobile", "remote-agent");
27234
+ await mkdir7(outdir, { recursive: true });
26926
27235
  const result = await Bun.build({
26927
27236
  entrypoints: [source],
26928
27237
  minify: true,
@@ -26931,13 +27240,13 @@ var materializeAbsoluteRemoteMacAgent = async (projectRoot) => {
26931
27240
  });
26932
27241
  if (!result.success)
26933
27242
  throw new AggregateError(result.logs, "Failed to build the AbsoluteJS remote Mac agent.");
26934
- path = join8(outdir, "remoteMacAgentEntry.js");
27243
+ path = join9(outdir, "remoteMacAgentEntry.js");
26935
27244
  }
26936
27245
  const bytes = await Bun.file(path).arrayBuffer();
26937
- const sha256 = createHash7("sha256").update(new Uint8Array(bytes)).digest("hex");
26938
- return { bytes: bytes.byteLength, path, sha256 };
27246
+ const sha2562 = createHash8("sha256").update(new Uint8Array(bytes)).digest("hex");
27247
+ return { bytes: bytes.byteLength, path, sha256: sha2562 };
26939
27248
  };
26940
- var portableRelativePath = (root, path) => relative6(root, path).split(sep5).join(posix.sep);
27249
+ var portableRelativePath = (root, path) => relative7(root, path).split(sep6).join(posix.sep);
26941
27250
  var portableMobileConfig = (project) => ({
26942
27251
  appId: project.config.appId,
26943
27252
  appName: project.config.appName,
@@ -27118,9 +27427,9 @@ var writeRemoteArtifact = async (path, stream) => {
27118
27427
  };
27119
27428
  var retrieveAbsoluteRemoteIosRelease = async (project, metadata, outputDirectory) => {
27120
27429
  const releaseRoot = posix.join(project.remoteProjectRoot, ".absolutejs", "mobile", "releases", "ios", metadata.releaseId);
27121
- const stagingParent = join8(project.projectRoot, ".absolutejs", "mobile");
27122
- await mkdir6(stagingParent, { recursive: true });
27123
- const staging = await mkdtemp4(join8(stagingParent, ".remote-ios-"));
27430
+ const stagingParent = join9(project.projectRoot, ".absolutejs", "mobile");
27431
+ await mkdir7(stagingParent, { recursive: true });
27432
+ const staging = await mkdtemp5(join9(stagingParent, ".remote-ios-"));
27124
27433
  try {
27125
27434
  const remoteMetadata = requireRemoteSuccess(await defaultTransport.capture([
27126
27435
  ...absoluteRemoteMacSshBase(project.profile),
@@ -27130,7 +27439,7 @@ var retrieveAbsoluteRemoteIosRelease = async (project, metadata, outputDirectory
27130
27439
  const downloadedMetadata = JSON.parse(remoteMetadata);
27131
27440
  if (JSON.stringify(requireAbsoluteIosReleaseMetadata(downloadedMetadata)) !== JSON.stringify(metadata))
27132
27441
  throw new TypeError("Remote iOS release metadata changed during retrieval.");
27133
- const artifactPath = join8(staging, "App.ipa");
27442
+ const artifactPath = join9(staging, "App.ipa");
27134
27443
  const download = Bun.spawn([
27135
27444
  ...absoluteRemoteMacSshBase(project.profile),
27136
27445
  "/bin/sh -lc",
@@ -27150,7 +27459,7 @@ var retrieveAbsoluteRemoteIosRelease = async (project, metadata, outputDirectory
27150
27459
  projectRoot: project.projectRoot
27151
27460
  });
27152
27461
  } finally {
27153
- await rm6(staging, { force: true, recursive: true }).catch(() => {
27462
+ await rm7(staging, { force: true, recursive: true }).catch(() => {
27154
27463
  return;
27155
27464
  });
27156
27465
  }
@@ -27392,7 +27701,7 @@ var startAbsoluteRemoteDevSession = async (options) => {
27392
27701
  await syncProject(options.project);
27393
27702
  const syncDuration = performance.now() - syncStartedAt;
27394
27703
  const encodedConfig = Buffer.from(JSON.stringify(portableMobileConfig(options.project))).toString("base64url");
27395
- const encodedCertificateAuthority = options.certificateAuthorityPath ? (await readFile9(options.certificateAuthorityPath)).toString("base64url") : undefined;
27704
+ const encodedCertificateAuthority = options.certificateAuthorityPath ? (await readFile10(options.certificateAuthorityPath)).toString("base64url") : undefined;
27396
27705
  const physicalDevice = options.deviceIdentifier !== undefined;
27397
27706
  const expo = options.project.config.engine === "expo";
27398
27707
  if (expo && options.metroPort === undefined)
@@ -27459,8 +27768,8 @@ var startAbsoluteRemoteDevSession = async (options) => {
27459
27768
  const pending = new Map;
27460
27769
  let resolveReady;
27461
27770
  let rejectReady;
27462
- const readyPromise = new Promise((resolve6, reject) => {
27463
- resolveReady = resolve6;
27771
+ const readyPromise = new Promise((resolve7, reject) => {
27772
+ resolveReady = resolve7;
27464
27773
  rejectReady = reject;
27465
27774
  });
27466
27775
  const handleEvent = (event) => {
@@ -27563,7 +27872,7 @@ var startAbsoluteRemoteDevSession = async (options) => {
27563
27872
  options.log?.(`Remote Mac connected (${options.project.profile.name}); agent ${agent.uploaded ? "uploaded" : "cache hit"}, project synced, and ${expo ? "Expo " : ""}iOS ready in ${totalDuration.toFixed(2)}ms.`);
27564
27873
  const request = (commandName) => {
27565
27874
  const id = randomUUID4();
27566
- const response = new Promise((resolve6, reject) => pending.set(id, { reject, resolve: resolve6 }));
27875
+ const response = new Promise((resolve7, reject) => pending.set(id, { reject, resolve: resolve7 }));
27567
27876
  process2.stdin.write(`${JSON.stringify({ command: commandName, id, v: ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION })}
27568
27877
  `);
27569
27878
  const flush = async () => {
@@ -27583,7 +27892,7 @@ var startAbsoluteRemoteDevSession = async (options) => {
27583
27892
  if (closed)
27584
27893
  return;
27585
27894
  closed = true;
27586
- const timeout = () => new Promise((resolve6) => setTimeout(() => resolve6("timeout"), REMOTE_SESSION_CLOSE_TIMEOUT_MS));
27895
+ const timeout = () => new Promise((resolve7) => setTimeout(() => resolve7("timeout"), REMOTE_SESSION_CLOSE_TIMEOUT_MS));
27587
27896
  const id = randomUUID4();
27588
27897
  process2.stdin.write(`${JSON.stringify({ command: "close", id, v: ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION })}
27589
27898
  `);
@@ -27630,11 +27939,11 @@ var startAbsoluteRemoteDevSession = async (options) => {
27630
27939
  screenshot: async (destination) => {
27631
27940
  const result = await request("screenshot");
27632
27941
  const target = resolvePath3(options.project.projectRoot, destination);
27633
- const targetRelative = relative6(options.project.projectRoot, target);
27634
- if (targetRelative.startsWith("..") || isAbsolute5(targetRelative))
27942
+ const targetRelative = relative7(options.project.projectRoot, target);
27943
+ if (targetRelative.startsWith("..") || isAbsolute6(targetRelative))
27635
27944
  throw new Error("iOS screenshot must remain inside the project.");
27636
- await mkdir6(dirname5(target), { recursive: true });
27637
- await writeFile7(target, Buffer.from(result.data, "base64"));
27945
+ await mkdir7(dirname6(target), { recursive: true });
27946
+ await writeFile8(target, Buffer.from(result.data, "base64"));
27638
27947
  return target;
27639
27948
  },
27640
27949
  get state() {
@@ -27661,20 +27970,20 @@ var absoluteIosDeviceAcceptanceCommands = (options) => {
27661
27970
  ]
27662
27971
  };
27663
27972
  };
27664
- var requireSuccess3 = (result, message) => {
27973
+ var requireSuccess4 = (result, message) => {
27665
27974
  if (result.exitCode !== 0)
27666
27975
  throw new Error(message);
27667
27976
  return result;
27668
27977
  };
27669
27978
  var testAbsoluteIosPhysicalDevice = async (options) => {
27670
27979
  const commands = absoluteIosDeviceAcceptanceCommands(options);
27671
- requireSuccess3(await options.capture(commands.details), "The selected physical iOS device is unavailable. Pair it in Xcode Device Hub, trust this Mac, unlock it, and enable Developer Mode.");
27672
- const apps = requireSuccess3(await options.capture(commands.apps), "AbsoluteJS could not inspect installed apps on the physical iOS device.");
27980
+ requireSuccess4(await options.capture(commands.details), "The selected physical iOS device is unavailable. Pair it in Xcode Device Hub, trust this Mac, unlock it, and enable Developer Mode.");
27981
+ const apps = requireSuccess4(await options.capture(commands.apps), "AbsoluteJS could not inspect installed apps on the physical iOS device.");
27673
27982
  if (!apps.stdout.includes(options.appId))
27674
27983
  throw new Error("The AbsoluteJS app is not installed on the selected physical iOS device. Start bun dev with the same --ios-device value first.");
27675
27984
  const now = options.now ?? performance.now.bind(performance);
27676
27985
  const startedAt = now();
27677
- requireSuccess3(await options.capture(commands.launch), "AbsoluteJS could not relaunch the app on the physical iOS device.");
27986
+ requireSuccess4(await options.capture(commands.launch), "AbsoluteJS could not relaunch the app on the physical iOS device.");
27678
27987
  await options.waitForHmr();
27679
27988
  return {
27680
27989
  hmrConnected: true,
@@ -27697,10 +28006,10 @@ var frameworks2 = new Set([
27697
28006
  "svelte",
27698
28007
  "vue"
27699
28008
  ]);
27700
- var isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
28009
+ var isRecord5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
27701
28010
  var isPageFramework2 = (value) => typeof value === "string" && frameworks2.has(value);
27702
28011
  var parseAbsoluteMobileBuildPageMetadata = (value) => {
27703
- if (!isRecord4(value))
28012
+ if (!isRecord5(value))
27704
28013
  return;
27705
28014
  if (typeof value.bundleKey !== "string" || typeof value.contract !== "string" || !isPageFramework2(value.framework) || typeof value.pageId !== "string" || typeof value.propsSchemaHash !== "string") {
27706
28015
  return;
@@ -27714,32 +28023,32 @@ var parseAbsoluteMobileBuildPageMetadata = (value) => {
27714
28023
  };
27715
28024
  };
27716
28025
  // src/mobile/buildPipeline.ts
27717
- import { readFile as readFile15 } from "fs/promises";
27718
- import { join as join18, resolve as resolve13 } from "path";
28026
+ import { readFile as readFile16 } from "fs/promises";
28027
+ import { join as join19, resolve as resolve14 } from "path";
27719
28028
  import { pathToFileURL as pathToFileURL2 } from "url";
27720
28029
 
27721
28030
  // src/mobile/buildRelease.ts
27722
- import { createHash as createHash9 } from "crypto";
27723
- import { mkdir as mkdir8, readFile as readFile11, writeFile as writeFile9 } from "fs/promises";
27724
- import { basename as basename2, dirname as dirname6, extname, join as join9, relative as relative7, resolve as resolve8 } from "path";
28031
+ import { createHash as createHash10 } from "crypto";
28032
+ import { mkdir as mkdir9, readFile as readFile12, writeFile as writeFile10 } from "fs/promises";
28033
+ import { basename as basename3, dirname as dirname7, extname, join as join10, relative as relative8, resolve as resolve9 } from "path";
27725
28034
  init_releaseArtifact();
27726
- var sha256 = (bytes) => createHash9("sha256").update(bytes).digest("hex");
28035
+ var sha2562 = (bytes) => createHash10("sha256").update(bytes).digest("hex");
27727
28036
  var STATIC_SCRIPT_PATTERN = /(<script\b[^>]*?\bsrc\s*=\s*["'])(\/[^"']+\.(?:js|ts))(["'][^>]*>)/giu;
27728
28037
  var rewriteStaticScriptPaths = (source, manifest) => source.replace(STATIC_SCRIPT_PATTERN, (match, prefix, path, suffix) => {
27729
28038
  if (path.endsWith("/htmx.min.js"))
27730
28039
  return match;
27731
- const key = toPascal(basename2(path, extname(path)));
28040
+ const key = toPascal(basename3(path, extname(path)));
27732
28041
  const builtPath = manifest[key];
27733
28042
  return builtPath ? `${prefix}${builtPath}${suffix}` : match;
27734
28043
  });
27735
28044
  var readPageMetadata = (route) => parseAbsoluteMobileBuildPageMetadata(route.hooks?.detail?.[ABSOLUTE_MOBILE_ROUTE_DETAIL]);
27736
28045
  var resolveAssetPath = (buildDirectory, assetPath) => {
27737
- const resolvedBuildDirectory = resolve8(buildDirectory);
27738
- const resolvedAsset = resolve8(assetPath);
28046
+ const resolvedBuildDirectory = resolve9(buildDirectory);
28047
+ const resolvedAsset = resolve9(assetPath);
27739
28048
  if (resolvedAsset.startsWith(`${resolvedBuildDirectory}/`)) {
27740
28049
  return resolvedAsset;
27741
28050
  }
27742
- return join9(buildDirectory, assetPath.replace(/^\/+/, ""));
28051
+ return join10(buildDirectory, assetPath.replace(/^\/+/, ""));
27743
28052
  };
27744
28053
  var pageFor = async (metadata, manifest, buildDirectory) => {
27745
28054
  const assetPath = manifest[metadata.bundleKey];
@@ -27748,12 +28057,12 @@ var pageFor = async (metadata, manifest, buildDirectory) => {
27748
28057
  }
27749
28058
  let resolvedAssetPath = resolveAssetPath(buildDirectory, assetPath);
27750
28059
  if (metadata.framework === "html" || metadata.framework === "htmx") {
27751
- const source = await readFile11(resolvedAssetPath, "utf8");
28060
+ const source = await readFile12(resolvedAssetPath, "utf8");
27752
28061
  const rewritten = rewriteStaticScriptPaths(source, manifest);
27753
- const documentHash = sha256(new TextEncoder().encode(rewritten));
27754
- resolvedAssetPath = join9(buildDirectory, ".absolutejs", "mobile-pages", `${documentHash}.html`);
27755
- await mkdir8(dirname6(resolvedAssetPath), { recursive: true });
27756
- await writeFile9(resolvedAssetPath, rewritten);
28062
+ const documentHash = sha2562(new TextEncoder().encode(rewritten));
28063
+ resolvedAssetPath = join10(buildDirectory, ".absolutejs", "mobile-pages", `${documentHash}.html`);
28064
+ await mkdir9(dirname7(resolvedAssetPath), { recursive: true });
28065
+ await writeFile10(resolvedAssetPath, rewritten);
27757
28066
  }
27758
28067
  const pageAssetKey = metadata.bundleKey.replace(/Index$/u, "");
27759
28068
  const styleAssetPath = [
@@ -27762,20 +28071,20 @@ var pageFor = async (metadata, manifest, buildDirectory) => {
27762
28071
  ].map((key) => manifest[key]).find((path) => typeof path === "string");
27763
28072
  const resolvedStylePath = styleAssetPath ? resolveAssetPath(buildDirectory, styleAssetPath) : undefined;
27764
28073
  const [bytes, styleBytes] = await Promise.all([
27765
- readFile11(resolvedAssetPath),
27766
- resolvedStylePath ? readFile11(resolvedStylePath) : undefined
28074
+ readFile12(resolvedAssetPath),
28075
+ resolvedStylePath ? readFile12(resolvedStylePath) : undefined
27767
28076
  ]);
27768
- const bundlePath = `/${relative7(resolve8(buildDirectory), resolvedAssetPath).replaceAll("\\", "/")}`;
27769
- const styleBundlePath = resolvedStylePath ? `/${relative7(resolve8(buildDirectory), resolvedStylePath).replaceAll("\\", "/")}` : undefined;
28077
+ const bundlePath = `/${relative8(resolve9(buildDirectory), resolvedAssetPath).replaceAll("\\", "/")}`;
28078
+ const styleBundlePath = resolvedStylePath ? `/${relative8(resolve9(buildDirectory), resolvedStylePath).replaceAll("\\", "/")}` : undefined;
27770
28079
  return {
27771
- bundleHash: sha256(bytes),
28080
+ bundleHash: sha2562(bytes),
27772
28081
  bundlePath,
27773
28082
  contract: metadata.contract,
27774
28083
  framework: metadata.framework,
27775
28084
  pageId: metadata.pageId,
27776
28085
  propsSchemaHash: metadata.propsSchemaHash,
27777
28086
  ...styleBytes && styleBundlePath ? {
27778
- styleBundleHash: sha256(styleBytes),
28087
+ styleBundleHash: sha2562(styleBytes),
27779
28088
  styleBundlePath
27780
28089
  } : {}
27781
28090
  };
@@ -27783,7 +28092,7 @@ var pageFor = async (metadata, manifest, buildDirectory) => {
27783
28092
  var buildAbsoluteMobileCompatibilityRelease = async (options) => {
27784
28093
  const [captured, producerBytes] = await Promise.all([
27785
28094
  captureAbsoluteMobileRouteGraph(options.app),
27786
- readFile11(options.producerPath)
28095
+ readFile12(options.producerPath)
27787
28096
  ]);
27788
28097
  if (captured.length === 0) {
27789
28098
  throw new TypeError("No instrumented AbsoluteJS mobile page routes were found in the finalized Elysia route graph.");
@@ -27797,8 +28106,8 @@ var buildAbsoluteMobileCompatibilityRelease = async (options) => {
27797
28106
  metadataByPage.set(metadata.pageId, metadata);
27798
28107
  }
27799
28108
  const pages = await Promise.all([...metadataByPage.values()].map((metadata) => pageFor(metadata, options.manifest, options.buildDirectory)));
27800
- const producerHash = sha256(producerBytes);
27801
- const appBuild = `ambuild_${sha256(new TextEncoder().encode(JSON.stringify({
28109
+ const producerHash = sha2562(producerBytes);
28110
+ const appBuild = `ambuild_${sha2562(new TextEncoder().encode(JSON.stringify({
27802
28111
  pages: pages.map(({
27803
28112
  bundleHash,
27804
28113
  bundlePath,
@@ -27874,15 +28183,15 @@ init_routeMatcher();
27874
28183
  import {
27875
28184
  cp,
27876
28185
  copyFile as copyFile5,
27877
- mkdir as mkdir9,
27878
- mkdtemp as mkdtemp5,
27879
- readFile as readFile12,
27880
- rename as rename9,
27881
- rm as rm8,
27882
- writeFile as writeFile10
28186
+ mkdir as mkdir10,
28187
+ mkdtemp as mkdtemp6,
28188
+ readFile as readFile13,
28189
+ rename as rename10,
28190
+ rm as rm9,
28191
+ writeFile as writeFile11
27883
28192
  } from "fs/promises";
27884
28193
  import { existsSync as existsSync2 } from "fs";
27885
- import { basename as basename3, dirname as dirname7, extname as extname2, join as join10, relative as relative8, resolve as resolve9 } from "path";
28194
+ import { basename as basename4, dirname as dirname8, extname as extname2, join as join11, relative as relative9, resolve as resolve10 } from "path";
27886
28195
 
27887
28196
  // src/mobile/client.ts
27888
28197
  init_pageProtocol();
@@ -27916,14 +28225,14 @@ var upgradeReasons = new Set([
27916
28225
  "protocol",
27917
28226
  "runtime"
27918
28227
  ]);
27919
- var isRecord6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
28228
+ var isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
27920
28229
  var isFramework = (value) => typeof value === "string" && frameworks4.has(value);
27921
28230
  var isUpgradeReason = (value) => typeof value === "string" && upgradeReasons.has(value);
27922
28231
  var parsePageResult = (value) => {
27923
28232
  if (typeof value.contract !== "string" || !isFramework(value.framework) || typeof value.pageId !== "string" || typeof value.status !== "number") {
27924
28233
  throw new AbsoluteMobilePageProtocolError("invalid-envelope", "The mobile page response is missing required page metadata.");
27925
28234
  }
27926
- if (!isRecord6(value.props)) {
28235
+ if (!isRecord7(value.props)) {
27927
28236
  throw new AbsoluteMobilePageProtocolError("invalid-props", "The mobile page response must contain an object props value.");
27928
28237
  }
27929
28238
  return {
@@ -27974,7 +28283,7 @@ var activateAbsoluteMobilePage = async (value, options) => {
27974
28283
  };
27975
28284
  };
27976
28285
  var parseAbsoluteMobilePageEnvelope = (value) => {
27977
- if (!isRecord6(value) || !isRecord6(value.response)) {
28286
+ if (!isRecord7(value) || !isRecord7(value.response)) {
27978
28287
  throw new AbsoluteMobilePageProtocolError("invalid-envelope", "The server did not return an AbsoluteJS mobile page envelope.");
27979
28288
  }
27980
28289
  if (value.protocol !== ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION) {
@@ -28093,49 +28402,49 @@ var CAPACITOR_CLIENT_FRAMEWORKS = new Set([
28093
28402
  var CLIENT_ASSET_DIRECTORIES = ["assets", "html", "htmx", "indexes"];
28094
28403
  var errorHasCode2 = (error, code) => typeof error === "object" && error !== null && Reflect.get(error, "code") === code;
28095
28404
  var shellBootstrapModule = () => {
28096
- const candidate = ["js", "ts"].map((extension) => join10(import.meta.dir, `shellBootstrap.${extension}`)).find(existsSync2);
28405
+ const candidate = ["js", "ts"].map((extension) => join11(import.meta.dir, `shellBootstrap.${extension}`)).find(existsSync2);
28097
28406
  if (candidate)
28098
28407
  return candidate;
28099
28408
  throw new TypeError("AbsoluteJS mobile shell bootstrap module is missing.");
28100
28409
  };
28101
28410
  var shellAuthModule = () => {
28102
- const candidate = ["js", "ts"].map((extension) => join10(import.meta.dir, `shellAuth.${extension}`)).find(existsSync2);
28411
+ const candidate = ["js", "ts"].map((extension) => join11(import.meta.dir, `shellAuth.${extension}`)).find(existsSync2);
28103
28412
  if (candidate)
28104
28413
  return candidate;
28105
28414
  throw new TypeError("AbsoluteJS mobile auth shell module is missing.");
28106
28415
  };
28107
28416
  var shellExpoAuthModule = () => {
28108
- const candidate = ["js", "ts"].map((extension) => join10(import.meta.dir, `shellExpoAuth.${extension}`)).find(existsSync2);
28417
+ const candidate = ["js", "ts"].map((extension) => join11(import.meta.dir, `shellExpoAuth.${extension}`)).find(existsSync2);
28109
28418
  if (candidate)
28110
28419
  return candidate;
28111
28420
  throw new TypeError("AbsoluteJS Expo auth bridge module is missing.");
28112
28421
  };
28113
28422
  var shellSyncModule = () => {
28114
- const candidate = ["js", "ts"].map((extension) => join10(import.meta.dir, `shellSync.${extension}`)).find(existsSync2);
28423
+ const candidate = ["js", "ts"].map((extension) => join11(import.meta.dir, `shellSync.${extension}`)).find(existsSync2);
28115
28424
  if (candidate)
28116
28425
  return candidate;
28117
28426
  throw new TypeError("AbsoluteJS mobile Sync shell module is missing.");
28118
28427
  };
28119
28428
  var shellExpoSyncModule = () => {
28120
- const candidate = ["js", "ts"].map((extension) => join10(import.meta.dir, `shellExpoSync.${extension}`)).find(existsSync2);
28429
+ const candidate = ["js", "ts"].map((extension) => join11(import.meta.dir, `shellExpoSync.${extension}`)).find(existsSync2);
28121
28430
  if (candidate)
28122
28431
  return candidate;
28123
28432
  throw new TypeError("AbsoluteJS Expo Sync bridge module is missing.");
28124
28433
  };
28125
28434
  var shellPushModule = () => {
28126
- const candidate = ["js", "ts"].map((extension) => join10(import.meta.dir, `shellPush.${extension}`)).find(existsSync2);
28435
+ const candidate = ["js", "ts"].map((extension) => join11(import.meta.dir, `shellPush.${extension}`)).find(existsSync2);
28127
28436
  if (candidate)
28128
28437
  return candidate;
28129
28438
  throw new TypeError("AbsoluteJS mobile push shell module is missing.");
28130
28439
  };
28131
28440
  var shellExpoDevicesModule = () => {
28132
- const candidate = ["js", "ts"].map((extension) => join10(import.meta.dir, `shellExpoDevices.${extension}`)).find(existsSync2);
28441
+ const candidate = ["js", "ts"].map((extension) => join11(import.meta.dir, `shellExpoDevices.${extension}`)).find(existsSync2);
28133
28442
  if (candidate)
28134
28443
  return candidate;
28135
28444
  throw new TypeError("AbsoluteJS Expo device bridge module is missing.");
28136
28445
  };
28137
28446
  var shellUpdateModule = () => {
28138
- const candidate = ["js", "ts"].map((extension) => join10(import.meta.dir, `shellUpdate.${extension}`)).find(existsSync2);
28447
+ const candidate = ["js", "ts"].map((extension) => join11(import.meta.dir, `shellUpdate.${extension}`)).find(existsSync2);
28139
28448
  if (candidate)
28140
28449
  return candidate;
28141
28450
  throw new TypeError("AbsoluteJS mobile update shell module is missing.");
@@ -28170,8 +28479,8 @@ var indexHtml = (appName, productionOrigin) => `<!doctype html>
28170
28479
  </html>
28171
28480
  `;
28172
28481
  var sourceAssetPath = (buildDirectory, bundlePath) => {
28173
- const root = resolve9(buildDirectory);
28174
- const asset = resolve9(root, bundlePath.replace(/^\/+/, ""));
28482
+ const root = resolve10(buildDirectory);
28483
+ const asset = resolve10(root, bundlePath.replace(/^\/+/, ""));
28175
28484
  if (!asset.startsWith(`${root}/`)) {
28176
28485
  throw new TypeError("Mobile page bundle escaped the build directory.");
28177
28486
  }
@@ -28188,15 +28497,15 @@ var resolveProjectImport = async (projectRoot, specifier) => {
28188
28497
  const segments = specifier.split("/");
28189
28498
  const packageName = specifier.startsWith("@") ? segments.slice(0, 2).join("/") : segments[0] ?? "";
28190
28499
  const subpath = specifier.slice(packageName.length);
28191
- const packageDirectory = join10(resolve9(projectRoot), "node_modules", packageName);
28192
- const manifest = JSON.parse(await readFile12(join10(packageDirectory, "package.json"), "utf8"));
28500
+ const packageDirectory = join11(resolve10(projectRoot), "node_modules", packageName);
28501
+ const manifest = JSON.parse(await readFile13(join11(packageDirectory, "package.json"), "utf8"));
28193
28502
  const exports = typeof manifest === "object" && manifest !== null ? Reflect.get(manifest, "exports") : undefined;
28194
28503
  const entry = typeof exports === "object" && exports !== null ? Reflect.get(exports, subpath ? `.${subpath}` : ".") : undefined;
28195
28504
  const target = importEntryTarget(entry);
28196
28505
  if (typeof target !== "string" || !target.startsWith("./"))
28197
28506
  throw new TypeError(`${specifier} does not publish an import entry.`);
28198
- const resolved = resolve9(packageDirectory, target);
28199
- if (!resolved.startsWith(`${resolve9(packageDirectory)}/`))
28507
+ const resolved = resolve10(packageDirectory, target);
28508
+ if (!resolved.startsWith(`${resolve10(packageDirectory)}/`))
28200
28509
  throw new TypeError(`${specifier} has an unsafe import entry.`);
28201
28510
  return resolved;
28202
28511
  };
@@ -28227,7 +28536,7 @@ var buildShellBootstrap = async (staging, auth, sync, storagePrefix, engine, upd
28227
28536
  const absoluteMobilePushCapability = absoluteDeviceCapability${pushIndex}(absoluteMobilePush.capabilityOptions);
28228
28537
  ` : "";
28229
28538
  const capabilityOptions = shellCapabilities.map((name, index) => `${JSON.stringify(name)}: ${name === "pushNotifications" ? "absoluteMobilePushCapability" : `absoluteDeviceCapability${index}()`}`).join(", ");
28230
- const entryPath = join10(staging, ".absolute-mobile-entry.ts");
28539
+ const entryPath = join11(staging, ".absolute-mobile-entry.ts");
28231
28540
  const baseAdapterModule = capacitor ? await resolveProjectImport(projectRoot, "@absolutejs/devices-capacitor") : shellExpoDevicesModule();
28232
28541
  const adapterImport = capacitor ? `import { installCapacitorDeviceAdapterIfNative } from ${JSON.stringify(baseAdapterModule)};` : `import { createAbsoluteExpoBridgeFetch, installAbsoluteExpoWebDeviceAdapter } from ${JSON.stringify(baseAdapterModule)};`;
28233
28542
  const adapterInstall = capacitor ? `installCapacitorDeviceAdapterIfNative({ storagePrefix: ${JSON.stringify(storagePrefix)}${capabilityOptions ? `, ${capabilityOptions}` : ""} });` : `installAbsoluteExpoWebDeviceAdapter(${JSON.stringify(deviceCapabilities.capabilities)});`;
@@ -28245,7 +28554,7 @@ const absoluteMobilePushCapability = absoluteDeviceCapability${pushIndex}(absolu
28245
28554
  if (updates)
28246
28555
  shellOptionProperties.push("installUpdates: installAbsoluteMobileShellUpdates");
28247
28556
  const shellOptions = `{ ${shellOptionProperties.join(", ")} }`;
28248
- await writeFile10(entryPath, `import { startAbsoluteMobileShell } from ${JSON.stringify(modulePath)};
28557
+ await writeFile11(entryPath, `import { startAbsoluteMobileShell } from ${JSON.stringify(modulePath)};
28249
28558
  ${adapterImport}
28250
28559
  ${authImport}${syncImport}${pushImport}${updateImport}${capabilityImports}
28251
28560
  ${pushSetup}${adapterInstall}
@@ -28261,31 +28570,31 @@ void startAbsoluteMobileShell(${shellOptions});
28261
28570
  if (!build.success || build.outputs.length !== 1) {
28262
28571
  throw new AggregateError(build.logs, "Failed to build the AbsoluteJS Capacitor shell.");
28263
28572
  }
28264
- await rename9(build.outputs[0]?.path ?? "", join10(staging, BOOTSTRAP_FILE));
28265
- await rm8(entryPath, { force: true });
28573
+ await rename10(build.outputs[0]?.path ?? "", join11(staging, BOOTSTRAP_FILE));
28574
+ await rm9(entryPath, { force: true });
28266
28575
  };
28267
28576
  var removePreviousBundle = async (backup, moved) => {
28268
28577
  if (!moved)
28269
28578
  return;
28270
- await rm8(backup, { force: true, recursive: true });
28579
+ await rm9(backup, { force: true, recursive: true });
28271
28580
  };
28272
28581
  var restorePreviousBundle = async (backup, destination, moved) => {
28273
28582
  if (!moved)
28274
28583
  return;
28275
- await rename9(backup, destination);
28584
+ await rename10(backup, destination);
28276
28585
  };
28277
28586
  var installBundle = async (staging, destination) => {
28278
28587
  const backup = `${destination}.previous-${crypto.randomUUID()}`;
28279
28588
  let movedPrevious = false;
28280
28589
  try {
28281
- await rename9(destination, backup);
28590
+ await rename10(destination, backup);
28282
28591
  movedPrevious = true;
28283
28592
  } catch (error) {
28284
28593
  if (!errorHasCode2(error, "ENOENT"))
28285
28594
  throw error;
28286
28595
  }
28287
28596
  try {
28288
- await rename9(staging, destination);
28597
+ await rename10(staging, destination);
28289
28598
  await removePreviousBundle(backup, movedPrevious);
28290
28599
  } catch (error) {
28291
28600
  await restorePreviousBundle(backup, destination, movedPrevious);
@@ -28299,17 +28608,17 @@ var copyClientPage = async (page, buildDirectory, staging, copiedDependencies) =
28299
28608
  const extension = extname2(page.bundlePath) || ".js";
28300
28609
  const localBundlePath = `./pages/${page.bundleHash}${extension}`;
28301
28610
  const source = sourceAssetPath(buildDirectory, page.bundlePath);
28302
- await copyFile5(source, join10(staging, localBundlePath));
28611
+ await copyFile5(source, join11(staging, localBundlePath));
28303
28612
  await copyAbsoluteClientDependencies(source, buildDirectory, staging, copiedDependencies);
28304
28613
  let localStylePath;
28305
28614
  if (page.styleBundlePath && page.styleBundleHash) {
28306
28615
  const styleExtension = extname2(page.styleBundlePath) || ".css";
28307
28616
  localStylePath = `./styles/${page.styleBundleHash}${styleExtension}`;
28308
28617
  const styleSource = sourceAssetPath(buildDirectory, page.styleBundlePath);
28309
- await mkdir9(dirname7(join10(staging, localStylePath)), {
28618
+ await mkdir10(dirname8(join11(staging, localStylePath)), {
28310
28619
  recursive: true
28311
28620
  });
28312
- await copyFile5(styleSource, join10(staging, localStylePath));
28621
+ await copyFile5(styleSource, join11(staging, localStylePath));
28313
28622
  await copyAbsoluteClientDependencies(styleSource, buildDirectory, staging, copiedDependencies);
28314
28623
  }
28315
28624
  return {
@@ -28325,26 +28634,26 @@ var materializeAbsoluteMobileSourcemaps = async (pages, appBuild, projectRoot) =
28325
28634
  return value;
28326
28635
  };
28327
28636
  const release = safeLeaf(appBuild, "Mobile app build");
28328
- const privateRoot = join10(projectRoot, "sourcemaps");
28329
- const releaseRoot = join10(privateRoot, "mobile", release);
28637
+ const privateRoot = join11(projectRoot, "sourcemaps");
28638
+ const releaseRoot = join11(privateRoot, "mobile", release);
28330
28639
  const copied = [];
28331
28640
  const available = pages.flatMap((page) => {
28332
- const source = join10(privateRoot, `${basename3(page.bundlePath)}.map`);
28641
+ const source = join11(privateRoot, `${basename4(page.bundlePath)}.map`);
28333
28642
  return existsSync2(source) ? [{ page, source }] : [];
28334
28643
  });
28335
28644
  if (available.length > 0)
28336
- await mkdir9(releaseRoot, { recursive: true });
28645
+ await mkdir10(releaseRoot, { recursive: true });
28337
28646
  await Promise.all(available.map(async ({ page, source }) => {
28338
28647
  const extension = extname2(page.bundlePath) || ".js";
28339
28648
  if (!/^\.[a-z0-9]+$/iu.test(extension))
28340
28649
  throw new TypeError("Mobile page extension is not a safe source-map key.");
28341
28650
  const bundleHash = safeLeaf(page.bundleHash, "Mobile page bundle hash");
28342
28651
  const file = `${bundleHash}${extension}.map`;
28343
- await copyFile5(source, join10(releaseRoot, file));
28652
+ await copyFile5(source, join11(releaseRoot, file));
28344
28653
  copied.push({ bundleHash, file, pageId: page.pageId });
28345
28654
  }));
28346
28655
  if (copied.length > 0) {
28347
- await writeFile10(join10(releaseRoot, "manifest.json"), `${JSON.stringify({
28656
+ await writeFile11(join11(releaseRoot, "manifest.json"), `${JSON.stringify({
28348
28657
  appBuild,
28349
28658
  format: 1,
28350
28659
  pages: copied.sort((left, right) => left.pageId.localeCompare(right.pageId))
@@ -28354,7 +28663,7 @@ var materializeAbsoluteMobileSourcemaps = async (pages, appBuild, projectRoot) =
28354
28663
  return copied.length;
28355
28664
  };
28356
28665
  var absoluteClientImports = async (sourcePath, buildDirectory) => {
28357
- const source = await readFile12(sourcePath, "utf8");
28666
+ const source = await readFile13(sourcePath, "utf8");
28358
28667
  const extension = extname2(sourcePath).toLowerCase();
28359
28668
  let scriptLoader;
28360
28669
  if (extension === ".tsx")
@@ -28377,9 +28686,9 @@ var absoluteClientImports = async (sourcePath, buildDirectory) => {
28377
28686
  const clean = specifier.split(/[?#]/u, 1)[0] ?? specifier;
28378
28687
  if (clean.startsWith("/"))
28379
28688
  return [clean];
28380
- const resolved = resolve9(dirname7(sourcePath), clean);
28381
- const root = resolve9(buildDirectory);
28382
- const relativePath = relative8(root, resolved).replaceAll("\\", "/");
28689
+ const resolved = resolve10(dirname8(sourcePath), clean);
28690
+ const root = resolve10(buildDirectory);
28691
+ const relativePath = relative9(root, resolved).replaceAll("\\", "/");
28383
28692
  if (relativePath === ".." || relativePath.startsWith("../")) {
28384
28693
  throw new TypeError(`Mobile client dependency escaped the build directory: ${specifier}`);
28385
28694
  }
@@ -28391,8 +28700,8 @@ var copyAbsoluteClientDependency = async (specifier, buildDirectory, staging, co
28391
28700
  return;
28392
28701
  copied.add(specifier);
28393
28702
  const source = sourceAssetPath(buildDirectory, specifier);
28394
- const destination = join10(staging, specifier.replace(/^\/+/, ""));
28395
- await mkdir9(dirname7(destination), { recursive: true });
28703
+ const destination = join11(staging, specifier.replace(/^\/+/, ""));
28704
+ await mkdir10(dirname8(destination), { recursive: true });
28396
28705
  await copyFile5(source, destination);
28397
28706
  await copyAbsoluteClientDependencies(source, buildDirectory, staging, copied);
28398
28707
  };
@@ -28405,14 +28714,14 @@ var materializeAbsoluteCapacitorWebBundle = async (options) => {
28405
28714
  throw new TypeError(`mobile.entry ${options.config.entry} is not a captured mobile page route.`);
28406
28715
  }
28407
28716
  const destination = options.config.bundleDirectory;
28408
- await mkdir9(dirname7(destination), { recursive: true });
28409
- const staging = await mkdtemp5(join10(dirname7(destination), `.${basename3(destination)}.stage-`));
28717
+ await mkdir10(dirname8(destination), { recursive: true });
28718
+ const staging = await mkdtemp6(join11(dirname8(destination), `.${basename4(destination)}.stage-`));
28410
28719
  try {
28411
- const pageDirectory = join10(staging, "pages");
28412
- await mkdir9(pageDirectory, { recursive: true });
28720
+ const pageDirectory = join11(staging, "pages");
28721
+ await mkdir10(pageDirectory, { recursive: true });
28413
28722
  await Promise.all(CLIENT_ASSET_DIRECTORIES.map((directory) => ({
28414
- destination: join10(staging, directory),
28415
- source: join10(options.buildDirectory, directory)
28723
+ destination: join11(staging, directory),
28724
+ source: join11(options.buildDirectory, directory)
28416
28725
  })).filter(({ source }) => existsSync2(source)).map(({ destination: assetDestination, source }) => cp(source, assetDestination, { recursive: true })));
28417
28726
  const copiedDependencies = new Set;
28418
28727
  const pages = await Promise.all(options.artifact.pages.map((page) => copyClientPage(page, options.buildDirectory, staging, copiedDependencies)));
@@ -28449,16 +28758,16 @@ var materializeAbsoluteCapacitorWebBundle = async (options) => {
28449
28758
  } : {}
28450
28759
  };
28451
28760
  await Promise.all([
28452
- writeFile10(join10(staging, MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
28761
+ writeFile11(join11(staging, MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
28453
28762
  `),
28454
- writeFile10(join10(staging, INDEX_FILE), indexHtml(options.config.appName, options.config.productionOrigin)),
28763
+ writeFile11(join11(staging, INDEX_FILE), indexHtml(options.config.appName, options.config.productionOrigin)),
28455
28764
  buildShellBootstrap(staging, options.auth !== undefined, options.auth !== undefined && options.sync === true, `absolutejs.${options.auth?.clientId ?? options.config.appId}.`, options.config.engine, options.config.engine === "capacitor" && options.config.updates !== undefined, options.deviceCapabilities, options.projectRoot)
28456
28765
  ]);
28457
28766
  await installBundle(staging, destination);
28458
28767
  await materializeAbsoluteMobileSourcemaps(options.artifact.pages, options.artifact.appBuild, options.projectRoot);
28459
28768
  return manifest;
28460
28769
  } catch (error) {
28461
- await rm8(staging, { force: true, recursive: true });
28770
+ await rm9(staging, { force: true, recursive: true });
28462
28771
  throw error;
28463
28772
  }
28464
28773
  };
@@ -28475,23 +28784,22 @@ init_nativeAuth();
28475
28784
  init_syncSchema();
28476
28785
  init_deviceCapabilities();
28477
28786
  import {
28478
- access as access10,
28479
- cp as cp2,
28480
- mkdir as mkdir11,
28481
- mkdtemp as mkdtemp7,
28787
+ access as access11,
28788
+ mkdir as mkdir12,
28789
+ mkdtemp as mkdtemp8,
28482
28790
  readdir as readdir4,
28483
- readFile as readFile14,
28484
- rename as rename11,
28485
- rm as rm10,
28486
- writeFile as writeFile12
28791
+ readFile as readFile15,
28792
+ rename as rename12,
28793
+ rm as rm11,
28794
+ writeFile as writeFile13
28487
28795
  } from "fs/promises";
28488
- import { createHash as createHash12 } from "crypto";
28489
- import { basename as basename4, dirname as dirname10, join as join17, relative as relative10, resolve as resolve12, sep as sep6 } from "path";
28796
+ import { createHash as createHash13 } from "crypto";
28797
+ import { basename as basename5, dirname as dirname11, join as join18, relative as relative11, resolve as resolve13, sep as sep7 } from "path";
28490
28798
 
28491
28799
  // src/mobile/updateRuntime.ts
28492
28800
  init_deviceCapabilities();
28493
28801
  init_nativeAuth();
28494
- import { createHash as createHash11 } from "crypto";
28802
+ import { createHash as createHash12 } from "crypto";
28495
28803
 
28496
28804
  // src/mobile/updateProtocol.ts
28497
28805
  var ABSOLUTE_MOBILE_UPDATE_FORMAT = 1;
@@ -28632,7 +28940,7 @@ var createAbsoluteMobileUpdateRuntimeDescriptor = (options) => ({
28632
28940
  syncSchema: options.syncSchema ?? null,
28633
28941
  updates: options.config.updates ?? null
28634
28942
  });
28635
- var fingerprintAbsoluteMobileUpdateRuntime = (descriptor) => createHash11("sha256").update(canonicalizeAbsoluteMobileUpdate(descriptor)).digest("hex");
28943
+ var fingerprintAbsoluteMobileUpdateRuntime = (descriptor) => createHash12("sha256").update(canonicalizeAbsoluteMobileUpdate(descriptor)).digest("hex");
28636
28944
  var resolveAbsoluteMobileUpdateRuntime = (config, projectRoot) => {
28637
28945
  const auth = resolveAbsoluteMobileAuthManifest(projectRoot, config);
28638
28946
  const sync = auth !== undefined && projectUsesAbsoluteSync(projectRoot);
@@ -28655,7 +28963,7 @@ var resolveAbsoluteMobileUpdateRuntime = (config, projectRoot) => {
28655
28963
  };
28656
28964
 
28657
28965
  // src/mobile/expoNativeObservability.ts
28658
- import { join as join15 } from "path";
28966
+ import { join as join16 } from "path";
28659
28967
  var HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.
28660
28968
  `;
28661
28969
  var XML_HEADER = `<!-- Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync. -->
@@ -29097,31 +29405,31 @@ export const enqueueAbsoluteExpoNativeObservabilityForTesting = async (testId: s
29097
29405
  `;
29098
29406
  var absoluteExpoNativeObservabilityFiles = (project) => new Map([
29099
29407
  [
29100
- join15(project, "modules/absolute-mobile-observability/expo-module.config.json"),
29408
+ join16(project, "modules/absolute-mobile-observability/expo-module.config.json"),
29101
29409
  moduleConfig
29102
29410
  ],
29103
29411
  [
29104
- join15(project, "modules/absolute-mobile-observability/ios/AbsoluteMobileObservability.podspec"),
29412
+ join16(project, "modules/absolute-mobile-observability/ios/AbsoluteMobileObservability.podspec"),
29105
29413
  podspec
29106
29414
  ],
29107
29415
  [
29108
- join15(project, "modules/absolute-mobile-observability/ios/AbsoluteMobileObservabilityModule.swift"),
29416
+ join16(project, "modules/absolute-mobile-observability/ios/AbsoluteMobileObservabilityModule.swift"),
29109
29417
  iosModule
29110
29418
  ],
29111
29419
  [
29112
- join15(project, "modules/absolute-mobile-observability/android/build.gradle"),
29420
+ join16(project, "modules/absolute-mobile-observability/android/build.gradle"),
29113
29421
  androidBuild
29114
29422
  ],
29115
29423
  [
29116
- join15(project, "modules/absolute-mobile-observability/android/src/main/AndroidManifest.xml"),
29424
+ join16(project, "modules/absolute-mobile-observability/android/src/main/AndroidManifest.xml"),
29117
29425
  androidManifest
29118
29426
  ],
29119
29427
  [
29120
- join15(project, "modules/absolute-mobile-observability/android/src/main/java/expo/modules/absolutemobileobservability/AbsoluteMobileObservabilityModule.kt"),
29428
+ join16(project, "modules/absolute-mobile-observability/android/src/main/java/expo/modules/absolutemobileobservability/AbsoluteMobileObservabilityModule.kt"),
29121
29429
  androidModule
29122
29430
  ],
29123
29431
  [
29124
- join15(project, "src/generated/AbsoluteNativeObservability.ts"),
29432
+ join16(project, "src/generated/AbsoluteNativeObservability.ts"),
29125
29433
  expoNativeObservabilityRuntimeSource
29126
29434
  ]
29127
29435
  ]);
@@ -29130,7 +29438,7 @@ var absoluteExpoNativeObservabilityPaths = (project) => [
29130
29438
  ];
29131
29439
 
29132
29440
  // src/mobile/expoActivityResultRecovery.ts
29133
- import { join as join16 } from "path";
29441
+ import { join as join17 } from "path";
29134
29442
  var HEADER2 = `// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.
29135
29443
  `;
29136
29444
  var XML_HEADER2 = `<!-- Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync. -->
@@ -29257,6 +29565,15 @@ class AbsoluteActivityResultRecoveryModule : Module() {
29257
29565
  Log.d("AbsoluteJS", "Expo application runtime ready for Android activity results")
29258
29566
  }
29259
29567
 
29568
+ Function("markEmbeddedWebReady") {
29569
+ Log.i("AbsoluteJS", "Expo embedded web content ready")
29570
+ }
29571
+
29572
+ Function("markEmbeddedWebPhase") { phase: String ->
29573
+ val allowed = setOf("assets-start", "assets-ready", "assets-root-failed", "assets-directory-failed", "assets-destination-failed", "assets-module-failed", "assets-source-failed", "assets-download-failed", "assets-copy-failed", "assets-read-failed", "assets-write-failed", "assets-finalize-failed", "assets-unexpected-failed", "devices-start", "devices-ready", "devices-failed")
29574
+ if (allowed.contains(phase)) Log.i("AbsoluteJS", "Expo embedded web phase: " + phase)
29575
+ }
29576
+
29260
29577
  Function("takePendingCancellation") {
29261
29578
  AbsoluteActivityResultRecoveryState.takePendingCancellation()
29262
29579
  }
@@ -29267,6 +29584,8 @@ var runtime = `${HEADER2}import { requireNativeModule } from 'expo-modules-core'
29267
29584
 
29268
29585
  type AbsoluteActivityResultRecoveryNative = {
29269
29586
  markApplicationRuntimeReady(): void;
29587
+ markEmbeddedWebPhase(phase: AbsoluteEmbeddedWebPhase): void;
29588
+ markEmbeddedWebReady(): void;
29270
29589
  takePendingCancellation(): boolean;
29271
29590
  };
29272
29591
 
@@ -29277,28 +29596,52 @@ const native = requireNativeModule<AbsoluteActivityResultRecoveryNative>(
29277
29596
  export const markAbsoluteApplicationRuntimeReady = () =>
29278
29597
  native.markApplicationRuntimeReady();
29279
29598
 
29599
+ export const markAbsoluteEmbeddedWebReady = () =>
29600
+ native.markEmbeddedWebReady();
29601
+
29602
+ export type AbsoluteEmbeddedWebPhase =
29603
+ | 'assets-start'
29604
+ | 'assets-ready'
29605
+ | 'assets-root-failed'
29606
+ | 'assets-directory-failed'
29607
+ | 'assets-destination-failed'
29608
+ | 'assets-module-failed'
29609
+ | 'assets-source-failed'
29610
+ | 'assets-download-failed'
29611
+ | 'assets-copy-failed'
29612
+ | 'assets-read-failed'
29613
+ | 'assets-write-failed'
29614
+ | 'assets-finalize-failed'
29615
+ | 'assets-unexpected-failed'
29616
+ | 'devices-start'
29617
+ | 'devices-ready'
29618
+ | 'devices-failed';
29619
+
29620
+ export const markAbsoluteEmbeddedWebPhase = (phase: AbsoluteEmbeddedWebPhase) =>
29621
+ native.markEmbeddedWebPhase(phase);
29622
+
29280
29623
  export const takeAbsoluteActivityResultCancellation = () =>
29281
29624
  native.takePendingCancellation();
29282
29625
  `;
29283
29626
  var absoluteExpoActivityResultRecoveryFiles = (project) => new Map([
29284
29627
  [
29285
- join16(project, "modules/absolute-activity-result-recovery/expo-module.config.json"),
29628
+ join17(project, "modules/absolute-activity-result-recovery/expo-module.config.json"),
29286
29629
  moduleConfig2
29287
29630
  ],
29288
29631
  [
29289
- join16(project, "modules/absolute-activity-result-recovery/android/build.gradle"),
29632
+ join17(project, "modules/absolute-activity-result-recovery/android/build.gradle"),
29290
29633
  androidBuild2
29291
29634
  ],
29292
29635
  [
29293
- join16(project, "modules/absolute-activity-result-recovery/android/src/main/AndroidManifest.xml"),
29636
+ join17(project, "modules/absolute-activity-result-recovery/android/src/main/AndroidManifest.xml"),
29294
29637
  androidManifest2
29295
29638
  ],
29296
29639
  [
29297
- join16(project, "modules/absolute-activity-result-recovery/android/src/main/java/expo/modules/absoluteactivityresultrecovery/AbsoluteActivityResultRecoveryModule.kt"),
29640
+ join17(project, "modules/absolute-activity-result-recovery/android/src/main/java/expo/modules/absoluteactivityresultrecovery/AbsoluteActivityResultRecoveryModule.kt"),
29298
29641
  androidModule2
29299
29642
  ],
29300
29643
  [
29301
- join16(project, "src/generated/AbsoluteActivityResultRecovery.ts"),
29644
+ join17(project, "src/generated/AbsoluteActivityResultRecovery.ts"),
29302
29645
  runtime
29303
29646
  ]
29304
29647
  ]);
@@ -29308,15 +29651,15 @@ var EXPO_GENERATED_HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts
29308
29651
  `;
29309
29652
  var EXPO_ASSET_EXTENSION = ".absasset";
29310
29653
  var EXPO_PROJECT_MARKER = ".absolutejs-expo-project";
29311
- var exists3 = async (path) => {
29654
+ var exists4 = async (path) => {
29312
29655
  try {
29313
- await access10(path);
29656
+ await access11(path);
29314
29657
  return true;
29315
29658
  } catch {
29316
29659
  return false;
29317
29660
  }
29318
29661
  };
29319
- var isRecord8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
29662
+ var isRecord9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
29320
29663
  var requireManifestString = (value, field2) => {
29321
29664
  if (typeof value !== "string" || !value) {
29322
29665
  throw new TypeError(`AbsoluteJS mobile manifest ${field2} is invalid.`);
@@ -29324,11 +29667,11 @@ var requireManifestString = (value, field2) => {
29324
29667
  return value;
29325
29668
  };
29326
29669
  var expoNativeDataManifest = (value) => {
29327
- if (!isRecord8(value) || !Array.isArray(value.pages) || !Array.isArray(value.routes)) {
29670
+ if (!isRecord9(value) || !Array.isArray(value.pages) || !Array.isArray(value.routes)) {
29328
29671
  throw new TypeError("AbsoluteJS mobile manifest is invalid.");
29329
29672
  }
29330
29673
  const pages = value.pages.map((page) => {
29331
- if (!isRecord8(page))
29674
+ if (!isRecord9(page))
29332
29675
  throw new TypeError("AbsoluteJS mobile manifest page is invalid.");
29333
29676
  return {
29334
29677
  bundleHash: requireManifestString(page.bundleHash, "page.bundleHash"),
@@ -29337,7 +29680,7 @@ var expoNativeDataManifest = (value) => {
29337
29680
  };
29338
29681
  });
29339
29682
  const routes = value.routes.flatMap((route) => {
29340
- if (!isRecord8(route) || typeof route.method !== "string") {
29683
+ if (!isRecord9(route) || typeof route.method !== "string") {
29341
29684
  throw new TypeError("AbsoluteJS mobile manifest route is invalid.");
29342
29685
  }
29343
29686
  if (route.method !== "GET")
@@ -29352,7 +29695,7 @@ var expoNativeDataManifest = (value) => {
29352
29695
  });
29353
29696
  return {
29354
29697
  appBuild: requireManifestString(value.appBuild, "appBuild"),
29355
- ...isRecord8(value.observability) && typeof value.observability.endpoint === "string" && typeof value.observability.project === "string" && typeof value.observability.sampleRate === "number" ? {
29698
+ ...isRecord9(value.observability) && typeof value.observability.endpoint === "string" && typeof value.observability.project === "string" && typeof value.observability.sampleRate === "number" ? {
29356
29699
  observability: {
29357
29700
  endpoint: value.observability.endpoint,
29358
29701
  ...typeof value.observability.environment === "string" ? { environment: value.observability.environment } : {},
@@ -29367,7 +29710,7 @@ var expoNativeDataManifest = (value) => {
29367
29710
  };
29368
29711
  };
29369
29712
  var portableRelative2 = (from, destination) => {
29370
- const value = relative10(from, destination).replaceAll("\\", "/");
29713
+ const value = relative11(from, destination).replaceAll("\\", "/");
29371
29714
  return value.startsWith(".") ? value : `./${value}`;
29372
29715
  };
29373
29716
  var routeSegments = (route) => {
@@ -29383,7 +29726,7 @@ var routeSegments = (route) => {
29383
29726
  return segment;
29384
29727
  });
29385
29728
  };
29386
- var routeFile = (project, route) => join17(project, "app", ...routeSegments(route), "index.tsx");
29729
+ var routeFile = (project, route) => join18(project, "app", ...routeSegments(route), "index.tsx");
29387
29730
  var packageDependencies = (plan) => Object.fromEntries(plan.requiredPackages.map((spec) => {
29388
29731
  const separator = spec.lastIndexOf("@");
29389
29732
  return [spec.slice(0, separator), spec.slice(separator + 1)];
@@ -29937,7 +30280,7 @@ ${push ? `absoluteExpoAuth.onPrincipalChange(principal => {
29937
30280
  `;
29938
30281
  };
29939
30282
  var authRuntimeSource = (auth, appId) => {
29940
- const storageIdentity = createHash12("sha256").update(appId).digest("hex").slice(0, 24);
30283
+ const storageIdentity = createHash13("sha256").update(appId).digest("hex").slice(0, 24);
29941
30284
  return `${EXPO_GENERATED_HEADER}import { createAbsoluteExpoAuthClient } from '@absolutejs/auth-expo';
29942
30285
  import { createMobileAuthTransport, installAuthClientRuntimeTransport } from '@absolutejs/auth/client/mobile';
29943
30286
 
@@ -29969,7 +30312,7 @@ export const startAbsoluteExpoAuth = () => {
29969
30312
  `;
29970
30313
  };
29971
30314
  var syncRuntimeSource = (config, schema) => {
29972
- const storageIdentity = createHash12("sha256").update(config.appId).digest("hex").slice(0, 24);
30315
+ const storageIdentity = createHash13("sha256").update(config.appId).digest("hex").slice(0, 24);
29973
30316
  const backgroundEndpoint = new URL("/__absolute/sync/background", config.productionOrigin).href;
29974
30317
  const backgroundTask = `${config.appId}.absolutejs.sync`;
29975
30318
  return `${EXPO_GENERATED_HEADER}import { runHeadlessSync } from '@absolutejs/sync/client/headless';
@@ -30088,10 +30431,11 @@ var webHostSource = (config, auth, sync) => {
30088
30431
  return `${EXPO_GENERATED_HEADER}import * as Linking from 'expo-linking';
30089
30432
  import { router, usePathname } from 'expo-router';
30090
30433
  import { useEffect, useMemo, useRef, useState } from 'react';
30091
- import { ActivityIndicator, BackHandler, Platform, StyleSheet, View } from 'react-native';
30434
+ import { ActivityIndicator, BackHandler, Platform, Pressable, StyleSheet, Text, View } from 'react-native';
30092
30435
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
30093
30436
  import { WebView, type WebViewMessageEvent } from 'react-native-webview';
30094
30437
  import { materializeAbsoluteWebBundle } from './webAssets';
30438
+ import { markAbsoluteEmbeddedWebPhase, markAbsoluteEmbeddedWebReady } from './AbsoluteActivityResultRecovery';
30095
30439
  import { createExpoDevicesBridgeHost } from '@absolutejs/devices-expo/bridge';
30096
30440
  import { absoluteExpoDevices, beforeAbsoluteExpoDeviceSignOut } from './AbsoluteDevices';
30097
30441
  ${auth ? "import { absoluteExpoAuth, getAbsoluteExpoAuthPrincipal, startAbsoluteExpoAuth } from './AbsoluteAuth';" : ""}
@@ -30255,7 +30599,10 @@ export function AbsoluteWebHost({ path }: AbsoluteWebHostProps = {}) {
30255
30599
  const canGoBack = useRef(false);
30256
30600
  const [runtimeReady, setRuntimeReady] = useState(!AUTH_ENABLED && !SYNC_ENABLED);
30257
30601
  const [devicesReady, setDevicesReady] = useState(false);
30602
+ const [startupError, setStartupError] = useState<'assets' | 'devices'>();
30603
+ const [startupRevision, setStartupRevision] = useState(0);
30258
30604
  const activeWebPath = useRef(pathname);
30605
+ const embeddedReadyReported = useRef(false);
30259
30606
  const webSource = useMemo(() => indexUri ? { uri: indexUri } : undefined, [indexUri]);
30260
30607
 
30261
30608
  useEffect(() => {
@@ -30289,8 +30636,18 @@ export function AbsoluteWebHost({ path }: AbsoluteWebHostProps = {}) {
30289
30636
  setIndexUri(target.href);
30290
30637
  return;
30291
30638
  }
30292
- void materializeAbsoluteWebBundle().then(uri => setIndexUri(uri + '?absolutePath=' + encodeURIComponent(pathname)));
30293
- }, [pathname]);
30639
+ markAbsoluteEmbeddedWebPhase('assets-start');
30640
+ void materializeAbsoluteWebBundle().then(uri => {
30641
+ markAbsoluteEmbeddedWebPhase('assets-ready');
30642
+ setIndexUri(uri + '?absolutePath=' + encodeURIComponent(pathname));
30643
+ }).catch(error => {
30644
+ const phase = error instanceof Error && (error.message === 'assets-root-failed' || error.message === 'assets-directory-failed' || error.message === 'assets-destination-failed' || error.message === 'assets-module-failed' || error.message === 'assets-source-failed' || error.message === 'assets-download-failed' || error.message === 'assets-copy-failed' || error.message === 'assets-read-failed' || error.message === 'assets-write-failed' || error.message === 'assets-finalize-failed')
30645
+ ? error.message
30646
+ : 'assets-unexpected-failed';
30647
+ markAbsoluteEmbeddedWebPhase(phase);
30648
+ setStartupError('assets');
30649
+ });
30650
+ }, [pathname, startupRevision]);
30294
30651
  useEffect(() => {
30295
30652
  webView.current?.injectJavaScript(hostMetricsScript(safeAreaInsets));
30296
30653
  }, [safeAreaInsets.bottom, safeAreaInsets.left, safeAreaInsets.right, safeAreaInsets.top]);
@@ -30310,13 +30667,19 @@ export function AbsoluteWebHost({ path }: AbsoluteWebHostProps = {}) {
30310
30667
  };
30311
30668
  useEffect(() => {
30312
30669
  let active = true;
30670
+ markAbsoluteEmbeddedWebPhase('devices-start');
30313
30671
  void createExpoDevicesBridgeHost(absoluteExpoDevices, (event, payload) => {
30314
30672
  if (!active) return;
30315
30673
  respond({ event, format: BRIDGE_FORMAT, kind: 'event', path: activeWebPath.current, payload });
30316
30674
  }).then(host => {
30317
30675
  if (!active) return void Promise.resolve(host.close()).catch(() => undefined);
30318
30676
  devicesBridge.current = host;
30677
+ markAbsoluteEmbeddedWebPhase('devices-ready');
30319
30678
  setDevicesReady(true);
30679
+ }).catch(() => {
30680
+ if (!active) return;
30681
+ markAbsoluteEmbeddedWebPhase('devices-failed');
30682
+ setStartupError('devices');
30320
30683
  });
30321
30684
  return () => {
30322
30685
  active = false;
@@ -30324,7 +30687,7 @@ export function AbsoluteWebHost({ path }: AbsoluteWebHostProps = {}) {
30324
30687
  devicesBridge.current = undefined;
30325
30688
  if (host) void Promise.resolve(host.close()).catch(() => undefined);
30326
30689
  };
30327
- }, []);
30690
+ }, [startupRevision]);
30328
30691
  const hasOrigin = (source: string, origin: string) => {
30329
30692
  try { return new URL(source).origin === origin; } catch { return false; }
30330
30693
  };
@@ -30337,6 +30700,10 @@ export function AbsoluteWebHost({ path }: AbsoluteWebHostProps = {}) {
30337
30700
  if (message.kind === 'event' && (message.event === 'navigation' || message.event === 'ready')) {
30338
30701
  const target = new URL(message.path, PRODUCTION_ORIGIN);
30339
30702
  if (target.origin !== PRODUCTION_ORIGIN) return;
30703
+ if (message.event === 'ready' && !DEV_ORIGIN && !embeddedReadyReported.current) {
30704
+ embeddedReadyReported.current = true;
30705
+ markAbsoluteEmbeddedWebReady();
30706
+ }
30340
30707
  if (isNativeRoute(target.pathname)) router.push(message.path as never);
30341
30708
  else activeWebPath.current = message.path;
30342
30709
  return;
@@ -30376,6 +30743,15 @@ export function AbsoluteWebHost({ path }: AbsoluteWebHostProps = {}) {
30376
30743
  }
30377
30744
  };
30378
30745
 
30746
+ if (startupError) return <View style={styles.loading}>
30747
+ <Text accessibilityRole="alert" style={styles.error}>Embedded content could not start.</Text>
30748
+ <Pressable accessibilityRole="button" onPress={() => {
30749
+ setStartupError(undefined);
30750
+ setIndexUri(undefined);
30751
+ setDevicesReady(false);
30752
+ setStartupRevision(value => value + 1);
30753
+ }} style={styles.retry}><Text>Try again</Text></Pressable>
30754
+ </View>;
30379
30755
  if (!webSource || !runtimeReady || !devicesReady) return <View style={styles.loading}><ActivityIndicator /></View>;
30380
30756
  return <WebView
30381
30757
  allowFileAccess
@@ -30401,7 +30777,7 @@ export function AbsoluteWebHost({ path }: AbsoluteWebHostProps = {}) {
30401
30777
  />;
30402
30778
  }
30403
30779
 
30404
- const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, justifyContent: 'center' }, web: { flex: 1 } });
30780
+ const styles = StyleSheet.create({ error: { marginBottom: 12 }, loading: { alignItems: 'center', flex: 1, justifyContent: 'center' }, retry: { borderWidth: 1, paddingHorizontal: 16, paddingVertical: 12 }, web: { flex: 1 } });
30405
30781
  `;
30406
30782
  };
30407
30783
  var webRouteSource = `${EXPO_GENERATED_HEADER}import { AbsoluteWebHost } from '../src/generated/AbsoluteWebHost';
@@ -30595,8 +30971,8 @@ const styles = StyleSheet.create({
30595
30971
  error: { color: '#b91c1c', fontSize: 16, textAlign: 'center' }
30596
30972
  });
30597
30973
  `;
30598
- var nativeWrapperSource = (wrapper, module, runtime2, route) => `${EXPO_GENERATED_HEADER}import ApplicationNativeRoute from ${JSON.stringify(portableRelative2(dirname10(wrapper), module).replace(/\.(?:[cm]?[jt]sx?)$/u, ""))};
30599
- import { createAbsoluteNativeRoute, createAbsoluteNativeRouteErrorBoundary } from ${JSON.stringify(portableRelative2(dirname10(wrapper), runtime2).replace(/\.(?:[cm]?[jt]sx?)$/u, ""))};
30974
+ var nativeWrapperSource = (wrapper, module, runtime2, route) => `${EXPO_GENERATED_HEADER}import ApplicationNativeRoute from ${JSON.stringify(portableRelative2(dirname11(wrapper), module).replace(/\.(?:[cm]?[jt]sx?)$/u, ""))};
30975
+ import { createAbsoluteNativeRoute, createAbsoluteNativeRouteErrorBoundary } from ${JSON.stringify(portableRelative2(dirname11(wrapper), runtime2).replace(/\.(?:[cm]?[jt]sx?)$/u, ""))};
30600
30976
 
30601
30977
  export const ErrorBoundary = createAbsoluteNativeRouteErrorBoundary(${JSON.stringify(route)});
30602
30978
  export default createAbsoluteNativeRoute(ApplicationNativeRoute, ${JSON.stringify(route)});
@@ -30638,9 +31014,9 @@ var expoTsConfig = (projectRoot, project, auth, sync) => ({
30638
31014
  extends: "expo/tsconfig.base"
30639
31015
  });
30640
31016
  var writeManagedFile = async (path, source, force) => {
30641
- await mkdir11(dirname10(path), { recursive: true });
30642
- if (await exists3(path)) {
30643
- const current = await readFile14(path, "utf8");
31017
+ await mkdir12(dirname11(path), { recursive: true });
31018
+ if (await exists4(path)) {
31019
+ const current = await readFile15(path, "utf8");
30644
31020
  if (current === source)
30645
31021
  return false;
30646
31022
  if (!force && !current.startsWith(EXPO_GENERATED_HEADER)) {
@@ -30648,32 +31024,32 @@ var writeManagedFile = async (path, source, force) => {
30648
31024
  }
30649
31025
  }
30650
31026
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
30651
- await writeFile12(temporary, source, { flag: "wx" });
30652
- await rename11(temporary, path);
31027
+ await writeFile13(temporary, source, { flag: "wx" });
31028
+ await rename12(temporary, path);
30653
31029
  return true;
30654
31030
  };
30655
31031
  var pruneManagedFiles = async (paths) => {
30656
31032
  const removed = await Promise.all(paths.map(async (path) => {
30657
- if (!await exists3(path))
31033
+ if (!await exists4(path))
30658
31034
  return false;
30659
- const source = await readFile14(path, "utf8");
31035
+ const source = await readFile15(path, "utf8");
30660
31036
  if (!source.startsWith(EXPO_GENERATED_HEADER) && !path.endsWith("expo-module.config.json"))
30661
31037
  return false;
30662
- await rm10(path, { force: true });
31038
+ await rm11(path, { force: true });
30663
31039
  return true;
30664
31040
  }));
30665
31041
  return removed.filter(Boolean).length;
30666
31042
  };
30667
31043
  var pruneStaleManagedExpoRoutes = async (project, expected) => {
30668
- const appDirectory = join17(project, "app");
30669
- if (!await exists3(appDirectory))
31044
+ const appDirectory = join18(project, "app");
31045
+ if (!await exists4(appDirectory))
30670
31046
  return 0;
30671
31047
  const files = await walkFiles(appDirectory);
30672
31048
  const stale = (await Promise.all(files.map(async (path) => ({
30673
- managed: path.endsWith(".tsx") && (await readFile14(path, "utf8")).startsWith(EXPO_GENERATED_HEADER),
31049
+ managed: path.endsWith(".tsx") && (await readFile15(path, "utf8")).startsWith(EXPO_GENERATED_HEADER),
30674
31050
  path
30675
31051
  })))).filter(({ managed, path }) => managed && !expected.has(path));
30676
- await Promise.all(stale.map(({ path }) => rm10(path, { force: true })));
31052
+ await Promise.all(stale.map(({ path }) => rm11(path, { force: true })));
30677
31053
  return stale.length;
30678
31054
  };
30679
31055
  var jsonSource = (value) => `${JSON.stringify(value, null, "\t")}
@@ -30696,7 +31072,7 @@ export const ABSOLUTE_MOBILE_MANIFEST: AbsoluteMobileManifest | undefined = unde
30696
31072
  var writeAbsoluteExpoProject = async (config, options) => {
30697
31073
  if (config.engine !== "expo")
30698
31074
  throw new TypeError("Expo project generation requires mobile.engine: expo.");
30699
- const projectRoot = resolve12(options.projectRoot);
31075
+ const projectRoot = resolve13(options.projectRoot);
30700
31076
  const project = config.nativeProjectDirectory;
30701
31077
  const auth = resolveAbsoluteMobileAuthManifest(projectRoot, config);
30702
31078
  const devices = resolveAbsoluteDeviceCapabilityPlan(projectRoot, "expo");
@@ -30705,7 +31081,7 @@ var writeAbsoluteExpoProject = async (config, options) => {
30705
31081
  const runtimeFingerprint = resolveAbsoluteMobileUpdateRuntime(config, projectRoot).fingerprint;
30706
31082
  const routeModules = Object.entries(config.expoNativeRoutes);
30707
31083
  const moduleChecks = await Promise.all(routeModules.map(async ([route, module]) => ({
30708
- exists: await exists3(module),
31084
+ exists: await exists4(module),
30709
31085
  module,
30710
31086
  route
30711
31087
  })));
@@ -30713,20 +31089,20 @@ var writeAbsoluteExpoProject = async (config, options) => {
30713
31089
  if (missing) {
30714
31090
  throw new TypeError(`Expo native route ${missing.route} references missing module ${missing.module}.`);
30715
31091
  }
30716
- const marker = join17(project, EXPO_PROJECT_MARKER);
30717
- if (await exists3(project) && !await exists3(marker)) {
31092
+ const marker = join18(project, EXPO_PROJECT_MARKER);
31093
+ if (await exists4(project) && !await exists4(marker)) {
30718
31094
  const entries = await readdir4(project);
30719
31095
  if (entries.length > 0 && !options.force) {
30720
31096
  throw new TypeError(`Expo project directory ${project} is not AbsoluteJS-managed; rerun with --force only after reviewing it.`);
30721
31097
  }
30722
31098
  }
30723
- await mkdir11(project, { recursive: true });
30724
- await writeFile12(marker, `format=1
31099
+ await mkdir12(project, { recursive: true });
31100
+ await writeFile13(marker, `format=1
30725
31101
  `);
30726
31102
  const authEnabled = Boolean(auth);
30727
31103
  const files = new Map([
30728
31104
  [
30729
- join17(project, ".gitignore"),
31105
+ join18(project, ".gitignore"),
30730
31106
  `.expo/
30731
31107
  android/
30732
31108
  ios/
@@ -30734,45 +31110,45 @@ node_modules/
30734
31110
  `
30735
31111
  ],
30736
31112
  [
30737
- join17(project, "app.json"),
31113
+ join18(project, "app.json"),
30738
31114
  jsonSource(expoAppConfig(config, authEnabled, syncEnabled, devices, runtimeFingerprint))
30739
31115
  ],
30740
- [join17(project, "app.config.js"), expoDynamicAppConfig],
31116
+ [join18(project, "app.config.js"), expoDynamicAppConfig],
30741
31117
  [
30742
- join17(project, "package.json"),
31118
+ join18(project, "package.json"),
30743
31119
  jsonSource(expoPackage(authEnabled, syncEnabled, devices, config.updates !== undefined))
30744
31120
  ],
30745
- [join17(project, "metro.config.js"), metroConfig(projectRoot)],
31121
+ [join18(project, "metro.config.js"), metroConfig(projectRoot)],
30746
31122
  [
30747
- join17(project, "plugins", "withAbsoluteDevelopmentCa.js"),
31123
+ join18(project, "plugins", "withAbsoluteDevelopmentCa.js"),
30748
31124
  expoDevelopmentCaPlugin
30749
31125
  ],
30750
31126
  [
30751
- join17(project, "plugins", "withAbsoluteActivityResultRecovery.js"),
31127
+ join18(project, "plugins", "withAbsoluteActivityResultRecovery.js"),
30752
31128
  expoActivityResultRecoveryPlugin
30753
31129
  ],
30754
31130
  [
30755
- join17(project, "tsconfig.json"),
31131
+ join18(project, "tsconfig.json"),
30756
31132
  jsonSource(expoTsConfig(projectRoot, project, authEnabled, syncEnabled))
30757
31133
  ],
30758
31134
  [
30759
- join17(project, "app", "_layout.tsx"),
31135
+ join18(project, "app", "_layout.tsx"),
30760
31136
  layoutSource(authEnabled, syncEnabled, config.updates !== undefined, config.observability !== undefined)
30761
31137
  ],
30762
31138
  [
30763
- join17(project, "app", "__absolute", "native", "index.tsx"),
31139
+ join18(project, "app", "__absolute", "native", "index.tsx"),
30764
31140
  nativeDiagnosticSource
30765
31141
  ],
30766
31142
  [
30767
- join17(project, "src", "generated", "AbsoluteDevices.ts"),
31143
+ join18(project, "src", "generated", "AbsoluteDevices.ts"),
30768
31144
  devicesRuntimeSource(config, devices, authEnabled)
30769
31145
  ],
30770
31146
  [
30771
- join17(project, "src", "generated", "AbsoluteNativeRoute.tsx"),
31147
+ join18(project, "src", "generated", "AbsoluteNativeRoute.tsx"),
30772
31148
  nativeRouteRuntimeSource(authEnabled)
30773
31149
  ],
30774
31150
  [
30775
- join17(project, "src", "generated", "AbsoluteWebHost.tsx"),
31151
+ join18(project, "src", "generated", "AbsoluteWebHost.tsx"),
30776
31152
  webHostSource(config, auth, syncEnabled)
30777
31153
  ]
30778
31154
  ]);
@@ -30783,31 +31159,31 @@ node_modules/
30783
31159
  files.set(path, source);
30784
31160
  }
30785
31161
  if (config.updates) {
30786
- files.set(join17(project, "src", "generated", "AbsoluteUpdates.ts"), updatesRuntimeSource(config));
31162
+ files.set(join18(project, "src", "generated", "AbsoluteUpdates.ts"), updatesRuntimeSource(config));
30787
31163
  }
30788
31164
  const expoCodeSigning = config.updates?.expoCodeSigning;
30789
31165
  if (expoCodeSigning)
30790
- files.set(join17(project, "certs", "absolute-mobile-update.pem"), expoCodeSigning.certificatePem);
31166
+ files.set(join18(project, "certs", "absolute-mobile-update.pem"), expoCodeSigning.certificatePem);
30791
31167
  if (auth) {
30792
- files.set(join17(project, "src", "generated", "AbsoluteAuth.ts"), authRuntimeSource(auth, config.appId));
31168
+ files.set(join18(project, "src", "generated", "AbsoluteAuth.ts"), authRuntimeSource(auth, config.appId));
30793
31169
  }
30794
31170
  if (syncSchema) {
30795
- files.set(join17(project, "src", "generated", "AbsoluteSync.ts"), syncRuntimeSource(config, syncSchema));
31171
+ files.set(join18(project, "src", "generated", "AbsoluteSync.ts"), syncRuntimeSource(config, syncSchema));
30796
31172
  }
30797
- const webAssetsPath = join17(project, "src", "generated", "webAssets.ts");
30798
- if (!await exists3(webAssetsPath)) {
31173
+ const webAssetsPath = join18(project, "src", "generated", "webAssets.ts");
31174
+ if (!await exists4(webAssetsPath)) {
30799
31175
  files.set(webAssetsPath, emptyWebAssetsSource);
30800
31176
  }
30801
31177
  if (!config.expoNativeRoutes["/"]) {
30802
- files.set(join17(project, "app", "index.tsx"), webRouteSource);
31178
+ files.set(join18(project, "app", "index.tsx"), webRouteSource);
30803
31179
  }
30804
- files.set(join17(project, "app", "[...absolute].tsx"), catchAllRouteSource);
30805
- const nativeRouteRuntime = join17(project, "src", "generated", "AbsoluteNativeRoute.tsx");
31180
+ files.set(join18(project, "app", "[...absolute].tsx"), catchAllRouteSource);
31181
+ const nativeRouteRuntime = join18(project, "src", "generated", "AbsoluteNativeRoute.tsx");
30806
31182
  for (const [route, module] of routeModules) {
30807
- const wrapper = route === "/" ? join17(project, "app", "index.tsx") : routeFile(project, route);
31183
+ const wrapper = route === "/" ? join18(project, "app", "index.tsx") : routeFile(project, route);
30808
31184
  files.set(wrapper, nativeWrapperSource(wrapper, module, nativeRouteRuntime, route));
30809
31185
  }
30810
- const removedRoutes = await pruneStaleManagedExpoRoutes(project, new Set([...files.keys()].filter((path) => path.startsWith(`${join17(project, "app")}${sep6}`))));
31186
+ const removedRoutes = await pruneStaleManagedExpoRoutes(project, new Set([...files.keys()].filter((path) => path.startsWith(`${join18(project, "app")}${sep7}`))));
30811
31187
  const removedObservability = config.observability ? 0 : await pruneManagedFiles(absoluteExpoNativeObservabilityPaths(project));
30812
31188
  const changes = await Promise.all([...files].map(([path, source]) => writeManagedFile(path, source, true)));
30813
31189
  const changed = removedRoutes + removedObservability + changes.filter(Boolean).length;
@@ -30816,7 +31192,7 @@ node_modules/
30816
31192
  var walkFiles = async (root, directory = root) => {
30817
31193
  const entries = await readdir4(directory, { withFileTypes: true });
30818
31194
  const nested = await Promise.all(entries.map((entry) => {
30819
- const path = join17(directory, entry.name);
31195
+ const path = join18(directory, entry.name);
30820
31196
  if (entry.isDirectory())
30821
31197
  return walkFiles(root, path);
30822
31198
  if (entry.isFile())
@@ -30827,7 +31203,7 @@ var walkFiles = async (root, directory = root) => {
30827
31203
  };
30828
31204
  var renameIfPresent = async (source, destination) => {
30829
31205
  try {
30830
- await rename11(source, destination);
31206
+ await rename12(source, destination);
30831
31207
  return true;
30832
31208
  } catch (error) {
30833
31209
  if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "ENOENT") {
@@ -30840,87 +31216,130 @@ var installStagedDirectory = async (staging, destination) => {
30840
31216
  const backup = `${destination}.previous-${crypto.randomUUID()}`;
30841
31217
  const moved = await renameIfPresent(destination, backup);
30842
31218
  try {
30843
- await rename11(staging, destination);
31219
+ await rename12(staging, destination);
30844
31220
  if (moved)
30845
- await rm10(backup, { force: true, recursive: true });
31221
+ await rm11(backup, { force: true, recursive: true });
30846
31222
  } catch (error) {
30847
31223
  if (moved)
30848
- await rename11(backup, destination);
31224
+ await rename12(backup, destination);
30849
31225
  throw error;
30850
31226
  }
30851
31227
  };
30852
- var assetModuleSource = (assets, bundleId, manifest) => `${EXPO_GENERATED_HEADER}import { Asset } from 'expo-asset';
31228
+ var assetModuleSource = (assets, archiveAsset, bundleId, manifest) => `${EXPO_GENERATED_HEADER}import { Asset } from 'expo-asset';
30853
31229
  import { Directory, File, Paths } from 'expo-file-system';
31230
+ import { copyAsync as copyLegacyAsync } from 'expo-file-system/legacy';
30854
31231
 
30855
31232
  ${nativeDataManifestTypeSource}
30856
31233
  declare const require: (path: string) => number;
30857
31234
  const BUNDLE_ID = ${JSON.stringify(bundleId)};
30858
31235
  export const ABSOLUTE_MOBILE_MANIFEST: AbsoluteMobileManifest = ${JSON.stringify(manifest)};
31236
+ const ARCHIVE_MODULE = require(${JSON.stringify(archiveAsset)});
30859
31237
  const ASSETS = [
30860
- ${assets.map(({ asset, path }) => ` { module: require(${JSON.stringify(asset)}), path: ${JSON.stringify(path)} }`).join(`,
31238
+ ${assets.map((entry) => ` ${JSON.stringify(entry)}`).join(`,
30861
31239
  `)}
30862
31240
  ] as const;
30863
31241
 
30864
31242
  export const materializeAbsoluteWebBundle = async () => {
30865
- const root = new Directory(Paths.document, 'absolutejs-web', BUNDLE_ID);
30866
- root.create({ idempotent: true, intermediates: true });
31243
+ let root: Directory;
31244
+ try {
31245
+ root = new Directory(Paths.document, 'absolutejs-web', BUNDLE_ID);
31246
+ root.create({ idempotent: true, intermediates: true });
31247
+ } catch { throw new Error('assets-root-failed'); }
31248
+ let archive: File;
31249
+ try { archive = new File(root, '.absolutejs-bundle.absasset'); }
31250
+ catch { throw new Error('assets-destination-failed'); }
31251
+ if (!archive.exists) {
31252
+ let asset: Asset;
31253
+ try { asset = Asset.fromModule(ARCHIVE_MODULE); }
31254
+ catch { throw new Error('assets-module-failed'); }
31255
+ try { if (!asset.localUri) asset = await asset.downloadAsync(); }
31256
+ catch { throw new Error('assets-download-failed'); }
31257
+ if (!asset.localUri) throw new Error('assets-download-failed');
31258
+ let source: File;
31259
+ try { source = new File(asset.localUri); }
31260
+ catch { throw new Error('assets-source-failed'); }
31261
+ try { await source.copy(archive); }
31262
+ catch {
31263
+ try { await copyLegacyAsync({ from: asset.localUri, to: archive.uri }); }
31264
+ catch { throw new Error('assets-copy-failed'); }
31265
+ }
31266
+ }
31267
+ let contents: Uint8Array;
31268
+ try { contents = await archive.bytes(); }
31269
+ catch { throw new Error('assets-read-failed'); }
30867
31270
  for (const entry of ASSETS) {
30868
31271
  const parts = entry.path.split('/');
30869
31272
  const name = parts.pop();
30870
- if (!name) throw new Error('AbsoluteJS embedded asset path is invalid.');
30871
- const directory = new Directory(root, ...parts);
30872
- directory.create({ idempotent: true, intermediates: true });
30873
- const destination = new File(directory, name);
30874
- if (destination.exists) continue;
30875
- const asset = await Asset.fromModule(entry.module).downloadAsync();
30876
- if (!asset.localUri) throw new Error('Expo did not materialize an embedded AbsoluteJS asset.');
30877
- new File(asset.localUri).copy(destination);
31273
+ if (!name) throw new Error('assets-directory-failed');
31274
+ let directory: Directory;
31275
+ try {
31276
+ directory = new Directory(root, ...parts);
31277
+ directory.create({ idempotent: true, intermediates: true });
31278
+ }
31279
+ catch { throw new Error('assets-directory-failed'); }
31280
+ let destination: File;
31281
+ try {
31282
+ destination = new File(directory, name);
31283
+ if (destination.exists && destination.size === entry.length) continue;
31284
+ if (destination.exists) destination.delete();
31285
+ } catch { throw new Error('assets-destination-failed'); }
31286
+ try { destination.write(contents.slice(entry.offset, entry.offset + entry.length)); }
31287
+ catch { throw new Error('assets-write-failed'); }
30878
31288
  }
31289
+ try { archive.delete(); }
31290
+ catch { throw new Error('assets-finalize-failed'); }
30879
31291
 
30880
- return new File(root, 'index.html').uri;
31292
+ try { return new File(root, 'index.html').uri; }
31293
+ catch { throw new Error('assets-finalize-failed'); }
30881
31294
  };
30882
31295
  `;
30883
31296
  var syncAbsoluteExpoWebAssets = async (config) => {
30884
31297
  if (config.engine !== "expo")
30885
31298
  throw new TypeError("Expo asset sync requires mobile.engine: expo.");
30886
- const marker = join17(config.nativeProjectDirectory, EXPO_PROJECT_MARKER);
30887
- if (!await exists3(marker)) {
31299
+ const marker = join18(config.nativeProjectDirectory, EXPO_PROJECT_MARKER);
31300
+ if (!await exists4(marker)) {
30888
31301
  throw new TypeError("Expo asset sync requires an AbsoluteJS-managed Expo project. Run mobile init first.");
30889
31302
  }
30890
- const manifestPath = join17(config.bundleDirectory, "absolute-mobile-manifest.json");
30891
- const manifest = JSON.parse(await readFile14(manifestPath, "utf8"));
31303
+ const manifestPath = join18(config.bundleDirectory, "absolute-mobile-manifest.json");
31304
+ const manifest = JSON.parse(await readFile15(manifestPath, "utf8"));
30892
31305
  const nativeDataManifest = expoNativeDataManifest(manifest);
30893
31306
  const { appBuild } = nativeDataManifest;
30894
31307
  const files = await walkFiles(config.bundleDirectory);
30895
- const bundleHash = createHash12("sha256");
30896
- const filesWithContents = await Promise.all(files.map(async (file) => ({ contents: await readFile14(file), file })));
31308
+ const bundleHash = createHash13("sha256");
31309
+ const filesWithContents = await Promise.all(files.map(async (file) => ({ contents: await readFile15(file), file })));
30897
31310
  filesWithContents.forEach(({ contents, file }) => {
30898
- bundleHash.update(relative10(config.bundleDirectory, file).replaceAll("\\", "/"));
31311
+ bundleHash.update(relative11(config.bundleDirectory, file).replaceAll("\\", "/"));
30899
31312
  bundleHash.update("\x00");
30900
31313
  bundleHash.update(contents);
30901
31314
  bundleHash.update("\x00");
30902
31315
  });
30903
31316
  const bundleId = `amexpo_${bundleHash.digest("hex")}`;
30904
- const destination = join17(config.nativeProjectDirectory, "assets", "absolute");
30905
- await mkdir11(dirname10(destination), { recursive: true });
30906
- const staging = await mkdtemp7(join17(dirname10(destination), `.${basename4(destination)}.stage-`));
31317
+ const destination = join18(config.nativeProjectDirectory, "assets", "absolute");
31318
+ await mkdir12(dirname11(destination), { recursive: true });
31319
+ const staging = await mkdtemp8(join18(dirname11(destination), `.${basename5(destination)}.stage-`));
30907
31320
  let assets;
31321
+ let archiveAsset;
30908
31322
  try {
30909
- assets = await Promise.all(files.map(async (source, index) => {
30910
- const name = `${String(index).padStart(6, "0")}${EXPO_ASSET_EXTENSION}`;
30911
- await cp2(source, join17(staging, name));
30912
- return {
30913
- asset: portableRelative2(join17(config.nativeProjectDirectory, "src", "generated"), join17(destination, name)),
30914
- path: relative10(config.bundleDirectory, source).replaceAll("\\", "/")
31323
+ let offset = 0;
31324
+ assets = filesWithContents.map(({ contents, file }) => {
31325
+ const entry = {
31326
+ length: contents.byteLength,
31327
+ offset,
31328
+ path: relative11(config.bundleDirectory, file).replaceAll("\\", "/")
30915
31329
  };
30916
- }));
31330
+ offset += contents.byteLength;
31331
+ return entry;
31332
+ });
31333
+ const name = `bundle${EXPO_ASSET_EXTENSION}`;
31334
+ await writeFile13(join18(staging, name), Buffer.concat(filesWithContents.map(({ contents }) => contents)));
31335
+ archiveAsset = portableRelative2(join18(config.nativeProjectDirectory, "src", "generated"), join18(destination, name));
30917
31336
  await installStagedDirectory(staging, destination);
30918
31337
  } catch (error) {
30919
- await rm10(staging, { force: true, recursive: true });
31338
+ await rm11(staging, { force: true, recursive: true });
30920
31339
  throw error;
30921
31340
  }
30922
- const generated = join17(config.nativeProjectDirectory, "src", "generated", "webAssets.ts");
30923
- await writeManagedFile(generated, assetModuleSource(assets, bundleId, nativeDataManifest), true);
31341
+ const generated = join18(config.nativeProjectDirectory, "src", "generated", "webAssets.ts");
31342
+ await writeManagedFile(generated, assetModuleSource(assets, archiveAsset, bundleId, nativeDataManifest), true);
30924
31343
  return { appBuild, assets: assets.length, bundleId, path: destination };
30925
31344
  };
30926
31345
 
@@ -30958,11 +31377,11 @@ var loadServerApp = async (producerPath) => {
30958
31377
  return { app, exportName };
30959
31378
  };
30960
31379
  var finalizeAbsoluteMobileCompatibilityBuild = async (options) => {
30961
- const buildDirectory = resolve13(options.buildDirectory);
31380
+ const buildDirectory = resolve14(options.buildDirectory);
30962
31381
  const mobile = normalizeAbsoluteMobileConfig(options.mobile, options.projectRoot);
30963
- const root = join18(buildDirectory, ".absolutejs", "mobile-compatibility");
31382
+ const root = join19(buildDirectory, ".absolutejs", "mobile-compatibility");
30964
31383
  const [manifestSource, previous] = await Promise.all([
30965
- readFile15(join18(buildDirectory, "manifest.json"), "utf8"),
31384
+ readFile16(join19(buildDirectory, "manifest.json"), "utf8"),
30966
31385
  readAbsoluteMobileMaterializedReleases(root)
30967
31386
  ]);
30968
31387
  const manifest = JSON.parse(manifestSource);
@@ -30975,11 +31394,11 @@ var finalizeAbsoluteMobileCompatibilityBuild = async (options) => {
30975
31394
  process.env.ABSOLUTE_BUILD_DIR = buildDirectory;
30976
31395
  process.env.ABSOLUTE_COMPILED_RUNTIME = "1";
30977
31396
  if (options.configPath) {
30978
- process.env.ABSOLUTE_CONFIG = resolve13(options.projectRoot, options.configPath);
31397
+ process.env.ABSOLUTE_CONFIG = resolve14(options.projectRoot, options.configPath);
30979
31398
  }
30980
31399
  let loaded;
30981
31400
  try {
30982
- loaded = await loadServerApp(resolve13(options.producerPath));
31401
+ loaded = await loadServerApp(resolve14(options.producerPath));
30983
31402
  } finally {
30984
31403
  restoreEnvironmentVariable("ABSOLUTE_BUILD_DIR", previousBuildDirectory);
30985
31404
  restoreEnvironmentVariable("ABSOLUTE_COMPILED_RUNTIME", previousCompiledRuntime);
@@ -30992,7 +31411,7 @@ var finalizeAbsoluteMobileCompatibilityBuild = async (options) => {
30992
31411
  manifest,
30993
31412
  previousArtifacts: previous.map(({ artifact }) => artifact),
30994
31413
  producerExport: loaded.exportName,
30995
- producerPath: resolve13(options.producerPath),
31414
+ producerPath: resolve14(options.producerPath),
30996
31415
  runtime: String(ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION)
30997
31416
  });
30998
31417
  const {
@@ -31242,7 +31661,7 @@ var ABSOLUTE_EXPO_BRIDGE_METHODS = [
31242
31661
  "sync.socket.open",
31243
31662
  "sync.socket.sendChunk"
31244
31663
  ];
31245
- var isRecord9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
31664
+ var isRecord10 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
31246
31665
  var validId = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,80}$/u.test(value);
31247
31666
  var validPath = (value) => typeof value === "string" && value.startsWith("/") && !value.startsWith("//") && value.length <= 4096;
31248
31667
  var parseRequest = (value) => {
@@ -31252,7 +31671,7 @@ var parseRequest = (value) => {
31252
31671
  if (!method) {
31253
31672
  throw new TypeError("Expo bridge method is not allowed.");
31254
31673
  }
31255
- if (!isRecord9(value.params))
31674
+ if (!isRecord10(value.params))
31256
31675
  throw new TypeError("Expo bridge request params must be an object.");
31257
31676
  if (typeof value.path !== "string" || !validPath(value.path))
31258
31677
  throw new TypeError("Expo bridge request path is invalid.");
@@ -31288,7 +31707,7 @@ var parseRequest = (value) => {
31288
31707
  throw new TypeError("Expo bridge HTTP body exceeds 48 KiB.");
31289
31708
  if ((value.params.method === "GET" || value.params.method === "DELETE") && value.params.body !== undefined)
31290
31709
  throw new TypeError("Expo bridge HTTP method cannot contain a body.");
31291
- if (!isRecord9(value.params.headers))
31710
+ if (!isRecord10(value.params.headers))
31292
31711
  throw new TypeError("Expo bridge HTTP headers must be an object.");
31293
31712
  const headersAllowed = Object.entries(value.params.headers).every(([name, header]) => typeof header === "string" && (name.toLowerCase() === "accept" || name.toLowerCase() === "content-type" || name.toLowerCase().startsWith("x-absolute-mobile-")));
31294
31713
  if (!headersAllowed) {
@@ -31314,13 +31733,13 @@ var parseResponse = (value) => {
31314
31733
  if (typeof value.id !== "string" || !validId(value.id))
31315
31734
  throw new TypeError("Expo bridge response id is invalid.");
31316
31735
  if (value.error !== undefined) {
31317
- if (!isRecord9(value.error) || typeof value.error.code !== "string" || typeof value.error.message !== "string") {
31736
+ if (!isRecord10(value.error) || typeof value.error.code !== "string" || typeof value.error.message !== "string") {
31318
31737
  throw new TypeError("Expo bridge response error is invalid.");
31319
31738
  }
31320
31739
  if (value.result !== undefined)
31321
31740
  throw new TypeError("Expo bridge response cannot contain result and error.");
31322
31741
  }
31323
- if (isRecord9(value.error)) {
31742
+ if (isRecord10(value.error)) {
31324
31743
  return {
31325
31744
  error: {
31326
31745
  code: String(value.error.code),
@@ -31344,7 +31763,7 @@ var parseEvent = (value) => {
31344
31763
  }
31345
31764
  if (typeof value.path !== "string" || !validPath(value.path))
31346
31765
  throw new TypeError("Expo bridge event path is invalid.");
31347
- if (value.payload !== undefined && !isRecord9(value.payload)) {
31766
+ if (value.payload !== undefined && !isRecord10(value.payload)) {
31348
31767
  throw new TypeError("Expo bridge event payload must be an object.");
31349
31768
  }
31350
31769
  return {
@@ -31378,7 +31797,7 @@ var parseAbsoluteExpoBridgeMessage = (source) => {
31378
31797
  cause
31379
31798
  });
31380
31799
  }
31381
- if (!isRecord9(parsed) || parsed.format !== ABSOLUTE_EXPO_BRIDGE_FORMAT) {
31800
+ if (!isRecord10(parsed) || parsed.format !== ABSOLUTE_EXPO_BRIDGE_FORMAT) {
31382
31801
  throw new TypeError("Expo bridge message format is unsupported.");
31383
31802
  }
31384
31803
  if (parsed.kind === "request")
@@ -31391,21 +31810,21 @@ var parseAbsoluteExpoBridgeMessage = (source) => {
31391
31810
  };
31392
31811
  // src/mobile/expoCodeSigning.ts
31393
31812
  var import_code_signing_certificates = __toESM(require_main(), 1);
31394
- import { access as access11, mkdir as mkdir12, writeFile as writeFile13 } from "fs/promises";
31395
- import { dirname as dirname11, isAbsolute as isAbsolute6, relative as relative11, resolve as resolve14, sep as sep7 } from "path";
31396
- var exists4 = async (path) => access11(path).then(() => true).catch(() => false);
31397
- var inside = (root, path) => {
31398
- const location2 = relative11(root, path);
31399
- return location2 === "" || location2 !== ".." && !location2.startsWith(`..${sep7}`) && !isAbsolute6(location2);
31813
+ import { access as access12, mkdir as mkdir13, writeFile as writeFile14 } from "fs/promises";
31814
+ import { dirname as dirname12, isAbsolute as isAbsolute7, relative as relative12, resolve as resolve15, sep as sep8 } from "path";
31815
+ var exists5 = async (path) => access12(path).then(() => true).catch(() => false);
31816
+ var inside2 = (root, path) => {
31817
+ const location2 = relative12(root, path);
31818
+ return location2 === "" || location2 !== ".." && !location2.startsWith(`..${sep8}`) && !isAbsolute7(location2);
31400
31819
  };
31401
31820
  var generateAbsoluteExpoCodeSigning = async (options) => {
31402
- const root = resolve14(options.projectRoot);
31403
- const certificatePath = resolve14(root, options.certificatePath);
31404
- const privateKeyPath = resolve14(root, options.privateKeyPath);
31405
- const publicKeyPath = resolve14(root, options.publicKeyPath ?? resolve14(dirname11(privateKeyPath), "public-key.pem"));
31406
- if (!inside(root, certificatePath))
31821
+ const root = resolve15(options.projectRoot);
31822
+ const certificatePath = resolve15(root, options.certificatePath);
31823
+ const privateKeyPath = resolve15(root, options.privateKeyPath);
31824
+ const publicKeyPath = resolve15(root, options.publicKeyPath ?? resolve15(dirname12(privateKeyPath), "public-key.pem"));
31825
+ if (!inside2(root, certificatePath))
31407
31826
  throw new TypeError("Expo code-signing certificate must be written inside the project so store builds can embed it.");
31408
- if (inside(root, privateKeyPath) || inside(root, publicKeyPath))
31827
+ if (inside2(root, privateKeyPath) || inside2(root, publicKeyPath))
31409
31828
  throw new TypeError("Expo code-signing private/public key output must remain outside the project and source control.");
31410
31829
  const commonName = options.commonName.trim();
31411
31830
  if (!commonName || commonName.length > 64)
@@ -31414,7 +31833,7 @@ var generateAbsoluteExpoCodeSigning = async (options) => {
31414
31833
  if (!Number.isSafeInteger(validityYears) || validityYears < 1 || validityYears > 20)
31415
31834
  throw new TypeError("Expo code-signing validity must be an integer from 1 through 20 years.");
31416
31835
  const collisions = (await Promise.all([certificatePath, privateKeyPath, publicKeyPath].map(async (path) => ({
31417
- exists: await exists4(path),
31836
+ exists: await exists5(path),
31418
31837
  path
31419
31838
  })))).filter((entry) => entry.exists);
31420
31839
  if (collisions.length > 0)
@@ -31432,11 +31851,11 @@ var generateAbsoluteExpoCodeSigning = async (options) => {
31432
31851
  import_code_signing_certificates.validateSelfSignedCertificate(certificate, keyPair);
31433
31852
  const { privateKeyPEM, publicKeyPEM } = import_code_signing_certificates.convertKeyPairToPEM(keyPair);
31434
31853
  const certificatePem = import_code_signing_certificates.convertCertificateToCertificatePEM(certificate);
31435
- await Promise.all([certificatePath, privateKeyPath, publicKeyPath].map((path) => mkdir12(dirname11(path), { recursive: true })));
31854
+ await Promise.all([certificatePath, privateKeyPath, publicKeyPath].map((path) => mkdir13(dirname12(path), { recursive: true })));
31436
31855
  await Promise.all([
31437
- writeFile13(certificatePath, certificatePem, { flag: "wx", mode: 420 }),
31438
- writeFile13(privateKeyPath, privateKeyPEM, { flag: "wx", mode: 384 }),
31439
- writeFile13(publicKeyPath, publicKeyPEM, { flag: "wx", mode: 420 })
31856
+ writeFile14(certificatePath, certificatePem, { flag: "wx", mode: 420 }),
31857
+ writeFile14(privateKeyPath, privateKeyPEM, { flag: "wx", mode: 384 }),
31858
+ writeFile14(publicKeyPath, publicKeyPEM, { flag: "wx", mode: 420 })
31440
31859
  ]);
31441
31860
  return {
31442
31861
  certificatePath,
@@ -31538,9 +31957,9 @@ var parseAbsoluteAndroidAccessibilityHierarchy = (source) => [...source.matchAll
31538
31957
  });
31539
31958
  // src/mobile/expoNativeWatcher.ts
31540
31959
  import { watch as watch2 } from "fs";
31541
- import { access as access12, readdir as readdir5, readFile as readFile16 } from "fs/promises";
31542
- import { basename as basename5, join as join19, relative as relative12 } from "path";
31543
- import { createHash as createHash13 } from "crypto";
31960
+ import { access as access13, readdir as readdir5, readFile as readFile17 } from "fs/promises";
31961
+ import { basename as basename6, join as join20, relative as relative13 } from "path";
31962
+ import { createHash as createHash14 } from "crypto";
31544
31963
  var NATIVE_CHANGE_DEBOUNCE_MS2 = 500;
31545
31964
  var ROOT_NATIVE_INPUTS2 = new Set([
31546
31965
  "absolute.config.js",
@@ -31554,13 +31973,13 @@ var ROOT_NATIVE_INPUTS2 = new Set([
31554
31973
  "package.json"
31555
31974
  ]);
31556
31975
  var EXPO_NATIVE_DIRECTORIES = ["modules", "plugins"];
31557
- var exists5 = async (path) => access12(path).then(() => true, () => false);
31976
+ var exists6 = async (path) => access13(path).then(() => true, () => false);
31558
31977
  var filesIn = async (directory, prefix) => {
31559
- if (!await exists5(directory))
31978
+ if (!await exists6(directory))
31560
31979
  return [];
31561
31980
  const entries = await readdir5(directory, { withFileTypes: true });
31562
31981
  const nested = await Promise.all(entries.map((entry) => {
31563
- const path = join19(directory, entry.name);
31982
+ const path = join20(directory, entry.name);
31564
31983
  const name = `${prefix}/${entry.name}`;
31565
31984
  if (entry.isDirectory())
31566
31985
  return filesIn(path, name);
@@ -31569,21 +31988,21 @@ var filesIn = async (directory, prefix) => {
31569
31988
  return nested.flat().sort((left, right) => left.name.localeCompare(right.name));
31570
31989
  };
31571
31990
  var fingerprintAbsoluteExpoNativeInputs = async (options) => {
31572
- const hash = createHash13("sha256");
31991
+ const hash = createHash14("sha256");
31573
31992
  const rootFiles = await Promise.all([...ROOT_NATIVE_INPUTS2].sort().map(async (name) => {
31574
- const path = join19(options.projectRoot, name);
31575
- return await exists5(path) ? [{ name: `root/${name}`, path }] : [];
31993
+ const path = join20(options.projectRoot, name);
31994
+ return await exists6(path) ? [{ name: `root/${name}`, path }] : [];
31576
31995
  }));
31577
- const nativeFiles = await Promise.all(EXPO_NATIVE_DIRECTORIES.map((name) => filesIn(join19(options.expoProjectDirectory, name), name)));
31996
+ const nativeFiles = await Promise.all(EXPO_NATIVE_DIRECTORIES.map((name) => filesIn(join20(options.expoProjectDirectory, name), name)));
31578
31997
  const files = [...rootFiles.flat(), ...nativeFiles.flat()].sort((left, right) => left.name.localeCompare(right.name));
31579
- const contents = await Promise.all(files.map(({ path }) => readFile16(path)));
31998
+ const contents = await Promise.all(files.map(({ path }) => readFile17(path)));
31580
31999
  files.forEach(({ name }, index) => {
31581
32000
  hash.update(name);
31582
32001
  hash.update(contents[index] ?? Buffer.alloc(0));
31583
32002
  });
31584
32003
  return hash.digest("hex");
31585
32004
  };
31586
- var isAbsoluteExpoNativeRootInput = (path) => ROOT_NATIVE_INPUTS2.has(basename5(path));
32005
+ var isAbsoluteExpoNativeRootInput = (path) => ROOT_NATIVE_INPUTS2.has(basename6(path));
31587
32006
  var createAbsoluteExpoNativeWatcher = async (options) => {
31588
32007
  let fingerprint = await fingerprintAbsoluteExpoNativeInputs(options);
31589
32008
  let closed = false;
@@ -31645,14 +32064,14 @@ var createAbsoluteExpoNativeWatcher = async (options) => {
31645
32064
  }
31646
32065
  };
31647
32066
  const nativeDirectories = (await Promise.all(EXPO_NATIVE_DIRECTORIES.map(async (name) => {
31648
- const directory = join19(options.expoProjectDirectory, name);
31649
- return await exists5(directory) ? [directory] : [];
32067
+ const directory = join20(options.expoProjectDirectory, name);
32068
+ return await exists6(directory) ? [directory] : [];
31650
32069
  }))).flat();
31651
32070
  nativeDirectories.forEach((directory) => {
31652
32071
  watchers.push(watch2(directory, { recursive: true }, (_event, filename) => {
31653
32072
  if (!filename)
31654
32073
  return;
31655
- record(relative12(options.expoProjectDirectory, join19(directory, String(filename))), false);
32074
+ record(relative13(options.expoProjectDirectory, join20(directory, String(filename))), false);
31656
32075
  }));
31657
32076
  });
31658
32077
  watchers.push(watch2(options.projectRoot, (_event, filename) => {
@@ -31667,8 +32086,8 @@ var createAbsoluteExpoNativeWatcher = async (options) => {
31667
32086
  return { close };
31668
32087
  };
31669
32088
  // src/mobile/expoUpdate.ts
31670
- import { access as access13, mkdir as mkdir13, readFile as readFile17, writeFile as writeFile14 } from "fs/promises";
31671
- import { dirname as dirname12, extname as extname4, join as join20 } from "path";
32089
+ import { access as access14, mkdir as mkdir14, readFile as readFile18, writeFile as writeFile15 } from "fs/promises";
32090
+ import { dirname as dirname13, extname as extname4, join as join21 } from "path";
31672
32091
  var ABSOLUTE_EXPO_UPDATE_DESCRIPTOR = "_absolute/expo-update.json";
31673
32092
  var ABSOLUTE_EXPO_UPDATE_FORMAT = 1;
31674
32093
  var object4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -31734,7 +32153,7 @@ var parseAbsoluteExpoUpdateDescriptor = (value) => {
31734
32153
  };
31735
32154
  };
31736
32155
  var finalizeAbsoluteExpoUpdateExport = async (options) => {
31737
- const metadata = JSON.parse(await readFile17(join20(options.exportDirectory, "metadata.json"), "utf8"));
32156
+ const metadata = JSON.parse(await readFile18(join21(options.exportDirectory, "metadata.json"), "utf8"));
31738
32157
  if (!object4(metadata) || !object4(metadata.fileMetadata))
31739
32158
  throw new TypeError("Expo export metadata.json is invalid.");
31740
32159
  const descriptor = parseAbsoluteExpoUpdateDescriptor({
@@ -31745,12 +32164,12 @@ var finalizeAbsoluteExpoUpdateExport = async (options) => {
31745
32164
  runtimeVersion: options.runtimeVersion
31746
32165
  });
31747
32166
  const referenced = Object.values(descriptor.platforms).flatMap((entry) => entry ? [entry.launchAsset, ...entry.assets] : []);
31748
- await Promise.all(referenced.map(({ path }) => access13(join20(options.exportDirectory, path)).catch(() => {
32167
+ await Promise.all(referenced.map(({ path }) => access14(join21(options.exportDirectory, path)).catch(() => {
31749
32168
  throw new TypeError(`Expo export metadata references missing asset ${path}.`);
31750
32169
  })));
31751
- const destination = join20(options.exportDirectory, ABSOLUTE_EXPO_UPDATE_DESCRIPTOR);
31752
- await mkdir13(dirname12(destination), { recursive: true });
31753
- await writeFile14(destination, `${JSON.stringify(descriptor, null, "\t")}
32170
+ const destination = join21(options.exportDirectory, ABSOLUTE_EXPO_UPDATE_DESCRIPTOR);
32171
+ await mkdir14(dirname13(destination), { recursive: true });
32172
+ await writeFile15(destination, `${JSON.stringify(descriptor, null, "\t")}
31754
32173
  `);
31755
32174
  return { descriptor, path: destination };
31756
32175
  };
@@ -31760,8 +32179,8 @@ init_config();
31760
32179
 
31761
32180
  // src/mobile/ciWorkflow.ts
31762
32181
  import { existsSync as existsSync4 } from "fs";
31763
- import { access as access14, mkdir as mkdir14, readFile as readFile18, writeFile as writeFile15 } from "fs/promises";
31764
- import { dirname as dirname13, extname as extname5, relative as relative13, resolve as resolve15, sep as sep8 } from "path";
32182
+ import { access as access15, mkdir as mkdir15, readFile as readFile19, writeFile as writeFile16 } from "fs/promises";
32183
+ import { dirname as dirname14, extname as extname5, relative as relative14, resolve as resolve16, sep as sep9 } from "path";
31765
32184
  var ABSOLUTE_MOBILE_CI_WORKFLOW_FORMAT = 1;
31766
32185
  var SECRET_NAME_PATTERN = /^[A-Z][A-Z0-9_]*$/u;
31767
32186
  var CI_ENV_INDENTATION = 6;
@@ -31780,9 +32199,9 @@ var RESERVED_SECRET_NAMES = new Set([
31780
32199
  "APP_STORE_CONNECT_KEY_ID",
31781
32200
  "APP_STORE_CONNECT_PRIVATE_KEY_BASE64"
31782
32201
  ]);
31783
- var exists6 = async (path) => {
32202
+ var exists7 = async (path) => {
31784
32203
  try {
31785
- await access14(path);
32204
+ await access15(path);
31786
32205
  return true;
31787
32206
  } catch {
31788
32207
  return false;
@@ -31790,10 +32209,10 @@ var exists6 = async (path) => {
31790
32209
  };
31791
32210
  var yamlString = (value) => `'${value.replaceAll("'", "''")}'`;
31792
32211
  var projectPath = (projectRoot, value, field2, options = {}) => {
31793
- const root = resolve15(projectRoot);
31794
- const path = resolve15(root, value);
31795
- const portable = relative13(root, path).replaceAll("\\", "/");
31796
- if (portable === ".." || portable.startsWith(`..${sep8}`) || portable.startsWith("../") || portable === "") {
32212
+ const root = resolve16(projectRoot);
32213
+ const path = resolve16(root, value);
32214
+ const portable = relative14(root, path).replaceAll("\\", "/");
32215
+ if (portable === ".." || portable.startsWith(`..${sep9}`) || portable.startsWith("../") || portable === "") {
31797
32216
  throw new TypeError(`${field2} must remain inside the project root.`);
31798
32217
  }
31799
32218
  if (/\r|\n/u.test(portable) || portable.startsWith("-"))
@@ -31803,11 +32222,11 @@ var projectPath = (projectRoot, value, field2, options = {}) => {
31803
32222
  return portable;
31804
32223
  };
31805
32224
  var workflowOutputPath = (projectRoot, value) => {
31806
- const root = resolve15(projectRoot);
31807
- const workflows = resolve15(root, ".github/workflows");
31808
- const path = resolve15(root, value ?? ".github/workflows/absolute-mobile.yml");
31809
- const portable = relative13(workflows, path);
31810
- if (portable === ".." || portable.startsWith(`..${sep8}`) || extname5(path) !== ".yml" && extname5(path) !== ".yaml") {
32225
+ const root = resolve16(projectRoot);
32226
+ const workflows = resolve16(root, ".github/workflows");
32227
+ const path = resolve16(root, value ?? ".github/workflows/absolute-mobile.yml");
32228
+ const portable = relative14(workflows, path);
32229
+ if (portable === ".." || portable.startsWith(`..${sep9}`) || extname5(path) !== ".yml" && extname5(path) !== ".yaml") {
31811
32230
  throw new TypeError("mobile ci github --output must be a .yml or .yaml file inside .github/workflows.");
31812
32231
  }
31813
32232
  return path;
@@ -32236,12 +32655,12 @@ ${bundleAuditSteps}${platforms.includes("android") ? androidJob({ customSecrets,
32236
32655
  var writeAbsoluteMobileGithubWorkflow = async (options) => {
32237
32656
  const path = workflowOutputPath(options.projectRoot, options.outputPath);
32238
32657
  const generated = createAbsoluteMobileGithubWorkflow(options);
32239
- const previous = await exists6(path) ? await readFile18(path, "utf8") : undefined;
32658
+ const previous = await exists7(path) ? await readFile19(path, "utf8") : undefined;
32240
32659
  if (previous !== undefined && previous !== generated.workflow && !options.force)
32241
- throw new TypeError(`${relative13(options.projectRoot, path)} already exists and differs. Rerun with --force to replace the generated workflow.`);
32660
+ throw new TypeError(`${relative14(options.projectRoot, path)} already exists and differs. Rerun with --force to replace the generated workflow.`);
32242
32661
  if (previous !== generated.workflow) {
32243
- await mkdir14(dirname13(path), { recursive: true });
32244
- await writeFile15(path, generated.workflow);
32662
+ await mkdir15(dirname14(path), { recursive: true });
32663
+ await writeFile16(path, generated.workflow);
32245
32664
  }
32246
32665
  return {
32247
32666
  changed: previous !== generated.workflow,
@@ -32259,20 +32678,20 @@ init_materializedBundle();
32259
32678
  init_mobilePreview();
32260
32679
 
32261
32680
  // src/mobile/nativeDeepLinks.ts
32262
- import { readFile as readFile19, rename as rename12, writeFile as writeFile16 } from "fs/promises";
32263
- import { join as join23 } from "path";
32681
+ import { readFile as readFile20, rename as rename13, writeFile as writeFile17 } from "fs/promises";
32682
+ import { join as join24 } from "path";
32264
32683
  var START_MARKER = "<!-- absolutejs:deep-links:start -->";
32265
32684
  var END_MARKER = "<!-- absolutejs:deep-links:end -->";
32266
32685
  var IOS_ENTITLEMENTS = "App/AbsoluteJS.entitlements";
32267
32686
  var NOT_FOUND = -1;
32268
32687
  var escapeXml = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
32269
32688
  var writeChangedFile = async (path, source) => {
32270
- const current = await readFile19(path, "utf8");
32689
+ const current = await readFile20(path, "utf8");
32271
32690
  if (current === source)
32272
32691
  return false;
32273
32692
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
32274
- await writeFile16(temporary, source, { flag: "wx" });
32275
- await rename12(temporary, path);
32693
+ await writeFile17(temporary, source, { flag: "wx" });
32694
+ await rename13(temporary, path);
32276
32695
  return true;
32277
32696
  };
32278
32697
  var replaceManagedRegion = (source, region, insertAt) => {
@@ -32317,8 +32736,8 @@ ${hosts}
32317
32736
  `;
32318
32737
  };
32319
32738
  var configureAndroid = async (config) => {
32320
- const path = join23(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
32321
- const source = await readFile19(path, "utf8");
32739
+ const path = join24(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
32740
+ const source = await readFile20(path, "utf8");
32322
32741
  const mainActivity = source.indexOf('android:name=".MainActivity"');
32323
32742
  if (mainActivity === NOT_FOUND) {
32324
32743
  throw new TypeError("Android MainActivity was not found.");
@@ -32343,8 +32762,8 @@ var iosSchemeRegion = (scheme) => ` ${START_MARKER}
32343
32762
  ${END_MARKER}
32344
32763
  `;
32345
32764
  var configureIosInfo = async (config) => {
32346
- const path = join23(config.nativeProjectDirectory, "ios/App/App/Info.plist");
32347
- const source = await readFile19(path, "utf8");
32765
+ const path = join24(config.nativeProjectDirectory, "ios/App/App/Info.plist");
32766
+ const source = await readFile20(path, "utf8");
32348
32767
  const region = config.deepLinkScheme ? iosSchemeRegion(config.deepLinkScheme) : ` ${START_MARKER}
32349
32768
  ${END_MARKER}
32350
32769
  `;
@@ -32367,10 +32786,10 @@ ${domains}
32367
32786
  `;
32368
32787
  };
32369
32788
  var configureIosEntitlements = async (config) => {
32370
- const path = join23(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
32789
+ const path = join24(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
32371
32790
  let current = "";
32372
32791
  try {
32373
- current = await readFile19(path, "utf8");
32792
+ current = await readFile20(path, "utf8");
32374
32793
  } catch (error) {
32375
32794
  if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
32376
32795
  throw error;
@@ -32380,13 +32799,13 @@ var configureIosEntitlements = async (config) => {
32380
32799
  if (current === source)
32381
32800
  return false;
32382
32801
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
32383
- await writeFile16(temporary, source, { flag: "wx" });
32384
- await rename12(temporary, path);
32802
+ await writeFile17(temporary, source, { flag: "wx" });
32803
+ await rename13(temporary, path);
32385
32804
  return true;
32386
32805
  };
32387
32806
  var configureIosProject = async (config) => {
32388
- const path = join23(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
32389
- const source = await readFile19(path, "utf8");
32807
+ const path = join24(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
32808
+ const source = await readFile20(path, "utf8");
32390
32809
  const declarations = [
32391
32810
  ...source.matchAll(/CODE_SIGN_ENTITLEMENTS = ([^;]+);/g)
32392
32811
  ].map((match) => match[1]);
@@ -32425,8 +32844,8 @@ var applyAbsoluteNativeDeepLinks = async (config, platforms = config.platforms)
32425
32844
  };
32426
32845
  // src/mobile/nativeDeviceCapabilities.ts
32427
32846
  init_deviceCapabilities();
32428
- import { readFile as readFile20, rename as rename13, writeFile as writeFile17 } from "fs/promises";
32429
- import { join as join24 } from "path";
32847
+ import { readFile as readFile21, rename as rename14, writeFile as writeFile18 } from "fs/promises";
32848
+ import { join as join25 } from "path";
32430
32849
  var START_MARKER2 = "<!-- absolutejs:device-capabilities:start -->";
32431
32850
  var END_MARKER2 = "<!-- absolutejs:device-capabilities:end -->";
32432
32851
  var NOT_FOUND2 = -1;
@@ -32436,12 +32855,12 @@ var PUSH_START_MARKER = "absolutejs:push-notifications:start";
32436
32855
  var PUSH_END_MARKER = "absolutejs:push-notifications:end";
32437
32856
  var escapeXml2 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
32438
32857
  var writeChangedFile2 = async (path, source) => {
32439
- const current = await readFile20(path, "utf8");
32858
+ const current = await readFile21(path, "utf8");
32440
32859
  if (current === source)
32441
32860
  return false;
32442
32861
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
32443
- await writeFile17(temporary, source, { flag: "wx" });
32444
- await rename13(temporary, path);
32862
+ await writeFile18(temporary, source, { flag: "wx" });
32863
+ await rename14(temporary, path);
32445
32864
  return true;
32446
32865
  };
32447
32866
  var writeOptionalChangedFile = async (path, source) => {
@@ -32449,14 +32868,14 @@ var writeOptionalChangedFile = async (path, source) => {
32449
32868
  if (current === source)
32450
32869
  return false;
32451
32870
  if (current === null) {
32452
- await writeFile17(path, source, { flag: "wx" });
32871
+ await writeFile18(path, source, { flag: "wx" });
32453
32872
  return true;
32454
32873
  }
32455
32874
  return writeChangedFile2(path, source);
32456
32875
  };
32457
32876
  var optionalSource = async (path) => {
32458
32877
  try {
32459
- return await readFile20(path, "utf8");
32878
+ return await readFile21(path, "utf8");
32460
32879
  } catch (error) {
32461
32880
  if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "ENOENT")
32462
32881
  return null;
@@ -32570,14 +32989,14 @@ var writeIosPrivacyManifest = async (path, current, source) => {
32570
32989
  return false;
32571
32990
  if (current !== null)
32572
32991
  return writeChangedFile2(path, source);
32573
- await writeFile17(path, source, { flag: "wx" });
32992
+ await writeFile18(path, source, { flag: "wx" });
32574
32993
  return true;
32575
32994
  };
32576
32995
  var configureIosPrivacyProject = async (config, requirements) => {
32577
32996
  if (requirements.iosPrivacyAccessedApis.length === 0)
32578
32997
  return false;
32579
- const projectPath2 = join24(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
32580
- const project = await readFile20(projectPath2, "utf8");
32998
+ const projectPath2 = join25(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
32999
+ const project = await readFile21(projectPath2, "utf8");
32581
33000
  return writeChangedFile2(projectPath2, addIosPrivacyProjectReference(project));
32582
33001
  };
32583
33002
  var addIosPrivacyProjectReference = (source) => {
@@ -32629,8 +33048,8 @@ ${next.slice(index)}`;
32629
33048
  return next;
32630
33049
  };
32631
33050
  var configureIos2 = async (config, plan) => {
32632
- const path = join24(config.nativeProjectDirectory, "ios/App/App/Info.plist");
32633
- const source = await readFile20(path, "utf8");
33051
+ const path = join25(config.nativeProjectDirectory, "ios/App/App/Info.plist");
33052
+ const source = await readFile21(path, "utf8");
32634
33053
  const requirements = absoluteDeviceNativeRequirements(plan);
32635
33054
  const existingSystemBars = source.match(/<key>UIViewControllerBasedStatusBarAppearance<\/key>\s*<(true|false)\s*\/>/u);
32636
33055
  const ownedStart = source.indexOf(START_MARKER2);
@@ -32650,7 +33069,7 @@ ${content}
32650
33069
  ${END_MARKER2}
32651
33070
  ` : "";
32652
33071
  const infoChanged = await writeChangedFile2(path, managed(source, region, source.lastIndexOf("</dict>")));
32653
- const privacyPath = join24(config.nativeProjectDirectory, "ios/App/App/PrivacyInfo.xcprivacy");
33072
+ const privacyPath = join25(config.nativeProjectDirectory, "ios/App/App/PrivacyInfo.xcprivacy");
32654
33073
  const privacyCurrent = await optionalSource(privacyPath);
32655
33074
  const privacySource = privacyManifestSource(privacyCurrent, requirements);
32656
33075
  const [privacyChanged, projectChanged, pushChanged] = await Promise.all([
@@ -32661,7 +33080,7 @@ ${content}
32661
33080
  return infoChanged || privacyChanged || projectChanged || pushChanged;
32662
33081
  };
32663
33082
  var configureIosPushNotifications = async (config, enabled) => {
32664
- const entitlementsPath = join24(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
33083
+ const entitlementsPath = join25(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
32665
33084
  const entitlements = await optionalSource(entitlementsPath);
32666
33085
  if (entitlements === null && !enabled)
32667
33086
  return false;
@@ -32673,7 +33092,7 @@ var configureIosPushNotifications = async (config, enabled) => {
32673
33092
  <!-- ${PUSH_END_MARKER} -->
32674
33093
  ` : "";
32675
33094
  const nextEntitlements = replacePushRegion(entitlements, entitlementRegion, entitlements.lastIndexOf("</dict>"));
32676
- const delegatePath = join24(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
33095
+ const delegatePath = join25(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
32677
33096
  const delegate = await optionalSource(delegatePath);
32678
33097
  if (delegate === null && !enabled)
32679
33098
  return false;
@@ -32722,8 +33141,8 @@ var replacePushRegion = (source, region, insertion) => {
32722
33141
  return `${source.slice(0, insertion)}${region}${source.slice(insertion)}`;
32723
33142
  };
32724
33143
  var configureAndroid2 = async (config, plan) => {
32725
- const path = join24(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
32726
- const source = await readFile20(path, "utf8");
33144
+ const path = join25(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
33145
+ const source = await readFile21(path, "utf8");
32727
33146
  const permissions = absoluteDeviceNativeRequirements(plan).androidPermissions;
32728
33147
  const content = permissions.map((permission) => ` <uses-permission android:name="${escapeXml2(permission)}" />`).join(`
32729
33148
  `);
@@ -32758,7 +33177,7 @@ ${content}
32758
33177
  throw new TypeError(`Android google-services.json does not contain package ${config.appId}.`);
32759
33178
  const [manifestChanged, firebaseChanged] = await Promise.all([
32760
33179
  writeChangedFile2(path, nextManifest),
32761
- writeOptionalChangedFile(join24(config.nativeProjectDirectory, "android/app/google-services.json"), firebaseSource)
33180
+ writeOptionalChangedFile(join25(config.nativeProjectDirectory, "android/app/google-services.json"), firebaseSource)
32762
33181
  ]);
32763
33182
  return manifestChanged || firebaseChanged;
32764
33183
  };
@@ -32777,14 +33196,14 @@ init_nativeAuth();
32777
33196
 
32778
33197
  // src/mobile/nativeUpdates.ts
32779
33198
  import {
32780
- mkdir as mkdir15,
32781
- readFile as readFile21,
33199
+ mkdir as mkdir16,
33200
+ readFile as readFile22,
32782
33201
  readdir as readdir6,
32783
- rename as rename14,
32784
- rm as rm11,
32785
- writeFile as writeFile18
33202
+ rename as rename15,
33203
+ rm as rm12,
33204
+ writeFile as writeFile19
32786
33205
  } from "fs/promises";
32787
- import { dirname as dirname15, join as join25 } from "path";
33206
+ import { dirname as dirname16, join as join26 } from "path";
32788
33207
  var START = "// absolutejs:mobile-updates:start";
32789
33208
  var END = "// absolutejs:mobile-updates:end";
32790
33209
  var PLUGIN_START = "// absolutejs:mobile-update-plugin:start";
@@ -32792,32 +33211,32 @@ var PLUGIN_END = "// absolutejs:mobile-update-plugin:end";
32792
33211
  var ANDROID_PLUGIN = "AbsoluteMobileUpdateWatchdogPlugin.java";
32793
33212
  var optionalSource2 = async (path) => {
32794
33213
  try {
32795
- return await readFile21(path, "utf8");
33214
+ return await readFile22(path, "utf8");
32796
33215
  } catch (error) {
32797
33216
  if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "ENOENT")
32798
33217
  return null;
32799
33218
  throw error;
32800
33219
  }
32801
33220
  };
32802
- var isRecord11 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
33221
+ var isRecord12 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
32803
33222
  var writeChanged = async (path, source) => {
32804
33223
  const current = await optionalSource2(path);
32805
33224
  if (current === source)
32806
33225
  return false;
32807
- await mkdir15(dirname15(path), { recursive: true });
33226
+ await mkdir16(dirname16(path), { recursive: true });
32808
33227
  if (current === null) {
32809
- await writeFile18(path, source, { flag: "wx" });
33228
+ await writeFile19(path, source, { flag: "wx" });
32810
33229
  return true;
32811
33230
  }
32812
33231
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
32813
- await writeFile18(temporary, source, { flag: "wx" });
32814
- await rename14(temporary, path);
33232
+ await writeFile19(temporary, source, { flag: "wx" });
33233
+ await rename15(temporary, path);
32815
33234
  return true;
32816
33235
  };
32817
33236
  var removeOwnedFile = async (path) => {
32818
33237
  if (await optionalSource2(path) === null)
32819
33238
  return false;
32820
- await rm11(path);
33239
+ await rm12(path);
32821
33240
  return true;
32822
33241
  };
32823
33242
  var replaceMarkedRegion = (source, start, end, region, insertion, error) => {
@@ -32954,11 +33373,11 @@ public final class AbsoluteMobileUpdateWatchdogPlugin: CAPPlugin, CAPBridgedPlug
32954
33373
  ${PLUGIN_END}
32955
33374
  `;
32956
33375
  var configureIos3 = async (config, enabled) => {
32957
- const path = join25(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
32958
- const capacitorConfigPath = join25(config.nativeProjectDirectory, "ios/App/App/capacitor.config.json");
32959
- let source = await readFile21(path, "utf8");
32960
- const launch = source.indexOf("didFinishLaunchingWithOptions");
32961
- const brace = launch < 0 ? -1 : source.indexOf("{", launch);
33376
+ const path = join26(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
33377
+ const capacitorConfigPath = join26(config.nativeProjectDirectory, "ios/App/App/capacitor.config.json");
33378
+ let source = await readFile22(path, "utf8");
33379
+ const launch2 = source.indexOf("didFinishLaunchingWithOptions");
33380
+ const brace = launch2 < 0 ? -1 : source.indexOf("{", launch2);
32962
33381
  const launchRegion = enabled ? ` ${START}
32963
33382
  AbsoluteMobileUpdateWatchdogPlugin.recoverInterruptedBoot()
32964
33383
  ${END}
@@ -32967,11 +33386,11 @@ var configureIos3 = async (config, enabled) => {
32967
33386
  `, brace) + 1, "Could not find a safe iOS location for mobile update recovery.");
32968
33387
  const plugin = enabled ? iosPluginRegion(config.updates?.bootTimeoutMs ?? 20000) : "";
32969
33388
  source = replaceMarkedRegion(source, PLUGIN_START, PLUGIN_END, plugin, source.length, "Could not find a safe iOS location for the mobile update watchdog.");
32970
- const capacitorConfigSource2 = await readFile21(capacitorConfigPath, "utf8");
33389
+ const capacitorConfigSource2 = await readFile22(capacitorConfigPath, "utf8");
32971
33390
  let capacitorConfig;
32972
33391
  try {
32973
33392
  const value = JSON.parse(capacitorConfigSource2);
32974
- if (!isRecord11(value))
33393
+ if (!isRecord12(value))
32975
33394
  throw new TypeError;
32976
33395
  capacitorConfig = value;
32977
33396
  } catch {
@@ -33147,12 +33566,12 @@ var androidActivityInRoot = async (root) => {
33147
33566
  throw error;
33148
33567
  }
33149
33568
  const candidate = entries.find((entry) => entry.endsWith("/MainActivity.java") || entry.endsWith("/MainActivity.kt") || entry === "MainActivity.java" || entry === "MainActivity.kt");
33150
- return candidate ? join25(root, candidate) : undefined;
33569
+ return candidate ? join26(root, candidate) : undefined;
33151
33570
  };
33152
33571
  var androidActivity = async (config) => {
33153
33572
  const roots = [
33154
- join25(config.nativeProjectDirectory, "android/app/src/main/java"),
33155
- join25(config.nativeProjectDirectory, "android/app/src/main/kotlin")
33573
+ join26(config.nativeProjectDirectory, "android/app/src/main/java"),
33574
+ join26(config.nativeProjectDirectory, "android/app/src/main/kotlin")
33156
33575
  ];
33157
33576
  const candidates = await Promise.all(roots.map(androidActivityInRoot));
33158
33577
  const candidate = candidates.find((value) => value !== undefined);
@@ -33251,12 +33670,12 @@ var injectAndroidActivity = (source, enabled) => {
33251
33670
  };
33252
33671
  var configureAndroid3 = async (config, enabled) => {
33253
33672
  const activityPath = await androidActivity(config);
33254
- const activity = await readFile21(activityPath, "utf8");
33673
+ const activity = await readFile22(activityPath, "utf8");
33255
33674
  const packageName = activity.match(/^\s*package\s+([A-Za-z0-9_.]+)\s*[;\n]/mu)?.[1];
33256
33675
  if (!packageName)
33257
33676
  throw new TypeError("Android MainActivity package declaration was not found.");
33258
33677
  const packagePath = packageName.replaceAll(".", "/");
33259
- const pluginPath = join25(config.nativeProjectDirectory, "android/app/src/main/java", packagePath, ANDROID_PLUGIN);
33678
+ const pluginPath = join26(config.nativeProjectDirectory, "android/app/src/main/java", packagePath, ANDROID_PLUGIN);
33260
33679
  const changed = await Promise.all([
33261
33680
  writeChanged(activityPath, injectAndroidActivity(activity, enabled)),
33262
33681
  enabled ? writeChanged(pluginPath, androidPluginSource(packageName, config.updates?.bootTimeoutMs ?? 20000)) : removeOwnedFile(pluginPath)
@@ -33276,14 +33695,14 @@ var applyAbsoluteNativeUpdates = async (config, platforms = config.platforms) =>
33276
33695
  };
33277
33696
  // src/mobile/nativeObservability.ts
33278
33697
  import {
33279
- mkdir as mkdir16,
33280
- readFile as readFile22,
33698
+ mkdir as mkdir17,
33699
+ readFile as readFile23,
33281
33700
  readdir as readdir7,
33282
- rename as rename15,
33283
- rm as rm12,
33284
- writeFile as writeFile19
33701
+ rename as rename16,
33702
+ rm as rm13,
33703
+ writeFile as writeFile20
33285
33704
  } from "fs/promises";
33286
- import { dirname as dirname16, join as join26 } from "path";
33705
+ import { dirname as dirname17, join as join27 } from "path";
33287
33706
  var START2 = "// absolutejs:native-observability:start";
33288
33707
  var END2 = "// absolutejs:native-observability:end";
33289
33708
  var PLUGIN_START2 = "// absolutejs:native-observability-plugin:start";
@@ -33291,7 +33710,7 @@ var PLUGIN_END2 = "// absolutejs:native-observability-plugin:end";
33291
33710
  var ANDROID_PLUGIN2 = "AbsoluteMobileObservabilityPlugin.java";
33292
33711
  var optionalSource3 = async (path) => {
33293
33712
  try {
33294
- return await readFile22(path, "utf8");
33713
+ return await readFile23(path, "utf8");
33295
33714
  } catch (error) {
33296
33715
  if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "ENOENT")
33297
33716
  return null;
@@ -33302,23 +33721,23 @@ var writeChanged2 = async (path, source) => {
33302
33721
  const current = await optionalSource3(path);
33303
33722
  if (current === source)
33304
33723
  return false;
33305
- await mkdir16(dirname16(path), { recursive: true });
33724
+ await mkdir17(dirname17(path), { recursive: true });
33306
33725
  if (current === null) {
33307
- await writeFile19(path, source, { flag: "wx" });
33726
+ await writeFile20(path, source, { flag: "wx" });
33308
33727
  return true;
33309
33728
  }
33310
33729
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
33311
- await writeFile19(temporary, source, { flag: "wx" });
33312
- await rename15(temporary, path);
33730
+ await writeFile20(temporary, source, { flag: "wx" });
33731
+ await rename16(temporary, path);
33313
33732
  return true;
33314
33733
  };
33315
33734
  var removeOwnedFile2 = async (path) => {
33316
33735
  if (await optionalSource3(path) === null)
33317
33736
  return false;
33318
- await rm12(path);
33737
+ await rm13(path);
33319
33738
  return true;
33320
33739
  };
33321
- var isRecord12 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
33740
+ var isRecord13 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
33322
33741
  var replaceMarkedRegion2 = (source, start, end, region, insertion, error) => {
33323
33742
  const existingStart = source.indexOf(start);
33324
33743
  const existingEnd = source.indexOf(end);
@@ -33451,9 +33870,9 @@ public final class AbsoluteMobileObservabilityPlugin: CAPPlugin, CAPBridgedPlugi
33451
33870
  ${PLUGIN_END2}
33452
33871
  `;
33453
33872
  var configureIos4 = async (config, enabled) => {
33454
- const path = join26(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
33455
- const capacitorConfigPath = join26(config.nativeProjectDirectory, "ios/App/App/capacitor.config.json");
33456
- let source = await readFile22(path, "utf8");
33873
+ const path = join27(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
33874
+ const capacitorConfigPath = join27(config.nativeProjectDirectory, "ios/App/App/capacitor.config.json");
33875
+ let source = await readFile23(path, "utf8");
33457
33876
  if (enabled && !source.includes("import MetricKit")) {
33458
33877
  const capacitorImport = source.lastIndexOf("import Capacitor");
33459
33878
  if (capacitorImport < 0)
@@ -33467,11 +33886,11 @@ ${source.slice(newline + 1)}`;
33467
33886
  source = source.replace(`import MetricKit
33468
33887
  `, "");
33469
33888
  source = replaceMarkedRegion2(source, PLUGIN_START2, PLUGIN_END2, enabled ? iosPluginRegion2 : "", source.length, "Could not find a safe iOS location for native observability.");
33470
- const capacitorConfigSource2 = await readFile22(capacitorConfigPath, "utf8");
33889
+ const capacitorConfigSource2 = await readFile23(capacitorConfigPath, "utf8");
33471
33890
  let capacitorConfig;
33472
33891
  try {
33473
33892
  const value = JSON.parse(capacitorConfigSource2);
33474
- if (!isRecord12(value))
33893
+ if (!isRecord13(value))
33475
33894
  throw new TypeError;
33476
33895
  capacitorConfig = value;
33477
33896
  } catch {
@@ -33712,12 +34131,12 @@ var androidActivityInRoot2 = async (root) => {
33712
34131
  throw error;
33713
34132
  }
33714
34133
  const candidate = entries.find((entry) => entry.endsWith("/MainActivity.java") || entry.endsWith("/MainActivity.kt") || entry === "MainActivity.java" || entry === "MainActivity.kt");
33715
- return candidate ? join26(root, candidate) : undefined;
34134
+ return candidate ? join27(root, candidate) : undefined;
33716
34135
  };
33717
34136
  var androidActivity2 = async (config) => {
33718
34137
  const roots = [
33719
- join26(config.nativeProjectDirectory, "android/app/src/main/java"),
33720
- join26(config.nativeProjectDirectory, "android/app/src/main/kotlin")
34138
+ join27(config.nativeProjectDirectory, "android/app/src/main/java"),
34139
+ join27(config.nativeProjectDirectory, "android/app/src/main/kotlin")
33721
34140
  ];
33722
34141
  const candidates = await Promise.all(roots.map(androidActivityInRoot2));
33723
34142
  const candidate = candidates.find((value) => value !== undefined);
@@ -33785,11 +34204,11 @@ var injectAndroidActivity2 = (source, enabled) => {
33785
34204
  };
33786
34205
  var configureAndroid4 = async (config, enabled) => {
33787
34206
  const activityPath = await androidActivity2(config);
33788
- const activity = await readFile22(activityPath, "utf8");
34207
+ const activity = await readFile23(activityPath, "utf8");
33789
34208
  const packageName = activity.match(/^\s*package\s+([A-Za-z0-9_.]+)\s*[;\n]/mu)?.[1];
33790
34209
  if (!packageName)
33791
34210
  throw new TypeError("Android MainActivity package declaration was not found.");
33792
- const pluginPath = join26(config.nativeProjectDirectory, "android/app/src/main/java", packageName.replaceAll(".", "/"), ANDROID_PLUGIN2);
34211
+ const pluginPath = join27(config.nativeProjectDirectory, "android/app/src/main/java", packageName.replaceAll(".", "/"), ANDROID_PLUGIN2);
33793
34212
  const changed = await Promise.all([
33794
34213
  writeChanged2(activityPath, injectAndroidActivity2(activity, enabled)),
33795
34214
  enabled ? writeChanged2(pluginPath, androidPluginSource2(packageName)) : removeOwnedFile2(pluginPath)
@@ -33814,8 +34233,8 @@ init_producerContext();
33814
34233
  init_releaseArtifact();
33815
34234
 
33816
34235
  // src/mobile/releasePublisher.ts
33817
- import { access as access15 } from "fs/promises";
33818
- import { isAbsolute as isAbsolute7, relative as relative14, resolve as resolve16, sep as sep9 } from "path";
34236
+ import { access as access16 } from "fs/promises";
34237
+ import { isAbsolute as isAbsolute8, relative as relative15, resolve as resolve17, sep as sep10 } from "path";
33819
34238
  import { pathToFileURL as pathToFileURL3 } from "url";
33820
34239
  var prepareAbsoluteIosRelease = async (publisher, options) => {
33821
34240
  if (typeof publisher.prepareIosRelease !== "function") {
@@ -33838,24 +34257,24 @@ var prepareAbsoluteAndroidRelease = async (publisher, options) => {
33838
34257
  }
33839
34258
  return versionCode;
33840
34259
  };
33841
- var isRecord13 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
33842
- var isPublisher = (value) => isRecord13(value) && typeof value.publish === "function";
34260
+ var isRecord14 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
34261
+ var isPublisher = (value) => isRecord14(value) && typeof value.publish === "function";
33843
34262
  var publisherModulePath = (projectRoot, requested) => {
33844
- const root = resolve16(projectRoot);
33845
- const path = resolve16(root, requested);
33846
- const projectRelative = relative14(root, path);
33847
- if (projectRelative === ".." || projectRelative.startsWith(`..${sep9}`) || isAbsolute7(projectRelative)) {
34263
+ const root = resolve17(projectRoot);
34264
+ const path = resolve17(root, requested);
34265
+ const projectRelative = relative15(root, path);
34266
+ if (projectRelative === ".." || projectRelative.startsWith(`..${sep10}`) || isAbsolute8(projectRelative)) {
33848
34267
  throw new TypeError("mobile publish --registry must remain inside the project.");
33849
34268
  }
33850
34269
  return path;
33851
34270
  };
33852
34271
  var loadAbsoluteNativeReleasePublisher = async (projectRoot, requestedModulePath) => {
33853
34272
  const modulePath = publisherModulePath(projectRoot, requestedModulePath);
33854
- await access15(modulePath).catch(() => {
34273
+ await access16(modulePath).catch(() => {
33855
34274
  throw new TypeError(`Native release registry module does not exist: ${modulePath}`);
33856
34275
  });
33857
34276
  const loaded = await import(pathToFileURL3(modulePath).href);
33858
- const publisher = isRecord13(loaded) ? loaded.default ?? loaded.registry : undefined;
34277
+ const publisher = isRecord14(loaded) ? loaded.default ?? loaded.registry : undefined;
33859
34278
  if (!isPublisher(publisher)) {
33860
34279
  throw new TypeError("Native release registry module must default-export a registry with publish(options).");
33861
34280
  }
@@ -33915,7 +34334,7 @@ var publishAbsoluteIosRelease = async (options) => {
33915
34334
  init_pageProtocol();
33916
34335
  init_releaseArtifact();
33917
34336
  import { existsSync as existsSync7, readFileSync as readFileSync8 } from "fs";
33918
- import { dirname as dirname17, extname as extname6, relative as relative15, resolve as resolve17 } from "path";
34337
+ import { dirname as dirname18, extname as extname6, relative as relative16, resolve as resolve18 } from "path";
33919
34338
  import ts2 from "typescript";
33920
34339
  var ROUTE_METHODS = new Set(["get", "head"]);
33921
34340
  var SOURCE_FILTER = /\.[cm]?[jt]sx?$/;
@@ -33966,7 +34385,7 @@ var PAGE_HANDLERS = new Map([
33966
34385
  ]
33967
34386
  ]);
33968
34387
  var posixPath = (value) => value.replace(/\\/g, "/");
33969
- var findTsconfig = (entry, projectRoot) => ts2.findConfigFile(dirname17(entry), existsSync7, "tsconfig.json") ?? ts2.findConfigFile(projectRoot, existsSync7, "tsconfig.json");
34388
+ var findTsconfig = (entry, projectRoot) => ts2.findConfigFile(dirname18(entry), existsSync7, "tsconfig.json") ?? ts2.findConfigFile(projectRoot, existsSync7, "tsconfig.json");
33970
34389
  var createProgram = (entry, projectRoot) => {
33971
34390
  const configPath2 = findTsconfig(entry, projectRoot);
33972
34391
  if (!configPath2) {
@@ -33978,7 +34397,7 @@ var createProgram = (entry, projectRoot) => {
33978
34397
  target: ts2.ScriptTarget.ESNext
33979
34398
  });
33980
34399
  }
33981
- const parsed = ts2.parseJsonConfigFileContent(ts2.readConfigFile(configPath2, (path) => readFileSync8(path, "utf8")).config, ts2.sys, dirname17(configPath2));
34400
+ const parsed = ts2.parseJsonConfigFileContent(ts2.readConfigFile(configPath2, (path) => readFileSync8(path, "utf8")).config, ts2.sys, dirname18(configPath2));
33982
34401
  if (!parsed.fileNames.includes(entry))
33983
34402
  parsed.fileNames.push(entry);
33984
34403
  return ts2.createProgram(parsed.fileNames, parsed.options);
@@ -34084,7 +34503,7 @@ var resolvePageIdentity = (expression, sourceFile, checker, projectRoot) => {
34084
34503
  const declaration = symbol?.declarations?.[0];
34085
34504
  const file = declaration?.getSourceFile().fileName ?? sourceFile.fileName;
34086
34505
  const exportedName = symbol?.name ?? expression.getText(sourceFile);
34087
- const source = posixPath(relative15(projectRoot, file));
34506
+ const source = posixPath(relative16(projectRoot, file));
34088
34507
  return `${source}#${exportedName}`;
34089
34508
  };
34090
34509
  var resolveAlias = (symbol, checker) => {
@@ -34323,7 +34742,7 @@ var analyzeProgram = (program, projectRoot) => {
34323
34742
  const checker = program.getTypeChecker();
34324
34743
  const analyzed = new Map;
34325
34744
  for (const sourceFile of program.getSourceFiles()) {
34326
- const resolvedFile = resolve17(sourceFile.fileName);
34745
+ const resolvedFile = resolve18(sourceFile.fileName);
34327
34746
  if (!isProjectSource(sourceFile, resolvedFile, projectRoot))
34328
34747
  continue;
34329
34748
  const analysis = analyzeSourceFile(sourceFile, checker, projectRoot);
@@ -34416,14 +34835,14 @@ var transformFile = (source, fileName, analysis) => {
34416
34835
  };
34417
34836
  var ABSOLUTE_MOBILE_TRANSFORM_PROTOCOL = ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION;
34418
34837
  var createAbsoluteMobileRouteMetadataPlugin = (options) => {
34419
- const projectRoot = resolve17(options.projectRoot ?? process.cwd());
34420
- const entry = resolve17(options.entry);
34838
+ const projectRoot = resolve18(options.projectRoot ?? process.cwd());
34839
+ const entry = resolve18(options.entry);
34421
34840
  const analyzed = analyzeProgram(createProgram(entry, projectRoot), projectRoot);
34422
34841
  return {
34423
34842
  name: "absolute-mobile-route-metadata",
34424
34843
  setup(build) {
34425
34844
  build.onLoad({ filter: SOURCE_FILTER }, async ({ path }) => {
34426
- const analysis = analyzed.get(resolve17(path));
34845
+ const analysis = analyzed.get(resolve18(path));
34427
34846
  if (!analysis)
34428
34847
  return;
34429
34848
  const source = await Bun.file(path).text();
@@ -34436,11 +34855,11 @@ var createAbsoluteMobileRouteMetadataPlugin = (options) => {
34436
34855
  };
34437
34856
  };
34438
34857
  var inspectAbsoluteMobileRouteMetadata = (options) => {
34439
- const projectRoot = resolve17(options.projectRoot ?? process.cwd());
34440
- const entry = resolve17(options.entry);
34858
+ const projectRoot = resolve18(options.projectRoot ?? process.cwd());
34859
+ const entry = resolve18(options.entry);
34441
34860
  const analyzed = analyzeProgram(createProgram(entry, projectRoot), projectRoot);
34442
34861
  return [...analyzed.entries()].flatMap(([file, analysis]) => [...analysis.byRouteCall.values()].map(({ metadata }) => ({
34443
- file: posixPath(relative15(projectRoot, file)),
34862
+ file: posixPath(relative16(projectRoot, file)),
34444
34863
  metadata
34445
34864
  })));
34446
34865
  };
@@ -34774,7 +35193,7 @@ var createCapacitor = (win) => {
34774
35193
  callbackId
34775
35194
  }, callback);
34776
35195
  };
34777
- const p = new Promise((resolve18) => call.then(() => resolve18({ remove })));
35196
+ const p = new Promise((resolve19) => call.then(() => resolve19({ remove })));
34778
35197
  p.remove = async () => {
34779
35198
  console.warn(`Using addListener() without 'await' is deprecated.`);
34780
35199
  await remove();
@@ -34979,11 +35398,11 @@ class CapacitorCookiesPluginWeb extends WebPlugin {
34979
35398
  var CapacitorCookies = registerPlugin("CapacitorCookies", {
34980
35399
  web: () => new CapacitorCookiesPluginWeb
34981
35400
  });
34982
- var readBlobAsBase64 = async (blob) => new Promise((resolve18, reject) => {
35401
+ var readBlobAsBase64 = async (blob) => new Promise((resolve19, reject) => {
34983
35402
  const reader = new FileReader;
34984
35403
  reader.onload = () => {
34985
35404
  const base64String = reader.result;
34986
- resolve18(base64String.indexOf(",") >= 0 ? base64String.split(",")[1] : base64String);
35405
+ resolve19(base64String.indexOf(",") >= 0 ? base64String.split(",")[1] : base64String);
34987
35406
  };
34988
35407
  reader.onerror = (error) => reject(error);
34989
35408
  reader.readAsDataURL(blob);
@@ -35159,7 +35578,7 @@ var REPORT_KINDS = new Set([
35159
35578
  "signal"
35160
35579
  ]);
35161
35580
  var nativeObservability = registerPlugin("AbsoluteMobileObservability");
35162
- var isRecord14 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
35581
+ var isRecord15 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
35163
35582
  var redactText = (value) => value.slice(0, MAX_STRING_LENGTH).replace(/\b(Bearer)\s+[A-Za-z0-9._~+/-]+=*/giu, "$1 [REDACTED]").replace(/([?&](?:access_token|api_?key|authorization|code|id_token|password|refresh_token|secret|token)=)[^&#\s]*/giu, "$1[REDACTED]").replace(/\b((?:access_?token|api_?key|authorization|client_?secret|cookie|id_?token|password|passwd|refresh_?token|secret|token)\s*[:=]\s*)[^,\s;]+/giu, "$1[REDACTED]").replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/gu, "[REDACTED]");
35164
35583
  var redactValue = (value, depth = 0) => {
35165
35584
  if (depth >= MAX_REDACTION_DEPTH)
@@ -35170,7 +35589,7 @@ var redactValue = (value, depth = 0) => {
35170
35589
  return value;
35171
35590
  if (Array.isArray(value))
35172
35591
  return value.slice(0, 64).map((entry) => redactValue(entry, depth + 1));
35173
- if (!isRecord14(value))
35592
+ if (!isRecord15(value))
35174
35593
  return String(value).slice(0, MAX_STRING_LENGTH);
35175
35594
  return Object.fromEntries(Object.entries(value).slice(0, 128).map(([key, entry]) => [
35176
35595
  key,
@@ -35178,7 +35597,7 @@ var redactValue = (value, depth = 0) => {
35178
35597
  ]));
35179
35598
  };
35180
35599
  var parseReport = (value) => {
35181
- if (!isRecord14(value) || !isRecord14(value.details))
35600
+ if (!isRecord15(value) || !isRecord15(value.details))
35182
35601
  return;
35183
35602
  if (typeof value.id !== "string" || !REPORT_ID.test(value.id))
35184
35603
  return;
@@ -35189,7 +35608,7 @@ var parseReport = (value) => {
35189
35608
  if (value.platform !== "android" && value.platform !== "ios")
35190
35609
  return;
35191
35610
  const details = redactValue(value.details);
35192
- if (!isRecord14(details))
35611
+ if (!isRecord15(details))
35193
35612
  return;
35194
35613
  if (new TextEncoder().encode(JSON.stringify(details)).byteLength > MAX_DETAIL_BYTES)
35195
35614
  return;
@@ -39643,8 +40062,8 @@ var createBeacon = (options) => {
39643
40062
  if (await fontAvailable(element))
39644
40063
  return;
39645
40064
  if (confirmationMs > 0) {
39646
- await new Promise((resolve18) => {
39647
- const timer2 = window.setTimeout(resolve18, confirmationMs);
40065
+ await new Promise((resolve19) => {
40066
+ const timer2 = window.setTimeout(resolve19, confirmationMs);
39648
40067
  cleanups.push(() => window.clearTimeout(timer2));
39649
40068
  });
39650
40069
  if (document.visibilityState === "hidden")
@@ -40632,51 +41051,51 @@ var createAbsoluteMobileUpdateClient = (options) => {
40632
41051
  };
40633
41052
  };
40634
41053
  // src/mobile/updatePublisher.ts
40635
- import { access as access16 } from "fs/promises";
40636
- import { isAbsolute as isAbsolute8, relative as relative17, resolve as resolve19, sep as sep10 } from "path";
41054
+ import { access as access17 } from "fs/promises";
41055
+ import { isAbsolute as isAbsolute9, relative as relative18, resolve as resolve20, sep as sep11 } from "path";
40637
41056
  import { pathToFileURL as pathToFileURL4 } from "url";
40638
41057
 
40639
41058
  // src/mobile/updateSigning.ts
40640
- import { createHash as createHash14, sign, verify } from "crypto";
41059
+ import { createHash as createHash15, sign, verify } from "crypto";
40641
41060
  import {
40642
- cp as cp3,
40643
- mkdir as mkdir17,
40644
- mkdtemp as mkdtemp8,
41061
+ cp as cp2,
41062
+ mkdir as mkdir18,
41063
+ mkdtemp as mkdtemp9,
40645
41064
  readdir as readdir8,
40646
- readFile as readFile23,
40647
- rename as rename16,
40648
- rm as rm13,
40649
- stat as stat4,
40650
- writeFile as writeFile20
41065
+ readFile as readFile24,
41066
+ rename as rename17,
41067
+ rm as rm14,
41068
+ stat as stat5,
41069
+ writeFile as writeFile21
40651
41070
  } from "fs/promises";
40652
- import { dirname as dirname18, join as join27, relative as relative16, resolve as resolve18 } from "path";
41071
+ import { dirname as dirname19, join as join28, relative as relative17, resolve as resolve19 } from "path";
40653
41072
  var UPDATE_MANIFEST_FILE = "update.json";
40654
41073
  var UPDATE_FILES_DIRECTORY = "files";
40655
- var sha2562 = (value) => createHash14("sha256").update(value).digest("hex");
41074
+ var sha2563 = (value) => createHash15("sha256").update(value).digest("hex");
40656
41075
  var listFiles = async (root, directory = root) => {
40657
41076
  const entries = await readdir8(directory, { withFileTypes: true });
40658
41077
  const paths = await Promise.all(entries.map(async (entry) => {
40659
- const path = join27(directory, entry.name);
41078
+ const path = join28(directory, entry.name);
40660
41079
  if (entry.isDirectory())
40661
41080
  return listFiles(root, path);
40662
41081
  if (!entry.isFile())
40663
41082
  throw new TypeError("Mobile updates cannot contain links or special files.");
40664
- return [relative16(root, path).replaceAll("\\", "/")];
41083
+ return [relative17(root, path).replaceAll("\\", "/")];
40665
41084
  }));
40666
41085
  return paths.flat().sort((left, right) => left.localeCompare(right));
40667
41086
  };
40668
41087
  var inspectFiles = async (root, paths) => Promise.all(paths.map(async (path) => {
40669
- const source = join27(root, path);
41088
+ const source = join28(root, path);
40670
41089
  const [metadata, contents] = await Promise.all([
40671
- stat4(source),
40672
- readFile23(source)
41090
+ stat5(source),
41091
+ readFile24(source)
40673
41092
  ]);
40674
- return { bytes: metadata.size, path, sha256: sha2562(contents) };
41093
+ return { bytes: metadata.size, path, sha256: sha2563(contents) };
40675
41094
  }));
40676
- var releaseIdFor = (value) => `amu_${sha2562(canonicalizeAbsoluteMobileUpdate(value))}`;
41095
+ var releaseIdFor = (value) => `amu_${sha2563(canonicalizeAbsoluteMobileUpdate(value))}`;
40677
41096
  var buildAbsoluteMobileUpdate = async (options) => {
40678
- const bundleDirectory = resolve18(options.bundleDirectory);
40679
- const outputRoot = resolve18(options.outputDirectory);
41097
+ const bundleDirectory = resolve19(options.bundleDirectory);
41098
+ const outputRoot = resolve19(options.outputDirectory);
40680
41099
  if (outputRoot === bundleDirectory || outputRoot.startsWith(`${bundleDirectory}/`))
40681
41100
  throw new TypeError("Mobile update output must be outside the embedded bundle.");
40682
41101
  const paths = await listFiles(bundleDirectory);
@@ -40704,38 +41123,38 @@ var buildAbsoluteMobileUpdate = async (options) => {
40704
41123
  value: signature.toString("base64")
40705
41124
  }
40706
41125
  });
40707
- await mkdir17(outputRoot, { recursive: true });
40708
- const outputDirectory = join27(outputRoot, manifest.releaseId);
40709
- const staging = await mkdtemp8(join27(outputRoot, ".stage-"));
41126
+ await mkdir18(outputRoot, { recursive: true });
41127
+ const outputDirectory = join28(outputRoot, manifest.releaseId);
41128
+ const staging = await mkdtemp9(join28(outputRoot, ".stage-"));
40710
41129
  try {
40711
- await cp3(bundleDirectory, join27(staging, UPDATE_FILES_DIRECTORY), {
41130
+ await cp2(bundleDirectory, join28(staging, UPDATE_FILES_DIRECTORY), {
40712
41131
  force: true,
40713
41132
  recursive: true
40714
41133
  });
40715
- await writeFile20(join27(staging, UPDATE_MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
41134
+ await writeFile21(join28(staging, UPDATE_MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
40716
41135
  `);
40717
- await rename16(staging, outputDirectory);
41136
+ await rename17(staging, outputDirectory);
40718
41137
  } catch (error) {
40719
- await rm13(staging, { force: true, recursive: true });
41138
+ await rm14(staging, { force: true, recursive: true });
40720
41139
  if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "EEXIST")
40721
41140
  throw new TypeError(`Mobile update ${manifest.releaseId} already exists.`, { cause: error });
40722
41141
  throw error;
40723
41142
  }
40724
41143
  return {
40725
41144
  manifest,
40726
- manifestPath: join27(outputDirectory, UPDATE_MANIFEST_FILE),
41145
+ manifestPath: join28(outputDirectory, UPDATE_MANIFEST_FILE),
40727
41146
  outputDirectory
40728
41147
  };
40729
41148
  };
40730
41149
  var copyAbsoluteMobileUpdateFile = async (updateDirectory, path, destination) => {
40731
- const source = resolve18(updateDirectory, UPDATE_FILES_DIRECTORY, path);
40732
- const root = resolve18(updateDirectory, UPDATE_FILES_DIRECTORY);
41150
+ const source = resolve19(updateDirectory, UPDATE_FILES_DIRECTORY, path);
41151
+ const root = resolve19(updateDirectory, UPDATE_FILES_DIRECTORY);
40733
41152
  if (!source.startsWith(`${root}/`))
40734
41153
  throw new TypeError("Update file escaped its release.");
40735
- await mkdir17(dirname18(destination), { recursive: true });
40736
- await cp3(source, destination, { force: true });
41154
+ await mkdir18(dirname19(destination), { recursive: true });
41155
+ await cp2(source, destination, { force: true });
40737
41156
  };
40738
- var readAbsoluteMobileUpdate = async (directory) => parseAbsoluteMobileUpdateManifest(JSON.parse(await readFile23(join27(resolve18(directory), UPDATE_MANIFEST_FILE), "utf8")));
41157
+ var readAbsoluteMobileUpdate = async (directory) => parseAbsoluteMobileUpdateManifest(JSON.parse(await readFile24(join28(resolve19(directory), UPDATE_MANIFEST_FILE), "utf8")));
40739
41158
  var verifyAbsoluteMobileUpdateSignature = (manifestValue, publicKey) => {
40740
41159
  const manifest = parseAbsoluteMobileUpdateManifest(manifestValue);
40741
41160
  const valid = verify("sha256", absoluteMobileUpdateSigningPayload(unsignedAbsoluteMobileUpdate(manifest)), { dsaEncoding: "ieee-p1363", key: publicKey }, Buffer.from(manifest.signature.value, "base64"));
@@ -40852,16 +41271,16 @@ var pruneAbsoluteMobileUpdates = async (options) => {
40852
41271
  var object5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
40853
41272
  var isPublisher2 = (value) => object5(value) && typeof value.publishUpdate === "function" && typeof value.promoteUpdate === "function" && typeof value.rollbackUpdate === "function";
40854
41273
  var projectPath2 = (projectRoot, requested, label) => {
40855
- const root = resolve19(projectRoot);
40856
- const path = resolve19(root, requested);
40857
- const projectRelative = relative17(root, path);
40858
- if (projectRelative === ".." || projectRelative.startsWith(`..${sep10}`) || isAbsolute8(projectRelative))
41274
+ const root = resolve20(projectRoot);
41275
+ const path = resolve20(root, requested);
41276
+ const projectRelative = relative18(root, path);
41277
+ if (projectRelative === ".." || projectRelative.startsWith(`..${sep11}`) || isAbsolute9(projectRelative))
40859
41278
  throw new TypeError(`${label} must remain inside the project.`);
40860
41279
  return path;
40861
41280
  };
40862
41281
  var loadAbsoluteMobileUpdatePublisher = async (projectRoot, requestedModulePath) => {
40863
41282
  const modulePath = projectPath2(projectRoot, requestedModulePath, "mobile update registry");
40864
- await access16(modulePath).catch(() => {
41283
+ await access17(modulePath).catch(() => {
40865
41284
  throw new TypeError(`Mobile update registry does not exist: ${modulePath}`);
40866
41285
  });
40867
41286
  const loaded = await import(pathToFileURL4(modulePath).href);
@@ -40912,7 +41331,7 @@ var rollbackAbsoluteMobileUpdate = async (options) => {
40912
41331
  return result;
40913
41332
  };
40914
41333
  // src/mobile/updateRollout.ts
40915
- import { createHash as createHash15 } from "crypto";
41334
+ import { createHash as createHash16 } from "crypto";
40916
41335
  var UUID_PATTERN = /^[a-f0-9]{8}-[a-f0-9]{4}-[1-8][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/u;
40917
41336
  var requireHeader = (headers, name) => {
40918
41337
  const value = headers.get(name);
@@ -40927,7 +41346,7 @@ var isAbsoluteMobileUpdateRolloutMember = (options) => {
40927
41346
  return false;
40928
41347
  if (options.rollout === 1)
40929
41348
  return true;
40930
- const digest = createHash15("sha256").update(`${options.appId}\x00${options.channel}\x00${options.releaseId}\x00${options.installationId}`).digest();
41349
+ const digest = createHash16("sha256").update(`${options.appId}\x00${options.channel}\x00${options.releaseId}\x00${options.installationId}`).digest();
40931
41350
  const bucket = digest.readUInt32BE(0) / 4294967296;
40932
41351
  return bucket < options.rollout;
40933
41352
  };
@@ -40951,6 +41370,9 @@ init_updateServer();
40951
41370
  export {
40952
41371
  ABSOLUTE_ANDROID_RELEASE_FORMAT,
40953
41372
  ABSOLUTE_AUTH_PACKAGE,
41373
+ ABSOLUTE_BUNDLETOOL_SHA256,
41374
+ ABSOLUTE_BUNDLETOOL_URL,
41375
+ ABSOLUTE_BUNDLETOOL_VERSION,
40954
41376
  ABSOLUTE_EXPO_AUTH_CORE_VERSION,
40955
41377
  ABSOLUTE_EXPO_AUTH_PACKAGE,
40956
41378
  ABSOLUTE_EXPO_AUTH_VERSION,
@@ -40999,6 +41421,7 @@ export {
40999
41421
  MOBILE_PAGE_REQUEST_HEADERS,
41000
41422
  absoluteAndroidNodeLabel,
41001
41423
  absoluteAndroidTouchTargetDp,
41424
+ absoluteBundletoolPath,
41002
41425
  absoluteDeviceNativeRequirements,
41003
41426
  absoluteExpoExecutable,
41004
41427
  absoluteExpoNativeObservabilityFiles,
@@ -41066,6 +41489,7 @@ export {
41066
41489
  discoverAbsoluteSyncSchema,
41067
41490
  disposeAbsoluteMobilePage,
41068
41491
  drainAbsoluteMobileNativeObservability,
41492
+ ensureAbsoluteBundletool,
41069
41493
  expoNativeObservabilityRuntimeSource,
41070
41494
  fetchAbsoluteMobilePage,
41071
41495
  finalizeAbsoluteExpoUpdateExport,
@@ -41082,6 +41506,7 @@ export {
41082
41506
  getCurrentAbsoluteMobileProducerContext,
41083
41507
  hashAbsoluteMobilePropsSchema,
41084
41508
  inspectAbsoluteAndroidInstalledApp,
41509
+ inspectAbsoluteBundletool,
41085
41510
  inspectAbsoluteIosInstalledApp,
41086
41511
  inspectAbsoluteMobileRouteMetadata,
41087
41512
  inspectAbsoluteMobileUpdateHealth,
@@ -41157,6 +41582,7 @@ export {
41157
41582
  publishAbsoluteAndroidRelease,
41158
41583
  publishAbsoluteIosRelease,
41159
41584
  publishAbsoluteMobileUpdate,
41585
+ readAbsoluteAndroidRelease,
41160
41586
  readAbsoluteMobileLinkIntent,
41161
41587
  readAbsoluteMobileMaterializedReleases,
41162
41588
  readAbsoluteMobileUpdate,
@@ -41179,6 +41605,7 @@ export {
41179
41605
  resumeAbsoluteMobileUpdateRollout,
41180
41606
  retainAbsoluteMobileCompatibilityArtifacts,
41181
41607
  rollbackAbsoluteMobileUpdate,
41608
+ runAbsoluteAndroidReleaseAcceptance,
41182
41609
  runAbsoluteAndroidUpgradeConformance,
41183
41610
  runWithAbsoluteMobileProducer,
41184
41611
  serializeAbsoluteMobileAuthEnvironment,
@@ -41205,5 +41632,5 @@ export {
41205
41632
  writeAbsoluteMobileUpdateRegistry
41206
41633
  };
41207
41634
 
41208
- //# debugId=F9E3EF5E6450400964756E2164756E21
41635
+ //# debugId=FC8B1849EF68EB6464756E2164756E21
41209
41636
  //# sourceMappingURL=index.js.map