@absolutejs/absolute 0.20.0-beta.45 → 0.20.0-beta.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -718,7 +718,7 @@ var init_portScan = () => {};
718
718
 
719
719
  // src/mobile/config.ts
720
720
  import { resolve as resolve2 } from "path";
721
- var APP_ID_PATTERN, SCHEME_PATTERN, APPLE_APP_ID_PREFIX_PATTERN, CERTIFICATE_FINGERPRINT_PATTERN, HOSTNAME_PATTERN, resolveProjectPath = (projectRoot, value, field) => {
721
+ var APP_ID_PATTERN, SCHEME_PATTERN, APPLE_APP_ID_PREFIX_PATTERN, CERTIFICATE_FINGERPRINT_PATTERN, HOSTNAME_PATTERN, EXPO_RESERVED_ROUTE_PREFIXES, resolveProjectPath = (projectRoot, value, field) => {
722
722
  const root = resolve2(projectRoot);
723
723
  const path = resolve2(root, value);
724
724
  if (path !== root && !path.startsWith(`${root}/`)) {
@@ -791,11 +791,31 @@ var APP_ID_PATTERN, SCHEME_PATTERN, APPLE_APP_ID_PREFIX_PATTERN, CERTIFICATE_FIN
791
791
  }
792
792
  return value.match(/.{2}/g)?.join(":") ?? value;
793
793
  }))
794
- ].sort(), normalizeExpoNativeRoutes = (config, projectRoot) => {
794
+ ].sort(), validateExpoNativeRouteSegment = (path, segment, index, count, parameters) => {
795
+ if (segment === "*" && (index !== count - 1 || count === 1)) {
796
+ throw new TypeError(`mobile.routes.native route ${path} must use * once, as the final segment after a static or parameterized prefix.`);
797
+ }
798
+ if (segment === "*")
799
+ return;
800
+ if (!segment.startsWith(":") && (segment.includes("*") || segment.includes(":"))) {
801
+ throw new TypeError(`mobile.routes.native route ${path} contains invalid segment ${segment}.`);
802
+ }
803
+ if (!segment.startsWith(":"))
804
+ return;
805
+ const name = segment.slice(1);
806
+ if (!/^[A-Za-z][A-Za-z0-9_]*$/u.test(name)) {
807
+ throw new TypeError(`mobile.routes.native route ${path} has invalid parameter ${segment}.`);
808
+ }
809
+ if (parameters.has(name)) {
810
+ throw new TypeError(`mobile.routes.native route ${path} repeats parameter ${segment}.`);
811
+ }
812
+ parameters.add(name);
813
+ }, normalizeExpoNativeRoutes = (config, projectRoot) => {
795
814
  if (config.engine !== "expo")
796
815
  return {};
797
816
  const routes = config.routes?.native ?? {};
798
817
  const normalized = {};
818
+ const ownership = new Map;
799
819
  for (const [route, module] of Object.entries(routes)) {
800
820
  const path = normalizeEntry(route);
801
821
  if (path.includes("?") || path.includes("#") || path !== "/" && path.endsWith("/")) {
@@ -804,9 +824,18 @@ var APP_ID_PATTERN, SCHEME_PATTERN, APPLE_APP_ID_PREFIX_PATTERN, CERTIFICATE_FIN
804
824
  if (path === "/__absolute/native") {
805
825
  throw new TypeError("mobile.routes.native reserves /__absolute/native for the Expo diagnostic screen.");
806
826
  }
807
- if (path.includes("*") || path.includes(":")) {
808
- throw new TypeError(`mobile.routes.native route ${path} must be static during the Expo experiment; parameters and wildcards are not supported yet.`);
827
+ const segments = path.split("/").filter(Boolean);
828
+ if (segments[0] && EXPO_RESERVED_ROUTE_PREFIXES.has(segments[0])) {
829
+ throw new TypeError(`mobile.routes.native route ${path} conflicts with an Expo Router or Metro reserved path.`);
830
+ }
831
+ const parameters = new Set;
832
+ segments.forEach((segment, index) => validateExpoNativeRouteSegment(path, segment, index, segments.length, parameters));
833
+ const signature = segments.map((segment) => segment.startsWith(":") ? ":" : segment).join("/");
834
+ const existing = ownership.get(signature);
835
+ if (existing) {
836
+ throw new TypeError(`mobile.routes.native routes ${existing} and ${path} claim the same Expo route pattern.`);
809
837
  }
838
+ ownership.set(signature, path);
810
839
  normalized[path] = resolveProjectPath(projectRoot, requireText(module, `mobile.routes.native[${path}]`), `mobile.routes.native[${path}]`);
811
840
  }
812
841
  return Object.fromEntries(Object.entries(normalized).sort(([left], [right]) => left.localeCompare(right)));
@@ -845,6 +874,16 @@ var init_config = __esm(() => {
845
874
  APPLE_APP_ID_PREFIX_PATTERN = /^[A-Z0-9]{10}$/;
846
875
  CERTIFICATE_FINGERPRINT_PATTERN = /^[0-9A-F]{64}$/;
847
876
  HOSTNAME_PATTERN = /^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\.(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?))*$/;
877
+ EXPO_RESERVED_ROUTE_PREFIXES = new Set([
878
+ "_expo",
879
+ "_flight",
880
+ "_sitemap",
881
+ "assets",
882
+ "expo-dev-plugins",
883
+ "inspector",
884
+ "manifest",
885
+ "public"
886
+ ]);
848
887
  });
849
888
 
850
889
  // src/mobile/nativeAuth.ts
@@ -1314,6 +1353,279 @@ var init_syncSchema = __esm(() => {
1314
1353
  init_client();
1315
1354
  });
1316
1355
 
1356
+ // src/mobile/deviceCapabilities.ts
1357
+ import { existsSync as existsSync3, readFileSync as readFileSync7 } from "fs";
1358
+ import { extname, join as join7, relative, resolve as resolve4 } from "path";
1359
+ import { fileURLToPath } from "url";
1360
+ import ts from "typescript";
1361
+ var DEVICES_PACKAGE = "@absolutejs/devices", 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, object2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), readJson = (path) => {
1362
+ const value = JSON.parse(readFileSync7(path, "utf8"));
1363
+ if (!object2(value))
1364
+ throw new TypeError(`${path} must contain an object.`);
1365
+ return value;
1366
+ }, text = (value, field) => {
1367
+ if (typeof value !== "string" || value.length === 0)
1368
+ throw new TypeError(`${field} must be a non-empty string.`);
1369
+ return value;
1370
+ }, androidPermissions = (value, field) => {
1371
+ if (value === undefined)
1372
+ return;
1373
+ if (!object2(value))
1374
+ throw new TypeError(`${field} must be an object.`);
1375
+ const { permissions } = value;
1376
+ if (!Array.isArray(permissions) || !permissions.every((permission) => typeof permission === "string" && ANDROID_PERMISSION_PATTERN.test(permission)))
1377
+ throw new TypeError(`${field}.permissions must contain Android permission names.`);
1378
+ return [...permissions];
1379
+ }, iosPrivacyAccessedApis = (value, field) => {
1380
+ if (value === undefined)
1381
+ return;
1382
+ if (!object2(value))
1383
+ throw new TypeError(`${field} must be an object.`);
1384
+ const privacy = {};
1385
+ for (const api of IOS_PRIVACY_ACCESSED_APIS) {
1386
+ const reasons = value[api];
1387
+ if (reasons === undefined)
1388
+ continue;
1389
+ const supported = IOS_PRIVACY_ACCESSED_API_REASONS[api];
1390
+ if (!Array.isArray(reasons) || reasons.length === 0 || !reasons.every((reason) => typeof reason === "string" && supported.has(reason)))
1391
+ throw new TypeError(`${field} contains an unsupported API or reason.`);
1392
+ privacy[api] = [...reasons];
1393
+ }
1394
+ if (Object.keys(value).some((api) => !IOS_PRIVACY_ACCESSED_APIS.some((known) => known === api)))
1395
+ throw new TypeError(`${field} contains an unsupported API or reason.`);
1396
+ return privacy;
1397
+ }, iosNativeRequirements = (value, field) => {
1398
+ if (value === undefined)
1399
+ return;
1400
+ if (!object2(value))
1401
+ throw new TypeError(`${field} must be an object.`);
1402
+ const {
1403
+ privacyAccessedApis,
1404
+ pushNotifications,
1405
+ systemBars,
1406
+ usageDescriptions
1407
+ } = value;
1408
+ if (pushNotifications !== undefined && pushNotifications !== true)
1409
+ throw new TypeError(`${field}.pushNotifications must be true.`);
1410
+ if (systemBars !== undefined && systemBars !== true)
1411
+ throw new TypeError(`${field}.systemBars must be true.`);
1412
+ if (usageDescriptions !== undefined && (!Array.isArray(usageDescriptions) || !usageDescriptions.every((purpose) => typeof purpose === "string" && IOS_USAGE_DESCRIPTIONS.has(purpose))))
1413
+ throw new TypeError(`${field}.usageDescriptions contains an unsupported purpose.`);
1414
+ const privacy = iosPrivacyAccessedApis(privacyAccessedApis, `${field}.privacyAccessedApis`);
1415
+ return {
1416
+ ...privacy === undefined ? {} : { privacyAccessedApis: privacy },
1417
+ ...pushNotifications === true ? { pushNotifications: true } : {},
1418
+ ...systemBars === true ? { systemBars: true } : {},
1419
+ ...usageDescriptions === undefined ? {} : { usageDescriptions: [...usageDescriptions] }
1420
+ };
1421
+ }, parseProvider = (name, value, providerName) => {
1422
+ if (!IDENTIFIER_PATTERN.test(name))
1423
+ throw new TypeError("Device capability names must be identifiers.");
1424
+ if (!object2(value))
1425
+ throw new TypeError(`Device capability ${name} must be an object.`);
1426
+ const factory = text(value.factory, `${name}.factory`);
1427
+ const module = text(value.module, `${name}.module`);
1428
+ if (!IDENTIFIER_PATTERN.test(factory))
1429
+ throw new TypeError(`${name}.factory must be a JavaScript identifier.`);
1430
+ if (!providerModulePattern(providerName).test(module))
1431
+ throw new TypeError(`${name}.module must be an official devices-${providerName} subpath.`);
1432
+ if (!Array.isArray(value.packages) || !value.packages.every((spec) => typeof spec === "string" && providerPackagePattern(providerName).test(spec)))
1433
+ throw new TypeError(`${name}.packages must contain exact official ${providerLabel(providerName)} package versions.`);
1434
+ const { plugins } = value;
1435
+ if (plugins !== undefined && (!Array.isArray(plugins) || !plugins.every((plugin) => typeof plugin === "string" && /^expo-[a-z][a-z0-9-]*$/u.test(plugin))))
1436
+ throw new TypeError(`${name}.plugins must contain Expo config plugin names.`);
1437
+ let native;
1438
+ const { native: nativeMetadata } = value;
1439
+ if (nativeMetadata !== undefined) {
1440
+ if (!object2(nativeMetadata))
1441
+ throw new TypeError(`${name}.native must be an object.`);
1442
+ const { android, ios } = nativeMetadata;
1443
+ const permissions = androidPermissions(android, `${name}.native.android`);
1444
+ const iosRequirements = iosNativeRequirements(ios, `${name}.native.ios`);
1445
+ native = {
1446
+ ...permissions === undefined ? {} : { android: { permissions } },
1447
+ ...iosRequirements === undefined ? {} : { ios: iosRequirements }
1448
+ };
1449
+ }
1450
+ return {
1451
+ factory,
1452
+ module,
1453
+ ...native === undefined ? {} : { native },
1454
+ ...plugins === undefined ? {} : { plugins: [...plugins] },
1455
+ packages: [...value.packages]
1456
+ };
1457
+ }, absoluteDeviceNativeRequirements = (plan) => {
1458
+ const privacy = plan.capabilities.reduce((requirements, name) => {
1459
+ for (const api of IOS_PRIVACY_ACCESSED_APIS) {
1460
+ const reasons = plan.providers[name]?.native?.ios?.privacyAccessedApis?.[api] ?? [];
1461
+ if (reasons.length === 0)
1462
+ continue;
1463
+ const current = requirements[api] ?? new Set;
1464
+ for (const reason of reasons)
1465
+ current.add(reason);
1466
+ requirements[api] = current;
1467
+ }
1468
+ return requirements;
1469
+ }, {});
1470
+ return {
1471
+ androidPermissions: [
1472
+ ...new Set(plan.capabilities.flatMap((name) => plan.providers[name]?.native?.android?.permissions ?? []))
1473
+ ].sort(),
1474
+ iosPrivacyAccessedApis: IOS_PRIVACY_ACCESSED_APIS.flatMap((api) => {
1475
+ const reasons = privacy[api];
1476
+ return reasons ? [{ api, reasons: [...reasons].sort() }] : [];
1477
+ }),
1478
+ iosPushNotifications: plan.capabilities.some((name) => plan.providers[name]?.native?.ios?.pushNotifications === true),
1479
+ iosSystemBars: plan.capabilities.some((name) => plan.providers[name]?.native?.ios?.systemBars === true),
1480
+ iosUsageDescriptions: [
1481
+ ...new Set(plan.capabilities.flatMap((name) => plan.providers[name]?.native?.ios?.usageDescriptions ?? []))
1482
+ ].sort()
1483
+ };
1484
+ }, loadAbsoluteDeviceCapabilityProviders = (projectRoot, provider = "capacitor") => {
1485
+ const adapter = ADAPTERS[provider];
1486
+ let path = join7(resolve4(projectRoot), "node_modules", adapter, "package.json");
1487
+ try {
1488
+ readFileSync7(path, "utf8");
1489
+ } catch {
1490
+ path = fileURLToPath(import.meta.resolve(`${adapter}/package.json`));
1491
+ }
1492
+ const manifest = readJson(path);
1493
+ const { absolutejs } = manifest;
1494
+ const devices = object2(absolutejs) ? absolutejs.devices : undefined;
1495
+ if (!object2(devices) || devices.format !== 1 || devices.provider !== provider || !object2(devices.capabilities))
1496
+ throw new TypeError(`${adapter} does not publish supported capability metadata.`);
1497
+ const entries = Object.entries(devices.capabilities).map(([name, capability]) => ({
1498
+ name,
1499
+ provider: parseProvider(name, capability, provider)
1500
+ }));
1501
+ return Object.fromEntries(entries.sort((left, right) => left.name.localeCompare(right.name)).map(({ name, provider: capabilityProvider }) => [
1502
+ name,
1503
+ capabilityProvider
1504
+ ]));
1505
+ }, isIgnored = (path) => path.split("/").some((segment) => IGNORED_DIRECTORIES.has(segment)), importedCapabilities = (source, file) => {
1506
+ const names = new Set;
1507
+ const namespaces = new Set;
1508
+ const visit = (node) => {
1509
+ if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier) && node.moduleSpecifier.text === DEVICES_PACKAGE && !node.importClause?.isTypeOnly) {
1510
+ const bindings = node.importClause?.namedBindings;
1511
+ if (bindings && ts.isNamedImports(bindings)) {
1512
+ for (const element of bindings.elements)
1513
+ if (!element.isTypeOnly)
1514
+ names.add((element.propertyName ?? element.name).text);
1515
+ }
1516
+ if (bindings && ts.isNamespaceImport(bindings))
1517
+ namespaces.add(bindings.name.text);
1518
+ }
1519
+ if (ts.isExportDeclaration(node) && !node.isTypeOnly && node.moduleSpecifier !== undefined && ts.isStringLiteral(node.moduleSpecifier) && node.moduleSpecifier.text === DEVICES_PACKAGE && node.exportClause && ts.isNamedExports(node.exportClause)) {
1520
+ for (const element of node.exportClause.elements)
1521
+ if (!element.isTypeOnly)
1522
+ names.add((element.propertyName ?? element.name).text);
1523
+ }
1524
+ if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression) && namespaces.has(node.expression.text))
1525
+ names.add(node.name.text);
1526
+ ts.forEachChild(node, visit);
1527
+ };
1528
+ const extension = extname(file).toLowerCase();
1529
+ const sources = extension === ".svelte" || extension === ".vue" ? [...source.matchAll(/<script\b[^>]*>([\s\S]*?)<\/script\s*>/giu)].map((match) => match[1]).filter((value) => value !== undefined) : [source];
1530
+ for (const [index, script] of sources.entries())
1531
+ visit(ts.createSourceFile(`${file}#script-${index}`, script, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX));
1532
+ return names;
1533
+ }, assertAbsoluteDeviceCapabilityPackages = (projectRoot, plan) => {
1534
+ const missing = missingAbsoluteDeviceCapabilityPackages(plan, directAbsoluteProjectPackages(projectRoot));
1535
+ const mismatched = plan.requiredPackages.filter((spec) => {
1536
+ const separator = spec.lastIndexOf("@");
1537
+ const packageName = spec.slice(0, separator);
1538
+ if (missing.includes(spec))
1539
+ return false;
1540
+ try {
1541
+ return readJson(join7(resolve4(projectRoot), "node_modules", packageName, "package.json")).version !== spec.slice(separator + 1);
1542
+ } catch {
1543
+ return true;
1544
+ }
1545
+ });
1546
+ const unmet = [...missing, ...mismatched];
1547
+ if (unmet.length > 0)
1548
+ throw new TypeError(`Device capabilities ${plan.capabilities.join(", ")} require ${unmet.join(", ")}. Run absolute mobile sync and approve the detected capability plugins.`);
1549
+ }, directAbsoluteProjectPackages = (projectRoot) => {
1550
+ const manifest = readJson(join7(resolve4(projectRoot), "package.json"));
1551
+ const packages = new Set;
1552
+ for (const field of ["dependencies", "devDependencies"]) {
1553
+ const dependencies = manifest[field];
1554
+ if (object2(dependencies))
1555
+ for (const name of Object.keys(dependencies))
1556
+ packages.add(name);
1557
+ }
1558
+ return packages;
1559
+ }, discoverAbsoluteDeviceCapabilities = (projectRoot, providers = loadAbsoluteDeviceCapabilityProviders(projectRoot)) => {
1560
+ const root = resolve4(projectRoot);
1561
+ if (!existsSync3(root))
1562
+ return [];
1563
+ const known = new Set(Object.keys(providers));
1564
+ const capabilities = new Set;
1565
+ for (const path of SOURCE_GLOB.scanSync({ cwd: root })) {
1566
+ const portable = relative(root, resolve4(root, path)).replaceAll("\\", "/");
1567
+ if (isIgnored(portable))
1568
+ continue;
1569
+ const source = readFileSync7(resolve4(root, portable), "utf8");
1570
+ for (const name of importedCapabilities(source, portable))
1571
+ if (known.has(name))
1572
+ capabilities.add(name);
1573
+ }
1574
+ return [...capabilities].sort();
1575
+ }, missingAbsoluteDeviceCapabilityPackages = (plan, directPackages) => plan.requiredPackages.filter((spec) => {
1576
+ const packageName = spec.slice(0, spec.lastIndexOf("@"));
1577
+ return !directPackages.has(packageName);
1578
+ }), resolveAbsoluteDeviceCapabilityPlan = (projectRoot, provider = "capacitor") => {
1579
+ const allProviders = loadAbsoluteDeviceCapabilityProviders(projectRoot, provider);
1580
+ const capabilities = discoverAbsoluteDeviceCapabilities(projectRoot, allProviders);
1581
+ const providers = {};
1582
+ for (const name of capabilities) {
1583
+ const capabilityProvider = allProviders[name];
1584
+ if (capabilityProvider)
1585
+ providers[name] = capabilityProvider;
1586
+ }
1587
+ return {
1588
+ capabilities,
1589
+ providers,
1590
+ requiredPackages: [
1591
+ ...new Set(capabilities.flatMap((name) => providers[name]?.packages ?? []))
1592
+ ].sort()
1593
+ };
1594
+ };
1595
+ var init_deviceCapabilities = __esm(() => {
1596
+ ADAPTERS = {
1597
+ capacitor: "@absolutejs/devices-capacitor",
1598
+ expo: "@absolutejs/devices-expo"
1599
+ };
1600
+ SOURCE_GLOB = new Bun.Glob("**/*.{js,jsx,ts,tsx,svelte,vue}");
1601
+ IGNORED_DIRECTORIES = new Set([
1602
+ ".absolutejs",
1603
+ ".git",
1604
+ ".test-builds",
1605
+ ".test-shards",
1606
+ "build",
1607
+ "dist",
1608
+ "node_modules",
1609
+ "test",
1610
+ "tests"
1611
+ ]);
1612
+ IDENTIFIER_PATTERN = /^[A-Za-z_$][\w$]*$/u;
1613
+ ANDROID_PERMISSION_PATTERN = /^android\.permission\.[A-Z][A-Z0-9_]*$/u;
1614
+ IOS_USAGE_DESCRIPTIONS = new Set([
1615
+ "camera",
1616
+ "location-always",
1617
+ "location-when-in-use",
1618
+ "photo-library",
1619
+ "photo-library-add"
1620
+ ]);
1621
+ IOS_PRIVACY_ACCESSED_API_REASONS = {
1622
+ NSPrivacyAccessedAPICategoryFileTimestamp: new Set(["C617.1"])
1623
+ };
1624
+ IOS_PRIVACY_ACCESSED_APIS = [
1625
+ "NSPrivacyAccessedAPICategoryFileTimestamp"
1626
+ ];
1627
+ });
1628
+
1317
1629
  // src/mobile/expoProject.ts
1318
1630
  import {
1319
1631
  access,
@@ -1327,7 +1639,7 @@ import {
1327
1639
  writeFile
1328
1640
  } from "fs/promises";
1329
1641
  import { createHash } from "crypto";
1330
- import { basename as basename2, dirname as dirname4, join as join7, relative, resolve as resolve4 } from "path";
1642
+ import { basename as basename2, dirname as dirname4, join as join8, relative as relative2, resolve as resolve5, sep } from "path";
1331
1643
  var EXPO_GENERATED_HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.
1332
1644
  `, EXPO_ASSET_EXTENSION = ".absasset", EXPO_PROJECT_MARKER = ".absolutejs-expo-project", exists = async (path) => {
1333
1645
  try {
@@ -1337,17 +1649,27 @@ var EXPO_GENERATED_HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts
1337
1649
  return false;
1338
1650
  }
1339
1651
  }, portableRelative = (from, destination) => {
1340
- const value = relative(from, destination).replaceAll("\\", "/");
1652
+ const value = relative2(from, destination).replaceAll("\\", "/");
1341
1653
  return value.startsWith(".") ? value : `./${value}`;
1342
- }, routeSegments = (route) => route.split("/").filter(Boolean).map((segment) => {
1343
- if (segment.startsWith(":"))
1344
- return `[${segment.slice(1)}]`;
1345
- if (segment === "." || segment === ".." || !/^[A-Za-z0-9._~-]+$/u.test(segment)) {
1346
- throw new TypeError(`Expo native route ${route} contains an unsupported segment ${segment}.`);
1347
- }
1348
- return segment;
1349
- }), routeFile = (project, route) => join7(project, "app", ...routeSegments(route), "index.tsx"), expoPackage = (auth, sync) => ({
1654
+ }, routeSegments = (route) => {
1655
+ const segments = route.split("/").filter(Boolean);
1656
+ return segments.map((segment, index) => {
1657
+ if (segment.startsWith(":"))
1658
+ return `[${segment.slice(1)}]`;
1659
+ if (segment === "*" && index === segments.length - 1)
1660
+ return "[...absoluteWildcard]";
1661
+ if (segment === "." || segment === ".." || !/^[A-Za-z0-9._~-]+$/u.test(segment)) {
1662
+ throw new TypeError(`Expo native route ${route} contains an unsupported segment ${segment}.`);
1663
+ }
1664
+ return segment;
1665
+ });
1666
+ }, routeFile = (project, route) => join8(project, "app", ...routeSegments(route), "index.tsx"), packageDependencies = (plan) => Object.fromEntries(plan.requiredPackages.map((spec) => {
1667
+ const separator = spec.lastIndexOf("@");
1668
+ return [spec.slice(0, separator), spec.slice(separator + 1)];
1669
+ })), expoPackage = (auth, sync, devices) => ({
1350
1670
  dependencies: {
1671
+ "@absolutejs/devices": "0.7.0",
1672
+ "@absolutejs/devices-expo": "0.0.2",
1351
1673
  ...auth ? {
1352
1674
  "@absolutejs/auth": ABSOLUTE_EXPO_AUTH_CORE_VERSION,
1353
1675
  [ABSOLUTE_EXPO_AUTH_PACKAGE]: ABSOLUTE_EXPO_AUTH_VERSION
@@ -1379,7 +1701,8 @@ var EXPO_GENERATED_HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts
1379
1701
  "react-native": "0.86.3",
1380
1702
  "react-native-safe-area-context": "~5.7.0",
1381
1703
  "react-native-screens": "4.26.0",
1382
- "react-native-webview": "13.16.1"
1704
+ "react-native-webview": "13.16.1",
1705
+ ...packageDependencies(devices)
1383
1706
  },
1384
1707
  devDependencies: {
1385
1708
  "@types/react": "~19.2.2",
@@ -1394,36 +1717,107 @@ var EXPO_GENERATED_HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts
1394
1717
  start: "expo start --dev-client"
1395
1718
  },
1396
1719
  version: "0.0.0"
1397
- }), expoAppConfig = (config, auth, sync) => ({
1398
- expo: {
1399
- android: {
1400
- intentFilters: config.deepLinkHosts.map((host2) => ({
1401
- action: "VIEW",
1402
- autoVerify: true,
1403
- category: ["BROWSABLE", "DEFAULT"],
1404
- data: [{ host: host2, pathPrefix: "/", scheme: "https" }]
1405
- })),
1406
- package: config.appId
1407
- },
1408
- experiments: { typedRoutes: true },
1409
- ios: {
1410
- associatedDomains: config.deepLinkHosts.map((host2) => `applinks:${host2}`),
1411
- bundleIdentifier: config.appId,
1412
- ...config.iosVersion ? { buildNumber: config.iosVersion } : {}
1413
- },
1414
- name: config.appName,
1415
- plugins: [
1416
- "expo-router",
1417
- ["expo-dev-client", { launchMode: "most-recent" }],
1418
- ...auth ? ["expo-secure-store"] : [],
1419
- ...sync ? ["expo-sqlite", "expo-background-task", "expo-task-manager"] : []
1420
- ],
1421
- runtimeVersion: { policy: "appVersion" },
1422
- scheme: config.deepLinkScheme,
1423
- slug: config.appId.toLowerCase().replaceAll(".", "-"),
1424
- version: config.iosVersion ?? "0.1.0"
1425
- }
1426
- }), expoDynamicAppConfig, expoDevelopmentCaPlugin, metroConfig = (projectRoot) => `${EXPO_GENERATED_HEADER}const { getDefaultConfig } = require('expo/metro-config');
1720
+ }), expoAppConfig = (config, auth, sync, devices) => {
1721
+ const requirements = absoluteDeviceNativeRequirements(devices);
1722
+ const usageKey = (purpose) => {
1723
+ if (purpose === "camera")
1724
+ return "NSCameraUsageDescription";
1725
+ if (purpose === "photo-library")
1726
+ return "NSPhotoLibraryUsageDescription";
1727
+ if (purpose === "photo-library-add")
1728
+ return "NSPhotoLibraryAddUsageDescription";
1729
+ if (purpose === "location-always")
1730
+ return "NSLocationAlwaysAndWhenInUseUsageDescription";
1731
+ return "NSLocationWhenInUseUsageDescription";
1732
+ };
1733
+ const usageDescription = (purpose) => {
1734
+ if (purpose === "camera")
1735
+ return `${config.appName} uses your camera when you choose to take a photo.`;
1736
+ if (purpose === "photo-library")
1737
+ return `${config.appName} accesses your photo library only for photo actions you choose.`;
1738
+ if (purpose.startsWith("location-"))
1739
+ return `${config.appName} uses your location only while you use the app and request a location-based action.`;
1740
+ return `${config.appName} adds to your photo library only for photo actions you choose.`;
1741
+ };
1742
+ const descriptions = Object.fromEntries(requirements.iosUsageDescriptions.map((purpose) => [
1743
+ usageKey(purpose),
1744
+ usageDescription(purpose)
1745
+ ]));
1746
+ const devicePlugins = [
1747
+ ...new Set(devices.capabilities.flatMap((name) => devices.providers[name]?.plugins ?? []))
1748
+ ];
1749
+ const configuredPlugins = devicePlugins.map((plugin) => {
1750
+ if (plugin === "expo-image-picker")
1751
+ return [
1752
+ plugin,
1753
+ {
1754
+ cameraPermission: descriptions.NSCameraUsageDescription,
1755
+ microphonePermission: false,
1756
+ photosPermission: descriptions.NSPhotoLibraryUsageDescription
1757
+ }
1758
+ ];
1759
+ if (plugin === "expo-location")
1760
+ return [
1761
+ plugin,
1762
+ {
1763
+ locationWhenInUsePermission: descriptions.NSLocationWhenInUseUsageDescription
1764
+ }
1765
+ ];
1766
+ return plugin;
1767
+ });
1768
+ return {
1769
+ expo: {
1770
+ android: {
1771
+ ...devicePlugins.includes("expo-image-picker") ? {
1772
+ blockedPermissions: [
1773
+ "android.permission.READ_EXTERNAL_STORAGE",
1774
+ "android.permission.RECORD_AUDIO",
1775
+ "android.permission.WRITE_EXTERNAL_STORAGE"
1776
+ ]
1777
+ } : {},
1778
+ intentFilters: config.deepLinkHosts.map((host2) => ({
1779
+ action: "VIEW",
1780
+ autoVerify: true,
1781
+ category: ["BROWSABLE", "DEFAULT"],
1782
+ data: [{ host: host2, pathPrefix: "/", scheme: "https" }]
1783
+ })),
1784
+ package: config.appId,
1785
+ permissions: requirements.androidPermissions
1786
+ },
1787
+ experiments: { typedRoutes: true },
1788
+ ios: {
1789
+ associatedDomains: config.deepLinkHosts.map((host2) => `applinks:${host2}`),
1790
+ bundleIdentifier: config.appId,
1791
+ infoPlist: descriptions,
1792
+ ...requirements.iosPrivacyAccessedApis.length > 0 ? {
1793
+ privacyManifests: {
1794
+ NSPrivacyAccessedAPITypes: requirements.iosPrivacyAccessedApis.map(({ api, reasons }) => ({
1795
+ NSPrivacyAccessedAPIType: api,
1796
+ NSPrivacyAccessedAPITypeReasons: reasons
1797
+ }))
1798
+ }
1799
+ } : {},
1800
+ ...config.iosVersion ? { buildNumber: config.iosVersion } : {}
1801
+ },
1802
+ name: config.appName,
1803
+ plugins: [
1804
+ "expo-router",
1805
+ ["expo-dev-client", { launchMode: "most-recent" }],
1806
+ ...auth ? ["expo-secure-store"] : [],
1807
+ ...sync ? [
1808
+ "expo-sqlite",
1809
+ "expo-background-task",
1810
+ "expo-task-manager"
1811
+ ] : [],
1812
+ ...configuredPlugins
1813
+ ],
1814
+ runtimeVersion: { policy: "appVersion" },
1815
+ scheme: config.deepLinkScheme,
1816
+ slug: config.appId.toLowerCase().replaceAll(".", "-"),
1817
+ version: config.iosVersion ?? "0.1.0"
1818
+ }
1819
+ };
1820
+ }, expoDynamicAppConfig, expoDevelopmentCaPlugin, metroConfig = (projectRoot) => `${EXPO_GENERATED_HEADER}const { getDefaultConfig } = require('expo/metro-config');
1427
1821
  const path = require('node:path');
1428
1822
 
1429
1823
  const projectRoot = __dirname;
@@ -1438,6 +1832,7 @@ config.watchFolders = [appRoot];
1438
1832
 
1439
1833
  module.exports = config;
1440
1834
  `, layoutSource = (auth, sync) => `${EXPO_GENERATED_HEADER}import { Stack } from 'expo-router';
1835
+ import '../src/generated/AbsoluteDevices';
1441
1836
  ${auth ? `import { useEffect, useState } from 'react';
1442
1837
  import { startAbsoluteExpoAuth } from '../src/generated/AbsoluteAuth';` : ""}
1443
1838
  ${sync ? "import { startAbsoluteExpoSync } from '../src/generated/AbsoluteSync';" : ""}
@@ -1452,7 +1847,76 @@ export default function AbsoluteLayout() {
1452
1847
  if (!ready) return null;` : ""}
1453
1848
  return <Stack screenOptions={{ headerShown: false }} />;
1454
1849
  }
