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

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
@@ -1314,6 +1314,279 @@ var init_syncSchema = __esm(() => {
1314
1314
  init_client();
1315
1315
  });
1316
1316
 
1317
+ // src/mobile/deviceCapabilities.ts
1318
+ import { existsSync as existsSync3, readFileSync as readFileSync7 } from "fs";
1319
+ import { extname, join as join7, relative, resolve as resolve4 } from "path";
1320
+ import { fileURLToPath } from "url";
1321
+ import ts from "typescript";
1322
+ 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) => {
1323
+ const value = JSON.parse(readFileSync7(path, "utf8"));
1324
+ if (!object2(value))
1325
+ throw new TypeError(`${path} must contain an object.`);
1326
+ return value;
1327
+ }, text = (value, field) => {
1328
+ if (typeof value !== "string" || value.length === 0)
1329
+ throw new TypeError(`${field} must be a non-empty string.`);
1330
+ return value;
1331
+ }, androidPermissions = (value, field) => {
1332
+ if (value === undefined)
1333
+ return;
1334
+ if (!object2(value))
1335
+ throw new TypeError(`${field} must be an object.`);
1336
+ const { permissions } = value;
1337
+ if (!Array.isArray(permissions) || !permissions.every((permission) => typeof permission === "string" && ANDROID_PERMISSION_PATTERN.test(permission)))
1338
+ throw new TypeError(`${field}.permissions must contain Android permission names.`);
1339
+ return [...permissions];
1340
+ }, iosPrivacyAccessedApis = (value, field) => {
1341
+ if (value === undefined)
1342
+ return;
1343
+ if (!object2(value))
1344
+ throw new TypeError(`${field} must be an object.`);
1345
+ const privacy = {};
1346
+ for (const api of IOS_PRIVACY_ACCESSED_APIS) {
1347
+ const reasons = value[api];
1348
+ if (reasons === undefined)
1349
+ continue;
1350
+ const supported = IOS_PRIVACY_ACCESSED_API_REASONS[api];
1351
+ if (!Array.isArray(reasons) || reasons.length === 0 || !reasons.every((reason) => typeof reason === "string" && supported.has(reason)))
1352
+ throw new TypeError(`${field} contains an unsupported API or reason.`);
1353
+ privacy[api] = [...reasons];
1354
+ }
1355
+ if (Object.keys(value).some((api) => !IOS_PRIVACY_ACCESSED_APIS.some((known) => known === api)))
1356
+ throw new TypeError(`${field} contains an unsupported API or reason.`);
1357
+ return privacy;
1358
+ }, iosNativeRequirements = (value, field) => {
1359
+ if (value === undefined)
1360
+ return;
1361
+ if (!object2(value))
1362
+ throw new TypeError(`${field} must be an object.`);
1363
+ const {
1364
+ privacyAccessedApis,
1365
+ pushNotifications,
1366
+ systemBars,
1367
+ usageDescriptions
1368
+ } = value;
1369
+ if (pushNotifications !== undefined && pushNotifications !== true)
1370
+ throw new TypeError(`${field}.pushNotifications must be true.`);
1371
+ if (systemBars !== undefined && systemBars !== true)
1372
+ throw new TypeError(`${field}.systemBars must be true.`);
1373
+ if (usageDescriptions !== undefined && (!Array.isArray(usageDescriptions) || !usageDescriptions.every((purpose) => typeof purpose === "string" && IOS_USAGE_DESCRIPTIONS.has(purpose))))
1374
+ throw new TypeError(`${field}.usageDescriptions contains an unsupported purpose.`);
1375
+ const privacy = iosPrivacyAccessedApis(privacyAccessedApis, `${field}.privacyAccessedApis`);
1376
+ return {
1377
+ ...privacy === undefined ? {} : { privacyAccessedApis: privacy },
1378
+ ...pushNotifications === true ? { pushNotifications: true } : {},
1379
+ ...systemBars === true ? { systemBars: true } : {},
1380
+ ...usageDescriptions === undefined ? {} : { usageDescriptions: [...usageDescriptions] }
1381
+ };
1382
+ }, parseProvider = (name, value, providerName) => {
1383
+ if (!IDENTIFIER_PATTERN.test(name))
1384
+ throw new TypeError("Device capability names must be identifiers.");
1385
+ if (!object2(value))
1386
+ throw new TypeError(`Device capability ${name} must be an object.`);
1387
+ const factory = text(value.factory, `${name}.factory`);
1388
+ const module = text(value.module, `${name}.module`);
1389
+ if (!IDENTIFIER_PATTERN.test(factory))
1390
+ throw new TypeError(`${name}.factory must be a JavaScript identifier.`);
1391
+ if (!providerModulePattern(providerName).test(module))
1392
+ throw new TypeError(`${name}.module must be an official devices-${providerName} subpath.`);
1393
+ if (!Array.isArray(value.packages) || !value.packages.every((spec) => typeof spec === "string" && providerPackagePattern(providerName).test(spec)))
1394
+ throw new TypeError(`${name}.packages must contain exact official ${providerLabel(providerName)} package versions.`);
1395
+ const { plugins } = value;
1396
+ if (plugins !== undefined && (!Array.isArray(plugins) || !plugins.every((plugin) => typeof plugin === "string" && /^expo-[a-z][a-z0-9-]*$/u.test(plugin))))
1397
+ throw new TypeError(`${name}.plugins must contain Expo config plugin names.`);
1398
+ let native;
1399
+ const { native: nativeMetadata } = value;
1400
+ if (nativeMetadata !== undefined) {
1401
+ if (!object2(nativeMetadata))
1402
+ throw new TypeError(`${name}.native must be an object.`);
1403
+ const { android, ios } = nativeMetadata;
1404
+ const permissions = androidPermissions(android, `${name}.native.android`);
1405
+ const iosRequirements = iosNativeRequirements(ios, `${name}.native.ios`);
1406
+ native = {
1407
+ ...permissions === undefined ? {} : { android: { permissions } },
1408
+ ...iosRequirements === undefined ? {} : { ios: iosRequirements }
1409
+ };
1410
+ }
1411
+ return {
1412
+ factory,
1413
+ module,
1414
+ ...native === undefined ? {} : { native },
1415
+ ...plugins === undefined ? {} : { plugins: [...plugins] },
1416
+ packages: [...value.packages]
1417
+ };
1418
+ }, absoluteDeviceNativeRequirements = (plan) => {
1419
+ const privacy = plan.capabilities.reduce((requirements, name) => {
1420
+ for (const api of IOS_PRIVACY_ACCESSED_APIS) {
1421
+ const reasons = plan.providers[name]?.native?.ios?.privacyAccessedApis?.[api] ?? [];
1422
+ if (reasons.length === 0)
1423
+ continue;
1424
+ const current = requirements[api] ?? new Set;
1425
+ for (const reason of reasons)
1426
+ current.add(reason);
1427
+ requirements[api] = current;
1428
+ }
1429
+ return requirements;
1430
+ }, {});
1431
+ return {
1432
+ androidPermissions: [
1433
+ ...new Set(plan.capabilities.flatMap((name) => plan.providers[name]?.native?.android?.permissions ?? []))
1434
+ ].sort(),
1435
+ iosPrivacyAccessedApis: IOS_PRIVACY_ACCESSED_APIS.flatMap((api) => {
1436
+ const reasons = privacy[api];
1437
+ return reasons ? [{ api, reasons: [...reasons].sort() }] : [];
1438
+ }),
1439
+ iosPushNotifications: plan.capabilities.some((name) => plan.providers[name]?.native?.ios?.pushNotifications === true),
1440
+ iosSystemBars: plan.capabilities.some((name) => plan.providers[name]?.native?.ios?.systemBars === true),
1441
+ iosUsageDescriptions: [
1442
+ ...new Set(plan.capabilities.flatMap((name) => plan.providers[name]?.native?.ios?.usageDescriptions ?? []))
1443
+ ].sort()
1444
+ };
1445
+ }, loadAbsoluteDeviceCapabilityProviders = (projectRoot, provider = "capacitor") => {
1446
+ const adapter = ADAPTERS[provider];
1447
+ let path = join7(resolve4(projectRoot), "node_modules", adapter, "package.json");
1448
+ try {
1449
+ readFileSync7(path, "utf8");
1450
+ } catch {
1451
+ path = fileURLToPath(import.meta.resolve(`${adapter}/package.json`));
1452
+ }
1453
+ const manifest = readJson(path);
1454
+ const { absolutejs } = manifest;
1455
+ const devices = object2(absolutejs) ? absolutejs.devices : undefined;
1456
+ if (!object2(devices) || devices.format !== 1 || devices.provider !== provider || !object2(devices.capabilities))
1457
+ throw new TypeError(`${adapter} does not publish supported capability metadata.`);
1458
+ const entries = Object.entries(devices.capabilities).map(([name, capability]) => ({
1459
+ name,
1460
+ provider: parseProvider(name, capability, provider)
1461
+ }));
1462
+ return Object.fromEntries(entries.sort((left, right) => left.name.localeCompare(right.name)).map(({ name, provider: capabilityProvider }) => [
1463
+ name,
1464
+ capabilityProvider
1465
+ ]));
1466
+ }, isIgnored = (path) => path.split("/").some((segment) => IGNORED_DIRECTORIES.has(segment)), importedCapabilities = (source, file) => {
1467
+ const names = new Set;
1468
+ const namespaces = new Set;
1469
+ const visit = (node) => {
1470
+ if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier) && node.moduleSpecifier.text === DEVICES_PACKAGE && !node.importClause?.isTypeOnly) {
1471
+ const bindings = node.importClause?.namedBindings;
1472
+ if (bindings && ts.isNamedImports(bindings)) {
1473
+ for (const element of bindings.elements)
1474
+ if (!element.isTypeOnly)
1475
+ names.add((element.propertyName ?? element.name).text);
1476
+ }
1477
+ if (bindings && ts.isNamespaceImport(bindings))
1478
+ namespaces.add(bindings.name.text);
1479
+ }
1480
+ if (ts.isExportDeclaration(node) && !node.isTypeOnly && node.moduleSpecifier !== undefined && ts.isStringLiteral(node.moduleSpecifier) && node.moduleSpecifier.text === DEVICES_PACKAGE && node.exportClause && ts.isNamedExports(node.exportClause)) {
1481
+ for (const element of node.exportClause.elements)
1482
+ if (!element.isTypeOnly)
1483
+ names.add((element.propertyName ?? element.name).text);
1484
+ }
1485
+ if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression) && namespaces.has(node.expression.text))
1486
+ names.add(node.name.text);
1487
+ ts.forEachChild(node, visit);
1488
+ };
1489
+ const extension = extname(file).toLowerCase();
1490
+ const sources = extension === ".svelte" || extension === ".vue" ? [...source.matchAll(/<script\b[^>]*>([\s\S]*?)<\/script\s*>/giu)].map((match) => match[1]).filter((value) => value !== undefined) : [source];
1491
+ for (const [index, script] of sources.entries())
1492
+ visit(ts.createSourceFile(`${file}#script-${index}`, script, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX));
1493
+ return names;
1494
+ }, assertAbsoluteDeviceCapabilityPackages = (projectRoot, plan) => {
1495
+ const missing = missingAbsoluteDeviceCapabilityPackages(plan, directAbsoluteProjectPackages(projectRoot));
1496
+ const mismatched = plan.requiredPackages.filter((spec) => {
1497
+ const separator = spec.lastIndexOf("@");
1498
+ const packageName = spec.slice(0, separator);
1499
+ if (missing.includes(spec))
1500
+ return false;
1501
+ try {
1502
+ return readJson(join7(resolve4(projectRoot), "node_modules", packageName, "package.json")).version !== spec.slice(separator + 1);
1503
+ } catch {
1504
+ return true;
1505
+ }
1506
+ });
1507
+ const unmet = [...missing, ...mismatched];
1508
+ if (unmet.length > 0)
1509
+ throw new TypeError(`Device capabilities ${plan.capabilities.join(", ")} require ${unmet.join(", ")}. Run absolute mobile sync and approve the detected capability plugins.`);
1510
+ }, directAbsoluteProjectPackages = (projectRoot) => {
1511
+ const manifest = readJson(join7(resolve4(projectRoot), "package.json"));
1512
+ const packages = new Set;
1513
+ for (const field of ["dependencies", "devDependencies"]) {
1514
+ const dependencies = manifest[field];
1515
+ if (object2(dependencies))
1516
+ for (const name of Object.keys(dependencies))
1517
+ packages.add(name);
1518
+ }
1519
+ return packages;
1520
+ }, discoverAbsoluteDeviceCapabilities = (projectRoot, providers = loadAbsoluteDeviceCapabilityProviders(projectRoot)) => {
1521
+ const root = resolve4(projectRoot);
1522
+ if (!existsSync3(root))
1523
+ return [];
1524
+ const known = new Set(Object.keys(providers));
1525
+ const capabilities = new Set;
1526
+ for (const path of SOURCE_GLOB.scanSync({ cwd: root })) {
1527
+ const portable = relative(root, resolve4(root, path)).replaceAll("\\", "/");
1528
+ if (isIgnored(portable))
1529
+ continue;
1530
+ const source = readFileSync7(resolve4(root, portable), "utf8");
1531
+ for (const name of importedCapabilities(source, portable))
1532
+ if (known.has(name))
1533
+ capabilities.add(name);
1534
+ }
1535
+ return [...capabilities].sort();
1536
+ }, missingAbsoluteDeviceCapabilityPackages = (plan, directPackages) => plan.requiredPackages.filter((spec) => {
1537
+ const packageName = spec.slice(0, spec.lastIndexOf("@"));
1538
+ return !directPackages.has(packageName);
1539
+ }), resolveAbsoluteDeviceCapabilityPlan = (projectRoot, provider = "capacitor") => {
1540
+ const allProviders = loadAbsoluteDeviceCapabilityProviders(projectRoot, provider);
1541
+ const capabilities = discoverAbsoluteDeviceCapabilities(projectRoot, allProviders);
1542
+ const providers = {};
1543
+ for (const name of capabilities) {
1544
+ const capabilityProvider = allProviders[name];
1545
+ if (capabilityProvider)
1546
+ providers[name] = capabilityProvider;
1547
+ }
1548
+ return {
1549
+ capabilities,
1550
+ providers,
1551
+ requiredPackages: [
1552
+ ...new Set(capabilities.flatMap((name) => providers[name]?.packages ?? []))
1553
+ ].sort()
1554
+ };
1555
+ };
1556
+ var init_deviceCapabilities = __esm(() => {
1557
+ ADAPTERS = {
1558
+ capacitor: "@absolutejs/devices-capacitor",
1559
+ expo: "@absolutejs/devices-expo"
1560
+ };
1561
+ SOURCE_GLOB = new Bun.Glob("**/*.{js,jsx,ts,tsx,svelte,vue}");
1562
+ IGNORED_DIRECTORIES = new Set([
1563
+ ".absolutejs",
1564
+ ".git",
1565
+ ".test-builds",
1566
+ ".test-shards",
1567
+ "build",
1568
+ "dist",
1569
+ "node_modules",
1570
+ "test",
1571
+ "tests"
1572
+ ]);
1573
+ IDENTIFIER_PATTERN = /^[A-Za-z_$][\w$]*$/u;
1574
+ ANDROID_PERMISSION_PATTERN = /^android\.permission\.[A-Z][A-Z0-9_]*$/u;
1575
+ IOS_USAGE_DESCRIPTIONS = new Set([
1576
+ "camera",
1577
+ "location-always",
1578
+ "location-when-in-use",
1579
+ "photo-library",
1580
+ "photo-library-add"
1581
+ ]);
1582
+ IOS_PRIVACY_ACCESSED_API_REASONS = {
1583
+ NSPrivacyAccessedAPICategoryFileTimestamp: new Set(["C617.1"])
1584
+ };
1585
+ IOS_PRIVACY_ACCESSED_APIS = [
1586
+ "NSPrivacyAccessedAPICategoryFileTimestamp"
1587
+ ];
1588
+ });
1589
+
1317
1590
  // src/mobile/expoProject.ts