1455
- `, nativeDiagnosticSource, authRuntimeSource = (auth, appId) => {
1850
+ `, nativeDiagnosticSource, devicesRuntimeSource = (config, plan, auth) => {
1851
+ const imports = plan.capabilities.map((name, index) => {
1852
+ const provider = plan.providers[name];
1853
+ if (!provider)
1854
+ throw new TypeError(`Missing Expo device capability provider ${name}.`);
1855
+ return `import { ${provider.factory} as absoluteExpoCapability${index} } from ${JSON.stringify(provider.module)};`;
1856
+ });
1857
+ const pushIndex = plan.capabilities.indexOf("pushNotifications");
1858
+ const push = pushIndex !== -1;
1859
+ if (push && !auth)
1860
+ throw new TypeError("Expo push notifications require the provisioned AbsoluteJS Auth runtime.");
1861
+ const entries = plan.capabilities.map((name, index) => `${JSON.stringify(name)}: absoluteExpoCapability${index}(${name === "pushNotifications" ? "absoluteExpoPushOptions" : ""})`).join(`,
1862
+ `);
1863
+ const pushSource = push ? `const INSTALLATION_KEY = 'absolutejs.push.installation-id';
1864
+ const requirePushResponse = async (response: Response, operation: string) => {
1865
+ if (!response.ok) throw new Error(\`AbsoluteJS native push \${operation} failed with HTTP \${response.status}.\`);
1866
+ return response.json() as Promise<Record<string, unknown>>;
1867
+ };
1868
+ const absoluteExpoPushOptions = {
1869
+ onRegistration: async (registration: { platform: 'apns' | 'fcm'; token: string }) => {
1870
+ const known = await absoluteExpoDevices.storage.get(INSTALLATION_KEY);
1871
+ const register = (installationId?: string | null) => absoluteExpoAuth.fetch('/auth/push', {
1872
+ body: JSON.stringify({ ...(installationId ? { installationId } : {}), platform: registration.platform, token: registration.token }),
1873
+ headers: { 'content-type': 'application/json' },
1874
+ method: 'POST'
1875
+ });
1876
+ let response = await register(known);
1877
+ const conflict = response.status === 409 && await response.clone().json().then(value => typeof value === 'object' && value !== null && Reflect.get(value, 'code') === 'installation-ownership').catch(() => false);
1878
+ if (known && conflict) {
1879
+ await absoluteExpoDevices.storage.remove(INSTALLATION_KEY);
1880
+ response = await register();
1881
+ }
1882
+ const result = await requirePushResponse(response, 'registration');
1883
+ if (typeof result.installationId !== 'string' || !result.installationId || result.installationId.length > 128) throw new Error('AbsoluteJS native push returned an invalid installation identity.');
1884
+ await absoluteExpoDevices.storage.set(INSTALLATION_KEY, result.installationId);
1885
+ },
1886
+ onUnregistration: async () => {
1887
+ const installationId = await absoluteExpoDevices.storage.get(INSTALLATION_KEY);
1888
+ if (!installationId) return;
1889
+ await requirePushResponse(await absoluteExpoAuth.fetch('/auth/push', {
1890
+ body: JSON.stringify({ installationId }),
1891
+ headers: { 'content-type': 'application/json' },
1892
+ method: 'DELETE'
1893
+ }), 'removal');
1894
+ await absoluteExpoDevices.storage.remove(INSTALLATION_KEY);
1895
+ }
1896
+ };` : "";
1897
+ return `${EXPO_GENERATED_HEADER}import { installDeviceAdapter } from '@absolutejs/devices/runtime';
1898
+ import { createExpoDeviceAdapter } from '@absolutejs/devices-expo';
1899
+ ${push ? "import { absoluteExpoAuth } from './AbsoluteAuth';" : ""}
1900
+ ${imports.join(`
1901
+ `)}
1902
+
1903
+ ${pushSource}
1904
+
1905
+ export const absoluteExpoDeviceCapabilities = ${JSON.stringify(plan.capabilities)} as const;
1906
+ export const absoluteExpoDevices = createExpoDeviceAdapter({
1907
+ storagePrefix: ${JSON.stringify(`absolutejs.${config.appId}.`)},
1908
+ ${entries}
1909
+ });
1910
+ installDeviceAdapter(absoluteExpoDevices);
1911
+ export const beforeAbsoluteExpoDeviceSignOut = async () => {
1912
+ ${push ? "await absoluteExpoDevices.pushNotifications?.disable();" : ""}
1913
+ };
1914
+ ${push ? `absoluteExpoAuth.onPrincipalChange(principal => {
1915
+ if (!principal) return;
1916
+ void absoluteExpoDevices.pushNotifications?.queryPermission().then(permission => permission.state === 'granted' ? absoluteExpoDevices.pushNotifications?.enable() : undefined).catch(() => undefined);
1917
+ });` : ""}
1918
+ `;
1919
+ }, authRuntimeSource = (auth, appId) => {
1456
1920
  const storageIdentity = createHash("sha256").update(appId).digest("hex").slice(0, 24);
1457
1921
  return `${EXPO_GENERATED_HEADER}import { createAbsoluteExpoAuthClient } from '@absolutejs/auth-expo';
1458
1922
  import { createMobileAuthTransport, installAuthClientRuntimeTransport } from '@absolutejs/auth/client/mobile';
@@ -1585,20 +2049,22 @@ export const createAbsoluteExpoSyncBridge = async (
1585
2049
  "/__absolute/native",
1586
2050
  ...Object.keys(config.expoNativeRoutes)
1587
2051
  ];
1588
- return `${EXPO_GENERATED_HEADER}import * as Haptics from 'expo-haptics';
1589
- import * as Linking from 'expo-linking';
2052
+ const nativeRoutePatterns = nativeRoutes.map((route) => route.split("/").filter(Boolean));
2053
+ return `${EXPO_GENERATED_HEADER}import * as Linking from 'expo-linking';
1590
2054
  import { router, usePathname } from 'expo-router';
1591
2055
  import { useEffect, useRef, useState } from 'react';
1592
2056
  import { ActivityIndicator, BackHandler, Platform, StyleSheet, View } from 'react-native';
1593
2057
  import { WebView, type WebViewMessageEvent } from 'react-native-webview';
1594
2058
  import { materializeAbsoluteWebBundle } from './webAssets';
2059
+ import { createExpoDevicesBridgeHost } from '@absolutejs/devices-expo/bridge';
2060
+ import { absoluteExpoDevices, beforeAbsoluteExpoDeviceSignOut } from './AbsoluteDevices';
1595
2061
  ${auth ? "import { absoluteExpoAuth, getAbsoluteExpoAuthPrincipal, startAbsoluteExpoAuth } from './AbsoluteAuth';" : ""}
1596
2062
  ${sync ? "import { createAbsoluteExpoSyncBridge, startAbsoluteExpoSync } from './AbsoluteSync';" : ""}
1597
2063
 
1598
2064
  const BRIDGE_FORMAT = 3;
1599
2065
  const MAX_MESSAGE_BYTES = 64 * 1024;
1600
2066
  const MAX_HTTP_BODY_BYTES = 48 * 1024;
1601
- const NATIVE_ROUTES = new Set(${JSON.stringify(nativeRoutes)});
2067
+ const NATIVE_ROUTE_PATTERNS = ${JSON.stringify(nativeRoutePatterns)};
1602
2068
  const PRODUCTION_ORIGIN = ${JSON.stringify(config.productionOrigin)};
1603
2069
  const DEV_ORIGIN = Platform.OS === 'android'
1604
2070
  ? process.env.EXPO_PUBLIC_ABSOLUTE_DEV_ANDROID_ORIGIN
@@ -1607,6 +2073,19 @@ const HMR_TARGET = Platform.OS === 'android' ? 'expo-android' : 'expo-ios';
1607
2073
  const AUTH_ENABLED = ${auth ? "true" : "false"};
1608
2074
  const SYNC_ENABLED = ${sync ? "true" : "false"};
1609
2075
 
2076
+ const isNativeRoute = (pathname: string) => {
2077
+ const segments = pathname.split('/').filter(Boolean);
2078
+ return NATIVE_ROUTE_PATTERNS.some(pattern => {
2079
+ for (let index = 0; index < pattern.length; index += 1) {
2080
+ const expected = pattern[index]!;
2081
+ if (expected === '*') return segments.length > index;
2082
+ if (segments[index] === undefined) return false;
2083
+ if (!expected.startsWith(':') && expected !== segments[index]) return false;
2084
+ }
2085
+ return segments.length === pattern.length;
2086
+ });
2087
+ };
2088
+
1610
2089
  const bridgeBootstrap = (path: string) => {
1611
2090
  const initialPath = DEV_ORIGIN
1612
2091
  ? 'location.pathname + location.search + location.hash'
@@ -1647,10 +2126,11 @@ const bridgeBootstrap = (path: string) => {
1647
2126
  const id = 'web_' + Date.now().toString(36) + '_' + (++sequence).toString(36);
1648
2127
  send({ format: 3, id, kind: 'request', method, params, path: currentPath });
1649
2128
  return new Promise((resolve, reject) => {
2129
+ const interactive = method.startsWith('devices.camera.') || method.startsWith('devices.photos.') || method.startsWith('devices.documents.') || method.endsWith('.requestPermission');
1650
2130
  const timer = setTimeout(() => {
1651
2131
  pending.delete(id);
1652
2132
  reject(new Error('Expo bridge request timed out.'));
1653
- }, 10000);
2133
+ }, interactive ? 5 * 60 * 1000 : 30 * 1000);
1654
2134
  pending.set(id, { reject, resolve, timer });
1655
2135
  });
1656
2136
  },
@@ -1681,7 +2161,7 @@ const bridgeBootstrap = (path: string) => {
1681
2161
  const anchor = event.target instanceof Element ? event.target.closest('a[href]') : null;
1682
2162
  if (!anchor) return;
1683
2163
  const url = new URL(anchor.href, location.href);
1684
- if (!${JSON.stringify(nativeRoutes)}.includes(url.pathname)) return;
2164
+ if (!isNativeRoute(url.pathname)) return;
1685
2165
  event.preventDefault();
1686
2166
  send({ format: 3, kind: 'event', event: 'navigation', path: url.pathname + url.search + url.hash });
1687
2167
  }, true);
@@ -1689,17 +2169,6 @@ const bridgeBootstrap = (path: string) => {
1689
2169
  })(); true;\`;
1690
2170
  };
1691
2171
 
1692
- const impact = async (params: Record<string, unknown>) => {
1693
- const style = params.style;
1694
- if (style === 'selection') return Haptics.selectionAsync();
1695
- if (style === 'success' || style === 'warning' || style === 'error') {
1696
- const value = style === 'success' ? Haptics.NotificationFeedbackType.Success : style === 'warning' ? Haptics.NotificationFeedbackType.Warning : Haptics.NotificationFeedbackType.Error;
1697
- return Haptics.notificationAsync(value);
1698
- }
1699
- const value = style === 'light' ? Haptics.ImpactFeedbackStyle.Light : style === 'heavy' ? Haptics.ImpactFeedbackStyle.Heavy : Haptics.ImpactFeedbackStyle.Medium;
1700
- return Haptics.impactAsync(value);
1701
- };
1702
-
1703
2172
  const bridgeFetch = async (params: Record<string, unknown>) => {
1704
2173
  if (typeof params.method !== 'string' || !['DELETE', 'GET', 'PATCH', 'POST', 'PUT'].includes(params.method) || typeof params.url !== 'string' || typeof params.headers !== 'object' || params.headers === null || Array.isArray(params.headers) || params.body !== undefined && typeof params.body !== 'string') throw new Error('Expo bridge HTTP request is invalid.');
1705
2174
  const url = new URL(params.url);
@@ -1731,10 +2200,12 @@ const authStatus = async () => {
1731
2200
  export function AbsoluteWebHost() {
1732
2201
  const pathname = usePathname() || '/';
1733
2202
  const webView = useRef<WebView>(null);
2203
+ const devicesBridge = useRef<{ close(): void | Promise<void>; request(method: string, params: Record<string, unknown>): Promise<unknown> } | undefined>(undefined);
1734
2204
  const syncBridge = useRef<{ close(): void | Promise<void>; request(method: string, params: Record<string, unknown>): Promise<unknown> } | undefined>(undefined);
1735
2205
  const [indexUri, setIndexUri] = useState<string>();
1736
2206
  const [canGoBack, setCanGoBack] = useState(false);
1737
2207
  const [runtimeReady, setRuntimeReady] = useState(!AUTH_ENABLED && !SYNC_ENABLED);
2208
+ const [devicesReady, setDevicesReady] = useState(false);
1738
2209
  const activeWebPath = useRef(pathname);
1739
2210
 
1740
2211
  useEffect(() => {
@@ -1784,6 +2255,23 @@ export function AbsoluteWebHost() {
1784
2255
  if (new TextEncoder().encode(source).byteLength > MAX_MESSAGE_BYTES) throw new Error('Expo bridge response exceeds 64 KiB.');
1785
2256
  webView.current?.injectJavaScript(\`globalThis.__absoluteExpoReceive(\${JSON.stringify(source)}); true;\`);
1786
2257
  };
2258
+ useEffect(() => {
2259
+ let active = true;
2260
+ void createExpoDevicesBridgeHost(absoluteExpoDevices, (event, payload) => {
2261
+ if (!active) return;
2262
+ respond({ event, format: BRIDGE_FORMAT, kind: 'event', path: activeWebPath.current, payload });
2263
+ }).then(host => {
2264
+ if (!active) return void host.close();
2265
+ devicesBridge.current = host;
2266
+ setDevicesReady(true);
2267
+ });
2268
+ return () => {
2269
+ active = false;
2270
+ const host = devicesBridge.current;
2271
+ devicesBridge.current = undefined;
2272
+ void host?.close();
2273
+ };
2274
+ }, []);
1787
2275
  const hasOrigin = (source: string, origin: string) => {
1788
2276
  try { return new URL(source).origin === origin; } catch { return false; }
1789
2277
  };
@@ -1796,18 +2284,16 @@ export function AbsoluteWebHost() {
1796
2284
  if (message.kind === 'event' && (message.event === 'navigation' || message.event === 'ready')) {
1797
2285
  const target = new URL(message.path, PRODUCTION_ORIGIN);
1798
2286
  if (target.origin !== PRODUCTION_ORIGIN) return;
1799
- if (NATIVE_ROUTES.has(target.pathname)) router.push(message.path as never);
2287
+ if (isNativeRoute(target.pathname)) router.push(message.path as never);
1800
2288
  else activeWebPath.current = message.path;
1801
2289
  return;
1802
2290
  }
1803
2291
  if (message.kind !== 'request' || typeof message.id !== 'string' || message.path !== activeWebPath.current) return;
1804
2292
  try {
1805
2293
  if (typeof message.params !== 'object' || message.params === null || Array.isArray(message.params)) throw new Error('Expo bridge method params are invalid.');
1806
- if (message.method === 'devices.haptics.impact') {
1807
- const style = (message.params as Record<string, unknown>).style;
1808
- if (typeof style !== 'string' || !['error', 'heavy', 'light', 'medium', 'selection', 'success', 'vibrate', 'warning'].includes(style)) throw new Error('Expo bridge haptics style is invalid.');
1809
- await impact(message.params as Record<string, unknown>);
1810
- respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: null });
2294
+ if (typeof message.method === 'string' && message.method.startsWith('devices.')) {
2295
+ if (!devicesBridge.current) throw new Error('Expo devices bridge is unavailable.');
2296
+ respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: await devicesBridge.current.request(message.method, message.params as Record<string, unknown>) });
1811
2297
  } else if (message.method === 'http.fetch') {
1812
2298
  respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: await bridgeFetch(message.params as Record<string, unknown>) });
1813
2299
  } else if (message.method === 'auth.signIn') {
@@ -1816,7 +2302,8 @@ export function AbsoluteWebHost() {
1816
2302
  await absoluteExpoAuth.signIn({ authorizationParameters: { login_hint: params.email, ...(params.signup ? { screen_hint: 'signup' } : {}) } });
1817
2303
  respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: await authStatus() });` : "throw new Error('Expo Auth is not configured.');"}
1818
2304
  } else if (message.method === 'auth.signOut') {
1819
- ${auth ? `await absoluteExpoAuth.signOut();
2305
+ ${auth ? `await beforeAbsoluteExpoDeviceSignOut();
2306
+ await absoluteExpoAuth.signOut();
1820
2307
  respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: null });` : "throw new Error('Expo Auth is not configured.');"}
1821
2308
  } else if (message.method === 'auth.status') {
1822
2309
  respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: await authStatus() });
@@ -1831,7 +2318,7 @@ export function AbsoluteWebHost() {
1831
2318
  }
1832
2319
  };
1833
2320
 
1834
- if (!indexUri || !runtimeReady) return <View style={styles.loading}><ActivityIndicator /></View>;
2321
+ if (!indexUri || !runtimeReady || !devicesReady) return <View style={styles.loading}><ActivityIndicator /></View>;
1835
2322
  return <WebView
1836
2323
  allowFileAccess
1837
2324
  allowFileAccessFromFileURLs
@@ -1903,13 +2390,25 @@ const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, jus
1903
2390
  await writeFile(temporary, source, { flag: "wx" });
1904
2391
  await rename(temporary, path);
1905
2392
  return true;
2393
+ }, pruneStaleManagedExpoRoutes = async (project, expected) => {
2394
+ const appDirectory = join8(project, "app");
2395
+ if (!await exists(appDirectory))
2396
+ return 0;
2397
+ const files = await walkFiles(appDirectory);
2398
+ const stale = (await Promise.all(files.map(async (path) => ({
2399
+ managed: path.endsWith(".tsx") && (await readFile(path, "utf8")).startsWith(EXPO_GENERATED_HEADER),
2400
+ path
2401
+ })))).filter(({ managed, path }) => managed && !expected.has(path));
2402
+ await Promise.all(stale.map(({ path }) => rm(path, { force: true })));
2403
+ return stale.length;
1906
2404
  }, jsonSource = (value) => `${JSON.stringify(value, null, "\t")}
1907
2405
  `, emptyWebAssetsSource, writeAbsoluteExpoProject = async (config, options) => {
1908
2406
  if (config.engine !== "expo")
1909
2407
  throw new TypeError("Expo project generation requires mobile.engine: expo.");
1910
- const projectRoot = resolve4(options.projectRoot);
2408
+ const projectRoot = resolve5(options.projectRoot);
1911
2409
  const project = config.nativeProjectDirectory;
1912
2410
  const auth = resolveAbsoluteMobileAuthManifest(projectRoot, config);
2411
+ const devices = resolveAbsoluteDeviceCapabilityPlan(projectRoot, "expo");
1913
2412
  const syncEnabled = Boolean(auth && projectUsesAbsoluteSync(projectRoot));
1914
2413
  const syncSchema = syncEnabled ? { components: discoverAbsoluteSyncSchema(projectRoot).components } : undefined;
1915
2414
  const routeModules = Object.entries(config.expoNativeRoutes);
@@ -1922,7 +2421,7 @@ const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, jus
1922
2421
  if (missing) {
1923
2422
  throw new TypeError(`Expo native route ${missing.route} references missing module ${missing.module}.`);
1924
2423
  }
1925
- const marker = join7(project, EXPO_PROJECT_MARKER);
2424
+ const marker = join8(project, EXPO_PROJECT_MARKER);
1926
2425
  if (await exists(project) && !await exists(marker)) {
1927
2426
  const entries = await readdir(project);
1928
2427
  if (entries.length > 0 && !options.force) {
@@ -1935,7 +2434,7 @@ const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, jus
1935
2434
  const authEnabled = Boolean(auth);
1936
2435
  const files = new Map([
1937
2436
  [
1938
- join7(project, ".gitignore"),
2437
+ join8(project, ".gitignore"),
1939
2438
  `.expo/
1940
2439
  android/
1941
2440
  ios/
@@ -1943,61 +2442,66 @@ node_modules/
1943
2442
  `
1944
2443
  ],
1945
2444
  [
1946
- join7(project, "app.json"),
1947
- jsonSource(expoAppConfig(config, authEnabled, syncEnabled))
2445
+ join8(project, "app.json"),
2446
+ jsonSource(expoAppConfig(config, authEnabled, syncEnabled, devices))
1948
2447
  ],
1949
- [join7(project, "app.config.js"), expoDynamicAppConfig],
2448
+ [join8(project, "app.config.js"), expoDynamicAppConfig],
1950
2449
  [
1951
- join7(project, "package.json"),
1952
- jsonSource(expoPackage(authEnabled, syncEnabled))
2450
+ join8(project, "package.json"),
2451
+ jsonSource(expoPackage(authEnabled, syncEnabled, devices))
1953
2452
  ],
1954
- [join7(project, "metro.config.js"), metroConfig(projectRoot)],
2453
+ [join8(project, "metro.config.js"), metroConfig(projectRoot)],
1955
2454
  [
1956
- join7(project, "plugins", "withAbsoluteDevelopmentCa.js"),
2455
+ join8(project, "plugins", "withAbsoluteDevelopmentCa.js"),
1957
2456
  expoDevelopmentCaPlugin
1958
2457
  ],
1959
2458
  [
1960
- join7(project, "tsconfig.json"),
2459
+ join8(project, "tsconfig.json"),
1961
2460
  jsonSource(expoTsConfig(projectRoot, project, authEnabled, syncEnabled))
1962
2461
  ],
1963
2462
  [
1964
- join7(project, "app", "_layout.tsx"),
2463
+ join8(project, "app", "_layout.tsx"),
1965
2464
  layoutSource(authEnabled, syncEnabled)
1966
2465
  ],
1967
2466
  [
1968
- join7(project, "app", "__absolute", "native", "index.tsx"),
2467
+ join8(project, "app", "__absolute", "native", "index.tsx"),
1969
2468
  nativeDiagnosticSource
1970
2469
  ],
1971
2470
  [
1972
- join7(project, "src", "generated", "AbsoluteWebHost.tsx"),
2471
+ join8(project, "src", "generated", "AbsoluteDevices.ts"),
2472
+ devicesRuntimeSource(config, devices, authEnabled)
2473
+ ],
2474
+ [
2475
+ join8(project, "src", "generated", "AbsoluteWebHost.tsx"),
1973
2476
  webHostSource(config, auth, syncEnabled)
1974
2477
  ]
1975
2478
  ]);
1976
2479
  if (auth) {
1977
- files.set(join7(project, "src", "generated", "AbsoluteAuth.ts"), authRuntimeSource(auth, config.appId));
2480
+ files.set(join8(project, "src", "generated", "AbsoluteAuth.ts"), authRuntimeSource(auth, config.appId));
1978
2481
  }
1979
2482
  if (syncSchema) {
1980
- files.set(join7(project, "src", "generated", "AbsoluteSync.ts"), syncRuntimeSource(config, syncSchema));
2483
+ files.set(join8(project, "src", "generated", "AbsoluteSync.ts"), syncRuntimeSource(config, syncSchema));
1981
2484
  }
1982
- const webAssetsPath = join7(project, "src", "generated", "webAssets.ts");
2485
+ const webAssetsPath = join8(project, "src", "generated", "webAssets.ts");
1983
2486
  if (!await exists(webAssetsPath)) {
1984
2487
  files.set(webAssetsPath, emptyWebAssetsSource);
1985
2488
  }
1986
2489
  if (!config.expoNativeRoutes["/"]) {
1987
- files.set(join7(project, "app", "index.tsx"), webRouteSource);
2490
+ files.set(join8(project, "app", "index.tsx"), webRouteSource);
1988
2491
  }
1989
- files.set(join7(project, "app", "[...absolute].tsx"), catchAllRouteSource);
2492
+ files.set(join8(project, "app", "[...absolute].tsx"), catchAllRouteSource);
1990
2493
  for (const [route, module] of routeModules) {
1991
- const wrapper = route === "/" ? join7(project, "app", "index.tsx") : routeFile(project, route);
2494
+ const wrapper = route === "/" ? join8(project, "app", "index.tsx") : routeFile(project, route);
1992
2495
  files.set(wrapper, nativeWrapperSource(wrapper, module));
1993
2496
  }
2497
+ const removed = await pruneStaleManagedExpoRoutes(project, new Set([...files.keys()].filter((path) => path.startsWith(`${join8(project, "app")}${sep}`))));
1994
2498
  const changes = await Promise.all([...files].map(([path, source]) => writeManagedFile(path, source, true)));
1995
- const changed = changes.filter(Boolean).length;
2499
+ const changed = removed + changes.filter(Boolean).length;
1996
2500
  return { changed, path: project, written: [...files.keys()] };
1997
2501
  }, walkFiles = async (root, directory = root) => {
1998
2502
  const entries = await readdir(directory, { withFileTypes: true });
1999
2503
  const nested = await Promise.all(entries.map((entry) => {
2000
- const path = join7(directory, entry.name);
2504
+ const path = join8(directory, entry.name);
2001
2505
  if (entry.isDirectory())
2002
2506
  return walkFiles(root, path);
2003
2507
  if (entry.isFile())
@@ -2058,11 +2562,11 @@ export const materializeAbsoluteWebBundle = async () => {
2058
2562
  `, syncAbsoluteExpoWebAssets = async (config) => {
2059
2563
  if (config.engine !== "expo")
2060
2564
  throw new TypeError("Expo asset sync requires mobile.engine: expo.");
2061
- const marker = join7(config.nativeProjectDirectory, EXPO_PROJECT_MARKER);
2565
+ const marker = join8(config.nativeProjectDirectory, EXPO_PROJECT_MARKER);
2062
2566
  if (!await exists(marker)) {
2063
2567
  throw new TypeError("Expo asset sync requires an AbsoluteJS-managed Expo project. Run mobile init first.");
2064
2568
  }
2065
- const manifestPath = join7(config.bundleDirectory, "absolute-mobile-manifest.json");
2569
+ const manifestPath = join8(config.bundleDirectory, "absolute-mobile-manifest.json");
2066
2570
  const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
2067
2571
  const appBuild = typeof manifest === "object" && manifest !== null && typeof Reflect.get(manifest, "appBuild") === "string" ? String(Reflect.get(manifest, "appBuild")) : undefined;
2068
2572
  if (!appBuild)
@@ -2071,23 +2575,23 @@ export const materializeAbsoluteWebBundle = async () => {
2071
2575
  const bundleHash = createHash("sha256");
2072
2576
  const filesWithContents = await Promise.all(files.map(async (file) => ({ contents: await readFile(file), file })));
2073
2577
  filesWithContents.forEach(({ contents, file }) => {
2074
- bundleHash.update(relative(config.bundleDirectory, file).replaceAll("\\", "/"));
2578
+ bundleHash.update(relative2(config.bundleDirectory, file).replaceAll("\\", "/"));
2075
2579
  bundleHash.update("\x00");
2076
2580
  bundleHash.update(contents);
2077
2581
  bundleHash.update("\x00");
2078
2582
  });
2079
2583
  const bundleId = `amexpo_${bundleHash.digest("hex")}`;
2080
- const destination = join7(config.nativeProjectDirectory, "assets", "absolute");
2584
+ const destination = join8(config.nativeProjectDirectory, "assets", "absolute");
2081
2585
  await mkdir(dirname4(destination), { recursive: true });
2082
- const staging = await mkdtemp(join7(dirname4(destination), `.${basename2(destination)}.stage-`));
2586
+ const staging = await mkdtemp(join8(dirname4(destination), `.${basename2(destination)}.stage-`));
2083
2587
  let assets;
2084
2588
  try {
2085
2589
  assets = await Promise.all(files.map(async (source, index) => {
2086
2590
  const name = `${String(index).padStart(6, "0")}${EXPO_ASSET_EXTENSION}`;
2087
- await cp(source, join7(staging, name));
2591
+ await cp(source, join8(staging, name));
2088
2592
  return {
2089
- asset: portableRelative(join7(config.nativeProjectDirectory, "src", "generated"), join7(destination, name)),
2090
- path: relative(config.bundleDirectory, source).replaceAll("\\", "/")
2593
+ asset: portableRelative(join8(config.nativeProjectDirectory, "src", "generated"), join8(destination, name)),
2594
+ path: relative2(config.bundleDirectory, source).replaceAll("\\", "/")
2091
2595
  };
2092
2596
  }));
2093
2597
  await installStagedDirectory(staging, destination);
@@ -2095,13 +2599,14 @@ export const materializeAbsoluteWebBundle = async () => {
2095
2599
  await rm(staging, { force: true, recursive: true });
2096
2600
  throw error;
2097
2601
  }
2098
- const generated = join7(config.nativeProjectDirectory, "src", "generated", "webAssets.ts");
2602
+ const generated = join8(config.nativeProjectDirectory, "src", "generated", "webAssets.ts");
2099
2603
  await writeManagedFile(generated, assetModuleSource(assets, bundleId), true);
2100
2604
  return { appBuild, assets: assets.length, bundleId, path: destination };
2101
2605
  };
2102
2606
  var init_expoProject = __esm(() => {
2103
2607
  init_nativeAuth();
2104
2608
  init_syncSchema();
2609
+ init_deviceCapabilities();
2105
2610
  expoDynamicAppConfig = `${EXPO_GENERATED_HEADER}const config = require('./app.json');
2106
2611
 
2107
2612
  if (process.env.ABSOLUTE_EXPO_DEVELOPMENT === '1' && process.env.ABSOLUTE_EXPO_DEVELOPMENT_CA_PATH) {
@@ -2207,14 +2712,14 @@ import {
2207
2712
  isIP
2208
2713
  } from "net";
2209
2714
  import { readFile as readFile2 } from "fs/promises";
2210
- var closeServer = (server) => new Promise((resolve5, reject) => {
2715
+ var closeServer = (server) => new Promise((resolve6, reject) => {
2211
2716
  server.close((error) => {
2212
2717
  if (error)
2213
2718
  reject(error);
2214
2719
  else
2215
- resolve5();
2720
+ resolve6();
2216
2721
  });
2217
- }), listen = (server, port) => new Promise((resolve5, reject) => {
2722
+ }), listen = (server, port) => new Promise((resolve6, reject) => {
2218
2723
  server.once("error", reject);
2219
2724
  server.listen(port, "0.0.0.0", () => {
2220
2725
  server.off("error", reject);
@@ -2223,11 +2728,11 @@ var closeServer = (server) => new Promise((resolve5, reject) => {
2223
2728
  reject(new Error("Could not determine the iOS device helper port."));
2224
2729
  return;
2225
2730
  }
2226
- resolve5(address.port);
2731
+ resolve6(address.port);
2227
2732
  });
2228
2733
  }), findEphemeralPort = async () => {
2229
2734
  const probe = createTcpServer();
2230
- const port = await new Promise((resolve5, reject) => {
2735
+ const port = await new Promise((resolve6, reject) => {
2231
2736
  probe.once("error", reject);
2232
2737
  probe.listen(0, "127.0.0.1", () => {
2233
2738
  const address = probe.address();
@@ -2235,7 +2740,7 @@ var closeServer = (server) => new Promise((resolve5, reject) => {
2235
2740
  reject(new Error("Could not allocate the iOS CA enrollment port."));
2236
2741
  return;
2237
2742
  }
2238
- resolve5(address.port);
2743
+ resolve6(address.port);
2239
2744
  });
2240
2745
  });
2241
2746
  await closeServer(probe);
@@ -2292,12 +2797,12 @@ var init_iosPhysicalDeviceTransport = () => {};
2292
2797
  // src/cli/utils.ts
2293
2798
  var {$: $2 } = globalThis.Bun;
2294
2799
  import { execSync } from "child_process";
2295
- import { existsSync as existsSync3, readFileSync as readFileSync7 } from "fs";
2800
+ import { existsSync as existsSync4, readFileSync as readFileSync8 } from "fs";
2296
2801
  import { createServer as createServer3 } from "net";
2297
- import { resolve as resolve5 } from "path";
2802
+ import { resolve as resolve6 } from "path";
2298
2803
  var COMPOSE_PATH = "db/docker-compose.db.yml", DEFAULT_SERVER_ENTRY = "src/backend/server.ts", isWSLEnvironment = () => {
2299
2804
  try {
2300
- const release = readFileSync7("/proc/version", "utf-8");
2805
+ const release = readFileSync8("/proc/version", "utf-8");
2301
2806
  return /microsoft|wsl/i.test(release);
2302
2807
  } catch {
2303
2808
  return false;
@@ -2396,8 +2901,8 @@ var COMPOSE_PATH = "db/docker-compose.db.yml", DEFAULT_SERVER_ENTRY = "src/backe
2396
2901
  }, printHint = () => {
2397
2902
  console.log("\x1B[90mpress h + enter to show shortcuts\x1B[0m");
2398
2903
  }, readDbScripts = async () => {
2399
- const pkgPath = resolve5("package.json");
2400
- if (!existsSync3(pkgPath))
2904
+ const pkgPath = resolve6("package.json");
2905
+ if (!existsSync4(pkgPath))
2401
2906
  return null;
2402
2907
  const pkg = await Bun.file(pkgPath).json();
2403
2908
  const upCommand = pkg.scripts?.["db:up"];
@@ -2431,7 +2936,7 @@ var init_utils = __esm(() => {
2431
2936
  // src/mobile/emulatorDoctor.ts
2432
2937
  import { access as access3 } from "fs/promises";
2433
2938
  import { homedir as homedir3 } from "os";
2434
- import { join as join9 } from "path";
2939
+ import { join as join10 } from "path";
2435
2940
  var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command) => {
2436
2941
  try {
2437
2942
  const result = Bun.spawnSync(command, {
@@ -2476,15 +2981,15 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
2476
2981
  }
2477
2982
  }, absoluteManagedAndroidSdkRoot = (host2, env = process.env) => {
2478
2983
  if (host2 === "windows") {
2479
- return join9(env.LOCALAPPDATA ?? join9(homedir3(), "AppData", "Local"), "AbsoluteJS", "Android", "Sdk");
2984
+ return join10(env.LOCALAPPDATA ?? join10(homedir3(), "AppData", "Local"), "AbsoluteJS", "Android", "Sdk");
2480
2985
  }
2481
2986
  if (host2 === "wsl") {
2482
2987
  const localAppData = windowsLocalAppDataFromWsl();
2483
2988
  if (localAppData) {
2484
- return join9(localAppData, "AbsoluteJS", "Android", "Sdk");
2989
+ return join10(localAppData, "AbsoluteJS", "Android", "Sdk");
2485
2990
  }
2486
2991
  }
2487
- return join9(homedir3(), ".absolutejs", "android-sdk");
2992
+ return join10(homedir3(), ".absolutejs", "android-sdk");
2488
2993
  }, pathExists = async (path) => {
2489
2994
  try {
2490
2995
  await access3(path);
@@ -2537,7 +3042,7 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
2537
3042
  const capture = input.capture ?? captureCommand;
2538
3043
  const androidRoot = input.androidRoot === null ? undefined : input.androidRoot ?? env.ANDROID_HOME ?? env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(host2, env);
2539
3044
  const windowsAndroidTools = host2 === "windows" || host2 === "wsl";
2540
- const android = (segments) => androidRoot ? join9(androidRoot, ...segments) : undefined;
3045
+ const android = (segments) => androidRoot ? join10(androidRoot, ...segments) : undefined;
2541
3046
  const paths = (values) => values.filter((value) => Boolean(value));
2542
3047
  const adb = await findExecutable("adb", paths([
2543
3048
  android(["platform-tools", windowsAndroidTools ? "adb.exe" : "adb"])
@@ -2644,8 +3149,8 @@ var init_emulatorDoctor = __esm(() => {
2644
3149
 
2645
3150
  // src/mobile/capacitorProject.ts
2646
3151
  import { access as access4, readFile as readFile3, rename as rename2, writeFile as writeFile2 } from "fs/promises";
2647
- import { relative as relative2, resolve as resolve6 } from "path";
2648
- var CONFIG_FILE = "capacitor.config.ts", portableRelative2 = (root, path) => relative2(root, path).replaceAll("\\", "/"), capacitorConfigSource = (config, projectRoot) => `import type { CapacitorConfig } from '@capacitor/cli';
3152
+ import { relative as relative3, resolve as resolve7 } from "path";
3153
+ var CONFIG_FILE = "capacitor.config.ts", portableRelative2 = (root, path) => relative3(root, path).replaceAll("\\", "/"), capacitorConfigSource = (config, projectRoot) => `import type { CapacitorConfig } from '@capacitor/cli';
2649
3154
 
2650
3155
  const config: CapacitorConfig = {
2651
3156
  appId: ${JSON.stringify(config.appId)},
@@ -2668,8 +3173,8 @@ export default config;
2668
3173
  return false;
2669
3174
  }
2670
3175
  }, writeAbsoluteCapacitorConfig = async (config, options) => {
2671
- const projectRoot = resolve6(options.projectRoot);
2672
- const destination = resolve6(projectRoot, CONFIG_FILE);
3176
+ const projectRoot = resolve7(options.projectRoot);
3177
+ const destination = resolve7(projectRoot, CONFIG_FILE);
2673
3178
  const source = capacitorConfigSource(config, projectRoot);
2674
3179
  if (await exists2(destination)) {
2675
3180
  const current = await readFile3(destination, "utf8");
@@ -2704,10 +3209,10 @@ import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
2704
3209
  import {
2705
3210
  dirname as dirname5,
2706
3211
  isAbsolute,
2707
- join as join10,
2708
- relative as relative3,
2709
- resolve as resolve7,
2710
- sep,
3212
+ join as join11,
3213
+ relative as relative4,
3214
+ resolve as resolve8,
3215
+ sep as sep2,
2711
3216
  win32
2712
3217
  } from "path";
2713
3218
  var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_FORMAT = 1, NATIVE_CACHE_FORMAT = 1, HASH_RADIX = 16, EXECUTABLE_MODE_MASK = 73, NATIVE_PUBLIC_PATH_SEGMENTS = 5, CAPACITOR_PROJECT_DIRECTORY_PATTERN, ANDROID_TIMING_PHASES, androidTimingSummary = (timings, physicalDevice = false) => ANDROID_TIMING_PHASES.map(([phase, label]) => {
@@ -2876,21 +3381,21 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
2876
3381
  return;
2877
3382
  throw new DOMException("Android development startup was cancelled.", "AbortError");
2878
3383
  }, journalPaths = (projectRoot) => {
2879
- const root = join10(projectRoot, ".absolutejs", "mobile", "dev-session");
3384
+ const root = join11(projectRoot, ".absolutejs", "mobile", "dev-session");
2880
3385
  return {
2881
- backup: join10(root, "capacitor.config.backup.json"),
2882
- caBackup: join10(root, "absolutejs_dev_ca.backup.pem"),
2883
- journal: join10(root, "journal.json"),
2884
- manifestBackup: join10(root, "AndroidManifest.backup.xml"),
2885
- networkConfigBackup: join10(root, "absolutejs_dev_network_security.backup.xml"),
3386
+ backup: join11(root, "capacitor.config.backup.json"),
3387
+ caBackup: join11(root, "absolutejs_dev_ca.backup.pem"),
3388
+ journal: join11(root, "journal.json"),
3389
+ manifestBackup: join11(root, "AndroidManifest.backup.xml"),
3390
+ networkConfigBackup: join11(root, "absolutejs_dev_network_security.backup.xml"),
2886
3391
  root
2887
3392
  };
2888
3393
  }, isInside = (root, path) => {
2889
- const resolvedRoot = resolve7(root);
2890
- const resolvedPath = resolve7(path);
2891
- const relativePath = relative3(resolvedRoot, resolvedPath);
2892
- return relativePath === "" || relativePath !== ".." && !relativePath.startsWith(`..${sep}`) && !isAbsolute(relativePath);
2893
- }, isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value), nativeCachePath = (projectRoot) => join10(projectRoot, ".absolutejs", "mobile", "cache", "android-debug.json"), parseNativeCache = (value) => {
3394
+ const resolvedRoot = resolve8(root);
3395
+ const resolvedPath = resolve8(path);
3396
+ const relativePath = relative4(resolvedRoot, resolvedPath);
3397
+ return relativePath === "" || relativePath !== ".." && !relativePath.startsWith(`..${sep2}`) && !isAbsolute(relativePath);
3398
+ }, isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value), nativeCachePath = (projectRoot) => join11(projectRoot, ".absolutejs", "mobile", "cache", "android-debug.json"), parseNativeCache = (value) => {
2894
3399
  if (!isRecord(value))
2895
3400
  return null;
2896
3401
  const { appId, fingerprint, format, installations } = value;
@@ -2922,27 +3427,27 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
2922
3427
  });
2923
3428
  }
2924
3429
  }, nativeDependencySources = async (nativeDirectory) => {
2925
- const settings = await readFile4(join10(nativeDirectory, "capacitor.settings.gradle"), "utf8");
3430
+ const settings = await readFile4(join11(nativeDirectory, "capacitor.settings.gradle"), "utf8");
2926
3431
  const pattern = new RegExp(CAPACITOR_PROJECT_DIRECTORY_PATTERN.source, CAPACITOR_PROJECT_DIRECTORY_PATTERN.flags);
2927
3432
  const dependencies = [...settings.matchAll(pattern)].map((match) => ({
2928
3433
  name: (match[1] ?? "").slice(1).replaceAll(/[^a-zA-Z0-9_.-]/gu, "_"),
2929
- source: resolve7(nativeDirectory, match[2] ?? "")
3434
+ source: resolve8(nativeDirectory, match[2] ?? "")
2930
3435
  }));
2931
3436
  if (dependencies.length === 0) {
2932
3437
  throw new Error("Capacitor Android settings did not declare any native dependencies.");
2933
3438
  }
2934
3439
  return { dependencies, settings };
2935
3440
  }, shouldIgnoreNativePath = (relativePath, ignorePublicBundle) => {
2936
- const parts = relativePath.split(sep);
3441
+ const parts = relativePath.split(sep2);
2937
3442
  if (parts.includes(".gradle") || parts.includes("build") || parts.includes(".absolutejs-dependencies")) {
2938
3443
  return true;
2939
3444
  }
2940
3445
  return ignorePublicBundle && parts.slice(0, NATIVE_PUBLIC_PATH_SEGMENTS).join("/") === "app/src/main/assets/public";
2941
3446
  }, collectNativePath = async (root, label, path, isDirectory, isFile, isSymbolicLink, ignorePublicBundle) => {
2942
- const relativePath = relative3(root, path);
3447
+ const relativePath = relative4(root, path);
2943
3448
  if (shouldIgnoreNativePath(relativePath, ignorePublicBundle))
2944
3449
  return [];
2945
- const identity = `${label}:${relativePath.split(sep).join("/")}\x00`;
3450
+ const identity = `${label}:${relativePath.split(sep2).join("/")}\x00`;
2946
3451
  if (isDirectory) {
2947
3452
  return collectNativeDirectory(root, label, path, ignorePublicBundle);
2948
3453
  }
@@ -2962,7 +3467,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
2962
3467
  }, collectNativeDirectory = async (root, label, directory, ignorePublicBundle) => {
2963
3468
  const entries = await readdir2(directory, { withFileTypes: true });
2964
3469
  entries.sort((left, right) => left.name.localeCompare(right.name));
2965
- const records = await Promise.all(entries.map((entry) => collectNativePath(root, label, join10(directory, entry.name), entry.isDirectory(), entry.isFile(), entry.isSymbolicLink(), ignorePublicBundle)));
3470
+ const records = await Promise.all(entries.map((entry) => collectNativePath(root, label, join11(directory, entry.name), entry.isDirectory(), entry.isFile(), entry.isSymbolicLink(), ignorePublicBundle)));
2966
3471
  return records.flat();
2967
3472
  }, hashNativeTree = async (root, label, ignorePublicBundle) => {
2968
3473
  const resolvedRoot = await realpath(root);
@@ -3091,11 +3596,11 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
3091
3596
  await mkdir2(paths.root, { recursive: true });
3092
3597
  await writeFile3(paths.backup, source, { flag: "wx" });
3093
3598
  await writeFile3(paths.manifestBackup, manifestSource, { flag: "wx" });
3094
- const resourceRoot = join10(dirname5(nativeManifestPath), "res");
3095
- const caPath = join10(resourceRoot, "raw", "absolutejs_dev_ca.pem");
3599
+ const resourceRoot = join11(dirname5(nativeManifestPath), "res");
3600
+ const caPath = join11(resourceRoot, "raw", "absolutejs_dev_ca.pem");
3096
3601
  const existingNetworkConfig = manifestSource.match(/android:networkSecurityConfig=["']@xml\/([a-z0-9_]+)["']/u)?.[1];
3097
3602
  const networkConfigName = existingNetworkConfig ?? "absolutejs_dev_network_security";
3098
- const networkConfigPath = join10(resourceRoot, "xml", `${networkConfigName}.xml`);
3603
+ const networkConfigPath = join11(resourceRoot, "xml", `${networkConfigName}.xml`);
3099
3604
  const backupProjectedFile = async ([path, backupPath]) => {
3100
3605
  if (!await pathExists2(path))
3101
3606
  return { path };
@@ -3188,12 +3693,12 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
3188
3693
  }
3189
3694
  return result.stdout.trim();
3190
3695
  }, mirroredCapacitorDependencies = async (project, capture) => {
3191
- const settingsPath = join10(project.nativeDirectory, "capacitor.settings.gradle");
3696
+ const settingsPath = join11(project.nativeDirectory, "capacitor.settings.gradle");
3192
3697
  const settings = await readFile4(settingsPath, "utf8");
3193
3698
  const dependencies = [];
3194
3699
  const rewrittenSettings = settings.replace(CAPACITOR_PROJECT_DIRECTORY_PATTERN, (_statement, projectName, sourcePath) => {
3195
3700
  const name = projectName.slice(1).replaceAll(/[^a-zA-Z0-9_.-]/gu, "_");
3196
- const source = resolve7(project.nativeDirectory, sourcePath);
3701
+ const source = resolve8(project.nativeDirectory, sourcePath);
3197
3702
  dependencies.push({
3198
3703
  name,
3199
3704
  windowsSource: windowsPathFromWsl(source, capture)
@@ -3234,7 +3739,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
3234
3739
  ].join("; ");
3235
3740
  return Buffer.from(source, "utf16le").toString("base64");
3236
3741
  }, gradleArtifactPath = (nativeDirectory, task, windows = false) => {
3237
- const pathJoin = windows ? win32.join : join10;
3742
+ const pathJoin = windows ? win32.join : join11;
3238
3743
  if (task === "assembleDebug") {
3239
3744
  return pathJoin(nativeDirectory, "app", "build", "outputs", "apk", "debug", "app-debug.apk");
3240
3745
  }
@@ -3247,7 +3752,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
3247
3752
  if (task !== "assembleRelease" || await pathExists2(primary)) {
3248
3753
  return primary;
3249
3754
  }
3250
- return join10(nativeDirectory, "app", "build", "outputs", "apk", "release", "app-release-unsigned.apk");
3755
+ return join11(nativeDirectory, "app", "build", "outputs", "apk", "release", "app-release-unsigned.apk");
3251
3756
  }, buildAbsoluteAndroidGradleArtifact = async (options) => {
3252
3757
  const { project, task } = options;
3253
3758
  const capture = options.capture ?? captureCommand2;
@@ -3257,7 +3762,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
3257
3762
  if (project.host === "wsl") {
3258
3763
  const windowsSource = windowsPathFromWsl(project.nativeDirectory, capture);
3259
3764
  const buildId = Bun.hash(project.projectRoot).toString(HASH_RADIX);
3260
- const managedBuildDirectory = resolve7(project.androidRoot, "..", "..", "Builds", `${project.config.appId}-${buildId}`);
3765
+ const managedBuildDirectory = resolve8(project.androidRoot, "..", "..", "Builds", `${project.config.appId}-${buildId}`);
3261
3766
  const windowsDirectory = windowsPathFromWsl(managedBuildDirectory, capture);
3262
3767
  const windowsAndroidRoot = windowsPathFromWsl(project.androidRoot, capture);
3263
3768
  const { dependencies, rewrittenSettings } = await mirroredCapacitorDependencies(project, capture);
@@ -3440,7 +3945,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
3440
3945
  "chromium:I"
3441
3946
  ], { env }, onLine);
3442
3947
  }, prepareAbsoluteAndroidDevProject = async (config, options) => {
3443
- const projectRoot = resolve7(options.projectRoot);
3948
+ const projectRoot = resolve8(options.projectRoot);
3444
3949
  const host2 = detectAbsoluteMobileHost();
3445
3950
  const androidRoot = process.env.ANDROID_HOME ?? process.env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(host2);
3446
3951
  const checks = await inspectAbsoluteMobileToolchain({ androidRoot, host: host2 });
@@ -3459,18 +3964,18 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
3459
3964
  if (!adb || options.target !== "device" && !emulator) {
3460
3965
  throw new Error("Android SDK tools disappeared after readiness checks.");
3461
3966
  }
3462
- const cap = join10(projectRoot, "node_modules", ".bin", host2 === "windows" ? "cap.cmd" : "cap");
3967
+ const cap = join11(projectRoot, "node_modules", ".bin", host2 === "windows" ? "cap.cmd" : "cap");
3463
3968
  if (!await pathExists2(cap)) {
3464
3969
  throw new Error("Capacitor CLI is not installed. Run absolute mobile init first.");
3465
3970
  }
3466
3971
  await writeAbsoluteCapacitorConfig(config, { projectRoot });
3467
3972
  await mkdir2(config.bundleDirectory, { recursive: true });
3468
- const placeholder = join10(config.bundleDirectory, "index.html");
3973
+ const placeholder = join11(config.bundleDirectory, "index.html");
3469
3974
  if (!await pathExists2(placeholder)) {
3470
3975
  await writeFile3(placeholder, `<!doctype html><title>AbsoluteJS mobile development</title>
3471
3976
  `);
3472
3977
  }
3473
- const nativeDirectory = join10(config.nativeProjectDirectory, "android");
3978
+ const nativeDirectory = join11(config.nativeProjectDirectory, "android");
3474
3979
  if (!await pathExists2(nativeDirectory)) {
3475
3980
  if (!options.createNativeProject) {
3476
3981
  throw new Error("Android native project has not been created.");
@@ -3531,8 +4036,8 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
3531
4036
  await requireSuccess([project.cap, "sync", "android"], "Capacitor Android synchronization", run, { cwd: project.projectRoot, env, signal: options.signal });
3532
4037
  throwIfAborted(options.signal);
3533
4038
  transition("configuring");
3534
- const nativeConfigPath = join10(project.nativeDirectory, "app", "src", "main", "assets", "capacitor.config.json");
3535
- const nativeManifestPath = join10(project.nativeDirectory, "app", "src", "main", "AndroidManifest.xml");
4039
+ const nativeConfigPath = join11(project.nativeDirectory, "app", "src", "main", "assets", "capacitor.config.json");
4040
+ const nativeManifestPath = join11(project.nativeDirectory, "app", "src", "main", "AndroidManifest.xml");
3536
4041
  let connectedSerial;
3537
4042
  let nativeLogs = null;
3538
4043
  const closeNativeLogs = async () => {
@@ -3691,7 +4196,7 @@ var init_androidEmulatorController = __esm(() => {
3691
4196
  import { createHash as createHash3 } from "crypto";
3692
4197
  import { cp as cp2, mkdir as mkdir3, mkdtemp as mkdtemp2, readFile as readFile5, rm as rm3 } from "fs/promises";
3693
4198
  import { tmpdir } from "os";
3694
- import { basename as basename3, join as join11 } from "path";
4199
+ import { basename as basename3, join as join12 } from "path";
3695
4200
  var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION = "15859902", LICENSE_ACCEPTANCE_RESPONSES = 100, COMMAND_LINE_TOOLS, defaultRun = async (command, options = {}) => {
3696
4201
  const subprocess = Bun.spawn(command, {
3697
4202
  env: options.env,
@@ -3723,7 +4228,7 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
3723
4228
  exitCode: result.exitCode,
3724
4229
  stdout: result.stdout.toString()
3725
4230
  };
3726
- }, commandPath = (root, host2, tool) => join11(root, "cmdline-tools", "latest", "bin", host2 === "windows" || host2 === "wsl" ? `${tool}.bat` : tool), executablePath = (root, host2, directory, tool) => join11(root, directory, host2 === "windows" || host2 === "wsl" ? `${tool}.exe` : tool), windowsPath = (path) => {
4231
+ }, commandPath = (root, host2, tool) => join12(root, "cmdline-tools", "latest", "bin", host2 === "windows" || host2 === "wsl" ? `${tool}.bat` : tool), executablePath = (root, host2, directory, tool) => join12(root, directory, host2 === "windows" || host2 === "wsl" ? `${tool}.exe` : tool), windowsPath = (path) => {
3727
4232
  const match = /^\/mnt\/([a-z])\/(.*)$/i.exec(path);
3728
4233
  if (!match)
3729
4234
  return path;
@@ -3797,10 +4302,10 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
3797
4302
  if (digest !== release.sha256) {
3798
4303
  throw new Error(`Android command-line-tools checksum mismatch: expected ${release.sha256}, received ${digest}.`);
3799
4304
  }
3800
- const temporary = await mkdtemp2(join11(tmpdir(), "absolutejs-android-sdk-"));
4305
+ const temporary = await mkdtemp2(join12(tmpdir(), "absolutejs-android-sdk-"));
3801
4306
  try {
3802
- const archive = join11(temporary, "command-line-tools.zip");
3803
- const extracted = join11(temporary, "extracted");
4307
+ const archive = join12(temporary, "command-line-tools.zip");
4308
+ const extracted = join12(temporary, "extracted");
3804
4309
  await Bun.write(archive, bytes);
3805
4310
  await mkdir3(extracted, { recursive: true });
3806
4311
  const extraction = plan.host === "windows" ? [
@@ -3817,12 +4322,12 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
3817
4322
  if (await input.run(extraction) !== 0) {
3818
4323
  throw new Error("Failed to extract Android command-line tools.");
3819
4324
  }
3820
- const destination = join11(plan.androidRoot, "cmdline-tools", "latest");
3821
- await mkdir3(join11(plan.androidRoot, "cmdline-tools"), {
4325
+ const destination = join12(plan.androidRoot, "cmdline-tools", "latest");
4326
+ await mkdir3(join12(plan.androidRoot, "cmdline-tools"), {
3822
4327
  recursive: true
3823
4328
  });
3824
4329
  await rm3(destination, { force: true, recursive: true });
3825
- await cp2(join11(extracted, "cmdline-tools"), destination, {
4330
+ await cp2(join12(extracted, "cmdline-tools"), destination, {
3826
4331
  recursive: true
3827
4332
  });
3828
4333
  } finally {
@@ -4007,7 +4512,7 @@ import {
4007
4512
  stat,
4008
4513
  writeFile as writeFile4
4009
4514
  } from "fs/promises";
4010
- import { dirname as dirname6, isAbsolute as isAbsolute2, join as join12, relative as relative4, resolve as resolve8, sep as sep2 } from "path";
4515
+ import { dirname as dirname6, isAbsolute as isAbsolute2, join as join13, relative as relative5, resolve as resolve9, sep as sep3 } from "path";
4011
4516
  var developmentTeamArgument = (value) => {
4012
4517
  if (value === undefined)
4013
4518
  return;
@@ -4064,8 +4569,8 @@ var developmentTeamArgument = (value) => {
4064
4569
  }, ignoredFingerprintDirectories, fingerprintFiles = async (root, current = root, options = {}) => {
4065
4570
  const entries = await readdir3(current, { withFileTypes: true });
4066
4571
  const nested = await Promise.all(entries.sort((left, right) => left.name.localeCompare(right.name)).map(async (entry) => {
4067
- const path = join12(current, entry.name);
4068
- const projectRelative = relative4(root, path).replaceAll("\\", "/");
4572
+ const path = join13(current, entry.name);
4573
+ const projectRelative = relative5(root, path).replaceAll("\\", "/");
4069
4574
  const ignored = entry.isDirectory() && (ignoredFingerprintDirectories.has(entry.name) || projectRelative === "App/App/public" && options.includePublicBundle !== true);
4070
4575
  if (ignored)
4071
4576
  return [];
@@ -4079,17 +4584,17 @@ var developmentTeamArgument = (value) => {
4079
4584
  const files = await fingerprintFiles(nativeDirectory, nativeDirectory, options);
4080
4585
  const contents = await Promise.all(files.map((file) => readFile6(file)));
4081
4586
  files.forEach((file, index) => {
4082
- hasher.update(relative4(nativeDirectory, file).replaceAll("\\", "/"));
4587
+ hasher.update(relative5(nativeDirectory, file).replaceAll("\\", "/"));
4083
4588
  hasher.update("\x00");
4084
4589
  hasher.update(contents[index] ?? new Uint8Array);
4085
4590
  hasher.update("\x00");
4086
4591
  });
4087
4592
  return hasher.digest("hex");
4088
4593
  }, safeOutputDirectory = (projectRoot, requested) => {
4089
- const root = resolve8(projectRoot);
4090
- const output = resolve8(root, requested ?? ".absolutejs/mobile/releases/ios");
4091
- const projectRelative = relative4(root, output);
4092
- if (projectRelative === ".." || projectRelative.startsWith(`..${sep2}`) || isAbsolute2(projectRelative)) {
4594
+ const root = resolve9(projectRoot);
4595
+ const output = resolve9(root, requested ?? ".absolutejs/mobile/releases/ios");
4596
+ const projectRelative = relative5(root, output);
4597
+ if (projectRelative === ".." || projectRelative.startsWith(`..${sep3}`) || isAbsolute2(projectRelative)) {
4093
4598
  throw new TypeError("mobile build --outdir must remain inside the project.");
4094
4599
  }
4095
4600
  return output;
@@ -4098,7 +4603,7 @@ var developmentTeamArgument = (value) => {
4098
4603
  return;
4099
4604
  const entries = await readdir3(root, { withFileTypes: true });
4100
4605
  const matches = await Promise.all(entries.map(async (entry) => {
4101
- const path = join12(root, entry.name);
4606
+ const path = join13(root, entry.name);
4102
4607
  if (entry.isDirectory() && entry.name.endsWith(extension))
4103
4608
  return path;
4104
4609
  if (entry.isFile() && entry.name.endsWith(extension))
@@ -4121,10 +4626,10 @@ var developmentTeamArgument = (value) => {
4121
4626
  throw new TypeError("iOS build number must be a positive integer.");
4122
4627
  return value;
4123
4628
  }, installRelease = async (artifactPath, metadata, outputRoot) => {
4124
- const releaseRoot = join12(outputRoot, metadata.releaseId);
4125
- const destination = join12(releaseRoot, "App.ipa");
4629
+ const releaseRoot = join13(outputRoot, metadata.releaseId);
4630
+ const destination = join13(releaseRoot, "App.ipa");
4126
4631
  if (await pathExists3(releaseRoot)) {
4127
- const value = JSON.parse(await readFile6(join12(releaseRoot, "release.json"), "utf8"));
4632
+ const value = JSON.parse(await readFile6(join13(releaseRoot, "release.json"), "utf8"));
4128
4633
  if (!isRecord2(value) || value.artifact !== "App.ipa" || Object.entries(metadata).some(([key, expected]) => Reflect.get(value, key) !== expected)) {
4129
4634
  throw new TypeError(`Immutable iOS release ${metadata.releaseId} does not match its content.`);
4130
4635
  }
@@ -4144,14 +4649,14 @@ var developmentTeamArgument = (value) => {
4144
4649
  };
4145
4650
  }
4146
4651
  await mkdir4(dirname6(releaseRoot), { recursive: true });
4147
- const staging = await mkdtemp3(join12(dirname6(releaseRoot), ".ios-stage-"));
4652
+ const staging = await mkdtemp3(join13(dirname6(releaseRoot), ".ios-stage-"));
4148
4653
  try {
4149
- await copyFile2(artifactPath, join12(staging, "App.ipa"));
4654
+ await copyFile2(artifactPath, join13(staging, "App.ipa"));
4150
4655
  const complete = {
4151
4656
  ...metadata,
4152
4657
  artifact: "App.ipa"
4153
4658
  };
4154
- await writeFile4(join12(staging, "release.json"), `${JSON.stringify(complete, null, "\t")}
4659
+ await writeFile4(join13(staging, "release.json"), `${JSON.stringify(complete, null, "\t")}
4155
4660
  `, { flag: "wx" });
4156
4661
  await rename4(staging, releaseRoot);
4157
4662
  return { artifactPath: destination, metadata: complete, releaseRoot };
@@ -4168,22 +4673,22 @@ var developmentTeamArgument = (value) => {
4168
4673
  const marketingVersion = options.config.iosVersion;
4169
4674
  if (!marketingVersion)
4170
4675
  throw new TypeError("iOS release builds require mobile.ios.version in absolutejs.config.ts.");
4171
- const manifest = requireManifest(JSON.parse(await readFile6(join12(options.config.bundleDirectory, "absolute-mobile-manifest.json"), "utf8")));
4676
+ const manifest = requireManifest(JSON.parse(await readFile6(join13(options.config.bundleDirectory, "absolute-mobile-manifest.json"), "utf8")));
4172
4677
  if (manifest.appId !== options.config.appId)
4173
4678
  throw new TypeError("Embedded mobile manifest appId does not match mobile.appId.");
4174
- const nativeDirectory = join12(options.config.nativeProjectDirectory, "ios");
4679
+ const nativeDirectory = join13(options.config.nativeProjectDirectory, "ios");
4175
4680
  let buildNumber = requireBuildNumber(options.buildNumber);
4176
4681
  if (options.prepareBuildNumber) {
4177
4682
  const nativeFingerprint = await fingerprintAbsoluteIosNativeProject(nativeDirectory);
4178
4683
  const buildIdentity = createHash4("sha256").update(`${manifest.appBuild}\x00${nativeFingerprint}\x00${marketingVersion}`).digest("hex");
4179
4684
  buildNumber = requireBuildNumber(await options.prepareBuildNumber(buildIdentity));
4180
4685
  }
4181
- const stagingParent = resolve8(options.projectRoot, ".absolutejs/mobile");
4686
+ const stagingParent = resolve9(options.projectRoot, ".absolutejs/mobile");
4182
4687
  await mkdir4(stagingParent, { recursive: true });
4183
- const staging = await mkdtemp3(join12(stagingParent, ".ios-build-"));
4184
- const archivePath = join12(staging, "App.xcarchive");
4185
- const exportPath = join12(staging, "export");
4186
- const exportPlist = join12(staging, "ExportOptions.plist");
4688
+ const staging = await mkdtemp3(join13(stagingParent, ".ios-build-"));
4689
+ const archivePath = join13(staging, "App.xcarchive");
4690
+ const exportPath = join13(staging, "export");
4691
+ const exportPlist = join13(staging, "ExportOptions.plist");
4187
4692
  await mkdir4(exportPath, { recursive: true });
4188
4693
  await writeFile4(exportPlist, exportOptions());
4189
4694
  const run = options.run ?? defaultRun2;
@@ -4197,7 +4702,7 @@ var developmentTeamArgument = (value) => {
4197
4702
  const archiveExit = await run([
4198
4703
  "xcodebuild",
4199
4704
  "-workspace",
4200
- join12(nativeDirectory, "App", "App.xcworkspace"),
4705
+ join13(nativeDirectory, "App", "App.xcworkspace"),
4201
4706
  "-scheme",
4202
4707
  "App",
4203
4708
  "-configuration",
@@ -4211,7 +4716,7 @@ var developmentTeamArgument = (value) => {
4211
4716
  ], { cwd: nativeDirectory });
4212
4717
  if (archiveExit !== 0)
4213
4718
  throw new TypeError("Xcode failed to archive the iOS app.");
4214
- const archivedApp = await findByExtension(join12(archivePath, "Products", "Applications"), ".app");
4719
+ const archivedApp = await findByExtension(join13(archivePath, "Products", "Applications"), ".app");
4215
4720
  const capture = options.capture ?? defaultCapture2;
4216
4721
  const signed = archivedApp ? capture([
4217
4722
  "codesign",
@@ -4285,7 +4790,7 @@ import {
4285
4790
  writeFile as writeFile5
4286
4791
  } from "fs/promises";
4287
4792
  import { isIP as isIP2 } from "net";
4288
- import { dirname as dirname7, isAbsolute as isAbsolute3, join as join13, relative as relative5, resolve as resolve9, sep as sep3 } from "path";
4793
+ import { dirname as dirname7, isAbsolute as isAbsolute3, join as join14, relative as relative6, resolve as resolve10, sep as sep4 } from "path";
4289
4794
  var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000, BOOT_POLL_MS = 1000, DEV_JOURNAL_FORMAT2 = 1, NATIVE_CACHE_FORMAT2 = 1, isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), pathExists4 = async (path) => {
4290
4795
  try {
4291
4796
  await access7(path);
@@ -4503,16 +5008,16 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
4503
5008
  const leftPro = left.name.includes("Pro") ? 1 : 0;
4504
5009
  return rightPro - leftPro;
4505
5010
  })[0], journalPaths2 = (projectRoot) => {
4506
- const root = join13(projectRoot, ".absolutejs", "mobile", "ios-dev-session");
5011
+ const root = join14(projectRoot, ".absolutejs", "mobile", "ios-dev-session");
4507
5012
  return {
4508
- configBackup: join13(root, "capacitor-config.backup"),
4509
- infoBackup: join13(root, "Info.plist.backup"),
4510
- journal: join13(root, "journal.json"),
5013
+ configBackup: join14(root, "capacitor-config.backup"),
5014
+ infoBackup: join14(root, "Info.plist.backup"),
5015
+ journal: join14(root, "journal.json"),
4511
5016
  root
4512
5017
  };
4513
- }, nativeCachePath2 = (projectRoot) => join13(projectRoot, ".absolutejs", "mobile", "ios-native-cache.json"), isInside2 = (root, path) => {
4514
- const value = relative5(resolve9(root), resolve9(path));
4515
- return value === "" || !value.startsWith(`..${sep3}`) && value !== ".." && !isAbsolute3(value);
5018
+ }, nativeCachePath2 = (projectRoot) => join14(projectRoot, ".absolutejs", "mobile", "ios-native-cache.json"), isInside2 = (root, path) => {
5019
+ const value = relative6(resolve10(root), resolve10(path));
5020
+ return value === "" || !value.startsWith(`..${sep4}`) && value !== ".." && !isAbsolute3(value);
4516
5021
  }, parseJournal2 = (value) => {
4517
5022
  if (!isRecord3(value) || value.format !== DEV_JOURNAL_FORMAT2)
4518
5023
  return null;
@@ -4567,8 +5072,8 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
4567
5072
  }, writeDevProjection = async (project, port, https, serverHost = "localhost") => {
4568
5073
  const paths = journalPaths2(project.projectRoot);
4569
5074
  await repairAbsoluteIosDevSession(project.projectRoot);
4570
- const nativeConfigPath = join13(project.nativeDirectory, "App", "App", "capacitor.config.json");
4571
- const infoPath = join13(project.nativeDirectory, "App", "App", "Info.plist");
5075
+ const nativeConfigPath = join14(project.nativeDirectory, "App", "App", "capacitor.config.json");
5076
+ const infoPath = join14(project.nativeDirectory, "App", "App", "Info.plist");
4572
5077
  const [configSource, infoSource] = await Promise.all([
4573
5078
  readFile7(nativeConfigPath, "utf8"),
4574
5079
  readFile7(infoPath, "utf8")
@@ -4729,12 +5234,12 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
4729
5234
  ]);
4730
5235
  return result.exitCode === 0 && result.stdout.includes(project.config.appId);
4731
5236
  }, buildIosDebugApp = async (project, udid, fingerprint, run, signal) => {
4732
- const derivedDataPath = join13(project.projectRoot, ".absolutejs", "mobile", "ios-derived-data", createHash5("sha256").update(project.config.appId).digest("hex").slice(0, 16));
5237
+ const derivedDataPath = join14(project.projectRoot, ".absolutejs", "mobile", "ios-derived-data", createHash5("sha256").update(project.config.appId).digest("hex").slice(0, 16));
4733
5238
  await mkdir5(derivedDataPath, { recursive: true });
4734
5239
  await requireSuccess2([
4735
5240
  project.xcodebuild,
4736
5241
  "-workspace",
4737
- join13(project.nativeDirectory, "App", "App.xcworkspace"),
5242
+ join14(project.nativeDirectory, "App", "App.xcworkspace"),
4738
5243
  "-scheme",
4739
5244
  "App",
4740
5245
  "-configuration",
@@ -4745,17 +5250,17 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
4745
5250
  derivedDataPath,
4746
5251
  "build"
4747
5252
  ], "iOS simulator build", run, { cwd: project.nativeDirectory, signal });
4748
- const appPath = join13(derivedDataPath, "Build", "Products", "Debug-iphonesimulator", "App.app");
5253
+ const appPath = join14(derivedDataPath, "Build", "Products", "Debug-iphonesimulator", "App.app");
4749
5254
  if (!await pathExists4(appPath))
4750
5255
  throw new Error(`Xcode did not produce the simulator app at ${appPath}.`);
4751
5256
  return appPath;
4752
5257
  }, buildPhysicalIosDebugApp = async (project, identifier, run, signal) => {
4753
- const derivedDataPath = join13(project.projectRoot, ".absolutejs", "mobile", "ios-derived-data", createHash5("sha256").update(project.config.appId).digest("hex").slice(0, 16));
5258
+ const derivedDataPath = join14(project.projectRoot, ".absolutejs", "mobile", "ios-derived-data", createHash5("sha256").update(project.config.appId).digest("hex").slice(0, 16));
4754
5259
  await mkdir5(derivedDataPath, { recursive: true });
4755
5260
  await requireSuccess2([
4756
5261
  project.xcodebuild,
4757
5262
  "-workspace",
4758
- join13(project.nativeDirectory, "App", "App.xcworkspace"),
5263
+ join14(project.nativeDirectory, "App", "App.xcworkspace"),
4759
5264
  "-scheme",
4760
5265
  "App",
4761
5266
  "-configuration",
@@ -4767,7 +5272,7 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
4767
5272
  "-allowProvisioningUpdates",
4768
5273
  "build"
4769
5274
  ], "iOS physical-device build (configure automatic signing and a Development Team in Xcode if this is the first run)", run, { cwd: project.nativeDirectory, signal });
4770
- const appPath = join13(derivedDataPath, "Build", "Products", "Debug-iphoneos", "App.app");
5275
+ const appPath = join14(derivedDataPath, "Build", "Products", "Debug-iphoneos", "App.app");
4771
5276
  if (!await pathExists4(appPath))
4772
5277
  throw new Error(`Xcode did not produce the physical-device app at ${appPath}.`);
4773
5278
  return appPath;
@@ -4878,7 +5383,7 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
4878
5383
  if (detectAbsoluteMobileHost() !== "macos")
4879
5384
  throw new Error("iOS development requires macOS and Xcode.");
4880
5385
  const target = options.target ?? "simulator";
4881
- const projectRoot = resolve9(options.projectRoot);
5386
+ const projectRoot = resolve10(options.projectRoot);
4882
5387
  const checks = await inspectAbsoluteMobileToolchain({ host: "macos" });
4883
5388
  const failed = checks.filter((check) => check.platform === "ios" && !(target === "device" && check.id === "ios.runtime") && (check.status === "fail" || check.status === "warn"));
4884
5389
  if (failed.length > 0)
@@ -4887,16 +5392,16 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
4887
5392
  const xcodebuild = checks.find((check) => check.id === "ios.xcodebuild")?.path;
4888
5393
  if (!xcrun || !xcodebuild)
4889
5394
  throw new Error("Xcode tools disappeared after readiness checks.");
4890
- const cap = join13(projectRoot, "node_modules", ".bin", "cap");
5395
+ const cap = join14(projectRoot, "node_modules", ".bin", "cap");
4891
5396
  if (!await pathExists4(cap))
4892
5397
  throw new Error("Capacitor CLI is not installed. Run absolute mobile init first.");
4893
5398
  await writeAbsoluteCapacitorConfig(config, { projectRoot });
4894
5399
  await mkdir5(config.bundleDirectory, { recursive: true });
4895
- const placeholder = join13(config.bundleDirectory, "index.html");
5400
+ const placeholder = join14(config.bundleDirectory, "index.html");
4896
5401
  if (!await pathExists4(placeholder))
4897
5402
  await writeFile5(placeholder, `<!doctype html><title>AbsoluteJS mobile development</title>
4898
5403
  `);
4899
- const nativeDirectory = join13(config.nativeProjectDirectory, "ios");
5404
+ const nativeDirectory = join14(config.nativeProjectDirectory, "ios");
4900
5405
  if (!await pathExists4(nativeDirectory)) {
4901
5406
  if (!options.createNativeProject)
4902
5407
  throw new Error("iOS native project has not been created.");
@@ -5121,7 +5626,7 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
5121
5626
  screenshot: async (destination) => {
5122
5627
  if (deviceIdentifier)
5123
5628
  throw new Error("Physical iOS screenshots are captured in Xcode Device Hub; the CLI never records a device screen automatically.");
5124
- const resolved = resolve9(project.projectRoot, destination);
5629
+ const resolved = resolve10(project.projectRoot, destination);
5125
5630
  if (!isInside2(project.projectRoot, resolved))
5126
5631
  throw new Error("iOS screenshot destination must remain inside the project.");
5127
5632
  await mkdir5(dirname7(resolved), { recursive: true });
@@ -5185,13 +5690,13 @@ import { isIP as isIP3 } from "net";
5185
5690
  import {
5186
5691
  dirname as dirname8,
5187
5692
  isAbsolute as isAbsolute4,
5188
- join as join14,
5693
+ join as join15,
5189
5694
  posix,
5190
- relative as relative6,
5695
+ relative as relative7,
5191
5696
  resolve as resolvePath,
5192
- sep as sep4
5697
+ sep as sep5
5193
5698
  } from "path";
5194
- var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TIMEOUT_MS = 2000, PROFILE_NAME, SSH_DESTINATION, defaultProfilePath = () => join14(homedir4(), ".absolutejs", "mobile", "remote-macs.json"), emptyStore = () => ({
5699
+ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TIMEOUT_MS = 2000, PROFILE_NAME, SSH_DESTINATION, defaultProfilePath = () => join15(homedir4(), ".absolutejs", "mobile", "remote-macs.json"), emptyStore = () => ({
5195
5700
  format: PROFILE_FORMAT,
5196
5701
  profiles: {}
5197
5702
  }), loadStore = async (path = defaultProfilePath()) => {
@@ -5367,9 +5872,9 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
5367
5872
  throw new TypeError("Remote Expo execution requires mobile.engine: expo.");
5368
5873
  return createAbsoluteRemoteIosDevProject(config, projectRoot, profile);
5369
5874
  }, createAbsoluteRemoteIosDevProject = (config, projectRoot, profile) => ({
5370
- cap: join14(resolvePath(projectRoot), "node_modules", ".bin", "cap"),
5875
+ cap: join15(resolvePath(projectRoot), "node_modules", ".bin", "cap"),
5371
5876
  config,
5372
- nativeDirectory: join14(config.nativeProjectDirectory, "ios"),
5877
+ nativeDirectory: join15(config.nativeProjectDirectory, "ios"),
5373
5878
  profile,
5374
5879
  projectRoot: resolvePath(projectRoot),
5375
5880
  remote: true,
@@ -5416,8 +5921,8 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
5416
5921
  return { ...artifact, remotePath, uploaded: true };
5417
5922
  }, materializeAbsoluteRemoteMacAgent = async (projectRoot) => {
5418
5923
  const shippedCandidates = [
5419
- join14(import.meta.dir, "remoteMacAgentEntry.js"),
5420
- join14(import.meta.dir, "..", "mobile", "remoteMacAgentEntry.js")
5924
+ join15(import.meta.dir, "remoteMacAgentEntry.js"),
5925
+ join15(import.meta.dir, "..", "mobile", "remoteMacAgentEntry.js")
5421
5926
  ];
5422
5927
  let path;
5423
5928
  for (const candidate of shippedCandidates) {
@@ -5428,13 +5933,13 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
5428
5933
  }
5429
5934
  if (!path) {
5430
5935
  const sourceCandidates = [
5431
- join14(import.meta.dir, "remoteMacAgentEntry.ts"),
5432
- join14(import.meta.dir, "..", "..", "src", "mobile", "remoteMacAgentEntry.ts")
5936
+ join15(import.meta.dir, "remoteMacAgentEntry.ts"),
5937
+ join15(import.meta.dir, "..", "..", "src", "mobile", "remoteMacAgentEntry.ts")
5433
5938
  ];
5434
5939
  const source = await sourceCandidates.reduce(async (found, candidate) => await found ?? (await Bun.file(candidate).exists() ? candidate : undefined), Promise.resolve(undefined));
5435
5940
  if (!source)
5436
5941
  throw new Error("The AbsoluteJS installation does not contain its remote Mac agent artifact.");
5437
- const outdir = join14(resolvePath(projectRoot), ".absolutejs", "mobile", "remote-agent");
5942
+ const outdir = join15(resolvePath(projectRoot), ".absolutejs", "mobile", "remote-agent");
5438
5943
  await mkdir6(outdir, { recursive: true });
5439
5944
  const result = await Bun.build({
5440
5945
  entrypoints: [source],
@@ -5444,12 +5949,12 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
5444
5949
  });
5445
5950
  if (!result.success)
5446
5951
  throw new AggregateError(result.logs, "Failed to build the AbsoluteJS remote Mac agent.");
5447
- path = join14(outdir, "remoteMacAgentEntry.js");
5952
+ path = join15(outdir, "remoteMacAgentEntry.js");
5448
5953
  }
5449
5954
  const bytes = await Bun.file(path).arrayBuffer();
5450
5955
  const sha256 = createHash6("sha256").update(new Uint8Array(bytes)).digest("hex");
5451
5956
  return { bytes: bytes.byteLength, path, sha256 };
5452
- }, portableRelativePath = (root, path) => relative6(root, path).split(sep4).join(posix.sep), portableMobileConfig = (project) => ({
5957
+ }, portableRelativePath = (root, path) => relative7(root, path).split(sep5).join(posix.sep), portableMobileConfig = (project) => ({
5453
5958
  appId: project.config.appId,
5454
5959
  appName: project.config.appName,
5455
5960
  bundleDirectory: portableRelativePath(project.projectRoot, project.config.bundleDirectory),
@@ -5665,8 +6170,8 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
5665
6170
  const pending = new Map;
5666
6171
  let resolveReady;
5667
6172
  let rejectReady;
5668
- const readyPromise = new Promise((resolve10, reject) => {
5669
- resolveReady = resolve10;
6173
+ const readyPromise = new Promise((resolve11, reject) => {
6174
+ resolveReady = resolve11;
5670
6175
  rejectReady = reject;
5671
6176
  });
5672
6177
  const handleEvent = (event) => {
@@ -5767,7 +6272,7 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
5767
6272
  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.`);
5768
6273
  const request = (commandName) => {
5769
6274
  const id = randomUUID4();
5770
- const response = new Promise((resolve10, reject) => pending.set(id, { reject, resolve: resolve10 }));
6275
+ const response = new Promise((resolve11, reject) => pending.set(id, { reject, resolve: resolve11 }));
5771
6276
  process2.stdin.write(`${JSON.stringify({ command: commandName, id, v: ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION })}
5772
6277
  `);
5773
6278
  const flush = async () => {
@@ -5787,7 +6292,7 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
5787
6292
  if (closed)
5788
6293
  return;
5789
6294
  closed = true;
5790
- const timeout = () => new Promise((resolve10) => setTimeout(() => resolve10("timeout"), REMOTE_SESSION_CLOSE_TIMEOUT_MS));
6295
+ const timeout = () => new Promise((resolve11) => setTimeout(() => resolve11("timeout"), REMOTE_SESSION_CLOSE_TIMEOUT_MS));
5791
6296
  await Promise.race([
5792
6297
  request("close").catch(() => {
5793
6298
  return;
@@ -5835,7 +6340,7 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
5835
6340
  screenshot: async (destination) => {
5836
6341
  const result = await request("screenshot");
5837
6342
  const target = resolvePath(options.project.projectRoot, destination);
5838
- const targetRelative = relative6(options.project.projectRoot, target);
6343
+ const targetRelative = relative7(options.project.projectRoot, target);
5839
6344
  if (targetRelative.startsWith("..") || isAbsolute4(targetRelative))
5840
6345
  throw new Error("iOS screenshot must remain inside the project.");
5841
6346
  await mkdir6(dirname8(target), { recursive: true });
@@ -5875,16 +6380,16 @@ __export(exports_devCert, {
5875
6380
  });
5876
6381
  import {
5877
6382
  copyFileSync,
5878
- existsSync as existsSync4,
6383
+ existsSync as existsSync5,
5879
6384
  mkdirSync as mkdirSync4,
5880
- readFileSync as readFileSync8,
6385
+ readFileSync as readFileSync9,
5881
6386
  rmSync
5882
6387
  } from "fs";
5883
6388
  import { X509Certificate as X509Certificate2 } from "crypto";
5884
6389
  import { isIP as isIP4 } from "net";
5885
6390
  import { platform as platform2 } from "os";
5886
- import { join as join15 } from "path";
5887
- var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE_HOSTS, CERTIFICATE_HOSTNAME_PATTERN, devLog = (msg) => console.log(`\x1B[2m${new Date().toLocaleTimeString()}\x1B[0m \x1B[36m[dev]\x1B[0m ${msg}`), devWarn = (msg) => console.log(`\x1B[2m${new Date().toLocaleTimeString()}\x1B[0m \x1B[33m[dev]\x1B[0m \x1B[33m${msg}\x1B[0m`), certFilesExist = () => existsSync4(CERT_PATH) && existsSync4(KEY_PATH), normalizeDevCertificateHosts = (hosts = []) => {
6391
+ import { join as join16 } from "path";
6392
+ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE_HOSTS, CERTIFICATE_HOSTNAME_PATTERN, devLog = (msg) => console.log(`\x1B[2m${new Date().toLocaleTimeString()}\x1B[0m \x1B[36m[dev]\x1B[0m ${msg}`), devWarn = (msg) => console.log(`\x1B[2m${new Date().toLocaleTimeString()}\x1B[0m \x1B[33m[dev]\x1B[0m \x1B[33m${msg}\x1B[0m`), certFilesExist = () => existsSync5(CERT_PATH) && existsSync5(KEY_PATH), normalizeDevCertificateHosts = (hosts = []) => {
5888
6393
  const normalized = new Set(DEFAULT_CERTIFICATE_HOSTS);
5889
6394
  for (const host2 of hosts) {
5890
6395
  const value = host2.trim().toLowerCase();
@@ -5898,7 +6403,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
5898
6403
  return [...normalized];
5899
6404
  }, certificateIsUsable = (hosts) => {
5900
6405
  try {
5901
- const certPem = readFileSync8(CERT_PATH, "utf-8");
6406
+ const certPem = readFileSync9(CERT_PATH, "utf-8");
5902
6407
  const certificate = new X509Certificate2(certPem);
5903
6408
  if (new Date(certificate.validTo).getTime() <= Date.now())
5904
6409
  return false;
@@ -5983,8 +6488,8 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
5983
6488
  return null;
5984
6489
  try {
5985
6490
  return {
5986
- cert: readFileSync8(paths.cert, "utf-8"),
5987
- key: readFileSync8(paths.key, "utf-8")
6491
+ cert: readFileSync9(paths.cert, "utf-8"),
6492
+ key: readFileSync9(paths.key, "utf-8")
5988
6493
  };
5989
6494
  } catch {
5990
6495
  return null;
@@ -6080,7 +6585,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
6080
6585
  if (platform2() !== "linux")
6081
6586
  return false;
6082
6587
  try {
6083
- return /microsoft|wsl/i.test(readFileSync8("/proc/version", "utf-8"));
6588
+ return /microsoft|wsl/i.test(readFileSync9("/proc/version", "utf-8"));
6084
6589
  } catch {
6085
6590
  return false;
6086
6591
  }
@@ -6096,8 +6601,8 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
6096
6601
  }
6097
6602
  }, mkcertCaRoot = () => runCapture(["mkcert", "-CAROOT"]), getDevCertificateAuthorityPath = () => {
6098
6603
  const caRoot = hasMkcert() ? mkcertCaRoot() : null;
6099
- const rootCertificate = caRoot ? join15(caRoot, "rootCA.pem") : null;
6100
- if (rootCertificate && existsSync4(rootCertificate))
6604
+ const rootCertificate = caRoot ? join16(caRoot, "rootCA.pem") : null;
6605
+ if (rootCertificate && existsSync5(rootCertificate))
6101
6606
  return rootCertificate;
6102
6607
  if (certFilesExist())
6103
6608
  return CERT_PATH;
@@ -6111,13 +6616,13 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
6111
6616
  const caRoot = mkcertCaRoot();
6112
6617
  if (!caRoot)
6113
6618
  return false;
6114
- const rootCa = join15(caRoot, "rootCA.pem");
6115
- if (!existsSync4(rootCa))
6619
+ const rootCa = join16(caRoot, "rootCA.pem");
6620
+ if (!existsSync5(rootCa))
6116
6621
  return false;
6117
6622
  const winTemp = windowsTempDir();
6118
6623
  if (!winTemp)
6119
6624
  return false;
6120
- const staged = join15(winTemp, "absolutejs-mkcert-rootCA.crt");
6625
+ const staged = join16(winTemp, "absolutejs-mkcert-rootCA.crt");
6121
6626
  try {
6122
6627
  copyFileSync(rootCa, staged);
6123
6628
  } catch {
@@ -6153,7 +6658,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
6153
6658
  devLog("Trusted the local CA in the Windows store \u2014 Chrome/Edge on Windows now accept dev HTTPS");
6154
6659
  } else {
6155
6660
  const caRoot = mkcertCaRoot();
6156
- const hint = caRoot ? toWindowsPath(join15(caRoot, "rootCA.pem")) : null;
6661
+ const hint = caRoot ? toWindowsPath(join16(caRoot, "rootCA.pem")) : null;
6157
6662
  devWarn("Could not auto-trust the local CA on Windows; Windows browsers may warn.");
6158
6663
  if (hint) {
6159
6664
  console.log(` Run in PowerShell: Import-Certificate -FilePath "${hint}" -CertStoreLocation Cert:\\CurrentUser\\Root`);
@@ -6169,9 +6674,9 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
6169
6674
  return true;
6170
6675
  };
6171
6676
  var init_devCert = __esm(() => {
6172
- CERT_DIR = join15(process.cwd(), ".absolutejs");
6173
- CERT_PATH = join15(CERT_DIR, "cert.pem");
6174
- KEY_PATH = join15(CERT_DIR, "key.pem");
6677
+ CERT_DIR = join16(process.cwd(), ".absolutejs");
6678
+ CERT_PATH = join16(CERT_DIR, "cert.pem");
6679
+ KEY_PATH = join16(CERT_DIR, "key.pem");
6175
6680
  DEFAULT_CERTIFICATE_HOSTS = ["localhost", "127.0.0.1", "::1"];
6176
6681
  CERTIFICATE_HOSTNAME_PATTERN = /^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\.(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?))*$/u;
6177
6682
  });
@@ -6187,9 +6692,9 @@ __export(exports_eslintChunked, {
6187
6692
  ruleSummary: () => ruleSummary,
6188
6693
  upstreamRef: () => upstreamRef
6189
6694
  });
6190
- import { existsSync as existsSync6 } from "fs";
6191
- import { relative as relative7, resolve as resolve10 } from "path";
6192
- var DEFAULT_CHUNK_SIZE = 20, DEFAULT_SHARDS = 4, DEFAULT_CONCURRENCY = 2, DEFAULT_REPORT = ".absolutejs/lint-report.txt", CHILD_HEAP_MB = 4096, DJB2_SEED = 5381, DJB2_MULTIPLIER = 33, MS_PER_SECOND = 1000, SUMMARY_RULE_WIDTH = 60, SUMMARY_COUNT_PAD = 5, PORCELAIN_STATUS_WIDTH = 3, RENAME_ARROW = " -> ", ASCII_ESC = 27, LINTABLE_EXTENSIONS, ANSI_COLOR, stripAnsi = (text) => text.replace(ANSI_COLOR, ""), shardOf = (path, shards) => [...path].reduce((accumulator, character) => (Math.imul(accumulator, DJB2_MULTIPLIER) ^ character.charCodeAt(0)) >>> 0, DJB2_SEED) % shards, gitLines = (cmd, cwd) => Bun.spawnSync(cmd, { cwd }).stdout.toString().split(`
6695
+ import { existsSync as existsSync7 } from "fs";
6696
+ import { relative as relative8, resolve as resolve11 } from "path";
6697
+ var DEFAULT_CHUNK_SIZE = 20, DEFAULT_SHARDS = 4, DEFAULT_CONCURRENCY = 2, DEFAULT_REPORT = ".absolutejs/lint-report.txt", CHILD_HEAP_MB = 4096, DJB2_SEED = 5381, DJB2_MULTIPLIER = 33, MS_PER_SECOND = 1000, SUMMARY_RULE_WIDTH = 60, SUMMARY_COUNT_PAD = 5, PORCELAIN_STATUS_WIDTH = 3, RENAME_ARROW = " -> ", ASCII_ESC = 27, LINTABLE_EXTENSIONS, ANSI_COLOR, stripAnsi = (text2) => text2.replace(ANSI_COLOR, ""), shardOf = (path, shards) => [...path].reduce((accumulator, character) => (Math.imul(accumulator, DJB2_MULTIPLIER) ^ character.charCodeAt(0)) >>> 0, DJB2_SEED) % shards, gitLines = (cmd, cwd) => Bun.spawnSync(cmd, { cwd }).stdout.toString().split(`
6193
6698
  `).map((line) => line.trimEnd()).filter(Boolean), applyChangedBase = (parsed, base) => {
6194
6699
  parsed.changedOnly = true;
6195
6700
  parsed.changedBase = base;
@@ -6200,7 +6705,7 @@ var DEFAULT_CHUNK_SIZE = 20, DEFAULT_SHARDS = 4, DEFAULT_CONCURRENCY = 2, DEFAUL
6200
6705
  }, matchesAnyGlob = (file, globs) => globs.some((pattern) => new Bun.Glob(pattern).match(file)), resolveLintSet = (parsed, cwd) => {
6201
6706
  const visible = gitVisibleFiles(cwd);
6202
6707
  const matched = parsed.globs.length === 0 ? visible.filter((file) => LINTABLE_EXTENSIONS.test(file)) : visible.filter((file) => matchesAnyGlob(file, parsed.globs));
6203
- return matched.filter((file) => existsSync6(resolve10(cwd, file))).sort();
6708
+ return matched.filter((file) => existsSync7(resolve11(cwd, file))).sort();
6204
6709
  }, resolveLintTargets = (args, cwd = process.cwd()) => resolveLintSet(parseChunkedArgs(args), cwd), buildShardChunks = (files, shards, chunkSize) => {
6205
6710
  const shardFiles = Array.from({ length: shards }, () => []);
6206
6711
  for (const file of files)
@@ -6222,7 +6727,7 @@ var DEFAULT_CHUNK_SIZE = 20, DEFAULT_SHARDS = 4, DEFAULT_CONCURRENCY = 2, DEFAUL
6222
6727
  "content"
6223
6728
  ];
6224
6729
  const proc = Bun.spawn([
6225
- resolve10(cwd, "node_modules/.bin/eslint"),
6730
+ resolve11(cwd, "node_modules/.bin/eslint"),
6226
6731
  "--color",
6227
6732
  ...hasMaxWarnings ? [] : ["--max-warnings", "0"],
6228
6733
  ...cacheArgs,
@@ -6269,7 +6774,7 @@ var DEFAULT_CHUNK_SIZE = 20, DEFAULT_SHARDS = 4, DEFAULT_CONCURRENCY = 2, DEFAUL
6269
6774
  const fingerprint = createEslintCacheFingerprint(cwd);
6270
6775
  for (let shard = 0;shard < parsed.shards; shard++)
6271
6776
  prepareEslintCache({
6272
- cacheLocation: relative7(cwd, resolve10(cwd, `${cachePrefix}${shard}`)),
6777
+ cacheLocation: relative8(cwd, resolve11(cwd, `${cachePrefix}${shard}`)),
6273
6778
  cwd,
6274
6779
  fingerprint
6275
6780
  });
@@ -6310,7 +6815,7 @@ var DEFAULT_CHUNK_SIZE = 20, DEFAULT_SHARDS = 4, DEFAULT_CONCURRENCY = 2, DEFAUL
6310
6815
  const header = `eslint report \u2014 ${files.length} files, ${totalChunks} chunks, ${elapsed}s
6311
6816
  ${"=".repeat(SUMMARY_RULE_WIDTH)}
6312
6817
  `;
6313
- await Bun.write(resolve10(cwd, parsed.outFile), header + report + summary);
6818
+ await Bun.write(resolve11(cwd, parsed.outFile), header + report + summary);
6314
6819
  console.log(summary);
6315
6820
  console.log(`Full report written to ${parsed.outFile}`);
6316
6821
  if (failedChunks > 0) {
@@ -6397,14 +6902,14 @@ var init_eslintChunked = __esm(() => {
6397
6902
  // src/cli/scripts/eslint.ts
6398
6903
  import { createHash as createHash7 } from "crypto";
6399
6904
  import {
6400
- existsSync as existsSync7,
6905
+ existsSync as existsSync8,
6401
6906
  mkdirSync as mkdirSync5,
6402
- readFileSync as readFileSync10,
6907
+ readFileSync as readFileSync11,
6403
6908
  renameSync,
6404
6909
  rmSync as rmSync3,
6405
6910
  writeFileSync as writeFileSync5
6406
6911
  } from "fs";
6407
- import { dirname as dirname9, relative as relative8, resolve as resolve11 } from "path";
6912
+ import { dirname as dirname9, relative as relative9, resolve as resolve12 } from "path";
6408
6913
  var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION = "1", CACHE_FINGERPRINT_SUFFIX = ".fingerprint", flagValue = (args, flag) => {
6409
6914
  const assignment = args.find((arg) => arg.startsWith(`${flag}=`));
6410
6915
  if (assignment)
@@ -6428,20 +6933,20 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
6428
6933
  return false;
6429
6934
  }, findEslintConfigPath = (cwd = process.cwd()) => {
6430
6935
  for (const name of CONFIG_CANDIDATES) {
6431
- const candidate = resolve11(cwd, name);
6432
- if (existsSync7(candidate))
6936
+ const candidate = resolve12(cwd, name);
6937
+ if (existsSync8(candidate))
6433
6938
  return candidate;
6434
6939
  }
6435
6940
  return null;
6436
6941
  }, fingerprintLocation = (cacheLocation, cwd) => {
6437
- const absolute = resolve11(cwd, cacheLocation);
6438
- return /[\\/]$/.test(cacheLocation) ? resolve11(absolute, CACHE_FINGERPRINT_SUFFIX.slice(1)) : `${absolute}${CACHE_FINGERPRINT_SUFFIX}`;
6942
+ const absolute = resolve12(cwd, cacheLocation);
6943
+ return /[\\/]$/.test(cacheLocation) ? resolve12(absolute, CACHE_FINGERPRINT_SUFFIX.slice(1)) : `${absolute}${CACHE_FINGERPRINT_SUFFIX}`;
6439
6944
  }, addFileToFingerprint = (hash, path, label) => {
6440
- if (!existsSync7(path))
6945
+ if (!existsSync8(path))
6441
6946
  return;
6442
6947
  hash.update(label);
6443
6948
  hash.update("\x00");
6444
- hash.update(readFileSync10(path));
6949
+ hash.update(readFileSync11(path));
6445
6950
  hash.update("\x00");
6446
6951
  }, packageNameFor = (specifier) => {
6447
6952
  if (specifier.startsWith("@"))
@@ -6451,7 +6956,7 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
6451
6956
  }, configPackageNames = (configPath2) => {
6452
6957
  if (!configPath2)
6453
6958
  return [];
6454
- const source = readFileSync10(configPath2, "utf-8");
6959
+ const source = readFileSync11(configPath2, "utf-8");
6455
6960
  const names = new Set;
6456
6961
  for (const match of source.matchAll(/(?:from\s+|import\s*(?:\(\s*)?|require\s*\(\s*)(['"])([^'".][^'"]*)\1/g)) {
6457
6962
  const [, , specifier] = match;
@@ -6470,11 +6975,11 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
6470
6975
  return Object.keys(value);
6471
6976
  });
6472
6977
  }, lintDependencyNames = (cwd, configPath2) => {
6473
- const manifestPath = resolve11(cwd, "package.json");
6474
- if (!existsSync7(manifestPath))
6978
+ const manifestPath = resolve12(cwd, "package.json");
6979
+ if (!existsSync8(manifestPath))
6475
6980
  return configPackageNames(configPath2);
6476
6981
  try {
6477
- const manifest = JSON.parse(readFileSync10(manifestPath, "utf-8"));
6982
+ const manifest = JSON.parse(readFileSync11(manifestPath, "utf-8"));
6478
6983
  const lintPackages = manifestDependencyNames(manifest).filter((name) => /eslint|typescript/.test(name));
6479
6984
  return [
6480
6985
  ...new Set([...lintPackages, ...configPackageNames(configPath2)])
@@ -6485,8 +6990,8 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
6485
6990
  }, findInstalledManifest = (cwd, dependency) => {
6486
6991
  let directory = cwd;
6487
6992
  while (true) {
6488
- const candidate = resolve11(directory, "node_modules", dependency, "package.json");
6489
- if (existsSync7(candidate))
6993
+ const candidate = resolve12(directory, "node_modules", dependency, "package.json");
6994
+ if (existsSync8(candidate))
6490
6995
  return candidate;
6491
6996
  const parent = dirname9(directory);
6492
6997
  if (parent === directory)
@@ -6508,7 +7013,7 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
6508
7013
  hash.update(`absolute-eslint-config:${CACHE_CONTRACT_VERSION}\x00`);
6509
7014
  const configPath2 = findEslintConfigPath(cwd);
6510
7015
  if (configPath2)
6511
- addFileToFingerprint(hash, configPath2, relative8(cwd, configPath2));
7016
+ addFileToFingerprint(hash, configPath2, relative9(cwd, configPath2));
6512
7017
  return hash.digest("hex");
6513
7018
  }, writeFingerprint = (path, fingerprint) => {
6514
7019
  mkdirSync5(dirname9(path), { recursive: true });
@@ -6518,10 +7023,10 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
6518
7023
  renameSync(temporary, path);
6519
7024
  }, prepareEslintCache = (options) => {
6520
7025
  const cwd = options.cwd ?? process.cwd();
6521
- const cachePath = resolve11(cwd, options.cacheLocation);
7026
+ const cachePath = resolve12(cwd, options.cacheLocation);
6522
7027
  const metadataPath = fingerprintLocation(options.cacheLocation, cwd);
6523
7028
  const fingerprint = options.fingerprint ?? createEslintCacheFingerprint(cwd);
6524
- const prior = existsSync7(metadataPath) ? readFileSync10(metadataPath, "utf-8").trim() : null;
7029
+ const prior = existsSync8(metadataPath) ? readFileSync11(metadataPath, "utf-8").trim() : null;
6525
7030
  if (prior === fingerprint)
6526
7031
  return false;
6527
7032
  rmSync3(cachePath, { force: true, recursive: true });
@@ -6609,7 +7114,7 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
6609
7114
  return;
6610
7115
  let source;
6611
7116
  try {
6612
- source = readFileSync10(configPath2, "utf-8");
7117
+ source = readFileSync11(configPath2, "utf-8");
6613
7118
  } catch {
6614
7119
  return;
6615
7120
  }
@@ -6648,7 +7153,7 @@ Detected at: ${configPath2}${reset}`);
6648
7153
  return `${minutes}m ${seconds}s`;
6649
7154
  }, handleClearCache = (cacheLocation, cwd = process.cwd()) => {
6650
7155
  try {
6651
- const cachePath = resolve11(cwd, cacheLocation);
7156
+ const cachePath = resolve12(cwd, cacheLocation);
6652
7157
  const metadataPath = fingerprintLocation(cacheLocation, cwd);
6653
7158
  rmSync3(cachePath, { force: true, recursive: true });
6654
7159
  rmSync3(metadataPath, { force: true, recursive: true });
@@ -6677,7 +7182,7 @@ Detected at: ${configPath2}${reset}`);
6677
7182
  return;
6678
7183
  }
6679
7184
  if (args.includes("--chunked")) {
6680
- if (!existsSync7(resolve11("node_modules", ".bin", "eslint"))) {
7185
+ if (!existsSync8(resolve12("node_modules", ".bin", "eslint"))) {
6681
7186
  console.error("\x1B[31m\u2717\x1B[0m ESLint is not installed in this project. Add it (and a flat `eslint.config.*`): bun add -d eslint");
6682
7187
  process.exit(1);
6683
7188
  }
@@ -6685,7 +7190,7 @@ Detected at: ${configPath2}${reset}`);
6685
7190
  await eslintChunked2(args);
6686
7191
  return;
6687
7192
  }
6688
- if (!existsSync7(resolve11("node_modules", ".bin", "eslint"))) {
7193
+ if (!existsSync8(resolve12("node_modules", ".bin", "eslint"))) {
6689
7194
  console.error("\x1B[31m\u2717\x1B[0m ESLint is not installed in this project. Add it (and a flat `eslint.config.*`): bun add -d eslint");
6690
7195
  process.exit(1);
6691
7196
  }
@@ -6876,8 +7381,8 @@ var isRecord4 = (value) => typeof value === "object" && value !== null, getIslan
6876
7381
  var init_islands = () => {};
6877
7382
 
6878
7383
  // src/build/islandEntries.ts
6879
- import { dirname as dirname10, extname, join as join18, relative as relative9, resolve as resolve13 } from "path";
6880
- import ts from "typescript";
7384
+ import { dirname as dirname10, extname as extname2, join as join19, relative as relative10, resolve as resolve14 } from "path";
7385
+ import ts2 from "typescript";
6881
7386
  var frameworks, isRecord5 = (value) => typeof value === "object" && value !== null, resolveRegistryExport = (mod) => {
6882
7387
  if (isRecord5(mod.islandRegistry))
6883
7388
  return mod.islandRegistry;
@@ -6888,9 +7393,9 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
6888
7393
  if (sourcePath.startsWith("file://")) {
6889
7394
  return new URL(sourcePath).pathname;
6890
7395
  }
6891
- return resolve13(dirname10(registryPath), sourcePath);
7396
+ return resolve14(dirname10(registryPath), sourcePath);
6892
7397
  }, getObjectPropertyName = (name) => {
6893
- if (ts.isIdentifier(name) || ts.isStringLiteral(name)) {
7398
+ if (ts2.isIdentifier(name) || ts2.isStringLiteral(name)) {
6894
7399
  return name.text;
6895
7400
  }
6896
7401
  return null;
@@ -6903,7 +7408,7 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
6903
7408
  });
6904
7409
  }, collectNamedImports = (imports, importClause, source) => {
6905
7410
  const bindings = importClause.namedBindings;
6906
- if (!bindings || !ts.isNamedImports(bindings))
7411
+ if (!bindings || !ts2.isNamedImports(bindings))
6907
7412
  return;
6908
7413
  for (const element of bindings.elements) {
6909
7414
  imports.set(element.name.text, {
@@ -6917,7 +7422,7 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
6917
7422
  const bindings = importClause.namedBindings;
6918
7423
  if (!bindings)
6919
7424
  return;
6920
- if (ts.isNamespaceImport(bindings)) {
7425
+ if (ts2.isNamespaceImport(bindings)) {
6921
7426
  registryNamespaceNames.add(bindings.name.text);
6922
7427
  return;
6923
7428
  }
@@ -6935,13 +7440,13 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
6935
7440
  const frameworkRegistry = registry2[framework] ?? {};
6936
7441
  registry2[framework] = frameworkRegistry;
6937
7442
  for (const property of frameworkNode.properties) {
6938
- if (!ts.isPropertyAssignment(property) && !ts.isShorthandPropertyAssignment(property))
7443
+ if (!ts2.isPropertyAssignment(property) && !ts2.isShorthandPropertyAssignment(property))
6939
7444
  continue;
6940
7445
  const componentName = getObjectPropertyName(property.name);
6941
7446
  if (!componentName)
6942
7447
  continue;
6943
- const initializer = ts.isPropertyAssignment(property) ? property.initializer : property.name;
6944
- if (!ts.isIdentifier(initializer))
7448
+ const initializer = ts2.isPropertyAssignment(property) ? property.initializer : property.name;
7449
+ if (!ts2.isIdentifier(initializer))
6945
7450
  continue;
6946
7451
  const reference = imports.get(initializer.text);
6947
7452
  if (!reference)
@@ -6955,7 +7460,7 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
6955
7460
  }
6956
7461
  }, processDefineIslandRegistry = (node, imports, definitions, registry2) => {
6957
7462
  const [firstArg] = node.arguments;
6958
- if (!firstArg || !ts.isObjectLiteralExpression(firstArg))
7463
+ if (!firstArg || !ts2.isObjectLiteralExpression(firstArg))
6959
7464
  return;
6960
7465
  const validFrameworks = [
6961
7466
  "react",
@@ -6964,7 +7469,7 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
6964
7469
  "angular"
6965
7470
  ];
6966
7471
  for (const property of firstArg.properties) {
6967
- if (!ts.isPropertyAssignment(property))
7472
+ if (!ts2.isPropertyAssignment(property))
6968
7473
  continue;
6969
7474
  const frameworkName = getObjectPropertyName(property.name);
6970
7475
  if (!frameworkName)
@@ -6972,28 +7477,28 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
6972
7477
  const framework = validFrameworks.find((f) => f === frameworkName);
6973
7478
  if (!framework)
6974
7479
  continue;
6975
- if (!ts.isObjectLiteralExpression(property.initializer))
7480
+ if (!ts2.isObjectLiteralExpression(property.initializer))
6976
7481
  continue;
6977
7482
  addRegistryEntries(property.initializer, framework, imports, definitions, registry2);
6978
7483
  }
6979
7484
  }, walkRegistryNode = (node, imports, registryFactoryNames, registryNamespaceNames, definitions, registry2) => {
6980
- if (ts.isCallExpression(node) && isDefineIslandRegistryCall(node.expression, registryFactoryNames, registryNamespaceNames)) {
7485
+ if (ts2.isCallExpression(node) && isDefineIslandRegistryCall(node.expression, registryFactoryNames, registryNamespaceNames)) {
6981
7486
  processDefineIslandRegistry(node, imports, definitions, registry2);
6982
7487
  }
6983
- ts.forEachChild(node, (child) => walkRegistryNode(child, imports, registryFactoryNames, registryNamespaceNames, definitions, registry2));
7488
+ ts2.forEachChild(node, (child) => walkRegistryNode(child, imports, registryFactoryNames, registryNamespaceNames, definitions, registry2));
6984
7489
  }, isDefineIslandRegistryCall = (expression, registryFactoryNames, registryNamespaceNames) => {
6985
- if (ts.isIdentifier(expression)) {
7490
+ if (ts2.isIdentifier(expression)) {
6986
7491
  return registryFactoryNames.has(expression.text);
6987
7492
  }
6988
- return ts.isPropertyAccessExpression(expression) && expression.name.text === "defineIslandRegistry" && ts.isIdentifier(expression.expression) && registryNamespaceNames.has(expression.expression.text);
7493
+ return ts2.isPropertyAccessExpression(expression) && expression.name.text === "defineIslandRegistry" && ts2.isIdentifier(expression.expression) && registryNamespaceNames.has(expression.expression.text);
6989
7494
  }, hasIslandRegistryNamedExport = (sourceFile) => {
6990
7495
  for (const statement of sourceFile.statements) {
6991
- if (ts.isVariableStatement(statement) && statement.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) && statement.declarationList.declarations.some((declaration) => ts.isIdentifier(declaration.name) && declaration.name.text === "islandRegistry")) {
7496
+ if (ts2.isVariableStatement(statement) && statement.modifiers?.some((modifier) => modifier.kind === ts2.SyntaxKind.ExportKeyword) && statement.declarationList.declarations.some((declaration) => ts2.isIdentifier(declaration.name) && declaration.name.text === "islandRegistry")) {
6992
7497
  return true;
6993
7498
  }
6994
- if (!ts.isExportDeclaration(statement) || !statement.exportClause)
7499
+ if (!ts2.isExportDeclaration(statement) || !statement.exportClause)
6995
7500
  continue;
6996
- if (!ts.isNamedExports(statement.exportClause))
7501
+ if (!ts2.isNamedExports(statement.exportClause))
6997
7502
  continue;
6998
7503
  if (statement.exportClause.elements.some((element) => element.name.text === "islandRegistry")) {
6999
7504
  return true;
@@ -7002,7 +7507,7 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
7002
7507
  return false;
7003
7508
  }, collectImportDeclarations = (sourceFile, registryPath, imports, registryFactoryNames, registryNamespaceNames) => {
7004
7509
  for (const statement of sourceFile.statements) {
7005
- if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier))
7510
+ if (!ts2.isImportDeclaration(statement) || !ts2.isStringLiteral(statement.moduleSpecifier))
7006
7511
  continue;
7007
7512
  const { importClause } = statement;
7008
7513
  if (!importClause)
@@ -7013,7 +7518,7 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
7013
7518
  collectRegistryHelperImports(importClause, statement.moduleSpecifier.text, registryFactoryNames, registryNamespaceNames);
7014
7519
  }
7015
7520
  }, parseIslandRegistryBuildInfo = (registrySource, registryPath) => {
7016
- const sourceFile = ts.createSourceFile(registryPath, registrySource, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
7521
+ const sourceFile = ts2.createSourceFile(registryPath, registrySource, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TS);
7017
7522
  const imports = new Map;
7018
7523
  const registryFactoryNames = new Set(["defineIslandRegistry"]);
7019
7524
  const registryNamespaceNames = new Set;
@@ -7045,7 +7550,7 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
7045
7550
  registry: registry2
7046
7551
  };
7047
7552
  }, loadIslandRegistryBuildInfo = async (registryPath) => {
7048
- const resolvedRegistryPath = resolve13(registryPath);
7553
+ const resolvedRegistryPath = resolve14(registryPath);
7049
7554
  const registrySource = Bun.file(resolvedRegistryPath);
7050
7555
  const registrySourceText = await registrySource.text();
7051
7556
  const parsedInfo = parseIslandRegistryBuildInfo(registrySourceText, resolvedRegistryPath);
@@ -7075,25 +7580,25 @@ var init_islandEntries = __esm(() => {
7075
7580
 
7076
7581
  // src/build/islandRegistryTransform.ts
7077
7582
  import { basename as basename6 } from "path";
7078
- import ts2 from "typescript";
7079
- var VALID_FRAMEWORKS, getObjectPropertyName2 = (name) => ts2.isIdentifier(name) || ts2.isStringLiteral(name) ? name.text : null, isIslandRegistryHelperImport2 = (source) => source === "@absolutejs/absolute/islands" || source.endsWith("/islands") || source.endsWith("/core/islands"), collectRegistryFactory = (sourceFile) => {
7583
+ import ts3 from "typescript";
7584
+ var VALID_FRAMEWORKS, getObjectPropertyName2 = (name) => ts3.isIdentifier(name) || ts3.isStringLiteral(name) ? name.text : null, isIslandRegistryHelperImport2 = (source) => source === "@absolutejs/absolute/islands" || source.endsWith("/islands") || source.endsWith("/core/islands"), collectRegistryFactory = (sourceFile) => {
7080
7585
  const factoryNames = new Set;
7081
7586
  const namespaceNames = new Set;
7082
7587
  for (const statement of sourceFile.statements) {
7083
- if (!ts2.isImportDeclaration(statement))
7588
+ if (!ts3.isImportDeclaration(statement))
7084
7589
  continue;
7085
- if (!ts2.isStringLiteral(statement.moduleSpecifier))
7590
+ if (!ts3.isStringLiteral(statement.moduleSpecifier))
7086
7591
  continue;
7087
7592
  if (!isIslandRegistryHelperImport2(statement.moduleSpecifier.text))
7088
7593
  continue;
7089
7594
  const bindings = statement.importClause?.namedBindings;
7090
7595
  if (!bindings)
7091
7596
  continue;
7092
- if (ts2.isNamespaceImport(bindings)) {
7597
+ if (ts3.isNamespaceImport(bindings)) {
7093
7598
  namespaceNames.add(bindings.name.text);
7094
7599
  continue;
7095
7600
  }
7096
- if (!ts2.isNamedImports(bindings))
7601
+ if (!ts3.isNamedImports(bindings))
7097
7602
  continue;
7098
7603
  for (const element of bindings.elements) {
7099
7604
  const imported = element.propertyName?.text ?? element.name.text;
@@ -7104,20 +7609,20 @@ var VALID_FRAMEWORKS, getObjectPropertyName2 = (name) => ts2.isIdentifier(name)
7104
7609
  }
7105
7610
  return { factoryNames, namespaceNames };
7106
7611
  }, isDefineIslandRegistryCall2 = (expression, factoryNames, namespaceNames) => {
7107
- if (ts2.isIdentifier(expression))
7612
+ if (ts3.isIdentifier(expression))
7108
7613
  return factoryNames.has(expression.text);
7109
- return ts2.isPropertyAccessExpression(expression) && expression.name.text === "defineIslandRegistry" && ts2.isIdentifier(expression.expression) && namespaceNames.has(expression.expression.text);
7614
+ return ts3.isPropertyAccessExpression(expression) && expression.name.text === "defineIslandRegistry" && ts3.isIdentifier(expression.expression) && namespaceNames.has(expression.expression.text);
7110
7615
  }, findDefineIslandRegistryCall = (sourceFile, factoryNames, namespaceNames) => {
7111
7616
  let found = null;
7112
7617
  const visit = (node) => {
7113
7618
  if (found)
7114
7619
  return;
7115
- const [firstArg] = ts2.isCallExpression(node) ? node.arguments : [];
7116
- if (ts2.isCallExpression(node) && isDefineIslandRegistryCall2(node.expression, factoryNames, namespaceNames) && firstArg && ts2.isObjectLiteralExpression(firstArg)) {
7620
+ const [firstArg] = ts3.isCallExpression(node) ? node.arguments : [];
7621
+ if (ts3.isCallExpression(node) && isDefineIslandRegistryCall2(node.expression, factoryNames, namespaceNames) && firstArg && ts3.isObjectLiteralExpression(firstArg)) {
7117
7622
  found = node;
7118
7623
  return;
7119
7624
  }
7120
- ts2.forEachChild(node, visit);
7625
+ ts3.forEachChild(node, visit);
7121
7626
  };
7122
7627
  visit(sourceFile);
7123
7628
  return found;
@@ -7127,8 +7632,8 @@ var VALID_FRAMEWORKS, getObjectPropertyName2 = (name) => ts2.isIdentifier(name)
7127
7632
  }, transformIslandRegistrySource = (source, filePath, info2) => {
7128
7633
  if (!source.includes("defineIslandRegistry"))
7129
7634
  return null;
7130
- const scriptKind = filePath.endsWith(".tsx") || filePath.endsWith(".jsx") ? ts2.ScriptKind.TSX : ts2.ScriptKind.TS;
7131
- const sourceFile = ts2.createSourceFile(filePath, source, ts2.ScriptTarget.Latest, true, scriptKind);
7635
+ const scriptKind = filePath.endsWith(".tsx") || filePath.endsWith(".jsx") ? ts3.ScriptKind.TSX : ts3.ScriptKind.TS;
7636
+ const sourceFile = ts3.createSourceFile(filePath, source, ts3.ScriptTarget.Latest, true, scriptKind);
7132
7637
  const { factoryNames, namespaceNames } = collectRegistryFactory(sourceFile);
7133
7638
  if (factoryNames.size === 0 && namespaceNames.size === 0)
7134
7639
  return null;
@@ -7136,7 +7641,7 @@ var VALID_FRAMEWORKS, getObjectPropertyName2 = (name) => ts2.isIdentifier(name)
7136
7641
  if (!call)
7137
7642
  return null;
7138
7643
  const [objectLiteral] = call.arguments;
7139
- if (!objectLiteral || !ts2.isObjectLiteralExpression(objectLiteral)) {
7644
+ if (!objectLiteral || !ts3.isObjectLiteralExpression(objectLiteral)) {
7140
7645
  return null;
7141
7646
  }
7142
7647
  const definitionLookup = new Map;
@@ -7151,20 +7656,20 @@ var VALID_FRAMEWORKS, getObjectPropertyName2 = (name) => ts2.isIdentifier(name)
7151
7656
  const edits = [];
7152
7657
  const replacedLocals = new Set;
7153
7658
  for (const frameworkProperty of objectLiteral.properties) {
7154
- if (!ts2.isPropertyAssignment(frameworkProperty))
7659
+ if (!ts3.isPropertyAssignment(frameworkProperty))
7155
7660
  continue;
7156
7661
  const frameworkName = getObjectPropertyName2(frameworkProperty.name);
7157
7662
  const framework = VALID_FRAMEWORKS.find((f) => f === frameworkName);
7158
7663
  if (!framework)
7159
7664
  continue;
7160
- if (!ts2.isObjectLiteralExpression(frameworkProperty.initializer))
7665
+ if (!ts3.isObjectLiteralExpression(frameworkProperty.initializer))
7161
7666
  continue;
7162
7667
  for (const componentProperty of frameworkProperty.initializer.properties) {
7163
7668
  let componentKey = null;
7164
7669
  let localName = null;
7165
7670
  let replaceNode = null;
7166
7671
  let replacementText = "";
7167
- if (ts2.isShorthandPropertyAssignment(componentProperty)) {
7672
+ if (ts3.isShorthandPropertyAssignment(componentProperty)) {
7168
7673
  componentKey = componentProperty.name.text;
7169
7674
  localName = componentProperty.name.text;
7170
7675
  const reference = definitionLookup.get(`${framework}:${componentKey}`);
@@ -7172,7 +7677,7 @@ var VALID_FRAMEWORKS, getObjectPropertyName2 = (name) => ts2.isIdentifier(name)
7172
7677
  continue;
7173
7678
  replaceNode = componentProperty;
7174
7679
  replacementText = `${quoteKey(componentKey)}: ${definitionLiteral(reference)}`;
7175
- } else if (ts2.isPropertyAssignment(componentProperty) && ts2.isIdentifier(componentProperty.initializer)) {
7680
+ } else if (ts3.isPropertyAssignment(componentProperty) && ts3.isIdentifier(componentProperty.initializer)) {
7176
7681
  componentKey = getObjectPropertyName2(componentProperty.name);
7177
7682
  localName = componentProperty.initializer.text;
7178
7683
  if (!componentKey)
@@ -7196,7 +7701,7 @@ var VALID_FRAMEWORKS, getObjectPropertyName2 = (name) => ts2.isIdentifier(name)
7196
7701
  if (edits.length === 0)
7197
7702
  return null;
7198
7703
  for (const statement of sourceFile.statements) {
7199
- if (!ts2.isImportDeclaration(statement))
7704
+ if (!ts3.isImportDeclaration(statement))
7200
7705
  continue;
7201
7706
  const clause = statement.importClause;
7202
7707
  if (!clause)
@@ -7205,11 +7710,11 @@ var VALID_FRAMEWORKS, getObjectPropertyName2 = (name) => ts2.isIdentifier(name)
7205
7710
  if (clause.name)
7206
7711
  localNames.push(clause.name.text);
7207
7712
  const bindings = clause.namedBindings;
7208
- if (bindings && ts2.isNamedImports(bindings)) {
7713
+ if (bindings && ts3.isNamedImports(bindings)) {
7209
7714
  for (const element of bindings.elements) {
7210
7715
  localNames.push(element.name.text);
7211
7716
  }
7212
- } else if (bindings && ts2.isNamespaceImport(bindings)) {
7717
+ } else if (bindings && ts3.isNamespaceImport(bindings)) {
7213
7718
  localNames.push(bindings.name.text);
7214
7719
  }
7215
7720
  if (localNames.length === 0)
@@ -7266,18 +7771,18 @@ var init_islandRegistryTransform = __esm(() => {
7266
7771
  });
7267
7772
 
7268
7773
  // src/build/bunStringRawUnicodePlugin.ts
7269
- import { extname as extname2 } from "path";
7270
- import ts3 from "typescript";
7774
+ import { extname as extname3 } from "path";
7775
+ import ts4 from "typescript";
7271
7776
  var NON_ASCII, getScriptKind = (filePath) => {
7272
7777
  if (/\.[cm]?tsx$/.test(filePath))
7273
- return ts3.ScriptKind.TSX;
7778
+ return ts4.ScriptKind.TSX;
7274
7779
  if (/\.[cm]?jsx$/.test(filePath))
7275
- return ts3.ScriptKind.JSX;
7780
+ return ts4.ScriptKind.JSX;
7276
7781
  if (/\.[cm]?ts$/.test(filePath))
7277
- return ts3.ScriptKind.TS;
7278
- return ts3.ScriptKind.JS;
7782
+ return ts4.ScriptKind.TS;
7783
+ return ts4.ScriptKind.JS;
7279
7784
  }, getLoader = (filePath) => {
7280
- const extension = extname2(filePath);
7785
+ const extension = extname3(filePath);
7281
7786
  if (extension === ".tsx")
7282
7787
  return "tsx";
7283
7788
  if (extension === ".jsx")
@@ -7286,24 +7791,24 @@ var NON_ASCII, getScriptKind = (filePath) => {
7286
7791
  return "ts";
7287
7792
  }
7288
7793
  return "js";
7289
- }, isStringRawTag = (node) => ts3.isPropertyAccessExpression(node.tag) && ts3.isIdentifier(node.tag.expression) && node.tag.expression.text === "String" && node.tag.name.text === "raw", getRawText = (node) => node.rawText ?? node.text, rewriteBunStringRawUnicode = (source, filePath = "input.ts") => {
7794
+ }, isStringRawTag = (node) => ts4.isPropertyAccessExpression(node.tag) && ts4.isIdentifier(node.tag.expression) && node.tag.expression.text === "String" && node.tag.name.text === "raw", getRawText = (node) => node.rawText ?? node.text, rewriteBunStringRawUnicode = (source, filePath = "input.ts") => {
7290
7795
  if (!source.includes("String.raw") || !NON_ASCII.test(source))
7291
7796
  return source;
7292
- const sourceFile = ts3.createSourceFile(filePath, source, ts3.ScriptTarget.Latest, true, getScriptKind(filePath));
7797
+ const sourceFile = ts4.createSourceFile(filePath, source, ts4.ScriptTarget.Latest, true, getScriptKind(filePath));
7293
7798
  const replacements = [];
7294
7799
  const visit = (node) => {
7295
- if (ts3.isTaggedTemplateExpression(node) && isStringRawTag(node)) {
7296
- const rawSegments = ts3.isNoSubstitutionTemplateLiteral(node.template) ? [getRawText(node.template)] : [
7800
+ if (ts4.isTaggedTemplateExpression(node) && isStringRawTag(node)) {
7801
+ const rawSegments = ts4.isNoSubstitutionTemplateLiteral(node.template) ? [getRawText(node.template)] : [
7297
7802
  getRawText(node.template.head),
7298
7803
  ...node.template.templateSpans.map((span) => getRawText(span.literal))
7299
7804
  ];
7300
7805
  if (rawSegments.some((segment) => NON_ASCII.test(segment))) {
7301
- const expressions = ts3.isTemplateExpression(node.template) ? node.template.templateSpans.map((span) => {
7806
+ const expressions = ts4.isTemplateExpression(node.template) ? node.template.templateSpans.map((span) => {
7302
7807
  const expression = source.slice(span.expression.getStart(sourceFile), span.expression.end);
7303
7808
  return rewriteBunStringRawUnicode(expression, filePath);
7304
7809
  }) : [];
7305
7810
  const args = [
7306
- `{ raw: [${rawSegments.map((text) => JSON.stringify(text)).join(", ")}] }`,
7811
+ `{ raw: [${rawSegments.map((text2) => JSON.stringify(text2)).join(", ")}] }`,
7307
7812
  ...expressions
7308
7813
  ];
7309
7814
  replacements.push({
@@ -7314,7 +7819,7 @@ var NON_ASCII, getScriptKind = (filePath) => {
7314
7819
  return;
7315
7820
  }
7316
7821
  }
7317
- ts3.forEachChild(node, visit);
7822
+ ts4.forEachChild(node, visit);
7318
7823
  };
7319
7824
  visit(sourceFile);
7320
7825
  let result = source;
@@ -7579,20 +8084,20 @@ var normalizeSlug = (str) => str.trim().replace(/\s+/g, "-").replace(/[^A-Za-z0-
7579
8084
  // src/mobile/buildRelease.ts
7580
8085
  import { createHash as createHash9 } from "crypto";
7581
8086
  import { mkdir as mkdir8, readFile as readFile9, writeFile as writeFile7 } from "fs/promises";
7582
- import { basename as basename7, dirname as dirname11, extname as extname3, join as join19, relative as relative10, resolve as resolve14 } from "path";
8087
+ import { basename as basename7, dirname as dirname11, extname as extname4, join as join20, relative as relative11, resolve as resolve15 } from "path";
7583
8088
  var sha256 = (bytes) => createHash9("sha256").update(bytes).digest("hex"), STATIC_SCRIPT_PATTERN, rewriteStaticScriptPaths = (source, manifest) => source.replace(STATIC_SCRIPT_PATTERN, (match, prefix, path, suffix) => {
7584
8089
  if (path.endsWith("/htmx.min.js"))
7585
8090
  return match;
7586
- const key = toPascal(basename7(path, extname3(path)));
8091
+ const key = toPascal(basename7(path, extname4(path)));
7587
8092
  const builtPath = manifest[key];
7588
8093
  return builtPath ? `${prefix}${builtPath}${suffix}` : match;
7589
8094
  }), readPageMetadata = (route) => parseAbsoluteMobileBuildPageMetadata(route.hooks?.detail?.[ABSOLUTE_MOBILE_ROUTE_DETAIL]), resolveAssetPath = (buildDirectory, assetPath) => {
7590
- const resolvedBuildDirectory = resolve14(buildDirectory);
7591
- const resolvedAsset = resolve14(assetPath);
8095
+ const resolvedBuildDirectory = resolve15(buildDirectory);
8096
+ const resolvedAsset = resolve15(assetPath);
7592
8097
  if (resolvedAsset.startsWith(`${resolvedBuildDirectory}/`)) {
7593
8098
  return resolvedAsset;
7594
8099
  }
7595
- return join19(buildDirectory, assetPath.replace(/^\/+/, ""));
8100
+ return join20(buildDirectory, assetPath.replace(/^\/+/, ""));
7596
8101
  }, pageFor = async (metadata, manifest, buildDirectory) => {
7597
8102
  const assetPath = manifest[metadata.bundleKey];
7598
8103
  if (!assetPath) {
@@ -7603,7 +8108,7 @@ var sha256 = (bytes) => createHash9("sha256").update(bytes).digest("hex"), STATI
7603
8108
  const source = await readFile9(resolvedAssetPath, "utf8");
7604
8109
  const rewritten = rewriteStaticScriptPaths(source, manifest);
7605
8110
  const documentHash = sha256(new TextEncoder().encode(rewritten));
7606
- resolvedAssetPath = join19(buildDirectory, ".absolutejs", "mobile-pages", `${documentHash}.html`);
8111
+ resolvedAssetPath = join20(buildDirectory, ".absolutejs", "mobile-pages", `${documentHash}.html`);
7607
8112
  await mkdir8(dirname11(resolvedAssetPath), { recursive: true });
7608
8113
  await writeFile7(resolvedAssetPath, rewritten);
7609
8114
  }
@@ -7617,8 +8122,8 @@ var sha256 = (bytes) => createHash9("sha256").update(bytes).digest("hex"), STATI
7617
8122
  readFile9(resolvedAssetPath),
7618
8123
  resolvedStylePath ? readFile9(resolvedStylePath) : undefined
7619
8124
  ]);
7620
- const bundlePath = `/${relative10(resolve14(buildDirectory), resolvedAssetPath).replaceAll("\\", "/")}`;
7621
- const styleBundlePath = resolvedStylePath ? `/${relative10(resolve14(buildDirectory), resolvedStylePath).replaceAll("\\", "/")}` : undefined;
8125
+ const bundlePath = `/${relative11(resolve15(buildDirectory), resolvedAssetPath).replaceAll("\\", "/")}`;
8126
+ const styleBundlePath = resolvedStylePath ? `/${relative11(resolve15(buildDirectory), resolvedStylePath).replaceAll("\\", "/")}` : undefined;
7622
8127
  return {
7623
8128
  bundleHash: sha256(bytes),
7624
8129
  bundlePath,
@@ -7819,40 +8324,40 @@ import {
7819
8324
  rm as rm6,
7820
8325
  writeFile as writeFile8
7821
8326
  } from "fs/promises";
7822
- import { existsSync as existsSync9 } from "fs";
7823
- import { basename as basename8, dirname as dirname12, extname as extname4, join as join20, relative as relative11, resolve as resolve15 } from "path";
8327
+ import { existsSync as existsSync10 } from "fs";
8328
+ import { basename as basename8, dirname as dirname12, extname as extname5, join as join21, relative as relative12, resolve as resolve16 } from "path";
7824
8329
  var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-mobile-bootstrap.js", INDEX_FILE = "index.html", CLIENT_CSS_DEPENDENCY_PATTERN, CLIENT_MARKUP_DEPENDENCY_PATTERN, CAPACITOR_CLIENT_FRAMEWORKS, CLIENT_ASSET_DIRECTORIES, errorHasCode = (error, code) => typeof error === "object" && error !== null && Reflect.get(error, "code") === code, shellBootstrapModule = () => {
7825
- const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellBootstrap.${extension}`)).find(existsSync9);
8330
+ const candidate = ["js", "ts"].map((extension) => join21(import.meta.dir, `shellBootstrap.${extension}`)).find(existsSync10);
7826
8331
  if (candidate)
7827
8332
  return candidate;
7828
8333
  throw new TypeError("AbsoluteJS mobile shell bootstrap module is missing.");
7829
8334
  }, shellAuthModule = () => {
7830
- const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellAuth.${extension}`)).find(existsSync9);
8335
+ const candidate = ["js", "ts"].map((extension) => join21(import.meta.dir, `shellAuth.${extension}`)).find(existsSync10);
7831
8336
  if (candidate)
7832
8337
  return candidate;
7833
8338
  throw new TypeError("AbsoluteJS mobile auth shell module is missing.");
7834
8339
  }, shellExpoAuthModule = () => {
7835
- const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellExpoAuth.${extension}`)).find(existsSync9);
8340
+ const candidate = ["js", "ts"].map((extension) => join21(import.meta.dir, `shellExpoAuth.${extension}`)).find(existsSync10);
7836
8341
  if (candidate)
7837
8342
  return candidate;
7838
8343
  throw new TypeError("AbsoluteJS Expo auth bridge module is missing.");
7839
8344
  }, shellSyncModule = () => {
7840
- const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellSync.${extension}`)).find(existsSync9);
8345
+ const candidate = ["js", "ts"].map((extension) => join21(import.meta.dir, `shellSync.${extension}`)).find(existsSync10);
7841
8346
  if (candidate)
7842
8347
  return candidate;
7843
8348
  throw new TypeError("AbsoluteJS mobile Sync shell module is missing.");
7844
8349
  }, shellExpoSyncModule = () => {
7845
- const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellExpoSync.${extension}`)).find(existsSync9);
8350
+ const candidate = ["js", "ts"].map((extension) => join21(import.meta.dir, `shellExpoSync.${extension}`)).find(existsSync10);
7846
8351
  if (candidate)
7847
8352
  return candidate;
7848
8353
  throw new TypeError("AbsoluteJS Expo Sync bridge module is missing.");
7849
8354
  }, shellPushModule = () => {
7850
- const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellPush.${extension}`)).find(existsSync9);
8355
+ const candidate = ["js", "ts"].map((extension) => join21(import.meta.dir, `shellPush.${extension}`)).find(existsSync10);
7851
8356
  if (candidate)
7852
8357
  return candidate;
7853
8358
  throw new TypeError("AbsoluteJS mobile push shell module is missing.");
7854
8359
  }, shellExpoDevicesModule = () => {
7855
- const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellExpoDevices.${extension}`)).find(existsSync9);
8360
+ const candidate = ["js", "ts"].map((extension) => join21(import.meta.dir, `shellExpoDevices.${extension}`)).find(existsSync10);
7856
8361
  if (candidate)
7857
8362
  return candidate;
7858
8363
  throw new TypeError("AbsoluteJS Expo device bridge module is missing.");
@@ -7883,8 +8388,8 @@ var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-
7883
8388
  </body>
7884
8389
  </html>
7885
8390
  `, sourceAssetPath = (buildDirectory, bundlePath) => {
7886
- const root = resolve15(buildDirectory);
7887
- const asset = resolve15(root, bundlePath.replace(/^\/+/, ""));
8391
+ const root = resolve16(buildDirectory);
8392
+ const asset = resolve16(root, bundlePath.replace(/^\/+/, ""));
7888
8393
  if (!asset.startsWith(`${root}/`)) {
7889
8394
  throw new TypeError("Mobile page bundle escaped the build directory.");
7890
8395
  }
@@ -7899,15 +8404,15 @@ var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-
7899
8404
  const segments = specifier.split("/");
7900
8405
  const packageName = specifier.startsWith("@") ? segments.slice(0, 2).join("/") : segments[0] ?? "";
7901
8406
  const subpath = specifier.slice(packageName.length);
7902
- const packageDirectory = join20(resolve15(projectRoot), "node_modules", packageName);
7903
- const manifest = JSON.parse(await readFile10(join20(packageDirectory, "package.json"), "utf8"));
8407
+ const packageDirectory = join21(resolve16(projectRoot), "node_modules", packageName);
8408
+ const manifest = JSON.parse(await readFile10(join21(packageDirectory, "package.json"), "utf8"));
7904
8409
  const exports = typeof manifest === "object" && manifest !== null ? Reflect.get(manifest, "exports") : undefined;
7905
8410
  const entry = typeof exports === "object" && exports !== null ? Reflect.get(exports, subpath ? `.${subpath}` : ".") : undefined;
7906
8411
  const target = importEntryTarget(entry);
7907
8412
  if (typeof target !== "string" || !target.startsWith("./"))
7908
8413
  throw new TypeError(`${specifier} does not publish an import entry.`);
7909
- const resolved = resolve15(packageDirectory, target);
7910
- if (!resolved.startsWith(`${resolve15(packageDirectory)}/`))
8414
+ const resolved = resolve16(packageDirectory, target);
8415
+ if (!resolved.startsWith(`${resolve16(packageDirectory)}/`))
7911
8416
  throw new TypeError(`${specifier} has an unsafe import entry.`);
7912
8417
  return resolved;
7913
8418
  }, buildShellBootstrap = async (staging, auth, sync, storagePrefix, engine, deviceCapabilities, projectRoot) => {
@@ -7936,10 +8441,10 @@ var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-
7936
8441
  const absoluteMobilePushCapability = absoluteDeviceCapability${pushIndex}(absoluteMobilePush.capabilityOptions);
7937
8442
  ` : "";
7938
8443
  const capabilityOptions = shellCapabilities.map((name, index) => `${JSON.stringify(name)}: ${name === "pushNotifications" ? "absoluteMobilePushCapability" : `absoluteDeviceCapability${index}()`}`).join(", ");
7939
- const entryPath = join20(staging, ".absolute-mobile-entry.ts");
8444
+ const entryPath = join21(staging, ".absolute-mobile-entry.ts");
7940
8445
  const baseAdapterModule = capacitor ? await resolveProjectImport(projectRoot, "@absolutejs/devices-capacitor") : shellExpoDevicesModule();
7941
8446
  const adapterImport = capacitor ? `import { installCapacitorDeviceAdapterIfNative } from ${JSON.stringify(baseAdapterModule)};` : `import { createAbsoluteExpoBridgeFetch, installAbsoluteExpoWebDeviceAdapter } from ${JSON.stringify(baseAdapterModule)};`;
7942
- const adapterInstall = capacitor ? `installCapacitorDeviceAdapterIfNative({ storagePrefix: ${JSON.stringify(storagePrefix)}${capabilityOptions ? `, ${capabilityOptions}` : ""} });` : "installAbsoluteExpoWebDeviceAdapter();";
8447
+ const adapterInstall = capacitor ? `installCapacitorDeviceAdapterIfNative({ storagePrefix: ${JSON.stringify(storagePrefix)}${capabilityOptions ? `, ${capabilityOptions}` : ""} });` : `installAbsoluteExpoWebDeviceAdapter(${JSON.stringify(deviceCapabilities.capabilities)});`;
7943
8448
  let shellOptions = auth ? options : "{ createFetch: createAbsoluteExpoBridgeFetch }";
7944
8449
  if (capacitor)
7945
8450
  shellOptions = options;
@@ -7961,7 +8466,7 @@ void startAbsoluteMobileShell(${shellOptions});
7961
8466
  if (!build.success || build.outputs.length !== 1) {
7962
8467
  throw new AggregateError(build.logs, "Failed to build the AbsoluteJS Capacitor shell.");
7963
8468
  }
7964
- await rename7(build.outputs[0]?.path ?? "", join20(staging, BOOTSTRAP_FILE));
8469
+ await rename7(build.outputs[0]?.path ?? "", join21(staging, BOOTSTRAP_FILE));
7965
8470
  await rm6(entryPath, { force: true });
7966
8471
  }, removePreviousBundle = async (backup, moved) => {
7967
8472
  if (!moved)
@@ -7992,20 +8497,20 @@ void startAbsoluteMobileShell(${shellOptions});
7992
8497
  if (!CAPACITOR_CLIENT_FRAMEWORKS.has(page.framework)) {
7993
8498
  throw new TypeError(`Capacitor client rendering does not yet support ${page.framework} page ${page.pageId}.`);
7994
8499
  }
7995
- const extension = extname4(page.bundlePath) || ".js";
8500
+ const extension = extname5(page.bundlePath) || ".js";
7996
8501
  const localBundlePath = `./pages/${page.bundleHash}${extension}`;
7997
8502
  const source = sourceAssetPath(buildDirectory, page.bundlePath);
7998
- await copyFile4(source, join20(staging, localBundlePath));
8503
+ await copyFile4(source, join21(staging, localBundlePath));
7999
8504
  await copyAbsoluteClientDependencies(source, buildDirectory, staging, copiedDependencies);
8000
8505
  let localStylePath;
8001
8506
  if (page.styleBundlePath && page.styleBundleHash) {
8002
- const styleExtension = extname4(page.styleBundlePath) || ".css";
8507
+ const styleExtension = extname5(page.styleBundlePath) || ".css";
8003
8508
  localStylePath = `./styles/${page.styleBundleHash}${styleExtension}`;
8004
8509
  const styleSource = sourceAssetPath(buildDirectory, page.styleBundlePath);
8005
- await mkdir9(dirname12(join20(staging, localStylePath)), {
8510
+ await mkdir9(dirname12(join21(staging, localStylePath)), {
8006
8511
  recursive: true
8007
8512
  });
8008
- await copyFile4(styleSource, join20(staging, localStylePath));
8513
+ await copyFile4(styleSource, join21(staging, localStylePath));
8009
8514
  await copyAbsoluteClientDependencies(styleSource, buildDirectory, staging, copiedDependencies);
8010
8515
  }
8011
8516
  return {
@@ -8015,7 +8520,7 @@ void startAbsoluteMobileShell(${shellOptions});
8015
8520
  };
8016
8521
  }, absoluteClientImports = async (sourcePath, buildDirectory) => {
8017
8522
  const source = await readFile10(sourcePath, "utf8");
8018
- const extension = extname4(sourcePath).toLowerCase();
8523
+ const extension = extname5(sourcePath).toLowerCase();
8019
8524
  let scriptLoader;
8020
8525
  if (extension === ".tsx")
8021
8526
  scriptLoader = "tsx";
@@ -8037,9 +8542,9 @@ void startAbsoluteMobileShell(${shellOptions});
8037
8542
  const clean = specifier.split(/[?#]/u, 1)[0] ?? specifier;
8038
8543
  if (clean.startsWith("/"))
8039
8544
  return [clean];
8040
- const resolved = resolve15(dirname12(sourcePath), clean);
8041
- const root = resolve15(buildDirectory);
8042
- const relativePath = relative11(root, resolved).replaceAll("\\", "/");
8545
+ const resolved = resolve16(dirname12(sourcePath), clean);
8546
+ const root = resolve16(buildDirectory);
8547
+ const relativePath = relative12(root, resolved).replaceAll("\\", "/");
8043
8548
  if (relativePath === ".." || relativePath.startsWith("../")) {
8044
8549
  throw new TypeError(`Mobile client dependency escaped the build directory: ${specifier}`);
8045
8550
  }
@@ -8050,7 +8555,7 @@ void startAbsoluteMobileShell(${shellOptions});
8050
8555
  return;
8051
8556
  copied.add(specifier);
8052
8557
  const source = sourceAssetPath(buildDirectory, specifier);
8053
- const destination = join20(staging, specifier.replace(/^\/+/, ""));
8558
+ const destination = join21(staging, specifier.replace(/^\/+/, ""));
8054
8559
  await mkdir9(dirname12(destination), { recursive: true });
8055
8560
  await copyFile4(source, destination);
8056
8561
  await copyAbsoluteClientDependencies(source, buildDirectory, staging, copied);
@@ -8063,14 +8568,14 @@ void startAbsoluteMobileShell(${shellOptions});
8063
8568
  }
8064
8569
  const destination = options.config.bundleDirectory;
8065
8570
  await mkdir9(dirname12(destination), { recursive: true });
8066
- const staging = await mkdtemp4(join20(dirname12(destination), `.${basename8(destination)}.stage-`));
8571
+ const staging = await mkdtemp4(join21(dirname12(destination), `.${basename8(destination)}.stage-`));
8067
8572
  try {
8068
- const pageDirectory = join20(staging, "pages");
8573
+ const pageDirectory = join21(staging, "pages");
8069
8574
  await mkdir9(pageDirectory, { recursive: true });
8070
8575
  await Promise.all(CLIENT_ASSET_DIRECTORIES.map((directory) => ({
8071
- destination: join20(staging, directory),
8072
- source: join20(options.buildDirectory, directory)
8073
- })).filter(({ source }) => existsSync9(source)).map(({ destination: assetDestination, source }) => cp3(source, assetDestination, { recursive: true })));
8576
+ destination: join21(staging, directory),
8577
+ source: join21(options.buildDirectory, directory)
8578
+ })).filter(({ source }) => existsSync10(source)).map(({ destination: assetDestination, source }) => cp3(source, assetDestination, { recursive: true })));
8074
8579
  const copiedDependencies = new Set;
8075
8580
  const pages = await Promise.all(options.artifact.pages.map((page) => copyClientPage(page, options.buildDirectory, staging, copiedDependencies)));
8076
8581
  const manifest = {
@@ -8103,9 +8608,9 @@ void startAbsoluteMobileShell(${shellOptions});
8103
8608
  } : {}
8104
8609
  };
8105
8610
  await Promise.all([
8106
- writeFile8(join20(staging, MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
8611
+ writeFile8(join21(staging, MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
8107
8612
  `),
8108
- writeFile8(join20(staging, INDEX_FILE), indexHtml(options.config.appName, options.config.productionOrigin)),
8613
+ writeFile8(join21(staging, INDEX_FILE), indexHtml(options.config.appName, options.config.productionOrigin)),
8109
8614
  buildShellBootstrap(staging, options.auth !== undefined, options.auth !== undefined && options.sync === true, `absolutejs.${options.auth?.clientId ?? options.config.appId}.`, options.config.engine, options.deviceCapabilities, options.projectRoot)
8110
8615
  ]);
8111
8616
  await installBundle(staging, destination);
@@ -8161,7 +8666,7 @@ import {
8161
8666
  rm as rm7,
8162
8667
  writeFile as writeFile9
8163
8668
  } from "fs/promises";
8164
- import { dirname as dirname13, join as join21, resolve as resolvePath3 } from "path";
8669
+ import { dirname as dirname13, join as join22, resolve as resolvePath3 } from "path";
8165
8670
  var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "current.json", BUNDLES_DIRECTORY = "bundles", ARTIFACT_FILE = "artifact.json", BUNDLE_ID_PATTERN, isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), errorHasCode2 = (error, code) => typeof error === "object" && error !== null && Reflect.get(error, "code") === code, bundleIdFor = (currentReleaseId, releases) => {
8166
8671
  const identity = JSON.stringify({
8167
8672
  currentReleaseId,
@@ -8191,16 +8696,16 @@ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "curre
8191
8696
  releases
8192
8697
  };
8193
8698
  }, writeRelease = async (root, release) => {
8194
- const directory = join21(root, release.artifact.releaseId);
8195
- const producerPath = join21(directory, release.artifact.producer.module);
8699
+ const directory = join22(root, release.artifact.releaseId);
8700
+ const producerPath = join22(directory, release.artifact.producer.module);
8196
8701
  await mkdir10(dirname13(producerPath), { recursive: true });
8197
8702
  await Promise.all([
8198
- writeFile9(join21(directory, ARTIFACT_FILE), `${JSON.stringify(release.artifact, null, "\t")}
8703
+ writeFile9(join22(directory, ARTIFACT_FILE), `${JSON.stringify(release.artifact, null, "\t")}
8199
8704
  `),
8200
8705
  writeFile9(producerPath, new Uint8Array(await release.producer.arrayBuffer()))
8201
8706
  ]);
8202
8707
  }, installImmutableBundle = async (bundlesRoot, bundleId, releases) => {
8203
- const destination = join21(bundlesRoot, bundleId);
8708
+ const destination = join22(bundlesRoot, bundleId);
8204
8709
  try {
8205
8710
  await access8(destination);
8206
8711
  return destination;
@@ -8208,7 +8713,7 @@ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "curre
8208
8713
  if (!errorHasCode2(error, "ENOENT"))
8209
8714
  throw error;
8210
8715
  }
8211
- const staging = await mkdtemp5(join21(bundlesRoot, ".stage-"));
8716
+ const staging = await mkdtemp5(join22(bundlesRoot, ".stage-"));
8212
8717
  try {
8213
8718
  await Promise.all(releases.map((release) => writeRelease(staging, release)));
8214
8719
  await rename8(staging, destination);
@@ -8237,7 +8742,7 @@ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "curre
8237
8742
  return release;
8238
8743
  });
8239
8744
  const root = resolvePath3(input.root);
8240
- const bundlesRoot = join21(root, BUNDLES_DIRECTORY);
8745
+ const bundlesRoot = join22(root, BUNDLES_DIRECTORY);
8241
8746
  await mkdir10(bundlesRoot, { recursive: true });
8242
8747
  const bundleId = bundleIdFor(input.currentReleaseId, artifacts);
8243
8748
  await installImmutableBundle(bundlesRoot, bundleId, orderedReleases);
@@ -8247,8 +8752,8 @@ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "curre
8247
8752
  format: ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT,
8248
8753
  releases: artifacts
8249
8754
  };
8250
- const pointerPath = join21(root, CURRENT_BUNDLE_FILE);
8251
- const temporaryPointerPath = join21(root, `.current-${crypto.randomUUID()}.json`);
8755
+ const pointerPath = join22(root, CURRENT_BUNDLE_FILE);
8756
+ const temporaryPointerPath = join22(root, `.current-${crypto.randomUUID()}.json`);
8252
8757
  await writeFile9(temporaryPointerPath, `${JSON.stringify(index, null, "\t")}
8253
8758
  `, { flag: "wx" });
8254
8759
  await rename8(temporaryPointerPath, pointerPath);
@@ -8256,12 +8761,12 @@ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "curre
8256
8761
  }, readAbsoluteMobileMaterializedReleases = async (root) => {
8257
8762
  const resolvedRoot = resolvePath3(root);
8258
8763
  try {
8259
- const serialized = await readFile11(join21(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
8764
+ const serialized = await readFile11(join22(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
8260
8765
  const parsed = JSON.parse(serialized);
8261
8766
  const index = parseBundleIndex(parsed);
8262
- const bundleRoot = join21(resolvedRoot, BUNDLES_DIRECTORY, index.bundleId);
8767
+ const bundleRoot = join22(resolvedRoot, BUNDLES_DIRECTORY, index.bundleId);
8263
8768
  return Promise.all(index.releases.map(async (artifact) => {
8264
- const producer = Bun.file(join21(bundleRoot, artifact.releaseId, artifact.producer.module));
8769
+ const producer = Bun.file(join22(bundleRoot, artifact.releaseId, artifact.producer.module));
8265
8770
  await verifyAbsoluteMobileCompatibilityProducer({
8266
8771
  artifact,
8267
8772
  producer
@@ -8280,261 +8785,6 @@ var init_materializedBundle = __esm(() => {
8280
8785
  BUNDLE_ID_PATTERN = /^amb_[a-f0-9]{64}$/;
8281
8786
  });
8282
8787
 
8283
- // src/mobile/deviceCapabilities.ts
8284
- import { readFileSync as readFileSync12 } from "fs";
8285
- import { extname as extname5, join as join22, relative as relative12, resolve as resolve16 } from "path";
8286
- import ts4 from "typescript";
8287
- var DEVICES_PACKAGE = "@absolutejs/devices", CAPACITOR_ADAPTER = "@absolutejs/devices-capacitor", SOURCE_GLOB, IGNORED_DIRECTORIES, IDENTIFIER_PATTERN, CAPACITOR_MODULE_PATTERN, CAPACITOR_PACKAGE_PATTERN, ANDROID_PERMISSION_PATTERN, IOS_USAGE_DESCRIPTIONS, IOS_PRIVACY_ACCESSED_API_REASONS, IOS_PRIVACY_ACCESSED_APIS, object2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), readJson = (path) => {
8288
- const value = JSON.parse(readFileSync12(path, "utf8"));
8289
- if (!object2(value))
8290
- throw new TypeError(`${path} must contain an object.`);
8291
- return value;
8292
- }, text = (value, field) => {
8293
- if (typeof value !== "string" || value.length === 0)
8294
- throw new TypeError(`${field} must be a non-empty string.`);
8295
- return value;
8296
- }, androidPermissions = (value, field) => {
8297
- if (value === undefined)
8298
- return;
8299
- if (!object2(value))
8300
- throw new TypeError(`${field} must be an object.`);
8301
- const { permissions } = value;
8302
- if (!Array.isArray(permissions) || !permissions.every((permission) => typeof permission === "string" && ANDROID_PERMISSION_PATTERN.test(permission)))
8303
- throw new TypeError(`${field}.permissions must contain Android permission names.`);
8304
- return [...permissions];
8305
- }, iosPrivacyAccessedApis = (value, field) => {
8306
- if (value === undefined)
8307
- return;
8308
- if (!object2(value))
8309
- throw new TypeError(`${field} must be an object.`);
8310
- const privacy = {};
8311
- for (const api of IOS_PRIVACY_ACCESSED_APIS) {
8312
- const reasons = value[api];
8313
- if (reasons === undefined)
8314
- continue;
8315
- const supported = IOS_PRIVACY_ACCESSED_API_REASONS[api];
8316
- if (!Array.isArray(reasons) || reasons.length === 0 || !reasons.every((reason) => typeof reason === "string" && supported.has(reason)))
8317
- throw new TypeError(`${field} contains an unsupported API or reason.`);
8318
- privacy[api] = [...reasons];
8319
- }
8320
- if (Object.keys(value).some((api) => !IOS_PRIVACY_ACCESSED_APIS.some((known) => known === api)))
8321
- throw new TypeError(`${field} contains an unsupported API or reason.`);
8322
- return privacy;
8323
- }, iosNativeRequirements = (value, field) => {
8324
- if (value === undefined)
8325
- return;
8326
- if (!object2(value))
8327
- throw new TypeError(`${field} must be an object.`);
8328
- const {
8329
- privacyAccessedApis,
8330
- pushNotifications,
8331
- systemBars,
8332
- usageDescriptions
8333
- } = value;
8334
- if (pushNotifications !== undefined && pushNotifications !== true)
8335
- throw new TypeError(`${field}.pushNotifications must be true.`);
8336
- if (systemBars !== undefined && systemBars !== true)
8337
- throw new TypeError(`${field}.systemBars must be true.`);
8338
- if (usageDescriptions !== undefined && (!Array.isArray(usageDescriptions) || !usageDescriptions.every((purpose) => typeof purpose === "string" && IOS_USAGE_DESCRIPTIONS.has(purpose))))
8339
- throw new TypeError(`${field}.usageDescriptions contains an unsupported purpose.`);
8340
- const privacy = iosPrivacyAccessedApis(privacyAccessedApis, `${field}.privacyAccessedApis`);
8341
- return {
8342
- ...privacy === undefined ? {} : { privacyAccessedApis: privacy },
8343
- ...pushNotifications === true ? { pushNotifications: true } : {},
8344
- ...systemBars === true ? { systemBars: true } : {},
8345
- ...usageDescriptions === undefined ? {} : { usageDescriptions: [...usageDescriptions] }
8346
- };
8347
- }, parseProvider = (name, value) => {
8348
- if (!IDENTIFIER_PATTERN.test(name))
8349
- throw new TypeError("Device capability names must be identifiers.");
8350
- if (!object2(value))
8351
- throw new TypeError(`Device capability ${name} must be an object.`);
8352
- const factory = text(value.factory, `${name}.factory`);
8353
- const module = text(value.module, `${name}.module`);
8354
- if (!IDENTIFIER_PATTERN.test(factory))
8355
- throw new TypeError(`${name}.factory must be a JavaScript identifier.`);
8356
- if (!CAPACITOR_MODULE_PATTERN.test(module))
8357
- throw new TypeError(`${name}.module must be an official devices-capacitor subpath.`);
8358
- if (!Array.isArray(value.packages) || !value.packages.every((spec) => typeof spec === "string" && CAPACITOR_PACKAGE_PATTERN.test(spec)))
8359
- throw new TypeError(`${name}.packages must contain exact official Capacitor package versions.`);
8360
- let native;
8361
- const { native: nativeMetadata } = value;
8362
- if (nativeMetadata !== undefined) {
8363
- if (!object2(nativeMetadata))
8364
- throw new TypeError(`${name}.native must be an object.`);
8365
- const { android, ios } = nativeMetadata;
8366
- const permissions = androidPermissions(android, `${name}.native.android`);
8367
- const iosRequirements = iosNativeRequirements(ios, `${name}.native.ios`);
8368
- native = {
8369
- ...permissions === undefined ? {} : { android: { permissions } },
8370
- ...iosRequirements === undefined ? {} : { ios: iosRequirements }
8371
- };
8372
- }
8373
- return {
8374
- factory,
8375
- module,
8376
- ...native === undefined ? {} : { native },
8377
- packages: [...value.packages]
8378
- };
8379
- }, absoluteDeviceNativeRequirements = (plan) => {
8380
- const privacy = plan.capabilities.reduce((requirements, name) => {
8381
- for (const api of IOS_PRIVACY_ACCESSED_APIS) {
8382
- const reasons = plan.providers[name]?.native?.ios?.privacyAccessedApis?.[api] ?? [];
8383
- if (reasons.length === 0)
8384
- continue;
8385
- const current = requirements[api] ?? new Set;
8386
- for (const reason of reasons)
8387
- current.add(reason);
8388
- requirements[api] = current;
8389
- }
8390
- return requirements;
8391
- }, {});
8392
- return {
8393
- androidPermissions: [
8394
- ...new Set(plan.capabilities.flatMap((name) => plan.providers[name]?.native?.android?.permissions ?? []))
8395
- ].sort(),
8396
- iosPrivacyAccessedApis: IOS_PRIVACY_ACCESSED_APIS.flatMap((api) => {
8397
- const reasons = privacy[api];
8398
- return reasons ? [{ api, reasons: [...reasons].sort() }] : [];
8399
- }),
8400
- iosPushNotifications: plan.capabilities.some((name) => plan.providers[name]?.native?.ios?.pushNotifications === true),
8401
- iosSystemBars: plan.capabilities.some((name) => plan.providers[name]?.native?.ios?.systemBars === true),
8402
- iosUsageDescriptions: [
8403
- ...new Set(plan.capabilities.flatMap((name) => plan.providers[name]?.native?.ios?.usageDescriptions ?? []))
8404
- ].sort()
8405
- };
8406
- }, loadAbsoluteDeviceCapabilityProviders = (projectRoot) => {
8407
- const path = join22(resolve16(projectRoot), "node_modules", CAPACITOR_ADAPTER, "package.json");
8408
- const manifest = readJson(path);
8409
- const { absolutejs } = manifest;
8410
- const devices = object2(absolutejs) ? absolutejs.devices : undefined;
8411
- if (!object2(devices) || devices.format !== 1 || devices.provider !== "capacitor" || !object2(devices.capabilities))
8412
- throw new TypeError(`${CAPACITOR_ADAPTER} does not publish supported capability metadata.`);
8413
- const entries = Object.entries(devices.capabilities).map(([name, provider]) => ({
8414
- name,
8415
- provider: parseProvider(name, provider)
8416
- }));
8417
- return Object.fromEntries(entries.sort((left, right) => left.name.localeCompare(right.name)).map(({ name, provider }) => [name, provider]));
8418
- }, isIgnored2 = (path) => path.split("/").some((segment) => IGNORED_DIRECTORIES.has(segment)), importedCapabilities = (source, file) => {
8419
- const names = new Set;
8420
- const namespaces = new Set;
8421
- const visit = (node) => {
8422
- if (ts4.isImportDeclaration(node) && ts4.isStringLiteral(node.moduleSpecifier) && node.moduleSpecifier.text === DEVICES_PACKAGE && !node.importClause?.isTypeOnly) {
8423
- const bindings = node.importClause?.namedBindings;
8424
- if (bindings && ts4.isNamedImports(bindings)) {
8425
- for (const element of bindings.elements)
8426
- if (!element.isTypeOnly)
8427
- names.add((element.propertyName ?? element.name).text);
8428
- }
8429
- if (bindings && ts4.isNamespaceImport(bindings))
8430
- namespaces.add(bindings.name.text);
8431
- }
8432
- if (ts4.isExportDeclaration(node) && !node.isTypeOnly && node.moduleSpecifier !== undefined && ts4.isStringLiteral(node.moduleSpecifier) && node.moduleSpecifier.text === DEVICES_PACKAGE && node.exportClause && ts4.isNamedExports(node.exportClause)) {
8433
- for (const element of node.exportClause.elements)
8434
- if (!element.isTypeOnly)
8435
- names.add((element.propertyName ?? element.name).text);
8436
- }
8437
- if (ts4.isPropertyAccessExpression(node) && ts4.isIdentifier(node.expression) && namespaces.has(node.expression.text))
8438
- names.add(node.name.text);
8439
- ts4.forEachChild(node, visit);
8440
- };
8441
- const extension = extname5(file).toLowerCase();
8442
- const sources = extension === ".svelte" || extension === ".vue" ? [...source.matchAll(/<script\b[^>]*>([\s\S]*?)<\/script\s*>/giu)].map((match) => match[1]).filter((value) => value !== undefined) : [source];
8443
- for (const [index, script] of sources.entries())
8444
- visit(ts4.createSourceFile(`${file}#script-${index}`, script, ts4.ScriptTarget.Latest, true, ts4.ScriptKind.TSX));
8445
- return names;
8446
- }, assertAbsoluteDeviceCapabilityPackages = (projectRoot, plan) => {
8447
- const missing = missingAbsoluteDeviceCapabilityPackages(plan, directAbsoluteProjectPackages(projectRoot));
8448
- const mismatched = plan.requiredPackages.filter((spec) => {
8449
- const separator = spec.lastIndexOf("@");
8450
- const packageName = spec.slice(0, separator);
8451
- if (missing.includes(spec))
8452
- return false;
8453
- try {
8454
- return readJson(join22(resolve16(projectRoot), "node_modules", packageName, "package.json")).version !== spec.slice(separator + 1);
8455
- } catch {
8456
- return true;
8457
- }
8458
- });
8459
- const unmet = [...missing, ...mismatched];
8460
- if (unmet.length > 0)
8461
- throw new TypeError(`Device capabilities ${plan.capabilities.join(", ")} require ${unmet.join(", ")}. Run absolute mobile sync and approve the detected capability plugins.`);
8462
- }, directAbsoluteProjectPackages = (projectRoot) => {
8463
- const manifest = readJson(join22(resolve16(projectRoot), "package.json"));
8464
- const packages = new Set;
8465
- for (const field of ["dependencies", "devDependencies"]) {
8466
- const dependencies = manifest[field];
8467
- if (object2(dependencies))
8468
- for (const name of Object.keys(dependencies))
8469
- packages.add(name);
8470
- }
8471
- return packages;
8472
- }, discoverAbsoluteDeviceCapabilities = (projectRoot, providers = loadAbsoluteDeviceCapabilityProviders(projectRoot)) => {
8473
- const root = resolve16(projectRoot);
8474
- const known = new Set(Object.keys(providers));
8475
- const capabilities = new Set;
8476
- for (const path of SOURCE_GLOB.scanSync({ cwd: root })) {
8477
- const portable = relative12(root, resolve16(root, path)).replaceAll("\\", "/");
8478
- if (isIgnored2(portable))
8479
- continue;
8480
- const source = readFileSync12(resolve16(root, portable), "utf8");
8481
- for (const name of importedCapabilities(source, portable))
8482
- if (known.has(name))
8483
- capabilities.add(name);
8484
- }
8485
- return [...capabilities].sort();
8486
- }, missingAbsoluteDeviceCapabilityPackages = (plan, directPackages) => plan.requiredPackages.filter((spec) => {
8487
- const packageName = spec.slice(0, spec.lastIndexOf("@"));
8488
- return !directPackages.has(packageName);
8489
- }), resolveAbsoluteDeviceCapabilityPlan = (projectRoot) => {
8490
- const allProviders = loadAbsoluteDeviceCapabilityProviders(projectRoot);
8491
- const capabilities = discoverAbsoluteDeviceCapabilities(projectRoot, allProviders);
8492
- const providers = {};
8493
- for (const name of capabilities) {
8494
- const provider = allProviders[name];
8495
- if (provider)
8496
- providers[name] = provider;
8497
- }
8498
- return {
8499
- capabilities,
8500
- providers,
8501
- requiredPackages: [
8502
- ...new Set(capabilities.flatMap((name) => providers[name]?.packages ?? []))
8503
- ].sort()
8504
- };
8505
- };
8506
- var init_deviceCapabilities = __esm(() => {
8507
- SOURCE_GLOB = new Bun.Glob("**/*.{js,jsx,ts,tsx,svelte,vue}");
8508
- IGNORED_DIRECTORIES = new Set([
8509
- ".absolutejs",
8510
- ".git",
8511
- ".test-builds",
8512
- ".test-shards",
8513
- "build",
8514
- "dist",
8515
- "node_modules",
8516
- "test",
8517
- "tests"
8518
- ]);
8519
- IDENTIFIER_PATTERN = /^[A-Za-z_$][\w$]*$/u;
8520
- CAPACITOR_MODULE_PATTERN = /^@absolutejs\/devices-capacitor\/[a-z][a-z0-9-]*$/u;
8521
- CAPACITOR_PACKAGE_PATTERN = /^@capacitor\/[a-z][a-z0-9-]*@\d+\.\d+\.\d+$/u;
8522
- ANDROID_PERMISSION_PATTERN = /^android\.permission\.[A-Z][A-Z0-9_]*$/u;
8523
- IOS_USAGE_DESCRIPTIONS = new Set([
8524
- "camera",
8525
- "location-always",
8526
- "location-when-in-use",
8527
- "photo-library",
8528
- "photo-library-add"
8529
- ]);
8530
- IOS_PRIVACY_ACCESSED_API_REASONS = {
8531
- NSPrivacyAccessedAPICategoryFileTimestamp: new Set(["C617.1"])
8532
- };
8533
- IOS_PRIVACY_ACCESSED_APIS = [
8534
- "NSPrivacyAccessedAPICategoryFileTimestamp"
8535
- ];
8536
- });
8537
-
8538
8788
  // src/mobile/buildPipeline.ts
8539
8789
  import { readFile as readFile12 } from "fs/promises";
8540
8790
  import { join as join23, resolve as resolve17 } from "path";
@@ -8606,11 +8856,8 @@ var isElysiaApp = (value) => typeof value === "object" && value !== null && type
8606
8856
  const auth = resolveAbsoluteMobileAuthManifest(options.projectRoot, mobile);
8607
8857
  const sync = auth !== undefined && projectUsesAbsoluteSync(options.projectRoot);
8608
8858
  const syncSchema = sync ? discoverAbsoluteSyncSchema(options.projectRoot) : undefined;
8609
- const deviceCapabilities = resolveAbsoluteDeviceCapabilityPlan(options.projectRoot);
8859
+ const deviceCapabilities = resolveAbsoluteDeviceCapabilityPlan(options.projectRoot, mobile.engine);
8610
8860
  const usesPush = deviceCapabilities.capabilities.includes("pushNotifications");
8611
- if (mobile.engine === "expo" && deviceCapabilities.capabilities.some((capability) => capability !== "haptics")) {
8612
- throw new TypeError("Experimental Expo builds currently bridge only @absolutejs/devices haptics. Other detected device capabilities require their Expo adapters.");
8613
- }
8614
8861
  if (usesPush && !auth)
8615
8862
  throw new TypeError("Portable push notifications require @absolutejs/auth so provider tokens can be registered without exposing identity controls to page code.");
8616
8863
  if (usesPush && !loaded.app.routes.some((route) => route.path === "/auth/push" || route.path === "/auth/mobile/push"))
@@ -8663,10 +8910,10 @@ var init_buildPipeline = __esm(() => {
8663
8910
  });
8664
8911
 
8665
8912
  // src/mobile/routeMetadataTransform.ts
8666
- import { existsSync as existsSync10, readFileSync as readFileSync13 } from "fs";
8913
+ import { existsSync as existsSync11, readFileSync as readFileSync13 } from "fs";
8667
8914
  import { dirname as dirname14, extname as extname6, relative as relative13, resolve as resolve18 } from "path";
8668
8915
  import ts5 from "typescript";
8669
- var ROUTE_METHODS, SOURCE_FILTER, PAGE_HANDLERS, posixPath = (value) => value.replace(/\\/g, "/"), findTsconfig = (entry, projectRoot) => ts5.findConfigFile(dirname14(entry), existsSync10, "tsconfig.json") ?? ts5.findConfigFile(projectRoot, existsSync10, "tsconfig.json"), createProgram = (entry, projectRoot) => {
8916
+ var ROUTE_METHODS, SOURCE_FILTER, PAGE_HANDLERS, posixPath = (value) => value.replace(/\\/g, "/"), findTsconfig = (entry, projectRoot) => ts5.findConfigFile(dirname14(entry), existsSync11, "tsconfig.json") ?? ts5.findConfigFile(projectRoot, existsSync11, "tsconfig.json"), createProgram = (entry, projectRoot) => {
8670
8917
  const configPath2 = findTsconfig(entry, projectRoot);
8671
8918
  if (!configPath2) {
8672
8919
  return ts5.createProgram([entry], {
@@ -9934,7 +10181,7 @@ var init_rewriteImports = __esm(() => {
9934
10181
 
9935
10182
  // src/cli/scripts/start.ts
9936
10183
  var {env: env2 } = globalThis.Bun;
9937
- import { existsSync as existsSync11, readFileSync as readFileSync15, rmSync as rmSync4 } from "fs";
10184
+ import { existsSync as existsSync12, readFileSync as readFileSync15, rmSync as rmSync4 } from "fs";
9938
10185
  import { basename as basename9, join as join26, resolve as resolve21 } from "path";
9939
10186
  var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`, resolvePackageVersion = (candidates) => {
9940
10187
  for (const candidate of candidates) {
@@ -9992,7 +10239,7 @@ var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
9992
10239
  resolve21(import.meta.dir, "..", "..", "..", "src", "react", "jsxDevRuntimeCompat.ts")
9993
10240
  ];
9994
10241
  for (const candidate of candidates) {
9995
- if (existsSync11(candidate))
10242
+ if (existsSync12(candidate))
9996
10243
  return candidate;
9997
10244
  }
9998
10245
  return resolve21(import.meta.dir, "..", "..", "react", "jsxDevRuntimeCompat.js");
@@ -10029,7 +10276,7 @@ var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
10029
10276
  serverEntry,
10030
10277
  totalDuration
10031
10278
  }) => {
10032
- const usesDocker = existsSync11(resolve21(COMPOSE_PATH));
10279
+ const usesDocker = existsSync12(resolve21(COMPOSE_PATH));
10033
10280
  const scripts = usesDocker ? await readDbScripts() : null;
10034
10281
  if (scripts)
10035
10282
  await startDatabase(scripts);
@@ -10140,7 +10387,7 @@ var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
10140
10387
  ].filter((val) => Boolean(val));
10141
10388
  const outputPath = resolve21(resolvedOutdir, `${entryName}.js`);
10142
10389
  if (options.prebuilt) {
10143
- if (!existsSync11(outputPath)) {
10390
+ if (!existsSync12(outputPath)) {
10144
10391
  throw new Error(`Prepared production server not found: ${outputPath}`);
10145
10392
  }
10146
10393
  return runPreparedServer({
@@ -10267,11 +10514,11 @@ var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
10267
10514
  if (!serverBundle.success) {
10268
10515
  handleBundleFailure(serverBundle, bundleStart, serverEntry);
10269
10516
  }
10270
- if (!existsSync11(outputPath)) {
10517
+ if (!existsSync12(outputPath)) {
10271
10518
  console.error(cliTag2("\x1B[31m", `Expected output not found: ${outputPath}`));
10272
10519
  process.exit(1);
10273
10520
  }
10274
- if (existsSync11(resolve21(resolvedOutdir, "angular", "vendor", "server"))) {
10521
+ if (existsSync12(resolve21(resolvedOutdir, "angular", "vendor", "server"))) {
10275
10522
  const { readdirSync: readdirSync2 } = await import("fs");
10276
10523
  const vendorDir = resolve21(resolvedOutdir, "angular", "vendor", "server");
10277
10524
  const vendorEntries = readdirSync2(vendorDir).filter((fileName) => fileName.endsWith(".js"));
@@ -10470,11 +10717,11 @@ var exports_build = {};
10470
10717
  __export(exports_build, {
10471
10718
  build: () => build
10472
10719
  });
10473
- import { existsSync as existsSync13, readdirSync as readdirSync3, readFileSync as readFileSync17 } from "fs";
10720
+ import { existsSync as existsSync14, readdirSync as readdirSync3, readFileSync as readFileSync17 } from "fs";
10474
10721
  import { join as join27, resolve as resolve23 } from "path";
10475
10722
  var PROFILE_TOP = 15, PROFILE_COL = 8, FRAMEWORK_KEYS, cliTag3 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`, printProfile = (buildDir) => {
10476
10723
  const traceDir = join27(buildDir, ".absolute-trace");
10477
- if (!existsSync13(traceDir))
10724
+ if (!existsSync14(traceDir))
10478
10725
  return;
10479
10726
  const files = readdirSync3(traceDir).filter((file) => file.endsWith(".json")).sort();
10480
10727
  const latest = files[files.length - 1];
@@ -10573,7 +10820,7 @@ import {
10573
10820
  verify
10574
10821
  } from "crypto";
10575
10822
  import {
10576
- existsSync as existsSync14,
10823
+ existsSync as existsSync15,
10577
10824
  lstatSync,
10578
10825
  mkdirSync as mkdirSync8,
10579
10826
  mkdtempSync,
@@ -10773,7 +11020,7 @@ var DEFAULT_PROOF_LOCATION = ".absolutejs/lint-proof.json", PROOF_CONTRACT_VERSI
10773
11020
  const cwd = options.cwd ?? process.cwd();
10774
11021
  const proofLocation = options.proofLocation ?? DEFAULT_PROOF_LOCATION;
10775
11022
  const path = resolve24(cwd, proofLocation);
10776
- if (!existsSync14(path))
11023
+ if (!existsSync15(path))
10777
11024
  return { reason: `missing lint proof: ${proofLocation}`, valid: false };
10778
11025
  let proof;
10779
11026
  try {
@@ -10890,7 +11137,7 @@ var init_lintProof = __esm(() => {
10890
11137
  // src/build/scanConventions.ts
10891
11138
  import { basename as basename10 } from "path";
10892
11139
  var {Glob: Glob2 } = globalThis.Bun;
10893
- import { existsSync as existsSync15 } from "fs";
11140
+ import { existsSync as existsSync16 } from "fs";
10894
11141
  var CONVENTION_RE, classifyFile = (file, pageFiles, defaults, pages) => {
10895
11142
  const fileName = basename10(file);
10896
11143
  const match = CONVENTION_RE.exec(fileName);
@@ -10915,7 +11162,7 @@ var CONVENTION_RE, classifyFile = (file, pageFiles, defaults, pages) => {
10915
11162
  else if (kind === "loading")
10916
11163
  pages[pageName].loading = file;
10917
11164
  }, scanConventions = async (pagesDir, pattern) => {
10918
- if (!existsSync15(pagesDir)) {
11165
+ if (!existsSync16(pagesDir)) {
10919
11166
  const pageFiles2 = [];
10920
11167
  return { conventions: undefined, pageFiles: pageFiles2 };
10921
11168
  }
@@ -10942,7 +11189,7 @@ var exports_ls = {};
10942
11189
  __export(exports_ls, {
10943
11190
  runLs: () => runLs
10944
11191
  });
10945
- import { existsSync as existsSync16, readFileSync as readFileSync19, statSync } from "fs";
11192
+ import { existsSync as existsSync17, readFileSync as readFileSync19, statSync } from "fs";
10946
11193
  import { basename as basename11, extname as extname7, join as join28, relative as relative15 } from "path";
10947
11194
  var DEFAULT_BUILD_DIR = "build", LABEL_ORDER, ARTIFACT_SUFFIXES, FRAMEWORK_FIELDS, readStringField = (source, key) => {
10948
11195
  const value = Reflect.get(source, key);
@@ -10993,10 +11240,10 @@ var DEFAULT_BUILD_DIR = "build", LABEL_ORDER, ARTIFACT_SUFFIXES, FRAMEWORK_FIELD
10993
11240
  return pages ? [{ label, pages: sortPages(pages) }] : [];
10994
11241
  });
10995
11242
  }, resolveDiskPath = (buildDir, value) => {
10996
- if (existsSync16(value))
11243
+ if (existsSync17(value))
10997
11244
  return value;
10998
11245
  const underBuild = join28(buildDir, value);
10999
- if (existsSync16(underBuild))
11246
+ if (existsSync17(underBuild))
11000
11247
  return underBuild;
11001
11248
  return join28(process.cwd(), value);
11002
11249
  }, fileSize = (diskPath) => {
@@ -11124,7 +11371,7 @@ ${colors.dim}${frameworkCount} ${frameworkCount === 1 ? "framework" : "framework
11124
11371
  }
11125
11372
  const sizesDir = resolveSizesDir(args, candidates);
11126
11373
  const manifestPath = join28(sizesDir, "manifest.json");
11127
- if (!existsSync16(manifestPath)) {
11374
+ if (!existsSync17(manifestPath)) {
11128
11375
  printDim(`No build at ${relativeOrSelf(manifestPath)}. Run \`absolute build\` first, or pass \`--outdir <dir>\`.`);
11129
11376
  return;
11130
11377
  }
@@ -11974,7 +12221,7 @@ var exports_heapDiff = {};
11974
12221
  __export(exports_heapDiff, {
11975
12222
  runHeapDiff: () => runHeapDiff
11976
12223
  });
11977
- import { existsSync as existsSync17, readFileSync as readFileSync20 } from "fs";
12224
+ import { existsSync as existsSync18, readFileSync as readFileSync20 } from "fs";
11978
12225
  var TOP = 15, STRING_TYPES, aggregate = (path) => {
11979
12226
  const data = JSON.parse(readFileSync20(path, "utf-8"));
11980
12227
  const { nodes, strings } = data;
@@ -12005,7 +12252,7 @@ var TOP = 15, STRING_TYPES, aggregate = (path) => {
12005
12252
  return;
12006
12253
  }
12007
12254
  for (const path of [beforePath, afterPath]) {
12008
- if (existsSync17(path))
12255
+ if (existsSync18(path))
12009
12256
  continue;
12010
12257
  process.stdout.write(`${colors.red}No such file: ${path}${colors.reset}
12011
12258
  `);
@@ -12126,7 +12373,7 @@ var isRecord9 = (value) => typeof value === "object" && value !== null && !Array
12126
12373
  // src/cli/config/schema/fromType.ts
12127
12374
  import ts6 from "typescript";
12128
12375
  import {
12129
- existsSync as existsSync18,
12376
+ existsSync as existsSync19,
12130
12377
  mkdirSync as mkdirSync9,
12131
12378
  readFileSync as readFileSync21,
12132
12379
  statSync as statSync2,
@@ -12321,7 +12568,7 @@ export { value };
12321
12568
  const cached = cache.get(cacheKey);
12322
12569
  if (cached)
12323
12570
  return cached;
12324
- const local = specifier === "@absolutejs/absolute" && isFrameworkRepo(cwd) && existsSync18(resolve25(cwd, "types/index.ts"));
12571
+ const local = specifier === "@absolutejs/absolute" && isFrameworkRepo(cwd) && existsSync19(resolve25(cwd, "types/index.ts"));
12325
12572
  const signature = cacheSignature(cwd, typeName, local, specifier);
12326
12573
  const fromDisk = readDiskCache(cwd, typeName, signature, specifier);
12327
12574
  if (fromDisk) {
@@ -12349,16 +12596,16 @@ var init_fromType = __esm(() => {
12349
12596
 
12350
12597
  // src/cli/config/absolute/resolveAbsoluteConfig.ts
12351
12598
  import ts7 from "typescript";
12352
- import { existsSync as existsSync19, readFileSync as readFileSync22 } from "fs";
12599
+ import { existsSync as existsSync20, readFileSync as readFileSync22 } from "fs";
12353
12600
  import { resolve as resolve26 } from "path";
12354
12601
  var CONFIG_CANDIDATES2, RUNTIME_FIELDS, findConfigPath = (cwd, override) => {
12355
12602
  if (override) {
12356
12603
  const resolved = resolve26(cwd, override);
12357
- return existsSync19(resolved) ? resolved : null;
12604
+ return existsSync20(resolved) ? resolved : null;
12358
12605
  }
12359
12606
  for (const name of CONFIG_CANDIDATES2) {
12360
12607
  const candidate = resolve26(cwd, name);
12361
- if (existsSync19(candidate))
12608
+ if (existsSync20(candidate))
12362
12609
  return candidate;
12363
12610
  }
12364
12611
  return null;
@@ -12682,7 +12929,7 @@ var emptyOutcome = () => ({
12682
12929
 
12683
12930
  // src/cli/generate/routeWiring.ts
12684
12931
  import ts8 from "typescript";
12685
- import { existsSync as existsSync20, readFileSync as readFileSync23, readdirSync as readdirSync4, writeFileSync as writeFileSync9 } from "fs";
12932
+ import { existsSync as existsSync21, readFileSync as readFileSync23, readdirSync as readdirSync4, writeFileSync as writeFileSync9 } from "fs";
12686
12933
  import { dirname as dirname18, join as join30 } from "path";
12687
12934
  var DEFAULT_SEPARATOR = `
12688
12935
  `, BOUNDARY_USE, applyEdits = (text2, edits) => {
@@ -12831,13 +13078,13 @@ ${newLines.join(`
12831
13078
  return lines.join(`
12832
13079
  `);
12833
13080
  }, hasChain = (path) => {
12834
- if (!existsSync20(path))
13081
+ if (!existsSync21(path))
12835
13082
  return false;
12836
13083
  const sourceFile = parse2(path, readFileSync23(path, "utf-8"));
12837
13084
  const found = findElysiaNew(sourceFile);
12838
13085
  return found !== null;
12839
13086
  }, firstChainFile = (pluginsDir) => {
12840
- if (!existsSync20(pluginsDir))
13087
+ if (!existsSync21(pluginsDir))
12841
13088
  return null;
12842
13089
  for (const name of readdirSync4(pluginsDir)) {
12843
13090
  if (!name.endsWith(".ts"))
@@ -12940,7 +13187,7 @@ var init_routeWiring = __esm(() => {
12940
13187
  });
12941
13188
 
12942
13189
  // src/cli/generate/generateApi.ts
12943
- import { existsSync as existsSync21, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
13190
+ import { existsSync as existsSync22, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
12944
13191
  import { dirname as dirname19, join as join31 } from "path";
12945
13192
  var apiPluginTemplate = (pluginName, base) => `import { Elysia } from 'elysia';
12946
13193
 
@@ -12955,7 +13202,7 @@ export const ${pluginName} = new Elysia()
12955
13202
  const outcome = { ...emptyOutcome(), route: base };
12956
13203
  const pluginsDir = join31(dirname19(project.serverEntry), "plugins");
12957
13204
  const fileAbs = join31(pluginsDir, `${pluginName}.ts`);
12958
- if (existsSync21(fileAbs)) {
13205
+ if (existsSync22(fileAbs)) {
12959
13206
  outcome.notes.push(`${pluginName} already exists at ${fileAbs} \u2014 skipped.`);
12960
13207
  return outcome;
12961
13208
  }
@@ -13028,7 +13275,7 @@ var init_componentTemplates = __esm(() => {
13028
13275
  });
13029
13276
 
13030
13277
  // src/cli/generate/generateComponent.ts
13031
- import { existsSync as existsSync22, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "fs";
13278
+ import { existsSync as existsSync23, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "fs";
13032
13279
  import { dirname as dirname20, join as join32 } from "path";
13033
13280
  var generateComponent = (project, framework, rawName) => {
13034
13281
  const def = frameworks6[framework];
@@ -13041,7 +13288,7 @@ var generateComponent = (project, framework, rawName) => {
13041
13288
  return outcome;
13042
13289
  }
13043
13290
  const fileAbs = join32(frameworkDir, "components", def.componentFile({ kebab, pascal }));
13044
- if (existsSync22(fileAbs)) {
13291
+ if (existsSync23(fileAbs)) {
13045
13292
  outcome.notes.push(`${pascal} already exists at ${fileAbs} \u2014 skipped.`);
13046
13293
  return outcome;
13047
13294
  }
@@ -13061,7 +13308,7 @@ var init_generateComponent = __esm(() => {
13061
13308
 
13062
13309
  // src/cli/generate/cssStrategy.ts
13063
13310
  import ts9 from "typescript";
13064
- import { existsSync as existsSync23 } from "fs";
13311
+ import { existsSync as existsSync24 } from "fs";
13065
13312
  import { join as join33 } from "path";
13066
13313
  var CSS_SUFFIX = "CSS", SHARED_MIN_USES = 2, DEFAULT_CSS = `main {
13067
13314
  margin: 0 auto;
@@ -13109,7 +13356,7 @@ var CSS_SUFFIX = "CSS", SHARED_MIN_USES = 2, DEFAULT_CSS = `main {
13109
13356
  return {
13110
13357
  assetKey: sharedKey,
13111
13358
  contents: DEFAULT_CSS,
13112
- create: !existsSync23(cssFileAbs2),
13359
+ create: !existsSync24(cssFileAbs2),
13113
13360
  cssFileAbs: cssFileAbs2,
13114
13361
  shared: true
13115
13362
  };
@@ -13118,7 +13365,7 @@ var CSS_SUFFIX = "CSS", SHARED_MIN_USES = 2, DEFAULT_CSS = `main {
13118
13365
  return {
13119
13366
  assetKey: `${pascal}${CSS_SUFFIX}`,
13120
13367
  contents: DEFAULT_CSS,
13121
- create: !existsSync23(cssFileAbs),
13368
+ create: !existsSync24(cssFileAbs),
13122
13369
  cssFileAbs,
13123
13370
  shared: false
13124
13371
  };
@@ -13127,7 +13374,7 @@ var init_cssStrategy = () => {};
13127
13374
 
13128
13375
  // src/cli/generate/navData.ts
13129
13376
  import ts10 from "typescript";
13130
- import { existsSync as existsSync24, mkdirSync as mkdirSync12, readFileSync as readFileSync24, writeFileSync as writeFileSync12 } from "fs";
13377
+ import { existsSync as existsSync25, mkdirSync as mkdirSync12, readFileSync as readFileSync24, writeFileSync as writeFileSync12 } from "fs";
13131
13378
  import { dirname as dirname21 } from "path";
13132
13379
  var NAV_DATA_TEMPLATE = `type NavItem = {
13133
13380
  href: string;
@@ -13166,7 +13413,7 @@ export const navData: NavItem[] = [];
13166
13413
  }
13167
13414
  return items;
13168
13415
  }, readNavItems = (navDataPath) => {
13169
- if (!existsSync24(navDataPath))
13416
+ if (!existsSync25(navDataPath))
13170
13417
  return [];
13171
13418
  const text2 = readFileSync24(navDataPath, "utf-8");
13172
13419
  const sourceFile = ts10.createSourceFile(navDataPath, text2, ts10.ScriptTarget.Latest, true);
@@ -13203,7 +13450,7 @@ ${indentOf(text2, array.getStart(sourceFile))}`;
13203
13450
  ${indent}${entry}`;
13204
13451
  return text2.slice(0, insertAt) + insertion + text2.slice(insertAt);
13205
13452
  }, upsertNavItem = (navDataPath, item) => {
13206
- const created = !existsSync24(navDataPath);
13453
+ const created = !existsSync25(navDataPath);
13207
13454
  if (created) {
13208
13455
  mkdirSync12(dirname21(navDataPath), { recursive: true });
13209
13456
  writeFileSync12(navDataPath, NAV_DATA_TEMPLATE, "utf-8");
@@ -13369,7 +13616,7 @@ var init_pageTemplates = __esm(() => {
13369
13616
 
13370
13617
  // src/cli/generate/generatePage.ts
13371
13618
  import {
13372
- existsSync as existsSync25,
13619
+ existsSync as existsSync26,
13373
13620
  mkdirSync as mkdirSync13,
13374
13621
  readFileSync as readFileSync25,
13375
13622
  readdirSync as readdirSync5,
@@ -13382,7 +13629,7 @@ var writeNew = (path, contents) => {
13382
13629
  }, toHref = (fromDir, toFile) => {
13383
13630
  const rel = relative17(fromDir, toFile).split("\\").join("/");
13384
13631
  return rel.startsWith(".") ? rel : `./${rel}`;
13385
- }, staticPageFiles = (project) => ["html", "htmx"].map((key) => project.frameworkDirs[key]).map((dir) => dir ? join34(dir, "pages") : null).filter((pagesDir) => pagesDir !== null && existsSync25(pagesDir)).flatMap((pagesDir) => readdirSync5(pagesDir).filter((name) => name.endsWith(".html")).map((name) => join34(pagesDir, name))), resyncPage = (file, items) => {
13632
+ }, staticPageFiles = (project) => ["html", "htmx"].map((key) => project.frameworkDirs[key]).map((dir) => dir ? join34(dir, "pages") : null).filter((pagesDir) => pagesDir !== null && existsSync26(pagesDir)).flatMap((pagesDir) => readdirSync5(pagesDir).filter((name) => name.endsWith(".html")).map((name) => join34(pagesDir, name))), resyncPage = (file, items) => {
13386
13633
  const html = readFileSync25(file, "utf-8");
13387
13634
  const synced = syncStaticNav(html, items);
13388
13635
  if (synced === null || synced === html)
@@ -13411,7 +13658,7 @@ var writeNew = (path, contents) => {
13411
13658
  return outcome;
13412
13659
  }
13413
13660
  const pageFileAbs = join34(frameworkDir, "pages", def.pageFile({ kebab, pascal }));
13414
- if (existsSync25(pageFileAbs)) {
13661
+ if (existsSync26(pageFileAbs)) {
13415
13662
  outcome.notes.push(`${pascal} already exists at ${pageFileAbs} \u2014 skipped.`);
13416
13663
  return outcome;
13417
13664
  }
@@ -13797,11 +14044,11 @@ var init_catalog = __esm(() => {
13797
14044
  });
13798
14045
 
13799
14046
  // src/cli/integrations/addPlugin.ts
13800
- import { existsSync as existsSync26, readFileSync as readFileSync27 } from "fs";
14047
+ import { existsSync as existsSync27, readFileSync as readFileSync27 } from "fs";
13801
14048
  import { join as join35 } from "path";
13802
14049
  var isRecord11 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), readPackageJson = (cwd) => {
13803
14050
  const path = join35(cwd, "package.json");
13804
- if (!existsSync26(path))
14051
+ if (!existsSync27(path))
13805
14052
  return null;
13806
14053
  try {
13807
14054
  const parsed = JSON.parse(readFileSync27(path, "utf-8"));
@@ -14296,16 +14543,16 @@ var init_authCatalog = __esm(() => {
14296
14543
 
14297
14544
  // src/cli/config/auth/resolveAuthSettings.ts
14298
14545
  import ts12 from "typescript";
14299
- import { existsSync as existsSync27, readFileSync as readFileSync28 } from "fs";
14546
+ import { existsSync as existsSync28, readFileSync as readFileSync28 } from "fs";
14300
14547
  import { resolve as resolve28 } from "path";
14301
14548
  var AUTH_PACKAGE = "@absolutejs/auth", CONFIG_CANDIDATES3, findAuthSettingsPath = (cwd, override) => {
14302
14549
  if (override) {
14303
14550
  const resolved = resolve28(cwd, override);
14304
- return existsSync27(resolved) ? resolved : null;
14551
+ return existsSync28(resolved) ? resolved : null;
14305
14552
  }
14306
14553
  for (const name of CONFIG_CANDIDATES3) {
14307
14554
  const candidate = resolve28(cwd, name);
14308
- if (existsSync27(candidate))
14555
+ if (existsSync28(candidate))
14309
14556
  return candidate;
14310
14557
  }
14311
14558
  return null;
@@ -14401,10 +14648,10 @@ var init_resolveAuthSettings = __esm(() => {
14401
14648
 
14402
14649
  // src/cli/config/auth/resolveAuthState.ts
14403
14650
  import ts13 from "typescript";
14404
- import { existsSync as existsSync28, readdirSync as readdirSync6, readFileSync as readFileSync29 } from "fs";
14651
+ import { existsSync as existsSync29, readdirSync as readdirSync6, readFileSync as readFileSync29 } from "fs";
14405
14652
  import { join as join36, relative as relative19, resolve as resolve29 } from "path";
14406
14653
  var AUTH_PACKAGE2 = "@absolutejs/auth", REPO_URL = "https://github.com/absolutejs/absolute-auth", NPM_URL = "https://www.npmjs.com/package/@absolutejs/auth", SKIP_DIRS, MAX_FILES = 4000, SETUP_EXPORTS, isRecord12 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), readJson2 = (path) => {
14407
- if (!existsSync28(path))
14654
+ if (!existsSync29(path))
14408
14655
  return null;
14409
14656
  try {
14410
14657
  const parsed = JSON.parse(readFileSync29(path, "utf-8"));
@@ -14533,7 +14780,7 @@ var AUTH_PACKAGE2 = "@absolutejs/auth", REPO_URL = "https://github.com/absolutej
14533
14780
  scaffoldable: isScaffoldableFeature(feature.id)
14534
14781
  })), resolveAuthState = (cwd) => {
14535
14782
  const installedVersion = installedVersionFor(cwd);
14536
- const root = existsSync28(join36(cwd, "src")) ? join36(cwd, "src") : cwd;
14783
+ const root = existsSync29(join36(cwd, "src")) ? join36(cwd, "src") : cwd;
14537
14784
  let match = null;
14538
14785
  let setupPath = null;
14539
14786
  for (const file of candidateFiles(root)) {
@@ -14578,7 +14825,7 @@ var init_resolveAuthState = __esm(() => {
14578
14825
  });
14579
14826
 
14580
14827
  // src/cli/config/auth/scaffoldAuthFeature.ts
14581
- import { existsSync as existsSync29, writeFileSync as writeFileSync15 } from "fs";
14828
+ import { existsSync as existsSync30, writeFileSync as writeFileSync15 } from "fs";
14582
14829
  import { dirname as dirname23, join as join37, relative as relative20, resolve as resolve30 } from "path";
14583
14830
  var renderScaffold = (scaffold) => {
14584
14831
  const importNames = [...scaffold.imports, `type ${scaffold.typeName}`];
@@ -14606,7 +14853,7 @@ ${body}
14606
14853
  if (setupPath)
14607
14854
  return dirname23(resolve30(cwd, setupPath));
14608
14855
  const src = join37(cwd, "src");
14609
- return existsSync29(src) ? src : cwd;
14856
+ return existsSync30(src) ? src : cwd;
14610
14857
  }, spreadFor = (scaffold) => `import { ${scaffold.exportName} } from './${scaffold.exportName}';
14611
14858
  // add to your auth() call:
14612
14859
  ${scaffold.configKey}: ${scaffold.exportName}`, failure2 = (message) => ({
@@ -14621,7 +14868,7 @@ ${scaffold.configKey}: ${scaffold.exportName}`, failure2 = (message) => ({
14621
14868
  return failure2(`Unknown auth feature "${id}".`);
14622
14869
  const filePath = join37(targetDir(cwd), `${scaffold.exportName}.ts`);
14623
14870
  const relPath = relative20(cwd, filePath);
14624
- if (existsSync29(filePath)) {
14871
+ if (existsSync30(filePath)) {
14625
14872
  return {
14626
14873
  created: null,
14627
14874
  installed: false,
@@ -14648,13 +14895,13 @@ var init_scaffoldAuthFeature = __esm(() => {
14648
14895
  });
14649
14896
 
14650
14897
  // src/cli/htmx/install.ts
14651
- import { existsSync as existsSync30, mkdirSync as mkdirSync14, readFileSync as readFileSync30, writeFileSync as writeFileSync16 } from "fs";
14898
+ import { existsSync as existsSync31, mkdirSync as mkdirSync14, readFileSync as readFileSync30, writeFileSync as writeFileSync16 } from "fs";
14652
14899
  import { join as join38 } from "path";
14653
14900
  var VENDORED_HTMX_VERSION = "2.0.6", vendoredHtmxFile = () => [
14654
14901
  join38(import.meta.dir, "htmx.min.js"),
14655
14902
  join38(import.meta.dir, "htmx", "htmx.min.js"),
14656
14903
  join38(import.meta.dir, "..", "htmx", "htmx.min.js")
14657
- ].find((path) => existsSync30(path)) ?? null, detectHtmxVersion = (content) => {
14904
+ ].find((path) => existsSync31(path)) ?? null, detectHtmxVersion = (content) => {
14658
14905
  const match = content.match(/version:"([0-9.]+)"/);
14659
14906
  return match ? match[1] : null;
14660
14907
  }, fetchHtmx = async (version2) => {
@@ -14666,7 +14913,7 @@ var VENDORED_HTMX_VERSION = "2.0.6", vendoredHtmxFile = () => [
14666
14913
  return response.text();
14667
14914
  }, installedHtmxVersion = (htmxDir) => {
14668
14915
  const file = join38(htmxDir, "htmx.min.js");
14669
- if (!existsSync30(file))
14916
+ if (!existsSync31(file))
14670
14917
  return null;
14671
14918
  return detectHtmxVersion(readFileSync30(file, "utf-8"));
14672
14919
  }, readVendoredHtmx = () => {
@@ -14834,7 +15081,7 @@ var exports_analyze = {};
14834
15081
  __export(exports_analyze, {
14835
15082
  runAnalyze: () => runAnalyze
14836
15083
  });
14837
- import { existsSync as existsSync31, readFileSync as readFileSync31, statSync as statSync3, writeFileSync as writeFileSync17 } from "fs";
15084
+ import { existsSync as existsSync32, readFileSync as readFileSync31, statSync as statSync3, writeFileSync as writeFileSync17 } from "fs";
14838
15085
  import { join as join40, resolve as resolve31 } from "path";
14839
15086
  var BASELINE_FILE = ".absolute-size-baseline.json", TOP_CHANGES = 12, CATEGORY_WIDTH = 16, SIZE_WIDTH = 12, CHANGE_WIDTH = 10, CATEGORY_ORDER, categoryOf = (key) => {
14840
15087
  if (key.startsWith("Island"))
@@ -14856,7 +15103,7 @@ var BASELINE_FILE = ".absolute-size-baseline.json", TOP_CHANGES = 12, CATEGORY_W
14856
15103
  }
14857
15104
  }, readSizes = (manifestDir) => {
14858
15105
  const manifestPath = join40(manifestDir, "manifest.json");
14859
- if (!existsSync31(manifestPath))
15106
+ if (!existsSync32(manifestPath))
14860
15107
  return null;
14861
15108
  const manifest = JSON.parse(readFileSync31(manifestPath, "utf-8"));
14862
15109
  const sizes = {};
@@ -14866,7 +15113,7 @@ var BASELINE_FILE = ".absolute-size-baseline.json", TOP_CHANGES = 12, CATEGORY_W
14866
15113
  return sizes;
14867
15114
  }, readBaseline = (cwd) => {
14868
15115
  const path = join40(cwd, BASELINE_FILE);
14869
- if (!existsSync31(path))
15116
+ if (!existsSync32(path))
14870
15117
  return null;
14871
15118
  try {
14872
15119
  const parsed = JSON.parse(readFileSync31(path, "utf-8"));
@@ -15200,7 +15447,7 @@ var exports_remove = {};
15200
15447
  __export(exports_remove, {
15201
15448
  runRemove: () => runRemove
15202
15449
  });
15203
- import { existsSync as existsSync32, readFileSync as readFileSync32 } from "fs";
15450
+ import { existsSync as existsSync33, readFileSync as readFileSync32 } from "fs";
15204
15451
  import { relative as relative22 } from "path";
15205
15452
  var write3 = (text2) => process.stdout.write(`${text2}
15206
15453
  `), fail3 = (message) => {
@@ -15211,7 +15458,7 @@ var write3 = (text2) => process.stdout.write(`${text2}
15211
15458
  const candidates = [findRoutingFile(serverEntry), serverEntry];
15212
15459
  const seen = new Set;
15213
15460
  return candidates.filter((file) => {
15214
- if (file === null || seen.has(file) || !existsSync32(file))
15461
+ if (file === null || seen.has(file) || !existsSync33(file))
15215
15462
  return false;
15216
15463
  seen.add(file);
15217
15464
  return readFileSync32(file, "utf-8").includes(handler);
@@ -15341,10 +15588,10 @@ __export(exports_env, {
15341
15588
  runEnv: () => runEnv,
15342
15589
  scanEnvUsage: () => scanEnvUsage
15343
15590
  });
15344
- import { existsSync as existsSync33, readFileSync as readFileSync33 } from "fs";
15591
+ import { existsSync as existsSync34, readFileSync as readFileSync33 } from "fs";
15345
15592
  import { join as join41 } from "path";
15346
15593
  var {env: env3, Glob: Glob3 } = globalThis.Bun;
15347
- var EXTENSIONS = "ts,tsx,js,jsx,mjs,cjs,svelte,vue", STATUS_WIDTH2, keysInFile = (text2) => [...text2.matchAll(/getEnv\(\s*['"]([^'"]+)['"]\s*\)/g)].map((match) => match[1]).filter((key) => key !== undefined), scanPatterns = () => existsSync33(join41(process.cwd(), "src")) ? [`src/**/*.{${EXTENSIONS}}`] : [`*.{${EXTENSIONS}}`], scanEnvUsage = async () => {
15594
+ var EXTENSIONS = "ts,tsx,js,jsx,mjs,cjs,svelte,vue", STATUS_WIDTH2, keysInFile = (text2) => [...text2.matchAll(/getEnv\(\s*['"]([^'"]+)['"]\s*\)/g)].map((match) => match[1]).filter((key) => key !== undefined), scanPatterns = () => existsSync34(join41(process.cwd(), "src")) ? [`src/**/*.{${EXTENSIONS}}`] : [`*.{${EXTENSIONS}}`], scanEnvUsage = async () => {
15348
15595
  const scans = scanPatterns().map((pattern) => Array.fromAsync(new Glob3(pattern).scan({ cwd: process.cwd() })));
15349
15596
  const files = (await Promise.all(scans)).flat();
15350
15597
  const usage = new Map;
@@ -15410,7 +15657,7 @@ __export(exports_db, {
15410
15657
  quoteIdent: () => quoteIdent,
15411
15658
  runDb: () => runDb
15412
15659
  });
15413
- import { existsSync as existsSync34, mkdirSync as mkdirSync15, readFileSync as readFileSync34, writeFileSync as writeFileSync18 } from "fs";
15660
+ import { existsSync as existsSync35, mkdirSync as mkdirSync15, readFileSync as readFileSync34, writeFileSync as writeFileSync18 } from "fs";
15414
15661
  import { join as join42 } from "path";
15415
15662
  var {env: env4, spawn: spawn3, SQL } = globalThis.Bun;
15416
15663
  var BACKUP_FORMAT_VERSION = 1, RESTORE_CHUNK_ROWS = 500, URL_ENV_KEYS, JSON_DATA_TYPES, SEED_CANDIDATES, VALUE_FLAGS, paint = (text2, color) => `${color}${text2}${colors.reset}`, chunkRows = (items, size) => Array.from({ length: Math.ceil(items.length / size) }, (_, idx) => items.slice(idx * size, idx * size + size)), quoteIdent = (name) => `"${name.replace(/"/g, '""')}"`, resolveUrl = (explicit) => {
@@ -15531,7 +15778,7 @@ var BACKUP_FORMAT_VERSION = 1, RESTORE_CHUNK_ROWS = 500, URL_ENV_KEYS, JSON_DATA
15531
15778
  console.log(paint(`\u2713 backup \u2192 ${file}`, colors.green));
15532
15779
  console.log(paint(` ${chosen.length} tables, ${total} rows`, colors.dim));
15533
15780
  }, runRestore = async (file, options) => {
15534
- if (!existsSync34(file))
15781
+ if (!existsSync35(file))
15535
15782
  throw new Error(`Backup not found: ${file}`);
15536
15783
  const payload = JSON.parse(readFileSync34(file, "utf-8"));
15537
15784
  const names = Object.keys(payload.tables).filter((name) => keepTable(name, options));
@@ -15555,7 +15802,7 @@ var BACKUP_FORMAT_VERSION = 1, RESTORE_CHUNK_ROWS = 500, URL_ENV_KEYS, JSON_DATA
15555
15802
  const total = order.reduce((sum, name) => sum + (payload.tables[name]?.length ?? 0), 0);
15556
15803
  console.log(paint(`\u2713 restored ${order.length} tables, ${total} rows (idempotent upsert by primary key)`, colors.green));
15557
15804
  }, runSeed = async (entry) => {
15558
- const target = entry ?? SEED_CANDIDATES.find((candidate) => existsSync34(join42(process.cwd(), candidate)));
15805
+ const target = entry ?? SEED_CANDIDATES.find((candidate) => existsSync35(join42(process.cwd(), candidate)));
15559
15806
  if (target === undefined)
15560
15807
  throw new Error(`No seed script found (looked for ${SEED_CANDIDATES.join(", ")}). Pass a path: absolute db seed <file>.`);
15561
15808
  console.log(paint(`seeding via ${target}\u2026`, colors.cyan));
@@ -15616,7 +15863,7 @@ __export(exports_logs, {
15616
15863
  });
15617
15864
  import {
15618
15865
  closeSync as closeSync2,
15619
- existsSync as existsSync35,
15866
+ existsSync as existsSync36,
15620
15867
  openSync as openSync4,
15621
15868
  readSync as readSync2,
15622
15869
  statSync as statSync4,
@@ -15683,7 +15930,7 @@ var DEFAULT_LINES = 40, POLL_MS = 250, LINES_FLAG_SPAN = 2, readFrom = (path, st
15683
15930
  printAvailable(instances);
15684
15931
  return;
15685
15932
  }
15686
- if (match.logFile === null || !existsSync35(match.logFile)) {
15933
+ if (match.logFile === null || !existsSync36(match.logFile)) {
15687
15934
  printDim3(`"${name}" has no captured log (untracked, or started outside the CLI).`);
15688
15935
  return;
15689
15936
  }
@@ -15703,14 +15950,14 @@ var init_logs = __esm(() => {
15703
15950
 
15704
15951
  // src/cli/typeGraphCoherence.ts
15705
15952
  import {
15706
- existsSync as existsSync36,
15953
+ existsSync as existsSync37,
15707
15954
  readFileSync as readFileSync35,
15708
15955
  realpathSync as realpathSync2,
15709
15956
  rmSync as rmSync6,
15710
15957
  writeFileSync as writeFileSync19
15711
15958
  } from "fs";
15712
15959
  import { createRequire } from "module";
15713
- import { dirname as dirname25, join as join43, resolve as resolve32, sep as sep5 } from "path";
15960
+ import { dirname as dirname25, join as join43, resolve as resolve32, sep as sep6 } from "path";
15714
15961
  var DEPENDENCY_FIELDS, TYPE_GRAPH_PACKAGES, readManifest = (path) => {
15715
15962
  try {
15716
15963
  const parsed = JSON.parse(readFileSync35(path, "utf-8"));
@@ -15754,7 +16001,7 @@ var DEPENDENCY_FIELDS, TYPE_GRAPH_PACKAGES, readManifest = (path) => {
15754
16001
  }, findInstallRoot = (cwd) => {
15755
16002
  let directory = resolve32(cwd);
15756
16003
  for (;; ) {
15757
- if (existsSync36(join43(directory, "bun.lock")) || existsSync36(join43(directory, "bun.lockb"))) {
16004
+ if (existsSync37(join43(directory, "bun.lock")) || existsSync37(join43(directory, "bun.lockb"))) {
15758
16005
  return directory;
15759
16006
  }
15760
16007
  const parent = dirname25(directory);
@@ -15766,7 +16013,7 @@ var DEPENDENCY_FIELDS, TYPE_GRAPH_PACKAGES, readManifest = (path) => {
15766
16013
  let directory = resolve32(cwd);
15767
16014
  for (;; ) {
15768
16015
  const candidate = join43(directory, "package.json");
15769
- if (existsSync36(candidate))
16016
+ if (existsSync37(candidate))
15770
16017
  return candidate;
15771
16018
  if (directory === installRoot)
15772
16019
  return join43(installRoot, "package.json");
@@ -15870,8 +16117,8 @@ var DEPENDENCY_FIELDS, TYPE_GRAPH_PACKAGES, readManifest = (path) => {
15870
16117
  }, removeDuplicateTypeGraphPackages = (report) => {
15871
16118
  const manifest = readManifest(join43(report.installRoot, "package.json")) ?? {};
15872
16119
  const rootName = manifestName(manifest, "<workspace>");
15873
- const installPrefix = `${realpathSync2(report.installRoot)}${sep5}`;
15874
- const nodeModulesSegment = `${sep5}node_modules${sep5}`;
16120
+ const installPrefix = `${realpathSync2(report.installRoot)}${sep6}`;
16121
+ const nodeModulesSegment = `${sep6}node_modules${sep6}`;
15875
16122
  const removed = [];
15876
16123
  const stalePaths = duplicateTypeGraphPackages(report).flatMap((duplicate) => {
15877
16124
  const selected = preferredIdentity(duplicate, rootName);
@@ -15907,7 +16154,7 @@ var exports_doctor = {};
15907
16154
  __export(exports_doctor, {
15908
16155
  runDoctor: () => runDoctor
15909
16156
  });
15910
- import { existsSync as existsSync37, mkdirSync as mkdirSync16, readFileSync as readFileSync36, writeFileSync as writeFileSync20 } from "fs";
16157
+ import { existsSync as existsSync38, mkdirSync as mkdirSync16, readFileSync as readFileSync36, writeFileSync as writeFileSync20 } from "fs";
15911
16158
  import { createRequire as createRequire2 } from "module";
15912
16159
  import { arch as arch4, platform as platform5 } from "os";
15913
16160
  import { join as join44 } from "path";
@@ -15945,7 +16192,7 @@ var FRAMEWORK_FIELDS2, projectRequire, check = (status2, label, detail) => ({
15945
16192
  return [];
15946
16193
  const label = `${field.replace("Directory", "")} pages`;
15947
16194
  return [
15948
- existsSync37(join44(process.cwd(), dir)) ? check("ok", label, dir) : check("fail", label, `${dir} (missing)`)
16195
+ existsSync38(join44(process.cwd(), dir)) ? check("ok", label, dir) : check("fail", label, `${dir} (missing)`)
15949
16196
  ];
15950
16197
  }), envCheck = async () => {
15951
16198
  const vars = await collectEnvVars();
@@ -16007,7 +16254,7 @@ ${colors.dim}${checks.length} checks \xB7 ${colors.reset}${summary}${colors.dim}
16007
16254
  const fixes = [];
16008
16255
  for (const field of FRAMEWORK_FIELDS2) {
16009
16256
  const dir = readString2(config, field);
16010
- if (dir === undefined || existsSync37(join44(cwd, dir)))
16257
+ if (dir === undefined || existsSync38(join44(cwd, dir)))
16011
16258
  continue;
16012
16259
  mkdirSync16(join44(cwd, dir, "pages"), { recursive: true });
16013
16260
  fixes.push(`created ${dir}/pages`);
@@ -16018,7 +16265,7 @@ ${colors.dim}${checks.length} checks \xB7 ${colors.reset}${summary}${colors.dim}
16018
16265
  if (missing.length === 0)
16019
16266
  return null;
16020
16267
  const envExample = join44(cwd, ".env.example");
16021
- const existing = existsSync37(envExample) ? readFileSync36(envExample, "utf-8") : "";
16268
+ const existing = existsSync38(envExample) ? readFileSync36(envExample, "utf-8") : "";
16022
16269
  const existingKeys = new Set(existing.split(`
16023
16270
  `).map((line) => line.split("=")[0]?.trim()));
16024
16271
  const toAdd = missing.filter((entry) => !existingKeys.has(entry.key));
@@ -16392,10 +16639,10 @@ var init_inspect = __esm(() => {
16392
16639
  });
16393
16640
 
16394
16641
  // src/build/scanEntryPoints.ts
16395
- import { existsSync as existsSync38 } from "fs";
16642
+ import { existsSync as existsSync39 } from "fs";
16396
16643
  var {Glob: Glob4 } = globalThis.Bun;
16397
16644
  var scanEntryPoints = async (dir, pattern) => {
16398
- if (!existsSync38(dir))
16645
+ if (!existsSync39(dir))
16399
16646
  return [];
16400
16647
  const entryPaths = [];
16401
16648
  const glob = new Glob4(pattern);
@@ -16547,7 +16794,7 @@ var exports_islands = {};
16547
16794
  __export(exports_islands, {
16548
16795
  runIslands: () => runIslands
16549
16796
  });
16550
- import { existsSync as existsSync39, readFileSync as readFileSync38, statSync as statSync5 } from "fs";
16797
+ import { existsSync as existsSync40, readFileSync as readFileSync38, statSync as statSync5 } from "fs";
16551
16798
  import { join as join45, relative as relative23, resolve as resolve34 } from "path";
16552
16799
  var FRAMEWORK_DIR_KEY, FRAMEWORK_COLOR, printDim6 = (message) => process.stdout.write(`${colors.dim}${message}${colors.reset}
16553
16800
  `), hostFrameworkOf = (pagePath, cwd, config) => {
@@ -16567,7 +16814,7 @@ var FRAMEWORK_DIR_KEY, FRAMEWORK_COLOR, printDim6 = (message) => process.stdout.
16567
16814
  }
16568
16815
  }, readManifestSizes2 = (manifestDir) => {
16569
16816
  const manifestPath = join45(manifestDir, "manifest.json");
16570
- if (!existsSync39(manifestPath))
16817
+ if (!existsSync40(manifestPath))
16571
16818
  return null;
16572
16819
  const manifest = JSON.parse(readFileSync38(manifestPath, "utf-8"));
16573
16820
  const sizes = new Map;
@@ -16707,7 +16954,7 @@ var init_islands2 = __esm(() => {
16707
16954
  });
16708
16955
 
16709
16956
  // src/build/externalAssetPlugin.ts
16710
- import { copyFileSync as copyFileSync2, existsSync as existsSync40, mkdirSync as mkdirSync17, statSync as statSync6 } from "fs";
16957
+ import { copyFileSync as copyFileSync2, existsSync as existsSync41, mkdirSync as mkdirSync17, statSync as statSync6 } from "fs";
16711
16958
  import { basename as basename12, dirname as dirname27, join as join46, resolve as resolve35 } from "path";
16712
16959
  var createExternalAssetPlugin = (outDir, userSourceRoots = []) => ({
16713
16960
  name: "absolute-external-asset",
@@ -16729,12 +16976,12 @@ var createExternalAssetPlugin = (outDir, userSourceRoots = []) => ({
16729
16976
  if (!relPath)
16730
16977
  continue;
16731
16978
  const assetPath = resolve35(sourceDir, relPath);
16732
- if (!existsSync40(assetPath))
16979
+ if (!existsSync41(assetPath))
16733
16980
  continue;
16734
16981
  if (!statSync6(assetPath).isFile())
16735
16982
  continue;
16736
16983
  const targetPath = join46(outDir, basename12(assetPath));
16737
- if (existsSync40(targetPath))
16984
+ if (existsSync41(targetPath))
16738
16985
  continue;
16739
16986
  mkdirSync17(dirname27(targetPath), { recursive: true });
16740
16987
  copyFileSync2(assetPath, targetPath);
@@ -16754,7 +17001,7 @@ __export(exports_compile, {
16754
17001
  var {env: env5 } = globalThis.Bun;
16755
17002
  import {
16756
17003
  cpSync,
16757
- existsSync as existsSync41,
17004
+ existsSync as existsSync42,
16758
17005
  mkdirSync as mkdirSync18,
16759
17006
  readdirSync as readdirSync7,
16760
17007
  readFileSync as readFileSync39,
@@ -16845,7 +17092,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
16845
17092
  const normalizedOutdir = resolve36(outdir);
16846
17093
  const copyReference = (filePath, relPath) => {
16847
17094
  const assetSource = resolve36(dirname28(filePath), relPath);
16848
- if (!existsSync41(assetSource) || !statSync7(assetSource).isFile())
17095
+ if (!existsSync42(assetSource) || !statSync7(assetSource).isFile())
16849
17096
  return;
16850
17097
  const assetTarget = resolve36(normalizedOutdir, relPath.replace(/^\.\//, ""));
16851
17098
  if (assetTarget !== normalizedOutdir && !assetTarget.startsWith(`${normalizedOutdir}/`))
@@ -16929,7 +17176,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
16929
17176
  resolve36(import.meta.dir, "..", "..", "..", "src", "react", "jsxDevRuntimeCompat.ts")
16930
17177
  ];
16931
17178
  for (const candidate of candidates) {
16932
- if (existsSync41(candidate))
17179
+ if (existsSync42(candidate))
16933
17180
  return candidate;
16934
17181
  }
16935
17182
  return resolve36(import.meta.dir, "..", "..", "react", "jsxDevRuntimeCompat.js");
@@ -17004,7 +17251,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
17004
17251
  if (!buildConfig.angularDirectory)
17005
17252
  return;
17006
17253
  const angularScopeDir = resolve36(process.cwd(), "node_modules", "@angular");
17007
- const angularPackages = existsSync41(angularScopeDir) ? readdirSync7(angularScopeDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => entry.name !== "compiler-cli").map((entry) => `@angular/${entry.name}`) : [];
17254
+ const angularPackages = existsSync42(angularScopeDir) ? readdirSync7(angularScopeDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => entry.name !== "compiler-cli").map((entry) => `@angular/${entry.name}`) : [];
17008
17255
  const roots = new Set([...angularPackages, "rxjs", "tslib", "typescript"]);
17009
17256
  const seen = new Set;
17010
17257
  for (const specifier of roots) {
@@ -17023,7 +17270,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
17023
17270
  copyChunkReferencedPackages(outdir, seen);
17024
17271
  }, collectRuntimePackageSpecifiers = (distDir) => {
17025
17272
  const nodeModulesDir = join47(distDir, "node_modules");
17026
- if (!existsSync41(nodeModulesDir))
17273
+ if (!existsSync42(nodeModulesDir))
17027
17274
  return [];
17028
17275
  const specifiers = [];
17029
17276
  for (const entry of readdirSync7(nodeModulesDir, { withFileTypes: true })) {
@@ -17064,9 +17311,9 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
17064
17311
  const packageDir = join47(distDir, "node_modules", ...packageSpecifier.split("/"));
17065
17312
  const subpath = specifier.slice(packageSpecifier.length);
17066
17313
  const subPackageDir = subpath ? join47(packageDir, ...subpath.slice(1).split("/")) : null;
17067
- const resolvedPackageDir = subPackageDir && existsSync41(join47(subPackageDir, "package.json")) ? subPackageDir : packageDir;
17314
+ const resolvedPackageDir = subPackageDir && existsSync42(join47(subPackageDir, "package.json")) ? subPackageDir : packageDir;
17068
17315
  const packageJsonPath = join47(resolvedPackageDir, "package.json");
17069
- if (!existsSync41(packageJsonPath))
17316
+ if (!existsSync42(packageJsonPath))
17070
17317
  return null;
17071
17318
  const pkg = JSON.parse(readFileSync39(packageJsonPath, "utf-8"));
17072
17319
  const exportKey = resolvedPackageDir !== subPackageDir && subpath ? `.${subpath}` : ".";
@@ -17091,7 +17338,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
17091
17338
  }, findContainingRuntimePackageDir = (filePath) => {
17092
17339
  let dir = dirname28(filePath);
17093
17340
  while (dir !== dirname28(dir)) {
17094
- if (isNodeModulesPath(dir) && existsSync41(join47(dir, "package.json"))) {
17341
+ if (isNodeModulesPath(dir) && existsSync42(join47(dir, "package.json"))) {
17095
17342
  return dir;
17096
17343
  }
17097
17344
  dir = dirname28(dir);
@@ -17771,11 +18018,11 @@ export default server;
17771
18018
  process.exit(1);
17772
18019
  }
17773
18020
  const outputPath = resolve36(resolvedOutdir, `${entryName}.js`);
17774
- if (!existsSync41(outputPath)) {
18021
+ if (!existsSync42(outputPath)) {
17775
18022
  console.error(cliTag4("\x1B[31m", `Expected output not found: ${outputPath}`));
17776
18023
  process.exit(1);
17777
18024
  }
17778
- if (existsSync41(resolve36(resolvedOutdir, "angular", "vendor", "server"))) {
18025
+ if (existsSync42(resolve36(resolvedOutdir, "angular", "vendor", "server"))) {
17779
18026
  const vendorDir = resolve36(resolvedOutdir, "angular", "vendor", "server");
17780
18027
  const vendorEntries = readdirSync7(vendorDir).filter((fileName) => fileName.endsWith(".js"));
17781
18028
  const angularServerVendorPaths = {};
@@ -19739,7 +19986,7 @@ import {
19739
19986
  stat as stat3,
19740
19987
  writeFile as writeFile15
19741
19988
  } from "fs/promises";
19742
- import { dirname as dirname31, isAbsolute as isAbsolute7, join as join53, relative as relative27, resolve as resolve40, sep as sep6 } from "path";
19989
+ import { dirname as dirname31, isAbsolute as isAbsolute7, join as join53, relative as relative27, resolve as resolve40, sep as sep7 } from "path";
19743
19990
  var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord13 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), requireManifest2 = (value) => {
19744
19991
  if (!isRecord13(value) || typeof value.appBuild !== "string" || typeof value.appId !== "string" || typeof value.runtime !== "string") {
19745
19992
  throw new TypeError("Invalid embedded AbsoluteJS mobile manifest.");
@@ -19807,7 +20054,7 @@ var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord13 = (value) => typeof value ==
19807
20054
  const root = resolve40(projectRoot);
19808
20055
  const output = resolve40(root, requested ?? ".absolutejs/mobile/releases/android");
19809
20056
  const projectRelative = relative27(root, output);
19810
- if (projectRelative === ".." || projectRelative.startsWith(`..${sep6}`) || isAbsolute7(projectRelative)) {
20057
+ if (projectRelative === ".." || projectRelative.startsWith(`..${sep7}`) || isAbsolute7(projectRelative)) {
19811
20058
  throw new TypeError("mobile build --outdir must remain inside the project.");
19812
20059
  }
19813
20060
  return output;
@@ -20393,7 +20640,7 @@ var init_androidTestReport = __esm(() => {
20393
20640
 
20394
20641
  // src/mobile/releasePublisher.ts
20395
20642
  import { access as access13 } from "fs/promises";
20396
- import { isAbsolute as isAbsolute8, relative as relative28, resolve as resolve41, sep as sep7 } from "path";
20643
+ import { isAbsolute as isAbsolute8, relative as relative28, resolve as resolve41, sep as sep8 } from "path";
20397
20644
  import { pathToFileURL as pathToFileURL2 } from "url";
20398
20645
  var prepareAbsoluteIosRelease = async (publisher, options) => {
20399
20646
  if (typeof publisher.prepareIosRelease !== "function") {
@@ -20418,7 +20665,7 @@ var prepareAbsoluteIosRelease = async (publisher, options) => {
20418
20665
  const root = resolve41(projectRoot);
20419
20666
  const path = resolve41(root, requested);
20420
20667
  const projectRelative = relative28(root, path);
20421
- if (projectRelative === ".." || projectRelative.startsWith(`..${sep7}`) || isAbsolute8(projectRelative)) {
20668
+ if (projectRelative === ".." || projectRelative.startsWith(`..${sep8}`) || isAbsolute8(projectRelative)) {
20422
20669
  throw new TypeError("mobile publish --registry must remain inside the project.");
20423
20670
  }
20424
20671
  return path;
@@ -20633,9 +20880,9 @@ var init_mobileInspect = __esm(() => {
20633
20880
  });
20634
20881
 
20635
20882
  // src/mobile/ciWorkflow.ts
20636
- import { existsSync as existsSync42 } from "fs";
20883
+ import { existsSync as existsSync43 } from "fs";
20637
20884
  import { access as access15, mkdir as mkdir15, readFile as readFile23, writeFile as writeFile17 } from "fs/promises";
20638
- import { dirname as dirname32, extname as extname9, relative as relative30, resolve as resolve43, sep as sep8 } from "path";
20885
+ import { dirname as dirname32, extname as extname9, relative as relative30, resolve as resolve43, sep as sep9 } from "path";
20639
20886
  var ABSOLUTE_MOBILE_CI_WORKFLOW_FORMAT = 1, SECRET_NAME_PATTERN, CI_ENV_INDENTATION = 6, RESERVED_SECRET_NAMES, exists4 = async (path) => {
20640
20887
  try {
20641
20888
  await access15(path);
@@ -20647,12 +20894,12 @@ var ABSOLUTE_MOBILE_CI_WORKFLOW_FORMAT = 1, SECRET_NAME_PATTERN, CI_ENV_INDENTAT
20647
20894
  const root = resolve43(projectRoot);
20648
20895
  const path = resolve43(root, value);
20649
20896
  const portable = relative30(root, path).replaceAll("\\", "/");
20650
- if (portable === ".." || portable.startsWith(`..${sep8}`) || portable.startsWith("../") || portable === "") {
20897
+ if (portable === ".." || portable.startsWith(`..${sep9}`) || portable.startsWith("../") || portable === "") {
20651
20898
  throw new TypeError(`${field} must remain inside the project root.`);
20652
20899
  }
20653
20900
  if (/\r|\n/u.test(portable) || portable.startsWith("-"))
20654
20901
  throw new TypeError(`${field} contains an unsafe path.`);
20655
- if (!options.allowMissing && !existsSync42(path))
20902
+ if (!options.allowMissing && !existsSync43(path))
20656
20903
  throw new TypeError(`${field} does not exist inside the project.`);
20657
20904
  return portable;
20658
20905
  }, workflowOutputPath = (projectRoot, value) => {
@@ -20660,7 +20907,7 @@ var ABSOLUTE_MOBILE_CI_WORKFLOW_FORMAT = 1, SECRET_NAME_PATTERN, CI_ENV_INDENTAT
20660
20907
  const workflows = resolve43(root, ".github/workflows");
20661
20908
  const path = resolve43(root, value ?? ".github/workflows/absolute-mobile.yml");
20662
20909
  const portable = relative30(workflows, path);
20663
- if (portable === ".." || portable.startsWith(`..${sep8}`) || extname9(path) !== ".yml" && extname9(path) !== ".yaml") {
20910
+ if (portable === ".." || portable.startsWith(`..${sep9}`) || extname9(path) !== ".yml" && extname9(path) !== ".yaml") {
20664
20911
  throw new TypeError("mobile ci github --output must be a .yml or .yaml file inside .github/workflows.");
20665
20912
  }
20666
20913
  return path;
@@ -21213,7 +21460,26 @@ var NOT_FOUND4 = -1, isRecord15 = (value) => typeof value === "object" && value
21213
21460
  throw new TypeError(`Expo exited with status ${exitCode}.`);
21214
21461
  }, ensureExpoPackages = async (project, args) => {
21215
21462
  try {
21216
- await access16(join56(project, "node_modules", "expo", "package.json"));
21463
+ const manifest = JSON.parse(await readFile24(join56(project, "package.json"), "utf8"));
21464
+ const dependencies = typeof manifest === "object" && manifest !== null ? Reflect.get(manifest, "dependencies") : undefined;
21465
+ if (typeof dependencies !== "object" || dependencies === null || Array.isArray(dependencies))
21466
+ throw new TypeError("Generated Expo dependencies are invalid.");
21467
+ await Promise.all(Object.entries(dependencies).map(async ([name, expected]) => {
21468
+ if (typeof expected !== "string")
21469
+ throw new TypeError("Generated Expo dependency version is invalid.");
21470
+ const installed = JSON.parse(await readFile24(join56(project, "node_modules", name, "package.json"), "utf8"));
21471
+ const actual = typeof installed === "object" && installed !== null ? Reflect.get(installed, "version") : undefined;
21472
+ if (typeof actual !== "string")
21473
+ throw new TypeError("Installed Expo dependency version is invalid.");
21474
+ if (/^\d+\.\d+\.\d+$/u.test(expected) && actual !== expected)
21475
+ throw new TypeError("Installed Expo dependency is outdated.");
21476
+ if (expected.startsWith("~")) {
21477
+ const wanted = expected.slice(1).split(".").map(Number);
21478
+ const found = actual.split(".").map(Number);
21479
+ if (found[0] !== wanted[0] || found[1] !== wanted[1] || (found[2] ?? -1) < (wanted[2] ?? 0))
21480
+ throw new TypeError("Installed Expo dependency is outdated.");
21481
+ }
21482
+ }));
21217
21483
  return;
21218
21484
  } catch {}
21219
21485
  const approved = args.includes("--yes") || await confirmInstall("The experimental Expo shell dependencies are missing. Install the pinned Expo SDK 57 toolchain now?");
@@ -22779,10 +23045,10 @@ __export(exports_typecheck, {
22779
23045
  typecheck: () => typecheck
22780
23046
  });
22781
23047
  import { resolve as resolve45, join as join57 } from "path";
22782
- import { existsSync as existsSync43, readFileSync as readFileSync40 } from "fs";
23048
+ import { existsSync as existsSync44, readFileSync as readFileSync40 } from "fs";
22783
23049
  import { mkdir as mkdir17, writeFile as writeFile19 } from "fs/promises";
22784
23050
  var isCommandService3 = (service) => service.kind === "command" || Array.isArray(service.command), resolveConfigPath = (configPath2) => resolve45(configPath2 ?? process.env.ABSOLUTE_CONFIG ?? "absolute.config.ts"), getTypecheckTargets = async (configPath2) => {
22785
- if (!existsSync43(resolveConfigPath(configPath2))) {
23051
+ if (!existsSync44(resolveConfigPath(configPath2))) {
22786
23052
  const defaultService = {};
22787
23053
  return [defaultService];
22788
23054
  }
@@ -22804,7 +23070,7 @@ var isCommandService3 = (service) => service.kind === "command" || Array.isArray
22804
23070
  return { exitCode, name, output: (stdout + stderr).trim() };
22805
23071
  }, shellEscape = (value) => `'${value.replaceAll("'", "'\\''")}'`, runShell = async (name, command) => run(name, ["/bin/bash", "-lc", command]), findBin = (name) => {
22806
23072
  const local = resolve45("node_modules", ".bin", name);
22807
- return existsSync43(local) ? local : null;
23073
+ return existsSync44(local) ? local : null;
22808
23074
  }, ANSI_COLOR_REGEX, ANSI_PURPLE_REGEX, ANSI_CYAN_REGEX, ANSI_TOKEN_END_REGEX, stripAnsi4 = (str) => str.replace(ANSI_COLOR_REGEX, ""), formatSvelteOutput = (output) => {
22809
23075
  const cwd = `${process.cwd()}/`;
22810
23076
  const summaryMatch = stripAnsi4(output).match(/svelte-check found (\d+) error/);
@@ -22856,7 +23122,7 @@ Found ${errorCount} error${suffix}.`;
22856
23122
  resolve45(import.meta.dir, "../../types", fileName),
22857
23123
  resolve45(import.meta.dir, "../../../types", fileName)
22858
23124
  ];
22859
- return candidates.find((candidate) => existsSync43(candidate)) ?? candidates[0];
23125
+ return candidates.find((candidate) => existsSync44(candidate)) ?? candidates[0];
22860
23126
  }, ABSOLUTE_TYPECHECK_FILES, readProjectTsconfig = () => {
22861
23127
  try {
22862
23128
  return JSON.parse(readFileSync40(resolve45("tsconfig.json"), "utf-8"));
@@ -23215,13 +23481,13 @@ var {$: $3, env } = globalThis.Bun;
23215
23481
  import { spawn as nodeSpawn } from "child_process";
23216
23482
  import {
23217
23483
  createWriteStream,
23218
- existsSync as existsSync5,
23219
- readFileSync as readFileSync9,
23484
+ existsSync as existsSync6,
23485
+ readFileSync as readFileSync10,
23220
23486
  rmSync as rmSync2,
23221
23487
  writeFileSync as writeFileSync4
23222
23488
  } from "fs";
23223
23489
  import { tmpdir as tmpdir2 } from "os";
23224
- import { join as join16, resolve as resolvePath2 } from "path";
23490
+ import { join as join17, resolve as resolvePath2 } from "path";
23225
23491
 
23226
23492
  // src/dev/tunnel/client.ts
23227
23493
  var RECONNECT_DELAY_MS = 2000;
@@ -23731,7 +23997,7 @@ init_expoProject();
23731
23997
  init_iosPhysicalDeviceTransport();
23732
23998
  import { spawn } from "child_process";
23733
23999
  import { access as access2 } from "fs/promises";
23734
- import { join as join8 } from "path";
24000
+ import { join as join9 } from "path";
23735
24001
  var METRO_READY_TIMEOUT_MS = 60000;
23736
24002
  var PROCESS_CLOSE_TIMEOUT_MS = 2000;
23737
24003
  var commandEnvironment = (options) => ({
@@ -23744,7 +24010,7 @@ var commandEnvironment = (options) => ({
23744
24010
  ...options.metroHost ? { REACT_NATIVE_PACKAGER_HOSTNAME: options.metroHost } : {}
23745
24011
  });
23746
24012
  var absoluteExpoExecutable = async (project) => {
23747
- const executable = join8(project, "node_modules", ".bin", "expo");
24013
+ const executable = join9(project, "node_modules", ".bin", "expo");
23748
24014
  try {
23749
24015
  await access2(executable);
23750
24016
  return executable;
@@ -23840,18 +24106,18 @@ var stopProcess = async (process2) => {
23840
24106
  return;
23841
24107
  process2.kill("SIGTERM");
23842
24108
  await Promise.race([
23843
- new Promise((resolve5) => process2.once("exit", () => resolve5())),
23844
- new Promise((resolve5) => setTimeout(resolve5, PROCESS_CLOSE_TIMEOUT_MS))
24109
+ new Promise((resolve6) => process2.once("exit", () => resolve6())),
24110
+ new Promise((resolve6) => setTimeout(resolve6, PROCESS_CLOSE_TIMEOUT_MS))
23845
24111
  ]);
23846
24112
  if (process2.exitCode === null)
23847
24113
  process2.kill("SIGKILL");
23848
24114
  };
23849
- var waitForExit = (process2) => new Promise((resolve5) => {
24115
+ var waitForExit = (process2) => new Promise((resolve6) => {
23850
24116
  if (process2.exitCode !== null) {
23851
- resolve5(process2.exitCode);
24117
+ resolve6(process2.exitCode);
23852
24118
  return;
23853
24119
  }
23854
- process2.once("exit", (code) => resolve5(code ?? 1));
24120
+ process2.once("exit", (code) => resolve6(code ?? 1));
23855
24121
  });
23856
24122
  var runUtilityCommand = async (run, command, args, options) => {
23857
24123
  const child = run(command, args, {
@@ -23931,9 +24197,9 @@ var startAbsoluteExpoDevSession = async (options) => {
23931
24197
  }) : undefined;
23932
24198
  let metroReady = false;
23933
24199
  let resolveMetro;
23934
- const metroPromise = new Promise((resolve5, reject) => {
24200
+ const metroPromise = new Promise((resolve6, reject) => {
23935
24201
  if (!metro) {
23936
- resolve5();
24202
+ resolve6();
23937
24203
  return;
23938
24204
  }
23939
24205
  const timeout = setTimeout(() => {
@@ -23941,7 +24207,7 @@ var startAbsoluteExpoDevSession = async (options) => {
23941
24207
  }, METRO_READY_TIMEOUT_MS);
23942
24208
  resolveMetro = () => {
23943
24209
  clearTimeout(timeout);
23944
- resolve5();
24210
+ resolve6();
23945
24211
  };
23946
24212
  metro.once("exit", (code) => {
23947
24213
  if (!metroReady) {
@@ -24306,7 +24572,7 @@ var DEFAULT_PORT_RANGE = 10;
24306
24572
  var RESTART_PARK_POLL_MS = 20;
24307
24573
  var NODE_API_IMPORT_ERROR = "To load Node-API modules, use require() or process.dlopen instead of import.";
24308
24574
  var sourceServerBootstrap = resolvePath2(import.meta.dir, "../../dev/serverBootstrap.ts");
24309
- var serverBootstrap = existsSync5(sourceServerBootstrap) ? sourceServerBootstrap : resolvePath2(import.meta.dir, "../dev/serverBootstrap.js");
24575
+ var serverBootstrap = existsSync6(sourceServerBootstrap) ? sourceServerBootstrap : resolvePath2(import.meta.dir, "../dev/serverBootstrap.js");
24310
24576
  var formatServerBootDiagnostic = (output, serverEntry) => {
24311
24577
  if (!output.includes(NODE_API_IMPORT_ERROR))
24312
24578
  return null;
@@ -24496,7 +24762,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
24496
24762
  const generated = await writeAbsoluteExpoProject(normalized, {
24497
24763
  projectRoot: process.cwd()
24498
24764
  });
24499
- const dependenciesReady = existsSync5(join16(generated.path, "node_modules", "expo", "package.json")) && existsSync5(join16(generated.path, "node_modules", "expo-dev-client", "package.json"));
24765
+ const dependenciesReady = existsSync6(join17(generated.path, "node_modules", "expo", "package.json")) && existsSync6(join17(generated.path, "node_modules", "expo-dev-client", "package.json"));
24500
24766
  if (!dependenciesReady) {
24501
24767
  const install = await confirmPrompt("Expo development dependencies are missing. Install the pinned SDK 57 development client now?");
24502
24768
  if (!install) {
@@ -24506,7 +24772,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
24506
24772
  cwd: generated.path,
24507
24773
  stdio: "inherit"
24508
24774
  });
24509
- const installExit = await new Promise((resolve10) => installProcess.once("exit", (code) => resolve10(code ?? 1)));
24775
+ const installExit = await new Promise((resolve11) => installProcess.once("exit", (code) => resolve11(code ?? 1)));
24510
24776
  if (installExit !== 0) {
24511
24777
  throw new TypeError(`Expo dependency installation exited with status ${installExit}.`);
24512
24778
  }
@@ -24575,12 +24841,12 @@ var dev = async (serverEntry, configPath2, options = {}) => {
24575
24841
  }
24576
24842
  }
24577
24843
  if (ready) {
24578
- const nativeDirectory = join16(normalized.nativeProjectDirectory, "android");
24844
+ const nativeDirectory = join17(normalized.nativeProjectDirectory, "android");
24579
24845
  let createNativeProject = false;
24580
- if (!existsSync5(nativeDirectory)) {
24846
+ if (!existsSync6(nativeDirectory)) {
24581
24847
  createNativeProject = await confirmPrompt("Create the managed Capacitor Android project now?");
24582
24848
  }
24583
- if (existsSync5(nativeDirectory) || createNativeProject) {
24849
+ if (existsSync6(nativeDirectory) || createNativeProject) {
24584
24850
  androidDevProject = await prepareAbsoluteAndroidDevProject(normalized, {
24585
24851
  createNativeProject,
24586
24852
  projectRoot: process.cwd(),
@@ -24595,8 +24861,8 @@ var dev = async (serverEntry, configPath2, options = {}) => {
24595
24861
  if (!remote) {
24596
24862
  console.log(cliTag("\x1B[33m", "iOS target skipped. Pair a Mac with `absolute mobile pair mac <name> <user@host>`."));
24597
24863
  } else {
24598
- const nativeDirectory = join16(normalized.nativeProjectDirectory, "ios");
24599
- if (!existsSync5(nativeDirectory)) {
24864
+ const nativeDirectory = join17(normalized.nativeProjectDirectory, "ios");
24865
+ if (!existsSync6(nativeDirectory)) {
24600
24866
  console.log(cliTag("\x1B[33m", "The iOS project is missing. Run `absolute mobile init` before remote development."));
24601
24867
  } else {
24602
24868
  iosDevProject = createAbsoluteRemoteIosDevProject(normalized, process.cwd(), remote);
@@ -24616,12 +24882,12 @@ var dev = async (serverEntry, configPath2, options = {}) => {
24616
24882
  }
24617
24883
  }
24618
24884
  if (ready) {
24619
- const nativeDirectory = join16(normalized.nativeProjectDirectory, "ios");
24885
+ const nativeDirectory = join17(normalized.nativeProjectDirectory, "ios");
24620
24886
  let createNativeProject = false;
24621
- if (!existsSync5(nativeDirectory)) {
24887
+ if (!existsSync6(nativeDirectory)) {
24622
24888
  createNativeProject = await confirmPrompt("Create the managed Capacitor iOS project now?");
24623
24889
  }
24624
- if (existsSync5(nativeDirectory) || createNativeProject) {
24890
+ if (existsSync6(nativeDirectory) || createNativeProject) {
24625
24891
  iosDevProject = await prepareAbsoluteIosDevProject(normalized, {
24626
24892
  createNativeProject,
24627
24893
  projectRoot: process.cwd(),
@@ -24690,12 +24956,12 @@ var dev = async (serverEntry, configPath2, options = {}) => {
24690
24956
  startedAt: new Date().toISOString()
24691
24957
  });
24692
24958
  const instanceLog = createWriteStream(instanceLogFile, { flags: "w" });
24693
- const writeInstanceLog = (text) => {
24959
+ const writeInstanceLog = (text2) => {
24694
24960
  try {
24695
- instanceLog.write(text.replace(ANSI_LOG_REGEX, ""));
24961
+ instanceLog.write(text2.replace(ANSI_LOG_REGEX, ""));
24696
24962
  } catch {}
24697
24963
  };
24698
- const usesDocker = existsSync5(resolvePath2(COMPOSE_PATH));
24964
+ const usesDocker = existsSync6(resolvePath2(COMPOSE_PATH));
24699
24965
  const scripts = usesDocker ? await readDbScripts() : null;
24700
24966
  if (scripts)
24701
24967
  await startDatabase(scripts);
@@ -25181,8 +25447,8 @@ var dev = async (serverEntry, configPath2, options = {}) => {
25181
25447
  const ANSI_COLOR_SEQUENCE_RE = new RegExp(`${ANSI_ESCAPE}\\[[0-9;]*m`, "g");
25182
25448
  let restartScanBuffer = "";
25183
25449
  const handleChunk = (value) => {
25184
- const text = value.toString("utf8");
25185
- restartScanBuffer += text;
25450
+ const text2 = value.toString("utf8");
25451
+ restartScanBuffer += text2;
25186
25452
  let newlineIdx;
25187
25453
  while ((newlineIdx = restartScanBuffer.indexOf(`
25188
25454
  `)) !== -1) {
@@ -25250,13 +25516,13 @@ var dev = async (serverEntry, configPath2, options = {}) => {
25250
25516
  const merged = {};
25251
25517
  const candidates = [".env", ".env.development", ".env.local"];
25252
25518
  for (const name of candidates) {
25253
- let text;
25519
+ let text2;
25254
25520
  try {
25255
- text = readFileSync9(resolvePath2(process.cwd(), name), "utf8");
25521
+ text2 = readFileSync10(resolvePath2(process.cwd(), name), "utf8");
25256
25522
  } catch {
25257
25523
  continue;
25258
25524
  }
25259
- for (const rawLine of text.split(`
25525
+ for (const rawLine of text2.split(`
25260
25526
  `)) {
25261
25527
  const line = rawLine.trim();
25262
25528
  if (!line || line.startsWith("#"))
@@ -25274,7 +25540,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
25274
25540
  }
25275
25541
  return merged;
25276
25542
  };
25277
- const heapPreloadPath = join16(tmpdir2(), `absolute-heap-${process.pid}.ts`);
25543
+ const heapPreloadPath = join17(tmpdir2(), `absolute-heap-${process.pid}.ts`);
25278
25544
  let heapSnapshotEnabled = false;
25279
25545
  try {
25280
25546
  writeFileSync4(heapPreloadPath, DEV_CHILD_PRELOAD);
@@ -25407,7 +25673,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
25407
25673
  if (now - last < 100)
25408
25674
  return;
25409
25675
  recentlyHandled.set(filename, now);
25410
- scheduleServerRestart(join16(serverEntryDir, filename));
25676
+ scheduleServerRestart(join17(serverEntryDir, filename));
25411
25677
  };
25412
25678
  const recoveryScan = async () => {
25413
25679
  let entries;
@@ -25426,7 +25692,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
25426
25692
  continue;
25427
25693
  let fileStat;
25428
25694
  try {
25429
- fileStat = statSync(join16(serverEntryDir, entry.name));
25695
+ fileStat = statSync(join17(serverEntryDir, entry.name));
25430
25696
  } catch {
25431
25697
  continue;
25432
25698
  }
@@ -25814,9 +26080,9 @@ init_eslint();
25814
26080
  init_constants();
25815
26081
  init_utils();
25816
26082
  import { execSync as execSync2 } from "child_process";
25817
- import { existsSync as existsSync8, readFileSync as readFileSync11 } from "fs";
26083
+ import { existsSync as existsSync9, readFileSync as readFileSync12 } from "fs";
25818
26084
  import { arch as arch2, cpus, platform as platform3, totalmem, version } from "os";
25819
- import { resolve as resolve12 } from "path";
26085
+ import { resolve as resolve13 } from "path";
25820
26086
  var bold = (str) => `\x1B[1m${str}\x1B[0m`;
25821
26087
  var getBinaryVersion = (binary, flag = "--version") => {
25822
26088
  try {
@@ -25836,7 +26102,7 @@ var getPackageVersion = (packageName) => {
25836
26102
  const pkgPath = __require.resolve(`${packageName}/package.json`, {
25837
26103
  paths: [process.cwd()]
25838
26104
  });
25839
- const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
26105
+ const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
25840
26106
  const ver = pkg.version;
25841
26107
  return ver;
25842
26108
  } catch {
@@ -25846,10 +26112,10 @@ var getPackageVersion = (packageName) => {
25846
26112
  var getAbsoluteVersion = () => {
25847
26113
  try {
25848
26114
  const candidates = [
25849
- resolve12(import.meta.dir, "..", "..", "package.json"),
25850
- resolve12(import.meta.dir, "..", "..", "..", "package.json")
26115
+ resolve13(import.meta.dir, "..", "..", "package.json"),
26116
+ resolve13(import.meta.dir, "..", "..", "..", "package.json")
25851
26117
  ];
25852
- const pkgPath = candidates.find((candidate) => existsSync8(candidate));
26118
+ const pkgPath = candidates.find((candidate) => existsSync9(candidate));
25853
26119
  if (pkgPath)
25854
26120
  return readPackageVersion(pkgPath);
25855
26121
  } catch {
@@ -25858,7 +26124,7 @@ var getAbsoluteVersion = () => {
25858
26124
  return getPackageVersion("@absolutejs/absolute");
25859
26125
  };
25860
26126
  var readPackageVersion = (pkgPath) => {
25861
- const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
26127
+ const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
25862
26128
  const ver = pkg.version;
25863
26129
  return ver;
25864
26130
  };
@@ -25890,7 +26156,7 @@ var detectCI = () => {
25890
26156
  };
25891
26157
  var isDockerEnvironment = () => {
25892
26158
  try {
25893
- return existsSync8("/.dockerenv");
26159
+ return existsSync9("/.dockerenv");
25894
26160
  } catch {
25895
26161
  return false;
25896
26162
  }
@@ -25960,11 +26226,11 @@ var info = () => {
25960
26226
  // src/cli/cache.ts
25961
26227
  init_constants();
25962
26228
  import { mkdir as mkdir7 } from "fs/promises";
25963
- import { join as join17 } from "path";
26229
+ import { join as join18 } from "path";
25964
26230
  var {Glob } = globalThis.Bun;
25965
26231
  var CACHE_DIR = ".absolutejs";
25966
26232
  var MAX_FILES_PER_BATCH = 200;
25967
- var isIgnored = (file, ignorePatterns) => ignorePatterns.some((pat) => new Glob(pat).match(file));
26233
+ var isIgnored2 = (file, ignorePatterns) => ignorePatterns.some((pat) => new Glob(pat).match(file));
25968
26234
  var collectFiles = async (pattern, ignorePatterns) => {
25969
26235
  const files = [];
25970
26236
  const glob = new Glob(pattern);
@@ -25972,7 +26238,7 @@ var collectFiles = async (pattern, ignorePatterns) => {
25972
26238
  cwd: ".",
25973
26239
  dot: false
25974
26240
  })) {
25975
- if (!isIgnored(file, ignorePatterns))
26241
+ if (!isIgnored2(file, ignorePatterns))
25976
26242
  files.push(file);
25977
26243
  }
25978
26244
  return files;
@@ -26012,7 +26278,7 @@ var hashFiles = async (paths) => {
26012
26278
  };
26013
26279
  var loadCache = async (tool) => {
26014
26280
  try {
26015
- const path = join17(CACHE_DIR, `${tool}.cache.json`);
26281
+ const path = join18(CACHE_DIR, `${tool}.cache.json`);
26016
26282
  const data = await Bun.file(path).json();
26017
26283
  const result = data;
26018
26284
  return result;
@@ -26059,7 +26325,7 @@ var runTool = async (adapter, args) => {
26059
26325
  };
26060
26326
  var saveCache = async (tool, data) => {
26061
26327
  await mkdir7(CACHE_DIR, { recursive: true });
26062
- const path = join17(CACHE_DIR, `${tool}.cache.json`);
26328
+ const path = join18(CACHE_DIR, `${tool}.cache.json`);
26063
26329
  await Bun.write(path, JSON.stringify(data, null, "\t"));
26064
26330
  };
26065
26331
 
@@ -26152,7 +26418,7 @@ init_getDurationString();
26152
26418
  init_instanceRegistry();
26153
26419
  import {
26154
26420
  appendFileSync,
26155
- existsSync as existsSync12,
26421
+ existsSync as existsSync13,
26156
26422
  mkdirSync as mkdirSync7,
26157
26423
  readdirSync as readdirSync2,
26158
26424
  readFileSync as readFileSync16,
@@ -26723,7 +26989,7 @@ var createWorkspaceTui = ({
26723
26989
  // src/cli/scripts/workspace.ts
26724
26990
  init_utils();
26725
26991
  var sourceServerBootstrap2 = resolve22(import.meta.dir, "../../dev/serverBootstrap.ts");
26726
- var serverBootstrap2 = existsSync12(sourceServerBootstrap2) ? sourceServerBootstrap2 : resolve22(import.meta.dir, "../dev/serverBootstrap.js");
26992
+ var serverBootstrap2 = existsSync13(sourceServerBootstrap2) ? sourceServerBootstrap2 : resolve22(import.meta.dir, "../dev/serverBootstrap.js");
26727
26993
  var ANSI_REGEX2 = new RegExp(`${String.fromCharCode(ANSI_ESCAPE_CODE)}\\[[0-?]*[ -/]*[@-~]`, "g");
26728
26994
  var sleep = (durationMs) => Bun.sleep(durationMs);
26729
26995
  var stripAnsi3 = (value) => value.replace(ANSI_REGEX2, "");
@@ -27370,7 +27636,7 @@ var workspace = async (subcommand, options) => {
27370
27636
  const resolved = resolveService(name, service, workspaceEnv, options);
27371
27637
  const port = resolveWorkspaceServicePort(resolved.service, resolved.env);
27372
27638
  killStaleServicePort(port);
27373
- if (isAbsoluteService(resolved.service) && resolved.configPath && !existsSync12(resolved.configPath)) {
27639
+ if (isAbsoluteService(resolved.service) && resolved.configPath && !existsSync13(resolved.configPath)) {
27374
27640
  throw new Error(`${name} references missing config "${resolved.configPath}"`);
27375
27641
  }
27376
27642
  serviceBootStartedAt.set(name, performance.now());