1318
1591
  import {
1319
1592
  access,
@@ -1327,7 +1600,7 @@ import {
1327
1600
  writeFile
1328
1601
  } from "fs/promises";
1329
1602
  import { createHash } from "crypto";
1330
- import { basename as basename2, dirname as dirname4, join as join7, relative, resolve as resolve4 } from "path";
1603
+ import { basename as basename2, dirname as dirname4, join as join8, relative as relative2, resolve as resolve5 } from "path";
1331
1604
  var EXPO_GENERATED_HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.
1332
1605
  `, EXPO_ASSET_EXTENSION = ".absasset", EXPO_PROJECT_MARKER = ".absolutejs-expo-project", exists = async (path) => {
1333
1606
  try {
@@ -1337,7 +1610,7 @@ var EXPO_GENERATED_HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts
1337
1610
  return false;
1338
1611
  }
1339
1612
  }, portableRelative = (from, destination) => {
1340
- const value = relative(from, destination).replaceAll("\\", "/");
1613
+ const value = relative2(from, destination).replaceAll("\\", "/");
1341
1614
  return value.startsWith(".") ? value : `./${value}`;
1342
1615
  }, routeSegments = (route) => route.split("/").filter(Boolean).map((segment) => {
1343
1616
  if (segment.startsWith(":"))
@@ -1346,8 +1619,13 @@ var EXPO_GENERATED_HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts
1346
1619
  throw new TypeError(`Expo native route ${route} contains an unsupported segment ${segment}.`);
1347
1620
  }
1348
1621
  return segment;
1349
- }), routeFile = (project, route) => join7(project, "app", ...routeSegments(route), "index.tsx"), expoPackage = (auth, sync) => ({
1622
+ }), routeFile = (project, route) => join8(project, "app", ...routeSegments(route), "index.tsx"), packageDependencies = (plan) => Object.fromEntries(plan.requiredPackages.map((spec) => {
1623
+ const separator = spec.lastIndexOf("@");
1624
+ return [spec.slice(0, separator), spec.slice(separator + 1)];
1625
+ })), expoPackage = (auth, sync, devices) => ({
1350
1626
  dependencies: {
1627
+ "@absolutejs/devices": "0.7.0",
1628
+ "@absolutejs/devices-expo": "0.0.2",
1351
1629
  ...auth ? {
1352
1630
  "@absolutejs/auth": ABSOLUTE_EXPO_AUTH_CORE_VERSION,
1353
1631
  [ABSOLUTE_EXPO_AUTH_PACKAGE]: ABSOLUTE_EXPO_AUTH_VERSION
@@ -1379,7 +1657,8 @@ var EXPO_GENERATED_HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts
1379
1657
  "react-native": "0.86.3",
1380
1658
  "react-native-safe-area-context": "~5.7.0",
1381
1659
  "react-native-screens": "4.26.0",
1382
- "react-native-webview": "13.16.1"
1660
+ "react-native-webview": "13.16.1",
1661
+ ...packageDependencies(devices)
1383
1662
  },
1384
1663
  devDependencies: {
1385
1664
  "@types/react": "~19.2.2",
@@ -1394,36 +1673,107 @@ var EXPO_GENERATED_HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts
1394
1673
  start: "expo start --dev-client"
1395
1674
  },
1396
1675
  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');
1676
+ }), expoAppConfig = (config, auth, sync, devices) => {
1677
+ const requirements = absoluteDeviceNativeRequirements(devices);
1678
+ const usageKey = (purpose) => {
1679
+ if (purpose === "camera")
1680
+ return "NSCameraUsageDescription";
1681
+ if (purpose === "photo-library")
1682
+ return "NSPhotoLibraryUsageDescription";
1683
+ if (purpose === "photo-library-add")
1684
+ return "NSPhotoLibraryAddUsageDescription";
1685
+ if (purpose === "location-always")
1686
+ return "NSLocationAlwaysAndWhenInUseUsageDescription";
1687
+ return "NSLocationWhenInUseUsageDescription";
1688
+ };
1689
+ const usageDescription = (purpose) => {
1690
+ if (purpose === "camera")
1691
+ return `${config.appName} uses your camera when you choose to take a photo.`;
1692
+ if (purpose === "photo-library")
1693
+ return `${config.appName} accesses your photo library only for photo actions you choose.`;
1694
+ if (purpose.startsWith("location-"))
1695
+ return `${config.appName} uses your location only while you use the app and request a location-based action.`;
1696
+ return `${config.appName} adds to your photo library only for photo actions you choose.`;
1697
+ };
1698
+ const descriptions = Object.fromEntries(requirements.iosUsageDescriptions.map((purpose) => [
1699
+ usageKey(purpose),
1700
+ usageDescription(purpose)
1701
+ ]));
1702
+ const devicePlugins = [
1703
+ ...new Set(devices.capabilities.flatMap((name) => devices.providers[name]?.plugins ?? []))
1704
+ ];
1705
+ const configuredPlugins = devicePlugins.map((plugin) => {
1706
+ if (plugin === "expo-image-picker")
1707
+ return [
1708
+ plugin,
1709
+ {
1710
+ cameraPermission: descriptions.NSCameraUsageDescription,
1711
+ microphonePermission: false,
1712
+ photosPermission: descriptions.NSPhotoLibraryUsageDescription
1713
+ }
1714
+ ];
1715
+ if (plugin === "expo-location")
1716
+ return [
1717
+ plugin,
1718
+ {
1719
+ locationWhenInUsePermission: descriptions.NSLocationWhenInUseUsageDescription
1720
+ }
1721
+ ];
1722
+ return plugin;
1723
+ });
1724
+ return {
1725
+ expo: {
1726
+ android: {
1727
+ ...devicePlugins.includes("expo-image-picker") ? {
1728
+ blockedPermissions: [
1729
+ "android.permission.READ_EXTERNAL_STORAGE",
1730
+ "android.permission.RECORD_AUDIO",
1731
+ "android.permission.WRITE_EXTERNAL_STORAGE"
1732
+ ]
1733
+ } : {},
1734
+ intentFilters: config.deepLinkHosts.map((host2) => ({
1735
+ action: "VIEW",
1736
+ autoVerify: true,
1737
+ category: ["BROWSABLE", "DEFAULT"],
1738
+ data: [{ host: host2, pathPrefix: "/", scheme: "https" }]
1739
+ })),
1740
+ package: config.appId,
1741
+ permissions: requirements.androidPermissions
1742
+ },
1743
+ experiments: { typedRoutes: true },
1744
+ ios: {
1745
+ associatedDomains: config.deepLinkHosts.map((host2) => `applinks:${host2}`),
1746
+ bundleIdentifier: config.appId,
1747
+ infoPlist: descriptions,
1748
+ ...requirements.iosPrivacyAccessedApis.length > 0 ? {
1749
+ privacyManifests: {
1750
+ NSPrivacyAccessedAPITypes: requirements.iosPrivacyAccessedApis.map(({ api, reasons }) => ({
1751
+ NSPrivacyAccessedAPIType: api,
1752
+ NSPrivacyAccessedAPITypeReasons: reasons
1753
+ }))
1754
+ }
1755
+ } : {},
1756
+ ...config.iosVersion ? { buildNumber: config.iosVersion } : {}
1757
+ },
1758
+ name: config.appName,
1759
+ plugins: [
1760
+ "expo-router",
1761
+ ["expo-dev-client", { launchMode: "most-recent" }],
1762
+ ...auth ? ["expo-secure-store"] : [],
1763
+ ...sync ? [
1764
+ "expo-sqlite",
1765
+ "expo-background-task",
1766
+ "expo-task-manager"
1767
+ ] : [],
1768
+ ...configuredPlugins
1769
+ ],
1770
+ runtimeVersion: { policy: "appVersion" },
1771
+ scheme: config.deepLinkScheme,
1772
+ slug: config.appId.toLowerCase().replaceAll(".", "-"),
1773
+ version: config.iosVersion ?? "0.1.0"
1774
+ }
1775
+ };
1776
+ }, expoDynamicAppConfig, expoDevelopmentCaPlugin, metroConfig = (projectRoot) => `${EXPO_GENERATED_HEADER}const { getDefaultConfig } = require('expo/metro-config');
1427
1777
  const path = require('node:path');
1428
1778
 
1429
1779
  const projectRoot = __dirname;
@@ -1438,6 +1788,7 @@ config.watchFolders = [appRoot];
1438
1788
 
1439
1789
  module.exports = config;
1440
1790
  `, layoutSource = (auth, sync) => `${EXPO_GENERATED_HEADER}import { Stack } from 'expo-router';
1791
+ import '../src/generated/AbsoluteDevices';
1441
1792
  ${auth ? `import { useEffect, useState } from 'react';
1442
1793
  import { startAbsoluteExpoAuth } from '../src/generated/AbsoluteAuth';` : ""}
1443
1794
  ${sync ? "import { startAbsoluteExpoSync } from '../src/generated/AbsoluteSync';" : ""}
@@ -1452,7 +1803,76 @@ export default function AbsoluteLayout() {
1452
1803
  if (!ready) return null;` : ""}
1453
1804
  return <Stack screenOptions={{ headerShown: false }} />;
1454
1805
  }
1455
- `, nativeDiagnosticSource, authRuntimeSource = (auth, appId) => {
1806
+ `, nativeDiagnosticSource, devicesRuntimeSource = (config, plan, auth) => {
1807
+ const imports = plan.capabilities.map((name, index) => {
1808
+ const provider = plan.providers[name];
1809
+ if (!provider)
1810
+ throw new TypeError(`Missing Expo device capability provider ${name}.`);
1811
+ return `import { ${provider.factory} as absoluteExpoCapability${index} } from ${JSON.stringify(provider.module)};`;
1812
+ });
1813
+ const pushIndex = plan.capabilities.indexOf("pushNotifications");
1814
+ const push = pushIndex !== -1;
1815
+ if (push && !auth)
1816
+ throw new TypeError("Expo push notifications require the provisioned AbsoluteJS Auth runtime.");
1817
+ const entries = plan.capabilities.map((name, index) => `${JSON.stringify(name)}: absoluteExpoCapability${index}(${name === "pushNotifications" ? "absoluteExpoPushOptions" : ""})`).join(`,
1818
+ `);
1819
+ const pushSource = push ? `const INSTALLATION_KEY = 'absolutejs.push.installation-id';
1820
+ const requirePushResponse = async (response: Response, operation: string) => {
1821
+ if (!response.ok) throw new Error(\`AbsoluteJS native push \${operation} failed with HTTP \${response.status}.\`);
1822
+ return response.json() as Promise<Record<string, unknown>>;
1823
+ };
1824
+ const absoluteExpoPushOptions = {
1825
+ onRegistration: async (registration: { platform: 'apns' | 'fcm'; token: string }) => {
1826
+ const known = await absoluteExpoDevices.storage.get(INSTALLATION_KEY);
1827
+ const register = (installationId?: string | null) => absoluteExpoAuth.fetch('/auth/push', {
1828
+ body: JSON.stringify({ ...(installationId ? { installationId } : {}), platform: registration.platform, token: registration.token }),
1829
+ headers: { 'content-type': 'application/json' },
1830
+ method: 'POST'
1831
+ });
1832
+ let response = await register(known);
1833
+ const conflict = response.status === 409 && await response.clone().json().then(value => typeof value === 'object' && value !== null && Reflect.get(value, 'code') === 'installation-ownership').catch(() => false);
1834
+ if (known && conflict) {
1835
+ await absoluteExpoDevices.storage.remove(INSTALLATION_KEY);
1836
+ response = await register();
1837
+ }
1838
+ const result = await requirePushResponse(response, 'registration');
1839
+ if (typeof result.installationId !== 'string' || !result.installationId || result.installationId.length > 128) throw new Error('AbsoluteJS native push returned an invalid installation identity.');
1840
+ await absoluteExpoDevices.storage.set(INSTALLATION_KEY, result.installationId);
1841
+ },
1842
+ onUnregistration: async () => {
1843
+ const installationId = await absoluteExpoDevices.storage.get(INSTALLATION_KEY);
1844
+ if (!installationId) return;
1845
+ await requirePushResponse(await absoluteExpoAuth.fetch('/auth/push', {
1846
+ body: JSON.stringify({ installationId }),
1847
+ headers: { 'content-type': 'application/json' },
1848
+ method: 'DELETE'
1849
+ }), 'removal');
1850
+ await absoluteExpoDevices.storage.remove(INSTALLATION_KEY);
1851
+ }
1852
+ };` : "";
1853
+ return `${EXPO_GENERATED_HEADER}import { installDeviceAdapter } from '@absolutejs/devices/runtime';
1854
+ import { createExpoDeviceAdapter } from '@absolutejs/devices-expo';
1855
+ ${push ? "import { absoluteExpoAuth } from './AbsoluteAuth';" : ""}
1856
+ ${imports.join(`
1857
+ `)}
1858
+
1859
+ ${pushSource}
1860
+
1861
+ export const absoluteExpoDeviceCapabilities = ${JSON.stringify(plan.capabilities)} as const;
1862
+ export const absoluteExpoDevices = createExpoDeviceAdapter({
1863
+ storagePrefix: ${JSON.stringify(`absolutejs.${config.appId}.`)},
1864
+ ${entries}
1865
+ });
1866
+ installDeviceAdapter(absoluteExpoDevices);
1867
+ export const beforeAbsoluteExpoDeviceSignOut = async () => {
1868
+ ${push ? "await absoluteExpoDevices.pushNotifications?.disable();" : ""}
1869
+ };
1870
+ ${push ? `absoluteExpoAuth.onPrincipalChange(principal => {
1871
+ if (!principal) return;
1872
+ void absoluteExpoDevices.pushNotifications?.queryPermission().then(permission => permission.state === 'granted' ? absoluteExpoDevices.pushNotifications?.enable() : undefined).catch(() => undefined);
1873
+ });` : ""}
1874
+ `;
1875
+ }, authRuntimeSource = (auth, appId) => {
1456
1876
  const storageIdentity = createHash("sha256").update(appId).digest("hex").slice(0, 24);
1457
1877
  return `${EXPO_GENERATED_HEADER}import { createAbsoluteExpoAuthClient } from '@absolutejs/auth-expo';
1458
1878
  import { createMobileAuthTransport, installAuthClientRuntimeTransport } from '@absolutejs/auth/client/mobile';
@@ -1585,13 +2005,14 @@ export const createAbsoluteExpoSyncBridge = async (
1585
2005
  "/__absolute/native",
1586
2006
  ...Object.keys(config.expoNativeRoutes)
1587
2007
  ];
1588
- return `${EXPO_GENERATED_HEADER}import * as Haptics from 'expo-haptics';
1589
- import * as Linking from 'expo-linking';
2008
+ return `${EXPO_GENERATED_HEADER}import * as Linking from 'expo-linking';
1590
2009
  import { router, usePathname } from 'expo-router';
1591
2010
  import { useEffect, useRef, useState } from 'react';
1592
2011
  import { ActivityIndicator, BackHandler, Platform, StyleSheet, View } from 'react-native';
1593
2012
  import { WebView, type WebViewMessageEvent } from 'react-native-webview';
1594
2013
  import { materializeAbsoluteWebBundle } from './webAssets';
2014
+ import { createExpoDevicesBridgeHost } from '@absolutejs/devices-expo/bridge';
2015
+ import { absoluteExpoDevices, beforeAbsoluteExpoDeviceSignOut } from './AbsoluteDevices';
1595
2016
  ${auth ? "import { absoluteExpoAuth, getAbsoluteExpoAuthPrincipal, startAbsoluteExpoAuth } from './AbsoluteAuth';" : ""}
1596
2017
  ${sync ? "import { createAbsoluteExpoSyncBridge, startAbsoluteExpoSync } from './AbsoluteSync';" : ""}
1597
2018
 
@@ -1647,10 +2068,11 @@ const bridgeBootstrap = (path: string) => {
1647
2068
  const id = 'web_' + Date.now().toString(36) + '_' + (++sequence).toString(36);
1648
2069
  send({ format: 3, id, kind: 'request', method, params, path: currentPath });
1649
2070
  return new Promise((resolve, reject) => {
2071
+ const interactive = method.startsWith('devices.camera.') || method.startsWith('devices.photos.') || method.startsWith('devices.documents.') || method.endsWith('.requestPermission');
1650
2072
  const timer = setTimeout(() => {
1651
2073
  pending.delete(id);
1652
2074
  reject(new Error('Expo bridge request timed out.'));
1653
- }, 10000);
2075
+ }, interactive ? 5 * 60 * 1000 : 30 * 1000);
1654
2076
  pending.set(id, { reject, resolve, timer });
1655
2077
  });
1656
2078
  },
@@ -1689,17 +2111,6 @@ const bridgeBootstrap = (path: string) => {
1689
2111
  })(); true;\`;
1690
2112
  };
1691
2113
 
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
2114
  const bridgeFetch = async (params: Record<string, unknown>) => {
1704
2115
  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
2116
  const url = new URL(params.url);
@@ -1731,10 +2142,12 @@ const authStatus = async () => {
1731
2142
  export function AbsoluteWebHost() {
1732
2143
  const pathname = usePathname() || '/';
1733
2144
  const webView = useRef<WebView>(null);
2145
+ const devicesBridge = useRef<{ close(): void | Promise<void>; request(method: string, params: Record<string, unknown>): Promise<unknown> } | undefined>(undefined);
1734
2146
  const syncBridge = useRef<{ close(): void | Promise<void>; request(method: string, params: Record<string, unknown>): Promise<unknown> } | undefined>(undefined);
1735
2147
  const [indexUri, setIndexUri] = useState<string>();
1736
2148
  const [canGoBack, setCanGoBack] = useState(false);
1737
2149
  const [runtimeReady, setRuntimeReady] = useState(!AUTH_ENABLED && !SYNC_ENABLED);
2150
+ const [devicesReady, setDevicesReady] = useState(false);
1738
2151
  const activeWebPath = useRef(pathname);
1739
2152
 
1740
2153
  useEffect(() => {
@@ -1784,6 +2197,23 @@ export function AbsoluteWebHost() {
1784
2197
  if (new TextEncoder().encode(source).byteLength > MAX_MESSAGE_BYTES) throw new Error('Expo bridge response exceeds 64 KiB.');
1785
2198
  webView.current?.injectJavaScript(\`globalThis.__absoluteExpoReceive(\${JSON.stringify(source)}); true;\`);
1786
2199
  };
2200
+ useEffect(() => {
2201
+ let active = true;
2202
+ void createExpoDevicesBridgeHost(absoluteExpoDevices, (event, payload) => {
2203
+ if (!active) return;
2204
+ respond({ event, format: BRIDGE_FORMAT, kind: 'event', path: activeWebPath.current, payload });
2205
+ }).then(host => {
2206
+ if (!active) return void host.close();
2207
+ devicesBridge.current = host;
2208
+ setDevicesReady(true);
2209
+ });
2210
+ return () => {
2211
+ active = false;
2212
+ const host = devicesBridge.current;
2213
+ devicesBridge.current = undefined;
2214
+ void host?.close();
2215
+ };
2216
+ }, []);
1787
2217
  const hasOrigin = (source: string, origin: string) => {
1788
2218
  try { return new URL(source).origin === origin; } catch { return false; }
1789
2219
  };
@@ -1803,11 +2233,9 @@ export function AbsoluteWebHost() {
1803
2233
  if (message.kind !== 'request' || typeof message.id !== 'string' || message.path !== activeWebPath.current) return;
1804
2234
  try {
1805
2235
  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 });
2236
+ if (typeof message.method === 'string' && message.method.startsWith('devices.')) {
2237
+ if (!devicesBridge.current) throw new Error('Expo devices bridge is unavailable.');
2238
+ respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: await devicesBridge.current.request(message.method, message.params as Record<string, unknown>) });
1811
2239
  } else if (message.method === 'http.fetch') {
1812
2240
  respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: await bridgeFetch(message.params as Record<string, unknown>) });
1813
2241
  } else if (message.method === 'auth.signIn') {
@@ -1816,7 +2244,8 @@ export function AbsoluteWebHost() {
1816
2244
  await absoluteExpoAuth.signIn({ authorizationParameters: { login_hint: params.email, ...(params.signup ? { screen_hint: 'signup' } : {}) } });
1817
2245
  respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: await authStatus() });` : "throw new Error('Expo Auth is not configured.');"}
1818
2246
  } else if (message.method === 'auth.signOut') {
1819
- ${auth ? `await absoluteExpoAuth.signOut();
2247
+ ${auth ? `await beforeAbsoluteExpoDeviceSignOut();
2248
+ await absoluteExpoAuth.signOut();
1820
2249
  respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: null });` : "throw new Error('Expo Auth is not configured.');"}
1821
2250
  } else if (message.method === 'auth.status') {
1822
2251
  respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: await authStatus() });
@@ -1831,7 +2260,7 @@ export function AbsoluteWebHost() {
1831
2260
  }
1832
2261
  };
1833
2262
 
1834
- if (!indexUri || !runtimeReady) return <View style={styles.loading}><ActivityIndicator /></View>;
2263
+ if (!indexUri || !runtimeReady || !devicesReady) return <View style={styles.loading}><ActivityIndicator /></View>;
1835
2264
  return <WebView
1836
2265
  allowFileAccess
1837
2266
  allowFileAccessFromFileURLs
@@ -1907,9 +2336,10 @@ const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, jus
1907
2336
  `, emptyWebAssetsSource, writeAbsoluteExpoProject = async (config, options) => {
1908
2337
  if (config.engine !== "expo")
1909
2338
  throw new TypeError("Expo project generation requires mobile.engine: expo.");
1910
- const projectRoot = resolve4(options.projectRoot);
2339
+ const projectRoot = resolve5(options.projectRoot);
1911
2340
  const project = config.nativeProjectDirectory;
1912
2341
  const auth = resolveAbsoluteMobileAuthManifest(projectRoot, config);
2342
+ const devices = resolveAbsoluteDeviceCapabilityPlan(projectRoot, "expo");
1913
2343
  const syncEnabled = Boolean(auth && projectUsesAbsoluteSync(projectRoot));
1914
2344
  const syncSchema = syncEnabled ? { components: discoverAbsoluteSyncSchema(projectRoot).components } : undefined;
1915
2345
  const routeModules = Object.entries(config.expoNativeRoutes);
@@ -1922,7 +2352,7 @@ const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, jus
1922
2352
  if (missing) {
1923
2353
  throw new TypeError(`Expo native route ${missing.route} references missing module ${missing.module}.`);
1924
2354
  }
1925
- const marker = join7(project, EXPO_PROJECT_MARKER);
2355
+ const marker = join8(project, EXPO_PROJECT_MARKER);
1926
2356
  if (await exists(project) && !await exists(marker)) {
1927
2357
  const entries = await readdir(project);
1928
2358
  if (entries.length > 0 && !options.force) {
@@ -1935,7 +2365,7 @@ const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, jus
1935
2365
  const authEnabled = Boolean(auth);
1936
2366
  const files = new Map([
1937
2367
  [
1938
- join7(project, ".gitignore"),
2368
+ join8(project, ".gitignore"),
1939
2369
  `.expo/
1940
2370
  android/
1941
2371
  ios/
@@ -1943,52 +2373,56 @@ node_modules/
1943
2373
  `
1944
2374
  ],
1945
2375
  [
1946
- join7(project, "app.json"),
1947
- jsonSource(expoAppConfig(config, authEnabled, syncEnabled))
2376
+ join8(project, "app.json"),
2377
+ jsonSource(expoAppConfig(config, authEnabled, syncEnabled, devices))
1948
2378
  ],
1949
- [join7(project, "app.config.js"), expoDynamicAppConfig],
2379
+ [join8(project, "app.config.js"), expoDynamicAppConfig],
1950
2380
  [
1951
- join7(project, "package.json"),
1952
- jsonSource(expoPackage(authEnabled, syncEnabled))
2381
+ join8(project, "package.json"),
2382
+ jsonSource(expoPackage(authEnabled, syncEnabled, devices))
1953
2383
  ],
1954
- [join7(project, "metro.config.js"), metroConfig(projectRoot)],
2384
+ [join8(project, "metro.config.js"), metroConfig(projectRoot)],
1955
2385
  [
1956
- join7(project, "plugins", "withAbsoluteDevelopmentCa.js"),
2386
+ join8(project, "plugins", "withAbsoluteDevelopmentCa.js"),
1957
2387
  expoDevelopmentCaPlugin
1958
2388
  ],
1959
2389
  [
1960
- join7(project, "tsconfig.json"),
2390
+ join8(project, "tsconfig.json"),
1961
2391
  jsonSource(expoTsConfig(projectRoot, project, authEnabled, syncEnabled))
1962
2392
  ],
1963
2393
  [
1964
- join7(project, "app", "_layout.tsx"),
2394
+ join8(project, "app", "_layout.tsx"),
1965
2395
  layoutSource(authEnabled, syncEnabled)
1966
2396
  ],
1967
2397
  [
1968
- join7(project, "app", "__absolute", "native", "index.tsx"),
2398
+ join8(project, "app", "__absolute", "native", "index.tsx"),
1969
2399
  nativeDiagnosticSource
1970
2400
  ],
1971
2401
  [
1972
- join7(project, "src", "generated", "AbsoluteWebHost.tsx"),
2402
+ join8(project, "src", "generated", "AbsoluteDevices.ts"),
2403
+ devicesRuntimeSource(config, devices, authEnabled)
2404
+ ],
2405
+ [
2406
+ join8(project, "src", "generated", "AbsoluteWebHost.tsx"),
1973
2407
  webHostSource(config, auth, syncEnabled)
1974
2408
  ]
1975
2409
  ]);
1976
2410
  if (auth) {
1977
- files.set(join7(project, "src", "generated", "AbsoluteAuth.ts"), authRuntimeSource(auth, config.appId));
2411
+ files.set(join8(project, "src", "generated", "AbsoluteAuth.ts"), authRuntimeSource(auth, config.appId));
1978
2412
  }
1979
2413
  if (syncSchema) {
1980
- files.set(join7(project, "src", "generated", "AbsoluteSync.ts"), syncRuntimeSource(config, syncSchema));
2414
+ files.set(join8(project, "src", "generated", "AbsoluteSync.ts"), syncRuntimeSource(config, syncSchema));
1981
2415
  }
1982
- const webAssetsPath = join7(project, "src", "generated", "webAssets.ts");
2416
+ const webAssetsPath = join8(project, "src", "generated", "webAssets.ts");
1983
2417
  if (!await exists(webAssetsPath)) {
1984
2418
  files.set(webAssetsPath, emptyWebAssetsSource);
1985
2419
  }
1986
2420
  if (!config.expoNativeRoutes["/"]) {
1987
- files.set(join7(project, "app", "index.tsx"), webRouteSource);
2421
+ files.set(join8(project, "app", "index.tsx"), webRouteSource);
1988
2422
  }
1989
- files.set(join7(project, "app", "[...absolute].tsx"), catchAllRouteSource);
2423
+ files.set(join8(project, "app", "[...absolute].tsx"), catchAllRouteSource);
1990
2424
  for (const [route, module] of routeModules) {
1991
- const wrapper = route === "/" ? join7(project, "app", "index.tsx") : routeFile(project, route);
2425
+ const wrapper = route === "/" ? join8(project, "app", "index.tsx") : routeFile(project, route);
1992
2426
  files.set(wrapper, nativeWrapperSource(wrapper, module));
1993
2427
  }
1994
2428
  const changes = await Promise.all([...files].map(([path, source]) => writeManagedFile(path, source, true)));
@@ -1997,7 +2431,7 @@ node_modules/
1997
2431
  }, walkFiles = async (root, directory = root) => {
1998
2432
  const entries = await readdir(directory, { withFileTypes: true });
1999
2433
  const nested = await Promise.all(entries.map((entry) => {
2000
- const path = join7(directory, entry.name);
2434
+ const path = join8(directory, entry.name);
2001
2435
  if (entry.isDirectory())
2002
2436
  return walkFiles(root, path);
2003
2437
  if (entry.isFile())
@@ -2058,11 +2492,11 @@ export const materializeAbsoluteWebBundle = async () => {
2058
2492
  `, syncAbsoluteExpoWebAssets = async (config) => {
2059
2493
  if (config.engine !== "expo")
2060
2494
  throw new TypeError("Expo asset sync requires mobile.engine: expo.");
2061
- const marker = join7(config.nativeProjectDirectory, EXPO_PROJECT_MARKER);
2495
+ const marker = join8(config.nativeProjectDirectory, EXPO_PROJECT_MARKER);
2062
2496
  if (!await exists(marker)) {
2063
2497
  throw new TypeError("Expo asset sync requires an AbsoluteJS-managed Expo project. Run mobile init first.");
2064
2498
  }
2065
- const manifestPath = join7(config.bundleDirectory, "absolute-mobile-manifest.json");
2499
+ const manifestPath = join8(config.bundleDirectory, "absolute-mobile-manifest.json");
2066
2500
  const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
2067
2501
  const appBuild = typeof manifest === "object" && manifest !== null && typeof Reflect.get(manifest, "appBuild") === "string" ? String(Reflect.get(manifest, "appBuild")) : undefined;
2068
2502
  if (!appBuild)
@@ -2071,23 +2505,23 @@ export const materializeAbsoluteWebBundle = async () => {
2071
2505
  const bundleHash = createHash("sha256");
2072
2506
  const filesWithContents = await Promise.all(files.map(async (file) => ({ contents: await readFile(file), file })));
2073
2507
  filesWithContents.forEach(({ contents, file }) => {
2074
- bundleHash.update(relative(config.bundleDirectory, file).replaceAll("\\", "/"));
2508
+ bundleHash.update(relative2(config.bundleDirectory, file).replaceAll("\\", "/"));
2075
2509
  bundleHash.update("\x00");
2076
2510
  bundleHash.update(contents);
2077
2511
  bundleHash.update("\x00");
2078
2512
  });
2079
2513
  const bundleId = `amexpo_${bundleHash.digest("hex")}`;
2080
- const destination = join7(config.nativeProjectDirectory, "assets", "absolute");
2514
+ const destination = join8(config.nativeProjectDirectory, "assets", "absolute");
2081
2515
  await mkdir(dirname4(destination), { recursive: true });
2082
- const staging = await mkdtemp(join7(dirname4(destination), `.${basename2(destination)}.stage-`));
2516
+ const staging = await mkdtemp(join8(dirname4(destination), `.${basename2(destination)}.stage-`));
2083
2517
  let assets;
2084
2518
  try {
2085
2519
  assets = await Promise.all(files.map(async (source, index) => {
2086
2520
  const name = `${String(index).padStart(6, "0")}${EXPO_ASSET_EXTENSION}`;
2087
- await cp(source, join7(staging, name));
2521
+ await cp(source, join8(staging, name));
2088
2522
  return {
2089
- asset: portableRelative(join7(config.nativeProjectDirectory, "src", "generated"), join7(destination, name)),
2090
- path: relative(config.bundleDirectory, source).replaceAll("\\", "/")
2523
+ asset: portableRelative(join8(config.nativeProjectDirectory, "src", "generated"), join8(destination, name)),
2524
+ path: relative2(config.bundleDirectory, source).replaceAll("\\", "/")
2091
2525
  };
2092
2526
  }));
2093
2527
  await installStagedDirectory(staging, destination);
@@ -2095,13 +2529,14 @@ export const materializeAbsoluteWebBundle = async () => {
2095
2529
  await rm(staging, { force: true, recursive: true });
2096
2530
  throw error;
2097
2531
  }
2098
- const generated = join7(config.nativeProjectDirectory, "src", "generated", "webAssets.ts");
2532
+ const generated = join8(config.nativeProjectDirectory, "src", "generated", "webAssets.ts");
2099
2533
  await writeManagedFile(generated, assetModuleSource(assets, bundleId), true);
2100
2534
  return { appBuild, assets: assets.length, bundleId, path: destination };
2101
2535
  };
2102
2536
  var init_expoProject = __esm(() => {
2103
2537
  init_nativeAuth();
2104
2538
  init_syncSchema();
2539
+ init_deviceCapabilities();
2105
2540
  expoDynamicAppConfig = `${EXPO_GENERATED_HEADER}const config = require('./app.json');
2106
2541
 
2107
2542
  if (process.env.ABSOLUTE_EXPO_DEVELOPMENT === '1' && process.env.ABSOLUTE_EXPO_DEVELOPMENT_CA_PATH) {
@@ -2207,14 +2642,14 @@ import {
2207
2642
  isIP
2208
2643
  } from "net";
2209
2644
  import { readFile as readFile2 } from "fs/promises";
2210
- var closeServer = (server) => new Promise((resolve5, reject) => {
2645
+ var closeServer = (server) => new Promise((resolve6, reject) => {
2211
2646
  server.close((error) => {
2212
2647
  if (error)
2213
2648
  reject(error);
2214
2649
  else
2215
- resolve5();
2650
+ resolve6();
2216
2651
  });
2217
- }), listen = (server, port) => new Promise((resolve5, reject) => {
2652
+ }), listen = (server, port) => new Promise((resolve6, reject) => {
2218
2653
  server.once("error", reject);
2219
2654
  server.listen(port, "0.0.0.0", () => {
2220
2655
  server.off("error", reject);
@@ -2223,11 +2658,11 @@ var closeServer = (server) => new Promise((resolve5, reject) => {
2223
2658
  reject(new Error("Could not determine the iOS device helper port."));
2224
2659
  return;
2225
2660
  }
2226
- resolve5(address.port);
2661
+ resolve6(address.port);
2227
2662
  });
2228
2663
  }), findEphemeralPort = async () => {
2229
2664
  const probe = createTcpServer();
2230
- const port = await new Promise((resolve5, reject) => {
2665
+ const port = await new Promise((resolve6, reject) => {
2231
2666
  probe.once("error", reject);
2232
2667
  probe.listen(0, "127.0.0.1", () => {
2233
2668
  const address = probe.address();
@@ -2235,7 +2670,7 @@ var closeServer = (server) => new Promise((resolve5, reject) => {
2235
2670
  reject(new Error("Could not allocate the iOS CA enrollment port."));
2236
2671
  return;
2237
2672
  }
2238
- resolve5(address.port);
2673
+ resolve6(address.port);
2239
2674
  });
2240
2675
  });
2241
2676
  await closeServer(probe);
@@ -2292,12 +2727,12 @@ var init_iosPhysicalDeviceTransport = () => {};
2292
2727
  // src/cli/utils.ts
2293
2728
  var {$: $2 } = globalThis.Bun;
2294
2729
  import { execSync } from "child_process";
2295
- import { existsSync as existsSync3, readFileSync as readFileSync7 } from "fs";
2730
+ import { existsSync as existsSync4, readFileSync as readFileSync8 } from "fs";
2296
2731
  import { createServer as createServer3 } from "net";
2297
- import { resolve as resolve5 } from "path";
2732
+ import { resolve as resolve6 } from "path";
2298
2733
  var COMPOSE_PATH = "db/docker-compose.db.yml", DEFAULT_SERVER_ENTRY = "src/backend/server.ts", isWSLEnvironment = () => {
2299
2734
  try {
2300
- const release = readFileSync7("/proc/version", "utf-8");
2735
+ const release = readFileSync8("/proc/version", "utf-8");
2301
2736
  return /microsoft|wsl/i.test(release);
2302
2737
  } catch {
2303
2738
  return false;
@@ -2396,8 +2831,8 @@ var COMPOSE_PATH = "db/docker-compose.db.yml", DEFAULT_SERVER_ENTRY = "src/backe
2396
2831
  }, printHint = () => {
2397
2832
  console.log("\x1B[90mpress h + enter to show shortcuts\x1B[0m");
2398
2833
  }, readDbScripts = async () => {
2399
- const pkgPath = resolve5("package.json");
2400
- if (!existsSync3(pkgPath))
2834
+ const pkgPath = resolve6("package.json");
2835
+ if (!existsSync4(pkgPath))
2401
2836
  return null;
2402
2837
  const pkg = await Bun.file(pkgPath).json();
2403
2838
  const upCommand = pkg.scripts?.["db:up"];
@@ -2431,7 +2866,7 @@ var init_utils = __esm(() => {
2431
2866
  // src/mobile/emulatorDoctor.ts
2432
2867
  import { access as access3 } from "fs/promises";
2433
2868
  import { homedir as homedir3 } from "os";
2434
- import { join as join9 } from "path";
2869
+ import { join as join10 } from "path";
2435
2870
  var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command) => {
2436
2871
  try {
2437
2872
  const result = Bun.spawnSync(command, {
@@ -2476,15 +2911,15 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
2476
2911
  }
2477
2912
  }, absoluteManagedAndroidSdkRoot = (host2, env = process.env) => {
2478
2913
  if (host2 === "windows") {
2479
- return join9(env.LOCALAPPDATA ?? join9(homedir3(), "AppData", "Local"), "AbsoluteJS", "Android", "Sdk");
2914
+ return join10(env.LOCALAPPDATA ?? join10(homedir3(), "AppData", "Local"), "AbsoluteJS", "Android", "Sdk");
2480
2915
  }
2481
2916
  if (host2 === "wsl") {
2482
2917
  const localAppData = windowsLocalAppDataFromWsl();
2483
2918
  if (localAppData) {
2484
- return join9(localAppData, "AbsoluteJS", "Android", "Sdk");
2919
+ return join10(localAppData, "AbsoluteJS", "Android", "Sdk");
2485
2920
  }
2486
2921
  }
2487
- return join9(homedir3(), ".absolutejs", "android-sdk");
2922
+ return join10(homedir3(), ".absolutejs", "android-sdk");
2488
2923
  }, pathExists = async (path) => {
2489
2924
  try {
2490
2925
  await access3(path);
@@ -2537,7 +2972,7 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
2537
2972
  const capture = input.capture ?? captureCommand;
2538
2973
  const androidRoot = input.androidRoot === null ? undefined : input.androidRoot ?? env.ANDROID_HOME ?? env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(host2, env);
2539
2974
  const windowsAndroidTools = host2 === "windows" || host2 === "wsl";
2540
- const android = (segments) => androidRoot ? join9(androidRoot, ...segments) : undefined;
2975
+ const android = (segments) => androidRoot ? join10(androidRoot, ...segments) : undefined;
2541
2976
  const paths = (values) => values.filter((value) => Boolean(value));
2542
2977
  const adb = await findExecutable("adb", paths([
2543
2978
  android(["platform-tools", windowsAndroidTools ? "adb.exe" : "adb"])
@@ -2644,8 +3079,8 @@ var init_emulatorDoctor = __esm(() => {
2644
3079
 
2645
3080
  // src/mobile/capacitorProject.ts
2646
3081
  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';
3082
+ import { relative as relative3, resolve as resolve7 } from "path";
3083
+ var CONFIG_FILE = "capacitor.config.ts", portableRelative2 = (root, path) => relative3(root, path).replaceAll("\\", "/"), capacitorConfigSource = (config, projectRoot) => `import type { CapacitorConfig } from '@capacitor/cli';
2649
3084
 
2650
3085
  const config: CapacitorConfig = {
2651
3086
  appId: ${JSON.stringify(config.appId)},
@@ -2668,8 +3103,8 @@ export default config;
2668
3103
  return false;
2669
3104
  }
2670
3105
  }, writeAbsoluteCapacitorConfig = async (config, options) => {
2671
- const projectRoot = resolve6(options.projectRoot);
2672
- const destination = resolve6(projectRoot, CONFIG_FILE);
3106
+ const projectRoot = resolve7(options.projectRoot);
3107
+ const destination = resolve7(projectRoot, CONFIG_FILE);
2673
3108
  const source = capacitorConfigSource(config, projectRoot);
2674
3109
  if (await exists2(destination)) {
2675
3110
  const current = await readFile3(destination, "utf8");
@@ -2704,9 +3139,9 @@ import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
2704
3139
  import {
2705
3140
  dirname as dirname5,
2706
3141
  isAbsolute,
2707
- join as join10,
2708
- relative as relative3,
2709
- resolve as resolve7,
3142
+ join as join11,
3143
+ relative as relative4,
3144
+ resolve as resolve8,
2710
3145
  sep,
2711
3146
  win32
2712
3147
  } from "path";
@@ -2876,21 +3311,21 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
2876
3311
  return;
2877
3312
  throw new DOMException("Android development startup was cancelled.", "AbortError");
2878
3313
  }, journalPaths = (projectRoot) => {
2879
- const root = join10(projectRoot, ".absolutejs", "mobile", "dev-session");
3314
+ const root = join11(projectRoot, ".absolutejs", "mobile", "dev-session");
2880
3315
  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"),
3316
+ backup: join11(root, "capacitor.config.backup.json"),
3317
+ caBackup: join11(root, "absolutejs_dev_ca.backup.pem"),
3318
+ journal: join11(root, "journal.json"),
3319
+ manifestBackup: join11(root, "AndroidManifest.backup.xml"),
3320
+ networkConfigBackup: join11(root, "absolutejs_dev_network_security.backup.xml"),
2886
3321
  root
2887
3322
  };
2888
3323
  }, isInside = (root, path) => {
2889
- const resolvedRoot = resolve7(root);
2890
- const resolvedPath = resolve7(path);
2891
- const relativePath = relative3(resolvedRoot, resolvedPath);
3324
+ const resolvedRoot = resolve8(root);
3325
+ const resolvedPath = resolve8(path);
3326
+ const relativePath = relative4(resolvedRoot, resolvedPath);
2892
3327
  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) => {
3328
+ }, isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value), nativeCachePath = (projectRoot) => join11(projectRoot, ".absolutejs", "mobile", "cache", "android-debug.json"), parseNativeCache = (value) => {
2894
3329
  if (!isRecord(value))
2895
3330
  return null;
2896
3331
  const { appId, fingerprint, format, installations } = value;
@@ -2922,11 +3357,11 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
2922
3357
  });
2923
3358
  }
2924
3359
  }, nativeDependencySources = async (nativeDirectory) => {
2925
- const settings = await readFile4(join10(nativeDirectory, "capacitor.settings.gradle"), "utf8");
3360
+ const settings = await readFile4(join11(nativeDirectory, "capacitor.settings.gradle"), "utf8");
2926
3361
  const pattern = new RegExp(CAPACITOR_PROJECT_DIRECTORY_PATTERN.source, CAPACITOR_PROJECT_DIRECTORY_PATTERN.flags);
2927
3362
  const dependencies = [...settings.matchAll(pattern)].map((match) => ({
2928
3363
  name: (match[1] ?? "").slice(1).replaceAll(/[^a-zA-Z0-9_.-]/gu, "_"),
2929
- source: resolve7(nativeDirectory, match[2] ?? "")
3364
+ source: resolve8(nativeDirectory, match[2] ?? "")
2930
3365
  }));
2931
3366
  if (dependencies.length === 0) {
2932
3367
  throw new Error("Capacitor Android settings did not declare any native dependencies.");
@@ -2939,7 +3374,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
2939
3374
  }
2940
3375
  return ignorePublicBundle && parts.slice(0, NATIVE_PUBLIC_PATH_SEGMENTS).join("/") === "app/src/main/assets/public";
2941
3376
  }, collectNativePath = async (root, label, path, isDirectory, isFile, isSymbolicLink, ignorePublicBundle) => {
2942
- const relativePath = relative3(root, path);
3377
+ const relativePath = relative4(root, path);
2943
3378
  if (shouldIgnoreNativePath(relativePath, ignorePublicBundle))
2944
3379
  return [];
2945
3380
  const identity = `${label}:${relativePath.split(sep).join("/")}\x00`;
@@ -2962,7 +3397,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
2962
3397
  }, collectNativeDirectory = async (root, label, directory, ignorePublicBundle) => {
2963
3398
  const entries = await readdir2(directory, { withFileTypes: true });
2964
3399
  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)));
3400
+ const records = await Promise.all(entries.map((entry) => collectNativePath(root, label, join11(directory, entry.name), entry.isDirectory(), entry.isFile(), entry.isSymbolicLink(), ignorePublicBundle)));
2966
3401
  return records.flat();
2967
3402
  }, hashNativeTree = async (root, label, ignorePublicBundle) => {
2968
3403
  const resolvedRoot = await realpath(root);
@@ -3091,11 +3526,11 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
3091
3526
  await mkdir2(paths.root, { recursive: true });
3092
3527
  await writeFile3(paths.backup, source, { flag: "wx" });
3093
3528
  await writeFile3(paths.manifestBackup, manifestSource, { flag: "wx" });
3094
- const resourceRoot = join10(dirname5(nativeManifestPath), "res");
3095
- const caPath = join10(resourceRoot, "raw", "absolutejs_dev_ca.pem");
3529
+ const resourceRoot = join11(dirname5(nativeManifestPath), "res");
3530
+ const caPath = join11(resourceRoot, "raw", "absolutejs_dev_ca.pem");
3096
3531
  const existingNetworkConfig = manifestSource.match(/android:networkSecurityConfig=["']@xml\/([a-z0-9_]+)["']/u)?.[1];
3097
3532
  const networkConfigName = existingNetworkConfig ?? "absolutejs_dev_network_security";
3098
- const networkConfigPath = join10(resourceRoot, "xml", `${networkConfigName}.xml`);
3533
+ const networkConfigPath = join11(resourceRoot, "xml", `${networkConfigName}.xml`);
3099
3534
  const backupProjectedFile = async ([path, backupPath]) => {
3100
3535
  if (!await pathExists2(path))
3101
3536
  return { path };
@@ -3188,12 +3623,12 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
3188
3623
  }
3189
3624
  return result.stdout.trim();
3190
3625
  }, mirroredCapacitorDependencies = async (project, capture) => {
3191
- const settingsPath = join10(project.nativeDirectory, "capacitor.settings.gradle");
3626
+ const settingsPath = join11(project.nativeDirectory, "capacitor.settings.gradle");
3192
3627
  const settings = await readFile4(settingsPath, "utf8");
3193
3628
  const dependencies = [];
3194
3629
  const rewrittenSettings = settings.replace(CAPACITOR_PROJECT_DIRECTORY_PATTERN, (_statement, projectName, sourcePath) => {
3195
3630
  const name = projectName.slice(1).replaceAll(/[^a-zA-Z0-9_.-]/gu, "_");
3196
- const source = resolve7(project.nativeDirectory, sourcePath);
3631
+ const source = resolve8(project.nativeDirectory, sourcePath);
3197
3632
  dependencies.push({
3198
3633
  name,
3199
3634
  windowsSource: windowsPathFromWsl(source, capture)
@@ -3234,7 +3669,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
3234
3669
  ].join("; ");
3235
3670
  return Buffer.from(source, "utf16le").toString("base64");
3236
3671
  }, gradleArtifactPath = (nativeDirectory, task, windows = false) => {
3237
- const pathJoin = windows ? win32.join : join10;
3672
+ const pathJoin = windows ? win32.join : join11;
3238
3673
  if (task === "assembleDebug") {
3239
3674
  return pathJoin(nativeDirectory, "app", "build", "outputs", "apk", "debug", "app-debug.apk");
3240
3675
  }
@@ -3247,7 +3682,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
3247
3682
  if (task !== "assembleRelease" || await pathExists2(primary)) {
3248
3683
  return primary;
3249
3684
  }
3250
- return join10(nativeDirectory, "app", "build", "outputs", "apk", "release", "app-release-unsigned.apk");
3685
+ return join11(nativeDirectory, "app", "build", "outputs", "apk", "release", "app-release-unsigned.apk");
3251
3686
  }, buildAbsoluteAndroidGradleArtifact = async (options) => {
3252
3687
  const { project, task } = options;
3253
3688
  const capture = options.capture ?? captureCommand2;
@@ -3257,7 +3692,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
3257
3692
  if (project.host === "wsl") {
3258
3693
  const windowsSource = windowsPathFromWsl(project.nativeDirectory, capture);
3259
3694
  const buildId = Bun.hash(project.projectRoot).toString(HASH_RADIX);
3260
- const managedBuildDirectory = resolve7(project.androidRoot, "..", "..", "Builds", `${project.config.appId}-${buildId}`);
3695
+ const managedBuildDirectory = resolve8(project.androidRoot, "..", "..", "Builds", `${project.config.appId}-${buildId}`);
3261
3696
  const windowsDirectory = windowsPathFromWsl(managedBuildDirectory, capture);
3262
3697
  const windowsAndroidRoot = windowsPathFromWsl(project.androidRoot, capture);
3263
3698
  const { dependencies, rewrittenSettings } = await mirroredCapacitorDependencies(project, capture);
@@ -3440,7 +3875,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
3440
3875
  "chromium:I"
3441
3876
  ], { env }, onLine);
3442
3877
  }, prepareAbsoluteAndroidDevProject = async (config, options) => {
3443
- const projectRoot = resolve7(options.projectRoot);
3878
+ const projectRoot = resolve8(options.projectRoot);
3444
3879
  const host2 = detectAbsoluteMobileHost();
3445
3880
  const androidRoot = process.env.ANDROID_HOME ?? process.env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(host2);
3446
3881
  const checks = await inspectAbsoluteMobileToolchain({ androidRoot, host: host2 });
@@ -3459,18 +3894,18 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
3459
3894
  if (!adb || options.target !== "device" && !emulator) {
3460
3895
  throw new Error("Android SDK tools disappeared after readiness checks.");
3461
3896
  }
3462
- const cap = join10(projectRoot, "node_modules", ".bin", host2 === "windows" ? "cap.cmd" : "cap");
3897
+ const cap = join11(projectRoot, "node_modules", ".bin", host2 === "windows" ? "cap.cmd" : "cap");
3463
3898
  if (!await pathExists2(cap)) {
3464
3899
  throw new Error("Capacitor CLI is not installed. Run absolute mobile init first.");
3465
3900
  }
3466
3901
  await writeAbsoluteCapacitorConfig(config, { projectRoot });
3467
3902
  await mkdir2(config.bundleDirectory, { recursive: true });
3468
- const placeholder = join10(config.bundleDirectory, "index.html");
3903
+ const placeholder = join11(config.bundleDirectory, "index.html");
3469
3904
  if (!await pathExists2(placeholder)) {
3470
3905
  await writeFile3(placeholder, `<!doctype html><title>AbsoluteJS mobile development</title>
3471
3906
  `);
3472
3907
  }
3473
- const nativeDirectory = join10(config.nativeProjectDirectory, "android");
3908
+ const nativeDirectory = join11(config.nativeProjectDirectory, "android");
3474
3909
  if (!await pathExists2(nativeDirectory)) {
3475
3910
  if (!options.createNativeProject) {
3476
3911
  throw new Error("Android native project has not been created.");
@@ -3531,8 +3966,8 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
3531
3966
  await requireSuccess([project.cap, "sync", "android"], "Capacitor Android synchronization", run, { cwd: project.projectRoot, env, signal: options.signal });
3532
3967
  throwIfAborted(options.signal);
3533
3968
  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");
3969
+ const nativeConfigPath = join11(project.nativeDirectory, "app", "src", "main", "assets", "capacitor.config.json");
3970
+ const nativeManifestPath = join11(project.nativeDirectory, "app", "src", "main", "AndroidManifest.xml");
3536
3971
  let connectedSerial;
3537
3972
  let nativeLogs = null;
3538
3973
  const closeNativeLogs = async () => {
@@ -3691,7 +4126,7 @@ var init_androidEmulatorController = __esm(() => {
3691
4126
  import { createHash as createHash3 } from "crypto";
3692
4127
  import { cp as cp2, mkdir as mkdir3, mkdtemp as mkdtemp2, readFile as readFile5, rm as rm3 } from "fs/promises";
3693
4128
  import { tmpdir } from "os";
3694
- import { basename as basename3, join as join11 } from "path";
4129
+ import { basename as basename3, join as join12 } from "path";
3695
4130
  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
4131
  const subprocess = Bun.spawn(command, {
3697
4132
  env: options.env,
@@ -3723,7 +4158,7 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
3723
4158
  exitCode: result.exitCode,
3724
4159
  stdout: result.stdout.toString()
3725
4160
  };
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) => {
4161
+ }, 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
4162
  const match = /^\/mnt\/([a-z])\/(.*)$/i.exec(path);
3728
4163
  if (!match)
3729
4164
  return path;
@@ -3797,10 +4232,10 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
3797
4232
  if (digest !== release.sha256) {
3798
4233
  throw new Error(`Android command-line-tools checksum mismatch: expected ${release.sha256}, received ${digest}.`);
3799
4234
  }
3800
- const temporary = await mkdtemp2(join11(tmpdir(), "absolutejs-android-sdk-"));
4235
+ const temporary = await mkdtemp2(join12(tmpdir(), "absolutejs-android-sdk-"));
3801
4236
  try {
3802
- const archive = join11(temporary, "command-line-tools.zip");
3803
- const extracted = join11(temporary, "extracted");
4237
+ const archive = join12(temporary, "command-line-tools.zip");
4238
+ const extracted = join12(temporary, "extracted");
3804
4239
  await Bun.write(archive, bytes);
3805
4240
  await mkdir3(extracted, { recursive: true });
3806
4241
  const extraction = plan.host === "windows" ? [
@@ -3817,12 +4252,12 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
3817
4252
  if (await input.run(extraction) !== 0) {
3818
4253
  throw new Error("Failed to extract Android command-line tools.");
3819
4254
  }
3820
- const destination = join11(plan.androidRoot, "cmdline-tools", "latest");
3821
- await mkdir3(join11(plan.androidRoot, "cmdline-tools"), {
4255
+ const destination = join12(plan.androidRoot, "cmdline-tools", "latest");
4256
+ await mkdir3(join12(plan.androidRoot, "cmdline-tools"), {
3822
4257
  recursive: true
3823
4258
  });
3824
4259
  await rm3(destination, { force: true, recursive: true });
3825
- await cp2(join11(extracted, "cmdline-tools"), destination, {
4260
+ await cp2(join12(extracted, "cmdline-tools"), destination, {
3826
4261
  recursive: true
3827
4262
  });
3828
4263
  } finally {
@@ -4007,7 +4442,7 @@ import {
4007
4442
  stat,
4008
4443
  writeFile as writeFile4
4009
4444
  } 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";
4445
+ import { dirname as dirname6, isAbsolute as isAbsolute2, join as join13, relative as relative5, resolve as resolve9, sep as sep2 } from "path";
4011
4446
  var developmentTeamArgument = (value) => {
4012
4447
  if (value === undefined)
4013
4448
  return;
@@ -4064,8 +4499,8 @@ var developmentTeamArgument = (value) => {
4064
4499
  }, ignoredFingerprintDirectories, fingerprintFiles = async (root, current = root, options = {}) => {
4065
4500
  const entries = await readdir3(current, { withFileTypes: true });
4066
4501
  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("\\", "/");
4502
+ const path = join13(current, entry.name);
4503
+ const projectRelative = relative5(root, path).replaceAll("\\", "/");
4069
4504
  const ignored = entry.isDirectory() && (ignoredFingerprintDirectories.has(entry.name) || projectRelative === "App/App/public" && options.includePublicBundle !== true);
4070
4505
  if (ignored)
4071
4506
  return [];
@@ -4079,16 +4514,16 @@ var developmentTeamArgument = (value) => {
4079
4514
  const files = await fingerprintFiles(nativeDirectory, nativeDirectory, options);
4080
4515
  const contents = await Promise.all(files.map((file) => readFile6(file)));
4081
4516
  files.forEach((file, index) => {
4082
- hasher.update(relative4(nativeDirectory, file).replaceAll("\\", "/"));
4517
+ hasher.update(relative5(nativeDirectory, file).replaceAll("\\", "/"));
4083
4518
  hasher.update("\x00");
4084
4519
  hasher.update(contents[index] ?? new Uint8Array);
4085
4520
  hasher.update("\x00");
4086
4521
  });
4087
4522
  return hasher.digest("hex");
4088
4523
  }, safeOutputDirectory = (projectRoot, requested) => {
4089
- const root = resolve8(projectRoot);
4090
- const output = resolve8(root, requested ?? ".absolutejs/mobile/releases/ios");
4091
- const projectRelative = relative4(root, output);
4524
+ const root = resolve9(projectRoot);
4525
+ const output = resolve9(root, requested ?? ".absolutejs/mobile/releases/ios");
4526
+ const projectRelative = relative5(root, output);
4092
4527
  if (projectRelative === ".." || projectRelative.startsWith(`..${sep2}`) || isAbsolute2(projectRelative)) {
4093
4528
  throw new TypeError("mobile build --outdir must remain inside the project.");
4094
4529
  }
@@ -4098,7 +4533,7 @@ var developmentTeamArgument = (value) => {
4098
4533
  return;
4099
4534
  const entries = await readdir3(root, { withFileTypes: true });
4100
4535
  const matches = await Promise.all(entries.map(async (entry) => {
4101
- const path = join12(root, entry.name);
4536
+ const path = join13(root, entry.name);
4102
4537
  if (entry.isDirectory() && entry.name.endsWith(extension))
4103
4538
  return path;
4104
4539
  if (entry.isFile() && entry.name.endsWith(extension))
@@ -4121,10 +4556,10 @@ var developmentTeamArgument = (value) => {
4121
4556
  throw new TypeError("iOS build number must be a positive integer.");
4122
4557
  return value;
4123
4558
  }, installRelease = async (artifactPath, metadata, outputRoot) => {
4124
- const releaseRoot = join12(outputRoot, metadata.releaseId);
4125
- const destination = join12(releaseRoot, "App.ipa");
4559
+ const releaseRoot = join13(outputRoot, metadata.releaseId);
4560
+ const destination = join13(releaseRoot, "App.ipa");
4126
4561
  if (await pathExists3(releaseRoot)) {
4127
- const value = JSON.parse(await readFile6(join12(releaseRoot, "release.json"), "utf8"));
4562
+ const value = JSON.parse(await readFile6(join13(releaseRoot, "release.json"), "utf8"));
4128
4563
  if (!isRecord2(value) || value.artifact !== "App.ipa" || Object.entries(metadata).some(([key, expected]) => Reflect.get(value, key) !== expected)) {
4129
4564
  throw new TypeError(`Immutable iOS release ${metadata.releaseId} does not match its content.`);
4130
4565
  }
@@ -4144,14 +4579,14 @@ var developmentTeamArgument = (value) => {
4144
4579
  };
4145
4580
  }
4146
4581
  await mkdir4(dirname6(releaseRoot), { recursive: true });
4147
- const staging = await mkdtemp3(join12(dirname6(releaseRoot), ".ios-stage-"));
4582
+ const staging = await mkdtemp3(join13(dirname6(releaseRoot), ".ios-stage-"));
4148
4583
  try {
4149
- await copyFile2(artifactPath, join12(staging, "App.ipa"));
4584
+ await copyFile2(artifactPath, join13(staging, "App.ipa"));
4150
4585
  const complete = {
4151
4586
  ...metadata,
4152
4587
  artifact: "App.ipa"
4153
4588
  };
4154
- await writeFile4(join12(staging, "release.json"), `${JSON.stringify(complete, null, "\t")}
4589
+ await writeFile4(join13(staging, "release.json"), `${JSON.stringify(complete, null, "\t")}
4155
4590
  `, { flag: "wx" });
4156
4591
  await rename4(staging, releaseRoot);
4157
4592
  return { artifactPath: destination, metadata: complete, releaseRoot };
@@ -4168,22 +4603,22 @@ var developmentTeamArgument = (value) => {
4168
4603
  const marketingVersion = options.config.iosVersion;
4169
4604
  if (!marketingVersion)
4170
4605
  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")));
4606
+ const manifest = requireManifest(JSON.parse(await readFile6(join13(options.config.bundleDirectory, "absolute-mobile-manifest.json"), "utf8")));
4172
4607
  if (manifest.appId !== options.config.appId)
4173
4608
  throw new TypeError("Embedded mobile manifest appId does not match mobile.appId.");
4174
- const nativeDirectory = join12(options.config.nativeProjectDirectory, "ios");
4609
+ const nativeDirectory = join13(options.config.nativeProjectDirectory, "ios");
4175
4610
  let buildNumber = requireBuildNumber(options.buildNumber);
4176
4611
  if (options.prepareBuildNumber) {
4177
4612
  const nativeFingerprint = await fingerprintAbsoluteIosNativeProject(nativeDirectory);
4178
4613
  const buildIdentity = createHash4("sha256").update(`${manifest.appBuild}\x00${nativeFingerprint}\x00${marketingVersion}`).digest("hex");
4179
4614
  buildNumber = requireBuildNumber(await options.prepareBuildNumber(buildIdentity));
4180
4615
  }
4181
- const stagingParent = resolve8(options.projectRoot, ".absolutejs/mobile");
4616
+ const stagingParent = resolve9(options.projectRoot, ".absolutejs/mobile");
4182
4617
  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");
4618
+ const staging = await mkdtemp3(join13(stagingParent, ".ios-build-"));
4619
+ const archivePath = join13(staging, "App.xcarchive");
4620
+ const exportPath = join13(staging, "export");
4621
+ const exportPlist = join13(staging, "ExportOptions.plist");
4187
4622
  await mkdir4(exportPath, { recursive: true });
4188
4623
  await writeFile4(exportPlist, exportOptions());
4189
4624
  const run = options.run ?? defaultRun2;
@@ -4197,7 +4632,7 @@ var developmentTeamArgument = (value) => {
4197
4632
  const archiveExit = await run([
4198
4633
  "xcodebuild",
4199
4634
  "-workspace",
4200
- join12(nativeDirectory, "App", "App.xcworkspace"),
4635
+ join13(nativeDirectory, "App", "App.xcworkspace"),
4201
4636
  "-scheme",
4202
4637
  "App",
4203
4638
  "-configuration",
@@ -4211,7 +4646,7 @@ var developmentTeamArgument = (value) => {
4211
4646
  ], { cwd: nativeDirectory });
4212
4647
  if (archiveExit !== 0)
4213
4648
  throw new TypeError("Xcode failed to archive the iOS app.");
4214
- const archivedApp = await findByExtension(join12(archivePath, "Products", "Applications"), ".app");
4649
+ const archivedApp = await findByExtension(join13(archivePath, "Products", "Applications"), ".app");
4215
4650
  const capture = options.capture ?? defaultCapture2;
4216
4651
  const signed = archivedApp ? capture([
4217
4652
  "codesign",
@@ -4285,7 +4720,7 @@ import {
4285
4720
  writeFile as writeFile5
4286
4721
  } from "fs/promises";
4287
4722
  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";
4723
+ import { dirname as dirname7, isAbsolute as isAbsolute3, join as join14, relative as relative6, resolve as resolve10, sep as sep3 } from "path";
4289
4724
  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
4725
  try {
4291
4726
  await access7(path);
@@ -4503,15 +4938,15 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
4503
4938
  const leftPro = left.name.includes("Pro") ? 1 : 0;
4504
4939
  return rightPro - leftPro;
4505
4940
  })[0], journalPaths2 = (projectRoot) => {
4506
- const root = join13(projectRoot, ".absolutejs", "mobile", "ios-dev-session");
4941
+ const root = join14(projectRoot, ".absolutejs", "mobile", "ios-dev-session");
4507
4942
  return {
4508
- configBackup: join13(root, "capacitor-config.backup"),
4509
- infoBackup: join13(root, "Info.plist.backup"),
4510
- journal: join13(root, "journal.json"),
4943
+ configBackup: join14(root, "capacitor-config.backup"),
4944
+ infoBackup: join14(root, "Info.plist.backup"),
4945
+ journal: join14(root, "journal.json"),
4511
4946
  root
4512
4947
  };
4513
- }, nativeCachePath2 = (projectRoot) => join13(projectRoot, ".absolutejs", "mobile", "ios-native-cache.json"), isInside2 = (root, path) => {
4514
- const value = relative5(resolve9(root), resolve9(path));
4948
+ }, nativeCachePath2 = (projectRoot) => join14(projectRoot, ".absolutejs", "mobile", "ios-native-cache.json"), isInside2 = (root, path) => {
4949
+ const value = relative6(resolve10(root), resolve10(path));
4515
4950
  return value === "" || !value.startsWith(`..${sep3}`) && value !== ".." && !isAbsolute3(value);
4516
4951
  }, parseJournal2 = (value) => {
4517
4952
  if (!isRecord3(value) || value.format !== DEV_JOURNAL_FORMAT2)
@@ -4567,8 +5002,8 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
4567
5002
  }, writeDevProjection = async (project, port, https, serverHost = "localhost") => {
4568
5003
  const paths = journalPaths2(project.projectRoot);
4569
5004
  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");
5005
+ const nativeConfigPath = join14(project.nativeDirectory, "App", "App", "capacitor.config.json");
5006
+ const infoPath = join14(project.nativeDirectory, "App", "App", "Info.plist");
4572
5007
  const [configSource, infoSource] = await Promise.all([
4573
5008
  readFile7(nativeConfigPath, "utf8"),
4574
5009
  readFile7(infoPath, "utf8")
@@ -4729,12 +5164,12 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
4729
5164
  ]);
4730
5165
  return result.exitCode === 0 && result.stdout.includes(project.config.appId);
4731
5166
  }, 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));
5167
+ const derivedDataPath = join14(project.projectRoot, ".absolutejs", "mobile", "ios-derived-data", createHash5("sha256").update(project.config.appId).digest("hex").slice(0, 16));
4733
5168
  await mkdir5(derivedDataPath, { recursive: true });
4734
5169
  await requireSuccess2([
4735
5170
  project.xcodebuild,
4736
5171
  "-workspace",
4737
- join13(project.nativeDirectory, "App", "App.xcworkspace"),
5172
+ join14(project.nativeDirectory, "App", "App.xcworkspace"),
4738
5173
  "-scheme",
4739
5174
  "App",
4740
5175
  "-configuration",
@@ -4745,17 +5180,17 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
4745
5180
  derivedDataPath,
4746
5181
  "build"
4747
5182
  ], "iOS simulator build", run, { cwd: project.nativeDirectory, signal });
4748
- const appPath = join13(derivedDataPath, "Build", "Products", "Debug-iphonesimulator", "App.app");
5183
+ const appPath = join14(derivedDataPath, "Build", "Products", "Debug-iphonesimulator", "App.app");
4749
5184
  if (!await pathExists4(appPath))
4750
5185
  throw new Error(`Xcode did not produce the simulator app at ${appPath}.`);
4751
5186
  return appPath;
4752
5187
  }, 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));
5188
+ const derivedDataPath = join14(project.projectRoot, ".absolutejs", "mobile", "ios-derived-data", createHash5("sha256").update(project.config.appId).digest("hex").slice(0, 16));
4754
5189
  await mkdir5(derivedDataPath, { recursive: true });
4755
5190
  await requireSuccess2([
4756
5191
  project.xcodebuild,
4757
5192
  "-workspace",
4758
- join13(project.nativeDirectory, "App", "App.xcworkspace"),
5193
+ join14(project.nativeDirectory, "App", "App.xcworkspace"),
4759
5194
  "-scheme",
4760
5195
  "App",
4761
5196
  "-configuration",
@@ -4767,7 +5202,7 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
4767
5202
  "-allowProvisioningUpdates",
4768
5203
  "build"
4769
5204
  ], "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");
5205
+ const appPath = join14(derivedDataPath, "Build", "Products", "Debug-iphoneos", "App.app");
4771
5206
  if (!await pathExists4(appPath))
4772
5207
  throw new Error(`Xcode did not produce the physical-device app at ${appPath}.`);
4773
5208
  return appPath;
@@ -4878,7 +5313,7 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
4878
5313
  if (detectAbsoluteMobileHost() !== "macos")
4879
5314
  throw new Error("iOS development requires macOS and Xcode.");
4880
5315
  const target = options.target ?? "simulator";
4881
- const projectRoot = resolve9(options.projectRoot);
5316
+ const projectRoot = resolve10(options.projectRoot);
4882
5317
  const checks = await inspectAbsoluteMobileToolchain({ host: "macos" });
4883
5318
  const failed = checks.filter((check) => check.platform === "ios" && !(target === "device" && check.id === "ios.runtime") && (check.status === "fail" || check.status === "warn"));
4884
5319
  if (failed.length > 0)
@@ -4887,16 +5322,16 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
4887
5322
  const xcodebuild = checks.find((check) => check.id === "ios.xcodebuild")?.path;
4888
5323
  if (!xcrun || !xcodebuild)
4889
5324
  throw new Error("Xcode tools disappeared after readiness checks.");
4890
- const cap = join13(projectRoot, "node_modules", ".bin", "cap");
5325
+ const cap = join14(projectRoot, "node_modules", ".bin", "cap");
4891
5326
  if (!await pathExists4(cap))
4892
5327
  throw new Error("Capacitor CLI is not installed. Run absolute mobile init first.");
4893
5328
  await writeAbsoluteCapacitorConfig(config, { projectRoot });
4894
5329
  await mkdir5(config.bundleDirectory, { recursive: true });
4895
- const placeholder = join13(config.bundleDirectory, "index.html");
5330
+ const placeholder = join14(config.bundleDirectory, "index.html");
4896
5331
  if (!await pathExists4(placeholder))
4897
5332
  await writeFile5(placeholder, `<!doctype html><title>AbsoluteJS mobile development</title>
4898
5333
  `);
4899
- const nativeDirectory = join13(config.nativeProjectDirectory, "ios");
5334
+ const nativeDirectory = join14(config.nativeProjectDirectory, "ios");
4900
5335
  if (!await pathExists4(nativeDirectory)) {
4901
5336
  if (!options.createNativeProject)
4902
5337
  throw new Error("iOS native project has not been created.");
@@ -5121,7 +5556,7 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
5121
5556
  screenshot: async (destination) => {
5122
5557
  if (deviceIdentifier)
5123
5558
  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);
5559
+ const resolved = resolve10(project.projectRoot, destination);
5125
5560
  if (!isInside2(project.projectRoot, resolved))
5126
5561
  throw new Error("iOS screenshot destination must remain inside the project.");
5127
5562
  await mkdir5(dirname7(resolved), { recursive: true });
@@ -5185,13 +5620,13 @@ import { isIP as isIP3 } from "net";
5185
5620
  import {
5186
5621
  dirname as dirname8,
5187
5622
  isAbsolute as isAbsolute4,
5188
- join as join14,
5623
+ join as join15,
5189
5624
  posix,
5190
- relative as relative6,
5625
+ relative as relative7,
5191
5626
  resolve as resolvePath,
5192
5627
  sep as sep4
5193
5628
  } 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 = () => ({
5629
+ 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
5630
  format: PROFILE_FORMAT,
5196
5631
  profiles: {}
5197
5632
  }), loadStore = async (path = defaultProfilePath()) => {
@@ -5367,9 +5802,9 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
5367
5802
  throw new TypeError("Remote Expo execution requires mobile.engine: expo.");
5368
5803
  return createAbsoluteRemoteIosDevProject(config, projectRoot, profile);
5369
5804
  }, createAbsoluteRemoteIosDevProject = (config, projectRoot, profile) => ({
5370
- cap: join14(resolvePath(projectRoot), "node_modules", ".bin", "cap"),
5805
+ cap: join15(resolvePath(projectRoot), "node_modules", ".bin", "cap"),
5371
5806
  config,
5372
- nativeDirectory: join14(config.nativeProjectDirectory, "ios"),
5807
+ nativeDirectory: join15(config.nativeProjectDirectory, "ios"),
5373
5808
  profile,
5374
5809
  projectRoot: resolvePath(projectRoot),
5375
5810
  remote: true,
@@ -5416,8 +5851,8 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
5416
5851
  return { ...artifact, remotePath, uploaded: true };
5417
5852
  }, materializeAbsoluteRemoteMacAgent = async (projectRoot) => {
5418
5853
  const shippedCandidates = [
5419
- join14(import.meta.dir, "remoteMacAgentEntry.js"),
5420
- join14(import.meta.dir, "..", "mobile", "remoteMacAgentEntry.js")
5854
+ join15(import.meta.dir, "remoteMacAgentEntry.js"),
5855
+ join15(import.meta.dir, "..", "mobile", "remoteMacAgentEntry.js")
5421
5856
  ];
5422
5857
  let path;
5423
5858
  for (const candidate of shippedCandidates) {
@@ -5428,13 +5863,13 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
5428
5863
  }
5429
5864
  if (!path) {
5430
5865
  const sourceCandidates = [
5431
- join14(import.meta.dir, "remoteMacAgentEntry.ts"),
5432
- join14(import.meta.dir, "..", "..", "src", "mobile", "remoteMacAgentEntry.ts")
5866
+ join15(import.meta.dir, "remoteMacAgentEntry.ts"),
5867
+ join15(import.meta.dir, "..", "..", "src", "mobile", "remoteMacAgentEntry.ts")
5433
5868
  ];
5434
5869
  const source = await sourceCandidates.reduce(async (found, candidate) => await found ?? (await Bun.file(candidate).exists() ? candidate : undefined), Promise.resolve(undefined));
5435
5870
  if (!source)
5436
5871
  throw new Error("The AbsoluteJS installation does not contain its remote Mac agent artifact.");
5437
- const outdir = join14(resolvePath(projectRoot), ".absolutejs", "mobile", "remote-agent");
5872
+ const outdir = join15(resolvePath(projectRoot), ".absolutejs", "mobile", "remote-agent");
5438
5873
  await mkdir6(outdir, { recursive: true });
5439
5874
  const result = await Bun.build({
5440
5875
  entrypoints: [source],
@@ -5444,12 +5879,12 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
5444
5879
  });
5445
5880
  if (!result.success)
5446
5881
  throw new AggregateError(result.logs, "Failed to build the AbsoluteJS remote Mac agent.");
5447
- path = join14(outdir, "remoteMacAgentEntry.js");
5882
+ path = join15(outdir, "remoteMacAgentEntry.js");
5448
5883
  }
5449
5884
  const bytes = await Bun.file(path).arrayBuffer();
5450
5885
  const sha256 = createHash6("sha256").update(new Uint8Array(bytes)).digest("hex");
5451
5886
  return { bytes: bytes.byteLength, path, sha256 };
5452
- }, portableRelativePath = (root, path) => relative6(root, path).split(sep4).join(posix.sep), portableMobileConfig = (project) => ({
5887
+ }, portableRelativePath = (root, path) => relative7(root, path).split(sep4).join(posix.sep), portableMobileConfig = (project) => ({
5453
5888
  appId: project.config.appId,
5454
5889
  appName: project.config.appName,
5455
5890
  bundleDirectory: portableRelativePath(project.projectRoot, project.config.bundleDirectory),
@@ -5665,8 +6100,8 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
5665
6100
  const pending = new Map;
5666
6101
  let resolveReady;
5667
6102
  let rejectReady;
5668
- const readyPromise = new Promise((resolve10, reject) => {
5669
- resolveReady = resolve10;
6103
+ const readyPromise = new Promise((resolve11, reject) => {
6104
+ resolveReady = resolve11;
5670
6105
  rejectReady = reject;
5671
6106
  });
5672
6107
  const handleEvent = (event) => {
@@ -5767,7 +6202,7 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
5767
6202
  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
6203
  const request = (commandName) => {
5769
6204
  const id = randomUUID4();
5770
- const response = new Promise((resolve10, reject) => pending.set(id, { reject, resolve: resolve10 }));
6205
+ const response = new Promise((resolve11, reject) => pending.set(id, { reject, resolve: resolve11 }));
5771
6206
  process2.stdin.write(`${JSON.stringify({ command: commandName, id, v: ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION })}
5772
6207
  `);
5773
6208
  const flush = async () => {
@@ -5787,7 +6222,7 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
5787
6222
  if (closed)
5788
6223
  return;
5789
6224
  closed = true;
5790
- const timeout = () => new Promise((resolve10) => setTimeout(() => resolve10("timeout"), REMOTE_SESSION_CLOSE_TIMEOUT_MS));
6225
+ const timeout = () => new Promise((resolve11) => setTimeout(() => resolve11("timeout"), REMOTE_SESSION_CLOSE_TIMEOUT_MS));
5791
6226
  await Promise.race([
5792
6227
  request("close").catch(() => {
5793
6228
  return;
@@ -5835,7 +6270,7 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
5835
6270
  screenshot: async (destination) => {
5836
6271
  const result = await request("screenshot");
5837
6272
  const target = resolvePath(options.project.projectRoot, destination);
5838
- const targetRelative = relative6(options.project.projectRoot, target);
6273
+ const targetRelative = relative7(options.project.projectRoot, target);
5839
6274
  if (targetRelative.startsWith("..") || isAbsolute4(targetRelative))
5840
6275
  throw new Error("iOS screenshot must remain inside the project.");
5841
6276
  await mkdir6(dirname8(target), { recursive: true });
@@ -5875,16 +6310,16 @@ __export(exports_devCert, {
5875
6310
  });
5876
6311
  import {
5877
6312
  copyFileSync,
5878
- existsSync as existsSync4,
6313
+ existsSync as existsSync5,
5879
6314
  mkdirSync as mkdirSync4,
5880
- readFileSync as readFileSync8,
6315
+ readFileSync as readFileSync9,
5881
6316
  rmSync
5882
6317
  } from "fs";
5883
6318
  import { X509Certificate as X509Certificate2 } from "crypto";
5884
6319
  import { isIP as isIP4 } from "net";
5885
6320
  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 = []) => {
6321
+ import { join as join16 } from "path";
6322
+ 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
6323
  const normalized = new Set(DEFAULT_CERTIFICATE_HOSTS);
5889
6324
  for (const host2 of hosts) {
5890
6325
  const value = host2.trim().toLowerCase();
@@ -5898,7 +6333,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
5898
6333
  return [...normalized];
5899
6334
  }, certificateIsUsable = (hosts) => {
5900
6335
  try {
5901
- const certPem = readFileSync8(CERT_PATH, "utf-8");
6336
+ const certPem = readFileSync9(CERT_PATH, "utf-8");
5902
6337
  const certificate = new X509Certificate2(certPem);
5903
6338
  if (new Date(certificate.validTo).getTime() <= Date.now())
5904
6339
  return false;
@@ -5983,8 +6418,8 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
5983
6418
  return null;
5984
6419
  try {
5985
6420
  return {
5986
- cert: readFileSync8(paths.cert, "utf-8"),
5987
- key: readFileSync8(paths.key, "utf-8")
6421
+ cert: readFileSync9(paths.cert, "utf-8"),
6422
+ key: readFileSync9(paths.key, "utf-8")
5988
6423
  };
5989
6424
  } catch {
5990
6425
  return null;
@@ -6080,7 +6515,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
6080
6515
  if (platform2() !== "linux")
6081
6516
  return false;
6082
6517
  try {
6083
- return /microsoft|wsl/i.test(readFileSync8("/proc/version", "utf-8"));
6518
+ return /microsoft|wsl/i.test(readFileSync9("/proc/version", "utf-8"));
6084
6519
  } catch {
6085
6520
  return false;
6086
6521
  }
@@ -6096,8 +6531,8 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
6096
6531
  }
6097
6532
  }, mkcertCaRoot = () => runCapture(["mkcert", "-CAROOT"]), getDevCertificateAuthorityPath = () => {
6098
6533
  const caRoot = hasMkcert() ? mkcertCaRoot() : null;
6099
- const rootCertificate = caRoot ? join15(caRoot, "rootCA.pem") : null;
6100
- if (rootCertificate && existsSync4(rootCertificate))
6534
+ const rootCertificate = caRoot ? join16(caRoot, "rootCA.pem") : null;
6535
+ if (rootCertificate && existsSync5(rootCertificate))
6101
6536
  return rootCertificate;
6102
6537
  if (certFilesExist())
6103
6538
  return CERT_PATH;
@@ -6111,13 +6546,13 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
6111
6546
  const caRoot = mkcertCaRoot();
6112
6547
  if (!caRoot)
6113
6548
  return false;
6114
- const rootCa = join15(caRoot, "rootCA.pem");
6115
- if (!existsSync4(rootCa))
6549
+ const rootCa = join16(caRoot, "rootCA.pem");
6550
+ if (!existsSync5(rootCa))
6116
6551
  return false;
6117
6552
  const winTemp = windowsTempDir();
6118
6553
  if (!winTemp)
6119
6554
  return false;
6120
- const staged = join15(winTemp, "absolutejs-mkcert-rootCA.crt");
6555
+ const staged = join16(winTemp, "absolutejs-mkcert-rootCA.crt");
6121
6556
  try {
6122
6557
  copyFileSync(rootCa, staged);
6123
6558
  } catch {
@@ -6153,7 +6588,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
6153
6588
  devLog("Trusted the local CA in the Windows store \u2014 Chrome/Edge on Windows now accept dev HTTPS");
6154
6589
  } else {
6155
6590
  const caRoot = mkcertCaRoot();
6156
- const hint = caRoot ? toWindowsPath(join15(caRoot, "rootCA.pem")) : null;
6591
+ const hint = caRoot ? toWindowsPath(join16(caRoot, "rootCA.pem")) : null;
6157
6592
  devWarn("Could not auto-trust the local CA on Windows; Windows browsers may warn.");
6158
6593
  if (hint) {
6159
6594
  console.log(` Run in PowerShell: Import-Certificate -FilePath "${hint}" -CertStoreLocation Cert:\\CurrentUser\\Root`);
@@ -6169,9 +6604,9 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
6169
6604
  return true;
6170
6605
  };
6171
6606
  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");
6607
+ CERT_DIR = join16(process.cwd(), ".absolutejs");
6608
+ CERT_PATH = join16(CERT_DIR, "cert.pem");
6609
+ KEY_PATH = join16(CERT_DIR, "key.pem");
6175
6610
  DEFAULT_CERTIFICATE_HOSTS = ["localhost", "127.0.0.1", "::1"];
6176
6611
  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
6612
  });
@@ -6187,9 +6622,9 @@ __export(exports_eslintChunked, {
6187
6622
  ruleSummary: () => ruleSummary,
6188
6623
  upstreamRef: () => upstreamRef
6189
6624
  });
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(`
6625
+ import { existsSync as existsSync7 } from "fs";
6626
+ import { relative as relative8, resolve as resolve11 } from "path";
6627
+ 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
6628
  `).map((line) => line.trimEnd()).filter(Boolean), applyChangedBase = (parsed, base) => {
6194
6629
  parsed.changedOnly = true;
6195
6630
  parsed.changedBase = base;
@@ -6200,7 +6635,7 @@ var DEFAULT_CHUNK_SIZE = 20, DEFAULT_SHARDS = 4, DEFAULT_CONCURRENCY = 2, DEFAUL
6200
6635
  }, matchesAnyGlob = (file, globs) => globs.some((pattern) => new Bun.Glob(pattern).match(file)), resolveLintSet = (parsed, cwd) => {
6201
6636
  const visible = gitVisibleFiles(cwd);
6202
6637
  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();
6638
+ return matched.filter((file) => existsSync7(resolve11(cwd, file))).sort();
6204
6639
  }, resolveLintTargets = (args, cwd = process.cwd()) => resolveLintSet(parseChunkedArgs(args), cwd), buildShardChunks = (files, shards, chunkSize) => {
6205
6640
  const shardFiles = Array.from({ length: shards }, () => []);
6206
6641
  for (const file of files)
@@ -6222,7 +6657,7 @@ var DEFAULT_CHUNK_SIZE = 20, DEFAULT_SHARDS = 4, DEFAULT_CONCURRENCY = 2, DEFAUL
6222
6657
  "content"
6223
6658
  ];
6224
6659
  const proc = Bun.spawn([
6225
- resolve10(cwd, "node_modules/.bin/eslint"),
6660
+ resolve11(cwd, "node_modules/.bin/eslint"),
6226
6661
  "--color",
6227
6662
  ...hasMaxWarnings ? [] : ["--max-warnings", "0"],
6228
6663
  ...cacheArgs,
@@ -6269,7 +6704,7 @@ var DEFAULT_CHUNK_SIZE = 20, DEFAULT_SHARDS = 4, DEFAULT_CONCURRENCY = 2, DEFAUL
6269
6704
  const fingerprint = createEslintCacheFingerprint(cwd);
6270
6705
  for (let shard = 0;shard < parsed.shards; shard++)
6271
6706
  prepareEslintCache({
6272
- cacheLocation: relative7(cwd, resolve10(cwd, `${cachePrefix}${shard}`)),
6707
+ cacheLocation: relative8(cwd, resolve11(cwd, `${cachePrefix}${shard}`)),
6273
6708
  cwd,
6274
6709
  fingerprint
6275
6710
  });
@@ -6310,7 +6745,7 @@ var DEFAULT_CHUNK_SIZE = 20, DEFAULT_SHARDS = 4, DEFAULT_CONCURRENCY = 2, DEFAUL
6310
6745
  const header = `eslint report \u2014 ${files.length} files, ${totalChunks} chunks, ${elapsed}s
6311
6746
  ${"=".repeat(SUMMARY_RULE_WIDTH)}
6312
6747
  `;
6313
- await Bun.write(resolve10(cwd, parsed.outFile), header + report + summary);
6748
+ await Bun.write(resolve11(cwd, parsed.outFile), header + report + summary);
6314
6749
  console.log(summary);
6315
6750
  console.log(`Full report written to ${parsed.outFile}`);
6316
6751
  if (failedChunks > 0) {
@@ -6397,14 +6832,14 @@ var init_eslintChunked = __esm(() => {
6397
6832
  // src/cli/scripts/eslint.ts
6398
6833
  import { createHash as createHash7 } from "crypto";
6399
6834
  import {
6400
- existsSync as existsSync7,
6835
+ existsSync as existsSync8,
6401
6836
  mkdirSync as mkdirSync5,
6402
- readFileSync as readFileSync10,
6837
+ readFileSync as readFileSync11,
6403
6838
  renameSync,
6404
6839
  rmSync as rmSync3,
6405
6840
  writeFileSync as writeFileSync5
6406
6841
  } from "fs";
6407
- import { dirname as dirname9, relative as relative8, resolve as resolve11 } from "path";
6842
+ import { dirname as dirname9, relative as relative9, resolve as resolve12 } from "path";
6408
6843
  var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION = "1", CACHE_FINGERPRINT_SUFFIX = ".fingerprint", flagValue = (args, flag) => {
6409
6844
  const assignment = args.find((arg) => arg.startsWith(`${flag}=`));
6410
6845
  if (assignment)
@@ -6428,20 +6863,20 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
6428
6863
  return false;
6429
6864
  }, findEslintConfigPath = (cwd = process.cwd()) => {
6430
6865
  for (const name of CONFIG_CANDIDATES) {
6431
- const candidate = resolve11(cwd, name);
6432
- if (existsSync7(candidate))
6866
+ const candidate = resolve12(cwd, name);
6867
+ if (existsSync8(candidate))
6433
6868
  return candidate;
6434
6869
  }
6435
6870
  return null;
6436
6871
  }, fingerprintLocation = (cacheLocation, cwd) => {
6437
- const absolute = resolve11(cwd, cacheLocation);
6438
- return /[\\/]$/.test(cacheLocation) ? resolve11(absolute, CACHE_FINGERPRINT_SUFFIX.slice(1)) : `${absolute}${CACHE_FINGERPRINT_SUFFIX}`;
6872
+ const absolute = resolve12(cwd, cacheLocation);
6873
+ return /[\\/]$/.test(cacheLocation) ? resolve12(absolute, CACHE_FINGERPRINT_SUFFIX.slice(1)) : `${absolute}${CACHE_FINGERPRINT_SUFFIX}`;
6439
6874
  }, addFileToFingerprint = (hash, path, label) => {
6440
- if (!existsSync7(path))
6875
+ if (!existsSync8(path))
6441
6876
  return;
6442
6877
  hash.update(label);
6443
6878
  hash.update("\x00");
6444
- hash.update(readFileSync10(path));
6879
+ hash.update(readFileSync11(path));
6445
6880
  hash.update("\x00");
6446
6881
  }, packageNameFor = (specifier) => {
6447
6882
  if (specifier.startsWith("@"))
@@ -6451,7 +6886,7 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
6451
6886
  }, configPackageNames = (configPath2) => {
6452
6887
  if (!configPath2)
6453
6888
  return [];
6454
- const source = readFileSync10(configPath2, "utf-8");
6889
+ const source = readFileSync11(configPath2, "utf-8");
6455
6890
  const names = new Set;
6456
6891
  for (const match of source.matchAll(/(?:from\s+|import\s*(?:\(\s*)?|require\s*\(\s*)(['"])([^'".][^'"]*)\1/g)) {
6457
6892
  const [, , specifier] = match;
@@ -6470,11 +6905,11 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
6470
6905
  return Object.keys(value);
6471
6906
  });
6472
6907
  }, lintDependencyNames = (cwd, configPath2) => {
6473
- const manifestPath = resolve11(cwd, "package.json");
6474
- if (!existsSync7(manifestPath))
6908
+ const manifestPath = resolve12(cwd, "package.json");
6909
+ if (!existsSync8(manifestPath))
6475
6910
  return configPackageNames(configPath2);
6476
6911
  try {
6477
- const manifest = JSON.parse(readFileSync10(manifestPath, "utf-8"));
6912
+ const manifest = JSON.parse(readFileSync11(manifestPath, "utf-8"));
6478
6913
  const lintPackages = manifestDependencyNames(manifest).filter((name) => /eslint|typescript/.test(name));
6479
6914
  return [
6480
6915
  ...new Set([...lintPackages, ...configPackageNames(configPath2)])
@@ -6485,8 +6920,8 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
6485
6920
  }, findInstalledManifest = (cwd, dependency) => {
6486
6921
  let directory = cwd;
6487
6922
  while (true) {
6488
- const candidate = resolve11(directory, "node_modules", dependency, "package.json");
6489
- if (existsSync7(candidate))
6923
+ const candidate = resolve12(directory, "node_modules", dependency, "package.json");
6924
+ if (existsSync8(candidate))
6490
6925
  return candidate;
6491
6926
  const parent = dirname9(directory);
6492
6927
  if (parent === directory)
@@ -6508,7 +6943,7 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
6508
6943
  hash.update(`absolute-eslint-config:${CACHE_CONTRACT_VERSION}\x00`);
6509
6944
  const configPath2 = findEslintConfigPath(cwd);
6510
6945
  if (configPath2)
6511
- addFileToFingerprint(hash, configPath2, relative8(cwd, configPath2));
6946
+ addFileToFingerprint(hash, configPath2, relative9(cwd, configPath2));
6512
6947
  return hash.digest("hex");
6513
6948
  }, writeFingerprint = (path, fingerprint) => {
6514
6949
  mkdirSync5(dirname9(path), { recursive: true });
@@ -6518,10 +6953,10 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
6518
6953
  renameSync(temporary, path);
6519
6954
  }, prepareEslintCache = (options) => {
6520
6955
  const cwd = options.cwd ?? process.cwd();
6521
- const cachePath = resolve11(cwd, options.cacheLocation);
6956
+ const cachePath = resolve12(cwd, options.cacheLocation);
6522
6957
  const metadataPath = fingerprintLocation(options.cacheLocation, cwd);
6523
6958
  const fingerprint = options.fingerprint ?? createEslintCacheFingerprint(cwd);
6524
- const prior = existsSync7(metadataPath) ? readFileSync10(metadataPath, "utf-8").trim() : null;
6959
+ const prior = existsSync8(metadataPath) ? readFileSync11(metadataPath, "utf-8").trim() : null;
6525
6960
  if (prior === fingerprint)
6526
6961
  return false;
6527
6962
  rmSync3(cachePath, { force: true, recursive: true });
@@ -6609,7 +7044,7 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
6609
7044
  return;
6610
7045
  let source;
6611
7046
  try {
6612
- source = readFileSync10(configPath2, "utf-8");
7047
+ source = readFileSync11(configPath2, "utf-8");
6613
7048
  } catch {
6614
7049
  return;
6615
7050
  }
@@ -6648,7 +7083,7 @@ Detected at: ${configPath2}${reset}`);
6648
7083
  return `${minutes}m ${seconds}s`;
6649
7084
  }, handleClearCache = (cacheLocation, cwd = process.cwd()) => {
6650
7085
  try {
6651
- const cachePath = resolve11(cwd, cacheLocation);
7086
+ const cachePath = resolve12(cwd, cacheLocation);
6652
7087
  const metadataPath = fingerprintLocation(cacheLocation, cwd);
6653
7088
  rmSync3(cachePath, { force: true, recursive: true });
6654
7089
  rmSync3(metadataPath, { force: true, recursive: true });
@@ -6677,7 +7112,7 @@ Detected at: ${configPath2}${reset}`);
6677
7112
  return;
6678
7113
  }
6679
7114
  if (args.includes("--chunked")) {
6680
- if (!existsSync7(resolve11("node_modules", ".bin", "eslint"))) {
7115
+ if (!existsSync8(resolve12("node_modules", ".bin", "eslint"))) {
6681
7116
  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
7117
  process.exit(1);
6683
7118
  }
@@ -6685,7 +7120,7 @@ Detected at: ${configPath2}${reset}`);
6685
7120
  await eslintChunked2(args);
6686
7121
  return;
6687
7122
  }
6688
- if (!existsSync7(resolve11("node_modules", ".bin", "eslint"))) {
7123
+ if (!existsSync8(resolve12("node_modules", ".bin", "eslint"))) {
6689
7124
  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
7125
  process.exit(1);
6691
7126
  }
@@ -6876,8 +7311,8 @@ var isRecord4 = (value) => typeof value === "object" && value !== null, getIslan
6876
7311
  var init_islands = () => {};
6877
7312
 
6878
7313
  // 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";
7314
+ import { dirname as dirname10, extname as extname2, join as join19, relative as relative10, resolve as resolve14 } from "path";
7315
+ import ts2 from "typescript";
6881
7316
  var frameworks, isRecord5 = (value) => typeof value === "object" && value !== null, resolveRegistryExport = (mod) => {
6882
7317
  if (isRecord5(mod.islandRegistry))
6883
7318
  return mod.islandRegistry;
@@ -6888,9 +7323,9 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
6888
7323
  if (sourcePath.startsWith("file://")) {
6889
7324
  return new URL(sourcePath).pathname;
6890
7325
  }
6891
- return resolve13(dirname10(registryPath), sourcePath);
7326
+ return resolve14(dirname10(registryPath), sourcePath);
6892
7327
  }, getObjectPropertyName = (name) => {
6893
- if (ts.isIdentifier(name) || ts.isStringLiteral(name)) {
7328
+ if (ts2.isIdentifier(name) || ts2.isStringLiteral(name)) {
6894
7329
  return name.text;
6895
7330
  }
6896
7331
  return null;
@@ -6903,7 +7338,7 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
6903
7338
  });
6904
7339
  }, collectNamedImports = (imports, importClause, source) => {
6905
7340
  const bindings = importClause.namedBindings;
6906
- if (!bindings || !ts.isNamedImports(bindings))
7341
+ if (!bindings || !ts2.isNamedImports(bindings))
6907
7342
  return;
6908
7343
  for (const element of bindings.elements) {
6909
7344
  imports.set(element.name.text, {
@@ -6917,7 +7352,7 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
6917
7352
  const bindings = importClause.namedBindings;
6918
7353
  if (!bindings)
6919
7354
  return;
6920
- if (ts.isNamespaceImport(bindings)) {
7355
+ if (ts2.isNamespaceImport(bindings)) {
6921
7356
  registryNamespaceNames.add(bindings.name.text);
6922
7357
  return;
6923
7358
  }
@@ -6935,13 +7370,13 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
6935
7370
  const frameworkRegistry = registry2[framework] ?? {};
6936
7371
  registry2[framework] = frameworkRegistry;
6937
7372
  for (const property of frameworkNode.properties) {
6938
- if (!ts.isPropertyAssignment(property) && !ts.isShorthandPropertyAssignment(property))
7373
+ if (!ts2.isPropertyAssignment(property) && !ts2.isShorthandPropertyAssignment(property))
6939
7374
  continue;
6940
7375
  const componentName = getObjectPropertyName(property.name);
6941
7376
  if (!componentName)
6942
7377
  continue;
6943
- const initializer = ts.isPropertyAssignment(property) ? property.initializer : property.name;
6944
- if (!ts.isIdentifier(initializer))
7378
+ const initializer = ts2.isPropertyAssignment(property) ? property.initializer : property.name;
7379
+ if (!ts2.isIdentifier(initializer))
6945
7380
  continue;
6946
7381
  const reference = imports.get(initializer.text);
6947
7382
  if (!reference)
@@ -6955,7 +7390,7 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
6955
7390
  }
6956
7391
  }, processDefineIslandRegistry = (node, imports, definitions, registry2) => {
6957
7392
  const [firstArg] = node.arguments;
6958
- if (!firstArg || !ts.isObjectLiteralExpression(firstArg))
7393
+ if (!firstArg || !ts2.isObjectLiteralExpression(firstArg))
6959
7394
  return;
6960
7395
  const validFrameworks = [
6961
7396
  "react",
@@ -6964,7 +7399,7 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
6964
7399
  "angular"
6965
7400
  ];
6966
7401
  for (const property of firstArg.properties) {
6967
- if (!ts.isPropertyAssignment(property))
7402
+ if (!ts2.isPropertyAssignment(property))
6968
7403
  continue;
6969
7404
  const frameworkName = getObjectPropertyName(property.name);
6970
7405
  if (!frameworkName)
@@ -6972,28 +7407,28 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
6972
7407
  const framework = validFrameworks.find((f) => f === frameworkName);
6973
7408
  if (!framework)
6974
7409
  continue;
6975
- if (!ts.isObjectLiteralExpression(property.initializer))
7410
+ if (!ts2.isObjectLiteralExpression(property.initializer))
6976
7411
  continue;
6977
7412
  addRegistryEntries(property.initializer, framework, imports, definitions, registry2);
6978
7413
  }
6979
7414
  }, walkRegistryNode = (node, imports, registryFactoryNames, registryNamespaceNames, definitions, registry2) => {
6980
- if (ts.isCallExpression(node) && isDefineIslandRegistryCall(node.expression, registryFactoryNames, registryNamespaceNames)) {
7415
+ if (ts2.isCallExpression(node) && isDefineIslandRegistryCall(node.expression, registryFactoryNames, registryNamespaceNames)) {
6981
7416
  processDefineIslandRegistry(node, imports, definitions, registry2);
6982
7417
  }
6983
- ts.forEachChild(node, (child) => walkRegistryNode(child, imports, registryFactoryNames, registryNamespaceNames, definitions, registry2));
7418
+ ts2.forEachChild(node, (child) => walkRegistryNode(child, imports, registryFactoryNames, registryNamespaceNames, definitions, registry2));
6984
7419
  }, isDefineIslandRegistryCall = (expression, registryFactoryNames, registryNamespaceNames) => {
6985
- if (ts.isIdentifier(expression)) {
7420
+ if (ts2.isIdentifier(expression)) {
6986
7421
  return registryFactoryNames.has(expression.text);
6987
7422
  }
6988
- return ts.isPropertyAccessExpression(expression) && expression.name.text === "defineIslandRegistry" && ts.isIdentifier(expression.expression) && registryNamespaceNames.has(expression.expression.text);
7423
+ return ts2.isPropertyAccessExpression(expression) && expression.name.text === "defineIslandRegistry" && ts2.isIdentifier(expression.expression) && registryNamespaceNames.has(expression.expression.text);
6989
7424
  }, hasIslandRegistryNamedExport = (sourceFile) => {
6990
7425
  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")) {
7426
+ 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
7427
  return true;
6993
7428
  }
6994
- if (!ts.isExportDeclaration(statement) || !statement.exportClause)
7429
+ if (!ts2.isExportDeclaration(statement) || !statement.exportClause)
6995
7430
  continue;
6996
- if (!ts.isNamedExports(statement.exportClause))
7431
+ if (!ts2.isNamedExports(statement.exportClause))
6997
7432
  continue;
6998
7433
  if (statement.exportClause.elements.some((element) => element.name.text === "islandRegistry")) {
6999
7434
  return true;
@@ -7002,7 +7437,7 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
7002
7437
  return false;
7003
7438
  }, collectImportDeclarations = (sourceFile, registryPath, imports, registryFactoryNames, registryNamespaceNames) => {
7004
7439
  for (const statement of sourceFile.statements) {
7005
- if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier))
7440
+ if (!ts2.isImportDeclaration(statement) || !ts2.isStringLiteral(statement.moduleSpecifier))
7006
7441
  continue;
7007
7442
  const { importClause } = statement;
7008
7443
  if (!importClause)
@@ -7013,7 +7448,7 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
7013
7448
  collectRegistryHelperImports(importClause, statement.moduleSpecifier.text, registryFactoryNames, registryNamespaceNames);
7014
7449
  }
7015
7450
  }, parseIslandRegistryBuildInfo = (registrySource, registryPath) => {
7016
- const sourceFile = ts.createSourceFile(registryPath, registrySource, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
7451
+ const sourceFile = ts2.createSourceFile(registryPath, registrySource, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TS);
7017
7452
  const imports = new Map;
7018
7453
  const registryFactoryNames = new Set(["defineIslandRegistry"]);
7019
7454
  const registryNamespaceNames = new Set;
@@ -7045,7 +7480,7 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
7045
7480
  registry: registry2
7046
7481
  };
7047
7482
  }, loadIslandRegistryBuildInfo = async (registryPath) => {
7048
- const resolvedRegistryPath = resolve13(registryPath);
7483
+ const resolvedRegistryPath = resolve14(registryPath);
7049
7484
  const registrySource = Bun.file(resolvedRegistryPath);
7050
7485
  const registrySourceText = await registrySource.text();
7051
7486
  const parsedInfo = parseIslandRegistryBuildInfo(registrySourceText, resolvedRegistryPath);
@@ -7075,25 +7510,25 @@ var init_islandEntries = __esm(() => {
7075
7510
 
7076
7511
  // src/build/islandRegistryTransform.ts
7077
7512
  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) => {
7513
+ import ts3 from "typescript";
7514
+ 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
7515
  const factoryNames = new Set;
7081
7516
  const namespaceNames = new Set;
7082
7517
  for (const statement of sourceFile.statements) {
7083
- if (!ts2.isImportDeclaration(statement))
7518
+ if (!ts3.isImportDeclaration(statement))
7084
7519
  continue;
7085
- if (!ts2.isStringLiteral(statement.moduleSpecifier))
7520
+ if (!ts3.isStringLiteral(statement.moduleSpecifier))
7086
7521
  continue;
7087
7522
  if (!isIslandRegistryHelperImport2(statement.moduleSpecifier.text))
7088
7523
  continue;
7089
7524
  const bindings = statement.importClause?.namedBindings;
7090
7525
  if (!bindings)
7091
7526
  continue;
7092
- if (ts2.isNamespaceImport(bindings)) {
7527
+ if (ts3.isNamespaceImport(bindings)) {
7093
7528
  namespaceNames.add(bindings.name.text);
7094
7529
  continue;
7095
7530
  }
7096
- if (!ts2.isNamedImports(bindings))
7531
+ if (!ts3.isNamedImports(bindings))
7097
7532
  continue;
7098
7533
  for (const element of bindings.elements) {
7099
7534
  const imported = element.propertyName?.text ?? element.name.text;
@@ -7104,20 +7539,20 @@ var VALID_FRAMEWORKS, getObjectPropertyName2 = (name) => ts2.isIdentifier(name)
7104
7539
  }
7105
7540
  return { factoryNames, namespaceNames };
7106
7541
  }, isDefineIslandRegistryCall2 = (expression, factoryNames, namespaceNames) => {
7107
- if (ts2.isIdentifier(expression))
7542
+ if (ts3.isIdentifier(expression))
7108
7543
  return factoryNames.has(expression.text);
7109
- return ts2.isPropertyAccessExpression(expression) && expression.name.text === "defineIslandRegistry" && ts2.isIdentifier(expression.expression) && namespaceNames.has(expression.expression.text);
7544
+ return ts3.isPropertyAccessExpression(expression) && expression.name.text === "defineIslandRegistry" && ts3.isIdentifier(expression.expression) && namespaceNames.has(expression.expression.text);
7110
7545
  }, findDefineIslandRegistryCall = (sourceFile, factoryNames, namespaceNames) => {
7111
7546
  let found = null;
7112
7547
  const visit = (node) => {
7113
7548
  if (found)
7114
7549
  return;
7115
- const [firstArg] = ts2.isCallExpression(node) ? node.arguments : [];
7116
- if (ts2.isCallExpression(node) && isDefineIslandRegistryCall2(node.expression, factoryNames, namespaceNames) && firstArg && ts2.isObjectLiteralExpression(firstArg)) {
7550
+ const [firstArg] = ts3.isCallExpression(node) ? node.arguments : [];
7551
+ if (ts3.isCallExpression(node) && isDefineIslandRegistryCall2(node.expression, factoryNames, namespaceNames) && firstArg && ts3.isObjectLiteralExpression(firstArg)) {
7117
7552
  found = node;
7118
7553
  return;
7119
7554
  }
7120
- ts2.forEachChild(node, visit);
7555
+ ts3.forEachChild(node, visit);
7121
7556
  };
7122
7557
  visit(sourceFile);
7123
7558
  return found;
@@ -7127,8 +7562,8 @@ var VALID_FRAMEWORKS, getObjectPropertyName2 = (name) => ts2.isIdentifier(name)
7127
7562
  }, transformIslandRegistrySource = (source, filePath, info2) => {
7128
7563
  if (!source.includes("defineIslandRegistry"))
7129
7564
  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);
7565
+ const scriptKind = filePath.endsWith(".tsx") || filePath.endsWith(".jsx") ? ts3.ScriptKind.TSX : ts3.ScriptKind.TS;
7566
+ const sourceFile = ts3.createSourceFile(filePath, source, ts3.ScriptTarget.Latest, true, scriptKind);
7132
7567
  const { factoryNames, namespaceNames } = collectRegistryFactory(sourceFile);
7133
7568
  if (factoryNames.size === 0 && namespaceNames.size === 0)
7134
7569
  return null;
@@ -7136,7 +7571,7 @@ var VALID_FRAMEWORKS, getObjectPropertyName2 = (name) => ts2.isIdentifier(name)
7136
7571
  if (!call)
7137
7572
  return null;
7138
7573
  const [objectLiteral] = call.arguments;
7139
- if (!objectLiteral || !ts2.isObjectLiteralExpression(objectLiteral)) {
7574
+ if (!objectLiteral || !ts3.isObjectLiteralExpression(objectLiteral)) {
7140
7575
  return null;
7141
7576
  }
7142
7577
  const definitionLookup = new Map;
@@ -7151,20 +7586,20 @@ var VALID_FRAMEWORKS, getObjectPropertyName2 = (name) => ts2.isIdentifier(name)
7151
7586
  const edits = [];
7152
7587
  const replacedLocals = new Set;
7153
7588
  for (const frameworkProperty of objectLiteral.properties) {
7154
- if (!ts2.isPropertyAssignment(frameworkProperty))
7589
+ if (!ts3.isPropertyAssignment(frameworkProperty))
7155
7590
  continue;
7156
7591
  const frameworkName = getObjectPropertyName2(frameworkProperty.name);
7157
7592
  const framework = VALID_FRAMEWORKS.find((f) => f === frameworkName);
7158
7593
  if (!framework)
7159
7594
  continue;
7160
- if (!ts2.isObjectLiteralExpression(frameworkProperty.initializer))
7595
+ if (!ts3.isObjectLiteralExpression(frameworkProperty.initializer))
7161
7596
  continue;
7162
7597
  for (const componentProperty of frameworkProperty.initializer.properties) {
7163
7598
  let componentKey = null;
7164
7599
  let localName = null;
7165
7600
  let replaceNode = null;
7166
7601
  let replacementText = "";
7167
- if (ts2.isShorthandPropertyAssignment(componentProperty)) {
7602
+ if (ts3.isShorthandPropertyAssignment(componentProperty)) {
7168
7603
  componentKey = componentProperty.name.text;
7169
7604
  localName = componentProperty.name.text;
7170
7605
  const reference = definitionLookup.get(`${framework}:${componentKey}`);
@@ -7172,7 +7607,7 @@ var VALID_FRAMEWORKS, getObjectPropertyName2 = (name) => ts2.isIdentifier(name)
7172
7607
  continue;
7173
7608
  replaceNode = componentProperty;
7174
7609
  replacementText = `${quoteKey(componentKey)}: ${definitionLiteral(reference)}`;
7175
- } else if (ts2.isPropertyAssignment(componentProperty) && ts2.isIdentifier(componentProperty.initializer)) {
7610
+ } else if (ts3.isPropertyAssignment(componentProperty) && ts3.isIdentifier(componentProperty.initializer)) {
7176
7611
  componentKey = getObjectPropertyName2(componentProperty.name);
7177
7612
  localName = componentProperty.initializer.text;
7178
7613
  if (!componentKey)
@@ -7196,7 +7631,7 @@ var VALID_FRAMEWORKS, getObjectPropertyName2 = (name) => ts2.isIdentifier(name)
7196
7631
  if (edits.length === 0)
7197
7632
  return null;
7198
7633
  for (const statement of sourceFile.statements) {
7199
- if (!ts2.isImportDeclaration(statement))
7634
+ if (!ts3.isImportDeclaration(statement))
7200
7635
  continue;
7201
7636
  const clause = statement.importClause;
7202
7637
  if (!clause)
@@ -7205,11 +7640,11 @@ var VALID_FRAMEWORKS, getObjectPropertyName2 = (name) => ts2.isIdentifier(name)
7205
7640
  if (clause.name)
7206
7641
  localNames.push(clause.name.text);
7207
7642
  const bindings = clause.namedBindings;
7208
- if (bindings && ts2.isNamedImports(bindings)) {
7643
+ if (bindings && ts3.isNamedImports(bindings)) {
7209
7644
  for (const element of bindings.elements) {
7210
7645
  localNames.push(element.name.text);
7211
7646
  }
7212
- } else if (bindings && ts2.isNamespaceImport(bindings)) {
7647
+ } else if (bindings && ts3.isNamespaceImport(bindings)) {
7213
7648
  localNames.push(bindings.name.text);
7214
7649
  }
7215
7650
  if (localNames.length === 0)
@@ -7266,18 +7701,18 @@ var init_islandRegistryTransform = __esm(() => {
7266
7701
  });
7267
7702
 
7268
7703
  // src/build/bunStringRawUnicodePlugin.ts
7269
- import { extname as extname2 } from "path";
7270
- import ts3 from "typescript";
7704
+ import { extname as extname3 } from "path";
7705
+ import ts4 from "typescript";
7271
7706
  var NON_ASCII, getScriptKind = (filePath) => {
7272
7707
  if (/\.[cm]?tsx$/.test(filePath))
7273
- return ts3.ScriptKind.TSX;
7708
+ return ts4.ScriptKind.TSX;
7274
7709
  if (/\.[cm]?jsx$/.test(filePath))
7275
- return ts3.ScriptKind.JSX;
7710
+ return ts4.ScriptKind.JSX;
7276
7711
  if (/\.[cm]?ts$/.test(filePath))
7277
- return ts3.ScriptKind.TS;
7278
- return ts3.ScriptKind.JS;
7712
+ return ts4.ScriptKind.TS;
7713
+ return ts4.ScriptKind.JS;
7279
7714
  }, getLoader = (filePath) => {
7280
- const extension = extname2(filePath);
7715
+ const extension = extname3(filePath);
7281
7716
  if (extension === ".tsx")
7282
7717
  return "tsx";
7283
7718
  if (extension === ".jsx")
@@ -7286,24 +7721,24 @@ var NON_ASCII, getScriptKind = (filePath) => {
7286
7721
  return "ts";
7287
7722
  }
7288
7723
  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") => {
7724
+ }, 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
7725
  if (!source.includes("String.raw") || !NON_ASCII.test(source))
7291
7726
  return source;
7292
- const sourceFile = ts3.createSourceFile(filePath, source, ts3.ScriptTarget.Latest, true, getScriptKind(filePath));
7727
+ const sourceFile = ts4.createSourceFile(filePath, source, ts4.ScriptTarget.Latest, true, getScriptKind(filePath));
7293
7728
  const replacements = [];
7294
7729
  const visit = (node) => {
7295
- if (ts3.isTaggedTemplateExpression(node) && isStringRawTag(node)) {
7296
- const rawSegments = ts3.isNoSubstitutionTemplateLiteral(node.template) ? [getRawText(node.template)] : [
7730
+ if (ts4.isTaggedTemplateExpression(node) && isStringRawTag(node)) {
7731
+ const rawSegments = ts4.isNoSubstitutionTemplateLiteral(node.template) ? [getRawText(node.template)] : [
7297
7732
  getRawText(node.template.head),
7298
7733
  ...node.template.templateSpans.map((span) => getRawText(span.literal))
7299
7734
  ];
7300
7735
  if (rawSegments.some((segment) => NON_ASCII.test(segment))) {
7301
- const expressions = ts3.isTemplateExpression(node.template) ? node.template.templateSpans.map((span) => {
7736
+ const expressions = ts4.isTemplateExpression(node.template) ? node.template.templateSpans.map((span) => {
7302
7737
  const expression = source.slice(span.expression.getStart(sourceFile), span.expression.end);
7303
7738
  return rewriteBunStringRawUnicode(expression, filePath);
7304
7739
  }) : [];
7305
7740
  const args = [
7306
- `{ raw: [${rawSegments.map((text) => JSON.stringify(text)).join(", ")}] }`,
7741
+ `{ raw: [${rawSegments.map((text2) => JSON.stringify(text2)).join(", ")}] }`,
7307
7742
  ...expressions
7308
7743
  ];
7309
7744
  replacements.push({
@@ -7314,7 +7749,7 @@ var NON_ASCII, getScriptKind = (filePath) => {
7314
7749
  return;
7315
7750
  }
7316
7751
  }
7317
- ts3.forEachChild(node, visit);
7752
+ ts4.forEachChild(node, visit);
7318
7753
  };
7319
7754
  visit(sourceFile);
7320
7755
  let result = source;
@@ -7579,20 +8014,20 @@ var normalizeSlug = (str) => str.trim().replace(/\s+/g, "-").replace(/[^A-Za-z0-
7579
8014
  // src/mobile/buildRelease.ts
7580
8015
  import { createHash as createHash9 } from "crypto";
7581
8016
  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";
8017
+ import { basename as basename7, dirname as dirname11, extname as extname4, join as join20, relative as relative11, resolve as resolve15 } from "path";
7583
8018
  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
8019
  if (path.endsWith("/htmx.min.js"))
7585
8020
  return match;
7586
- const key = toPascal(basename7(path, extname3(path)));
8021
+ const key = toPascal(basename7(path, extname4(path)));
7587
8022
  const builtPath = manifest[key];
7588
8023
  return builtPath ? `${prefix}${builtPath}${suffix}` : match;
7589
8024
  }), readPageMetadata = (route) => parseAbsoluteMobileBuildPageMetadata(route.hooks?.detail?.[ABSOLUTE_MOBILE_ROUTE_DETAIL]), resolveAssetPath = (buildDirectory, assetPath) => {
7590
- const resolvedBuildDirectory = resolve14(buildDirectory);
7591
- const resolvedAsset = resolve14(assetPath);
8025
+ const resolvedBuildDirectory = resolve15(buildDirectory);
8026
+ const resolvedAsset = resolve15(assetPath);
7592
8027
  if (resolvedAsset.startsWith(`${resolvedBuildDirectory}/`)) {
7593
8028
  return resolvedAsset;
7594
8029
  }
7595
- return join19(buildDirectory, assetPath.replace(/^\/+/, ""));
8030
+ return join20(buildDirectory, assetPath.replace(/^\/+/, ""));
7596
8031
  }, pageFor = async (metadata, manifest, buildDirectory) => {
7597
8032
  const assetPath = manifest[metadata.bundleKey];
7598
8033
  if (!assetPath) {
@@ -7603,7 +8038,7 @@ var sha256 = (bytes) => createHash9("sha256").update(bytes).digest("hex"), STATI
7603
8038
  const source = await readFile9(resolvedAssetPath, "utf8");
7604
8039
  const rewritten = rewriteStaticScriptPaths(source, manifest);
7605
8040
  const documentHash = sha256(new TextEncoder().encode(rewritten));
7606
- resolvedAssetPath = join19(buildDirectory, ".absolutejs", "mobile-pages", `${documentHash}.html`);
8041
+ resolvedAssetPath = join20(buildDirectory, ".absolutejs", "mobile-pages", `${documentHash}.html`);
7607
8042
  await mkdir8(dirname11(resolvedAssetPath), { recursive: true });
7608
8043
  await writeFile7(resolvedAssetPath, rewritten);
7609
8044
  }
@@ -7617,8 +8052,8 @@ var sha256 = (bytes) => createHash9("sha256").update(bytes).digest("hex"), STATI
7617
8052
  readFile9(resolvedAssetPath),
7618
8053
  resolvedStylePath ? readFile9(resolvedStylePath) : undefined
7619
8054
  ]);
7620
- const bundlePath = `/${relative10(resolve14(buildDirectory), resolvedAssetPath).replaceAll("\\", "/")}`;
7621
- const styleBundlePath = resolvedStylePath ? `/${relative10(resolve14(buildDirectory), resolvedStylePath).replaceAll("\\", "/")}` : undefined;
8055
+ const bundlePath = `/${relative11(resolve15(buildDirectory), resolvedAssetPath).replaceAll("\\", "/")}`;
8056
+ const styleBundlePath = resolvedStylePath ? `/${relative11(resolve15(buildDirectory), resolvedStylePath).replaceAll("\\", "/")}` : undefined;
7622
8057
  return {
7623
8058
  bundleHash: sha256(bytes),
7624
8059
  bundlePath,
@@ -7819,40 +8254,40 @@ import {
7819
8254
  rm as rm6,
7820
8255
  writeFile as writeFile8
7821
8256
  } 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";
8257
+ import { existsSync as existsSync10 } from "fs";
8258
+ import { basename as basename8, dirname as dirname12, extname as extname5, join as join21, relative as relative12, resolve as resolve16 } from "path";
7824
8259
  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);
8260
+ const candidate = ["js", "ts"].map((extension) => join21(import.meta.dir, `shellBootstrap.${extension}`)).find(existsSync10);
7826
8261
  if (candidate)
7827
8262
  return candidate;
7828
8263
  throw new TypeError("AbsoluteJS mobile shell bootstrap module is missing.");
7829
8264
  }, shellAuthModule = () => {
7830
- const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellAuth.${extension}`)).find(existsSync9);
8265
+ const candidate = ["js", "ts"].map((extension) => join21(import.meta.dir, `shellAuth.${extension}`)).find(existsSync10);
7831
8266
  if (candidate)
7832
8267
  return candidate;
7833
8268
  throw new TypeError("AbsoluteJS mobile auth shell module is missing.");
7834
8269
  }, shellExpoAuthModule = () => {
7835
- const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellExpoAuth.${extension}`)).find(existsSync9);
8270
+ const candidate = ["js", "ts"].map((extension) => join21(import.meta.dir, `shellExpoAuth.${extension}`)).find(existsSync10);
7836
8271
  if (candidate)
7837
8272
  return candidate;
7838
8273
  throw new TypeError("AbsoluteJS Expo auth bridge module is missing.");
7839
8274
  }, shellSyncModule = () => {
7840
- const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellSync.${extension}`)).find(existsSync9);
8275
+ const candidate = ["js", "ts"].map((extension) => join21(import.meta.dir, `shellSync.${extension}`)).find(existsSync10);
7841
8276
  if (candidate)
7842
8277
  return candidate;
7843
8278
  throw new TypeError("AbsoluteJS mobile Sync shell module is missing.");
7844
8279
  }, shellExpoSyncModule = () => {
7845
- const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellExpoSync.${extension}`)).find(existsSync9);
8280
+ const candidate = ["js", "ts"].map((extension) => join21(import.meta.dir, `shellExpoSync.${extension}`)).find(existsSync10);
7846
8281
  if (candidate)
7847
8282
  return candidate;
7848
8283
  throw new TypeError("AbsoluteJS Expo Sync bridge module is missing.");
7849
8284
  }, shellPushModule = () => {
7850
- const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellPush.${extension}`)).find(existsSync9);
8285
+ const candidate = ["js", "ts"].map((extension) => join21(import.meta.dir, `shellPush.${extension}`)).find(existsSync10);
7851
8286
  if (candidate)
7852
8287
  return candidate;
7853
8288
  throw new TypeError("AbsoluteJS mobile push shell module is missing.");
7854
8289
  }, shellExpoDevicesModule = () => {
7855
- const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellExpoDevices.${extension}`)).find(existsSync9);
8290
+ const candidate = ["js", "ts"].map((extension) => join21(import.meta.dir, `shellExpoDevices.${extension}`)).find(existsSync10);
7856
8291
  if (candidate)
7857
8292
  return candidate;
7858
8293
  throw new TypeError("AbsoluteJS Expo device bridge module is missing.");
@@ -7883,8 +8318,8 @@ var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-
7883
8318
  </body>
7884
8319
  </html>
7885
8320
  `, sourceAssetPath = (buildDirectory, bundlePath) => {
7886
- const root = resolve15(buildDirectory);
7887
- const asset = resolve15(root, bundlePath.replace(/^\/+/, ""));
8321
+ const root = resolve16(buildDirectory);
8322
+ const asset = resolve16(root, bundlePath.replace(/^\/+/, ""));
7888
8323
  if (!asset.startsWith(`${root}/`)) {
7889
8324
  throw new TypeError("Mobile page bundle escaped the build directory.");
7890
8325
  }
@@ -7899,15 +8334,15 @@ var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-
7899
8334
  const segments = specifier.split("/");
7900
8335
  const packageName = specifier.startsWith("@") ? segments.slice(0, 2).join("/") : segments[0] ?? "";
7901
8336
  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"));
8337
+ const packageDirectory = join21(resolve16(projectRoot), "node_modules", packageName);
8338
+ const manifest = JSON.parse(await readFile10(join21(packageDirectory, "package.json"), "utf8"));
7904
8339
  const exports = typeof manifest === "object" && manifest !== null ? Reflect.get(manifest, "exports") : undefined;
7905
8340
  const entry = typeof exports === "object" && exports !== null ? Reflect.get(exports, subpath ? `.${subpath}` : ".") : undefined;
7906
8341
  const target = importEntryTarget(entry);
7907
8342
  if (typeof target !== "string" || !target.startsWith("./"))
7908
8343
  throw new TypeError(`${specifier} does not publish an import entry.`);
7909
- const resolved = resolve15(packageDirectory, target);
7910
- if (!resolved.startsWith(`${resolve15(packageDirectory)}/`))
8344
+ const resolved = resolve16(packageDirectory, target);
8345
+ if (!resolved.startsWith(`${resolve16(packageDirectory)}/`))
7911
8346
  throw new TypeError(`${specifier} has an unsafe import entry.`);
7912
8347
  return resolved;
7913
8348
  }, buildShellBootstrap = async (staging, auth, sync, storagePrefix, engine, deviceCapabilities, projectRoot) => {
@@ -7936,10 +8371,10 @@ var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-
7936
8371
  const absoluteMobilePushCapability = absoluteDeviceCapability${pushIndex}(absoluteMobilePush.capabilityOptions);
7937
8372
  ` : "";
7938
8373
  const capabilityOptions = shellCapabilities.map((name, index) => `${JSON.stringify(name)}: ${name === "pushNotifications" ? "absoluteMobilePushCapability" : `absoluteDeviceCapability${index}()`}`).join(", ");
7939
- const entryPath = join20(staging, ".absolute-mobile-entry.ts");
8374
+ const entryPath = join21(staging, ".absolute-mobile-entry.ts");
7940
8375
  const baseAdapterModule = capacitor ? await resolveProjectImport(projectRoot, "@absolutejs/devices-capacitor") : shellExpoDevicesModule();
7941
8376
  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();";
8377
+ const adapterInstall = capacitor ? `installCapacitorDeviceAdapterIfNative({ storagePrefix: ${JSON.stringify(storagePrefix)}${capabilityOptions ? `, ${capabilityOptions}` : ""} });` : `installAbsoluteExpoWebDeviceAdapter(${JSON.stringify(deviceCapabilities.capabilities)});`;
7943
8378
  let shellOptions = auth ? options : "{ createFetch: createAbsoluteExpoBridgeFetch }";
7944
8379
  if (capacitor)
7945
8380
  shellOptions = options;
@@ -7961,7 +8396,7 @@ void startAbsoluteMobileShell(${shellOptions});
7961
8396
  if (!build.success || build.outputs.length !== 1) {
7962
8397
  throw new AggregateError(build.logs, "Failed to build the AbsoluteJS Capacitor shell.");
7963
8398
  }
7964
- await rename7(build.outputs[0]?.path ?? "", join20(staging, BOOTSTRAP_FILE));
8399
+ await rename7(build.outputs[0]?.path ?? "", join21(staging, BOOTSTRAP_FILE));
7965
8400
  await rm6(entryPath, { force: true });
7966
8401
  }, removePreviousBundle = async (backup, moved) => {
7967
8402
  if (!moved)
@@ -7992,20 +8427,20 @@ void startAbsoluteMobileShell(${shellOptions});
7992
8427
  if (!CAPACITOR_CLIENT_FRAMEWORKS.has(page.framework)) {
7993
8428
  throw new TypeError(`Capacitor client rendering does not yet support ${page.framework} page ${page.pageId}.`);
7994
8429
  }
7995
- const extension = extname4(page.bundlePath) || ".js";
8430
+ const extension = extname5(page.bundlePath) || ".js";
7996
8431
  const localBundlePath = `./pages/${page.bundleHash}${extension}`;
7997
8432
  const source = sourceAssetPath(buildDirectory, page.bundlePath);
7998
- await copyFile4(source, join20(staging, localBundlePath));
8433
+ await copyFile4(source, join21(staging, localBundlePath));
7999
8434
  await copyAbsoluteClientDependencies(source, buildDirectory, staging, copiedDependencies);
8000
8435
  let localStylePath;
8001
8436
  if (page.styleBundlePath && page.styleBundleHash) {
8002
- const styleExtension = extname4(page.styleBundlePath) || ".css";
8437
+ const styleExtension = extname5(page.styleBundlePath) || ".css";
8003
8438
  localStylePath = `./styles/${page.styleBundleHash}${styleExtension}`;
8004
8439
  const styleSource = sourceAssetPath(buildDirectory, page.styleBundlePath);
8005
- await mkdir9(dirname12(join20(staging, localStylePath)), {
8440
+ await mkdir9(dirname12(join21(staging, localStylePath)), {
8006
8441
  recursive: true
8007
8442
  });
8008
- await copyFile4(styleSource, join20(staging, localStylePath));
8443
+ await copyFile4(styleSource, join21(staging, localStylePath));
8009
8444
  await copyAbsoluteClientDependencies(styleSource, buildDirectory, staging, copiedDependencies);
8010
8445
  }
8011
8446
  return {
@@ -8015,7 +8450,7 @@ void startAbsoluteMobileShell(${shellOptions});
8015
8450
  };
8016
8451
  }, absoluteClientImports = async (sourcePath, buildDirectory) => {
8017
8452
  const source = await readFile10(sourcePath, "utf8");
8018
- const extension = extname4(sourcePath).toLowerCase();
8453
+ const extension = extname5(sourcePath).toLowerCase();
8019
8454
  let scriptLoader;
8020
8455
  if (extension === ".tsx")
8021
8456
  scriptLoader = "tsx";
@@ -8037,9 +8472,9 @@ void startAbsoluteMobileShell(${shellOptions});
8037
8472
  const clean = specifier.split(/[?#]/u, 1)[0] ?? specifier;
8038
8473
  if (clean.startsWith("/"))
8039
8474
  return [clean];
8040
- const resolved = resolve15(dirname12(sourcePath), clean);
8041
- const root = resolve15(buildDirectory);
8042
- const relativePath = relative11(root, resolved).replaceAll("\\", "/");
8475
+ const resolved = resolve16(dirname12(sourcePath), clean);
8476
+ const root = resolve16(buildDirectory);
8477
+ const relativePath = relative12(root, resolved).replaceAll("\\", "/");
8043
8478
  if (relativePath === ".." || relativePath.startsWith("../")) {
8044
8479
  throw new TypeError(`Mobile client dependency escaped the build directory: ${specifier}`);
8045
8480
  }
@@ -8050,7 +8485,7 @@ void startAbsoluteMobileShell(${shellOptions});
8050
8485
  return;
8051
8486
  copied.add(specifier);
8052
8487
  const source = sourceAssetPath(buildDirectory, specifier);
8053
- const destination = join20(staging, specifier.replace(/^\/+/, ""));
8488
+ const destination = join21(staging, specifier.replace(/^\/+/, ""));
8054
8489
  await mkdir9(dirname12(destination), { recursive: true });
8055
8490
  await copyFile4(source, destination);
8056
8491
  await copyAbsoluteClientDependencies(source, buildDirectory, staging, copied);
@@ -8063,14 +8498,14 @@ void startAbsoluteMobileShell(${shellOptions});
8063
8498
  }
8064
8499
  const destination = options.config.bundleDirectory;
8065
8500
  await mkdir9(dirname12(destination), { recursive: true });
8066
- const staging = await mkdtemp4(join20(dirname12(destination), `.${basename8(destination)}.stage-`));
8501
+ const staging = await mkdtemp4(join21(dirname12(destination), `.${basename8(destination)}.stage-`));
8067
8502
  try {
8068
- const pageDirectory = join20(staging, "pages");
8503
+ const pageDirectory = join21(staging, "pages");
8069
8504
  await mkdir9(pageDirectory, { recursive: true });
8070
8505
  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 })));
8506
+ destination: join21(staging, directory),
8507
+ source: join21(options.buildDirectory, directory)
8508
+ })).filter(({ source }) => existsSync10(source)).map(({ destination: assetDestination, source }) => cp3(source, assetDestination, { recursive: true })));
8074
8509
  const copiedDependencies = new Set;
8075
8510
  const pages = await Promise.all(options.artifact.pages.map((page) => copyClientPage(page, options.buildDirectory, staging, copiedDependencies)));
8076
8511
  const manifest = {
@@ -8103,9 +8538,9 @@ void startAbsoluteMobileShell(${shellOptions});
8103
8538
  } : {}
8104
8539
  };
8105
8540
  await Promise.all([
8106
- writeFile8(join20(staging, MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
8541
+ writeFile8(join21(staging, MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
8107
8542
  `),
8108
- writeFile8(join20(staging, INDEX_FILE), indexHtml(options.config.appName, options.config.productionOrigin)),
8543
+ writeFile8(join21(staging, INDEX_FILE), indexHtml(options.config.appName, options.config.productionOrigin)),
8109
8544
  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
8545
  ]);
8111
8546
  await installBundle(staging, destination);
@@ -8161,7 +8596,7 @@ import {
8161
8596
  rm as rm7,
8162
8597
  writeFile as writeFile9
8163
8598
  } from "fs/promises";
8164
- import { dirname as dirname13, join as join21, resolve as resolvePath3 } from "path";
8599
+ import { dirname as dirname13, join as join22, resolve as resolvePath3 } from "path";
8165
8600
  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
8601
  const identity = JSON.stringify({
8167
8602
  currentReleaseId,
@@ -8191,16 +8626,16 @@ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "curre
8191
8626
  releases
8192
8627
  };
8193
8628
  }, writeRelease = async (root, release) => {
8194
- const directory = join21(root, release.artifact.releaseId);
8195
- const producerPath = join21(directory, release.artifact.producer.module);
8629
+ const directory = join22(root, release.artifact.releaseId);
8630
+ const producerPath = join22(directory, release.artifact.producer.module);
8196
8631
  await mkdir10(dirname13(producerPath), { recursive: true });
8197
8632
  await Promise.all([
8198
- writeFile9(join21(directory, ARTIFACT_FILE), `${JSON.stringify(release.artifact, null, "\t")}
8633
+ writeFile9(join22(directory, ARTIFACT_FILE), `${JSON.stringify(release.artifact, null, "\t")}
8199
8634
  `),
8200
8635
  writeFile9(producerPath, new Uint8Array(await release.producer.arrayBuffer()))
8201
8636
  ]);
8202
8637
  }, installImmutableBundle = async (bundlesRoot, bundleId, releases) => {
8203
- const destination = join21(bundlesRoot, bundleId);
8638
+ const destination = join22(bundlesRoot, bundleId);
8204
8639
  try {
8205
8640
  await access8(destination);
8206
8641
  return destination;
@@ -8208,7 +8643,7 @@ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "curre
8208
8643
  if (!errorHasCode2(error, "ENOENT"))
8209
8644
  throw error;
8210
8645
  }
8211
- const staging = await mkdtemp5(join21(bundlesRoot, ".stage-"));
8646
+ const staging = await mkdtemp5(join22(bundlesRoot, ".stage-"));
8212
8647
  try {
8213
8648
  await Promise.all(releases.map((release) => writeRelease(staging, release)));
8214
8649
  await rename8(staging, destination);
@@ -8237,7 +8672,7 @@ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "curre
8237
8672
  return release;
8238
8673
  });
8239
8674
  const root = resolvePath3(input.root);
8240
- const bundlesRoot = join21(root, BUNDLES_DIRECTORY);
8675
+ const bundlesRoot = join22(root, BUNDLES_DIRECTORY);
8241
8676
  await mkdir10(bundlesRoot, { recursive: true });
8242
8677
  const bundleId = bundleIdFor(input.currentReleaseId, artifacts);
8243
8678
  await installImmutableBundle(bundlesRoot, bundleId, orderedReleases);
@@ -8247,8 +8682,8 @@ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "curre
8247
8682
  format: ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT,
8248
8683
  releases: artifacts
8249
8684
  };
8250
- const pointerPath = join21(root, CURRENT_BUNDLE_FILE);
8251
- const temporaryPointerPath = join21(root, `.current-${crypto.randomUUID()}.json`);
8685
+ const pointerPath = join22(root, CURRENT_BUNDLE_FILE);
8686
+ const temporaryPointerPath = join22(root, `.current-${crypto.randomUUID()}.json`);
8252
8687
  await writeFile9(temporaryPointerPath, `${JSON.stringify(index, null, "\t")}
8253
8688
  `, { flag: "wx" });
8254
8689
  await rename8(temporaryPointerPath, pointerPath);
@@ -8256,12 +8691,12 @@ var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "curre
8256
8691
  }, readAbsoluteMobileMaterializedReleases = async (root) => {
8257
8692
  const resolvedRoot = resolvePath3(root);
8258
8693
  try {
8259
- const serialized = await readFile11(join21(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
8694
+ const serialized = await readFile11(join22(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
8260
8695
  const parsed = JSON.parse(serialized);
8261
8696
  const index = parseBundleIndex(parsed);
8262
- const bundleRoot = join21(resolvedRoot, BUNDLES_DIRECTORY, index.bundleId);
8697
+ const bundleRoot = join22(resolvedRoot, BUNDLES_DIRECTORY, index.bundleId);
8263
8698
  return Promise.all(index.releases.map(async (artifact) => {
8264
- const producer = Bun.file(join21(bundleRoot, artifact.releaseId, artifact.producer.module));
8699
+ const producer = Bun.file(join22(bundleRoot, artifact.releaseId, artifact.producer.module));
8265
8700
  await verifyAbsoluteMobileCompatibilityProducer({
8266
8701
  artifact,
8267
8702
  producer
@@ -8280,261 +8715,6 @@ var init_materializedBundle = __esm(() => {
8280
8715
  BUNDLE_ID_PATTERN = /^amb_[a-f0-9]{64}$/;
8281
8716
  });
8282
8717
 
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
8718
  // src/mobile/buildPipeline.ts
8539
8719
  import { readFile as readFile12 } from "fs/promises";
8540
8720
  import { join as join23, resolve as resolve17 } from "path";
@@ -8606,11 +8786,8 @@ var isElysiaApp = (value) => typeof value === "object" && value !== null && type
8606
8786
  const auth = resolveAbsoluteMobileAuthManifest(options.projectRoot, mobile);
8607
8787
  const sync = auth !== undefined && projectUsesAbsoluteSync(options.projectRoot);
8608
8788
  const syncSchema = sync ? discoverAbsoluteSyncSchema(options.projectRoot) : undefined;
8609
- const deviceCapabilities = resolveAbsoluteDeviceCapabilityPlan(options.projectRoot);
8789
+ const deviceCapabilities = resolveAbsoluteDeviceCapabilityPlan(options.projectRoot, mobile.engine);
8610
8790
  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
8791
  if (usesPush && !auth)
8615
8792
  throw new TypeError("Portable push notifications require @absolutejs/auth so provider tokens can be registered without exposing identity controls to page code.");
8616
8793
  if (usesPush && !loaded.app.routes.some((route) => route.path === "/auth/push" || route.path === "/auth/mobile/push"))
@@ -8663,10 +8840,10 @@ var init_buildPipeline = __esm(() => {
8663
8840
  });
8664
8841
 
8665
8842
  // src/mobile/routeMetadataTransform.ts
8666
- import { existsSync as existsSync10, readFileSync as readFileSync13 } from "fs";
8843
+ import { existsSync as existsSync11, readFileSync as readFileSync13 } from "fs";
8667
8844
  import { dirname as dirname14, extname as extname6, relative as relative13, resolve as resolve18 } from "path";
8668
8845
  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) => {
8846
+ 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
8847
  const configPath2 = findTsconfig(entry, projectRoot);
8671
8848
  if (!configPath2) {
8672
8849
  return ts5.createProgram([entry], {
@@ -9934,7 +10111,7 @@ var init_rewriteImports = __esm(() => {
9934
10111
 
9935
10112
  // src/cli/scripts/start.ts
9936
10113
  var {env: env2 } = globalThis.Bun;
9937
- import { existsSync as existsSync11, readFileSync as readFileSync15, rmSync as rmSync4 } from "fs";
10114
+ import { existsSync as existsSync12, readFileSync as readFileSync15, rmSync as rmSync4 } from "fs";
9938
10115
  import { basename as basename9, join as join26, resolve as resolve21 } from "path";
9939
10116
  var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`, resolvePackageVersion = (candidates) => {
9940
10117
  for (const candidate of candidates) {
@@ -9992,7 +10169,7 @@ var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
9992
10169
  resolve21(import.meta.dir, "..", "..", "..", "src", "react", "jsxDevRuntimeCompat.ts")
9993
10170
  ];
9994
10171
  for (const candidate of candidates) {
9995
- if (existsSync11(candidate))
10172
+ if (existsSync12(candidate))
9996
10173
  return candidate;
9997
10174
  }
9998
10175
  return resolve21(import.meta.dir, "..", "..", "react", "jsxDevRuntimeCompat.js");
@@ -10029,7 +10206,7 @@ var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
10029
10206
  serverEntry,
10030
10207
  totalDuration
10031
10208
  }) => {
10032
- const usesDocker = existsSync11(resolve21(COMPOSE_PATH));
10209
+ const usesDocker = existsSync12(resolve21(COMPOSE_PATH));
10033
10210
  const scripts = usesDocker ? await readDbScripts() : null;
10034
10211
  if (scripts)
10035
10212
  await startDatabase(scripts);
@@ -10140,7 +10317,7 @@ var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
10140
10317
  ].filter((val) => Boolean(val));
10141
10318
  const outputPath = resolve21(resolvedOutdir, `${entryName}.js`);
10142
10319
  if (options.prebuilt) {
10143
- if (!existsSync11(outputPath)) {
10320
+ if (!existsSync12(outputPath)) {
10144
10321
  throw new Error(`Prepared production server not found: ${outputPath}`);
10145
10322
  }
10146
10323
  return runPreparedServer({
@@ -10267,11 +10444,11 @@ var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
10267
10444
  if (!serverBundle.success) {
10268
10445
  handleBundleFailure(serverBundle, bundleStart, serverEntry);
10269
10446
  }
10270
- if (!existsSync11(outputPath)) {
10447
+ if (!existsSync12(outputPath)) {
10271
10448
  console.error(cliTag2("\x1B[31m", `Expected output not found: ${outputPath}`));
10272
10449
  process.exit(1);
10273
10450
  }
10274
- if (existsSync11(resolve21(resolvedOutdir, "angular", "vendor", "server"))) {
10451
+ if (existsSync12(resolve21(resolvedOutdir, "angular", "vendor", "server"))) {
10275
10452
  const { readdirSync: readdirSync2 } = await import("fs");
10276
10453
  const vendorDir = resolve21(resolvedOutdir, "angular", "vendor", "server");
10277
10454
  const vendorEntries = readdirSync2(vendorDir).filter((fileName) => fileName.endsWith(".js"));
@@ -10470,11 +10647,11 @@ var exports_build = {};
10470
10647
  __export(exports_build, {
10471
10648
  build: () => build
10472
10649
  });
10473
- import { existsSync as existsSync13, readdirSync as readdirSync3, readFileSync as readFileSync17 } from "fs";
10650
+ import { existsSync as existsSync14, readdirSync as readdirSync3, readFileSync as readFileSync17 } from "fs";
10474
10651
  import { join as join27, resolve as resolve23 } from "path";
10475
10652
  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
10653
  const traceDir = join27(buildDir, ".absolute-trace");
10477
- if (!existsSync13(traceDir))
10654
+ if (!existsSync14(traceDir))
10478
10655
  return;
10479
10656
  const files = readdirSync3(traceDir).filter((file) => file.endsWith(".json")).sort();
10480
10657
  const latest = files[files.length - 1];
@@ -10573,7 +10750,7 @@ import {
10573
10750
  verify
10574
10751
  } from "crypto";
10575
10752
  import {
10576
- existsSync as existsSync14,
10753
+ existsSync as existsSync15,
10577
10754
  lstatSync,
10578
10755
  mkdirSync as mkdirSync8,
10579
10756
  mkdtempSync,
@@ -10773,7 +10950,7 @@ var DEFAULT_PROOF_LOCATION = ".absolutejs/lint-proof.json", PROOF_CONTRACT_VERSI
10773
10950
  const cwd = options.cwd ?? process.cwd();
10774
10951
  const proofLocation = options.proofLocation ?? DEFAULT_PROOF_LOCATION;
10775
10952
  const path = resolve24(cwd, proofLocation);
10776
- if (!existsSync14(path))
10953
+ if (!existsSync15(path))
10777
10954
  return { reason: `missing lint proof: ${proofLocation}`, valid: false };
10778
10955
  let proof;
10779
10956
  try {
@@ -10890,7 +11067,7 @@ var init_lintProof = __esm(() => {
10890
11067
  // src/build/scanConventions.ts
10891
11068
  import { basename as basename10 } from "path";
10892
11069
  var {Glob: Glob2 } = globalThis.Bun;
10893
- import { existsSync as existsSync15 } from "fs";
11070
+ import { existsSync as existsSync16 } from "fs";
10894
11071
  var CONVENTION_RE, classifyFile = (file, pageFiles, defaults, pages) => {
10895
11072
  const fileName = basename10(file);
10896
11073
  const match = CONVENTION_RE.exec(fileName);
@@ -10915,7 +11092,7 @@ var CONVENTION_RE, classifyFile = (file, pageFiles, defaults, pages) => {
10915
11092
  else if (kind === "loading")
10916
11093
  pages[pageName].loading = file;
10917
11094
  }, scanConventions = async (pagesDir, pattern) => {
10918
- if (!existsSync15(pagesDir)) {
11095
+ if (!existsSync16(pagesDir)) {
10919
11096
  const pageFiles2 = [];
10920
11097
  return { conventions: undefined, pageFiles: pageFiles2 };
10921
11098
  }
@@ -10942,7 +11119,7 @@ var exports_ls = {};
10942
11119
  __export(exports_ls, {
10943
11120
  runLs: () => runLs
10944
11121
  });
10945
- import { existsSync as existsSync16, readFileSync as readFileSync19, statSync } from "fs";
11122
+ import { existsSync as existsSync17, readFileSync as readFileSync19, statSync } from "fs";
10946
11123
  import { basename as basename11, extname as extname7, join as join28, relative as relative15 } from "path";
10947
11124
  var DEFAULT_BUILD_DIR = "build", LABEL_ORDER, ARTIFACT_SUFFIXES, FRAMEWORK_FIELDS, readStringField = (source, key) => {
10948
11125
  const value = Reflect.get(source, key);
@@ -10993,10 +11170,10 @@ var DEFAULT_BUILD_DIR = "build", LABEL_ORDER, ARTIFACT_SUFFIXES, FRAMEWORK_FIELD
10993
11170
  return pages ? [{ label, pages: sortPages(pages) }] : [];
10994
11171
  });
10995
11172
  }, resolveDiskPath = (buildDir, value) => {
10996
- if (existsSync16(value))
11173
+ if (existsSync17(value))
10997
11174
  return value;
10998
11175
  const underBuild = join28(buildDir, value);
10999
- if (existsSync16(underBuild))
11176
+ if (existsSync17(underBuild))
11000
11177
  return underBuild;
11001
11178
  return join28(process.cwd(), value);
11002
11179
  }, fileSize = (diskPath) => {
@@ -11124,7 +11301,7 @@ ${colors.dim}${frameworkCount} ${frameworkCount === 1 ? "framework" : "framework
11124
11301
  }
11125
11302
  const sizesDir = resolveSizesDir(args, candidates);
11126
11303
  const manifestPath = join28(sizesDir, "manifest.json");
11127
- if (!existsSync16(manifestPath)) {
11304
+ if (!existsSync17(manifestPath)) {
11128
11305
  printDim(`No build at ${relativeOrSelf(manifestPath)}. Run \`absolute build\` first, or pass \`--outdir <dir>\`.`);
11129
11306
  return;
11130
11307
  }
@@ -11974,7 +12151,7 @@ var exports_heapDiff = {};
11974
12151
  __export(exports_heapDiff, {
11975
12152
  runHeapDiff: () => runHeapDiff
11976
12153
  });
11977
- import { existsSync as existsSync17, readFileSync as readFileSync20 } from "fs";
12154
+ import { existsSync as existsSync18, readFileSync as readFileSync20 } from "fs";
11978
12155
  var TOP = 15, STRING_TYPES, aggregate = (path) => {
11979
12156
  const data = JSON.parse(readFileSync20(path, "utf-8"));
11980
12157
  const { nodes, strings } = data;
@@ -12005,7 +12182,7 @@ var TOP = 15, STRING_TYPES, aggregate = (path) => {
12005
12182
  return;
12006
12183
  }
12007
12184
  for (const path of [beforePath, afterPath]) {
12008
- if (existsSync17(path))
12185
+ if (existsSync18(path))
12009
12186
  continue;
12010
12187
  process.stdout.write(`${colors.red}No such file: ${path}${colors.reset}
12011
12188
  `);
@@ -12126,7 +12303,7 @@ var isRecord9 = (value) => typeof value === "object" && value !== null && !Array
12126
12303
  // src/cli/config/schema/fromType.ts
12127
12304
  import ts6 from "typescript";
12128
12305
  import {
12129
- existsSync as existsSync18,
12306
+ existsSync as existsSync19,
12130
12307
  mkdirSync as mkdirSync9,
12131
12308
  readFileSync as readFileSync21,
12132
12309
  statSync as statSync2,
@@ -12321,7 +12498,7 @@ export { value };
12321
12498
  const cached = cache.get(cacheKey);
12322
12499
  if (cached)
12323
12500
  return cached;
12324
- const local = specifier === "@absolutejs/absolute" && isFrameworkRepo(cwd) && existsSync18(resolve25(cwd, "types/index.ts"));
12501
+ const local = specifier === "@absolutejs/absolute" && isFrameworkRepo(cwd) && existsSync19(resolve25(cwd, "types/index.ts"));
12325
12502
  const signature = cacheSignature(cwd, typeName, local, specifier);
12326
12503
  const fromDisk = readDiskCache(cwd, typeName, signature, specifier);
12327
12504
  if (fromDisk) {
@@ -12349,16 +12526,16 @@ var init_fromType = __esm(() => {
12349
12526
 
12350
12527
  // src/cli/config/absolute/resolveAbsoluteConfig.ts
12351
12528
  import ts7 from "typescript";
12352
- import { existsSync as existsSync19, readFileSync as readFileSync22 } from "fs";
12529
+ import { existsSync as existsSync20, readFileSync as readFileSync22 } from "fs";
12353
12530
  import { resolve as resolve26 } from "path";
12354
12531
  var CONFIG_CANDIDATES2, RUNTIME_FIELDS, findConfigPath = (cwd, override) => {
12355
12532
  if (override) {
12356
12533
  const resolved = resolve26(cwd, override);
12357
- return existsSync19(resolved) ? resolved : null;
12534
+ return existsSync20(resolved) ? resolved : null;
12358
12535
  }
12359
12536
  for (const name of CONFIG_CANDIDATES2) {
12360
12537
  const candidate = resolve26(cwd, name);
12361
- if (existsSync19(candidate))
12538
+ if (existsSync20(candidate))
12362
12539
  return candidate;
12363
12540
  }
12364
12541
  return null;
@@ -12682,7 +12859,7 @@ var emptyOutcome = () => ({
12682
12859
 
12683
12860
  // src/cli/generate/routeWiring.ts
12684
12861
  import ts8 from "typescript";
12685
- import { existsSync as existsSync20, readFileSync as readFileSync23, readdirSync as readdirSync4, writeFileSync as writeFileSync9 } from "fs";
12862
+ import { existsSync as existsSync21, readFileSync as readFileSync23, readdirSync as readdirSync4, writeFileSync as writeFileSync9 } from "fs";
12686
12863
  import { dirname as dirname18, join as join30 } from "path";
12687
12864
  var DEFAULT_SEPARATOR = `
12688
12865
  `, BOUNDARY_USE, applyEdits = (text2, edits) => {
@@ -12831,13 +13008,13 @@ ${newLines.join(`
12831
13008
  return lines.join(`
12832
13009
  `);
12833
13010
  }, hasChain = (path) => {
12834
- if (!existsSync20(path))
13011
+ if (!existsSync21(path))
12835
13012
  return false;
12836
13013
  const sourceFile = parse2(path, readFileSync23(path, "utf-8"));
12837
13014
  const found = findElysiaNew(sourceFile);
12838
13015
  return found !== null;
12839
13016
  }, firstChainFile = (pluginsDir) => {
12840
- if (!existsSync20(pluginsDir))
13017
+ if (!existsSync21(pluginsDir))
12841
13018
  return null;
12842
13019
  for (const name of readdirSync4(pluginsDir)) {
12843
13020
  if (!name.endsWith(".ts"))
@@ -12940,7 +13117,7 @@ var init_routeWiring = __esm(() => {
12940
13117
  });
12941
13118
 
12942
13119
  // src/cli/generate/generateApi.ts
12943
- import { existsSync as existsSync21, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
13120
+ import { existsSync as existsSync22, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
12944
13121
  import { dirname as dirname19, join as join31 } from "path";
12945
13122
  var apiPluginTemplate = (pluginName, base) => `import { Elysia } from 'elysia';
12946
13123
 
@@ -12955,7 +13132,7 @@ export const ${pluginName} = new Elysia()
12955
13132
  const outcome = { ...emptyOutcome(), route: base };
12956
13133
  const pluginsDir = join31(dirname19(project.serverEntry), "plugins");
12957
13134
  const fileAbs = join31(pluginsDir, `${pluginName}.ts`);
12958
- if (existsSync21(fileAbs)) {
13135
+ if (existsSync22(fileAbs)) {
12959
13136
  outcome.notes.push(`${pluginName} already exists at ${fileAbs} \u2014 skipped.`);
12960
13137
  return outcome;
12961
13138
  }
@@ -13028,7 +13205,7 @@ var init_componentTemplates = __esm(() => {
13028
13205
  });
13029
13206
 
13030
13207
  // src/cli/generate/generateComponent.ts
13031
- import { existsSync as existsSync22, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "fs";
13208
+ import { existsSync as existsSync23, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "fs";
13032
13209
  import { dirname as dirname20, join as join32 } from "path";
13033
13210
  var generateComponent = (project, framework, rawName) => {
13034
13211
  const def = frameworks6[framework];
@@ -13041,7 +13218,7 @@ var generateComponent = (project, framework, rawName) => {
13041
13218
  return outcome;
13042
13219
  }
13043
13220
  const fileAbs = join32(frameworkDir, "components", def.componentFile({ kebab, pascal }));
13044
- if (existsSync22(fileAbs)) {
13221
+ if (existsSync23(fileAbs)) {
13045
13222
  outcome.notes.push(`${pascal} already exists at ${fileAbs} \u2014 skipped.`);
13046
13223
  return outcome;
13047
13224
  }
@@ -13061,7 +13238,7 @@ var init_generateComponent = __esm(() => {
13061
13238
 
13062
13239
  // src/cli/generate/cssStrategy.ts
13063
13240
  import ts9 from "typescript";
13064
- import { existsSync as existsSync23 } from "fs";
13241
+ import { existsSync as existsSync24 } from "fs";
13065
13242
  import { join as join33 } from "path";
13066
13243
  var CSS_SUFFIX = "CSS", SHARED_MIN_USES = 2, DEFAULT_CSS = `main {
13067
13244
  margin: 0 auto;
@@ -13109,7 +13286,7 @@ var CSS_SUFFIX = "CSS", SHARED_MIN_USES = 2, DEFAULT_CSS = `main {
13109
13286
  return {
13110
13287
  assetKey: sharedKey,
13111
13288
  contents: DEFAULT_CSS,
13112
- create: !existsSync23(cssFileAbs2),
13289
+ create: !existsSync24(cssFileAbs2),
13113
13290
  cssFileAbs: cssFileAbs2,
13114
13291
  shared: true
13115
13292
  };
@@ -13118,7 +13295,7 @@ var CSS_SUFFIX = "CSS", SHARED_MIN_USES = 2, DEFAULT_CSS = `main {
13118
13295
  return {
13119
13296
  assetKey: `${pascal}${CSS_SUFFIX}`,
13120
13297
  contents: DEFAULT_CSS,
13121
- create: !existsSync23(cssFileAbs),
13298
+ create: !existsSync24(cssFileAbs),
13122
13299
  cssFileAbs,
13123
13300
  shared: false
13124
13301
  };
@@ -13127,7 +13304,7 @@ var init_cssStrategy = () => {};
13127
13304
 
13128
13305
  // src/cli/generate/navData.ts
13129
13306
  import ts10 from "typescript";
13130
- import { existsSync as existsSync24, mkdirSync as mkdirSync12, readFileSync as readFileSync24, writeFileSync as writeFileSync12 } from "fs";
13307
+ import { existsSync as existsSync25, mkdirSync as mkdirSync12, readFileSync as readFileSync24, writeFileSync as writeFileSync12 } from "fs";
13131
13308
  import { dirname as dirname21 } from "path";
13132
13309
  var NAV_DATA_TEMPLATE = `type NavItem = {
13133
13310
  href: string;
@@ -13166,7 +13343,7 @@ export const navData: NavItem[] = [];
13166
13343
  }
13167
13344
  return items;
13168
13345
  }, readNavItems = (navDataPath) => {
13169
- if (!existsSync24(navDataPath))
13346
+ if (!existsSync25(navDataPath))
13170
13347
  return [];
13171
13348
  const text2 = readFileSync24(navDataPath, "utf-8");
13172
13349
  const sourceFile = ts10.createSourceFile(navDataPath, text2, ts10.ScriptTarget.Latest, true);
@@ -13203,7 +13380,7 @@ ${indentOf(text2, array.getStart(sourceFile))}`;
13203
13380
  ${indent}${entry}`;
13204
13381
  return text2.slice(0, insertAt) + insertion + text2.slice(insertAt);
13205
13382
  }, upsertNavItem = (navDataPath, item) => {
13206
- const created = !existsSync24(navDataPath);
13383
+ const created = !existsSync25(navDataPath);
13207
13384
  if (created) {
13208
13385
  mkdirSync12(dirname21(navDataPath), { recursive: true });
13209
13386
  writeFileSync12(navDataPath, NAV_DATA_TEMPLATE, "utf-8");
@@ -13369,7 +13546,7 @@ var init_pageTemplates = __esm(() => {
13369
13546
 
13370
13547
  // src/cli/generate/generatePage.ts
13371
13548
  import {
13372
- existsSync as existsSync25,
13549
+ existsSync as existsSync26,
13373
13550
  mkdirSync as mkdirSync13,
13374
13551
  readFileSync as readFileSync25,
13375
13552
  readdirSync as readdirSync5,
@@ -13382,7 +13559,7 @@ var writeNew = (path, contents) => {
13382
13559
  }, toHref = (fromDir, toFile) => {
13383
13560
  const rel = relative17(fromDir, toFile).split("\\").join("/");
13384
13561
  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) => {
13562
+ }, 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
13563
  const html = readFileSync25(file, "utf-8");
13387
13564
  const synced = syncStaticNav(html, items);
13388
13565
  if (synced === null || synced === html)
@@ -13411,7 +13588,7 @@ var writeNew = (path, contents) => {
13411
13588
  return outcome;
13412
13589
  }
13413
13590
  const pageFileAbs = join34(frameworkDir, "pages", def.pageFile({ kebab, pascal }));
13414
- if (existsSync25(pageFileAbs)) {
13591
+ if (existsSync26(pageFileAbs)) {
13415
13592
  outcome.notes.push(`${pascal} already exists at ${pageFileAbs} \u2014 skipped.`);
13416
13593
  return outcome;
13417
13594
  }
@@ -13797,11 +13974,11 @@ var init_catalog = __esm(() => {
13797
13974
  });
13798
13975
 
13799
13976
  // src/cli/integrations/addPlugin.ts
13800
- import { existsSync as existsSync26, readFileSync as readFileSync27 } from "fs";
13977
+ import { existsSync as existsSync27, readFileSync as readFileSync27 } from "fs";
13801
13978
  import { join as join35 } from "path";
13802
13979
  var isRecord11 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), readPackageJson = (cwd) => {
13803
13980
  const path = join35(cwd, "package.json");
13804
- if (!existsSync26(path))
13981
+ if (!existsSync27(path))
13805
13982
  return null;
13806
13983
  try {
13807
13984
  const parsed = JSON.parse(readFileSync27(path, "utf-8"));
@@ -14296,16 +14473,16 @@ var init_authCatalog = __esm(() => {
14296
14473
 
14297
14474
  // src/cli/config/auth/resolveAuthSettings.ts
14298
14475
  import ts12 from "typescript";
14299
- import { existsSync as existsSync27, readFileSync as readFileSync28 } from "fs";
14476
+ import { existsSync as existsSync28, readFileSync as readFileSync28 } from "fs";
14300
14477
  import { resolve as resolve28 } from "path";
14301
14478
  var AUTH_PACKAGE = "@absolutejs/auth", CONFIG_CANDIDATES3, findAuthSettingsPath = (cwd, override) => {
14302
14479
  if (override) {
14303
14480
  const resolved = resolve28(cwd, override);
14304
- return existsSync27(resolved) ? resolved : null;
14481
+ return existsSync28(resolved) ? resolved : null;
14305
14482
  }
14306
14483
  for (const name of CONFIG_CANDIDATES3) {
14307
14484
  const candidate = resolve28(cwd, name);
14308
- if (existsSync27(candidate))
14485
+ if (existsSync28(candidate))
14309
14486
  return candidate;
14310
14487
  }
14311
14488
  return null;
@@ -14401,10 +14578,10 @@ var init_resolveAuthSettings = __esm(() => {
14401
14578
 
14402
14579
  // src/cli/config/auth/resolveAuthState.ts
14403
14580
  import ts13 from "typescript";
14404
- import { existsSync as existsSync28, readdirSync as readdirSync6, readFileSync as readFileSync29 } from "fs";
14581
+ import { existsSync as existsSync29, readdirSync as readdirSync6, readFileSync as readFileSync29 } from "fs";
14405
14582
  import { join as join36, relative as relative19, resolve as resolve29 } from "path";
14406
14583
  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))
14584
+ if (!existsSync29(path))
14408
14585
  return null;
14409
14586
  try {
14410
14587
  const parsed = JSON.parse(readFileSync29(path, "utf-8"));
@@ -14533,7 +14710,7 @@ var AUTH_PACKAGE2 = "@absolutejs/auth", REPO_URL = "https://github.com/absolutej
14533
14710
  scaffoldable: isScaffoldableFeature(feature.id)
14534
14711
  })), resolveAuthState = (cwd) => {
14535
14712
  const installedVersion = installedVersionFor(cwd);
14536
- const root = existsSync28(join36(cwd, "src")) ? join36(cwd, "src") : cwd;
14713
+ const root = existsSync29(join36(cwd, "src")) ? join36(cwd, "src") : cwd;
14537
14714
  let match = null;
14538
14715
  let setupPath = null;
14539
14716
  for (const file of candidateFiles(root)) {
@@ -14578,7 +14755,7 @@ var init_resolveAuthState = __esm(() => {
14578
14755
  });
14579
14756
 
14580
14757
  // src/cli/config/auth/scaffoldAuthFeature.ts
14581
- import { existsSync as existsSync29, writeFileSync as writeFileSync15 } from "fs";
14758
+ import { existsSync as existsSync30, writeFileSync as writeFileSync15 } from "fs";
14582
14759
  import { dirname as dirname23, join as join37, relative as relative20, resolve as resolve30 } from "path";
14583
14760
  var renderScaffold = (scaffold) => {
14584
14761
  const importNames = [...scaffold.imports, `type ${scaffold.typeName}`];
@@ -14606,7 +14783,7 @@ ${body}
14606
14783
  if (setupPath)
14607
14784
  return dirname23(resolve30(cwd, setupPath));
14608
14785
  const src = join37(cwd, "src");
14609
- return existsSync29(src) ? src : cwd;
14786
+ return existsSync30(src) ? src : cwd;
14610
14787
  }, spreadFor = (scaffold) => `import { ${scaffold.exportName} } from './${scaffold.exportName}';
14611
14788
  // add to your auth() call:
14612
14789
  ${scaffold.configKey}: ${scaffold.exportName}`, failure2 = (message) => ({
@@ -14621,7 +14798,7 @@ ${scaffold.configKey}: ${scaffold.exportName}`, failure2 = (message) => ({
14621
14798
  return failure2(`Unknown auth feature "${id}".`);
14622
14799
  const filePath = join37(targetDir(cwd), `${scaffold.exportName}.ts`);
14623
14800
  const relPath = relative20(cwd, filePath);
14624
- if (existsSync29(filePath)) {
14801
+ if (existsSync30(filePath)) {
14625
14802
  return {
14626
14803
  created: null,
14627
14804
  installed: false,
@@ -14648,13 +14825,13 @@ var init_scaffoldAuthFeature = __esm(() => {
14648
14825
  });
14649
14826
 
14650
14827
  // src/cli/htmx/install.ts
14651
- import { existsSync as existsSync30, mkdirSync as mkdirSync14, readFileSync as readFileSync30, writeFileSync as writeFileSync16 } from "fs";
14828
+ import { existsSync as existsSync31, mkdirSync as mkdirSync14, readFileSync as readFileSync30, writeFileSync as writeFileSync16 } from "fs";
14652
14829
  import { join as join38 } from "path";
14653
14830
  var VENDORED_HTMX_VERSION = "2.0.6", vendoredHtmxFile = () => [
14654
14831
  join38(import.meta.dir, "htmx.min.js"),
14655
14832
  join38(import.meta.dir, "htmx", "htmx.min.js"),
14656
14833
  join38(import.meta.dir, "..", "htmx", "htmx.min.js")
14657
- ].find((path) => existsSync30(path)) ?? null, detectHtmxVersion = (content) => {
14834
+ ].find((path) => existsSync31(path)) ?? null, detectHtmxVersion = (content) => {
14658
14835
  const match = content.match(/version:"([0-9.]+)"/);
14659
14836
  return match ? match[1] : null;
14660
14837
  }, fetchHtmx = async (version2) => {
@@ -14666,7 +14843,7 @@ var VENDORED_HTMX_VERSION = "2.0.6", vendoredHtmxFile = () => [
14666
14843
  return response.text();
14667
14844
  }, installedHtmxVersion = (htmxDir) => {
14668
14845
  const file = join38(htmxDir, "htmx.min.js");
14669
- if (!existsSync30(file))
14846
+ if (!existsSync31(file))
14670
14847
  return null;
14671
14848
  return detectHtmxVersion(readFileSync30(file, "utf-8"));
14672
14849
  }, readVendoredHtmx = () => {
@@ -14834,7 +15011,7 @@ var exports_analyze = {};
14834
15011
  __export(exports_analyze, {
14835
15012
  runAnalyze: () => runAnalyze
14836
15013
  });
14837
- import { existsSync as existsSync31, readFileSync as readFileSync31, statSync as statSync3, writeFileSync as writeFileSync17 } from "fs";
15014
+ import { existsSync as existsSync32, readFileSync as readFileSync31, statSync as statSync3, writeFileSync as writeFileSync17 } from "fs";
14838
15015
  import { join as join40, resolve as resolve31 } from "path";
14839
15016
  var BASELINE_FILE = ".absolute-size-baseline.json", TOP_CHANGES = 12, CATEGORY_WIDTH = 16, SIZE_WIDTH = 12, CHANGE_WIDTH = 10, CATEGORY_ORDER, categoryOf = (key) => {
14840
15017
  if (key.startsWith("Island"))
@@ -14856,7 +15033,7 @@ var BASELINE_FILE = ".absolute-size-baseline.json", TOP_CHANGES = 12, CATEGORY_W
14856
15033
  }
14857
15034
  }, readSizes = (manifestDir) => {
14858
15035
  const manifestPath = join40(manifestDir, "manifest.json");
14859
- if (!existsSync31(manifestPath))
15036
+ if (!existsSync32(manifestPath))
14860
15037
  return null;
14861
15038
  const manifest = JSON.parse(readFileSync31(manifestPath, "utf-8"));
14862
15039
  const sizes = {};
@@ -14866,7 +15043,7 @@ var BASELINE_FILE = ".absolute-size-baseline.json", TOP_CHANGES = 12, CATEGORY_W
14866
15043
  return sizes;
14867
15044
  }, readBaseline = (cwd) => {
14868
15045
  const path = join40(cwd, BASELINE_FILE);
14869
- if (!existsSync31(path))
15046
+ if (!existsSync32(path))
14870
15047
  return null;
14871
15048
  try {
14872
15049
  const parsed = JSON.parse(readFileSync31(path, "utf-8"));
@@ -15200,7 +15377,7 @@ var exports_remove = {};
15200
15377
  __export(exports_remove, {
15201
15378
  runRemove: () => runRemove
15202
15379
  });
15203
- import { existsSync as existsSync32, readFileSync as readFileSync32 } from "fs";
15380
+ import { existsSync as existsSync33, readFileSync as readFileSync32 } from "fs";
15204
15381
  import { relative as relative22 } from "path";
15205
15382
  var write3 = (text2) => process.stdout.write(`${text2}
15206
15383
  `), fail3 = (message) => {
@@ -15211,7 +15388,7 @@ var write3 = (text2) => process.stdout.write(`${text2}
15211
15388
  const candidates = [findRoutingFile(serverEntry), serverEntry];
15212
15389
  const seen = new Set;
15213
15390
  return candidates.filter((file) => {
15214
- if (file === null || seen.has(file) || !existsSync32(file))
15391
+ if (file === null || seen.has(file) || !existsSync33(file))
15215
15392
  return false;
15216
15393
  seen.add(file);
15217
15394
  return readFileSync32(file, "utf-8").includes(handler);
@@ -15341,10 +15518,10 @@ __export(exports_env, {
15341
15518
  runEnv: () => runEnv,
15342
15519
  scanEnvUsage: () => scanEnvUsage
15343
15520
  });
15344
- import { existsSync as existsSync33, readFileSync as readFileSync33 } from "fs";
15521
+ import { existsSync as existsSync34, readFileSync as readFileSync33 } from "fs";
15345
15522
  import { join as join41 } from "path";
15346
15523
  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 () => {
15524
+ 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
15525
  const scans = scanPatterns().map((pattern) => Array.fromAsync(new Glob3(pattern).scan({ cwd: process.cwd() })));
15349
15526
  const files = (await Promise.all(scans)).flat();
15350
15527
  const usage = new Map;
@@ -15410,7 +15587,7 @@ __export(exports_db, {
15410
15587
  quoteIdent: () => quoteIdent,
15411
15588
  runDb: () => runDb
15412
15589
  });
15413
- import { existsSync as existsSync34, mkdirSync as mkdirSync15, readFileSync as readFileSync34, writeFileSync as writeFileSync18 } from "fs";
15590
+ import { existsSync as existsSync35, mkdirSync as mkdirSync15, readFileSync as readFileSync34, writeFileSync as writeFileSync18 } from "fs";
15414
15591
  import { join as join42 } from "path";
15415
15592
  var {env: env4, spawn: spawn3, SQL } = globalThis.Bun;
15416
15593
  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 +15708,7 @@ var BACKUP_FORMAT_VERSION = 1, RESTORE_CHUNK_ROWS = 500, URL_ENV_KEYS, JSON_DATA
15531
15708
  console.log(paint(`\u2713 backup \u2192 ${file}`, colors.green));
15532
15709
  console.log(paint(` ${chosen.length} tables, ${total} rows`, colors.dim));
15533
15710
  }, runRestore = async (file, options) => {
15534
- if (!existsSync34(file))
15711
+ if (!existsSync35(file))
15535
15712
  throw new Error(`Backup not found: ${file}`);
15536
15713
  const payload = JSON.parse(readFileSync34(file, "utf-8"));
15537
15714
  const names = Object.keys(payload.tables).filter((name) => keepTable(name, options));
@@ -15555,7 +15732,7 @@ var BACKUP_FORMAT_VERSION = 1, RESTORE_CHUNK_ROWS = 500, URL_ENV_KEYS, JSON_DATA
15555
15732
  const total = order.reduce((sum, name) => sum + (payload.tables[name]?.length ?? 0), 0);
15556
15733
  console.log(paint(`\u2713 restored ${order.length} tables, ${total} rows (idempotent upsert by primary key)`, colors.green));
15557
15734
  }, runSeed = async (entry) => {
15558
- const target = entry ?? SEED_CANDIDATES.find((candidate) => existsSync34(join42(process.cwd(), candidate)));
15735
+ const target = entry ?? SEED_CANDIDATES.find((candidate) => existsSync35(join42(process.cwd(), candidate)));
15559
15736
  if (target === undefined)
15560
15737
  throw new Error(`No seed script found (looked for ${SEED_CANDIDATES.join(", ")}). Pass a path: absolute db seed <file>.`);
15561
15738
  console.log(paint(`seeding via ${target}\u2026`, colors.cyan));
@@ -15616,7 +15793,7 @@ __export(exports_logs, {
15616
15793
  });
15617
15794
  import {
15618
15795
  closeSync as closeSync2,
15619
- existsSync as existsSync35,
15796
+ existsSync as existsSync36,
15620
15797
  openSync as openSync4,
15621
15798
  readSync as readSync2,
15622
15799
  statSync as statSync4,
@@ -15683,7 +15860,7 @@ var DEFAULT_LINES = 40, POLL_MS = 250, LINES_FLAG_SPAN = 2, readFrom = (path, st
15683
15860
  printAvailable(instances);
15684
15861
  return;
15685
15862
  }
15686
- if (match.logFile === null || !existsSync35(match.logFile)) {
15863
+ if (match.logFile === null || !existsSync36(match.logFile)) {
15687
15864
  printDim3(`"${name}" has no captured log (untracked, or started outside the CLI).`);
15688
15865
  return;
15689
15866
  }
@@ -15703,7 +15880,7 @@ var init_logs = __esm(() => {
15703
15880
 
15704
15881
  // src/cli/typeGraphCoherence.ts
15705
15882
  import {
15706
- existsSync as existsSync36,
15883
+ existsSync as existsSync37,
15707
15884
  readFileSync as readFileSync35,
15708
15885
  realpathSync as realpathSync2,
15709
15886
  rmSync as rmSync6,
@@ -15754,7 +15931,7 @@ var DEPENDENCY_FIELDS, TYPE_GRAPH_PACKAGES, readManifest = (path) => {
15754
15931
  }, findInstallRoot = (cwd) => {
15755
15932
  let directory = resolve32(cwd);
15756
15933
  for (;; ) {
15757
- if (existsSync36(join43(directory, "bun.lock")) || existsSync36(join43(directory, "bun.lockb"))) {
15934
+ if (existsSync37(join43(directory, "bun.lock")) || existsSync37(join43(directory, "bun.lockb"))) {
15758
15935
  return directory;
15759
15936
  }
15760
15937
  const parent = dirname25(directory);
@@ -15766,7 +15943,7 @@ var DEPENDENCY_FIELDS, TYPE_GRAPH_PACKAGES, readManifest = (path) => {
15766
15943
  let directory = resolve32(cwd);
15767
15944
  for (;; ) {
15768
15945
  const candidate = join43(directory, "package.json");
15769
- if (existsSync36(candidate))
15946
+ if (existsSync37(candidate))
15770
15947
  return candidate;
15771
15948
  if (directory === installRoot)
15772
15949
  return join43(installRoot, "package.json");
@@ -15907,7 +16084,7 @@ var exports_doctor = {};
15907
16084
  __export(exports_doctor, {
15908
16085
  runDoctor: () => runDoctor
15909
16086
  });
15910
- import { existsSync as existsSync37, mkdirSync as mkdirSync16, readFileSync as readFileSync36, writeFileSync as writeFileSync20 } from "fs";
16087
+ import { existsSync as existsSync38, mkdirSync as mkdirSync16, readFileSync as readFileSync36, writeFileSync as writeFileSync20 } from "fs";
15911
16088
  import { createRequire as createRequire2 } from "module";
15912
16089
  import { arch as arch4, platform as platform5 } from "os";
15913
16090
  import { join as join44 } from "path";
@@ -15945,7 +16122,7 @@ var FRAMEWORK_FIELDS2, projectRequire, check = (status2, label, detail) => ({
15945
16122
  return [];
15946
16123
  const label = `${field.replace("Directory", "")} pages`;
15947
16124
  return [
15948
- existsSync37(join44(process.cwd(), dir)) ? check("ok", label, dir) : check("fail", label, `${dir} (missing)`)
16125
+ existsSync38(join44(process.cwd(), dir)) ? check("ok", label, dir) : check("fail", label, `${dir} (missing)`)
15949
16126
  ];
15950
16127
  }), envCheck = async () => {
15951
16128
  const vars = await collectEnvVars();
@@ -16007,7 +16184,7 @@ ${colors.dim}${checks.length} checks \xB7 ${colors.reset}${summary}${colors.dim}
16007
16184
  const fixes = [];
16008
16185
  for (const field of FRAMEWORK_FIELDS2) {
16009
16186
  const dir = readString2(config, field);
16010
- if (dir === undefined || existsSync37(join44(cwd, dir)))
16187
+ if (dir === undefined || existsSync38(join44(cwd, dir)))
16011
16188
  continue;
16012
16189
  mkdirSync16(join44(cwd, dir, "pages"), { recursive: true });
16013
16190
  fixes.push(`created ${dir}/pages`);
@@ -16018,7 +16195,7 @@ ${colors.dim}${checks.length} checks \xB7 ${colors.reset}${summary}${colors.dim}
16018
16195
  if (missing.length === 0)
16019
16196
  return null;
16020
16197
  const envExample = join44(cwd, ".env.example");
16021
- const existing = existsSync37(envExample) ? readFileSync36(envExample, "utf-8") : "";
16198
+ const existing = existsSync38(envExample) ? readFileSync36(envExample, "utf-8") : "";
16022
16199
  const existingKeys = new Set(existing.split(`
16023
16200
  `).map((line) => line.split("=")[0]?.trim()));
16024
16201
  const toAdd = missing.filter((entry) => !existingKeys.has(entry.key));
@@ -16392,10 +16569,10 @@ var init_inspect = __esm(() => {
16392
16569
  });
16393
16570
 
16394
16571
  // src/build/scanEntryPoints.ts
16395
- import { existsSync as existsSync38 } from "fs";
16572
+ import { existsSync as existsSync39 } from "fs";
16396
16573
  var {Glob: Glob4 } = globalThis.Bun;
16397
16574
  var scanEntryPoints = async (dir, pattern) => {
16398
- if (!existsSync38(dir))
16575
+ if (!existsSync39(dir))
16399
16576
  return [];
16400
16577
  const entryPaths = [];
16401
16578
  const glob = new Glob4(pattern);
@@ -16547,7 +16724,7 @@ var exports_islands = {};
16547
16724
  __export(exports_islands, {
16548
16725
  runIslands: () => runIslands
16549
16726
  });
16550
- import { existsSync as existsSync39, readFileSync as readFileSync38, statSync as statSync5 } from "fs";
16727
+ import { existsSync as existsSync40, readFileSync as readFileSync38, statSync as statSync5 } from "fs";
16551
16728
  import { join as join45, relative as relative23, resolve as resolve34 } from "path";
16552
16729
  var FRAMEWORK_DIR_KEY, FRAMEWORK_COLOR, printDim6 = (message) => process.stdout.write(`${colors.dim}${message}${colors.reset}
16553
16730
  `), hostFrameworkOf = (pagePath, cwd, config) => {
@@ -16567,7 +16744,7 @@ var FRAMEWORK_DIR_KEY, FRAMEWORK_COLOR, printDim6 = (message) => process.stdout.
16567
16744
  }
16568
16745
  }, readManifestSizes2 = (manifestDir) => {
16569
16746
  const manifestPath = join45(manifestDir, "manifest.json");
16570
- if (!existsSync39(manifestPath))
16747
+ if (!existsSync40(manifestPath))
16571
16748
  return null;
16572
16749
  const manifest = JSON.parse(readFileSync38(manifestPath, "utf-8"));
16573
16750
  const sizes = new Map;
@@ -16707,7 +16884,7 @@ var init_islands2 = __esm(() => {
16707
16884
  });
16708
16885
 
16709
16886
  // src/build/externalAssetPlugin.ts
16710
- import { copyFileSync as copyFileSync2, existsSync as existsSync40, mkdirSync as mkdirSync17, statSync as statSync6 } from "fs";
16887
+ import { copyFileSync as copyFileSync2, existsSync as existsSync41, mkdirSync as mkdirSync17, statSync as statSync6 } from "fs";
16711
16888
  import { basename as basename12, dirname as dirname27, join as join46, resolve as resolve35 } from "path";
16712
16889
  var createExternalAssetPlugin = (outDir, userSourceRoots = []) => ({
16713
16890
  name: "absolute-external-asset",
@@ -16729,12 +16906,12 @@ var createExternalAssetPlugin = (outDir, userSourceRoots = []) => ({
16729
16906
  if (!relPath)
16730
16907
  continue;
16731
16908
  const assetPath = resolve35(sourceDir, relPath);
16732
- if (!existsSync40(assetPath))
16909
+ if (!existsSync41(assetPath))
16733
16910
  continue;
16734
16911
  if (!statSync6(assetPath).isFile())
16735
16912
  continue;
16736
16913
  const targetPath = join46(outDir, basename12(assetPath));
16737
- if (existsSync40(targetPath))
16914
+ if (existsSync41(targetPath))
16738
16915
  continue;
16739
16916
  mkdirSync17(dirname27(targetPath), { recursive: true });
16740
16917
  copyFileSync2(assetPath, targetPath);
@@ -16754,7 +16931,7 @@ __export(exports_compile, {
16754
16931
  var {env: env5 } = globalThis.Bun;
16755
16932
  import {
16756
16933
  cpSync,
16757
- existsSync as existsSync41,
16934
+ existsSync as existsSync42,
16758
16935
  mkdirSync as mkdirSync18,
16759
16936
  readdirSync as readdirSync7,
16760
16937
  readFileSync as readFileSync39,
@@ -16845,7 +17022,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
16845
17022
  const normalizedOutdir = resolve36(outdir);
16846
17023
  const copyReference = (filePath, relPath) => {
16847
17024
  const assetSource = resolve36(dirname28(filePath), relPath);
16848
- if (!existsSync41(assetSource) || !statSync7(assetSource).isFile())
17025
+ if (!existsSync42(assetSource) || !statSync7(assetSource).isFile())
16849
17026
  return;
16850
17027
  const assetTarget = resolve36(normalizedOutdir, relPath.replace(/^\.\//, ""));
16851
17028
  if (assetTarget !== normalizedOutdir && !assetTarget.startsWith(`${normalizedOutdir}/`))
@@ -16929,7 +17106,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
16929
17106
  resolve36(import.meta.dir, "..", "..", "..", "src", "react", "jsxDevRuntimeCompat.ts")
16930
17107
  ];
16931
17108
  for (const candidate of candidates) {
16932
- if (existsSync41(candidate))
17109
+ if (existsSync42(candidate))
16933
17110
  return candidate;
16934
17111
  }
16935
17112
  return resolve36(import.meta.dir, "..", "..", "react", "jsxDevRuntimeCompat.js");
@@ -17004,7 +17181,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
17004
17181
  if (!buildConfig.angularDirectory)
17005
17182
  return;
17006
17183
  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}`) : [];
17184
+ const angularPackages = existsSync42(angularScopeDir) ? readdirSync7(angularScopeDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => entry.name !== "compiler-cli").map((entry) => `@angular/${entry.name}`) : [];
17008
17185
  const roots = new Set([...angularPackages, "rxjs", "tslib", "typescript"]);
17009
17186
  const seen = new Set;
17010
17187
  for (const specifier of roots) {
@@ -17023,7 +17200,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
17023
17200
  copyChunkReferencedPackages(outdir, seen);
17024
17201
  }, collectRuntimePackageSpecifiers = (distDir) => {
17025
17202
  const nodeModulesDir = join47(distDir, "node_modules");
17026
- if (!existsSync41(nodeModulesDir))
17203
+ if (!existsSync42(nodeModulesDir))
17027
17204
  return [];
17028
17205
  const specifiers = [];
17029
17206
  for (const entry of readdirSync7(nodeModulesDir, { withFileTypes: true })) {
@@ -17064,9 +17241,9 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
17064
17241
  const packageDir = join47(distDir, "node_modules", ...packageSpecifier.split("/"));
17065
17242
  const subpath = specifier.slice(packageSpecifier.length);
17066
17243
  const subPackageDir = subpath ? join47(packageDir, ...subpath.slice(1).split("/")) : null;
17067
- const resolvedPackageDir = subPackageDir && existsSync41(join47(subPackageDir, "package.json")) ? subPackageDir : packageDir;
17244
+ const resolvedPackageDir = subPackageDir && existsSync42(join47(subPackageDir, "package.json")) ? subPackageDir : packageDir;
17068
17245
  const packageJsonPath = join47(resolvedPackageDir, "package.json");
17069
- if (!existsSync41(packageJsonPath))
17246
+ if (!existsSync42(packageJsonPath))
17070
17247
  return null;
17071
17248
  const pkg = JSON.parse(readFileSync39(packageJsonPath, "utf-8"));
17072
17249
  const exportKey = resolvedPackageDir !== subPackageDir && subpath ? `.${subpath}` : ".";
@@ -17091,7 +17268,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
17091
17268
  }, findContainingRuntimePackageDir = (filePath) => {
17092
17269
  let dir = dirname28(filePath);
17093
17270
  while (dir !== dirname28(dir)) {
17094
- if (isNodeModulesPath(dir) && existsSync41(join47(dir, "package.json"))) {
17271
+ if (isNodeModulesPath(dir) && existsSync42(join47(dir, "package.json"))) {
17095
17272
  return dir;
17096
17273
  }
17097
17274
  dir = dirname28(dir);
@@ -17771,11 +17948,11 @@ export default server;
17771
17948
  process.exit(1);
17772
17949
  }
17773
17950
  const outputPath = resolve36(resolvedOutdir, `${entryName}.js`);
17774
- if (!existsSync41(outputPath)) {
17951
+ if (!existsSync42(outputPath)) {
17775
17952
  console.error(cliTag4("\x1B[31m", `Expected output not found: ${outputPath}`));
17776
17953
  process.exit(1);
17777
17954
  }
17778
- if (existsSync41(resolve36(resolvedOutdir, "angular", "vendor", "server"))) {
17955
+ if (existsSync42(resolve36(resolvedOutdir, "angular", "vendor", "server"))) {
17779
17956
  const vendorDir = resolve36(resolvedOutdir, "angular", "vendor", "server");
17780
17957
  const vendorEntries = readdirSync7(vendorDir).filter((fileName) => fileName.endsWith(".js"));
17781
17958
  const angularServerVendorPaths = {};
@@ -20633,7 +20810,7 @@ var init_mobileInspect = __esm(() => {
20633
20810
  });
20634
20811
 
20635
20812
  // src/mobile/ciWorkflow.ts
20636
- import { existsSync as existsSync42 } from "fs";
20813
+ import { existsSync as existsSync43 } from "fs";
20637
20814
  import { access as access15, mkdir as mkdir15, readFile as readFile23, writeFile as writeFile17 } from "fs/promises";
20638
20815
  import { dirname as dirname32, extname as extname9, relative as relative30, resolve as resolve43, sep as sep8 } from "path";
20639
20816
  var ABSOLUTE_MOBILE_CI_WORKFLOW_FORMAT = 1, SECRET_NAME_PATTERN, CI_ENV_INDENTATION = 6, RESERVED_SECRET_NAMES, exists4 = async (path) => {
@@ -20652,7 +20829,7 @@ var ABSOLUTE_MOBILE_CI_WORKFLOW_FORMAT = 1, SECRET_NAME_PATTERN, CI_ENV_INDENTAT
20652
20829
  }
20653
20830
  if (/\r|\n/u.test(portable) || portable.startsWith("-"))
20654
20831
  throw new TypeError(`${field} contains an unsafe path.`);
20655
- if (!options.allowMissing && !existsSync42(path))
20832
+ if (!options.allowMissing && !existsSync43(path))
20656
20833
  throw new TypeError(`${field} does not exist inside the project.`);
20657
20834
  return portable;
20658
20835
  }, workflowOutputPath = (projectRoot, value) => {
@@ -21213,7 +21390,26 @@ var NOT_FOUND4 = -1, isRecord15 = (value) => typeof value === "object" && value
21213
21390
  throw new TypeError(`Expo exited with status ${exitCode}.`);
21214
21391
  }, ensureExpoPackages = async (project, args) => {
21215
21392
  try {
21216
- await access16(join56(project, "node_modules", "expo", "package.json"));
21393
+ const manifest = JSON.parse(await readFile24(join56(project, "package.json"), "utf8"));
21394
+ const dependencies = typeof manifest === "object" && manifest !== null ? Reflect.get(manifest, "dependencies") : undefined;
21395
+ if (typeof dependencies !== "object" || dependencies === null || Array.isArray(dependencies))
21396
+ throw new TypeError("Generated Expo dependencies are invalid.");
21397
+ await Promise.all(Object.entries(dependencies).map(async ([name, expected]) => {
21398
+ if (typeof expected !== "string")
21399
+ throw new TypeError("Generated Expo dependency version is invalid.");
21400
+ const installed = JSON.parse(await readFile24(join56(project, "node_modules", name, "package.json"), "utf8"));
21401
+ const actual = typeof installed === "object" && installed !== null ? Reflect.get(installed, "version") : undefined;
21402
+ if (typeof actual !== "string")
21403
+ throw new TypeError("Installed Expo dependency version is invalid.");
21404
+ if (/^\d+\.\d+\.\d+$/u.test(expected) && actual !== expected)
21405
+ throw new TypeError("Installed Expo dependency is outdated.");
21406
+ if (expected.startsWith("~")) {
21407
+ const wanted = expected.slice(1).split(".").map(Number);
21408
+ const found = actual.split(".").map(Number);
21409
+ if (found[0] !== wanted[0] || found[1] !== wanted[1] || (found[2] ?? -1) < (wanted[2] ?? 0))
21410
+ throw new TypeError("Installed Expo dependency is outdated.");
21411
+ }
21412
+ }));
21217
21413
  return;
21218
21414
  } catch {}
21219
21415
  const approved = args.includes("--yes") || await confirmInstall("The experimental Expo shell dependencies are missing. Install the pinned Expo SDK 57 toolchain now?");
@@ -22779,10 +22975,10 @@ __export(exports_typecheck, {
22779
22975
  typecheck: () => typecheck
22780
22976
  });
22781
22977
  import { resolve as resolve45, join as join57 } from "path";
22782
- import { existsSync as existsSync43, readFileSync as readFileSync40 } from "fs";
22978
+ import { existsSync as existsSync44, readFileSync as readFileSync40 } from "fs";
22783
22979
  import { mkdir as mkdir17, writeFile as writeFile19 } from "fs/promises";
22784
22980
  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))) {
22981
+ if (!existsSync44(resolveConfigPath(configPath2))) {
22786
22982
  const defaultService = {};
22787
22983
  return [defaultService];
22788
22984
  }
@@ -22804,7 +23000,7 @@ var isCommandService3 = (service) => service.kind === "command" || Array.isArray
22804
23000
  return { exitCode, name, output: (stdout + stderr).trim() };
22805
23001
  }, shellEscape = (value) => `'${value.replaceAll("'", "'\\''")}'`, runShell = async (name, command) => run(name, ["/bin/bash", "-lc", command]), findBin = (name) => {
22806
23002
  const local = resolve45("node_modules", ".bin", name);
22807
- return existsSync43(local) ? local : null;
23003
+ return existsSync44(local) ? local : null;
22808
23004
  }, ANSI_COLOR_REGEX, ANSI_PURPLE_REGEX, ANSI_CYAN_REGEX, ANSI_TOKEN_END_REGEX, stripAnsi4 = (str) => str.replace(ANSI_COLOR_REGEX, ""), formatSvelteOutput = (output) => {
22809
23005
  const cwd = `${process.cwd()}/`;
22810
23006
  const summaryMatch = stripAnsi4(output).match(/svelte-check found (\d+) error/);
@@ -22856,7 +23052,7 @@ Found ${errorCount} error${suffix}.`;
22856
23052
  resolve45(import.meta.dir, "../../types", fileName),
22857
23053
  resolve45(import.meta.dir, "../../../types", fileName)
22858
23054
  ];
22859
- return candidates.find((candidate) => existsSync43(candidate)) ?? candidates[0];
23055
+ return candidates.find((candidate) => existsSync44(candidate)) ?? candidates[0];
22860
23056
  }, ABSOLUTE_TYPECHECK_FILES, readProjectTsconfig = () => {
22861
23057
  try {
22862
23058
  return JSON.parse(readFileSync40(resolve45("tsconfig.json"), "utf-8"));
@@ -23215,13 +23411,13 @@ var {$: $3, env } = globalThis.Bun;
23215
23411
  import { spawn as nodeSpawn } from "child_process";
23216
23412
  import {
23217
23413
  createWriteStream,
23218
- existsSync as existsSync5,
23219
- readFileSync as readFileSync9,
23414
+ existsSync as existsSync6,
23415
+ readFileSync as readFileSync10,
23220
23416
  rmSync as rmSync2,
23221
23417
  writeFileSync as writeFileSync4
23222
23418
  } from "fs";
23223
23419
  import { tmpdir as tmpdir2 } from "os";
23224
- import { join as join16, resolve as resolvePath2 } from "path";
23420
+ import { join as join17, resolve as resolvePath2 } from "path";
23225
23421
 
23226
23422
  // src/dev/tunnel/client.ts
23227
23423
  var RECONNECT_DELAY_MS = 2000;
@@ -23731,7 +23927,7 @@ init_expoProject();
23731
23927
  init_iosPhysicalDeviceTransport();
23732
23928
  import { spawn } from "child_process";
23733
23929
  import { access as access2 } from "fs/promises";
23734
- import { join as join8 } from "path";
23930
+ import { join as join9 } from "path";
23735
23931
  var METRO_READY_TIMEOUT_MS = 60000;
23736
23932
  var PROCESS_CLOSE_TIMEOUT_MS = 2000;
23737
23933
  var commandEnvironment = (options) => ({
@@ -23744,7 +23940,7 @@ var commandEnvironment = (options) => ({
23744
23940
  ...options.metroHost ? { REACT_NATIVE_PACKAGER_HOSTNAME: options.metroHost } : {}
23745
23941
  });
23746
23942
  var absoluteExpoExecutable = async (project) => {
23747
- const executable = join8(project, "node_modules", ".bin", "expo");
23943
+ const executable = join9(project, "node_modules", ".bin", "expo");
23748
23944
  try {
23749
23945
  await access2(executable);
23750
23946
  return executable;
@@ -23840,18 +24036,18 @@ var stopProcess = async (process2) => {
23840
24036
  return;
23841
24037
  process2.kill("SIGTERM");
23842
24038
  await Promise.race([
23843
- new Promise((resolve5) => process2.once("exit", () => resolve5())),
23844
- new Promise((resolve5) => setTimeout(resolve5, PROCESS_CLOSE_TIMEOUT_MS))
24039
+ new Promise((resolve6) => process2.once("exit", () => resolve6())),
24040
+ new Promise((resolve6) => setTimeout(resolve6, PROCESS_CLOSE_TIMEOUT_MS))
23845
24041
  ]);
23846
24042
  if (process2.exitCode === null)
23847
24043
  process2.kill("SIGKILL");
23848
24044
  };
23849
- var waitForExit = (process2) => new Promise((resolve5) => {
24045
+ var waitForExit = (process2) => new Promise((resolve6) => {
23850
24046
  if (process2.exitCode !== null) {
23851
- resolve5(process2.exitCode);
24047
+ resolve6(process2.exitCode);
23852
24048
  return;
23853
24049
  }
23854
- process2.once("exit", (code) => resolve5(code ?? 1));
24050
+ process2.once("exit", (code) => resolve6(code ?? 1));
23855
24051
  });
23856
24052
  var runUtilityCommand = async (run, command, args, options) => {
23857
24053
  const child = run(command, args, {
@@ -23931,9 +24127,9 @@ var startAbsoluteExpoDevSession = async (options) => {
23931
24127
  }) : undefined;
23932
24128
  let metroReady = false;
23933
24129
  let resolveMetro;
23934
- const metroPromise = new Promise((resolve5, reject) => {
24130
+ const metroPromise = new Promise((resolve6, reject) => {
23935
24131
  if (!metro) {
23936
- resolve5();
24132
+ resolve6();
23937
24133
  return;
23938
24134
  }
23939
24135
  const timeout = setTimeout(() => {
@@ -23941,7 +24137,7 @@ var startAbsoluteExpoDevSession = async (options) => {
23941
24137
  }, METRO_READY_TIMEOUT_MS);
23942
24138
  resolveMetro = () => {
23943
24139
  clearTimeout(timeout);
23944
- resolve5();
24140
+ resolve6();
23945
24141
  };
23946
24142
  metro.once("exit", (code) => {
23947
24143
  if (!metroReady) {
@@ -24306,7 +24502,7 @@ var DEFAULT_PORT_RANGE = 10;
24306
24502
  var RESTART_PARK_POLL_MS = 20;
24307
24503
  var NODE_API_IMPORT_ERROR = "To load Node-API modules, use require() or process.dlopen instead of import.";
24308
24504
  var sourceServerBootstrap = resolvePath2(import.meta.dir, "../../dev/serverBootstrap.ts");
24309
- var serverBootstrap = existsSync5(sourceServerBootstrap) ? sourceServerBootstrap : resolvePath2(import.meta.dir, "../dev/serverBootstrap.js");
24505
+ var serverBootstrap = existsSync6(sourceServerBootstrap) ? sourceServerBootstrap : resolvePath2(import.meta.dir, "../dev/serverBootstrap.js");
24310
24506
  var formatServerBootDiagnostic = (output, serverEntry) => {
24311
24507
  if (!output.includes(NODE_API_IMPORT_ERROR))
24312
24508
  return null;
@@ -24496,7 +24692,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
24496
24692
  const generated = await writeAbsoluteExpoProject(normalized, {
24497
24693
  projectRoot: process.cwd()
24498
24694
  });
24499
- const dependenciesReady = existsSync5(join16(generated.path, "node_modules", "expo", "package.json")) && existsSync5(join16(generated.path, "node_modules", "expo-dev-client", "package.json"));
24695
+ const dependenciesReady = existsSync6(join17(generated.path, "node_modules", "expo", "package.json")) && existsSync6(join17(generated.path, "node_modules", "expo-dev-client", "package.json"));
24500
24696
  if (!dependenciesReady) {
24501
24697
  const install = await confirmPrompt("Expo development dependencies are missing. Install the pinned SDK 57 development client now?");
24502
24698
  if (!install) {
@@ -24506,7 +24702,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
24506
24702
  cwd: generated.path,
24507
24703
  stdio: "inherit"
24508
24704
  });
24509
- const installExit = await new Promise((resolve10) => installProcess.once("exit", (code) => resolve10(code ?? 1)));
24705
+ const installExit = await new Promise((resolve11) => installProcess.once("exit", (code) => resolve11(code ?? 1)));
24510
24706
  if (installExit !== 0) {
24511
24707
  throw new TypeError(`Expo dependency installation exited with status ${installExit}.`);
24512
24708
  }
@@ -24575,12 +24771,12 @@ var dev = async (serverEntry, configPath2, options = {}) => {
24575
24771
  }
24576
24772
  }
24577
24773
  if (ready) {
24578
- const nativeDirectory = join16(normalized.nativeProjectDirectory, "android");
24774
+ const nativeDirectory = join17(normalized.nativeProjectDirectory, "android");
24579
24775
  let createNativeProject = false;
24580
- if (!existsSync5(nativeDirectory)) {
24776
+ if (!existsSync6(nativeDirectory)) {
24581
24777
  createNativeProject = await confirmPrompt("Create the managed Capacitor Android project now?");
24582
24778
  }
24583
- if (existsSync5(nativeDirectory) || createNativeProject) {
24779
+ if (existsSync6(nativeDirectory) || createNativeProject) {
24584
24780
  androidDevProject = await prepareAbsoluteAndroidDevProject(normalized, {
24585
24781
  createNativeProject,
24586
24782
  projectRoot: process.cwd(),
@@ -24595,8 +24791,8 @@ var dev = async (serverEntry, configPath2, options = {}) => {
24595
24791
  if (!remote) {
24596
24792
  console.log(cliTag("\x1B[33m", "iOS target skipped. Pair a Mac with `absolute mobile pair mac <name> <user@host>`."));
24597
24793
  } else {
24598
- const nativeDirectory = join16(normalized.nativeProjectDirectory, "ios");
24599
- if (!existsSync5(nativeDirectory)) {
24794
+ const nativeDirectory = join17(normalized.nativeProjectDirectory, "ios");
24795
+ if (!existsSync6(nativeDirectory)) {
24600
24796
  console.log(cliTag("\x1B[33m", "The iOS project is missing. Run `absolute mobile init` before remote development."));
24601
24797
  } else {
24602
24798
  iosDevProject = createAbsoluteRemoteIosDevProject(normalized, process.cwd(), remote);
@@ -24616,12 +24812,12 @@ var dev = async (serverEntry, configPath2, options = {}) => {
24616
24812
  }
24617
24813
  }
24618
24814
  if (ready) {
24619
- const nativeDirectory = join16(normalized.nativeProjectDirectory, "ios");
24815
+ const nativeDirectory = join17(normalized.nativeProjectDirectory, "ios");
24620
24816
  let createNativeProject = false;
24621
- if (!existsSync5(nativeDirectory)) {
24817
+ if (!existsSync6(nativeDirectory)) {
24622
24818
  createNativeProject = await confirmPrompt("Create the managed Capacitor iOS project now?");
24623
24819
  }
24624
- if (existsSync5(nativeDirectory) || createNativeProject) {
24820
+ if (existsSync6(nativeDirectory) || createNativeProject) {
24625
24821
  iosDevProject = await prepareAbsoluteIosDevProject(normalized, {
24626
24822
  createNativeProject,
24627
24823
  projectRoot: process.cwd(),
@@ -24690,12 +24886,12 @@ var dev = async (serverEntry, configPath2, options = {}) => {
24690
24886
  startedAt: new Date().toISOString()
24691
24887
  });
24692
24888
  const instanceLog = createWriteStream(instanceLogFile, { flags: "w" });
24693
- const writeInstanceLog = (text) => {
24889
+ const writeInstanceLog = (text2) => {
24694
24890
  try {
24695
- instanceLog.write(text.replace(ANSI_LOG_REGEX, ""));
24891
+ instanceLog.write(text2.replace(ANSI_LOG_REGEX, ""));
24696
24892
  } catch {}
24697
24893
  };
24698
- const usesDocker = existsSync5(resolvePath2(COMPOSE_PATH));
24894
+ const usesDocker = existsSync6(resolvePath2(COMPOSE_PATH));
24699
24895
  const scripts = usesDocker ? await readDbScripts() : null;
24700
24896
  if (scripts)
24701
24897
  await startDatabase(scripts);
@@ -25181,8 +25377,8 @@ var dev = async (serverEntry, configPath2, options = {}) => {
25181
25377
  const ANSI_COLOR_SEQUENCE_RE = new RegExp(`${ANSI_ESCAPE}\\[[0-9;]*m`, "g");
25182
25378
  let restartScanBuffer = "";
25183
25379
  const handleChunk = (value) => {
25184
- const text = value.toString("utf8");
25185
- restartScanBuffer += text;
25380
+ const text2 = value.toString("utf8");
25381
+ restartScanBuffer += text2;
25186
25382
  let newlineIdx;
25187
25383
  while ((newlineIdx = restartScanBuffer.indexOf(`
25188
25384
  `)) !== -1) {
@@ -25250,13 +25446,13 @@ var dev = async (serverEntry, configPath2, options = {}) => {
25250
25446
  const merged = {};
25251
25447
  const candidates = [".env", ".env.development", ".env.local"];
25252
25448
  for (const name of candidates) {
25253
- let text;
25449
+ let text2;
25254
25450
  try {
25255
- text = readFileSync9(resolvePath2(process.cwd(), name), "utf8");
25451
+ text2 = readFileSync10(resolvePath2(process.cwd(), name), "utf8");
25256
25452
  } catch {
25257
25453
  continue;
25258
25454
  }
25259
- for (const rawLine of text.split(`
25455
+ for (const rawLine of text2.split(`
25260
25456
  `)) {
25261
25457
  const line = rawLine.trim();
25262
25458
  if (!line || line.startsWith("#"))
@@ -25274,7 +25470,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
25274
25470
  }
25275
25471
  return merged;
25276
25472
  };
25277
- const heapPreloadPath = join16(tmpdir2(), `absolute-heap-${process.pid}.ts`);
25473
+ const heapPreloadPath = join17(tmpdir2(), `absolute-heap-${process.pid}.ts`);
25278
25474
  let heapSnapshotEnabled = false;
25279
25475
  try {
25280
25476
  writeFileSync4(heapPreloadPath, DEV_CHILD_PRELOAD);
@@ -25407,7 +25603,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
25407
25603
  if (now - last < 100)
25408
25604
  return;
25409
25605
  recentlyHandled.set(filename, now);
25410
- scheduleServerRestart(join16(serverEntryDir, filename));
25606
+ scheduleServerRestart(join17(serverEntryDir, filename));
25411
25607
  };
25412
25608
  const recoveryScan = async () => {
25413
25609
  let entries;
@@ -25426,7 +25622,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
25426
25622
  continue;
25427
25623
  let fileStat;
25428
25624
  try {
25429
- fileStat = statSync(join16(serverEntryDir, entry.name));
25625
+ fileStat = statSync(join17(serverEntryDir, entry.name));
25430
25626
  } catch {
25431
25627
  continue;
25432
25628
  }
@@ -25814,9 +26010,9 @@ init_eslint();
25814
26010
  init_constants();
25815
26011
  init_utils();
25816
26012
  import { execSync as execSync2 } from "child_process";
25817
- import { existsSync as existsSync8, readFileSync as readFileSync11 } from "fs";
26013
+ import { existsSync as existsSync9, readFileSync as readFileSync12 } from "fs";
25818
26014
  import { arch as arch2, cpus, platform as platform3, totalmem, version } from "os";
25819
- import { resolve as resolve12 } from "path";
26015
+ import { resolve as resolve13 } from "path";
25820
26016
  var bold = (str) => `\x1B[1m${str}\x1B[0m`;
25821
26017
  var getBinaryVersion = (binary, flag = "--version") => {
25822
26018
  try {
@@ -25836,7 +26032,7 @@ var getPackageVersion = (packageName) => {
25836
26032
  const pkgPath = __require.resolve(`${packageName}/package.json`, {
25837
26033
  paths: [process.cwd()]
25838
26034
  });
25839
- const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
26035
+ const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
25840
26036
  const ver = pkg.version;
25841
26037
  return ver;
25842
26038
  } catch {
@@ -25846,10 +26042,10 @@ var getPackageVersion = (packageName) => {
25846
26042
  var getAbsoluteVersion = () => {
25847
26043
  try {
25848
26044
  const candidates = [
25849
- resolve12(import.meta.dir, "..", "..", "package.json"),
25850
- resolve12(import.meta.dir, "..", "..", "..", "package.json")
26045
+ resolve13(import.meta.dir, "..", "..", "package.json"),
26046
+ resolve13(import.meta.dir, "..", "..", "..", "package.json")
25851
26047
  ];
25852
- const pkgPath = candidates.find((candidate) => existsSync8(candidate));
26048
+ const pkgPath = candidates.find((candidate) => existsSync9(candidate));
25853
26049
  if (pkgPath)
25854
26050
  return readPackageVersion(pkgPath);
25855
26051
  } catch {
@@ -25858,7 +26054,7 @@ var getAbsoluteVersion = () => {
25858
26054
  return getPackageVersion("@absolutejs/absolute");
25859
26055
  };
25860
26056
  var readPackageVersion = (pkgPath) => {
25861
- const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
26057
+ const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
25862
26058
  const ver = pkg.version;
25863
26059
  return ver;
25864
26060
  };
@@ -25890,7 +26086,7 @@ var detectCI = () => {
25890
26086
  };
25891
26087
  var isDockerEnvironment = () => {
25892
26088
  try {
25893
- return existsSync8("/.dockerenv");
26089
+ return existsSync9("/.dockerenv");
25894
26090
  } catch {
25895
26091
  return false;
25896
26092
  }
@@ -25960,11 +26156,11 @@ var info = () => {
25960
26156
  // src/cli/cache.ts
25961
26157
  init_constants();
25962
26158
  import { mkdir as mkdir7 } from "fs/promises";
25963
- import { join as join17 } from "path";
26159
+ import { join as join18 } from "path";
25964
26160
  var {Glob } = globalThis.Bun;
25965
26161
  var CACHE_DIR = ".absolutejs";
25966
26162
  var MAX_FILES_PER_BATCH = 200;
25967
- var isIgnored = (file, ignorePatterns) => ignorePatterns.some((pat) => new Glob(pat).match(file));
26163
+ var isIgnored2 = (file, ignorePatterns) => ignorePatterns.some((pat) => new Glob(pat).match(file));
25968
26164
  var collectFiles = async (pattern, ignorePatterns) => {
25969
26165
  const files = [];
25970
26166
  const glob = new Glob(pattern);
@@ -25972,7 +26168,7 @@ var collectFiles = async (pattern, ignorePatterns) => {
25972
26168
  cwd: ".",
25973
26169
  dot: false
25974
26170
  })) {
25975
- if (!isIgnored(file, ignorePatterns))
26171
+ if (!isIgnored2(file, ignorePatterns))
25976
26172
  files.push(file);
25977
26173
  }
25978
26174
  return files;
@@ -26012,7 +26208,7 @@ var hashFiles = async (paths) => {
26012
26208
  };
26013
26209
  var loadCache = async (tool) => {
26014
26210
  try {
26015
- const path = join17(CACHE_DIR, `${tool}.cache.json`);
26211
+ const path = join18(CACHE_DIR, `${tool}.cache.json`);
26016
26212
  const data = await Bun.file(path).json();
26017
26213
  const result = data;
26018
26214
  return result;
@@ -26059,7 +26255,7 @@ var runTool = async (adapter, args) => {
26059
26255
  };
26060
26256
  var saveCache = async (tool, data) => {
26061
26257
  await mkdir7(CACHE_DIR, { recursive: true });
26062
- const path = join17(CACHE_DIR, `${tool}.cache.json`);
26258
+ const path = join18(CACHE_DIR, `${tool}.cache.json`);
26063
26259
  await Bun.write(path, JSON.stringify(data, null, "\t"));
26064
26260
  };
26065
26261
 
@@ -26152,7 +26348,7 @@ init_getDurationString();
26152
26348
  init_instanceRegistry();
26153
26349
  import {
26154
26350
  appendFileSync,
26155
- existsSync as existsSync12,
26351
+ existsSync as existsSync13,
26156
26352
  mkdirSync as mkdirSync7,
26157
26353
  readdirSync as readdirSync2,
26158
26354
  readFileSync as readFileSync16,
@@ -26723,7 +26919,7 @@ var createWorkspaceTui = ({
26723
26919
  // src/cli/scripts/workspace.ts
26724
26920
  init_utils();
26725
26921
  var sourceServerBootstrap2 = resolve22(import.meta.dir, "../../dev/serverBootstrap.ts");
26726
- var serverBootstrap2 = existsSync12(sourceServerBootstrap2) ? sourceServerBootstrap2 : resolve22(import.meta.dir, "../dev/serverBootstrap.js");
26922
+ var serverBootstrap2 = existsSync13(sourceServerBootstrap2) ? sourceServerBootstrap2 : resolve22(import.meta.dir, "../dev/serverBootstrap.js");
26727
26923
  var ANSI_REGEX2 = new RegExp(`${String.fromCharCode(ANSI_ESCAPE_CODE)}\\[[0-?]*[ -/]*[@-~]`, "g");
26728
26924
  var sleep = (durationMs) => Bun.sleep(durationMs);
26729
26925
  var stripAnsi3 = (value) => value.replace(ANSI_REGEX2, "");
@@ -27370,7 +27566,7 @@ var workspace = async (subcommand, options) => {
27370
27566
  const resolved = resolveService(name, service, workspaceEnv, options);
27371
27567
  const port = resolveWorkspaceServicePort(resolved.service, resolved.env);
27372
27568
  killStaleServicePort(port);
27373
- if (isAbsoluteService(resolved.service) && resolved.configPath && !existsSync12(resolved.configPath)) {
27569
+ if (isAbsoluteService(resolved.service) && resolved.configPath && !existsSync13(resolved.configPath)) {
27374
27570
  throw new Error(`${name} references missing config "${resolved.configPath}"`);
27375
27571
  }
27376
27572
  serviceBootStartedAt.set(name, performance.now());