@absolutejs/absolute 0.20.0-beta.39 → 0.20.0-beta.40

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
@@ -791,7 +791,26 @@ var APP_ID_PATTERN, SCHEME_PATTERN, APPLE_APP_ID_PREFIX_PATTERN, CERTIFICATE_FIN
791
791
  }
792
792
  return value.match(/.{2}/g)?.join(":") ?? value;
793
793
  }))
794
- ].sort(), normalizeAbsoluteMobileConfig = (config, projectRoot) => {
794
+ ].sort(), normalizeExpoNativeRoutes = (config, projectRoot) => {
795
+ if (config.engine !== "expo")
796
+ return {};
797
+ const routes = config.routes?.native ?? {};
798
+ const normalized = {};
799
+ for (const [route, module] of Object.entries(routes)) {
800
+ const path = normalizeEntry(route);
801
+ if (path.includes("?") || path.includes("#") || path !== "/" && path.endsWith("/")) {
802
+ throw new TypeError(`mobile.routes.native route ${path} must be a canonical path without a query, fragment, or trailing slash.`);
803
+ }
804
+ if (path === "/__absolute/native") {
805
+ throw new TypeError("mobile.routes.native reserves /__absolute/native for the Expo diagnostic screen.");
806
+ }
807
+ if (path.includes("*") || path.includes(":")) {
808
+ throw new TypeError(`mobile.routes.native route ${path} must be static during the Expo experiment; parameters and wildcards are not supported yet.`);
809
+ }
810
+ normalized[path] = resolveProjectPath(projectRoot, requireText(module, `mobile.routes.native[${path}]`), `mobile.routes.native[${path}]`);
811
+ }
812
+ return Object.fromEntries(Object.entries(normalized).sort(([left], [right]) => left.localeCompare(right)));
813
+ }, normalizeAbsoluteMobileConfig = (config, projectRoot) => {
795
814
  const appId = requireText(config.appId, "mobile.appId");
796
815
  if (!APP_ID_PATTERN.test(appId)) {
797
816
  throw new TypeError("mobile.appId must use reverse-domain notation, for example com.example.app.");
@@ -809,10 +828,12 @@ var APP_ID_PATTERN, SCHEME_PATTERN, APPLE_APP_ID_PREFIX_PATTERN, CERTIFICATE_FIN
809
828
  bundleDirectory: resolveProjectPath(projectRoot, config.bundleDirectory ?? ".absolutejs/mobile/web", "mobile.bundleDirectory"),
810
829
  deepLinkHosts: normalizeHosts(config.deepLinks?.hosts, productionOrigin),
811
830
  deepLinkScheme,
812
- engine: "capacitor",
831
+ engine: config.engine ?? "capacitor",
813
832
  entry: normalizeEntry(config.entry),
833
+ expoNativeRoutes: normalizeExpoNativeRoutes(config, projectRoot),
834
+ ...config.engine === "expo" ? { expoSdkVersion: config.expo?.sdkVersion ?? 57 } : {},
814
835
  iosVersion: normalizeIosVersion(config.ios?.version),
815
- nativeProjectDirectory: resolveProjectPath(projectRoot, config.nativeProject?.directory ?? "mobile", "mobile.nativeProject.directory"),
836
+ nativeProjectDirectory: resolveProjectPath(projectRoot, config.nativeProject?.directory ?? (config.engine === "expo" ? ".absolutejs/mobile/expo" : "mobile"), "mobile.nativeProject.directory"),
816
837
  platforms: normalizePlatforms(config.platforms),
817
838
  productionOrigin,
818
839
  pushAndroidGoogleServicesFile: resolveProjectPath(projectRoot, config.pushNotifications?.android?.googleServicesFile ?? "google-services.json", "mobile.pushNotifications.android.googleServicesFile")
@@ -6420,6 +6441,11 @@ var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-
6420
6441
  if (candidate)
6421
6442
  return candidate;
6422
6443
  throw new TypeError("AbsoluteJS mobile push shell module is missing.");
6444
+ }, shellExpoDevicesModule = () => {
6445
+ const candidate = ["js", "ts"].map((extension) => join17(import.meta.dir, `shellExpoDevices.${extension}`)).find(existsSync9);
6446
+ if (candidate)
6447
+ return candidate;
6448
+ throw new TypeError("AbsoluteJS Expo device bridge module is missing.");
6423
6449
  }, escapeHtml = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;"), contentSecurityPolicy = (productionOrigin) => {
6424
6450
  const backend = new URL(productionOrigin);
6425
6451
  const socketOrigin = `${backend.protocol === "https:" ? "wss:" : "ws:"}//${backend.host}`;
@@ -6474,18 +6500,20 @@ var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-
6474
6500
  if (!resolved.startsWith(`${resolve14(packageDirectory)}/`))
6475
6501
  throw new TypeError(`${specifier} has an unsafe import entry.`);
6476
6502
  return resolved;
6477
- }, buildShellBootstrap = async (staging, auth, sync, storagePrefix, deviceCapabilities, projectRoot) => {
6503
+ }, buildShellBootstrap = async (staging, auth, sync, storagePrefix, engine, deviceCapabilities, projectRoot) => {
6504
+ const capacitor = engine !== "expo";
6505
+ const shellCapabilities = capacitor ? deviceCapabilities.capabilities : [];
6478
6506
  const modulePath = shellBootstrapModule();
6479
6507
  const authImport = auth ? `import { createAbsoluteMobileShellAuth } from ${JSON.stringify(shellAuthModule())};
6480
6508
  ` : "";
6481
6509
  const options = auth ? `{ createAuth: createAbsoluteMobileShellAuth${sync ? ", installSync: installAbsoluteMobileShellSync" : ""} }` : "";
6482
6510
  const syncImport = sync ? `import { installAbsoluteMobileShellSync } from ${JSON.stringify(shellSyncModule())};
6483
6511
  ` : "";
6484
- const pushIndex = deviceCapabilities.capabilities.indexOf("pushNotifications");
6512
+ const pushIndex = shellCapabilities.indexOf("pushNotifications");
6485
6513
  const push = pushIndex !== -1;
6486
6514
  const pushImport = push ? `import { createAbsoluteMobileShellPush } from ${JSON.stringify(shellPushModule())};
6487
6515
  ` : "";
6488
- const capabilityImports = (await Promise.all(deviceCapabilities.capabilities.map(async (name, index) => {
6516
+ const capabilityImports = (await Promise.all(shellCapabilities.map(async (name, index) => {
6489
6517
  const provider = deviceCapabilities.providers[name];
6490
6518
  if (!provider)
6491
6519
  throw new TypeError(`Missing device capability provider ${name}.`);
@@ -6495,14 +6523,22 @@ var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-
6495
6523
  const pushSetup = push ? `const absoluteMobilePush = createAbsoluteMobileShellPush();
6496
6524
  const absoluteMobilePushCapability = absoluteDeviceCapability${pushIndex}(absoluteMobilePush.capabilityOptions);
6497
6525
  ` : "";
6498
- const capabilityOptions = deviceCapabilities.capabilities.map((name, index) => `${JSON.stringify(name)}: ${name === "pushNotifications" ? "absoluteMobilePushCapability" : `absoluteDeviceCapability${index}()`}`).join(", ");
6526
+ const capabilityOptions = shellCapabilities.map((name, index) => `${JSON.stringify(name)}: ${name === "pushNotifications" ? "absoluteMobilePushCapability" : `absoluteDeviceCapability${index}()`}`).join(", ");
6499
6527
  const entryPath = join17(staging, ".absolute-mobile-entry.ts");
6500
- const baseAdapterModule = await resolveProjectImport(projectRoot, "@absolutejs/devices-capacitor");
6528
+ const baseAdapterModule = capacitor ? await resolveProjectImport(projectRoot, "@absolutejs/devices-capacitor") : shellExpoDevicesModule();
6529
+ const adapterImport = capacitor ? `import { installCapacitorDeviceAdapterIfNative } from ${JSON.stringify(baseAdapterModule)};` : `import { createAbsoluteExpoBridgeFetch, installAbsoluteExpoWebDeviceAdapter } from ${JSON.stringify(baseAdapterModule)};`;
6530
+ const adapterInstall = capacitor ? `installCapacitorDeviceAdapterIfNative({ storagePrefix: ${JSON.stringify(storagePrefix)}${capabilityOptions ? `, ${capabilityOptions}` : ""} });` : "installAbsoluteExpoWebDeviceAdapter();";
6531
+ let shellOptions = "{ createFetch: createAbsoluteExpoBridgeFetch }";
6532
+ if (capacitor)
6533
+ shellOptions = options;
6534
+ if (push) {
6535
+ shellOptions = `{ createAuth: (config, options) => createAbsoluteMobileShellAuth(config, options), beforeSignOut: absoluteMobilePush.beforeSignOut, connectPush: (auth) => absoluteMobilePush.connect(auth, absoluteMobilePushCapability)${sync ? ", installSync: installAbsoluteMobileShellSync" : ""} }`;
6536
+ }
6501
6537
  await writeFile7(entryPath, `import { startAbsoluteMobileShell } from ${JSON.stringify(modulePath)};
6502
- import { installCapacitorDeviceAdapterIfNative } from ${JSON.stringify(baseAdapterModule)};
6538
+ ${adapterImport}
6503
6539
  ${authImport}${syncImport}${pushImport}${capabilityImports}
6504
- ${pushSetup}installCapacitorDeviceAdapterIfNative({ storagePrefix: ${JSON.stringify(storagePrefix)}${capabilityOptions ? `, ${capabilityOptions}` : ""} });
6505
- void startAbsoluteMobileShell(${push ? `{ createAuth: (config, options) => createAbsoluteMobileShellAuth(config, options), beforeSignOut: absoluteMobilePush.beforeSignOut, connectPush: (auth) => absoluteMobilePush.connect(auth, absoluteMobilePushCapability)${sync ? ", installSync: installAbsoluteMobileShellSync" : ""} }` : options});
6540
+ ${pushSetup}${adapterInstall}
6541
+ void startAbsoluteMobileShell(${shellOptions});
6506
6542
  `);
6507
6543
  const build = await Bun.build({
6508
6544
  entrypoints: [entryPath],
@@ -6658,7 +6694,7 @@ void startAbsoluteMobileShell(${push ? `{ createAuth: (config, options) => creat
6658
6694
  writeFile7(join17(staging, MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
6659
6695
  `),
6660
6696
  writeFile7(join17(staging, INDEX_FILE), indexHtml(options.config.appName, options.config.productionOrigin)),
6661
- buildShellBootstrap(staging, options.auth !== undefined, options.auth !== undefined && options.sync === true, `absolutejs.${options.auth?.clientId ?? options.config.appId}.`, options.deviceCapabilities, options.projectRoot)
6697
+ 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)
6662
6698
  ]);
6663
6699
  await installBundle(staging, destination);
6664
6700
  return manifest;
@@ -7509,9 +7545,523 @@ var init_deviceCapabilities = __esm(() => {
7509
7545
  ];
7510
7546
  });
7511
7547
 
7548
+ // src/mobile/expoProject.ts
7549
+ import {
7550
+ access as access7,
7551
+ cp as cp3,
7552
+ mkdir as mkdir10,
7553
+ mkdtemp as mkdtemp5,
7554
+ readdir as readdir3,
7555
+ readFile as readFile11,
7556
+ rename as rename8,
7557
+ rm as rm7,
7558
+ writeFile as writeFile9
7559
+ } from "fs/promises";
7560
+ import { createHash as createHash11 } from "crypto";
7561
+ import { basename as basename8, dirname as dirname13, join as join21, relative as relative12, resolve as resolve17 } from "path";
7562
+ var EXPO_GENERATED_HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.
7563
+ `, EXPO_ASSET_EXTENSION = ".absasset", EXPO_PROJECT_MARKER = ".absolutejs-expo-project", exists2 = async (path) => {
7564
+ try {
7565
+ await access7(path);
7566
+ return true;
7567
+ } catch {
7568
+ return false;
7569
+ }
7570
+ }, portableRelative2 = (from, destination) => {
7571
+ const value = relative12(from, destination).replaceAll("\\", "/");
7572
+ return value.startsWith(".") ? value : `./${value}`;
7573
+ }, routeSegments = (route) => route.split("/").filter(Boolean).map((segment) => {
7574
+ if (segment.startsWith(":"))
7575
+ return `[${segment.slice(1)}]`;
7576
+ if (segment === "." || segment === ".." || !/^[A-Za-z0-9._~-]+$/u.test(segment)) {
7577
+ throw new TypeError(`Expo native route ${route} contains an unsupported segment ${segment}.`);
7578
+ }
7579
+ return segment;
7580
+ }), routeFile = (project, route) => join21(project, "app", ...routeSegments(route), "index.tsx"), expoPackage = () => ({
7581
+ dependencies: {
7582
+ expo: "~57.0.9",
7583
+ "expo-asset": "~57.0.15",
7584
+ "expo-constants": "~57.0.16",
7585
+ "expo-file-system": "~57.0.6",
7586
+ "expo-haptics": "~57.0.2",
7587
+ "expo-linking": "~57.0.8",
7588
+ "expo-router": "~57.0.17",
7589
+ react: "19.2.3",
7590
+ "react-native": "0.86.3",
7591
+ "react-native-safe-area-context": "~5.7.0",
7592
+ "react-native-screens": "4.26.0",
7593
+ "react-native-webview": "13.16.1"
7594
+ },
7595
+ devDependencies: {
7596
+ "@types/react": "~19.2.2",
7597
+ typescript: "~6.0.3"
7598
+ },
7599
+ main: "expo-router/entry",
7600
+ name: "absolutejs-expo-shell",
7601
+ private: true,
7602
+ scripts: {
7603
+ android: "expo run:android",
7604
+ ios: "expo run:ios",
7605
+ start: "expo start --dev-client"
7606
+ },
7607
+ version: "0.0.0"
7608
+ }), expoAppConfig = (config) => ({
7609
+ expo: {
7610
+ android: {
7611
+ intentFilters: config.deepLinkHosts.map((host2) => ({
7612
+ action: "VIEW",
7613
+ autoVerify: true,
7614
+ category: ["BROWSABLE", "DEFAULT"],
7615
+ data: [{ host: host2, pathPrefix: "/", scheme: "https" }]
7616
+ })),
7617
+ package: config.appId
7618
+ },
7619
+ experiments: { typedRoutes: true },
7620
+ ios: {
7621
+ associatedDomains: config.deepLinkHosts.map((host2) => `applinks:${host2}`),
7622
+ bundleIdentifier: config.appId,
7623
+ ...config.iosVersion ? { buildNumber: config.iosVersion } : {}
7624
+ },
7625
+ name: config.appName,
7626
+ plugins: ["expo-router"],
7627
+ runtimeVersion: { policy: "appVersion" },
7628
+ scheme: config.deepLinkScheme,
7629
+ slug: config.appId.toLowerCase().replaceAll(".", "-"),
7630
+ version: config.iosVersion ?? "0.1.0"
7631
+ }
7632
+ }), metroConfig = (projectRoot) => `${EXPO_GENERATED_HEADER}const { getDefaultConfig } = require('expo/metro-config');
7633
+ const path = require('node:path');
7634
+
7635
+ const projectRoot = __dirname;
7636
+ const appRoot = ${JSON.stringify(projectRoot)};
7637
+ const config = getDefaultConfig(projectRoot);
7638
+ config.resolver.assetExts.push('absasset');
7639
+ config.resolver.nodeModulesPaths = [
7640
+ path.join(projectRoot, 'node_modules'),
7641
+ path.join(appRoot, 'node_modules')
7642
+ ];
7643
+ config.watchFolders = [appRoot];
7644
+
7645
+ module.exports = config;
7646
+ `, layoutSource, nativeDiagnosticSource, webHostSource = (config) => {
7647
+ const nativeRoutes = [
7648
+ "/__absolute/native",
7649
+ ...Object.keys(config.expoNativeRoutes)
7650
+ ];
7651
+ return `${EXPO_GENERATED_HEADER}import * as Haptics from 'expo-haptics';
7652
+ import * as Linking from 'expo-linking';
7653
+ import { router, usePathname } from 'expo-router';
7654
+ import { useEffect, useRef, useState } from 'react';
7655
+ import { ActivityIndicator, BackHandler, StyleSheet, View } from 'react-native';
7656
+ import { WebView, type WebViewMessageEvent } from 'react-native-webview';
7657
+ import { materializeAbsoluteWebBundle } from './webAssets';
7658
+
7659
+ const BRIDGE_FORMAT = 1;
7660
+ const MAX_MESSAGE_BYTES = 64 * 1024;
7661
+ const MAX_HTTP_BODY_BYTES = 48 * 1024;
7662
+ const NATIVE_ROUTES = new Set(${JSON.stringify(nativeRoutes)});
7663
+ const PRODUCTION_ORIGIN = ${JSON.stringify(config.productionOrigin)};
7664
+
7665
+ const bridgeBootstrap = (path: string) => \`(() => {
7666
+ const pending = new Map();
7667
+ let sequence = 0;
7668
+ let currentPath = \${JSON.stringify(path)};
7669
+ const send = value => {
7670
+ const source = JSON.stringify(value);
7671
+ if (new TextEncoder().encode(source).byteLength > 65536) throw new Error('Expo bridge message exceeds 64 KiB.');
7672
+ window.ReactNativeWebView.postMessage(source);
7673
+ };
7674
+ globalThis.__absoluteExpoReceive = source => {
7675
+ const message = JSON.parse(source);
7676
+ const operation = pending.get(message.id);
7677
+ if (!operation) return;
7678
+ pending.delete(message.id);
7679
+ clearTimeout(operation.timer);
7680
+ message.error ? operation.reject(new Error(message.error.message)) : operation.resolve(message.result);
7681
+ };
7682
+ globalThis.__absoluteExpoBridge = {
7683
+ request(method, params) {
7684
+ const id = 'web_' + Date.now().toString(36) + '_' + (++sequence).toString(36);
7685
+ send({ format: 1, id, kind: 'request', method, params, path: currentPath });
7686
+ return new Promise((resolve, reject) => {
7687
+ const timer = setTimeout(() => {
7688
+ pending.delete(id);
7689
+ reject(new Error('Expo bridge request timed out.'));
7690
+ }, 10000);
7691
+ pending.set(id, { reject, resolve, timer });
7692
+ });
7693
+ },
7694
+ setPath(path) {
7695
+ currentPath = path;
7696
+ send({ format: 1, kind: 'event', event: 'navigation', path });
7697
+ }
7698
+ };
7699
+ document.addEventListener('click', event => {
7700
+ const anchor = event.target instanceof Element ? event.target.closest('a[href]') : null;
7701
+ if (!anchor) return;
7702
+ const url = new URL(anchor.href, location.href);
7703
+ if (!${JSON.stringify(nativeRoutes)}.includes(url.pathname)) return;
7704
+ event.preventDefault();
7705
+ send({ format: 1, kind: 'event', event: 'navigation', path: url.pathname + url.search + url.hash });
7706
+ }, true);
7707
+ send({ format: 1, kind: 'event', event: 'ready', path: \${JSON.stringify(path)} });
7708
+ })(); true;\`;
7709
+
7710
+ const impact = async (params: Record<string, unknown>) => {
7711
+ const style = params.style;
7712
+ if (style === 'selection') return Haptics.selectionAsync();
7713
+ if (style === 'success' || style === 'warning' || style === 'error') {
7714
+ const value = style === 'success' ? Haptics.NotificationFeedbackType.Success : style === 'warning' ? Haptics.NotificationFeedbackType.Warning : Haptics.NotificationFeedbackType.Error;
7715
+ return Haptics.notificationAsync(value);
7716
+ }
7717
+ const value = style === 'light' ? Haptics.ImpactFeedbackStyle.Light : style === 'heavy' ? Haptics.ImpactFeedbackStyle.Heavy : Haptics.ImpactFeedbackStyle.Medium;
7718
+ return Haptics.impactAsync(value);
7719
+ };
7720
+
7721
+ const bridgeFetch = async (params: Record<string, unknown>) => {
7722
+ if (params.method !== 'GET' || typeof params.url !== 'string' || typeof params.headers !== 'object' || params.headers === null || Array.isArray(params.headers)) throw new Error('Expo bridge HTTP request is invalid.');
7723
+ const url = new URL(params.url);
7724
+ if (url.origin !== PRODUCTION_ORIGIN || url.username || url.password) throw new Error('Expo bridge HTTP request left productionOrigin.');
7725
+ const headers = new Headers();
7726
+ for (const [name, value] of Object.entries(params.headers as Record<string, unknown>)) {
7727
+ const normalized = name.toLowerCase();
7728
+ if (typeof value !== 'string' || (normalized !== 'accept' && !normalized.startsWith('x-absolute-mobile-'))) throw new Error('Expo bridge HTTP header is not allowed.');
7729
+ headers.set(normalized, value);
7730
+ }
7731
+ const response = await fetch(url, { headers, method: 'GET', redirect: 'manual' });
7732
+ if (new URL(response.url || url.href).origin !== PRODUCTION_ORIGIN || response.status >= 300 && response.status < 400) throw new Error('Expo bridge HTTP redirects are not allowed.');
7733
+ const body = await response.text();
7734
+ if (new TextEncoder().encode(body).byteLength > MAX_HTTP_BODY_BYTES) throw new Error('Expo bridge HTTP response exceeds 48 KiB.');
7735
+ const responseHeaders: Record<string, string> = {};
7736
+ for (const name of ['cache-control', 'content-type']) {
7737
+ const value = response.headers.get(name);
7738
+ if (value) responseHeaders[name] = value;
7739
+ }
7740
+ return { body, headers: responseHeaders, status: response.status };
7741
+ };
7742
+
7743
+ export function AbsoluteWebHost() {
7744
+ const pathname = usePathname() || '/';
7745
+ const webView = useRef<WebView>(null);
7746
+ const [indexUri, setIndexUri] = useState<string>();
7747
+ const [canGoBack, setCanGoBack] = useState(false);
7748
+ const activeWebPath = useRef(pathname);
7749
+
7750
+ useEffect(() => { void materializeAbsoluteWebBundle().then(setIndexUri); }, []);
7751
+ useEffect(() => {
7752
+ const subscription = BackHandler.addEventListener('hardwareBackPress', () => {
7753
+ if (!canGoBack) return false;
7754
+ webView.current?.goBack();
7755
+ return true;
7756
+ });
7757
+ return () => subscription.remove();
7758
+ }, [canGoBack]);
7759
+
7760
+ const respond = (message: Record<string, unknown>) => {
7761
+ const source = JSON.stringify(message).replaceAll('\\u2028', '\\\\u2028').replaceAll('\\u2029', '\\\\u2029');
7762
+ if (new TextEncoder().encode(source).byteLength > MAX_MESSAGE_BYTES) throw new Error('Expo bridge response exceeds 64 KiB.');
7763
+ webView.current?.injectJavaScript(\`globalThis.__absoluteExpoReceive(\${JSON.stringify(source)}); true;\`);
7764
+ };
7765
+ const onMessage = async (event: WebViewMessageEvent) => {
7766
+ const source = event.nativeEvent.data;
7767
+ if (new TextEncoder().encode(source).byteLength > MAX_MESSAGE_BYTES) return;
7768
+ let message: Record<string, unknown>;
7769
+ try { message = JSON.parse(source); } catch { return; }
7770
+ if (message.format !== BRIDGE_FORMAT || typeof message.path !== 'string' || !message.path.startsWith('/') || message.path.startsWith('//')) return;
7771
+ if (message.kind === 'event' && (message.event === 'navigation' || message.event === 'ready')) {
7772
+ const target = new URL(message.path, PRODUCTION_ORIGIN);
7773
+ if (target.origin !== PRODUCTION_ORIGIN) return;
7774
+ if (NATIVE_ROUTES.has(target.pathname)) router.push(message.path as never);
7775
+ else activeWebPath.current = message.path;
7776
+ return;
7777
+ }
7778
+ if (message.kind !== 'request' || typeof message.id !== 'string' || message.path !== activeWebPath.current) return;
7779
+ try {
7780
+ if (typeof message.params !== 'object' || message.params === null || Array.isArray(message.params)) throw new Error('Expo bridge method params are invalid.');
7781
+ if (message.method === 'devices.haptics.impact') {
7782
+ const style = (message.params as Record<string, unknown>).style;
7783
+ if (typeof style !== 'string' || !['error', 'heavy', 'light', 'medium', 'selection', 'success', 'vibrate', 'warning'].includes(style)) throw new Error('Expo bridge haptics style is invalid.');
7784
+ await impact(message.params as Record<string, unknown>);
7785
+ respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: null });
7786
+ } else if (message.method === 'http.fetch') {
7787
+ respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: await bridgeFetch(message.params as Record<string, unknown>) });
7788
+ } else {
7789
+ throw new Error('Expo bridge method is not allowed.');
7790
+ }
7791
+ } catch (error) {
7792
+ respond({ error: { code: 'failed', message: error instanceof Error ? error.message : 'Native operation failed.' }, format: BRIDGE_FORMAT, id: message.id, kind: 'response' });
7793
+ }
7794
+ };
7795
+
7796
+ if (!indexUri) return <View style={styles.loading}><ActivityIndicator /></View>;
7797
+ return <WebView
7798
+ allowFileAccess
7799
+ allowFileAccessFromFileURLs
7800
+ allowUniversalAccessFromFileURLs={false}
7801
+ allowingReadAccessToURL={indexUri.slice(0, indexUri.lastIndexOf('/') + 1)}
7802
+ injectedJavaScriptBeforeContentLoaded={bridgeBootstrap(pathname)}
7803
+ onMessage={onMessage}
7804
+ onNavigationStateChange={state => setCanGoBack(state.canGoBack)}
7805
+ onShouldStartLoadWithRequest={request => {
7806
+ if (request.url.startsWith('file:') || request.url.startsWith(PRODUCTION_ORIGIN)) return true;
7807
+ void Linking.openURL(request.url);
7808
+ return false;
7809
+ }}
7810
+ ref={webView}
7811
+ source={{ uri: indexUri + '?absolutePath=' + encodeURIComponent(pathname) }}
7812
+ style={styles.web}
7813
+ />;
7814
+ }
7815
+
7816
+ const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, justifyContent: 'center' }, web: { flex: 1 } });
7817
+ `;
7818
+ }, webRouteSource, catchAllRouteSource, nativeWrapperSource = (wrapper, module) => `${EXPO_GENERATED_HEADER}export { default } from ${JSON.stringify(portableRelative2(dirname13(wrapper), module).replace(/\.(?:[cm]?[jt]sx?)$/u, ""))};
7819
+ `, expoTsConfig = (projectRoot, project) => ({
7820
+ compilerOptions: {
7821
+ paths: {
7822
+ "*": [
7823
+ "./node_modules/*",
7824
+ `${portableRelative2(project, projectRoot)}/node_modules/*`
7825
+ ],
7826
+ react: ["./node_modules/@types/react/index.d.ts"],
7827
+ "react/*": ["./node_modules/@types/react/*"]
7828
+ },
7829
+ strict: true
7830
+ },
7831
+ extends: "expo/tsconfig.base"
7832
+ }), writeManagedFile = async (path, source, force) => {
7833
+ await mkdir10(dirname13(path), { recursive: true });
7834
+ if (await exists2(path)) {
7835
+ const current = await readFile11(path, "utf8");
7836
+ if (current === source)
7837
+ return false;
7838
+ if (!force && !current.startsWith(EXPO_GENERATED_HEADER)) {
7839
+ throw new TypeError(`Expo project file ${path} is not AbsoluteJS-managed; rerun with --force only after reviewing it.`);
7840
+ }
7841
+ }
7842
+ const temporary = `${path}.${crypto.randomUUID()}.tmp`;
7843
+ await writeFile9(temporary, source, { flag: "wx" });
7844
+ await rename8(temporary, path);
7845
+ return true;
7846
+ }, jsonSource = (value) => `${JSON.stringify(value, null, "\t")}
7847
+ `, writeAbsoluteExpoProject = async (config, options) => {
7848
+ if (config.engine !== "expo")
7849
+ throw new TypeError("Expo project generation requires mobile.engine: expo.");
7850
+ const projectRoot = resolve17(options.projectRoot);
7851
+ const project = config.nativeProjectDirectory;
7852
+ const routeModules = Object.entries(config.expoNativeRoutes);
7853
+ const moduleChecks = await Promise.all(routeModules.map(async ([route, module]) => ({
7854
+ exists: await exists2(module),
7855
+ module,
7856
+ route
7857
+ })));
7858
+ const missing = moduleChecks.find((entry) => !entry.exists);
7859
+ if (missing) {
7860
+ throw new TypeError(`Expo native route ${missing.route} references missing module ${missing.module}.`);
7861
+ }
7862
+ const marker = join21(project, EXPO_PROJECT_MARKER);
7863
+ if (await exists2(project) && !await exists2(marker)) {
7864
+ const entries = await readdir3(project);
7865
+ if (entries.length > 0 && !options.force) {
7866
+ throw new TypeError(`Expo project directory ${project} is not AbsoluteJS-managed; rerun with --force only after reviewing it.`);
7867
+ }
7868
+ }
7869
+ await mkdir10(project, { recursive: true });
7870
+ await writeFile9(marker, `format=1
7871
+ `);
7872
+ const files = new Map([
7873
+ [
7874
+ join21(project, ".gitignore"),
7875
+ `.expo/
7876
+ android/
7877
+ ios/
7878
+ node_modules/
7879
+ `
7880
+ ],
7881
+ [join21(project, "app.json"), jsonSource(expoAppConfig(config))],
7882
+ [join21(project, "package.json"), jsonSource(expoPackage())],
7883
+ [join21(project, "metro.config.js"), metroConfig(projectRoot)],
7884
+ [
7885
+ join21(project, "tsconfig.json"),
7886
+ jsonSource(expoTsConfig(projectRoot, project))
7887
+ ],
7888
+ [join21(project, "app", "_layout.tsx"), layoutSource],
7889
+ [
7890
+ join21(project, "app", "__absolute", "native", "index.tsx"),
7891
+ nativeDiagnosticSource
7892
+ ],
7893
+ [
7894
+ join21(project, "src", "generated", "AbsoluteWebHost.tsx"),
7895
+ webHostSource(config)
7896
+ ]
7897
+ ]);
7898
+ if (!config.expoNativeRoutes["/"]) {
7899
+ files.set(join21(project, "app", "index.tsx"), webRouteSource);
7900
+ }
7901
+ files.set(join21(project, "app", "[...absolute].tsx"), catchAllRouteSource);
7902
+ for (const [route, module] of routeModules) {
7903
+ const wrapper = route === "/" ? join21(project, "app", "index.tsx") : routeFile(project, route);
7904
+ files.set(wrapper, nativeWrapperSource(wrapper, module));
7905
+ }
7906
+ const changes = await Promise.all([...files].map(([path, source]) => writeManagedFile(path, source, true)));
7907
+ const changed = changes.filter(Boolean).length;
7908
+ return { changed, path: project, written: [...files.keys()] };
7909
+ }, walkFiles = async (root, directory = root) => {
7910
+ const entries = await readdir3(directory, { withFileTypes: true });
7911
+ const nested = await Promise.all(entries.map((entry) => {
7912
+ const path = join21(directory, entry.name);
7913
+ if (entry.isDirectory())
7914
+ return walkFiles(root, path);
7915
+ if (entry.isFile())
7916
+ return [path];
7917
+ throw new TypeError(`Expo embedded bundle cannot contain a symbolic link or special file: ${path}.`);
7918
+ }));
7919
+ return nested.flat().sort();
7920
+ }, renameIfPresent = async (source, destination) => {
7921
+ try {
7922
+ await rename8(source, destination);
7923
+ return true;
7924
+ } catch (error) {
7925
+ if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "ENOENT") {
7926
+ return false;
7927
+ }
7928
+ throw error;
7929
+ }
7930
+ }, installStagedDirectory = async (staging, destination) => {
7931
+ const backup = `${destination}.previous-${crypto.randomUUID()}`;
7932
+ const moved = await renameIfPresent(destination, backup);
7933
+ try {
7934
+ await rename8(staging, destination);
7935
+ if (moved)
7936
+ await rm7(backup, { force: true, recursive: true });
7937
+ } catch (error) {
7938
+ if (moved)
7939
+ await rename8(backup, destination);
7940
+ throw error;
7941
+ }
7942
+ }, assetModuleSource = (assets, bundleId) => `${EXPO_GENERATED_HEADER}import { Asset } from 'expo-asset';
7943
+ import { Directory, File, Paths } from 'expo-file-system';
7944
+
7945
+ declare const require: (path: string) => number;
7946
+ const BUNDLE_ID = ${JSON.stringify(bundleId)};
7947
+ const ASSETS = [
7948
+ ${assets.map(({ asset, path }) => ` { module: require(${JSON.stringify(asset)}), path: ${JSON.stringify(path)} }`).join(`,
7949
+ `)}
7950
+ ] as const;
7951
+
7952
+ export const materializeAbsoluteWebBundle = async () => {
7953
+ const root = new Directory(Paths.document, 'absolutejs-web', BUNDLE_ID);
7954
+ root.create({ idempotent: true, intermediates: true });
7955
+ for (const entry of ASSETS) {
7956
+ const parts = entry.path.split('/');
7957
+ const name = parts.pop();
7958
+ if (!name) throw new Error('AbsoluteJS embedded asset path is invalid.');
7959
+ const directory = new Directory(root, ...parts);
7960
+ directory.create({ idempotent: true, intermediates: true });
7961
+ const destination = new File(directory, name);
7962
+ if (destination.exists) continue;
7963
+ const asset = await Asset.fromModule(entry.module).downloadAsync();
7964
+ if (!asset.localUri) throw new Error('Expo did not materialize an embedded AbsoluteJS asset.');
7965
+ new File(asset.localUri).copy(destination);
7966
+ }
7967
+
7968
+ return new File(root, 'index.html').uri;
7969
+ };
7970
+ `, syncAbsoluteExpoWebAssets = async (config) => {
7971
+ if (config.engine !== "expo")
7972
+ throw new TypeError("Expo asset sync requires mobile.engine: expo.");
7973
+ const marker = join21(config.nativeProjectDirectory, EXPO_PROJECT_MARKER);
7974
+ if (!await exists2(marker)) {
7975
+ throw new TypeError("Expo asset sync requires an AbsoluteJS-managed Expo project. Run mobile init first.");
7976
+ }
7977
+ const manifestPath = join21(config.bundleDirectory, "absolute-mobile-manifest.json");
7978
+ const manifest = JSON.parse(await readFile11(manifestPath, "utf8"));
7979
+ const appBuild = typeof manifest === "object" && manifest !== null && typeof Reflect.get(manifest, "appBuild") === "string" ? String(Reflect.get(manifest, "appBuild")) : undefined;
7980
+ if (!appBuild)
7981
+ throw new TypeError("AbsoluteJS mobile manifest has no appBuild.");
7982
+ const files = await walkFiles(config.bundleDirectory);
7983
+ const bundleHash = createHash11("sha256");
7984
+ const filesWithContents = await Promise.all(files.map(async (file) => ({ contents: await readFile11(file), file })));
7985
+ filesWithContents.forEach(({ contents, file }) => {
7986
+ bundleHash.update(relative12(config.bundleDirectory, file).replaceAll("\\", "/"));
7987
+ bundleHash.update("\x00");
7988
+ bundleHash.update(contents);
7989
+ bundleHash.update("\x00");
7990
+ });
7991
+ const bundleId = `amexpo_${bundleHash.digest("hex")}`;
7992
+ const destination = join21(config.nativeProjectDirectory, "assets", "absolute");
7993
+ await mkdir10(dirname13(destination), { recursive: true });
7994
+ const staging = await mkdtemp5(join21(dirname13(destination), `.${basename8(destination)}.stage-`));
7995
+ let assets;
7996
+ try {
7997
+ assets = await Promise.all(files.map(async (source, index) => {
7998
+ const name = `${String(index).padStart(6, "0")}${EXPO_ASSET_EXTENSION}`;
7999
+ await cp3(source, join21(staging, name));
8000
+ return {
8001
+ asset: portableRelative2(join21(config.nativeProjectDirectory, "src", "generated"), join21(destination, name)),
8002
+ path: relative12(config.bundleDirectory, source).replaceAll("\\", "/")
8003
+ };
8004
+ }));
8005
+ await installStagedDirectory(staging, destination);
8006
+ } catch (error) {
8007
+ await rm7(staging, { force: true, recursive: true });
8008
+ throw error;
8009
+ }
8010
+ const generated = join21(config.nativeProjectDirectory, "src", "generated", "webAssets.ts");
8011
+ await writeManagedFile(generated, assetModuleSource(assets, bundleId), true);
8012
+ return { appBuild, assets: assets.length, bundleId, path: destination };
8013
+ };
8014
+ var init_expoProject = __esm(() => {
8015
+ layoutSource = `${EXPO_GENERATED_HEADER}import { Stack } from 'expo-router';
8016
+
8017
+ export default function AbsoluteLayout() {
8018
+ return <Stack screenOptions={{ headerShown: false }} />;
8019
+ }
8020
+ `;
8021
+ nativeDiagnosticSource = `${EXPO_GENERATED_HEADER}import * as Haptics from 'expo-haptics';
8022
+ import { Link } from 'expo-router';
8023
+ import { Pressable, SafeAreaView, StyleSheet, Text, View } from 'react-native';
8024
+
8025
+ export default function AbsoluteNativeDiagnostic() {
8026
+ return (
8027
+ <SafeAreaView style={styles.page}>
8028
+ <View style={styles.card}>
8029
+ <Text style={styles.eyebrow}>ABSOLUTEJS \xB7 EXPO EXPERIMENT</Text>
8030
+ <Text style={styles.title}>This screen is native React UI.</Text>
8031
+ <Text style={styles.body}>Ordinary AbsoluteJS routes remain embedded web routes. Only explicitly owned routes use React Native.</Text>
8032
+ <Pressable style={styles.button} onPress={() => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium)}>
8033
+ <Text style={styles.buttonText}>Test native haptics</Text>
8034
+ </Pressable>
8035
+ <Link href="/" style={styles.link}>Open the AbsoluteJS app</Link>
8036
+ </View>
8037
+ </SafeAreaView>
8038
+ );
8039
+ }
8040
+
8041
+ const styles = StyleSheet.create({
8042
+ body: { color: '#cbd5e1', fontSize: 16, lineHeight: 24 },
8043
+ button: { backgroundColor: '#f8fafc', borderRadius: 12, padding: 14 },
8044
+ buttonText: { color: '#020617', fontSize: 16, fontWeight: '700', textAlign: 'center' },
8045
+ card: { backgroundColor: '#0f172a', borderRadius: 24, gap: 20, maxWidth: 560, padding: 28, width: '100%' },
8046
+ eyebrow: { color: '#38bdf8', fontSize: 12, fontWeight: '800', letterSpacing: 1.5 },
8047
+ link: { color: '#7dd3fc', fontSize: 16, textAlign: 'center' },
8048
+ page: { alignItems: 'center', backgroundColor: '#020617', flex: 1, justifyContent: 'center', padding: 20 },
8049
+ title: { color: '#f8fafc', fontSize: 32, fontWeight: '800' }
8050
+ });
8051
+ `;
8052
+ webRouteSource = `${EXPO_GENERATED_HEADER}import { AbsoluteWebHost } from '../src/generated/AbsoluteWebHost';
8053
+
8054
+ export default AbsoluteWebHost;
8055
+ `;
8056
+ catchAllRouteSource = `${EXPO_GENERATED_HEADER}import { AbsoluteWebHost } from '../src/generated/AbsoluteWebHost';
8057
+
8058
+ export default AbsoluteWebHost;
8059
+ `;
8060
+ });
8061
+
7512
8062
  // src/mobile/buildPipeline.ts
7513
- import { readFile as readFile11 } from "fs/promises";
7514
- import { join as join21, resolve as resolve17 } from "path";
8063
+ import { readFile as readFile12 } from "fs/promises";
8064
+ import { join as join22, resolve as resolve18 } from "path";
7515
8065
  import { pathToFileURL } from "url";
7516
8066
  var isElysiaApp = (value) => typeof value === "object" && value !== null && typeof Reflect.get(value, "compile") === "function" && Array.isArray(Reflect.get(value, "routes")), isStringRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && Object.values(value).every((entry) => typeof entry === "string"), serverExportName = (loaded, app) => {
7517
8067
  if (loaded.server === app)
@@ -7540,11 +8090,11 @@ var isElysiaApp = (value) => typeof value === "object" && value !== null && type
7540
8090
  const exportName = serverExportName(loaded, app);
7541
8091
  return { app, exportName };
7542
8092
  }, finalizeAbsoluteMobileCompatibilityBuild = async (options) => {
7543
- const buildDirectory = resolve17(options.buildDirectory);
8093
+ const buildDirectory = resolve18(options.buildDirectory);
7544
8094
  const mobile = normalizeAbsoluteMobileConfig(options.mobile, options.projectRoot);
7545
- const root = join21(buildDirectory, ".absolutejs", "mobile-compatibility");
8095
+ const root = join22(buildDirectory, ".absolutejs", "mobile-compatibility");
7546
8096
  const [manifestSource, previous] = await Promise.all([
7547
- readFile11(join21(buildDirectory, "manifest.json"), "utf8"),
8097
+ readFile12(join22(buildDirectory, "manifest.json"), "utf8"),
7548
8098
  readAbsoluteMobileMaterializedReleases(root)
7549
8099
  ]);
7550
8100
  const manifest = JSON.parse(manifestSource);
@@ -7557,11 +8107,11 @@ var isElysiaApp = (value) => typeof value === "object" && value !== null && type
7557
8107
  process.env.ABSOLUTE_BUILD_DIR = buildDirectory;
7558
8108
  process.env.ABSOLUTE_COMPILED_RUNTIME = "1";
7559
8109
  if (options.configPath) {
7560
- process.env.ABSOLUTE_CONFIG = resolve17(options.projectRoot, options.configPath);
8110
+ process.env.ABSOLUTE_CONFIG = resolve18(options.projectRoot, options.configPath);
7561
8111
  }
7562
8112
  let loaded;
7563
8113
  try {
7564
- loaded = await loadServerApp(resolve17(options.producerPath));
8114
+ loaded = await loadServerApp(resolve18(options.producerPath));
7565
8115
  } finally {
7566
8116
  restoreEnvironmentVariable("ABSOLUTE_BUILD_DIR", previousBuildDirectory);
7567
8117
  restoreEnvironmentVariable("ABSOLUTE_COMPILED_RUNTIME", previousCompiledRuntime);
@@ -7574,19 +8124,27 @@ var isElysiaApp = (value) => typeof value === "object" && value !== null && type
7574
8124
  manifest,
7575
8125
  previousArtifacts: previous.map(({ artifact }) => artifact),
7576
8126
  producerExport: loaded.exportName,
7577
- producerPath: resolve17(options.producerPath),
8127
+ producerPath: resolve18(options.producerPath),
7578
8128
  runtime: String(ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION)
7579
8129
  });
7580
8130
  const auth = resolveAbsoluteMobileAuthManifest(options.projectRoot, mobile);
8131
+ if (mobile.engine === "expo" && auth) {
8132
+ throw new TypeError("Expo mobile Auth is not released yet. The experimental Expo shell cannot safely substitute Capacitor credentials; remove engine: 'expo' or wait for @absolutejs/auth-expo.");
8133
+ }
7581
8134
  const sync = auth !== undefined && projectUsesAbsoluteSync(options.projectRoot);
7582
8135
  const syncSchema = sync ? discoverAbsoluteSyncSchema(options.projectRoot) : undefined;
7583
8136
  const deviceCapabilities = resolveAbsoluteDeviceCapabilityPlan(options.projectRoot);
7584
8137
  const usesPush = deviceCapabilities.capabilities.includes("pushNotifications");
8138
+ if (mobile.engine === "expo" && deviceCapabilities.capabilities.some((capability) => capability !== "haptics")) {
8139
+ throw new TypeError("Experimental Expo builds currently bridge only @absolutejs/devices haptics. Other detected device capabilities require their Expo adapters.");
8140
+ }
7585
8141
  if (usesPush && !auth)
7586
8142
  throw new TypeError("Portable push notifications require @absolutejs/auth so provider tokens can be registered without exposing identity controls to page code.");
7587
8143
  if (usesPush && !loaded.app.routes.some((route) => route.path === "/auth/push" || route.path === "/auth/mobile/push"))
7588
8144
  throw new TypeError("@absolutejs/devices pushNotifications is used, but Auth push is not configured. Pass a trusted server-side registrar to auth({ push: ... }).");
7589
- assertAbsoluteDeviceCapabilityPackages(options.projectRoot, deviceCapabilities);
8145
+ if (mobile.engine === "capacitor") {
8146
+ assertAbsoluteDeviceCapabilityPackages(options.projectRoot, deviceCapabilities);
8147
+ }
7590
8148
  if (auth && !loaded.app.routes.some((route) => route.path === "/.well-known/openid-configuration")) {
7591
8149
  throw new TypeError("@absolutejs/auth is installed, but its OIDC provider is not mounted. Native authentication requires the auth oidc configuration so AbsoluteJS can provision a public PKCE client.");
7592
8150
  }
@@ -7610,6 +8168,12 @@ var isElysiaApp = (value) => typeof value === "object" && value !== null && type
7610
8168
  ...sync ? { sync: true } : {},
7611
8169
  ...syncSchema ? { syncSchema: { components: syncSchema.components } } : {}
7612
8170
  });
8171
+ if (mobile.engine === "expo") {
8172
+ await writeAbsoluteExpoProject(mobile, {
8173
+ projectRoot: options.projectRoot
8174
+ });
8175
+ await syncAbsoluteExpoWebAssets(mobile);
8176
+ }
7613
8177
  return current.artifact;
7614
8178
  };
7615
8179
  var init_buildPipeline = __esm(() => {
@@ -7622,13 +8186,14 @@ var init_buildPipeline = __esm(() => {
7622
8186
  init_nativeAuth();
7623
8187
  init_syncSchema();
7624
8188
  init_deviceCapabilities();
8189
+ init_expoProject();
7625
8190
  });
7626
8191
 
7627
8192
  // src/mobile/routeMetadataTransform.ts
7628
8193
  import { existsSync as existsSync10, readFileSync as readFileSync13 } from "fs";
7629
- import { dirname as dirname13, extname as extname6, relative as relative12, resolve as resolve18 } from "path";
8194
+ import { dirname as dirname14, extname as extname6, relative as relative13, resolve as resolve19 } from "path";
7630
8195
  import ts5 from "typescript";
7631
- var ROUTE_METHODS, SOURCE_FILTER, PAGE_HANDLERS, posixPath = (value) => value.replace(/\\/g, "/"), findTsconfig = (entry, projectRoot) => ts5.findConfigFile(dirname13(entry), existsSync10, "tsconfig.json") ?? ts5.findConfigFile(projectRoot, existsSync10, "tsconfig.json"), createProgram = (entry, projectRoot) => {
8196
+ 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) => {
7632
8197
  const configPath2 = findTsconfig(entry, projectRoot);
7633
8198
  if (!configPath2) {
7634
8199
  return ts5.createProgram([entry], {
@@ -7639,7 +8204,7 @@ var ROUTE_METHODS, SOURCE_FILTER, PAGE_HANDLERS, posixPath = (value) => value.re
7639
8204
  target: ts5.ScriptTarget.ESNext
7640
8205
  });
7641
8206
  }
7642
- const parsed = ts5.parseJsonConfigFileContent(ts5.readConfigFile(configPath2, (path) => readFileSync13(path, "utf8")).config, ts5.sys, dirname13(configPath2));
8207
+ const parsed = ts5.parseJsonConfigFileContent(ts5.readConfigFile(configPath2, (path) => readFileSync13(path, "utf8")).config, ts5.sys, dirname14(configPath2));
7643
8208
  if (!parsed.fileNames.includes(entry))
7644
8209
  parsed.fileNames.push(entry);
7645
8210
  return ts5.createProgram(parsed.fileNames, parsed.options);
@@ -7740,7 +8305,7 @@ var ROUTE_METHODS, SOURCE_FILTER, PAGE_HANDLERS, posixPath = (value) => value.re
7740
8305
  const declaration = symbol?.declarations?.[0];
7741
8306
  const file = declaration?.getSourceFile().fileName ?? sourceFile.fileName;
7742
8307
  const exportedName = symbol?.name ?? expression.getText(sourceFile);
7743
- const source = posixPath(relative12(projectRoot, file));
8308
+ const source = posixPath(relative13(projectRoot, file));
7744
8309
  return `${source}#${exportedName}`;
7745
8310
  }, resolveAlias = (symbol, checker) => {
7746
8311
  if (!(symbol.flags & ts5.SymbolFlags.Alias))
@@ -7967,7 +8532,7 @@ var ROUTE_METHODS, SOURCE_FILTER, PAGE_HANDLERS, posixPath = (value) => value.re
7967
8532
  const checker = program.getTypeChecker();
7968
8533
  const analyzed = new Map;
7969
8534
  for (const sourceFile of program.getSourceFiles()) {
7970
- const resolvedFile = resolve18(sourceFile.fileName);
8535
+ const resolvedFile = resolve19(sourceFile.fileName);
7971
8536
  if (!isProjectSource(sourceFile, resolvedFile, projectRoot))
7972
8537
  continue;
7973
8538
  const analysis = analyzeSourceFile(sourceFile, checker, projectRoot);
@@ -8053,14 +8618,14 @@ var ROUTE_METHODS, SOURCE_FILTER, PAGE_HANDLERS, posixPath = (value) => value.re
8053
8618
  result.dispose();
8054
8619
  }
8055
8620
  }, createAbsoluteMobileRouteMetadataPlugin = (options) => {
8056
- const projectRoot = resolve18(options.projectRoot ?? process.cwd());
8057
- const entry = resolve18(options.entry);
8621
+ const projectRoot = resolve19(options.projectRoot ?? process.cwd());
8622
+ const entry = resolve19(options.entry);
8058
8623
  const analyzed = analyzeProgram(createProgram(entry, projectRoot), projectRoot);
8059
8624
  return {
8060
8625
  name: "absolute-mobile-route-metadata",
8061
8626
  setup(build) {
8062
8627
  build.onLoad({ filter: SOURCE_FILTER }, async ({ path }) => {
8063
- const analysis = analyzed.get(resolve18(path));
8628
+ const analysis = analyzed.get(resolve19(path));
8064
8629
  if (!analysis)
8065
8630
  return;
8066
8631
  const source = await Bun.file(path).text();
@@ -8127,7 +8692,7 @@ var init_routeMetadataTransform = __esm(() => {
8127
8692
  });
8128
8693
 
8129
8694
  // src/cli/elysiaOpenApiTypeboxPlugin.ts
8130
- import { dirname as dirname14, resolve as resolve19 } from "path";
8695
+ import { dirname as dirname15, resolve as resolve20 } from "path";
8131
8696
  var OPENAPI_TYPEBOX_PREFIX = "../node_modules/typebox/", OPENAPI_DISTRIBUTION_SEGMENT = "/@elysia/openapi/dist/", createElysiaOpenApiTypeboxPlugin = () => ({
8132
8697
  name: "absolute-elysia-openapi-typebox",
8133
8698
  setup(build) {
@@ -8137,9 +8702,9 @@ var OPENAPI_TYPEBOX_PREFIX = "../node_modules/typebox/", OPENAPI_DISTRIBUTION_SE
8137
8702
  return;
8138
8703
  }
8139
8704
  const relativePath = args.path.slice(OPENAPI_TYPEBOX_PREFIX.length);
8140
- const typeboxEntry = Bun.resolveSync("typebox", dirname14(args.importer));
8705
+ const typeboxEntry = Bun.resolveSync("typebox", dirname15(args.importer));
8141
8706
  return {
8142
- path: resolve19(dirname14(typeboxEntry), "..", relativePath)
8707
+ path: resolve20(dirname15(typeboxEntry), "..", relativePath)
8143
8708
  };
8144
8709
  });
8145
8710
  }
@@ -8200,7 +8765,7 @@ __export(exports_prerender, {
8200
8765
  PRERENDER_BYPASS_HEADER: () => PRERENDER_BYPASS_HEADER
8201
8766
  });
8202
8767
  import { mkdirSync as mkdirSync6, readFileSync as readFileSync14 } from "fs";
8203
- import { join as join22 } from "path";
8768
+ import { join as join23 } from "path";
8204
8769
  var SERVER_OUTPUT_LIMIT = 4000, STARTUP_POLL_INTERVAL_MS = 100, DEFAULT_STARTUP_TIMEOUT_MS = 30000, DEFAULT_FETCH_TIMEOUT_MS = 1e4, PRERENDER_BYPASS_HEADER = "X-Absolute-Prerender-Bypass", routeToFilename = (route) => route === "/" ? "index.html" : `${route.slice(1).replace(/\//g, "-")}.html`, writeTimestamp = async (htmlPath) => {
8205
8770
  const metaPath = htmlPath.replace(/\.html$/, ".meta");
8206
8771
  await Bun.write(metaPath, String(Date.now()));
@@ -8270,7 +8835,7 @@ var SERVER_OUTPUT_LIMIT = 4000, STARTUP_POLL_INTERVAL_MS = 100, DEFAULT_STARTUP_
8270
8835
  if (!isCompleteHtml(html))
8271
8836
  return false;
8272
8837
  const fileName = routeToFilename(route);
8273
- const filePath = join22(prerenderDir, fileName);
8838
+ const filePath = join23(prerenderDir, fileName);
8274
8839
  await Bun.write(filePath, html);
8275
8840
  await writeTimestamp(filePath);
8276
8841
  return true;
@@ -8300,13 +8865,13 @@ var SERVER_OUTPUT_LIMIT = 4000, STARTUP_POLL_INTERVAL_MS = 100, DEFAULT_STARTUP_
8300
8865
  return;
8301
8866
  }
8302
8867
  const fileName = routeToFilename(route);
8303
- const filePath = join22(prerenderDir, fileName);
8868
+ const filePath = join23(prerenderDir, fileName);
8304
8869
  await Bun.write(filePath, html);
8305
8870
  await writeTimestamp(filePath);
8306
8871
  result.routes.set(route, filePath);
8307
8872
  log?.(` Pre-rendered ${route} \u2192 ${fileName} (${html.length} bytes)`);
8308
8873
  }, prerender = async (port, outDir, staticConfig, log) => {
8309
- const prerenderDir = join22(outDir, "_prerendered");
8874
+ const prerenderDir = join23(outDir, "_prerendered");
8310
8875
  mkdirSync6(prerenderDir, { recursive: true });
8311
8876
  const baseUrl = `http://localhost:${port}`;
8312
8877
  let routes;
@@ -8682,7 +9247,7 @@ var init_maskLiterals = __esm(() => {
8682
9247
  // src/build/nativeRewrite.ts
8683
9248
  import { dlopen, FFIType, ptr } from "bun:ffi";
8684
9249
  import { platform as platform4, arch as arch3 } from "os";
8685
- import { resolve as resolve20 } from "path";
9250
+ import { resolve as resolve21 } from "path";
8686
9251
  var ffiDefinition, nativeLib = null, loadNative = () => {
8687
9252
  if (nativeLib !== null)
8688
9253
  return nativeLib;
@@ -8700,7 +9265,7 @@ var ffiDefinition, nativeLib = null, loadNative = () => {
8700
9265
  if (!libPath)
8701
9266
  return null;
8702
9267
  try {
8703
- const fullPath = resolve20(import.meta.dir, "../../native/packages", libPath);
9268
+ const fullPath = resolve21(import.meta.dir, "../../native/packages", libPath);
8704
9269
  const lib = dlopen(fullPath, ffiDefinition);
8705
9270
  nativeLib = lib.symbols;
8706
9271
  return nativeLib;
@@ -8741,8 +9306,8 @@ var init_nativeRewrite = __esm(() => {
8741
9306
  });
8742
9307
 
8743
9308
  // src/build/rewriteImportsPlugin.ts
8744
- import { readdir as readdir3 } from "fs/promises";
8745
- import { join as join23 } from "path";
9309
+ import { readdir as readdir4 } from "fs/promises";
9310
+ import { join as join24 } from "path";
8746
9311
  var escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), jsRewriteImports = (content, replacements) => {
8747
9312
  let result = content;
8748
9313
  for (const [specifier, webPath] of replacements) {
@@ -8818,10 +9383,10 @@ ${content}`;
8818
9383
  const allFiles = [];
8819
9384
  for (const dir of vendorDirs) {
8820
9385
  try {
8821
- const entries = await readdir3(dir);
9386
+ const entries = await readdir4(dir);
8822
9387
  for (const entry of entries) {
8823
9388
  if (entry.endsWith(".js"))
8824
- allFiles.push(join23(dir, entry));
9389
+ allFiles.push(join24(dir, entry));
8825
9390
  }
8826
9391
  } catch {}
8827
9392
  }
@@ -8897,7 +9462,7 @@ var init_rewriteImports = __esm(() => {
8897
9462
  // src/cli/scripts/start.ts
8898
9463
  var {env: env2 } = globalThis.Bun;
8899
9464
  import { existsSync as existsSync11, readFileSync as readFileSync15, rmSync as rmSync4 } from "fs";
8900
- import { basename as basename8, join as join24, resolve as resolve21 } from "path";
9465
+ import { basename as basename9, join as join25, resolve as resolve22 } from "path";
8901
9466
  var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`, resolvePackageVersion = (candidates) => {
8902
9467
  for (const candidate of candidates) {
8903
9468
  const version2 = readPackageVersion2(candidate);
@@ -8946,18 +9511,18 @@ var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
8946
9511
  process.exit(1);
8947
9512
  }, resolveJsxDevRuntimeCompatPath = () => {
8948
9513
  const candidates = [
8949
- resolve21(import.meta.dir, "..", "..", "dist", "react", "jsxDevRuntimeCompat.js"),
8950
- resolve21(import.meta.dir, "..", "..", "react", "jsxDevRuntimeCompat.js"),
8951
- resolve21(import.meta.dir, "..", "..", "react", "jsxDevRuntimeCompat.ts"),
8952
- resolve21(import.meta.dir, "..", "..", "..", "dist", "react", "jsxDevRuntimeCompat.js"),
8953
- resolve21(import.meta.dir, "..", "..", "..", "react", "jsxDevRuntimeCompat.js"),
8954
- resolve21(import.meta.dir, "..", "..", "..", "src", "react", "jsxDevRuntimeCompat.ts")
9514
+ resolve22(import.meta.dir, "..", "..", "dist", "react", "jsxDevRuntimeCompat.js"),
9515
+ resolve22(import.meta.dir, "..", "..", "react", "jsxDevRuntimeCompat.js"),
9516
+ resolve22(import.meta.dir, "..", "..", "react", "jsxDevRuntimeCompat.ts"),
9517
+ resolve22(import.meta.dir, "..", "..", "..", "dist", "react", "jsxDevRuntimeCompat.js"),
9518
+ resolve22(import.meta.dir, "..", "..", "..", "react", "jsxDevRuntimeCompat.js"),
9519
+ resolve22(import.meta.dir, "..", "..", "..", "src", "react", "jsxDevRuntimeCompat.ts")
8955
9520
  ];
8956
9521
  for (const candidate of candidates) {
8957
9522
  if (existsSync11(candidate))
8958
9523
  return candidate;
8959
9524
  }
8960
- return resolve21(import.meta.dir, "..", "..", "react", "jsxDevRuntimeCompat.js");
9525
+ return resolve22(import.meta.dir, "..", "..", "react", "jsxDevRuntimeCompat.js");
8961
9526
  }, jsxDevRuntimeCompatPath, prerenderStaticPages = async (outputPath, prerenderPort, resolvedOutdir, staticConfig, absoluteVersion, configPath2) => {
8962
9527
  const prerenderStart = performance.now();
8963
9528
  process.stdout.write(cliTag2("\x1B[36m", "Pre-rendering static pages"));
@@ -8991,7 +9556,7 @@ var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
8991
9556
  serverEntry,
8992
9557
  totalDuration
8993
9558
  }) => {
8994
- const usesDocker = existsSync11(resolve21(COMPOSE_PATH));
9559
+ const usesDocker = existsSync11(resolve22(COMPOSE_PATH));
8995
9560
  const scripts = usesDocker ? await readDbScripts() : null;
8996
9561
  if (scripts)
8997
9562
  await startDatabase(scripts);
@@ -9081,11 +9646,11 @@ var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
9081
9646
  }
9082
9647
  const port = Number(env2.PORT) || DEFAULT_PORT;
9083
9648
  killStaleProcesses(port);
9084
- const entryName = basename8(serverEntry).replace(/\.[^.]+$/, "");
9085
- const resolvedOutdir = resolve21(outdir ?? "dist");
9649
+ const entryName = basename9(serverEntry).replace(/\.[^.]+$/, "");
9650
+ const resolvedOutdir = resolve22(outdir ?? "dist");
9086
9651
  const absoluteVersion = resolvePackageVersion([
9087
- resolve21(import.meta.dir, "..", "..", "..", "package.json"),
9088
- resolve21(import.meta.dir, "..", "..", "package.json")
9652
+ resolve22(import.meta.dir, "..", "..", "..", "package.json"),
9653
+ resolve22(import.meta.dir, "..", "..", "package.json")
9089
9654
  ]);
9090
9655
  const buildConfig = await loadConfig(configPath2);
9091
9656
  buildConfig.buildDirectory = resolvedOutdir;
@@ -9100,7 +9665,7 @@ var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
9100
9665
  buildConfig.vueDirectory && "vue",
9101
9666
  buildConfig.angularDirectory && "angular"
9102
9667
  ].filter((val) => Boolean(val));
9103
- const outputPath = resolve21(resolvedOutdir, `${entryName}.js`);
9668
+ const outputPath = resolve22(resolvedOutdir, `${entryName}.js`);
9104
9669
  if (options.prebuilt) {
9105
9670
  if (!existsSync11(outputPath)) {
9106
9671
  throw new Error(`Prepared production server not found: ${outputPath}`);
@@ -9123,13 +9688,13 @@ var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
9123
9688
  process.stdout.write(cliTag2("\x1B[36m", `Building assets`));
9124
9689
  try {
9125
9690
  const build = await resolveBuildModule([
9126
- resolve21(import.meta.dir, "..", "..", "core", "build"),
9127
- resolve21(import.meta.dir, "..", "build")
9691
+ resolve22(import.meta.dir, "..", "..", "core", "build"),
9692
+ resolve22(import.meta.dir, "..", "build")
9128
9693
  ]);
9129
9694
  if (!build)
9130
9695
  throw new Error("Could not locate build module");
9131
9696
  await build(buildConfig);
9132
- rmSync4(join24(resolvedOutdir, "_prerendered"), {
9697
+ rmSync4(join25(resolvedOutdir, "_prerendered"), {
9133
9698
  force: true,
9134
9699
  recursive: true
9135
9700
  });
@@ -9206,17 +9771,17 @@ var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
9206
9771
  }
9207
9772
  };
9208
9773
  const islandRegistrySpec = buildConfig.islands?.registry;
9209
- const islandRegistryPlugin = islandRegistrySpec ? createIslandRegistryDefinitionPlugin(await loadIslandRegistryBuildInfo(resolve21(islandRegistrySpec))) : undefined;
9774
+ const islandRegistryPlugin = islandRegistrySpec ? createIslandRegistryDefinitionPlugin(await loadIslandRegistryBuildInfo(resolve22(islandRegistrySpec))) : undefined;
9210
9775
  const serverBundle = await Bun.build({
9211
9776
  define: { "process.env.NODE_ENV": '"production"' },
9212
- entrypoints: [resolve21(serverEntry)],
9777
+ entrypoints: [resolve22(serverEntry)],
9213
9778
  external: resolveServerBundleExternals(buildConfig),
9214
9779
  outdir: resolvedOutdir,
9215
9780
  plugins: [
9216
9781
  ...islandRegistryPlugin ? [islandRegistryPlugin] : [],
9217
9782
  ...buildConfig.mobile ? [
9218
9783
  createAbsoluteMobileRouteMetadataPlugin({
9219
- entry: resolve21(serverEntry)
9784
+ entry: resolve22(serverEntry)
9220
9785
  })
9221
9786
  ] : [],
9222
9787
  createElysiaOpenApiTypeboxPlugin(),
@@ -9233,9 +9798,9 @@ var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
9233
9798
  console.error(cliTag2("\x1B[31m", `Expected output not found: ${outputPath}`));
9234
9799
  process.exit(1);
9235
9800
  }
9236
- if (existsSync11(resolve21(resolvedOutdir, "angular", "vendor", "server"))) {
9801
+ if (existsSync11(resolve22(resolvedOutdir, "angular", "vendor", "server"))) {
9237
9802
  const { readdirSync: readdirSync2 } = await import("fs");
9238
- const vendorDir = resolve21(resolvedOutdir, "angular", "vendor", "server");
9803
+ const vendorDir = resolve22(resolvedOutdir, "angular", "vendor", "server");
9239
9804
  const vendorEntries = readdirSync2(vendorDir).filter((fileName) => fileName.endsWith(".js"));
9240
9805
  const angularServerVendorPaths = {};
9241
9806
  const { relative: pathRelative, dirname: pathDirname } = await import("path");
@@ -9245,7 +9810,7 @@ var cliTag2 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
9245
9810
  if (scope !== "angular" || rest.length === 0)
9246
9811
  continue;
9247
9812
  const specifier = `@angular/${rest.join("/")}`;
9248
- const relPath = pathRelative(pathDirname(outputPath), resolve21(vendorDir, file));
9813
+ const relPath = pathRelative(pathDirname(outputPath), resolve22(vendorDir, file));
9249
9814
  angularServerVendorPaths[specifier] = relPath.startsWith(".") ? relPath : `./${relPath}`;
9250
9815
  }
9251
9816
  if (Object.keys(angularServerVendorPaths).length > 0) {
@@ -9433,16 +9998,16 @@ __export(exports_build, {
9433
9998
  build: () => build
9434
9999
  });
9435
10000
  import { existsSync as existsSync13, readdirSync as readdirSync3, readFileSync as readFileSync17 } from "fs";
9436
- import { join as join25, resolve as resolve23 } from "path";
10001
+ import { join as join26, resolve as resolve24 } from "path";
9437
10002
  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) => {
9438
- const traceDir = join25(buildDir, ".absolute-trace");
10003
+ const traceDir = join26(buildDir, ".absolute-trace");
9439
10004
  if (!existsSync13(traceDir))
9440
10005
  return;
9441
10006
  const files = readdirSync3(traceDir).filter((file) => file.endsWith(".json")).sort();
9442
10007
  const latest = files[files.length - 1];
9443
10008
  if (latest === undefined)
9444
10009
  return;
9445
- const trace = JSON.parse(readFileSync17(join25(traceDir, latest), "utf-8"));
10010
+ const trace = JSON.parse(readFileSync17(join26(traceDir, latest), "utf-8"));
9446
10011
  const events = Array.isArray(trace.events) ? trace.events : [];
9447
10012
  if (events.length === 0)
9448
10013
  return;
@@ -9479,7 +10044,7 @@ var PROFILE_TOP = 15, PROFILE_COL = 8, FRAMEWORK_KEYS, cliTag3 = (color, message
9479
10044
  }
9480
10045
  return resolveBuildModule2(remaining);
9481
10046
  }, build = async (outdir, configPath2, profile = false) => {
9482
- const resolvedOutdir = resolve23(outdir ?? "build");
10047
+ const resolvedOutdir = resolve24(outdir ?? "build");
9483
10048
  const buildStart = performance.now();
9484
10049
  if (profile)
9485
10050
  process.env.ABSOLUTE_BUILD_TRACE = "1";
@@ -9489,8 +10054,8 @@ var PROFILE_TOP = 15, PROFILE_COL = 8, FRAMEWORK_KEYS, cliTag3 = (color, message
9489
10054
  buildConfig.mode = "production";
9490
10055
  try {
9491
10056
  const buildApp = await resolveBuildModule2([
9492
- resolve23(import.meta.dir, "..", "..", "core", "build"),
9493
- resolve23(import.meta.dir, "..", "build")
10057
+ resolve24(import.meta.dir, "..", "..", "core", "build"),
10058
+ resolve24(import.meta.dir, "..", "build")
9494
10059
  ]);
9495
10060
  if (!buildApp)
9496
10061
  throw new Error("Could not locate build module");
@@ -9528,7 +10093,7 @@ __export(exports_lintProof, {
9528
10093
  createLintProof: () => createLintProof
9529
10094
  });
9530
10095
  import {
9531
- createHash as createHash11,
10096
+ createHash as createHash12,
9532
10097
  createPrivateKey,
9533
10098
  createPublicKey,
9534
10099
  sign,
@@ -9546,7 +10111,7 @@ import {
9546
10111
  writeFileSync as writeFileSync7
9547
10112
  } from "fs";
9548
10113
  import { tmpdir as tmpdir3 } from "os";
9549
- import { delimiter, dirname as dirname15, relative as relative13, resolve as resolve24 } from "path";
10114
+ import { delimiter, dirname as dirname16, relative as relative14, resolve as resolve25 } from "path";
9550
10115
  var DEFAULT_PROOF_LOCATION = ".absolutejs/lint-proof.json", PROOF_CONTRACT_VERSION = 2, FLAG_NOT_FOUND = -1, CHUNKED_FLAG = "--chunked", TSCONFIG_PATTERN, ABSOLUTE_BINARY, runGit = (args, options) => {
9551
10116
  const proc = Bun.spawnSync(["git", ...args], {
9552
10117
  cwd: options.cwd,
@@ -9559,8 +10124,8 @@ var DEFAULT_PROOF_LOCATION = ".absolutejs/lint-proof.json", PROOF_CONTRACT_VERSI
9559
10124
  throw new Error(detail || `git ${args.join(" ")} failed`);
9560
10125
  }
9561
10126
  return proc.stdout.toString().trim();
9562
- }, gitRoot = (cwd) => resolve24(runGit(["rev-parse", "--show-toplevel"], { cwd })), isInside3 = (parent, candidate) => {
9563
- const path = relative13(parent, candidate);
10127
+ }, gitRoot = (cwd) => resolve25(runGit(["rev-parse", "--show-toplevel"], { cwd })), isInside3 = (parent, candidate) => {
10128
+ const path = relative14(parent, candidate);
9564
10129
  return path === "" || !path.startsWith("../") && path !== "..";
9565
10130
  }, attestationPayload = (proof) => Buffer.from([
9566
10131
  "absolute-lint-proof-attestation:1",
@@ -9571,8 +10136,8 @@ var DEFAULT_PROOF_LOCATION = ".absolutejs/lint-proof.json", PROOF_CONTRACT_VERSI
9571
10136
  lintFingerprint: proof.lintFingerprint,
9572
10137
  sourceTree: proof.sourceTree
9573
10138
  })
9574
- ].join("\x00")), publicKeyId = (key) => createHash11("sha256").update(key.export({ format: "der", type: "spki" })).digest("hex"), readEd25519PrivateKey = (cwd, location) => {
9575
- const path = resolve24(cwd, location);
10139
+ ].join("\x00")), publicKeyId = (key) => createHash12("sha256").update(key.export({ format: "der", type: "spki" })).digest("hex"), readEd25519PrivateKey = (cwd, location) => {
10140
+ const path = resolve25(cwd, location);
9576
10141
  if (isInside3(realpathSync(gitRoot(cwd)), realpathSync(path))) {
9577
10142
  throw new Error("lint proof signing key must live outside the Git working tree");
9578
10143
  }
@@ -9582,7 +10147,7 @@ var DEFAULT_PROOF_LOCATION = ".absolutejs/lint-proof.json", PROOF_CONTRACT_VERSI
9582
10147
  }
9583
10148
  return key;
9584
10149
  }, readEd25519PublicKey = (cwd, location) => {
9585
- const key = createPublicKey(readFileSync18(resolve24(cwd, location)));
10150
+ const key = createPublicKey(readFileSync18(resolve25(cwd, location)));
9586
10151
  if (key.asymmetricKeyType !== "ed25519") {
9587
10152
  throw new Error("trusted lint proof key must be an Ed25519 public key");
9588
10153
  }
@@ -9610,7 +10175,7 @@ var DEFAULT_PROOF_LOCATION = ".absolutejs/lint-proof.json", PROOF_CONTRACT_VERSI
9610
10175
  return null;
9611
10176
  const auxiliary = gitVisibleFiles(root).filter((file) => TSCONFIG_PATTERN.test(file));
9612
10177
  const configPath2 = findEslintConfigPath(root);
9613
- const configRelative = configPath2 === null ? null : relative13(root, configPath2).replaceAll("\\", "/");
10178
+ const configRelative = configPath2 === null ? null : relative14(root, configPath2).replaceAll("\\", "/");
9614
10179
  return [
9615
10180
  ...new Set([
9616
10181
  ...resolveLintTargets(args, root),
@@ -9620,17 +10185,17 @@ var DEFAULT_PROOF_LOCATION = ".absolutejs/lint-proof.json", PROOF_CONTRACT_VERSI
9620
10185
  ].sort();
9621
10186
  }, createLintSourceTree = (cwd = process.cwd(), proofLocation = DEFAULT_PROOF_LOCATION, command = []) => {
9622
10187
  const root = gitRoot(cwd);
9623
- const proofPath = resolve24(cwd, proofLocation);
9624
- const proofRelative = relative13(root, proofPath).replaceAll("\\", "/");
10188
+ const proofPath = resolve25(cwd, proofLocation);
10189
+ const proofRelative = relative14(root, proofPath).replaceAll("\\", "/");
9625
10190
  if (proofRelative === ".." || proofRelative.startsWith("../") || proofRelative === "") {
9626
10191
  throw new Error("lint proof must live inside the Git working tree");
9627
10192
  }
9628
- const temporaryDirectory = mkdtempSync(resolve24(tmpdir3(), "absolute-lint-proof-"));
9629
- const temporaryIndex = resolve24(temporaryDirectory, "index");
9630
- const temporaryObjects = resolve24(temporaryDirectory, "objects");
10193
+ const temporaryDirectory = mkdtempSync(resolve25(tmpdir3(), "absolute-lint-proof-"));
10194
+ const temporaryIndex = resolve25(temporaryDirectory, "index");
10195
+ const temporaryObjects = resolve25(temporaryDirectory, "objects");
9631
10196
  mkdirSync8(temporaryObjects, { recursive: true });
9632
10197
  const repositoryObjectsPath = runGit(["rev-parse", "--git-path", "objects"], { cwd: root });
9633
- const repositoryObjects = resolve24(root, repositoryObjectsPath);
10198
+ const repositoryObjects = resolve25(root, repositoryObjectsPath);
9634
10199
  const existingAlternates = process.env.GIT_ALTERNATE_OBJECT_DIRECTORIES?.trim();
9635
10200
  const env3 = {
9636
10201
  GIT_ALTERNATE_OBJECT_DIRECTORIES: [
@@ -9654,7 +10219,7 @@ var DEFAULT_PROOF_LOCATION = ".absolutejs/lint-proof.json", PROOF_CONTRACT_VERSI
9654
10219
  if (!path || path === proofRelative)
9655
10220
  return false;
9656
10221
  try {
9657
- lstatSync(resolve24(root, path));
10222
+ lstatSync(resolve25(root, path));
9658
10223
  return true;
9659
10224
  } catch {
9660
10225
  return false;
@@ -9665,7 +10230,7 @@ var DEFAULT_PROOF_LOCATION = ".absolutejs/lint-proof.json", PROOF_CONTRACT_VERSI
9665
10230
  } finally {
9666
10231
  rmSync5(temporaryDirectory, { force: true, recursive: true });
9667
10232
  }
9668
- }, proofFingerprint = (cwd) => createHash11("sha256").update(`absolute-lint-proof:${PROOF_CONTRACT_VERSION}\x00`).update(createEslintCacheFingerprint(cwd)).update("\x00").update(createEslintConfigDigest(cwd)).digest("hex"), createLintProof = (command, options = {}) => {
10233
+ }, proofFingerprint = (cwd) => createHash12("sha256").update(`absolute-lint-proof:${PROOF_CONTRACT_VERSION}\x00`).update(createEslintCacheFingerprint(cwd)).update("\x00").update(createEslintConfigDigest(cwd)).digest("hex"), createLintProof = (command, options = {}) => {
9669
10234
  const cwd = options.cwd ?? process.cwd();
9670
10235
  const proofLocation = options.proofLocation ?? DEFAULT_PROOF_LOCATION;
9671
10236
  return {
@@ -9678,7 +10243,7 @@ var DEFAULT_PROOF_LOCATION = ".absolutejs/lint-proof.json", PROOF_CONTRACT_VERSI
9678
10243
  }, writeLintProof = (command, options = {}) => {
9679
10244
  const cwd = options.cwd ?? process.cwd();
9680
10245
  const proofLocation = options.proofLocation ?? DEFAULT_PROOF_LOCATION;
9681
- const path = resolve24(cwd, proofLocation);
10246
+ const path = resolve25(cwd, proofLocation);
9682
10247
  const temporary = `${path}.${process.pid}.tmp`;
9683
10248
  const proof = createLintProof(command, { cwd, proofLocation });
9684
10249
  if (options.signingKeyLocation) {
@@ -9690,7 +10255,7 @@ var DEFAULT_PROOF_LOCATION = ".absolutejs/lint-proof.json", PROOF_CONTRACT_VERSI
9690
10255
  signature: sign(null, attestationPayload(proof), privateKey).toString("base64")
9691
10256
  };
9692
10257
  }
9693
- mkdirSync8(dirname15(path), { recursive: true });
10258
+ mkdirSync8(dirname16(path), { recursive: true });
9694
10259
  writeFileSync7(temporary, `${JSON.stringify(proof, null, 2)}
9695
10260
  `);
9696
10261
  renameSync2(temporary, path);
@@ -9734,7 +10299,7 @@ var DEFAULT_PROOF_LOCATION = ".absolutejs/lint-proof.json", PROOF_CONTRACT_VERSI
9734
10299
  }, verifyLintProof = (command, options = {}) => {
9735
10300
  const cwd = options.cwd ?? process.cwd();
9736
10301
  const proofLocation = options.proofLocation ?? DEFAULT_PROOF_LOCATION;
9737
- const path = resolve24(cwd, proofLocation);
10302
+ const path = resolve25(cwd, proofLocation);
9738
10303
  if (!existsSync14(path))
9739
10304
  return { reason: `missing lint proof: ${proofLocation}`, valid: false };
9740
10305
  let proof;
@@ -9850,11 +10415,11 @@ var init_lintProof = __esm(() => {
9850
10415
  });
9851
10416
 
9852
10417
  // src/build/scanConventions.ts
9853
- import { basename as basename9 } from "path";
10418
+ import { basename as basename10 } from "path";
9854
10419
  var {Glob: Glob2 } = globalThis.Bun;
9855
10420
  import { existsSync as existsSync15 } from "fs";
9856
10421
  var CONVENTION_RE, classifyFile = (file, pageFiles, defaults, pages) => {
9857
- const fileName = basename9(file);
10422
+ const fileName = basename10(file);
9858
10423
  const match = CONVENTION_RE.exec(fileName);
9859
10424
  if (!match) {
9860
10425
  pageFiles.push(file);
@@ -9905,7 +10470,7 @@ __export(exports_ls, {
9905
10470
  runLs: () => runLs
9906
10471
  });
9907
10472
  import { existsSync as existsSync16, readFileSync as readFileSync19, statSync } from "fs";
9908
- import { basename as basename10, extname as extname7, join as join26, relative as relative14 } from "path";
10473
+ import { basename as basename11, extname as extname7, join as join27, relative as relative15 } from "path";
9909
10474
  var DEFAULT_BUILD_DIR = "build", LABEL_ORDER, ARTIFACT_SUFFIXES, FRAMEWORK_FIELDS, readStringField = (source, key) => {
9910
10475
  const value = Reflect.get(source, key);
9911
10476
  return typeof value === "string" ? value : undefined;
@@ -9920,24 +10485,24 @@ var DEFAULT_BUILD_DIR = "build", LABEL_ORDER, ARTIFACT_SUFFIXES, FRAMEWORK_FIELD
9920
10485
  } catch {
9921
10486
  return null;
9922
10487
  }
9923
- }, relativeOrSelf = (target) => relative14(process.cwd(), target) || target, configCandidates = (raw) => isWorkspaceConfig(raw) ? Object.values(raw).map((service) => ({
10488
+ }, relativeOrSelf = (target) => relative15(process.cwd(), target) || target, configCandidates = (raw) => isWorkspaceConfig(raw) ? Object.values(raw).map((service) => ({
9924
10489
  baseDir: readStringField(service, "cwd") ?? ".",
9925
10490
  source: service
9926
10491
  })) : [{ baseDir: ".", source: raw }], specsFor = (source, baseDir) => FRAMEWORK_FIELDS.flatMap((framework) => {
9927
10492
  const dir = readStringField(source, framework.field);
9928
10493
  return dir === undefined ? [] : [
9929
10494
  {
9930
- dir: join26(baseDir, dir),
10495
+ dir: join27(baseDir, dir),
9931
10496
  label: framework.label,
9932
10497
  pattern: framework.pattern
9933
10498
  }
9934
10499
  ];
9935
10500
  }), scanFramework = async (spec) => {
9936
- const { pageFiles } = await scanConventions(join26(spec.dir, "pages"), spec.pattern);
10501
+ const { pageFiles } = await scanConventions(join27(spec.dir, "pages"), spec.pattern);
9937
10502
  if (pageFiles.length === 0)
9938
10503
  return null;
9939
10504
  const pages = pageFiles.map((file) => ({
9940
- name: basename10(file, extname7(file)),
10505
+ name: basename11(file, extname7(file)),
9941
10506
  sizeBytes: null,
9942
10507
  sourcePath: relativeOrSelf(file)
9943
10508
  }));
@@ -9957,10 +10522,10 @@ var DEFAULT_BUILD_DIR = "build", LABEL_ORDER, ARTIFACT_SUFFIXES, FRAMEWORK_FIELD
9957
10522
  }, resolveDiskPath = (buildDir, value) => {
9958
10523
  if (existsSync16(value))
9959
10524
  return value;
9960
- const underBuild = join26(buildDir, value);
10525
+ const underBuild = join27(buildDir, value);
9961
10526
  if (existsSync16(underBuild))
9962
10527
  return underBuild;
9963
- return join26(process.cwd(), value);
10528
+ return join27(process.cwd(), value);
9964
10529
  }, fileSize = (diskPath) => {
9965
10530
  try {
9966
10531
  return statSync(diskPath).size;
@@ -9968,7 +10533,7 @@ var DEFAULT_BUILD_DIR = "build", LABEL_ORDER, ARTIFACT_SUFFIXES, FRAMEWORK_FIELD
9968
10533
  return 0;
9969
10534
  }
9970
10535
  }, readManifestSizes = (manifestDir) => {
9971
- const manifest = JSON.parse(readFileSync19(join26(manifestDir, "manifest.json"), "utf-8"));
10536
+ const manifest = JSON.parse(readFileSync19(join27(manifestDir, "manifest.json"), "utf-8"));
9972
10537
  const sizes = new Map;
9973
10538
  Object.entries(manifest).forEach(([key, value]) => {
9974
10539
  sizes.set(key, fileSize(resolveDiskPath(manifestDir, value)));
@@ -9987,7 +10552,7 @@ var DEFAULT_BUILD_DIR = "build", LABEL_ORDER, ARTIFACT_SUFFIXES, FRAMEWORK_FIELD
9987
10552
  }))
9988
10553
  })), manifestAge = (manifestPath) => getDurationString(Date.now() - statSync(manifestPath).mtimeMs), firstBuildDir = (candidates) => candidates.map((candidate) => {
9989
10554
  const dir = readStringField(candidate.source, "buildDirectory");
9990
- return dir === undefined ? undefined : join26(candidate.baseDir, dir);
10555
+ return dir === undefined ? undefined : join27(candidate.baseDir, dir);
9991
10556
  }).find((dir) => dir !== undefined), resolveSizesDir = (args, candidates) => parseFlagValue(args, "--outdir") ?? firstBuildDir(candidates) ?? DEFAULT_BUILD_DIR, formatSize = (bytes) => {
9992
10557
  if (bytes === null || bytes === 0)
9993
10558
  return "-";
@@ -10085,7 +10650,7 @@ ${colors.dim}${frameworkCount} ${frameworkCount === 1 ? "framework" : "framework
10085
10650
  return;
10086
10651
  }
10087
10652
  const sizesDir = resolveSizesDir(args, candidates);
10088
- const manifestPath = join26(sizesDir, "manifest.json");
10653
+ const manifestPath = join27(sizesDir, "manifest.json");
10089
10654
  if (!existsSync16(manifestPath)) {
10090
10655
  printDim(`No build at ${relativeOrSelf(manifestPath)}. Run \`absolute build\` first, or pass \`--outdir <dir>\`.`);
10091
10656
  return;
@@ -10210,21 +10775,21 @@ var init_discoverInstances = __esm(() => {
10210
10775
  import { createConnection as createConnection2 } from "net";
10211
10776
  var {$: $4 } = globalThis.Bun;
10212
10777
  var displayHost = (host2) => host2 === "0.0.0.0" || host2 === "::" ? "localhost" : host2, probePort = (host2, port) => {
10213
- const { promise, resolve: resolve25 } = Promise.withResolvers();
10778
+ const { promise, resolve: resolve26 } = Promise.withResolvers();
10214
10779
  const socket = createConnection2({ host: displayHost(host2), port });
10215
10780
  const timeout = setTimeout(() => {
10216
10781
  socket.destroy();
10217
- resolve25(false);
10782
+ resolve26(false);
10218
10783
  }, INSTANCE_PROBE_TIMEOUT_MS);
10219
10784
  socket.once("connect", () => {
10220
10785
  clearTimeout(timeout);
10221
10786
  socket.end();
10222
- resolve25(true);
10787
+ resolve26(true);
10223
10788
  });
10224
10789
  socket.once("error", () => {
10225
10790
  clearTimeout(timeout);
10226
10791
  socket.destroy();
10227
- resolve25(false);
10792
+ resolve26(false);
10228
10793
  });
10229
10794
  return promise;
10230
10795
  }, probeStatus = async (record) => {
@@ -11094,10 +11659,10 @@ import {
11094
11659
  statSync as statSync2,
11095
11660
  writeFileSync as writeFileSync8
11096
11661
  } from "fs";
11097
- import { resolve as resolve25 } from "path";
11662
+ import { resolve as resolve26 } from "path";
11098
11663
  var VIRTUAL_NAME = "__absolute_type_introspect__.ts", MAX_DEPTH = 6, isFrameworkRepo = (cwd) => {
11099
11664
  try {
11100
- const pkg = JSON.parse(readFileSync21(resolve25(cwd, "package.json"), "utf-8"));
11665
+ const pkg = JSON.parse(readFileSync21(resolve26(cwd, "package.json"), "utf-8"));
11101
11666
  return pkg?.name === "@absolutejs/absolute";
11102
11667
  } catch {
11103
11668
  return false;
@@ -11118,10 +11683,10 @@ var VIRTUAL_NAME = "__absolute_type_introspect__.ts", MAX_DEPTH = 6, isFramework
11118
11683
  };
11119
11684
  }, SCHEMA_VERSION = 1, packageVersion = (cwd, specifier) => {
11120
11685
  const candidates = specifier === "@absolutejs/absolute" ? [
11121
- resolve25(cwd, "node_modules", "@absolutejs", "absolute", "package.json"),
11122
- resolve25(cwd, "package.json")
11686
+ resolve26(cwd, "node_modules", "@absolutejs", "absolute", "package.json"),
11687
+ resolve26(cwd, "package.json")
11123
11688
  ] : [
11124
- resolve25(cwd, "node_modules", ...specifier.split("/"), "package.json")
11689
+ resolve26(cwd, "node_modules", ...specifier.split("/"), "package.json")
11125
11690
  ];
11126
11691
  for (const candidate of candidates) {
11127
11692
  try {
@@ -11136,13 +11701,13 @@ var VIRTUAL_NAME = "__absolute_type_introspect__.ts", MAX_DEPTH = 6, isFramework
11136
11701
  if (local) {
11137
11702
  const file = typeName === "PackageJson" ? "packageJson.ts" : "build.ts";
11138
11703
  try {
11139
- signature += `:${statSync2(resolve25(cwd, "types", file)).mtimeMs}`;
11704
+ signature += `:${statSync2(resolve26(cwd, "types", file)).mtimeMs}`;
11140
11705
  } catch {}
11141
11706
  }
11142
11707
  return signature;
11143
11708
  }, cacheSlug = (specifier) => specifier.replace("@", "").split("/").join("-"), cacheFile = (cwd, typeName, specifier) => {
11144
11709
  const name = specifier === "@absolutejs/absolute" ? typeName : `${typeName}.${cacheSlug(specifier)}`;
11145
- return resolve25(cwd, ".absolutejs", "config-schema", `${name}.json`);
11710
+ return resolve26(cwd, ".absolutejs", "config-schema", `${name}.json`);
11146
11711
  }, readDiskCache = (cwd, typeName, signature, specifier) => {
11147
11712
  try {
11148
11713
  const cached = JSON.parse(readFileSync21(cacheFile(cwd, typeName, specifier), "utf-8"));
@@ -11153,7 +11718,7 @@ var VIRTUAL_NAME = "__absolute_type_introspect__.ts", MAX_DEPTH = 6, isFramework
11153
11718
  return null;
11154
11719
  }, writeDiskCache = (cwd, typeName, signature, fields, specifier) => {
11155
11720
  try {
11156
- mkdirSync9(resolve25(cwd, ".absolutejs", "config-schema"), {
11721
+ mkdirSync9(resolve26(cwd, ".absolutejs", "config-schema"), {
11157
11722
  recursive: true
11158
11723
  });
11159
11724
  writeFileSync8(cacheFile(cwd, typeName, specifier), JSON.stringify({ fields, signature }));
@@ -11240,7 +11805,7 @@ var VIRTUAL_NAME = "__absolute_type_introspect__.ts", MAX_DEPTH = 6, isFramework
11240
11805
  }
11241
11806
  return opaque();
11242
11807
  }, introspectFrom = (cwd, specifier, typeName, options, exclude) => {
11243
- const virtualPath = resolve25(cwd, VIRTUAL_NAME);
11808
+ const virtualPath = resolve26(cwd, VIRTUAL_NAME);
11244
11809
  const source = `import type { ${typeName} } from '${specifier}';
11245
11810
  declare const value: ${typeName};
11246
11811
  export { value };
@@ -11250,8 +11815,8 @@ export { value };
11250
11815
  host2.getSourceFile = (fileName, languageVersion, onError, shouldCreate) => fileName === virtualPath ? ts6.createSourceFile(fileName, source, languageVersion, true) : getSourceFile(fileName, languageVersion, onError, shouldCreate);
11251
11816
  const fileExists = host2.fileExists.bind(host2);
11252
11817
  host2.fileExists = (fileName) => fileName === virtualPath ? true : fileExists(fileName);
11253
- const readFile12 = host2.readFile.bind(host2);
11254
- host2.readFile = (fileName) => fileName === virtualPath ? source : readFile12(fileName);
11818
+ const readFile13 = host2.readFile.bind(host2);
11819
+ host2.readFile = (fileName) => fileName === virtualPath ? source : readFile13(fileName);
11255
11820
  const program = ts6.createProgram([virtualPath], options, host2);
11256
11821
  const checker = program.getTypeChecker();
11257
11822
  const sourceFile = program.getSourceFile(virtualPath);
@@ -11283,7 +11848,7 @@ export { value };
11283
11848
  const cached = cache.get(cacheKey);
11284
11849
  if (cached)
11285
11850
  return cached;
11286
- const local = specifier === "@absolutejs/absolute" && isFrameworkRepo(cwd) && existsSync18(resolve25(cwd, "types/index.ts"));
11851
+ const local = specifier === "@absolutejs/absolute" && isFrameworkRepo(cwd) && existsSync18(resolve26(cwd, "types/index.ts"));
11287
11852
  const signature = cacheSignature(cwd, typeName, local, specifier);
11288
11853
  const fromDisk = readDiskCache(cwd, typeName, signature, specifier);
11289
11854
  if (fromDisk) {
@@ -11312,14 +11877,14 @@ var init_fromType = __esm(() => {
11312
11877
  // src/cli/config/absolute/resolveAbsoluteConfig.ts
11313
11878
  import ts7 from "typescript";
11314
11879
  import { existsSync as existsSync19, readFileSync as readFileSync22 } from "fs";
11315
- import { resolve as resolve26 } from "path";
11880
+ import { resolve as resolve27 } from "path";
11316
11881
  var CONFIG_CANDIDATES2, RUNTIME_FIELDS, findConfigPath = (cwd, override) => {
11317
11882
  if (override) {
11318
- const resolved = resolve26(cwd, override);
11883
+ const resolved = resolve27(cwd, override);
11319
11884
  return existsSync19(resolved) ? resolved : null;
11320
11885
  }
11321
11886
  for (const name of CONFIG_CANDIDATES2) {
11322
- const candidate = resolve26(cwd, name);
11887
+ const candidate = resolve27(cwd, name);
11323
11888
  if (existsSync19(candidate))
11324
11889
  return candidate;
11325
11890
  }
@@ -11552,8 +12117,8 @@ var init_frameworks = __esm(() => {
11552
12117
  });
11553
12118
 
11554
12119
  // src/cli/generate/context.ts
11555
- import { dirname as dirname16, isAbsolute as isAbsolute5, join as join27, relative as relative15, resolve as resolve27 } from "path";
11556
- var asString = (value) => typeof value === "string" ? value : undefined, isRecord10 = (value) => typeof value === "object" && value !== null, resolveDir = (cwd, value) => isAbsolute5(value) ? value : resolve27(cwd, value), resolveStylesDir = (cwd, config) => {
12120
+ import { dirname as dirname17, isAbsolute as isAbsolute5, join as join28, relative as relative16, resolve as resolve28 } from "path";
12121
+ var asString = (value) => typeof value === "string" ? value : undefined, isRecord10 = (value) => typeof value === "object" && value !== null, resolveDir = (cwd, value) => isAbsolute5(value) ? value : resolve28(cwd, value), resolveStylesDir = (cwd, config) => {
11557
12122
  const styles = config.stylesConfig;
11558
12123
  if (typeof styles === "string")
11559
12124
  return resolveDir(cwd, styles);
@@ -11562,10 +12127,10 @@ var asString = (value) => typeof value === "string" ? value : undefined, isRecor
11562
12127
  if (indexes)
11563
12128
  return resolveDir(cwd, indexes);
11564
12129
  }
11565
- return resolve27(cwd, "src/frontend/styles/indexes");
12130
+ return resolve28(cwd, "src/frontend/styles/indexes");
11566
12131
  }, configuredFrameworks = (project) => FRAMEWORK_KEYS2.filter((key) => project.frameworkDirs[key] !== undefined), frontendRootFor = (project, framework) => {
11567
12132
  const dir = project.frameworkDirs[framework];
11568
- return dir ? dirname16(dir) : resolve27(project.cwd, "src/frontend");
12133
+ return dir ? dirname17(dir) : resolve28(project.cwd, "src/frontend");
11569
12134
  }, resolveProject = async (cwd, configOverride) => {
11570
12135
  const loaded = await loadConfig(configOverride);
11571
12136
  const config = isRecord10(loaded) ? loaded : {};
@@ -11615,8 +12180,8 @@ var asString = (value) => typeof value === "string" ? value : undefined, isRecor
11615
12180
  message: `Multiple frameworks configured (${configured.join(", ")}). Pass --framework <name>.`,
11616
12181
  ok: false
11617
12182
  };
11618
- }, sharedDirFor = (project, framework) => join27(frontendRootFor(project, framework), "shared"), toModuleSpecifier = (fromDir, toFileNoExt) => {
11619
- const rel = relative15(fromDir, toFileNoExt).split("\\").join("/");
12183
+ }, sharedDirFor = (project, framework) => join28(frontendRootFor(project, framework), "shared"), toModuleSpecifier = (fromDir, toFileNoExt) => {
12184
+ const rel = relative16(fromDir, toFileNoExt).split("\\").join("/");
11620
12185
  return rel.startsWith(".") ? rel : `./${rel}`;
11621
12186
  };
11622
12187
  var init_context = __esm(() => {
@@ -11645,7 +12210,7 @@ var emptyOutcome = () => ({
11645
12210
  // src/cli/generate/routeWiring.ts
11646
12211
  import ts8 from "typescript";
11647
12212
  import { existsSync as existsSync20, readFileSync as readFileSync23, readdirSync as readdirSync4, writeFileSync as writeFileSync9 } from "fs";
11648
- import { dirname as dirname17, join as join28 } from "path";
12213
+ import { dirname as dirname18, join as join29 } from "path";
11649
12214
  var DEFAULT_SEPARATOR = `
11650
12215
  `, BOUNDARY_USE, applyEdits = (text2, edits) => {
11651
12216
  const ordered = [...edits].sort((first, second) => second.start - first.start);
@@ -11804,14 +12369,14 @@ ${newLines.join(`
11804
12369
  for (const name of readdirSync4(pluginsDir)) {
11805
12370
  if (!name.endsWith(".ts"))
11806
12371
  continue;
11807
- const candidate = join28(pluginsDir, name);
12372
+ const candidate = join29(pluginsDir, name);
11808
12373
  if (hasChain(candidate))
11809
12374
  return candidate;
11810
12375
  }
11811
12376
  return null;
11812
12377
  }, findRoutingFile = (serverEntry) => {
11813
- const pluginsDir = join28(dirname17(serverEntry), "plugins");
11814
- const preferred = join28(pluginsDir, "pagesPlugin.ts");
12378
+ const pluginsDir = join29(dirname18(serverEntry), "plugins");
12379
+ const preferred = join29(pluginsDir, "pagesPlugin.ts");
11815
12380
  if (hasChain(preferred))
11816
12381
  return preferred;
11817
12382
  const scanned = firstChainFile(pluginsDir);
@@ -11821,7 +12386,7 @@ ${newLines.join(`
11821
12386
  return serverEntry;
11822
12387
  return null;
11823
12388
  }, buildRouteContext = (input, routingFile) => {
11824
- const specifier = `${toModuleSpecifier(dirname17(routingFile), stripExtension(input.pageFileAbs))}${input.def.pageImportExtension ?? ""}`;
12389
+ const specifier = `${toModuleSpecifier(dirname18(routingFile), stripExtension(input.pageFileAbs))}${input.def.pageImportExtension ?? ""}`;
11825
12390
  return {
11826
12391
  cssAssetKey: input.cssAssetKey,
11827
12392
  indexKey: input.indexKey,
@@ -11903,7 +12468,7 @@ var init_routeWiring = __esm(() => {
11903
12468
 
11904
12469
  // src/cli/generate/generateApi.ts
11905
12470
  import { existsSync as existsSync21, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
11906
- import { dirname as dirname18, join as join29 } from "path";
12471
+ import { dirname as dirname19, join as join30 } from "path";
11907
12472
  var apiPluginTemplate = (pluginName, base) => `import { Elysia } from 'elysia';
11908
12473
 
11909
12474
  export const ${pluginName} = new Elysia()
@@ -11915,8 +12480,8 @@ export const ${pluginName} = new Elysia()
11915
12480
  const pluginName = `${camel}Plugin`;
11916
12481
  const base = `/api/${kebab}`;
11917
12482
  const outcome = { ...emptyOutcome(), route: base };
11918
- const pluginsDir = join29(dirname18(project.serverEntry), "plugins");
11919
- const fileAbs = join29(pluginsDir, `${pluginName}.ts`);
12483
+ const pluginsDir = join30(dirname19(project.serverEntry), "plugins");
12484
+ const fileAbs = join30(pluginsDir, `${pluginName}.ts`);
11920
12485
  if (existsSync21(fileAbs)) {
11921
12486
  outcome.notes.push(`${pluginName} already exists at ${fileAbs} \u2014 skipped.`);
11922
12487
  return outcome;
@@ -11924,7 +12489,7 @@ export const ${pluginName} = new Elysia()
11924
12489
  mkdirSync10(pluginsDir, { recursive: true });
11925
12490
  writeFileSync10(fileAbs, apiPluginTemplate(pluginName, base), "utf-8");
11926
12491
  outcome.created.push(fileAbs);
11927
- const specifier = toModuleSpecifier(dirname18(project.serverEntry), fileAbs.replace(/\.ts$/, ""));
12492
+ const specifier = toModuleSpecifier(dirname19(project.serverEntry), fileAbs.replace(/\.ts$/, ""));
11928
12493
  const wired = wirePluginUse(project.serverEntry, pluginName, specifier);
11929
12494
  if (wired.kind === "edited")
11930
12495
  outcome.updated.push(wired.routingFile);
@@ -11991,7 +12556,7 @@ var init_componentTemplates = __esm(() => {
11991
12556
 
11992
12557
  // src/cli/generate/generateComponent.ts
11993
12558
  import { existsSync as existsSync22, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "fs";
11994
- import { dirname as dirname19, join as join30 } from "path";
12559
+ import { dirname as dirname20, join as join31 } from "path";
11995
12560
  var generateComponent = (project, framework, rawName) => {
11996
12561
  const def = frameworks6[framework];
11997
12562
  const pascal = toPascalCase(rawName);
@@ -12002,12 +12567,12 @@ var generateComponent = (project, framework, rawName) => {
12002
12567
  outcome.manual = { reason: "framework directory missing", snippet: "" };
12003
12568
  return outcome;
12004
12569
  }
12005
- const fileAbs = join30(frameworkDir, "components", def.componentFile({ kebab, pascal }));
12570
+ const fileAbs = join31(frameworkDir, "components", def.componentFile({ kebab, pascal }));
12006
12571
  if (existsSync22(fileAbs)) {
12007
12572
  outcome.notes.push(`${pascal} already exists at ${fileAbs} \u2014 skipped.`);
12008
12573
  return outcome;
12009
12574
  }
12010
- mkdirSync11(dirname19(fileAbs), { recursive: true });
12575
+ mkdirSync11(dirname20(fileAbs), { recursive: true });
12011
12576
  writeFileSync11(fileAbs, componentTemplates[framework]({
12012
12577
  kebab,
12013
12578
  pascal,
@@ -12024,7 +12589,7 @@ var init_generateComponent = __esm(() => {
12024
12589
  // src/cli/generate/cssStrategy.ts
12025
12590
  import ts9 from "typescript";
12026
12591
  import { existsSync as existsSync23 } from "fs";
12027
- import { join as join31 } from "path";
12592
+ import { join as join32 } from "path";
12028
12593
  var CSS_SUFFIX = "CSS", SHARED_MIN_USES = 2, DEFAULT_CSS = `main {
12029
12594
  margin: 0 auto;
12030
12595
  max-width: 64rem;
@@ -12063,7 +12628,7 @@ var CSS_SUFFIX = "CSS", SHARED_MIN_USES = 2, DEFAULT_CSS = `main {
12063
12628
  return null;
12064
12629
  }, fileForKey = (stylesDir, assetKey2) => {
12065
12630
  const base = assetKey2.endsWith(CSS_SUFFIX) ? assetKey2.slice(0, -CSS_SUFFIX.length) : assetKey2;
12066
- return join31(stylesDir, `${toKebabCase(base)}.css`);
12631
+ return join32(stylesDir, `${toKebabCase(base)}.css`);
12067
12632
  }, planCss = (routingText, stylesDir, pascal, kebab) => {
12068
12633
  const sharedKey = detectSharedKey(routingText);
12069
12634
  if (sharedKey) {
@@ -12076,7 +12641,7 @@ var CSS_SUFFIX = "CSS", SHARED_MIN_USES = 2, DEFAULT_CSS = `main {
12076
12641
  shared: true
12077
12642
  };
12078
12643
  }
12079
- const cssFileAbs = join31(stylesDir, `${kebab}.css`);
12644
+ const cssFileAbs = join32(stylesDir, `${kebab}.css`);
12080
12645
  return {
12081
12646
  assetKey: `${pascal}${CSS_SUFFIX}`,
12082
12647
  contents: DEFAULT_CSS,
@@ -12090,7 +12655,7 @@ var init_cssStrategy = () => {};
12090
12655
  // src/cli/generate/navData.ts
12091
12656
  import ts10 from "typescript";
12092
12657
  import { existsSync as existsSync24, mkdirSync as mkdirSync12, readFileSync as readFileSync24, writeFileSync as writeFileSync12 } from "fs";
12093
- import { dirname as dirname20 } from "path";
12658
+ import { dirname as dirname21 } from "path";
12094
12659
  var NAV_DATA_TEMPLATE = `type NavItem = {
12095
12660
  href: string;
12096
12661
  label: string;
@@ -12167,7 +12732,7 @@ ${indent}${entry}`;
12167
12732
  }, upsertNavItem = (navDataPath, item) => {
12168
12733
  const created = !existsSync24(navDataPath);
12169
12734
  if (created) {
12170
- mkdirSync12(dirname20(navDataPath), { recursive: true });
12735
+ mkdirSync12(dirname21(navDataPath), { recursive: true });
12171
12736
  writeFileSync12(navDataPath, NAV_DATA_TEMPLATE, "utf-8");
12172
12737
  }
12173
12738
  const existing = readNavItems(navDataPath);
@@ -12337,14 +12902,14 @@ import {
12337
12902
  readdirSync as readdirSync5,
12338
12903
  writeFileSync as writeFileSync13
12339
12904
  } from "fs";
12340
- import { dirname as dirname21, join as join32, relative as relative16 } from "path";
12905
+ import { dirname as dirname22, join as join33, relative as relative17 } from "path";
12341
12906
  var writeNew = (path, contents) => {
12342
- mkdirSync13(dirname21(path), { recursive: true });
12907
+ mkdirSync13(dirname22(path), { recursive: true });
12343
12908
  writeFileSync13(path, contents, "utf-8");
12344
12909
  }, toHref = (fromDir, toFile) => {
12345
- const rel = relative16(fromDir, toFile).split("\\").join("/");
12910
+ const rel = relative17(fromDir, toFile).split("\\").join("/");
12346
12911
  return rel.startsWith(".") ? rel : `./${rel}`;
12347
- }, staticPageFiles = (project) => ["html", "htmx"].map((key) => project.frameworkDirs[key]).map((dir) => dir ? join32(dir, "pages") : null).filter((pagesDir) => pagesDir !== null && existsSync25(pagesDir)).flatMap((pagesDir) => readdirSync5(pagesDir).filter((name) => name.endsWith(".html")).map((name) => join32(pagesDir, name))), resyncPage = (file, items) => {
12912
+ }, staticPageFiles = (project) => ["html", "htmx"].map((key) => project.frameworkDirs[key]).map((dir) => dir ? join33(dir, "pages") : null).filter((pagesDir) => pagesDir !== null && existsSync25(pagesDir)).flatMap((pagesDir) => readdirSync5(pagesDir).filter((name) => name.endsWith(".html")).map((name) => join33(pagesDir, name))), resyncPage = (file, items) => {
12348
12913
  const html = readFileSync25(file, "utf-8");
12349
12914
  const synced = syncStaticNav(html, items);
12350
12915
  if (synced === null || synced === html)
@@ -12372,7 +12937,7 @@ var writeNew = (path, contents) => {
12372
12937
  outcome.manual = { reason: "framework directory missing", snippet: "" };
12373
12938
  return outcome;
12374
12939
  }
12375
- const pageFileAbs = join32(frameworkDir, "pages", def.pageFile({ kebab, pascal }));
12940
+ const pageFileAbs = join33(frameworkDir, "pages", def.pageFile({ kebab, pascal }));
12376
12941
  if (existsSync25(pageFileAbs)) {
12377
12942
  outcome.notes.push(`${pascal} already exists at ${pageFileAbs} \u2014 skipped.`);
12378
12943
  return outcome;
@@ -12380,11 +12945,11 @@ var writeNew = (path, contents) => {
12380
12945
  const routingFile = findRoutingFile(project.serverEntry);
12381
12946
  const routingText = routingFile ? readFileSync25(routingFile, "utf-8") : "";
12382
12947
  const css = planCss(routingText, project.stylesDir, pascal, kebab);
12383
- const navDataPath = join32(sharedDirFor(project, framework), "navData.ts");
12948
+ const navDataPath = join33(sharedDirFor(project, framework), "navData.ts");
12384
12949
  const nav = upsertNavItem(navDataPath, { href: route, label: title });
12385
- const navImportPath = toModuleSpecifier(dirname21(pageFileAbs), navDataPath.replace(/\.ts$/, ""));
12950
+ const navImportPath = toModuleSpecifier(dirname22(pageFileAbs), navDataPath.replace(/\.ts$/, ""));
12386
12951
  writeNew(pageFileAbs, pageTemplates[framework]({
12387
- cssHref: toHref(dirname21(pageFileAbs), css.cssFileAbs),
12952
+ cssHref: toHref(dirname22(pageFileAbs), css.cssFileAbs),
12388
12953
  kebab,
12389
12954
  navImportPath,
12390
12955
  navItems: nav.items,
@@ -12434,7 +12999,7 @@ var exports_generate = {};
12434
12999
  __export(exports_generate, {
12435
13000
  runGenerate: () => runGenerate
12436
13001
  });
12437
- import { relative as relative17 } from "path";
13002
+ import { relative as relative18 } from "path";
12438
13003
  var SUBCOMMANDS, write = (text2) => process.stdout.write(`${text2}
12439
13004
  `), fail = (message) => {
12440
13005
  process.stdout.write(`${colors.red}${message}${colors.reset}
@@ -12466,7 +13031,7 @@ var SUBCOMMANDS, write = (text2) => process.stdout.write(`${text2}
12466
13031
  return;
12467
13032
  write(` ${colors.dim}${label}${colors.reset}`);
12468
13033
  for (const path of paths)
12469
- write(` ${relative17(cwd, path)}`);
13034
+ write(` ${relative18(cwd, path)}`);
12470
13035
  }, printSummary = (title, outcome, cwd) => {
12471
13036
  for (const note of outcome.notes) {
12472
13037
  write(`${colors.yellow}!${colors.reset} ${note}`);
@@ -12760,9 +13325,9 @@ var init_catalog = __esm(() => {
12760
13325
 
12761
13326
  // src/cli/integrations/addPlugin.ts
12762
13327
  import { existsSync as existsSync26, readFileSync as readFileSync27 } from "fs";
12763
- import { join as join33 } from "path";
13328
+ import { join as join34 } from "path";
12764
13329
  var isRecord11 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), readPackageJson = (cwd) => {
12765
- const path = join33(cwd, "package.json");
13330
+ const path = join34(cwd, "package.json");
12766
13331
  if (!existsSync26(path))
12767
13332
  return null;
12768
13333
  try {
@@ -13259,14 +13824,14 @@ var init_authCatalog = __esm(() => {
13259
13824
  // src/cli/config/auth/resolveAuthSettings.ts
13260
13825
  import ts12 from "typescript";
13261
13826
  import { existsSync as existsSync27, readFileSync as readFileSync28 } from "fs";
13262
- import { resolve as resolve28 } from "path";
13827
+ import { resolve as resolve29 } from "path";
13263
13828
  var AUTH_PACKAGE = "@absolutejs/auth", CONFIG_CANDIDATES3, findAuthSettingsPath = (cwd, override) => {
13264
13829
  if (override) {
13265
- const resolved = resolve28(cwd, override);
13830
+ const resolved = resolve29(cwd, override);
13266
13831
  return existsSync27(resolved) ? resolved : null;
13267
13832
  }
13268
13833
  for (const name of CONFIG_CANDIDATES3) {
13269
- const candidate = resolve28(cwd, name);
13834
+ const candidate = resolve29(cwd, name);
13270
13835
  if (existsSync27(candidate))
13271
13836
  return candidate;
13272
13837
  }
@@ -13364,7 +13929,7 @@ var init_resolveAuthSettings = __esm(() => {
13364
13929
  // src/cli/config/auth/resolveAuthState.ts
13365
13930
  import ts13 from "typescript";
13366
13931
  import { existsSync as existsSync28, readdirSync as readdirSync6, readFileSync as readFileSync29 } from "fs";
13367
- import { join as join34, relative as relative18, resolve as resolve29 } from "path";
13932
+ import { join as join35, relative as relative19, resolve as resolve30 } from "path";
13368
13933
  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) => {
13369
13934
  if (!existsSync28(path))
13370
13935
  return null;
@@ -13378,7 +13943,7 @@ var AUTH_PACKAGE2 = "@absolutejs/auth", REPO_URL = "https://github.com/absolutej
13378
13943
  const value = record?.[key];
13379
13944
  return typeof value === "string" ? value : null;
13380
13945
  }, declaredVersionFor = (cwd) => {
13381
- const pkg = readJson2(join34(cwd, "package.json"));
13946
+ const pkg = readJson2(join35(cwd, "package.json"));
13382
13947
  if (!pkg)
13383
13948
  return null;
13384
13949
  for (const field of ["dependencies", "devDependencies"]) {
@@ -13390,14 +13955,14 @@ var AUTH_PACKAGE2 = "@absolutejs/auth", REPO_URL = "https://github.com/absolutej
13390
13955
  return version2;
13391
13956
  }
13392
13957
  return null;
13393
- }, installedVersionFor = (cwd) => stringField(readJson2(join34(cwd, "node_modules", AUTH_PACKAGE2, "package.json")), "version"), SOURCE_FILE, safeReaddir = (dir) => {
13958
+ }, installedVersionFor = (cwd) => stringField(readJson2(join35(cwd, "node_modules", AUTH_PACKAGE2, "package.json")), "version"), SOURCE_FILE, safeReaddir = (dir) => {
13394
13959
  try {
13395
13960
  return readdirSync6(dir, { withFileTypes: true });
13396
13961
  } catch {
13397
13962
  return [];
13398
13963
  }
13399
13964
  }, sortEntry = (dir, entry, found, dirs) => {
13400
- const full = join34(dir, entry.name);
13965
+ const full = join35(dir, entry.name);
13401
13966
  if (entry.isDirectory()) {
13402
13967
  if (SKIP_DIRS.has(entry.name) || entry.name.startsWith("."))
13403
13968
  return;
@@ -13495,7 +14060,7 @@ var AUTH_PACKAGE2 = "@absolutejs/auth", REPO_URL = "https://github.com/absolutej
13495
14060
  scaffoldable: isScaffoldableFeature(feature.id)
13496
14061
  })), resolveAuthState = (cwd) => {
13497
14062
  const installedVersion = installedVersionFor(cwd);
13498
- const root = existsSync28(join34(cwd, "src")) ? join34(cwd, "src") : cwd;
14063
+ const root = existsSync28(join35(cwd, "src")) ? join35(cwd, "src") : cwd;
13499
14064
  let match = null;
13500
14065
  let setupPath = null;
13501
14066
  for (const file of candidateFiles(root)) {
@@ -13503,7 +14068,7 @@ var AUTH_PACKAGE2 = "@absolutejs/auth", REPO_URL = "https://github.com/absolutej
13503
14068
  if (found === null)
13504
14069
  continue;
13505
14070
  match = found;
13506
- setupPath = relative18(cwd, resolve29(file));
14071
+ setupPath = relative19(cwd, resolve30(file));
13507
14072
  break;
13508
14073
  }
13509
14074
  const keys = match?.keys ?? new Set;
@@ -13541,7 +14106,7 @@ var init_resolveAuthState = __esm(() => {
13541
14106
 
13542
14107
  // src/cli/config/auth/scaffoldAuthFeature.ts
13543
14108
  import { existsSync as existsSync29, writeFileSync as writeFileSync15 } from "fs";
13544
- import { dirname as dirname22, join as join35, relative as relative19, resolve as resolve30 } from "path";
14109
+ import { dirname as dirname23, join as join36, relative as relative20, resolve as resolve31 } from "path";
13545
14110
  var renderScaffold = (scaffold) => {
13546
14111
  const importNames = [...scaffold.imports, `type ${scaffold.typeName}`];
13547
14112
  const importLine = `import { ${importNames.join(", ")} } from '@absolutejs/auth';`;
@@ -13566,8 +14131,8 @@ ${body}
13566
14131
  }, targetDir = (cwd) => {
13567
14132
  const { setupPath } = resolveAuthState(cwd);
13568
14133
  if (setupPath)
13569
- return dirname22(resolve30(cwd, setupPath));
13570
- const src = join35(cwd, "src");
14134
+ return dirname23(resolve31(cwd, setupPath));
14135
+ const src = join36(cwd, "src");
13571
14136
  return existsSync29(src) ? src : cwd;
13572
14137
  }, spreadFor = (scaffold) => `import { ${scaffold.exportName} } from './${scaffold.exportName}';
13573
14138
  // add to your auth() call:
@@ -13581,8 +14146,8 @@ ${scaffold.configKey}: ${scaffold.exportName}`, failure2 = (message) => ({
13581
14146
  const scaffold = AUTH_SCAFFOLDS[id];
13582
14147
  if (!scaffold)
13583
14148
  return failure2(`Unknown auth feature "${id}".`);
13584
- const filePath = join35(targetDir(cwd), `${scaffold.exportName}.ts`);
13585
- const relPath = relative19(cwd, filePath);
14149
+ const filePath = join36(targetDir(cwd), `${scaffold.exportName}.ts`);
14150
+ const relPath = relative20(cwd, filePath);
13586
14151
  if (existsSync29(filePath)) {
13587
14152
  return {
13588
14153
  created: null,
@@ -13611,11 +14176,11 @@ var init_scaffoldAuthFeature = __esm(() => {
13611
14176
 
13612
14177
  // src/cli/htmx/install.ts
13613
14178
  import { existsSync as existsSync30, mkdirSync as mkdirSync14, readFileSync as readFileSync30, writeFileSync as writeFileSync16 } from "fs";
13614
- import { join as join36 } from "path";
14179
+ import { join as join37 } from "path";
13615
14180
  var VENDORED_HTMX_VERSION = "2.0.6", vendoredHtmxFile = () => [
13616
- join36(import.meta.dir, "htmx.min.js"),
13617
- join36(import.meta.dir, "htmx", "htmx.min.js"),
13618
- join36(import.meta.dir, "..", "htmx", "htmx.min.js")
14181
+ join37(import.meta.dir, "htmx.min.js"),
14182
+ join37(import.meta.dir, "htmx", "htmx.min.js"),
14183
+ join37(import.meta.dir, "..", "htmx", "htmx.min.js")
13619
14184
  ].find((path) => existsSync30(path)) ?? null, detectHtmxVersion = (content) => {
13620
14185
  const match = content.match(/version:"([0-9.]+)"/);
13621
14186
  return match ? match[1] : null;
@@ -13627,7 +14192,7 @@ var VENDORED_HTMX_VERSION = "2.0.6", vendoredHtmxFile = () => [
13627
14192
  }
13628
14193
  return response.text();
13629
14194
  }, installedHtmxVersion = (htmxDir) => {
13630
- const file = join36(htmxDir, "htmx.min.js");
14195
+ const file = join37(htmxDir, "htmx.min.js");
13631
14196
  if (!existsSync30(file))
13632
14197
  return null;
13633
14198
  return detectHtmxVersion(readFileSync30(file, "utf-8"));
@@ -13636,7 +14201,7 @@ var VENDORED_HTMX_VERSION = "2.0.6", vendoredHtmxFile = () => [
13636
14201
  return file ? readFileSync30(file, "utf-8") : null;
13637
14202
  }, writeHtmx = (htmxDir, content) => {
13638
14203
  mkdirSync14(htmxDir, { recursive: true });
13639
- const file = join36(htmxDir, "htmx.min.js");
14204
+ const file = join37(htmxDir, "htmx.min.js");
13640
14205
  writeFileSync16(file, content, "utf-8");
13641
14206
  return file;
13642
14207
  };
@@ -13647,7 +14212,7 @@ var exports_add = {};
13647
14212
  __export(exports_add, {
13648
14213
  runAdd: () => runAdd
13649
14214
  });
13650
- import { dirname as dirname23, join as join37, relative as relative20 } from "path";
14215
+ import { dirname as dirname24, join as join38, relative as relative21 } from "path";
13651
14216
  var write2 = (text2) => process.stdout.write(`${text2}
13652
14217
  `), fail2 = (message) => {
13653
14218
  process.stdout.write(`${colors.red}${message}${colors.reset}
@@ -13658,11 +14223,11 @@ var write2 = (text2) => process.stdout.write(`${text2}
13658
14223
  return;
13659
14224
  write2(` ${colors.dim}${label}${colors.reset}`);
13660
14225
  for (const path of paths)
13661
- write2(` ${relative20(cwd, path)}`);
14226
+ write2(` ${relative21(cwd, path)}`);
13662
14227
  }, frontendRoot = (project, cwd) => {
13663
14228
  const [firstKey] = configuredFrameworks(project);
13664
14229
  const firstDir = firstKey ? project.frameworkDirs[firstKey] : undefined;
13665
- return firstDir ? dirname23(firstDir) : join37(cwd, "src", "frontend");
14230
+ return firstDir ? dirname24(firstDir) : join38(cwd, "src", "frontend");
13666
14231
  }, addIntegrationCli = (id, install) => {
13667
14232
  const result = addIntegration(process.cwd(), id, { install });
13668
14233
  if (!result.ok) {
@@ -13726,8 +14291,8 @@ var write2 = (text2) => process.stdout.write(`${text2}
13726
14291
  write2(`${colors.yellow}!${colors.reset} ${frameworks6[framework].label} is already configured \u2014 nothing to do.`);
13727
14292
  return;
13728
14293
  }
13729
- const dirAbs = join37(frontendRoot(project, cwd), framework);
13730
- const dirRel = `./${relative20(cwd, dirAbs).split("\\").join("/")}`;
14294
+ const dirAbs = join38(frontendRoot(project, cwd), framework);
14295
+ const dirRel = `./${relative21(cwd, dirAbs).split("\\").join("/")}`;
13731
14296
  let depNote = "Skipped dependency install (--no-install).";
13732
14297
  if (!noInstall) {
13733
14298
  write2(`${colors.dim}Installing ${frameworks6[framework].label} dependencies\u2026${colors.reset}`);
@@ -13797,7 +14362,7 @@ __export(exports_analyze, {
13797
14362
  runAnalyze: () => runAnalyze
13798
14363
  });
13799
14364
  import { existsSync as existsSync31, readFileSync as readFileSync31, statSync as statSync3, writeFileSync as writeFileSync17 } from "fs";
13800
- import { join as join38, resolve as resolve31 } from "path";
14365
+ import { join as join39, resolve as resolve32 } from "path";
13801
14366
  var BASELINE_FILE = ".absolute-size-baseline.json", TOP_CHANGES = 12, CATEGORY_WIDTH = 16, SIZE_WIDTH = 12, CHANGE_WIDTH = 10, CATEGORY_ORDER, categoryOf = (key) => {
13802
14367
  if (key.startsWith("Island"))
13803
14368
  return "Islands";
@@ -13817,17 +14382,17 @@ var BASELINE_FILE = ".absolute-size-baseline.json", TOP_CHANGES = 12, CATEGORY_W
13817
14382
  return 0;
13818
14383
  }
13819
14384
  }, readSizes = (manifestDir) => {
13820
- const manifestPath = join38(manifestDir, "manifest.json");
14385
+ const manifestPath = join39(manifestDir, "manifest.json");
13821
14386
  if (!existsSync31(manifestPath))
13822
14387
  return null;
13823
14388
  const manifest = JSON.parse(readFileSync31(manifestPath, "utf-8"));
13824
14389
  const sizes = {};
13825
14390
  for (const [key, value] of Object.entries(manifest)) {
13826
- sizes[key] = fileSize2(join38(manifestDir, value.replace(/^\//, "")));
14391
+ sizes[key] = fileSize2(join39(manifestDir, value.replace(/^\//, "")));
13827
14392
  }
13828
14393
  return sizes;
13829
14394
  }, readBaseline = (cwd) => {
13830
- const path = join38(cwd, BASELINE_FILE);
14395
+ const path = join39(cwd, BASELINE_FILE);
13831
14396
  if (!existsSync31(path))
13832
14397
  return null;
13833
14398
  try {
@@ -13909,14 +14474,14 @@ var BASELINE_FILE = ".absolute-size-baseline.json", TOP_CHANGES = 12, CATEGORY_W
13909
14474
  const config = await loadConfig(configIndex >= 0 ? args[configIndex + 1] : undefined);
13910
14475
  const outdirIndex = args.indexOf("--outdir");
13911
14476
  const outdir = outdirIndex >= 0 ? args[outdirIndex + 1] : config.buildDirectory;
13912
- const sizes = readSizes(resolve31(cwd, outdir ?? "build"));
14477
+ const sizes = readSizes(resolve32(cwd, outdir ?? "build"));
13913
14478
  if (sizes === null) {
13914
14479
  process.stdout.write(`${colors.dim}No build found. Run \`absolute build\` first.${colors.reset}
13915
14480
  `);
13916
14481
  return;
13917
14482
  }
13918
14483
  if (args.includes("--save")) {
13919
- writeFileSync17(join38(cwd, BASELINE_FILE), `${JSON.stringify(sizes, null, 2)}
14484
+ writeFileSync17(join39(cwd, BASELINE_FILE), `${JSON.stringify(sizes, null, 2)}
13920
14485
  `);
13921
14486
  process.stdout.write(`${colors.green}\u2713${colors.reset} Saved size baseline (${Object.keys(sizes).length} entries) to ${BASELINE_FILE}
13922
14487
  `);
@@ -14163,7 +14728,7 @@ __export(exports_remove, {
14163
14728
  runRemove: () => runRemove
14164
14729
  });
14165
14730
  import { existsSync as existsSync32, readFileSync as readFileSync32 } from "fs";
14166
- import { relative as relative21 } from "path";
14731
+ import { relative as relative22 } from "path";
14167
14732
  var write3 = (text2) => process.stdout.write(`${text2}
14168
14733
  `), fail3 = (message) => {
14169
14734
  process.stdout.write(`${colors.red}${message}${colors.reset}
@@ -14212,10 +14777,10 @@ var write3 = (text2) => process.stdout.write(`${text2}
14212
14777
  }
14213
14778
  write3(`${colors.green}\u2713${colors.reset} Removed ${framework}Directory from absolute.config.ts
14214
14779
  `);
14215
- write3(` ${colors.dim}Kept${colors.reset} ${relative21(cwd, frameworkDir)} \u2014 delete its source manually if no longer needed.`);
14780
+ write3(` ${colors.dim}Kept${colors.reset} ${relative22(cwd, frameworkDir)} \u2014 delete its source manually if no longer needed.`);
14216
14781
  const refs = referencingFiles(project.serverEntry, HANDLER_NAME[framework]);
14217
14782
  for (const file of refs) {
14218
- write3(` ${colors.yellow}Still references${colors.reset} ${relative21(cwd, file)} (calls ${HANDLER_NAME[framework]})`);
14783
+ write3(` ${colors.yellow}Still references${colors.reset} ${relative22(cwd, file)} (calls ${HANDLER_NAME[framework]})`);
14219
14784
  }
14220
14785
  const deps = frameworkDependencyNames(framework);
14221
14786
  if (prune && deps.length > 0) {
@@ -14304,9 +14869,9 @@ __export(exports_env, {
14304
14869
  collectEnvVars: () => collectEnvVars
14305
14870
  });
14306
14871
  import { existsSync as existsSync33, readFileSync as readFileSync33 } from "fs";
14307
- import { join as join39 } from "path";
14872
+ import { join as join40 } from "path";
14308
14873
  var {env: env3, Glob: Glob3 } = globalThis.Bun;
14309
- 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(join39(process.cwd(), "src")) ? [`src/**/*.{${EXTENSIONS}}`] : [`*.{${EXTENSIONS}}`], scanEnvUsage = async () => {
14874
+ 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(join40(process.cwd(), "src")) ? [`src/**/*.{${EXTENSIONS}}`] : [`*.{${EXTENSIONS}}`], scanEnvUsage = async () => {
14310
14875
  const scans = scanPatterns().map((pattern) => Array.fromAsync(new Glob3(pattern).scan({ cwd: process.cwd() })));
14311
14876
  const files = (await Promise.all(scans)).flat();
14312
14877
  const usage = new Map;
@@ -14373,7 +14938,7 @@ __export(exports_db, {
14373
14938
  chunkRows: () => chunkRows
14374
14939
  });
14375
14940
  import { existsSync as existsSync34, mkdirSync as mkdirSync15, readFileSync as readFileSync34, writeFileSync as writeFileSync18 } from "fs";
14376
- import { join as join40 } from "path";
14941
+ import { join as join41 } from "path";
14377
14942
  var {env: env4, spawn: spawn2, SQL } = globalThis.Bun;
14378
14943
  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) => {
14379
14944
  const found = explicit ?? URL_ENV_KEYS.map((key) => env4[key]).find((value) => typeof value === "string" && value !== "");
@@ -14483,12 +15048,12 @@ var BACKUP_FORMAT_VERSION = 1, RESTORE_CHUNK_ROWS = 500, URL_ENV_KEYS, JSON_DATA
14483
15048
  tables,
14484
15049
  v: BACKUP_FORMAT_VERSION
14485
15050
  };
14486
- const dir = options.out ?? join40(process.cwd(), "backups");
15051
+ const dir = options.out ?? join41(process.cwd(), "backups");
14487
15052
  mkdirSync15(dir, { recursive: true });
14488
15053
  const json = JSON.stringify(payload, (_, value) => typeof value === "bigint" ? value.toString() : value);
14489
- const file = join40(dir, `backup-${payload.at.replace(/[:.]/g, "-")}.json`);
15054
+ const file = join41(dir, `backup-${payload.at.replace(/[:.]/g, "-")}.json`);
14490
15055
  writeFileSync18(file, json);
14491
- writeFileSync18(join40(dir, "latest.json"), json);
15056
+ writeFileSync18(join41(dir, "latest.json"), json);
14492
15057
  const total = chosen.reduce((sum, name) => sum + (tables[name]?.length ?? 0), 0);
14493
15058
  console.log(paint(`\u2713 backup \u2192 ${file}`, colors.green));
14494
15059
  console.log(paint(` ${chosen.length} tables, ${total} rows`, colors.dim));
@@ -14517,7 +15082,7 @@ var BACKUP_FORMAT_VERSION = 1, RESTORE_CHUNK_ROWS = 500, URL_ENV_KEYS, JSON_DATA
14517
15082
  const total = order.reduce((sum, name) => sum + (payload.tables[name]?.length ?? 0), 0);
14518
15083
  console.log(paint(`\u2713 restored ${order.length} tables, ${total} rows (idempotent upsert by primary key)`, colors.green));
14519
15084
  }, runSeed = async (entry) => {
14520
- const target = entry ?? SEED_CANDIDATES.find((candidate) => existsSync34(join40(process.cwd(), candidate)));
15085
+ const target = entry ?? SEED_CANDIDATES.find((candidate) => existsSync34(join41(process.cwd(), candidate)));
14521
15086
  if (target === undefined)
14522
15087
  throw new Error(`No seed script found (looked for ${SEED_CANDIDATES.join(", ")}). Pass a path: absolute db seed <file>.`);
14523
15088
  console.log(paint(`seeding via ${target}\u2026`, colors.cyan));
@@ -14552,7 +15117,7 @@ var BACKUP_FORMAT_VERSION = 1, RESTORE_CHUNK_ROWS = 500, URL_ENV_KEYS, JSON_DATA
14552
15117
  return;
14553
15118
  }
14554
15119
  if (sub === "restore") {
14555
- const file = positionalArgs(rest)[0] ?? join40(process.cwd(), "backups", "latest.json");
15120
+ const file = positionalArgs(rest)[0] ?? join41(process.cwd(), "backups", "latest.json");
14556
15121
  await runRestore(file, parseOptions(rest));
14557
15122
  return;
14558
15123
  }
@@ -14672,7 +15237,7 @@ import {
14672
15237
  writeFileSync as writeFileSync19
14673
15238
  } from "fs";
14674
15239
  import { createRequire } from "module";
14675
- import { dirname as dirname24, join as join41, resolve as resolve32, sep as sep5 } from "path";
15240
+ import { dirname as dirname25, join as join42, resolve as resolve33, sep as sep5 } from "path";
14676
15241
  var DEPENDENCY_FIELDS, TYPE_GRAPH_PACKAGES, readManifest = (path) => {
14677
15242
  try {
14678
15243
  const parsed = JSON.parse(readFileSync35(path, "utf-8"));
@@ -14692,13 +15257,13 @@ var DEPENDENCY_FIELDS, TYPE_GRAPH_PACKAGES, readManifest = (path) => {
14692
15257
  const version2 = Reflect.get(manifest, "version");
14693
15258
  return typeof version2 === "string" ? version2 : "unknown";
14694
15259
  }, packageJsonFromEntry = (entry, expectedName) => {
14695
- let directory = dirname24(entry);
15260
+ let directory = dirname25(entry);
14696
15261
  for (;; ) {
14697
- const candidate = join41(directory, "package.json");
15262
+ const candidate = join42(directory, "package.json");
14698
15263
  const manifest = readManifest(candidate);
14699
15264
  if (manifest && manifestName(manifest, "") === expectedName)
14700
15265
  return candidate;
14701
- const parent = dirname24(directory);
15266
+ const parent = dirname25(directory);
14702
15267
  if (parent === directory)
14703
15268
  return null;
14704
15269
  directory = parent;
@@ -14714,27 +15279,27 @@ var DEPENDENCY_FIELDS, TYPE_GRAPH_PACKAGES, readManifest = (path) => {
14714
15279
  }
14715
15280
  }
14716
15281
  }, findInstallRoot = (cwd) => {
14717
- let directory = resolve32(cwd);
15282
+ let directory = resolve33(cwd);
14718
15283
  for (;; ) {
14719
- if (existsSync36(join41(directory, "bun.lock")) || existsSync36(join41(directory, "bun.lockb"))) {
15284
+ if (existsSync36(join42(directory, "bun.lock")) || existsSync36(join42(directory, "bun.lockb"))) {
14720
15285
  return directory;
14721
15286
  }
14722
- const parent = dirname24(directory);
15287
+ const parent = dirname25(directory);
14723
15288
  if (parent === directory)
14724
- return resolve32(cwd);
15289
+ return resolve33(cwd);
14725
15290
  directory = parent;
14726
15291
  }
14727
15292
  }, findProjectManifest = (cwd, installRoot) => {
14728
- let directory = resolve32(cwd);
15293
+ let directory = resolve33(cwd);
14729
15294
  for (;; ) {
14730
- const candidate = join41(directory, "package.json");
15295
+ const candidate = join42(directory, "package.json");
14731
15296
  if (existsSync36(candidate))
14732
15297
  return candidate;
14733
15298
  if (directory === installRoot)
14734
- return join41(installRoot, "package.json");
14735
- const parent = dirname24(directory);
15299
+ return join42(installRoot, "package.json");
15300
+ const parent = dirname25(directory);
14736
15301
  if (parent === directory)
14737
- return join41(installRoot, "package.json");
15302
+ return join42(installRoot, "package.json");
14738
15303
  directory = parent;
14739
15304
  }
14740
15305
  }, appendConsumer = (consumers, consumerPaths, path, manifest) => {
@@ -14772,7 +15337,7 @@ var DEPENDENCY_FIELDS, TYPE_GRAPH_PACKAGES, readManifest = (path) => {
14772
15337
  appendConsumer(consumers, consumerPaths, inspection.consumer.path, inspection.consumer.manifest);
14773
15338
  }, inspectTypeGraph = (cwd) => {
14774
15339
  const installRoot = findInstallRoot(cwd);
14775
- const rootManifestPath = join41(installRoot, "package.json");
15340
+ const rootManifestPath = join42(installRoot, "package.json");
14776
15341
  const rootManifest = readManifest(rootManifestPath) ?? {};
14777
15342
  const consumers = [
14778
15343
  { manifest: rootManifest, path: rootManifestPath }
@@ -14808,7 +15373,7 @@ var DEPENDENCY_FIELDS, TYPE_GRAPH_PACKAGES, readManifest = (path) => {
14808
15373
  const duplicates = duplicateTypeGraphPackages(report);
14809
15374
  if (duplicates.length === 0)
14810
15375
  return [];
14811
- const manifestPath = join41(report.installRoot, "package.json");
15376
+ const manifestPath = join42(report.installRoot, "package.json");
14812
15377
  const manifest = readManifest(manifestPath);
14813
15378
  if (!manifest)
14814
15379
  return [];
@@ -14830,7 +15395,7 @@ var DEPENDENCY_FIELDS, TYPE_GRAPH_PACKAGES, readManifest = (path) => {
14830
15395
  }
14831
15396
  return changes;
14832
15397
  }, removeDuplicateTypeGraphPackages = (report) => {
14833
- const manifest = readManifest(join41(report.installRoot, "package.json")) ?? {};
15398
+ const manifest = readManifest(join42(report.installRoot, "package.json")) ?? {};
14834
15399
  const rootName = manifestName(manifest, "<workspace>");
14835
15400
  const installPrefix = `${realpathSync2(report.installRoot)}${sep5}`;
14836
15401
  const nodeModulesSegment = `${sep5}node_modules${sep5}`;
@@ -14842,7 +15407,7 @@ var DEPENDENCY_FIELDS, TYPE_GRAPH_PACKAGES, readManifest = (path) => {
14842
15407
  for (const stalePath of stalePaths) {
14843
15408
  if (!stalePath.startsWith(installPrefix) || !stalePath.includes(nodeModulesSegment))
14844
15409
  continue;
14845
- rmSync6(dirname24(stalePath), { force: true, recursive: true });
15410
+ rmSync6(dirname25(stalePath), { force: true, recursive: true });
14846
15411
  removed.push(stalePath);
14847
15412
  }
14848
15413
  return removed;
@@ -14872,7 +15437,7 @@ __export(exports_doctor, {
14872
15437
  import { existsSync as existsSync37, mkdirSync as mkdirSync16, readFileSync as readFileSync36, writeFileSync as writeFileSync20 } from "fs";
14873
15438
  import { createRequire as createRequire2 } from "module";
14874
15439
  import { arch as arch4, platform as platform5 } from "os";
14875
- import { join as join42 } from "path";
15440
+ import { join as join43 } from "path";
14876
15441
  var FRAMEWORK_FIELDS2, projectRequire, check = (status2, label, detail) => ({
14877
15442
  detail,
14878
15443
  label,
@@ -14907,7 +15472,7 @@ var FRAMEWORK_FIELDS2, projectRequire, check = (status2, label, detail) => ({
14907
15472
  return [];
14908
15473
  const label = `${field.replace("Directory", "")} pages`;
14909
15474
  return [
14910
- existsSync37(join42(process.cwd(), dir)) ? check("ok", label, dir) : check("fail", label, `${dir} (missing)`)
15475
+ existsSync37(join43(process.cwd(), dir)) ? check("ok", label, dir) : check("fail", label, `${dir} (missing)`)
14911
15476
  ];
14912
15477
  }), envCheck = async () => {
14913
15478
  const vars = await collectEnvVars();
@@ -14969,9 +15534,9 @@ ${colors.dim}${checks.length} checks \xB7 ${colors.reset}${summary}${colors.dim}
14969
15534
  const fixes = [];
14970
15535
  for (const field of FRAMEWORK_FIELDS2) {
14971
15536
  const dir = readString2(config, field);
14972
- if (dir === undefined || existsSync37(join42(cwd, dir)))
15537
+ if (dir === undefined || existsSync37(join43(cwd, dir)))
14973
15538
  continue;
14974
- mkdirSync16(join42(cwd, dir, "pages"), { recursive: true });
15539
+ mkdirSync16(join43(cwd, dir, "pages"), { recursive: true });
14975
15540
  fixes.push(`created ${dir}/pages`);
14976
15541
  }
14977
15542
  return fixes;
@@ -14979,7 +15544,7 @@ ${colors.dim}${checks.length} checks \xB7 ${colors.reset}${summary}${colors.dim}
14979
15544
  const missing = (await collectEnvVars()).filter((entry) => !entry.set);
14980
15545
  if (missing.length === 0)
14981
15546
  return null;
14982
- const envExample = join42(cwd, ".env.example");
15547
+ const envExample = join43(cwd, ".env.example");
14983
15548
  const existing = existsSync37(envExample) ? readFileSync36(envExample, "utf-8") : "";
14984
15549
  const existingKeys = new Set(existing.split(`
14985
15550
  `).map((line) => line.split("=")[0]?.trim()));
@@ -15050,7 +15615,7 @@ var init_doctor = __esm(() => {
15050
15615
  "htmlDirectory",
15051
15616
  "htmxDirectory"
15052
15617
  ];
15053
- projectRequire = createRequire2(join42(process.cwd(), "package.json"));
15618
+ projectRequire = createRequire2(join43(process.cwd(), "package.json"));
15054
15619
  STATUS_MARK = {
15055
15620
  fail: `${colors.red}\u2717${colors.reset}`,
15056
15621
  ok: `${colors.green}\u2713${colors.reset}`,
@@ -15440,7 +16005,7 @@ var init_sourceMetadata = __esm(() => {
15440
16005
 
15441
16006
  // src/islands/pageMetadata.ts
15442
16007
  import { readFileSync as readFileSync37 } from "fs";
15443
- import { dirname as dirname25, resolve as resolve33 } from "path";
16008
+ import { dirname as dirname26, resolve as resolve34 } from "path";
15444
16009
  var pagePatterns, getPageDirs = (config) => [
15445
16010
  { dir: config.angularDirectory, framework: "angular" },
15446
16011
  { dir: config.emberDirectory, framework: "ember" },
@@ -15460,8 +16025,8 @@ var pagePatterns, getPageDirs = (config) => [
15460
16025
  const source = definition.buildReference?.source;
15461
16026
  if (!source)
15462
16027
  continue;
15463
- const resolvedSource = source.startsWith("file://") ? new URL(source).pathname : resolve33(dirname25(buildInfo.resolvedRegistryPath), source);
15464
- lookup.set(`${definition.framework}:${definition.component}`, resolve33(resolvedSource));
16028
+ const resolvedSource = source.startsWith("file://") ? new URL(source).pathname : resolve34(dirname26(buildInfo.resolvedRegistryPath), source);
16029
+ lookup.set(`${definition.framework}:${definition.component}`, resolve34(resolvedSource));
15465
16030
  }
15466
16031
  return lookup;
15467
16032
  }, resolveIslandUsages = (islands, islandSourceLookup) => islands.map((usage2) => {
@@ -15474,13 +16039,13 @@ var pagePatterns, getPageDirs = (config) => [
15474
16039
  const pattern = pagePatterns[entry.framework];
15475
16040
  if (!pattern)
15476
16041
  return;
15477
- const files = await scanEntryPoints(resolve33(entry.dir), pattern);
16042
+ const files = await scanEntryPoints(resolve34(entry.dir), pattern);
15478
16043
  for (const filePath of files) {
15479
16044
  const source = readFileSync37(filePath, "utf-8");
15480
16045
  const islands = extractIslandUsagesFromSource(source);
15481
- pageMetadata.set(resolve33(filePath), {
16046
+ pageMetadata.set(resolve34(filePath), {
15482
16047
  islands: resolveIslandUsages(islands, islandSourceLookup),
15483
- pagePath: resolve33(filePath)
16048
+ pagePath: resolve34(filePath)
15484
16049
  });
15485
16050
  }
15486
16051
  }, loadPageIslandMetadata = async (config) => {
@@ -15510,13 +16075,13 @@ __export(exports_islands, {
15510
16075
  runIslands: () => runIslands
15511
16076
  });
15512
16077
  import { existsSync as existsSync39, readFileSync as readFileSync38, statSync as statSync5 } from "fs";
15513
- import { join as join43, relative as relative22, resolve as resolve34 } from "path";
16078
+ import { join as join44, relative as relative23, resolve as resolve35 } from "path";
15514
16079
  var FRAMEWORK_DIR_KEY, FRAMEWORK_COLOR, printDim6 = (message) => process.stdout.write(`${colors.dim}${message}${colors.reset}
15515
16080
  `), hostFrameworkOf = (pagePath, cwd, config) => {
15516
- const resolved = resolve34(cwd, pagePath);
16081
+ const resolved = resolve35(cwd, pagePath);
15517
16082
  for (const [framework, key] of Object.entries(FRAMEWORK_DIR_KEY)) {
15518
16083
  const dir = config[key];
15519
- if (typeof dir === "string" && resolved.startsWith(resolve34(cwd, dir))) {
16084
+ if (typeof dir === "string" && resolved.startsWith(resolve35(cwd, dir))) {
15520
16085
  return framework;
15521
16086
  }
15522
16087
  }
@@ -15528,20 +16093,20 @@ var FRAMEWORK_DIR_KEY, FRAMEWORK_COLOR, printDim6 = (message) => process.stdout.
15528
16093
  return 0;
15529
16094
  }
15530
16095
  }, readManifestSizes2 = (manifestDir) => {
15531
- const manifestPath = join43(manifestDir, "manifest.json");
16096
+ const manifestPath = join44(manifestDir, "manifest.json");
15532
16097
  if (!existsSync39(manifestPath))
15533
16098
  return null;
15534
16099
  const manifest = JSON.parse(readFileSync38(manifestPath, "utf-8"));
15535
16100
  const sizes = new Map;
15536
16101
  for (const [key, value] of Object.entries(manifest)) {
15537
- sizes.set(key, fileSize3(join43(manifestDir, value.replace(/^\//, ""))));
16102
+ sizes.set(key, fileSize3(join44(manifestDir, value.replace(/^\//, ""))));
15538
16103
  }
15539
16104
  return sizes;
15540
16105
  }, collectIslands = async (cwd, config, sizes) => {
15541
16106
  const registryPath = config.islands?.registry;
15542
16107
  if (typeof registryPath !== "string")
15543
16108
  return null;
15544
- const buildInfo = await loadIslandRegistryBuildInfo(resolve34(cwd, registryPath));
16109
+ const buildInfo = await loadIslandRegistryBuildInfo(resolve35(cwd, registryPath));
15545
16110
  const pageMetadata = await loadPageIslandMetadata(config);
15546
16111
  const usages = [...pageMetadata.values()].flatMap((meta) => meta.islands.map((island) => ({ ...island, page: meta.pagePath })));
15547
16112
  return buildInfo.definitions.map((definition) => {
@@ -15551,7 +16116,7 @@ var FRAMEWORK_DIR_KEY, FRAMEWORK_COLOR, printDim6 = (message) => process.stdout.
15551
16116
  crossFramework: hostFramework !== null && hostFramework !== definition.framework,
15552
16117
  hostFramework,
15553
16118
  hydrate: usage2.hydrate ?? "load",
15554
- page: relative22(cwd, resolve34(cwd, usage2.page))
16119
+ page: relative23(cwd, resolve35(cwd, usage2.page))
15555
16120
  };
15556
16121
  });
15557
16122
  const key = getIslandManifestKey(definition.framework, definition.component);
@@ -15590,7 +16155,7 @@ var FRAMEWORK_DIR_KEY, FRAMEWORK_COLOR, printDim6 = (message) => process.stdout.
15590
16155
  ` ${color}\u2B21${colors.reset} ${colors.bold}${island.component}${colors.reset} ${meta}${sizeText}`
15591
16156
  ];
15592
16157
  if (island.source) {
15593
- lines.push(` ${colors.dim}${relative22(cwd, island.source)}${colors.reset}`);
16158
+ lines.push(` ${colors.dim}${relative23(cwd, island.source)}${colors.reset}`);
15594
16159
  }
15595
16160
  if (pages.length === 0) {
15596
16161
  lines.push(` ${colors.dim}(registered but not mounted on any page)${colors.reset}`);
@@ -15620,7 +16185,7 @@ var FRAMEWORK_DIR_KEY, FRAMEWORK_COLOR, printDim6 = (message) => process.stdout.
15620
16185
  }
15621
16186
  const outdirIndex = args.indexOf("--outdir");
15622
16187
  const outdir = outdirIndex >= 0 ? args[outdirIndex + 1] : config.buildDirectory;
15623
- const sizes = args.includes("--sizes") ? readManifestSizes2(resolve34(cwd, outdir ?? "build")) : null;
16188
+ const sizes = args.includes("--sizes") ? readManifestSizes2(resolve35(cwd, outdir ?? "build")) : null;
15624
16189
  const islands = await collectIslands(cwd, config, sizes);
15625
16190
  if (islands === null) {
15626
16191
  printDim6('No island registry configured. Set `islands: { registry: "..." }` in absolute.config.ts.');
@@ -15670,12 +16235,12 @@ var init_islands2 = __esm(() => {
15670
16235
 
15671
16236
  // src/build/externalAssetPlugin.ts
15672
16237
  import { copyFileSync as copyFileSync2, existsSync as existsSync40, mkdirSync as mkdirSync17, statSync as statSync6 } from "fs";
15673
- import { basename as basename11, dirname as dirname26, join as join44, resolve as resolve35 } from "path";
16238
+ import { basename as basename12, dirname as dirname27, join as join45, resolve as resolve36 } from "path";
15674
16239
  var createExternalAssetPlugin = (outDir, userSourceRoots = []) => ({
15675
16240
  name: "absolute-external-asset",
15676
16241
  setup(bld) {
15677
16242
  const urlPattern = /new\s+URL\(\s*["'](\.\.?\/[^"']+)["']\s*,\s*import\.meta\.url\s*\)/g;
15678
- const skipRoots = userSourceRoots.map((root) => resolve35(root));
16243
+ const skipRoots = userSourceRoots.map((root) => resolve36(root));
15679
16244
  const isUserSource = (path) => skipRoots.some((root) => path.startsWith(`${root}/`));
15680
16245
  bld.onLoad({ filter: /\.[mc]?[jt]sx?$/ }, async (args) => {
15681
16246
  if (isUserSource(args.path))
@@ -15685,20 +16250,20 @@ var createExternalAssetPlugin = (outDir, userSourceRoots = []) => ({
15685
16250
  return;
15686
16251
  urlPattern.lastIndex = 0;
15687
16252
  let match;
15688
- const sourceDir = dirname26(args.path);
16253
+ const sourceDir = dirname27(args.path);
15689
16254
  while ((match = urlPattern.exec(source)) !== null) {
15690
16255
  const relPath = match[1];
15691
16256
  if (!relPath)
15692
16257
  continue;
15693
- const assetPath = resolve35(sourceDir, relPath);
16258
+ const assetPath = resolve36(sourceDir, relPath);
15694
16259
  if (!existsSync40(assetPath))
15695
16260
  continue;
15696
16261
  if (!statSync6(assetPath).isFile())
15697
16262
  continue;
15698
- const targetPath = join44(outDir, basename11(assetPath));
16263
+ const targetPath = join45(outDir, basename12(assetPath));
15699
16264
  if (existsSync40(targetPath))
15700
16265
  continue;
15701
- mkdirSync17(dirname26(targetPath), { recursive: true });
16266
+ mkdirSync17(dirname27(targetPath), { recursive: true });
15702
16267
  copyFileSync2(assetPath, targetPath);
15703
16268
  }
15704
16269
  return;
@@ -15727,12 +16292,12 @@ import {
15727
16292
  } from "fs";
15728
16293
  import { createRequire as createRequire3 } from "module";
15729
16294
  import {
15730
- basename as basename12,
15731
- dirname as dirname27,
16295
+ basename as basename13,
16296
+ dirname as dirname28,
15732
16297
  isAbsolute as isAbsolute6,
15733
- join as join45,
15734
- relative as relative23,
15735
- resolve as resolve36
16298
+ join as join46,
16299
+ relative as relative24,
16300
+ resolve as resolve37
15736
16301
  } from "path";
15737
16302
  var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[cli]\x1B[0m ${color}${message}\x1B[0m`, compileBanner = (version2) => {
15738
16303
  const resolvedVersion = version2 || "unknown";
@@ -15746,7 +16311,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
15746
16311
  const entry = pending.pop();
15747
16312
  if (!entry)
15748
16313
  continue;
15749
- const fullPath = join45(entry.parentPath, entry.name);
16314
+ const fullPath = join46(entry.parentPath, entry.name);
15750
16315
  if (entry.isDirectory())
15751
16316
  pending = pending.concat(readdirSync7(fullPath, { withFileTypes: true }));
15752
16317
  else
@@ -15765,7 +16330,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
15765
16330
  if (!Array.isArray(map.sources))
15766
16331
  return;
15767
16332
  const sourceRoot = typeof map.sourceRoot === "string" ? map.sourceRoot : "";
15768
- const bundleDirectory = dirname27(filePath);
16333
+ const bundleDirectory = dirname28(filePath);
15769
16334
  map.sources = map.sources.map((entry) => {
15770
16335
  if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(entry))
15771
16336
  return entry;
@@ -15774,7 +16339,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
15774
16339
  if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(sourceRoot)) {
15775
16340
  return new URL(entry, sourceRoot).href;
15776
16341
  }
15777
- return resolve36(bundleDirectory, sourceRoot, entry);
16342
+ return resolve37(bundleDirectory, sourceRoot, entry);
15778
16343
  });
15779
16344
  delete map.sourceRoot;
15780
16345
  const rebased = Buffer.from(JSON.stringify(map)).toString("base64");
@@ -15792,7 +16357,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
15792
16357
  const entry = pending.pop();
15793
16358
  if (!entry)
15794
16359
  continue;
15795
- const fullPath = join45(entry.parentPath, entry.name);
16360
+ const fullPath = join46(entry.parentPath, entry.name);
15796
16361
  if (entry.isDirectory()) {
15797
16362
  if (SERVER_RUNTIME_SCAN_SKIP_DIRS.has(entry.name))
15798
16363
  continue;
@@ -15804,18 +16369,18 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
15804
16369
  return result;
15805
16370
  }, copyServerRuntimeAssetReferences = (outdir) => {
15806
16371
  const copied = new Set;
15807
- const normalizedOutdir = resolve36(outdir);
16372
+ const normalizedOutdir = resolve37(outdir);
15808
16373
  const copyReference = (filePath, relPath) => {
15809
- const assetSource = resolve36(dirname27(filePath), relPath);
16374
+ const assetSource = resolve37(dirname28(filePath), relPath);
15810
16375
  if (!existsSync41(assetSource) || !statSync7(assetSource).isFile())
15811
16376
  return;
15812
- const assetTarget = resolve36(normalizedOutdir, relPath.replace(/^\.\//, ""));
16377
+ const assetTarget = resolve37(normalizedOutdir, relPath.replace(/^\.\//, ""));
15813
16378
  if (assetTarget !== normalizedOutdir && !assetTarget.startsWith(`${normalizedOutdir}/`))
15814
16379
  return;
15815
16380
  if (copied.has(assetTarget))
15816
16381
  return;
15817
16382
  copied.add(assetTarget);
15818
- mkdirSync18(dirname27(assetTarget), { recursive: true });
16383
+ mkdirSync18(dirname28(assetTarget), { recursive: true });
15819
16384
  cpSync(assetSource, assetTarget, { force: true });
15820
16385
  };
15821
16386
  for (const filePath of collectProjectSourceFiles(process.cwd())) {
@@ -15883,18 +16448,18 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
15883
16448
  return resolveBuildModule3(remaining);
15884
16449
  }, resolveJsxDevRuntimeCompatPath2 = () => {
15885
16450
  const candidates = [
15886
- resolve36(import.meta.dir, "..", "..", "dist", "react", "jsxDevRuntimeCompat.js"),
15887
- resolve36(import.meta.dir, "..", "..", "react", "jsxDevRuntimeCompat.js"),
15888
- resolve36(import.meta.dir, "..", "..", "react", "jsxDevRuntimeCompat.ts"),
15889
- resolve36(import.meta.dir, "..", "..", "..", "dist", "react", "jsxDevRuntimeCompat.js"),
15890
- resolve36(import.meta.dir, "..", "..", "..", "react", "jsxDevRuntimeCompat.js"),
15891
- resolve36(import.meta.dir, "..", "..", "..", "src", "react", "jsxDevRuntimeCompat.ts")
16451
+ resolve37(import.meta.dir, "..", "..", "dist", "react", "jsxDevRuntimeCompat.js"),
16452
+ resolve37(import.meta.dir, "..", "..", "react", "jsxDevRuntimeCompat.js"),
16453
+ resolve37(import.meta.dir, "..", "..", "react", "jsxDevRuntimeCompat.ts"),
16454
+ resolve37(import.meta.dir, "..", "..", "..", "dist", "react", "jsxDevRuntimeCompat.js"),
16455
+ resolve37(import.meta.dir, "..", "..", "..", "react", "jsxDevRuntimeCompat.js"),
16456
+ resolve37(import.meta.dir, "..", "..", "..", "src", "react", "jsxDevRuntimeCompat.ts")
15892
16457
  ];
15893
16458
  for (const candidate of candidates) {
15894
16459
  if (existsSync41(candidate))
15895
16460
  return candidate;
15896
16461
  }
15897
- return resolve36(import.meta.dir, "..", "..", "react", "jsxDevRuntimeCompat.js");
16462
+ return resolve37(import.meta.dir, "..", "..", "react", "jsxDevRuntimeCompat.js");
15898
16463
  }, jsxDevRuntimeCompatPath2, shouldEmbedCompiledAsset = (relativePath, skip = new Set) => {
15899
16464
  if (skip.has(relativePath))
15900
16465
  return false;
@@ -15919,7 +16484,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
15919
16484
  return true;
15920
16485
  }), requireForCompile, resolveNativeAssetForRuntime = (specifier) => {
15921
16486
  if (specifier.startsWith("."))
15922
- return resolve36(process.cwd(), specifier);
16487
+ return resolve37(process.cwd(), specifier);
15923
16488
  if (specifier.startsWith("/"))
15924
16489
  return specifier;
15925
16490
  return requireForCompile.resolve(specifier, { paths: [process.cwd()] });
@@ -15931,11 +16496,11 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
15931
16496
  return nativeAssetEnv;
15932
16497
  }, tryReadNodePackageJson = (packageDir) => {
15933
16498
  try {
15934
- return JSON.parse(readFileSync39(join45(packageDir, "package.json"), "utf-8"));
16499
+ return JSON.parse(readFileSync39(join46(packageDir, "package.json"), "utf-8"));
15935
16500
  } catch {
15936
16501
  return null;
15937
16502
  }
15938
- }, resolveProjectPackageDir = (specifier) => resolve36(process.cwd(), "node_modules", ...specifier.split("/")), copyPackageToBuild = (specifier, outdir, seen) => {
16503
+ }, resolveProjectPackageDir = (specifier) => resolve37(process.cwd(), "node_modules", ...specifier.split("/")), copyPackageToBuild = (specifier, outdir, seen) => {
15939
16504
  if (seen.has(specifier))
15940
16505
  return;
15941
16506
  const srcDir = resolveProjectPackageDir(specifier);
@@ -15943,13 +16508,13 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
15943
16508
  if (!pkg)
15944
16509
  return;
15945
16510
  seen.add(specifier);
15946
- const destDir = join45(outdir, "node_modules", ...specifier.split("/"));
16511
+ const destDir = join46(outdir, "node_modules", ...specifier.split("/"));
15947
16512
  rmSync7(destDir, { force: true, recursive: true });
15948
16513
  cpSync(srcDir, destDir, {
15949
16514
  force: true,
15950
16515
  recursive: true,
15951
16516
  filter(source) {
15952
- const rel = relative23(srcDir, source);
16517
+ const rel = relative24(srcDir, source);
15953
16518
  const [firstSegment] = rel.split(/[\\/]/);
15954
16519
  return firstSegment !== "node_modules" && firstSegment !== ".git";
15955
16520
  }
@@ -15965,7 +16530,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
15965
16530
  }, copyAngularRuntimePackages = (buildConfig, outdir) => {
15966
16531
  if (!buildConfig.angularDirectory)
15967
16532
  return;
15968
- const angularScopeDir = resolve36(process.cwd(), "node_modules", "@angular");
16533
+ const angularScopeDir = resolve37(process.cwd(), "node_modules", "@angular");
15969
16534
  const angularPackages = existsSync41(angularScopeDir) ? readdirSync7(angularScopeDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => entry.name !== "compiler-cli").map((entry) => `@angular/${entry.name}`) : [];
15970
16535
  const roots = new Set([...angularPackages, "rxjs", "tslib", "typescript"]);
15971
16536
  const seen = new Set;
@@ -15984,7 +16549,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
15984
16549
  copyAngularRuntimePackages(buildConfig, outdir);
15985
16550
  copyChunkReferencedPackages(outdir, seen);
15986
16551
  }, collectRuntimePackageSpecifiers = (distDir) => {
15987
- const nodeModulesDir = join45(distDir, "node_modules");
16552
+ const nodeModulesDir = join46(distDir, "node_modules");
15988
16553
  if (!existsSync41(nodeModulesDir))
15989
16554
  return [];
15990
16555
  const specifiers = [];
@@ -15992,7 +16557,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
15992
16557
  if (!entry.isDirectory())
15993
16558
  continue;
15994
16559
  if (entry.name.startsWith("@")) {
15995
- const scopeDir = join45(nodeModulesDir, entry.name);
16560
+ const scopeDir = join46(nodeModulesDir, entry.name);
15996
16561
  for (const scopedEntry of readdirSync7(scopeDir, {
15997
16562
  withFileTypes: true
15998
16563
  })) {
@@ -16006,7 +16571,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
16006
16571
  }
16007
16572
  return specifiers.sort((firstSpecifier, secondSpecifier) => secondSpecifier.length - firstSpecifier.length);
16008
16573
  }, ensureRelativeModuleSpecifier = (fromFile, toFile) => {
16009
- const rel = relative23(dirname27(fromFile), toFile).replace(/\\/g, "/");
16574
+ const rel = relative24(dirname28(fromFile), toFile).replace(/\\/g, "/");
16010
16575
  return rel.startsWith(".") ? rel : `./${rel}`;
16011
16576
  }, pickExportEntry = (value) => {
16012
16577
  if (typeof value === "string")
@@ -16023,18 +16588,18 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
16023
16588
  const packageSpecifier = packageSpecifiers.find((root) => specifier === root || specifier.startsWith(`${root}/`));
16024
16589
  if (!packageSpecifier)
16025
16590
  return null;
16026
- const packageDir = join45(distDir, "node_modules", ...packageSpecifier.split("/"));
16591
+ const packageDir = join46(distDir, "node_modules", ...packageSpecifier.split("/"));
16027
16592
  const subpath = specifier.slice(packageSpecifier.length);
16028
- const subPackageDir = subpath ? join45(packageDir, ...subpath.slice(1).split("/")) : null;
16029
- const resolvedPackageDir = subPackageDir && existsSync41(join45(subPackageDir, "package.json")) ? subPackageDir : packageDir;
16030
- const packageJsonPath = join45(resolvedPackageDir, "package.json");
16593
+ const subPackageDir = subpath ? join46(packageDir, ...subpath.slice(1).split("/")) : null;
16594
+ const resolvedPackageDir = subPackageDir && existsSync41(join46(subPackageDir, "package.json")) ? subPackageDir : packageDir;
16595
+ const packageJsonPath = join46(resolvedPackageDir, "package.json");
16031
16596
  if (!existsSync41(packageJsonPath))
16032
16597
  return null;
16033
16598
  const pkg = JSON.parse(readFileSync39(packageJsonPath, "utf-8"));
16034
16599
  const exportKey = resolvedPackageDir !== subPackageDir && subpath ? `.${subpath}` : ".";
16035
16600
  const rootExport = pkg.exports?.[exportKey];
16036
16601
  const entry = pickExportEntry(rootExport) ?? (resolvedPackageDir === subPackageDir || !subpath ? pkg.module ?? pkg.main ?? "index.js" : `.${subpath}`);
16037
- return join45(resolvedPackageDir, entry);
16602
+ return join46(resolvedPackageDir, entry);
16038
16603
  }, RUNTIME_JS_EXTENSIONS, MODULE_SPECIFIER_RE, isRuntimeJsFile = (filePath) => RUNTIME_JS_EXTENSIONS.some((extension) => filePath.endsWith(extension)), isNodeModulesPath = (filePath) => filePath.split(/[\\/]/).includes("node_modules"), isFile = (filePath) => {
16039
16604
  try {
16040
16605
  return statSync7(filePath).isFile();
@@ -16047,16 +16612,16 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
16047
16612
  const candidates = [
16048
16613
  candidate,
16049
16614
  ...RUNTIME_JS_EXTENSIONS.map((extension) => `${candidate}${extension}`),
16050
- ...RUNTIME_JS_EXTENSIONS.map((extension) => join45(candidate, `index${extension}`))
16615
+ ...RUNTIME_JS_EXTENSIONS.map((extension) => join46(candidate, `index${extension}`))
16051
16616
  ];
16052
16617
  return candidates.find((filePath) => isRuntimeJsFile(filePath) && isFile(filePath)) ?? null;
16053
16618
  }, findContainingRuntimePackageDir = (filePath) => {
16054
- let dir = dirname27(filePath);
16055
- while (dir !== dirname27(dir)) {
16056
- if (isNodeModulesPath(dir) && existsSync41(join45(dir, "package.json"))) {
16619
+ let dir = dirname28(filePath);
16620
+ while (dir !== dirname28(dir)) {
16621
+ if (isNodeModulesPath(dir) && existsSync41(join46(dir, "package.json"))) {
16057
16622
  return dir;
16058
16623
  }
16059
- dir = dirname27(dir);
16624
+ dir = dirname28(dir);
16060
16625
  }
16061
16626
  return null;
16062
16627
  }, resolvePackageImportEntryFile = (fromFile, specifier) => {
@@ -16069,11 +16634,11 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
16069
16634
  const entry = pickExportEntry(pkg?.imports?.[specifier]);
16070
16635
  if (!entry)
16071
16636
  return null;
16072
- return join45(packageDir, entry);
16637
+ return join46(packageDir, entry);
16073
16638
  }, collectRuntimeRewriteRoots = (distDir) => collectFiles2(distDir).filter((filePath) => isRuntimeJsFile(filePath) && !isNodeModulesPath(filePath)), toTopLevelPackage = (specifier) => specifier.split("/").slice(0, specifier.startsWith("@") ? 2 : 1).join("/"), FRAMEWORK_PACKAGE_NAME = "@absolutejs/absolute", copyChunkReferencedPackages = (distDir, seen) => {
16074
- const distRoot = resolve36(distDir);
16639
+ const distRoot = resolve37(distDir);
16075
16640
  for (const filePath of collectRuntimeRewriteRoots(distDir)) {
16076
- if (resolve36(dirname27(filePath)) === distRoot)
16641
+ if (resolve37(dirname28(filePath)) === distRoot)
16077
16642
  continue;
16078
16643
  const source = readFileSync39(filePath, "utf-8");
16079
16644
  for (const match of source.matchAll(MODULE_SPECIFIER_RE)) {
@@ -16109,7 +16674,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
16109
16674
  const { masked, restore } = maskLiterals(source);
16110
16675
  const rewrittenMasked = masked.replace(MODULE_SPECIFIER_RE, (match, prefix, quote, specifier) => {
16111
16676
  if (typeof specifier === "string" && specifier.startsWith(".")) {
16112
- enqueue(resolveRuntimeJsFile(resolve36(dirname27(filePath), specifier)));
16677
+ enqueue(resolveRuntimeJsFile(resolve37(dirname28(filePath), specifier)));
16113
16678
  return match;
16114
16679
  }
16115
16680
  const packageImportTarget = resolveRuntimeJsFile(resolvePackageImportEntryFile(filePath, specifier) ?? "");
@@ -16130,7 +16695,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
16130
16695
  }
16131
16696
  }, generateEntrypoint = (distDir, serverEntry, prerenderMap, version2, buildConfig) => {
16132
16697
  const allFiles = collectFiles2(distDir);
16133
- const serverBundleName = `${basename12(serverEntry).replace(/\.[^.]+$/, "")}.js`;
16698
+ const serverBundleName = `${basename13(serverEntry).replace(/\.[^.]+$/, "")}.js`;
16134
16699
  const embeddedSkip = new Set(["_compile_entrypoint.ts"]);
16135
16700
  const assetSkip = new Set([
16136
16701
  serverBundleName,
@@ -16138,12 +16703,12 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
16138
16703
  "_compile_entrypoint.ts"
16139
16704
  ]);
16140
16705
  const embeddedFiles = allFiles.filter((file) => {
16141
- const rel = relative23(distDir, file);
16706
+ const rel = relative24(distDir, file);
16142
16707
  if (embeddedSkip.has(rel))
16143
16708
  return false;
16144
16709
  return true;
16145
16710
  });
16146
- const clientFiles = embeddedFiles.filter((file) => shouldEmbedCompiledAsset(relative23(distDir, file), assetSkip));
16711
+ const clientFiles = embeddedFiles.filter((file) => shouldEmbedCompiledAsset(relative24(distDir, file), assetSkip));
16147
16712
  const imports = [];
16148
16713
  const nativeImports = [];
16149
16714
  const nativeMappings = [];
@@ -16153,19 +16718,19 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
16153
16718
  const nativeAssets = resolveCompileNativeAssets(buildConfig);
16154
16719
  nativeAssets.forEach((asset, idx) => {
16155
16720
  const varName = `__native${idx}`;
16156
- const importSpecifier = asset.import.startsWith(".") ? resolve36(process.cwd(), asset.import) : asset.import;
16721
+ const importSpecifier = asset.import.startsWith(".") ? resolve37(process.cwd(), asset.import) : asset.import;
16157
16722
  nativeImports.push(`import ${varName} from ${JSON.stringify(importSpecifier)} with { type: "file" };`);
16158
16723
  nativeMappings.push(` [${JSON.stringify(asset.env)}, resolveNativeAssetPath(${varName})],`);
16159
16724
  });
16160
16725
  embeddedFiles.forEach((filePath, idx) => {
16161
- const rel = relative23(distDir, filePath).replace(/\\/g, "/");
16726
+ const rel = relative24(distDir, filePath).replace(/\\/g, "/");
16162
16727
  const varName = `__a${idx}`;
16163
16728
  embeddedVarMap.set(rel, varName);
16164
16729
  imports.push(`import ${varName} from "./${rel}" with { type: "file" };`);
16165
16730
  embeddedMappings.push(` ["${rel}", ${varName}],`);
16166
16731
  });
16167
16732
  clientFiles.forEach((filePath) => {
16168
- const rel = relative23(distDir, filePath).replace(/\\/g, "/");
16733
+ const rel = relative24(distDir, filePath).replace(/\\/g, "/");
16169
16734
  const varName = embeddedVarMap.get(rel);
16170
16735
  if (!varName)
16171
16736
  return;
@@ -16179,7 +16744,7 @@ var cliTag4 = (color, message) => `\x1B[2m${formatTimestamp()}\x1B[0m ${color}[c
16179
16744
  const pageVarMap = new Map;
16180
16745
  const prerenderEntries = Array.from(prerenderMap.entries());
16181
16746
  prerenderEntries.forEach(([route, filePath]) => {
16182
- const rel = relative23(distDir, filePath).replace(/\\/g, "/");
16747
+ const rel = relative24(distDir, filePath).replace(/\\/g, "/");
16183
16748
  const varName = embeddedVarMap.get(rel);
16184
16749
  if (varName)
16185
16750
  pageVarMap.set(route, varName);
@@ -16212,7 +16777,7 @@ import { buildGlobalWSHandler } from "elysia/ws";
16212
16777
  const SERVER_MODULE = (runtimeDir: string) => import(pathToFileURL(join(runtimeDir, ${JSON.stringify(serverBundleName)})).href);
16213
16778
  const RUNTIME_BUILD_ID = ${JSON.stringify(runtimeBuildId)};
16214
16779
  const RUNTIME_CONFIG_SOURCE = ${JSON.stringify(runtimeConfigSource)};
16215
- const ORIGINAL_BUILD_DIR = ${JSON.stringify(resolve36(distDir))};
16780
+ const ORIGINAL_BUILD_DIR = ${JSON.stringify(resolve37(distDir))};
16216
16781
  const ORIGINAL_BUILD_DIR_NORMALIZED = ORIGINAL_BUILD_DIR.replace(/\\\\/g, "/");
16217
16782
  const EMBEDDED_NATIVE_AUTH_CLIENTS = ${JSON.stringify(process.env[ABSOLUTE_NATIVE_AUTH_CLIENTS_ENV])};
16218
16783
 
@@ -16633,17 +17198,17 @@ console.log(\`
16633
17198
  });
16634
17199
  }
16635
17200
  }), compile = async (serverEntry, outdir, outfile, configPath2) => {
16636
- const resolvedOutdir = resolve36(outdir ?? "dist");
17201
+ const resolvedOutdir = resolve37(outdir ?? "dist");
16637
17202
  await withBuildDirectoryLock(resolvedOutdir, () => compileUnlocked(serverEntry, resolvedOutdir, outfile, configPath2));
16638
17203
  }, compileUnlocked = async (serverEntry, resolvedOutdir, outfile, configPath2) => {
16639
17204
  const configuredPrerenderPort = env5.COMPILE_PORT === undefined ? Number(env5.PORT) : Number(env5.COMPILE_PORT);
16640
17205
  const prerenderPort = configuredPrerenderPort > 0 ? configuredPrerenderPort : await findFreePort();
16641
17206
  killStaleProcesses(prerenderPort);
16642
- const entryName = basename12(serverEntry).replace(/\.[^.]+$/, "");
16643
- const resolvedOutfile = resolve36(outfile ?? "compiled-server");
17207
+ const entryName = basename13(serverEntry).replace(/\.[^.]+$/, "");
17208
+ const resolvedOutfile = resolve37(outfile ?? "compiled-server");
16644
17209
  const absoluteVersion = resolvePackageVersion3([
16645
- resolve36(import.meta.dir, "..", "..", "..", "package.json"),
16646
- resolve36(import.meta.dir, "..", "..", "package.json")
17210
+ resolve37(import.meta.dir, "..", "..", "..", "package.json"),
17211
+ resolve37(import.meta.dir, "..", "..", "package.json")
16647
17212
  ]);
16648
17213
  compileBanner(absoluteVersion);
16649
17214
  const totalStart = performance.now();
@@ -16656,8 +17221,8 @@ console.log(\`
16656
17221
  installAbsoluteMobileAuthEnvironment(process.cwd(), normalizeAbsoluteMobileConfig(buildConfig.mobile, process.cwd()));
16657
17222
  try {
16658
17223
  const build2 = await resolveBuildModule3([
16659
- resolve36(import.meta.dir, "..", "..", "core", "build"),
16660
- resolve36(import.meta.dir, "..", "build")
17224
+ resolve37(import.meta.dir, "..", "..", "core", "build"),
17225
+ resolve37(import.meta.dir, "..", "build")
16661
17226
  ]);
16662
17227
  if (!build2)
16663
17228
  throw new Error("Could not locate build module");
@@ -16679,11 +17244,11 @@ console.log(\`
16679
17244
  buildConfig.htmxDirectory
16680
17245
  ].filter((dir) => Boolean(dir));
16681
17246
  const islandRegistrySpec = buildConfig.islands?.registry;
16682
- const islandRegistryPlugin = islandRegistrySpec ? createIslandRegistryDefinitionPlugin(await loadIslandRegistryBuildInfo(resolve36(islandRegistrySpec))) : undefined;
16683
- const serverBundleEntryDirectory = join45(resolvedOutdir, ".absolutejs-server-entry");
17247
+ const islandRegistryPlugin = islandRegistrySpec ? createIslandRegistryDefinitionPlugin(await loadIslandRegistryBuildInfo(resolve37(islandRegistrySpec))) : undefined;
17248
+ const serverBundleEntryDirectory = join46(resolvedOutdir, ".absolutejs-server-entry");
16684
17249
  mkdirSync18(serverBundleEntryDirectory, { recursive: true });
16685
- const typeboxSetupEntry = join45(serverBundleEntryDirectory, "_typebox_setup.ts");
16686
- const serverBundleEntry = join45(serverBundleEntryDirectory, basename12(serverEntry));
17250
+ const typeboxSetupEntry = join46(serverBundleEntryDirectory, "_typebox_setup.ts");
17251
+ const serverBundleEntry = join46(serverBundleEntryDirectory, basename13(serverEntry));
16687
17252
  writeFileSync21(typeboxSetupEntry, `import { setupTypebox } from 'elysia';
16688
17253
  import * as compile from 'typebox/compile';
16689
17254
  import * as schema from 'typebox/schema';
@@ -16694,7 +17259,7 @@ import * as value from 'typebox/value';
16694
17259
  setupTypebox({ typebox: { compile, schema, system, type, value } });
16695
17260
  `);
16696
17261
  writeFileSync21(serverBundleEntry, `import './_typebox_setup';
16697
- import * as serverModule from ${JSON.stringify(resolve36(serverEntry))};
17262
+ import * as serverModule from ${JSON.stringify(resolve37(serverEntry))};
16698
17263
 
16699
17264
  export const server = serverModule.server ?? serverModule.app ?? serverModule.default;
16700
17265
  export default server;
@@ -16708,7 +17273,7 @@ export default server;
16708
17273
  ...islandRegistryPlugin ? [islandRegistryPlugin] : [],
16709
17274
  ...buildConfig.mobile ? [
16710
17275
  createAbsoluteMobileRouteMetadataPlugin({
16711
- entry: resolve36(serverEntry)
17276
+ entry: resolve37(serverEntry)
16712
17277
  })
16713
17278
  ] : [],
16714
17279
  createElysiaOpenApiTypeboxPlugin(),
@@ -16732,13 +17297,13 @@ export default server;
16732
17297
  console.error(cliTag4("\x1B[31m", "Server bundle failed."));
16733
17298
  process.exit(1);
16734
17299
  }
16735
- const outputPath = resolve36(resolvedOutdir, `${entryName}.js`);
17300
+ const outputPath = resolve37(resolvedOutdir, `${entryName}.js`);
16736
17301
  if (!existsSync41(outputPath)) {
16737
17302
  console.error(cliTag4("\x1B[31m", `Expected output not found: ${outputPath}`));
16738
17303
  process.exit(1);
16739
17304
  }
16740
- if (existsSync41(resolve36(resolvedOutdir, "angular", "vendor", "server"))) {
16741
- const vendorDir = resolve36(resolvedOutdir, "angular", "vendor", "server");
17305
+ if (existsSync41(resolve37(resolvedOutdir, "angular", "vendor", "server"))) {
17306
+ const vendorDir = resolve37(resolvedOutdir, "angular", "vendor", "server");
16742
17307
  const vendorEntries = readdirSync7(vendorDir).filter((fileName) => fileName.endsWith(".js"));
16743
17308
  const angularServerVendorPaths = {};
16744
17309
  for (const file of vendorEntries) {
@@ -16747,7 +17312,7 @@ export default server;
16747
17312
  if (scope !== "angular" || rest.length === 0)
16748
17313
  continue;
16749
17314
  const specifier = `@angular/${rest.join("/")}`;
16750
- const relPath = relative23(dirname27(outputPath), resolve36(vendorDir, file));
17315
+ const relPath = relative24(dirname28(outputPath), resolve37(vendorDir, file));
16751
17316
  angularServerVendorPaths[specifier] = relPath.startsWith(".") ? relPath : `./${relPath}`;
16752
17317
  }
16753
17318
  if (Object.keys(angularServerVendorPaths).length > 0) {
@@ -16759,7 +17324,7 @@ export default server;
16759
17324
  copyServerRuntimeAssetReferences(resolvedOutdir);
16760
17325
  const prerenderStart = performance.now();
16761
17326
  process.stdout.write(cliTag4("\x1B[36m", "Pre-rendering pages"));
16762
- rmSync7(join45(resolvedOutdir, "_prerendered"), {
17327
+ rmSync7(join46(resolvedOutdir, "_prerendered"), {
16763
17328
  force: true,
16764
17329
  recursive: true
16765
17330
  });
@@ -16789,9 +17354,9 @@ export default server;
16789
17354
  const compileStart = performance.now();
16790
17355
  process.stdout.write(cliTag4("\x1B[36m", "Compiling standalone executable"));
16791
17356
  const entrypointCode = generateEntrypoint(resolvedOutdir, serverEntry, prerenderMap, absoluteVersion, buildConfig);
16792
- const entrypointPath = join45(resolvedOutdir, "_compile_entrypoint.ts");
17357
+ const entrypointPath = join46(resolvedOutdir, "_compile_entrypoint.ts");
16793
17358
  await Bun.write(entrypointPath, entrypointCode);
16794
- mkdirSync18(dirname27(resolvedOutfile), { recursive: true });
17359
+ mkdirSync18(dirname28(resolvedOutfile), { recursive: true });
16795
17360
  const result = await Bun.build({
16796
17361
  compile: { outfile: resolvedOutfile },
16797
17362
  define: { "process.env.NODE_ENV": '"production"' },
@@ -16820,7 +17385,7 @@ export default server;
16820
17385
  const size = (Bun.file(resolvedOutfile).size / BYTES_PER_MB).toFixed(0);
16821
17386
  const totalDuration = getDurationString(performance.now() - totalStart);
16822
17387
  console.log(cliTag4("\x1B[32m", `Compiled to ${resolvedOutfile} (${size}MB) in ${totalDuration}`));
16823
- console.log(cliTag4("\x1B[2m", `Run with: ./${basename12(resolvedOutfile)}`));
17388
+ console.log(cliTag4("\x1B[2m", `Run with: ./${basename13(resolvedOutfile)}`));
16824
17389
  sendTelemetryEvent("compile:complete", {
16825
17390
  durationMs: Math.round(performance.now() - totalStart),
16826
17391
  entry: serverEntry,
@@ -16874,15 +17439,15 @@ var init_compile = __esm(() => {
16874
17439
  });
16875
17440
 
16876
17441
  // src/mobile/nativeDeepLinks.ts
16877
- import { readFile as readFile12, rename as rename8, writeFile as writeFile9 } from "fs/promises";
16878
- import { join as join46 } from "path";
17442
+ import { readFile as readFile13, rename as rename9, writeFile as writeFile10 } from "fs/promises";
17443
+ import { join as join47 } from "path";
16879
17444
  var START_MARKER = "<!-- absolutejs:deep-links:start -->", END_MARKER = "<!-- absolutejs:deep-links:end -->", IOS_ENTITLEMENTS = "App/AbsoluteJS.entitlements", NOT_FOUND = -1, escapeXml = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;"), writeChangedFile = async (path, source) => {
16880
- const current = await readFile12(path, "utf8");
17445
+ const current = await readFile13(path, "utf8");
16881
17446
  if (current === source)
16882
17447
  return false;
16883
17448
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
16884
- await writeFile9(temporary, source, { flag: "wx" });
16885
- await rename8(temporary, path);
17449
+ await writeFile10(temporary, source, { flag: "wx" });
17450
+ await rename9(temporary, path);
16886
17451
  return true;
16887
17452
  }, replaceManagedRegion = (source, region, insertAt) => {
16888
17453
  const start2 = source.indexOf(START_MARKER);
@@ -16924,8 +17489,8 @@ ${hosts}
16924
17489
  ${END_MARKER}
16925
17490
  `;
16926
17491
  }, configureAndroid = async (config) => {
16927
- const path = join46(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
16928
- const source = await readFile12(path, "utf8");
17492
+ const path = join47(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
17493
+ const source = await readFile13(path, "utf8");
16929
17494
  const mainActivity = source.indexOf('android:name=".MainActivity"');
16930
17495
  if (mainActivity === NOT_FOUND) {
16931
17496
  throw new TypeError("Android MainActivity was not found.");
@@ -16948,8 +17513,8 @@ ${hosts}
16948
17513
  </array>
16949
17514
  ${END_MARKER}
16950
17515
  `, configureIosInfo = async (config) => {
16951
- const path = join46(config.nativeProjectDirectory, "ios/App/App/Info.plist");
16952
- const source = await readFile12(path, "utf8");
17516
+ const path = join47(config.nativeProjectDirectory, "ios/App/App/Info.plist");
17517
+ const source = await readFile13(path, "utf8");
16953
17518
  const region = config.deepLinkScheme ? iosSchemeRegion(config.deepLinkScheme) : ` ${START_MARKER}
16954
17519
  ${END_MARKER}
16955
17520
  `;
@@ -16970,10 +17535,10 @@ ${domains}
16970
17535
  </plist>
16971
17536
  `;
16972
17537
  }, configureIosEntitlements = async (config) => {
16973
- const path = join46(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
17538
+ const path = join47(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
16974
17539
  let current = "";
16975
17540
  try {
16976
- current = await readFile12(path, "utf8");
17541
+ current = await readFile13(path, "utf8");
16977
17542
  } catch (error) {
16978
17543
  if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
16979
17544
  throw error;
@@ -16983,12 +17548,12 @@ ${domains}
16983
17548
  if (current === source)
16984
17549
  return false;
16985
17550
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
16986
- await writeFile9(temporary, source, { flag: "wx" });
16987
- await rename8(temporary, path);
17551
+ await writeFile10(temporary, source, { flag: "wx" });
17552
+ await rename9(temporary, path);
16988
17553
  return true;
16989
17554
  }, configureIosProject = async (config) => {
16990
- const path = join46(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
16991
- const source = await readFile12(path, "utf8");
17555
+ const path = join47(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
17556
+ const source = await readFile13(path, "utf8");
16992
17557
  const declarations = [
16993
17558
  ...source.matchAll(/CODE_SIGN_ENTITLEMENTS = ([^;]+);/g)
16994
17559
  ].map((match) => match[1]);
@@ -17026,28 +17591,28 @@ ${domains}
17026
17591
  var init_nativeDeepLinks = () => {};
17027
17592
 
17028
17593
  // src/mobile/nativeDeviceCapabilities.ts
17029
- import { readFile as readFile13, rename as rename9, writeFile as writeFile10 } from "fs/promises";
17030
- import { join as join47 } from "path";
17594
+ import { readFile as readFile14, rename as rename10, writeFile as writeFile11 } from "fs/promises";
17595
+ import { join as join48 } from "path";
17031
17596
  var START_MARKER2 = "<!-- absolutejs:device-capabilities:start -->", END_MARKER2 = "<!-- absolutejs:device-capabilities:end -->", NOT_FOUND2 = -1, IOS_PRIVACY_FILE_REFERENCE = "A85D0C000000000000000001", IOS_PRIVACY_BUILD_FILE = "A85D0C000000000000000002", PUSH_START_MARKER = "absolutejs:push-notifications:start", PUSH_END_MARKER = "absolutejs:push-notifications:end", escapeXml2 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;"), writeChangedFile2 = async (path, source) => {
17032
- const current = await readFile13(path, "utf8");
17597
+ const current = await readFile14(path, "utf8");
17033
17598
  if (current === source)
17034
17599
  return false;
17035
17600
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
17036
- await writeFile10(temporary, source, { flag: "wx" });
17037
- await rename9(temporary, path);
17601
+ await writeFile11(temporary, source, { flag: "wx" });
17602
+ await rename10(temporary, path);
17038
17603
  return true;
17039
17604
  }, writeOptionalChangedFile = async (path, source) => {
17040
17605
  const current = await optionalSource(path);
17041
17606
  if (current === source)
17042
17607
  return false;
17043
17608
  if (current === null) {
17044
- await writeFile10(path, source, { flag: "wx" });
17609
+ await writeFile11(path, source, { flag: "wx" });
17045
17610
  return true;
17046
17611
  }
17047
17612
  return writeChangedFile2(path, source);
17048
17613
  }, optionalSource = async (path) => {
17049
17614
  try {
17050
- return await readFile13(path, "utf8");
17615
+ return await readFile14(path, "utf8");
17051
17616
  } catch (error) {
17052
17617
  if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "ENOENT")
17053
17618
  return null;
@@ -17149,13 +17714,13 @@ ${entries}
17149
17714
  return false;
17150
17715
  if (current !== null)
17151
17716
  return writeChangedFile2(path, source);
17152
- await writeFile10(path, source, { flag: "wx" });
17717
+ await writeFile11(path, source, { flag: "wx" });
17153
17718
  return true;
17154
17719
  }, configureIosPrivacyProject = async (config, requirements) => {
17155
17720
  if (requirements.iosPrivacyAccessedApis.length === 0)
17156
17721
  return false;
17157
- const projectPath = join47(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
17158
- const project = await readFile13(projectPath, "utf8");
17722
+ const projectPath = join48(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
17723
+ const project = await readFile14(projectPath, "utf8");
17159
17724
  return writeChangedFile2(projectPath, addIosPrivacyProjectReference(project));
17160
17725
  }, addIosPrivacyProjectReference = (source) => {
17161
17726
  const fileMatch = source.match(/([A-F0-9]{24}) \/\* PrivacyInfo\.xcprivacy \*\/ = \{isa = PBXFileReference;/u);
@@ -17205,8 +17770,8 @@ ${next.slice(index)}`;
17205
17770
  }
17206
17771
  return next;
17207
17772
  }, configureIos2 = async (config, plan) => {
17208
- const path = join47(config.nativeProjectDirectory, "ios/App/App/Info.plist");
17209
- const source = await readFile13(path, "utf8");
17773
+ const path = join48(config.nativeProjectDirectory, "ios/App/App/Info.plist");
17774
+ const source = await readFile14(path, "utf8");
17210
17775
  const requirements = absoluteDeviceNativeRequirements(plan);
17211
17776
  const existingSystemBars = source.match(/<key>UIViewControllerBasedStatusBarAppearance<\/key>\s*<(true|false)\s*\/>/u);
17212
17777
  const ownedStart = source.indexOf(START_MARKER2);
@@ -17226,7 +17791,7 @@ ${content}
17226
17791
  ${END_MARKER2}
17227
17792
  ` : "";
17228
17793
  const infoChanged = await writeChangedFile2(path, managed(source, region, source.lastIndexOf("</dict>")));
17229
- const privacyPath = join47(config.nativeProjectDirectory, "ios/App/App/PrivacyInfo.xcprivacy");
17794
+ const privacyPath = join48(config.nativeProjectDirectory, "ios/App/App/PrivacyInfo.xcprivacy");
17230
17795
  const privacyCurrent = await optionalSource(privacyPath);
17231
17796
  const privacySource = privacyManifestSource(privacyCurrent, requirements);
17232
17797
  const [privacyChanged, projectChanged, pushChanged] = await Promise.all([
@@ -17236,7 +17801,7 @@ ${content}
17236
17801
  ]);
17237
17802
  return infoChanged || privacyChanged || projectChanged || pushChanged;
17238
17803
  }, configureIosPushNotifications = async (config, enabled) => {
17239
- const entitlementsPath = join47(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
17804
+ const entitlementsPath = join48(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
17240
17805
  const entitlements = await optionalSource(entitlementsPath);
17241
17806
  if (entitlements === null && !enabled)
17242
17807
  return false;
@@ -17248,7 +17813,7 @@ ${content}
17248
17813
  <!-- ${PUSH_END_MARKER} -->
17249
17814
  ` : "";
17250
17815
  const nextEntitlements = replacePushRegion(entitlements, entitlementRegion, entitlements.lastIndexOf("</dict>"));
17251
- const delegatePath = join47(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
17816
+ const delegatePath = join48(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
17252
17817
  const delegate = await optionalSource(delegatePath);
17253
17818
  if (delegate === null && !enabled)
17254
17819
  return false;
@@ -17295,8 +17860,8 @@ ${content}
17295
17860
  throw new TypeError("Could not find a safe native project location for push notifications.");
17296
17861
  return `${source.slice(0, insertion)}${region}${source.slice(insertion)}`;
17297
17862
  }, configureAndroid2 = async (config, plan) => {
17298
- const path = join47(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
17299
- const source = await readFile13(path, "utf8");
17863
+ const path = join48(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
17864
+ const source = await readFile14(path, "utf8");
17300
17865
  const permissions = absoluteDeviceNativeRequirements(plan).androidPermissions;
17301
17866
  const content = permissions.map((permission) => ` <uses-permission android:name="${escapeXml2(permission)}" />`).join(`
17302
17867
  `);
@@ -17331,7 +17896,7 @@ ${content}
17331
17896
  throw new TypeError(`Android google-services.json does not contain package ${config.appId}.`);
17332
17897
  const [manifestChanged, firebaseChanged] = await Promise.all([
17333
17898
  writeChangedFile2(path, nextManifest),
17334
- writeOptionalChangedFile(join47(config.nativeProjectDirectory, "android/app/google-services.json"), firebaseSource)
17899
+ writeOptionalChangedFile(join48(config.nativeProjectDirectory, "android/app/google-services.json"), firebaseSource)
17335
17900
  ]);
17336
17901
  return manifestChanged || firebaseChanged;
17337
17902
  }, applyAbsoluteNativeDeviceCapabilities = async (projectRoot, config, platforms = config.platforms, plan = resolveAbsoluteDeviceCapabilityPlan(projectRoot)) => {
@@ -17355,15 +17920,15 @@ var init_nativeDeviceCapabilities = __esm(() => {
17355
17920
  });
17356
17921
 
17357
17922
  // src/mobile/nativeBackgroundSync.ts
17358
- import { readFile as readFile14, rename as rename10, writeFile as writeFile11 } from "fs/promises";
17359
- import { join as join48 } from "path";
17923
+ import { readFile as readFile15, rename as rename11, writeFile as writeFile12 } from "fs/promises";
17924
+ import { join as join49 } from "path";
17360
17925
  var writeChanged = async (path, source) => {
17361
- const current = await readFile14(path, "utf8");
17926
+ const current = await readFile15(path, "utf8");
17362
17927
  if (current === source)
17363
17928
  return false;
17364
17929
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
17365
- await writeFile11(temporary, source, { flag: "wx" });
17366
- await rename10(temporary, path);
17930
+ await writeFile12(temporary, source, { flag: "wx" });
17931
+ await rename11(temporary, path);
17367
17932
  return true;
17368
17933
  }, replaceRegion = (source, start2, end, region, insert) => {
17369
17934
  const existingStart = source.indexOf(start2);
@@ -17439,11 +18004,11 @@ ${makeRegion(values)} </array>
17439
18004
  if (!platforms.includes("ios") || !projectUsesAbsoluteAuth(projectRoot) || !projectUsesAbsoluteSync(projectRoot))
17440
18005
  return { changed: false };
17441
18006
  const identifier = `${config.appId}.absolutejs.background-sync`;
17442
- const infoPath = join48(config.nativeProjectDirectory, "ios/App/App/Info.plist");
17443
- const info2 = await readFile14(infoPath, "utf8");
18007
+ const infoPath = join49(config.nativeProjectDirectory, "ios/App/App/Info.plist");
18008
+ const info2 = await readFile15(infoPath, "utf8");
17444
18009
  const nextInfo = ensurePlistArrayValues(ensurePlistArrayValues(info2, "BGTaskSchedulerPermittedIdentifiers", [identifier], "background-sync-identifiers"), "UIBackgroundModes", ["fetch", "processing"], "background-sync-modes");
17445
- const delegatePath = join48(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
17446
- let delegate = await readFile14(delegatePath, "utf8");
18010
+ const delegatePath = join49(config.nativeProjectDirectory, "ios/App/App/AppDelegate.swift");
18011
+ let delegate = await readFile15(delegatePath, "utf8");
17447
18012
  if (!delegate.includes("import AbsoluteSyncCapacitor")) {
17448
18013
  const importIndex = delegate.lastIndexOf("import Capacitor");
17449
18014
  if (importIndex < 0)
@@ -17475,14 +18040,14 @@ var init_nativeBackgroundSync = __esm(() => {
17475
18040
 
17476
18041
  // src/mobile/associationFiles.ts
17477
18042
  import {
17478
- access as access7,
17479
- mkdir as mkdir10,
17480
- readFile as readFile15,
17481
- rename as rename11,
17482
- rm as rm7,
17483
- writeFile as writeFile12
18043
+ access as access8,
18044
+ mkdir as mkdir11,
18045
+ readFile as readFile16,
18046
+ rename as rename12,
18047
+ rm as rm8,
18048
+ writeFile as writeFile13
17484
18049
  } from "fs/promises";
17485
- import { resolve as resolve37 } from "path";
18050
+ import { resolve as resolve38 } from "path";
17486
18051
  import { Elysia } from "elysia";
17487
18052
  var OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_OK = 200, VERIFY_TIMEOUT_MS = 1e4, ANDROID_ASSOCIATION_PATH = "/.well-known/assetlinks.json", APPLE_ASSOCIATION_PATH = "/.well-known/apple-app-site-association", missingIdentity = (field, platform6) => new TypeError(`${field} is required to publish ${platform6} deep-link association files.`), createAppleDocument = (config, requireAll) => {
17488
18053
  if (!config.platforms.includes("ios"))
@@ -17535,7 +18100,7 @@ var OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_OK = 200, VERI
17535
18100
  }, writeAtomic = async (path, source) => {
17536
18101
  let current;
17537
18102
  try {
17538
- current = await readFile15(path, "utf8");
18103
+ current = await readFile16(path, "utf8");
17539
18104
  } catch (error) {
17540
18105
  if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
17541
18106
  throw error;
@@ -17544,21 +18109,21 @@ var OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_OK = 200, VERI
17544
18109
  if (current === source)
17545
18110
  return false;
17546
18111
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
17547
- await writeFile12(temporary, source, { flag: "wx" });
17548
- await rename11(temporary, path);
18112
+ await writeFile13(temporary, source, { flag: "wx" });
18113
+ await rename12(temporary, path);
17549
18114
  return true;
17550
- }, exists2 = async (path) => {
18115
+ }, exists3 = async (path) => {
17551
18116
  try {
17552
- await access7(path);
18117
+ await access8(path);
17553
18118
  return true;
17554
18119
  } catch {
17555
18120
  return false;
17556
18121
  }
17557
18122
  }, assertOwnedOutput = async (root) => {
17558
- const path = resolve37(root, OWNERSHIP_FILE);
18123
+ const path = resolve38(root, OWNERSHIP_FILE);
17559
18124
  let ownership;
17560
18125
  try {
17561
- ownership = JSON.parse(await readFile15(path, "utf8"));
18126
+ ownership = JSON.parse(await readFile16(path, "utf8"));
17562
18127
  } catch {
17563
18128
  throw new TypeError(`Association output ${root} already exists and is not owned by AbsoluteJS.`);
17564
18129
  }
@@ -17566,26 +18131,26 @@ var OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_OK = 200, VERI
17566
18131
  throw new TypeError(`Association output ${root} has an unsupported ownership manifest.`);
17567
18132
  }
17568
18133
  }, publishGeneratedDirectory = async (temporary, root) => {
17569
- const hasCurrent = await exists2(root);
18134
+ const hasCurrent = await exists3(root);
17570
18135
  if (hasCurrent)
17571
18136
  await assertOwnedOutput(root);
17572
18137
  const backup = `${root}.${crypto.randomUUID()}.previous`;
17573
18138
  if (hasCurrent)
17574
- await rename11(root, backup);
18139
+ await rename12(root, backup);
17575
18140
  try {
17576
- await rename11(temporary, root);
18141
+ await rename12(temporary, root);
17577
18142
  } catch (error) {
17578
18143
  if (hasCurrent)
17579
- await rename11(backup, root);
18144
+ await rename12(backup, root);
17580
18145
  throw error;
17581
18146
  }
17582
18147
  if (hasCurrent)
17583
- await rm7(backup, { force: true, recursive: true });
18148
+ await rm8(backup, { force: true, recursive: true });
17584
18149
  }, materializeHost = async (root, host2, files) => {
17585
- const directory = resolve37(root, host2, ".well-known");
17586
- await mkdir10(directory, { recursive: true });
18150
+ const directory = resolve38(root, host2, ".well-known");
18151
+ await mkdir11(directory, { recursive: true });
17587
18152
  return Promise.all(files.map(async ([name, document]) => {
17588
- const path = resolve37(directory, name);
18153
+ const path = resolve38(directory, name);
17589
18154
  await writeAtomic(path, `${JSON.stringify(document, null, 2)}
17590
18155
  `);
17591
18156
  return path;
@@ -17608,7 +18173,7 @@ var OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_OK = 200, VERI
17608
18173
  });
17609
18174
  return endpoints;
17610
18175
  }), materializeAbsoluteMobileAssociationFiles = async (config, outputDirectory) => {
17611
- const root = resolve37(outputDirectory);
18176
+ const root = resolve38(outputDirectory);
17612
18177
  const temporary = `${root}.${crypto.randomUUID()}.tmp`;
17613
18178
  const documents = createAbsoluteMobileAssociationDocuments(config, {
17614
18179
  requireAll: true
@@ -17619,16 +18184,16 @@ var OWNERSHIP_FILE = ".absolutejs-mobile-associations.json", HTTP_OK = 200, VERI
17619
18184
  if (documents.apple) {
17620
18185
  files.push(["apple-app-site-association", documents.apple]);
17621
18186
  }
17622
- await mkdir10(temporary, { recursive: true });
18187
+ await mkdir11(temporary, { recursive: true });
17623
18188
  try {
17624
18189
  const temporaryPaths = (await Promise.all(config.deepLinkHosts.map((host2) => materializeHost(temporary, host2, files)))).flat();
17625
- await writeAtomic(resolve37(temporary, OWNERSHIP_FILE), `${JSON.stringify({ format: 1, hosts: config.deepLinkHosts }, null, 2)}
18190
+ await writeAtomic(resolve38(temporary, OWNERSHIP_FILE), `${JSON.stringify({ format: 1, hosts: config.deepLinkHosts }, null, 2)}
17626
18191
  `);
17627
18192
  await publishGeneratedDirectory(temporary, root);
17628
- const written = temporaryPaths.map((path) => resolve37(root, path.slice(temporary.length + 1)));
18193
+ const written = temporaryPaths.map((path) => resolve38(root, path.slice(temporary.length + 1)));
17629
18194
  return { root, written };
17630
18195
  } catch (error) {
17631
- await rm7(temporary, { force: true, recursive: true });
18196
+ await rm8(temporary, { force: true, recursive: true });
17632
18197
  throw error;
17633
18198
  }
17634
18199
  }, verifyAbsoluteMobileAssociationFiles = async (config, request = globalThis.fetch) => {
@@ -17666,8 +18231,8 @@ var init_associationFiles = __esm(() => {
17666
18231
  });
17667
18232
 
17668
18233
  // src/mobile/androidWebView.ts
17669
- import { mkdir as mkdir11, writeFile as writeFile13 } from "fs/promises";
17670
- import { dirname as dirname28, resolve as resolve38 } from "path";
18234
+ import { mkdir as mkdir12, writeFile as writeFile14 } from "fs/promises";
18235
+ import { dirname as dirname29, resolve as resolve39 } from "path";
17671
18236
 
17672
18237
  class CdpConnection {
17673
18238
  diagnostics = [];
@@ -17938,9 +18503,9 @@ var CDP_COMMAND_TIMEOUT_MS = 1e4, WEBVIEW_ATTACH_TIMEOUT_MS = 30000, WEBVIEW_POL
17938
18503
  if (typeof data !== "string") {
17939
18504
  throw new Error("Android WebView screenshot returned no image data.");
17940
18505
  }
17941
- const absolutePath = resolve38(path);
17942
- await mkdir11(dirname28(absolutePath), { recursive: true });
17943
- await writeFile13(absolutePath, Buffer.from(data, "base64"));
18506
+ const absolutePath = resolve39(path);
18507
+ await mkdir12(dirname29(absolutePath), { recursive: true });
18508
+ await writeFile14(absolutePath, Buffer.from(data, "base64"));
17944
18509
  return absolutePath;
17945
18510
  },
17946
18511
  tap: async (coordinateX, coordinateY) => {
@@ -18071,21 +18636,21 @@ var DEFAULT_ROUTE_TIMEOUT_MS = 30000, DEFAULT_HMR_TIMEOUT_MS = 30000, routeExpre
18071
18636
  };
18072
18637
 
18073
18638
  // src/mobile/mobileBundleInspection.ts
18074
- import { createHash as createHash12 } from "crypto";
18075
- import { access as access8, readFile as readFile16, stat as stat2 } from "fs/promises";
18076
- import { join as join49, relative as relative24, resolve as resolve39 } from "path";
18639
+ import { createHash as createHash13 } from "crypto";
18640
+ import { access as access9, readFile as readFile17, stat as stat2 } from "fs/promises";
18641
+ import { join as join50, relative as relative25, resolve as resolve40 } from "path";
18077
18642
  var MOBILE_FRAMEWORKS, SHA256_PATTERN, isObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), portablePath = (projectRoot, path) => {
18078
- const value = relative24(resolve39(projectRoot), resolve39(path)).replaceAll("\\", "/");
18643
+ const value = relative25(resolve40(projectRoot), resolve40(path)).replaceAll("\\", "/");
18079
18644
  return value || ".";
18080
18645
  }, pathExists5 = async (path) => {
18081
18646
  try {
18082
- await access8(path);
18647
+ await access9(path);
18083
18648
  return true;
18084
18649
  } catch {
18085
18650
  return false;
18086
18651
  }
18087
18652
  }, readObject = async (path) => {
18088
- const value = JSON.parse(await readFile16(path, "utf8"));
18653
+ const value = JSON.parse(await readFile17(path, "utf8"));
18089
18654
  if (!isObject2(value))
18090
18655
  throw new TypeError("JSON root must be an object.");
18091
18656
  return value;
@@ -18099,8 +18664,8 @@ var MOBILE_FRAMEWORKS, SHA256_PATTERN, isObject2 = (value) => typeof value === "
18099
18664
  return value;
18100
18665
  }, requireBundleFile = async (root, value, field, expectedHash) => {
18101
18666
  const portable = requireString(value, field);
18102
- const path = resolve39(root, portable);
18103
- const normalizedRoot = resolve39(root);
18667
+ const path = resolve40(root, portable);
18668
+ const normalizedRoot = resolve40(root);
18104
18669
  if (path === normalizedRoot || !path.startsWith(`${normalizedRoot}/`))
18105
18670
  throw new TypeError(`${field} must remain inside the mobile bundle.`);
18106
18671
  if (!(await stat2(path).catch(() => {
@@ -18110,13 +18675,13 @@ var MOBILE_FRAMEWORKS, SHA256_PATTERN, isObject2 = (value) => typeof value === "
18110
18675
  if (expectedHash !== undefined) {
18111
18676
  if (!SHA256_PATTERN.test(expectedHash))
18112
18677
  throw new TypeError(`${field} has an invalid SHA-256 digest.`);
18113
- const actual = createHash12("sha256").update(await readFile16(path)).digest("hex");
18678
+ const actual = createHash13("sha256").update(await readFile17(path)).digest("hex");
18114
18679
  if (actual !== expectedHash)
18115
18680
  throw new TypeError(`${field} failed its SHA-256 integrity check.`);
18116
18681
  }
18117
18682
  return portable;
18118
18683
  }, inspectAbsoluteMobileBundle = async (config, projectRoot) => {
18119
- const manifestPath = join49(config.bundleDirectory, "absolute-mobile-manifest.json");
18684
+ const manifestPath = join50(config.bundleDirectory, "absolute-mobile-manifest.json");
18120
18685
  const manifest = portablePath(projectRoot, manifestPath);
18121
18686
  if (!await pathExists5(manifestPath))
18122
18687
  return { manifest, status: "missing" };
@@ -18216,11 +18781,11 @@ var init_mobileBundleInspection = __esm(() => {
18216
18781
  });
18217
18782
 
18218
18783
  // src/mobile/releaseDoctor.ts
18219
- import { access as access9, readFile as readFile17, readdir as readdir4 } from "fs/promises";
18220
- import { dirname as dirname29, extname as extname8, join as join50, relative as relative25 } from "path";
18784
+ import { access as access10, readFile as readFile18, readdir as readdir5 } from "fs/promises";
18785
+ import { dirname as dirname30, extname as extname8, join as join51, relative as relative26 } from "path";
18221
18786
  var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASSET_EXTENSIONS, EXACT_VERSION_PATTERN, NOT_FOUND3 = -1, LOCK_FILES, MANUAL_REVIEW, pathExists6 = async (path) => {
18222
18787
  try {
18223
- await access9(path);
18788
+ await access10(path);
18224
18789
  return true;
18225
18790
  } catch {
18226
18791
  return false;
@@ -18230,13 +18795,13 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18230
18795
  return findHmrAsset(path);
18231
18796
  if (!isFile2 || !RELEASE_ASSET_EXTENSIONS.has(extname8(path)))
18232
18797
  return;
18233
- const source = await readFile17(path, "utf8");
18798
+ const source = await readFile18(path, "utf8");
18234
18799
  return HMR_ASSET_PATTERN.test(source) ? path : undefined;
18235
18800
  }, findHmrAsset = async (root) => {
18236
18801
  if (!await pathExists6(root))
18237
18802
  return;
18238
- const entries = await readdir4(root, { withFileTypes: true });
18239
- const matches = await Promise.all(entries.map((entry) => inspectReleaseAsset(join50(root, entry.name), entry.isDirectory(), entry.isFile())));
18803
+ const entries = await readdir5(root, { withFileTypes: true });
18804
+ const matches = await Promise.all(entries.map((entry) => inspectReleaseAsset(join51(root, entry.name), entry.isDirectory(), entry.isFile())));
18240
18805
  return matches.find((match) => match !== undefined);
18241
18806
  }, pass = (id, detail, path) => ({ detail, id, path, status: "pass" }), fail5 = (id, detail, path, remediation) => ({
18242
18807
  detail,
@@ -18251,7 +18816,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18251
18816
  remediation,
18252
18817
  status: "warn"
18253
18818
  }), readJsonObject = async (path) => {
18254
- const value = JSON.parse(await readFile17(path, "utf8"));
18819
+ const value = JSON.parse(await readFile18(path, "utf8"));
18255
18820
  if (typeof value !== "object" || value === null || Array.isArray(value))
18256
18821
  throw new TypeError("JSON root must be an object.");
18257
18822
  return Object.fromEntries(Object.entries(value));
@@ -18267,7 +18832,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18267
18832
  }
18268
18833
  return declarations;
18269
18834
  }, versionCore = (version2) => version2.split("-")[0]?.split(".").slice(0, 2).join("."), capacitorVersionCheck = async (config, projectRoot) => {
18270
- const manifestPath = join50(projectRoot, "package.json");
18835
+ const manifestPath = join51(projectRoot, "package.json");
18271
18836
  try {
18272
18837
  const manifest = await readJsonObject(manifestPath);
18273
18838
  const declarations = packageDeclarations(manifest);
@@ -18280,7 +18845,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18280
18845
  const declared = declarations.get(name);
18281
18846
  if (!declared || !EXACT_VERSION_PATTERN.test(declared))
18282
18847
  throw new TypeError(`${name} must be a direct exact dependency.`);
18283
- const installed = await readJsonObject(join50(projectRoot, "node_modules", name, "package.json"));
18848
+ const installed = await readJsonObject(join51(projectRoot, "node_modules", name, "package.json"));
18284
18849
  if (installed.version !== declared)
18285
18850
  throw new TypeError(`${name} does not match its installed version.`);
18286
18851
  return declared;
@@ -18294,10 +18859,10 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18294
18859
  }
18295
18860
  }, dependencyLockCheck = async (projectRoot) => {
18296
18861
  const present = (await Promise.all(LOCK_FILES.map(async (name) => ({
18297
- exists: await pathExists6(join50(projectRoot, name)),
18862
+ exists: await pathExists6(join51(projectRoot, name)),
18298
18863
  name
18299
- })))).find(({ exists: exists3 }) => exists3);
18300
- return present ? pass("mobile.dependency-lock", `Dependency graph is locked by ${present.name}.`, join50(projectRoot, present.name)) : fail5("mobile.dependency-lock", "No supported dependency lockfile is present.", projectRoot, "Install dependencies with the project package manager and commit its lockfile before release.");
18864
+ })))).find(({ exists: exists4 }) => exists4);
18865
+ return present ? pass("mobile.dependency-lock", `Dependency graph is locked by ${present.name}.`, join51(projectRoot, present.name)) : fail5("mobile.dependency-lock", "No supported dependency lockfile is present.", projectRoot, "Install dependencies with the project package manager and commit its lockfile before release.");
18301
18866
  }, productionOriginCheck = (config, projectRoot) => {
18302
18867
  const origin = new URL(config.productionOrigin);
18303
18868
  return origin.protocol === "https:" ? pass("mobile.production-origin", "Production transport uses an HTTPS origin.") : fail5("mobile.production-origin", "A loopback development origin cannot be used for a signed release.", projectRoot, "Configure mobile.server.productionOrigin with the deployed HTTPS origin.");
@@ -18332,7 +18897,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18332
18897
  if (!await pathExists6(nativeConfigPath)) {
18333
18898
  return fail5("android.capacitor-config", "The generated Android Capacitor config is missing.", nativeConfigPath, "Run `absolute mobile sync android` before release validation.");
18334
18899
  }
18335
- const unsafe = isUnsafeCapacitorConfig(await readFile17(nativeConfigPath, "utf8"));
18900
+ const unsafe = isUnsafeCapacitorConfig(await readFile18(nativeConfigPath, "utf8"));
18336
18901
  return unsafe ? fail5("android.capacitor-config", "Android Capacitor config contains a development server URL, cleartext transport, navigation allowlist, or invalid JSON.", nativeConfigPath, "Run `absolute mobile sync android`; do not ship development transport overrides.") : pass("android.capacitor-config", "Android Capacitor config contains no development transport overrides.", nativeConfigPath);
18337
18902
  }, capacitorIdentityCheck = async (config, platform6, nativeConfigPath) => {
18338
18903
  try {
@@ -18347,12 +18912,12 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18347
18912
  if (!await pathExists6(manifestPath)) {
18348
18913
  return fail5("android.cleartext", "The Android manifest is missing.", manifestPath, "Run `absolute mobile sync android` before release validation.");
18349
18914
  }
18350
- const source = await readFile17(manifestPath, "utf8");
18915
+ const source = await readFile18(manifestPath, "utf8");
18351
18916
  const cleartext = /android:usesCleartextTraffic=["']true["']/u.test(source);
18352
18917
  const networkConfigName = source.match(/android:networkSecurityConfig=["']@xml\/([a-z0-9_]+)["']/u)?.[1];
18353
- const networkConfigPath = networkConfigName ? join50(dirname29(manifestPath), "res", "xml", `${networkConfigName}.xml`) : undefined;
18918
+ const networkConfigPath = networkConfigName ? join51(dirname30(manifestPath), "res", "xml", `${networkConfigName}.xml`) : undefined;
18354
18919
  const developmentTrustReference = /android:networkSecurityConfig=["']@xml\/absolutejs_dev_network_security["']/u.test(source);
18355
- const developmentTrustContents = networkConfigPath ? await readFile17(networkConfigPath, "utf8").then((value) => value.includes("@raw/absolutejs_dev_ca")).catch(() => false) : false;
18920
+ const developmentTrustContents = networkConfigPath ? await readFile18(networkConfigPath, "utf8").then((value) => value.includes("@raw/absolutejs_dev_ca")).catch(() => false) : false;
18356
18921
  const developmentTrust = developmentTrustReference || developmentTrustContents;
18357
18922
  return cleartext || developmentTrust ? fail5("android.cleartext", developmentTrust ? "Android still references the AbsoluteJS development certificate authority." : "Android explicitly permits cleartext traffic.", manifestPath, "Run `absolute mobile sync android`; do not ship development transport or trust overrides.") : pass("android.cleartext", "Android does not explicitly permit cleartext traffic.", manifestPath);
18358
18923
  }, hmrAssetsReleaseCheck = async (publicRoot) => {
@@ -18361,12 +18926,12 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18361
18926
  }, embeddedBundleReleaseCheck = async (config, projectRoot, platform6, publicRoot) => {
18362
18927
  const inspection = await inspectAbsoluteMobileBundle({ ...config, bundleDirectory: publicRoot }, projectRoot);
18363
18928
  if (inspection.status === "valid")
18364
- return pass(`${platform6}.bundle-integrity`, `Packaged mobile manifest, runtime, routes, and ${inspection.pageCount ?? 0} page asset(s) passed structural and SHA-256 validation.`, join50(publicRoot, "absolute-mobile-manifest.json"));
18365
- return fail5(`${platform6}.bundle-integrity`, inspection.status === "missing" ? "The packaged mobile manifest is missing." : `The packaged mobile bundle is invalid: ${inspection.issue ?? "unknown validation error"}`, join50(publicRoot, "absolute-mobile-manifest.json"), "Rebuild the production mobile bundle and run Capacitor sync for this platform.");
18929
+ return pass(`${platform6}.bundle-integrity`, `Packaged mobile manifest, runtime, routes, and ${inspection.pageCount ?? 0} page asset(s) passed structural and SHA-256 validation.`, join51(publicRoot, "absolute-mobile-manifest.json"));
18930
+ return fail5(`${platform6}.bundle-integrity`, inspection.status === "missing" ? "The packaged mobile manifest is missing." : `The packaged mobile bundle is invalid: ${inspection.issue ?? "unknown validation error"}`, join51(publicRoot, "absolute-mobile-manifest.json"), "Rebuild the production mobile bundle and run Capacitor sync for this platform.");
18366
18931
  }, contentSecurityPolicyCheck = async (config, platform6, publicRoot) => {
18367
- const path = join50(publicRoot, "index.html");
18932
+ const path = join51(publicRoot, "index.html");
18368
18933
  try {
18369
- const source = await readFile17(path, "utf8");
18934
+ const source = await readFile18(path, "utf8");
18370
18935
  const requirements = [
18371
18936
  "Content-Security-Policy",
18372
18937
  "default-src 'self'",
@@ -18387,18 +18952,18 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18387
18952
  if (!await pathExists6(root))
18388
18953
  return [];
18389
18954
  const files = await Array.fromAsync(new Bun.Glob("**/*").scan({ cwd: root, onlyFiles: true }));
18390
- return files.filter((file) => extensions.has(extname8(file))).map((file) => join50(root, file));
18955
+ return files.filter((file) => extensions.has(extname8(file))).map((file) => join51(root, file));
18391
18956
  }, containsPattern = async (paths, pattern) => {
18392
- const sources = await Promise.all(paths.map((path) => readFile17(path, "utf8")));
18957
+ const sources = await Promise.all(paths.map((path) => readFile18(path, "utf8")));
18393
18958
  const index = sources.findIndex((source) => pattern.test(source));
18394
18959
  return index === NOT_FOUND3 ? undefined : paths[index];
18395
18960
  }, androidNativeSecurityCheck = async (androidRoot) => {
18396
- const manifestPath = join50(androidRoot, "app/src/main/AndroidManifest.xml");
18961
+ const manifestPath = join51(androidRoot, "app/src/main/AndroidManifest.xml");
18397
18962
  try {
18398
- const manifest = await readFile17(manifestPath, "utf8");
18963
+ const manifest = await readFile18(manifestPath, "utf8");
18399
18964
  if (/android:debuggable=["']true["']/u.test(manifest))
18400
18965
  throw new TypeError("Android release manifest explicitly enables application debugging.");
18401
- const sources = await sourceFiles(join50(androidRoot, "app/src/main"), new Set([".java", ".kt"]));
18966
+ const sources = await sourceFiles(join51(androidRoot, "app/src/main"), new Set([".java", ".kt"]));
18402
18967
  const debugSource = await containsPattern(sources, /setWebContentsDebuggingEnabled\s*\(\s*true\s*\)/u);
18403
18968
  if (debugSource)
18404
18969
  return fail5("android.native-debugging", "Android application source unconditionally enables WebView debugging.", debugSource, "Remove the unconditional WebView debugging call; use the platform debug-build behavior during development.");
@@ -18407,14 +18972,14 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18407
18972
  return fail5("android.native-debugging", error instanceof Error ? error.message : "Android native debugging configuration could not be validated.", manifestPath, "Remove explicit release debugging settings and rerun mobile sync.");
18408
18973
  }
18409
18974
  }, androidExportedComponentsCheck = async (manifestPath) => {
18410
- const source = await readFile17(manifestPath, "utf8").catch(() => "");
18975
+ const source = await readFile18(manifestPath, "utf8").catch(() => "");
18411
18976
  const exported = [
18412
18977
  ...source.matchAll(/<(?:activity|activity-alias|provider|receiver|service)\b[^>]*>/giu)
18413
18978
  ].map(([tag]) => tag).filter((tag) => /android:exported=["']true["']/iu.test(tag)).map((tag) => tag.match(/android:name=["']([^"']+)["']/iu)?.[1]).filter((name) => Boolean(name) && name !== ".MainActivity");
18414
18979
  return exported.length === 0 ? pass("android.exported-components", "No non-launcher Android component is explicitly exported.", manifestPath) : warn("android.exported-components", `${exported.length} non-launcher Android component(s) are exported and require manual authorization review.`, manifestPath, "Confirm each exported component is intentional, permission-protected where appropriate, and documented in the mobile threat model review.");
18415
18980
  }, androidDeepLinkProjectionCheck = async (config, manifestPath) => {
18416
18981
  try {
18417
- const source = await readFile17(manifestPath, "utf8");
18982
+ const source = await readFile18(manifestPath, "utf8");
18418
18983
  const required = [
18419
18984
  'android:autoVerify="true"',
18420
18985
  "android.intent.category.BROWSABLE",
@@ -18428,24 +18993,24 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18428
18993
  return fail5("android.deep-links", error instanceof Error ? error.message : "Android deep-link projection could not be validated.", manifestPath, "Run `absolute mobile sync android` and review the AbsoluteJS-owned deep-link region.");
18429
18994
  }
18430
18995
  }, iosNativeSecurityCheck = async (iosRoot) => {
18431
- const entitlementsPath = join50(iosRoot, "App/AbsoluteJS.entitlements");
18432
- const entitlements = await readFile17(entitlementsPath, "utf8").catch(() => "");
18996
+ const entitlementsPath = join51(iosRoot, "App/AbsoluteJS.entitlements");
18997
+ const entitlements = await readFile18(entitlementsPath, "utf8").catch(() => "");
18433
18998
  if (/<key>get-task-allow<\/key>\s*<true\s*\/>/u.test(entitlements) || /<key>com\.apple\.security\.get-task-allow<\/key>\s*<true\s*\/>/u.test(entitlements))
18434
18999
  return fail5("ios.native-debugging", "iOS source entitlements explicitly permit debugger attachment.", entitlementsPath, "Remove get-task-allow from source entitlements; Xcode supplies development entitlements only to debug builds.");
18435
- const sources = await sourceFiles(join50(iosRoot, "App"), new Set([".m", ".mm", ".swift"]));
19000
+ const sources = await sourceFiles(join51(iosRoot, "App"), new Set([".m", ".mm", ".swift"]));
18436
19001
  const debugSource = await containsPattern(sources, /\.isInspectable\s*=\s*true|setInspectable\s*\(\s*true\s*\)/u);
18437
19002
  if (debugSource)
18438
19003
  return fail5("ios.native-debugging", "iOS application source unconditionally enables WebView inspection.", debugSource, "Remove unconditional WebView inspection from release source.");
18439
19004
  return pass("ios.native-debugging", "iOS source does not enable release debugger attachment or WebView inspection.", entitlementsPath);
18440
19005
  }, iosDeepLinkProjectionCheck = async (config, iosRoot) => {
18441
- const infoPath = join50(iosRoot, "App/App/Info.plist");
18442
- const entitlementsPath = join50(iosRoot, "App/AbsoluteJS.entitlements");
18443
- const projectPath = join50(iosRoot, "App/App.xcodeproj/project.pbxproj");
19006
+ const infoPath = join51(iosRoot, "App/App/Info.plist");
19007
+ const entitlementsPath = join51(iosRoot, "App/AbsoluteJS.entitlements");
19008
+ const projectPath = join51(iosRoot, "App/App.xcodeproj/project.pbxproj");
18444
19009
  try {
18445
19010
  const [info2, entitlements, project] = await Promise.all([
18446
- readFile17(infoPath, "utf8"),
18447
- readFile17(entitlementsPath, "utf8"),
18448
- readFile17(projectPath, "utf8")
19011
+ readFile18(infoPath, "utf8"),
19012
+ readFile18(entitlementsPath, "utf8"),
19013
+ readFile18(projectPath, "utf8")
18449
19014
  ]);
18450
19015
  if (config.deepLinkScheme && (!info2.includes("<key>CFBundleURLTypes</key>") || !info2.includes(`<string>${config.deepLinkScheme}</string>`)))
18451
19016
  throw new TypeError("iOS custom URL scheme does not match mobile config.");
@@ -18460,7 +19025,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18460
19025
  }, syncSchemaReleaseCheck = (projectRoot) => {
18461
19026
  if (!projectUsesAbsoluteSync(projectRoot))
18462
19027
  return;
18463
- const manifestPath = join50(projectRoot, "package.json");
19028
+ const manifestPath = join51(projectRoot, "package.json");
18464
19029
  try {
18465
19030
  const schema = discoverAbsoluteSyncSchema(projectRoot);
18466
19031
  const versions = schema.components.map((component2) => `${component2.id}@${component2.version}`).join(", ");
@@ -18482,8 +19047,8 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18482
19047
  }, IOS_USAGE_KEYS, androidDevicePermissionCheck = async (config, permissions) => {
18483
19048
  if (!config.platforms.includes("android") || permissions.length === 0)
18484
19049
  return;
18485
- const path = join50(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
18486
- const source = await readFile17(path, "utf8");
19050
+ const path = join51(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
19051
+ const source = await readFile18(path, "utf8");
18487
19052
  const missing = permissions.filter((permission) => !source.includes(`android:name="${permission}"`) && !source.includes(`android:name='${permission}'`));
18488
19053
  if (missing.length === 0)
18489
19054
  return;
@@ -18491,8 +19056,8 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18491
19056
  }, iosDevicePermissionCheck = async (config, purposes) => {
18492
19057
  if (!config.platforms.includes("ios") || purposes.length === 0)
18493
19058
  return;
18494
- const path = join50(config.nativeProjectDirectory, "ios/App/App/Info.plist");
18495
- const source = await readFile17(path, "utf8");
19059
+ const path = join51(config.nativeProjectDirectory, "ios/App/App/Info.plist");
19060
+ const source = await readFile18(path, "utf8");
18496
19061
  const missing = purposes.filter((purpose) => !source.includes(`<key>${IOS_USAGE_KEYS[purpose]}</key>`));
18497
19062
  if (missing.length === 0)
18498
19063
  return;
@@ -18500,35 +19065,35 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18500
19065
  }, iosCapabilityProjectionCheck = async (config, requirements) => {
18501
19066
  if (!config.platforms.includes("ios"))
18502
19067
  return;
18503
- const appRoot = join50(config.nativeProjectDirectory, "ios/App/App");
18504
- const infoPath = join50(appRoot, "Info.plist");
18505
- const info2 = await readFile17(infoPath, "utf8").catch(() => "");
19068
+ const appRoot = join51(config.nativeProjectDirectory, "ios/App/App");
19069
+ const infoPath = join51(appRoot, "Info.plist");
19070
+ const info2 = await readFile18(infoPath, "utf8").catch(() => "");
18506
19071
  if (requirements.iosSystemBars && !/<key>UIViewControllerBasedStatusBarAppearance<\/key>\s*<true\s*\/>/u.test(info2))
18507
19072
  return fail5("mobile.device-capabilities", "iOS system-bar capability is missing its required view-controller setting.", infoPath, "Run `absolute mobile sync ios` to regenerate native capability settings.");
18508
19073
  if (requirements.iosPrivacyAccessedApis.length > 0) {
18509
- const privacyPath = join50(appRoot, "PrivacyInfo.xcprivacy");
18510
- const projectPath = join50(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
19074
+ const privacyPath = join51(appRoot, "PrivacyInfo.xcprivacy");
19075
+ const projectPath = join51(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
18511
19076
  const [privacy, project] = await Promise.all([
18512
- readFile17(privacyPath, "utf8").catch(() => ""),
18513
- readFile17(projectPath, "utf8").catch(() => "")
19077
+ readFile18(privacyPath, "utf8").catch(() => ""),
19078
+ readFile18(projectPath, "utf8").catch(() => "")
18514
19079
  ]);
18515
19080
  const missing = requirements.iosPrivacyAccessedApis.some(({ api, reasons }) => !privacy.includes(`<string>${api}</string>`) || reasons.some((reason) => !privacy.includes(`<string>${reason}</string>`)));
18516
19081
  if (missing || !project.includes("PrivacyInfo.xcprivacy in Resources"))
18517
19082
  return fail5("mobile.device-capabilities", "iOS privacy manifest or target membership does not match detected native capabilities.", privacyPath, "Run `absolute mobile sync ios` to regenerate and target PrivacyInfo.xcprivacy.");
18518
19083
  }
18519
19084
  if (requirements.iosPushNotifications) {
18520
- const entitlementsPath = join50(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
18521
- const delegatePath = join50(appRoot, "AppDelegate.swift");
19085
+ const entitlementsPath = join51(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
19086
+ const delegatePath = join51(appRoot, "AppDelegate.swift");
18522
19087
  const [entitlements, delegate] = await Promise.all([
18523
- readFile17(entitlementsPath, "utf8").catch(() => ""),
18524
- readFile17(delegatePath, "utf8").catch(() => "")
19088
+ readFile18(entitlementsPath, "utf8").catch(() => ""),
19089
+ readFile18(delegatePath, "utf8").catch(() => "")
18525
19090
  ]);
18526
19091
  if (!entitlements.includes("<key>aps-environment</key>") || !delegate.includes("capacitorDidRegisterForRemoteNotifications") || !delegate.includes("capacitorDidFailToRegisterForRemoteNotifications"))
18527
19092
  return fail5("mobile.device-capabilities", "iOS push entitlement or AppDelegate forwarding does not match detected capabilities.", entitlementsPath, "Run `absolute mobile sync ios` to regenerate native push integration.");
18528
19093
  }
18529
19094
  return;
18530
19095
  }, deviceCapabilityReleaseCheck = async (config, projectRoot) => {
18531
- const manifestPath = join50(projectRoot, "package.json");
19096
+ const manifestPath = join51(projectRoot, "package.json");
18532
19097
  try {
18533
19098
  const plan = resolveAbsoluteDeviceCapabilityPlan(projectRoot);
18534
19099
  assertAbsoluteDeviceCapabilityPackages(projectRoot, plan);
@@ -18547,11 +19112,11 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18547
19112
  return fail5("mobile.device-capabilities", error instanceof Error ? error.message : "Native device capability provisioning is invalid.", manifestPath, "Run `absolute mobile sync` and approve the exact capability plugins before releasing.");
18548
19113
  }
18549
19114
  }, inspectAndroidRelease = async (config, projectRoot) => {
18550
- const androidRoot = join50(config.nativeProjectDirectory, "android");
18551
- const nativeConfigPath = join50(androidRoot, "app", "src", "main", "assets", "capacitor.config.json");
18552
- const manifestPath = join50(androidRoot, "app", "src", "main", "AndroidManifest.xml");
18553
- const publicRoot = join50(androidRoot, "app", "src", "main", "assets", "public");
18554
- const journalPath = join50(projectRoot, ".absolutejs", "mobile", "dev-session", "journal.json");
19115
+ const androidRoot = join51(config.nativeProjectDirectory, "android");
19116
+ const nativeConfigPath = join51(androidRoot, "app", "src", "main", "assets", "capacitor.config.json");
19117
+ const manifestPath = join51(androidRoot, "app", "src", "main", "AndroidManifest.xml");
19118
+ const publicRoot = join51(androidRoot, "app", "src", "main", "assets", "public");
19119
+ const journalPath = join51(projectRoot, ".absolutejs", "mobile", "dev-session", "journal.json");
18555
19120
  const checks = await Promise.all([
18556
19121
  journalReleaseCheck(journalPath, "android"),
18557
19122
  capacitorConfigReleaseCheck(nativeConfigPath),
@@ -18566,14 +19131,14 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18566
19131
  ]);
18567
19132
  return checks.map((check2) => ({
18568
19133
  ...check2,
18569
- path: check2.path ? relative25(projectRoot, check2.path).replaceAll("\\", "/") || "." : undefined
19134
+ path: check2.path ? relative26(projectRoot, check2.path).replaceAll("\\", "/") || "." : undefined
18570
19135
  }));
18571
19136
  }, inspectIosRelease = async (config, projectRoot) => {
18572
- const iosAppRoot = join50(config.nativeProjectDirectory, "ios", "App", "App");
18573
- const nativeConfigPath = join50(iosAppRoot, "capacitor.config.json");
18574
- const infoPath = join50(iosAppRoot, "Info.plist");
18575
- const publicRoot = join50(iosAppRoot, "public");
18576
- const journalPath = join50(projectRoot, ".absolutejs", "mobile", "ios-dev-session", "journal.json");
19137
+ const iosAppRoot = join51(config.nativeProjectDirectory, "ios", "App", "App");
19138
+ const nativeConfigPath = join51(iosAppRoot, "capacitor.config.json");
19139
+ const infoPath = join51(iosAppRoot, "Info.plist");
19140
+ const publicRoot = join51(iosAppRoot, "public");
19141
+ const journalPath = join51(projectRoot, ".absolutejs", "mobile", "ios-dev-session", "journal.json");
18577
19142
  const checks = [
18578
19143
  await journalReleaseCheck(journalPath, "ios")
18579
19144
  ];
@@ -18584,7 +19149,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18584
19149
  }
18585
19150
  if (!await pathExists6(nativeConfigPath)) {
18586
19151
  checks.push(fail5("ios.capacitor-config", "The generated iOS Capacitor config is missing.", nativeConfigPath, "Run `absolute mobile sync ios` before release validation."));
18587
- } else if (isUnsafeCapacitorConfig(await readFile17(nativeConfigPath, "utf8"))) {
19152
+ } else if (isUnsafeCapacitorConfig(await readFile18(nativeConfigPath, "utf8"))) {
18588
19153
  checks.push(fail5("ios.capacitor-config", "iOS Capacitor config contains a development server URL, cleartext transport, navigation allowlist, or invalid JSON.", nativeConfigPath, "Run `absolute mobile sync ios`; do not ship development transport overrides."));
18589
19154
  } else {
18590
19155
  checks.push(pass("ios.capacitor-config", "iOS Capacitor config contains no development transport overrides.", nativeConfigPath));
@@ -18593,15 +19158,15 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18593
19158
  if (!await pathExists6(infoPath)) {
18594
19159
  checks.push(fail5("ios.transport-security", "The iOS Info.plist is missing.", infoPath, "Run `absolute mobile sync ios` before release validation."));
18595
19160
  } else {
18596
- const info2 = await readFile17(infoPath, "utf8");
19161
+ const info2 = await readFile18(infoPath, "utf8");
18597
19162
  checks.push(/<key>NSAllowsArbitraryLoads<\/key>\s*<true\s*\/>/u.test(info2) ? fail5("ios.transport-security", "iOS App Transport Security permits arbitrary network loads.", infoPath, "Remove NSAllowsArbitraryLoads from the release Info.plist.") : pass("ios.transport-security", "iOS App Transport Security does not permit arbitrary loads.", infoPath));
18598
19163
  }
18599
19164
  const hmrAsset = await findHmrAsset(publicRoot);
18600
19165
  checks.push(hmrAsset ? fail5("ios.hmr-assets", "A packaged iOS asset contains the development HMR client.", hmrAsset, "Rebuild the production mobile bundle and run Capacitor sync again.") : pass("ios.hmr-assets", "Packaged iOS assets contain no development HMR markers.", publicRoot));
18601
- checks.push(await embeddedBundleReleaseCheck(config, projectRoot, "ios", publicRoot), await contentSecurityPolicyCheck(config, "ios", publicRoot), await iosNativeSecurityCheck(join50(config.nativeProjectDirectory, "ios")), await iosDeepLinkProjectionCheck(config, join50(config.nativeProjectDirectory, "ios")));
19166
+ checks.push(await embeddedBundleReleaseCheck(config, projectRoot, "ios", publicRoot), await contentSecurityPolicyCheck(config, "ios", publicRoot), await iosNativeSecurityCheck(join51(config.nativeProjectDirectory, "ios")), await iosDeepLinkProjectionCheck(config, join51(config.nativeProjectDirectory, "ios")));
18602
19167
  return checks.map((check2) => ({
18603
19168
  ...check2,
18604
- path: check2.path ? relative25(projectRoot, check2.path).replaceAll("\\", "/") || "." : undefined
19169
+ path: check2.path ? relative26(projectRoot, check2.path).replaceAll("\\", "/") || "." : undefined
18605
19170
  }));
18606
19171
  }, createAbsoluteMobileComplianceReport = (config, result) => {
18607
19172
  const summary = {
@@ -18631,7 +19196,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18631
19196
  ]);
18632
19197
  const checks = globalChecks.map((check2) => ({
18633
19198
  ...check2,
18634
- path: check2.path ? relative25(projectRoot, check2.path).replaceAll("\\", "/") || "." : undefined
19199
+ path: check2.path ? relative26(projectRoot, check2.path).replaceAll("\\", "/") || "." : undefined
18635
19200
  }));
18636
19201
  if (config.platforms.includes("android"))
18637
19202
  checks.push(...await inspectAndroidRelease(config, projectRoot));
@@ -18642,13 +19207,13 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
18642
19207
  if (syncSchema) {
18643
19208
  checks.push({
18644
19209
  ...syncSchema,
18645
- path: syncSchema.path ? relative25(projectRoot, syncSchema.path).replaceAll("\\", "/") || "." : undefined
19210
+ path: syncSchema.path ? relative26(projectRoot, syncSchema.path).replaceAll("\\", "/") || "." : undefined
18646
19211
  });
18647
19212
  }
18648
19213
  const deviceCapabilities = await deviceCapabilityReleaseCheck(config, projectRoot);
18649
19214
  checks.push({
18650
19215
  ...deviceCapabilities,
18651
- path: deviceCapabilities.path ? relative25(projectRoot, deviceCapabilities.path).replaceAll("\\", "/") || "." : undefined
19216
+ path: deviceCapabilities.path ? relative26(projectRoot, deviceCapabilities.path).replaceAll("\\", "/") || "." : undefined
18652
19217
  });
18653
19218
  return {
18654
19219
  checks,
@@ -18687,19 +19252,19 @@ var init_releaseDoctor = __esm(() => {
18687
19252
  });
18688
19253
 
18689
19254
  // src/mobile/androidRelease.ts
18690
- import { createHash as createHash13 } from "crypto";
19255
+ import { createHash as createHash14 } from "crypto";
18691
19256
  import {
18692
- access as access10,
19257
+ access as access11,
18693
19258
  copyFile as copyFile5,
18694
- mkdir as mkdir12,
18695
- mkdtemp as mkdtemp5,
18696
- readFile as readFile18,
18697
- rename as rename12,
18698
- rm as rm8,
19259
+ mkdir as mkdir13,
19260
+ mkdtemp as mkdtemp6,
19261
+ readFile as readFile19,
19262
+ rename as rename13,
19263
+ rm as rm9,
18699
19264
  stat as stat3,
18700
- writeFile as writeFile14
19265
+ writeFile as writeFile15
18701
19266
  } from "fs/promises";
18702
- import { dirname as dirname30, isAbsolute as isAbsolute7, join as join51, relative as relative26, resolve as resolve40, sep as sep6 } from "path";
19267
+ import { dirname as dirname31, isAbsolute as isAbsolute7, join as join52, relative as relative27, resolve as resolve41, sep as sep6 } from "path";
18703
19268
  var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord13 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), requireManifest2 = (value) => {
18704
19269
  if (!isRecord13(value) || typeof value.appBuild !== "string" || typeof value.appId !== "string" || typeof value.runtime !== "string") {
18705
19270
  throw new TypeError("Invalid embedded AbsoluteJS mobile manifest.");
@@ -18711,7 +19276,7 @@ var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord13 = (value) => typeof value ==
18711
19276
  };
18712
19277
  }, pathExists7 = async (path) => {
18713
19278
  try {
18714
- await access10(path);
19279
+ await access11(path);
18715
19280
  return true;
18716
19281
  } catch {
18717
19282
  return false;
@@ -18763,20 +19328,20 @@ var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord13 = (value) => typeof value ==
18763
19328
  ]);
18764
19329
  if (result.exitCode !== 0)
18765
19330
  throw new TypeError("jarsigner could not sign the Android App Bundle with the configured CI identity.");
18766
- }, sha256File2 = async (path) => createHash13("sha256").update(await readFile18(path)).digest("hex"), safeOutputDirectory2 = (projectRoot, requested) => {
18767
- const root = resolve40(projectRoot);
18768
- const output = resolve40(root, requested ?? ".absolutejs/mobile/releases/android");
18769
- const projectRelative = relative26(root, output);
19331
+ }, sha256File2 = async (path) => createHash14("sha256").update(await readFile19(path)).digest("hex"), safeOutputDirectory2 = (projectRoot, requested) => {
19332
+ const root = resolve41(projectRoot);
19333
+ const output = resolve41(root, requested ?? ".absolutejs/mobile/releases/android");
19334
+ const projectRelative = relative27(root, output);
18770
19335
  if (projectRelative === ".." || projectRelative.startsWith(`..${sep6}`) || isAbsolute7(projectRelative)) {
18771
19336
  throw new TypeError("mobile build --outdir must remain inside the project.");
18772
19337
  }
18773
19338
  return output;
18774
19339
  }, installRelease2 = async (artifactPath, metadata, outputRoot) => {
18775
- const releaseRoot = join51(outputRoot, metadata.releaseId);
19340
+ const releaseRoot = join52(outputRoot, metadata.releaseId);
18776
19341
  const artifactName = "app-release.aab";
18777
- const destination = join51(releaseRoot, artifactName);
19342
+ const destination = join52(releaseRoot, artifactName);
18778
19343
  if (await pathExists7(releaseRoot)) {
18779
- const existing = requireManifestIdentity(JSON.parse(await readFile18(join51(releaseRoot, "release.json"), "utf8")), metadata);
19344
+ const existing = requireManifestIdentity(JSON.parse(await readFile19(join52(releaseRoot, "release.json"), "utf8")), metadata);
18780
19345
  const [installedBytes, installedSha256] = await Promise.all([
18781
19346
  stat3(destination).then(({ size }) => size),
18782
19347
  sha256File2(destination)
@@ -18786,20 +19351,20 @@ var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord13 = (value) => typeof value ==
18786
19351
  }
18787
19352
  return { artifactPath: destination, metadata: existing, releaseRoot };
18788
19353
  }
18789
- await mkdir12(dirname30(releaseRoot), { recursive: true });
18790
- const staging = await mkdtemp5(join51(dirname30(releaseRoot), ".android-stage-"));
19354
+ await mkdir13(dirname31(releaseRoot), { recursive: true });
19355
+ const staging = await mkdtemp6(join52(dirname31(releaseRoot), ".android-stage-"));
18791
19356
  try {
18792
- await copyFile5(artifactPath, join51(staging, artifactName));
19357
+ await copyFile5(artifactPath, join52(staging, artifactName));
18793
19358
  const complete = {
18794
19359
  ...metadata,
18795
19360
  artifact: artifactName
18796
19361
  };
18797
- await writeFile14(join51(staging, "release.json"), `${JSON.stringify(complete, null, "\t")}
19362
+ await writeFile15(join52(staging, "release.json"), `${JSON.stringify(complete, null, "\t")}
18798
19363
  `, { flag: "wx" });
18799
- await rename12(staging, releaseRoot);
19364
+ await rename13(staging, releaseRoot);
18800
19365
  return { artifactPath: destination, metadata: complete, releaseRoot };
18801
19366
  } finally {
18802
- await rm8(staging, { force: true, recursive: true }).catch(() => {
19367
+ await rm9(staging, { force: true, recursive: true }).catch(() => {
18803
19368
  return;
18804
19369
  });
18805
19370
  }
@@ -18819,18 +19384,18 @@ var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord13 = (value) => typeof value ==
18819
19384
  if (options.versionCode !== undefined && (!Number.isSafeInteger(options.versionCode) || options.versionCode < 1 || options.versionCode > 2100000000)) {
18820
19385
  throw new TypeError("Android versionCode must be an integer from 1 through 2100000000.");
18821
19386
  }
18822
- const projectRoot = resolve40(options.projectRoot);
19387
+ const projectRoot = resolve41(options.projectRoot);
18823
19388
  const host2 = options.host ?? detectAbsoluteMobileHost();
18824
19389
  const androidRoot = options.androidRoot ?? process.env.ANDROID_HOME ?? process.env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(host2);
18825
- const nativeDirectory = join51(options.config.nativeProjectDirectory, "android");
18826
- const manifest = requireManifest2(JSON.parse(await readFile18(join51(options.config.bundleDirectory, "absolute-mobile-manifest.json"), "utf8")));
19390
+ const nativeDirectory = join52(options.config.nativeProjectDirectory, "android");
19391
+ const manifest = requireManifest2(JSON.parse(await readFile19(join52(options.config.bundleDirectory, "absolute-mobile-manifest.json"), "utf8")));
18827
19392
  if (manifest.appId !== options.config.appId) {
18828
19393
  throw new TypeError("Embedded mobile manifest appId does not match mobile.appId.");
18829
19394
  }
18830
19395
  let { versionCode } = options;
18831
19396
  if (options.prepareVersionCode) {
18832
19397
  const nativeFingerprint = await fingerprintAbsoluteAndroidNativeProject({ nativeDirectory });
18833
- const buildIdentity = createHash13("sha256").update(`${manifest.appBuild}\x00${nativeFingerprint}`).digest("hex");
19398
+ const buildIdentity = createHash14("sha256").update(`${manifest.appBuild}\x00${nativeFingerprint}`).digest("hex");
18834
19399
  versionCode = await options.prepareVersionCode(buildIdentity);
18835
19400
  }
18836
19401
  if (versionCode !== undefined && (!Number.isSafeInteger(versionCode) || versionCode < 1 || versionCode > 2100000000)) {
@@ -18934,7 +19499,7 @@ var absoluteIosDeviceAcceptanceCommands = (options) => {
18934
19499
  };
18935
19500
 
18936
19501
  // src/mobile/iosConformance.ts
18937
- import { readFile as readFile19, stat as stat4 } from "fs/promises";
19502
+ import { readFile as readFile20, stat as stat4 } from "fs/promises";
18938
19503
  var HMR_LINE, parseAbsoluteIosHmrLog = (line) => {
18939
19504
  const match = HMR_LINE.exec(line);
18940
19505
  if (!match)
@@ -18969,7 +19534,7 @@ var HMR_LINE, parseAbsoluteIosHmrLog = (line) => {
18969
19534
  if (Date.now() > deadline)
18970
19535
  throw new Error(`No iOS native HMR acknowledgement was observed within ${timeoutMs}ms.`);
18971
19536
  options.signal?.throwIfAborted();
18972
- const contents = await readFile19(options.logPath).catch(() => Buffer.alloc(0));
19537
+ const contents = await readFile20(options.logPath).catch(() => Buffer.alloc(0));
18973
19538
  if (contents.byteLength < offset) {
18974
19539
  offset = 0;
18975
19540
  buffered = "";
@@ -18993,8 +19558,8 @@ var init_iosConformance = __esm(() => {
18993
19558
  });
18994
19559
 
18995
19560
  // src/mobile/nativeTestReport.ts
18996
- import { mkdir as mkdir13, readFile as readFile20, writeFile as writeFile15 } from "fs/promises";
18997
- import { join as join52 } from "path";
19561
+ import { mkdir as mkdir14, readFile as readFile21, writeFile as writeFile16 } from "fs/promises";
19562
+ import { join as join53 } from "path";
18998
19563
  var secretPattern, bearerPattern, coordinatePattern, nativeCredentialPattern, sanitizeNativeReportText = (value) => value.replace(nativeCredentialPattern, "[REDACTED]").replace(bearerPattern, "Bearer [REDACTED]").replace(secretPattern, "$1$2[REDACTED]").replace(coordinatePattern, "$1$2[REDACTED]").replace(/(https?:\/\/[^\s?#]+)[?#][^\s]*/giu, "$1?[REDACTED]"), markdownCell = (value) => sanitizeNativeReportText(value).replaceAll("|", "\\|").replaceAll(`
18999
19564
  `, "<br>"), createAbsoluteNativeAutomatedChecks = (run) => {
19000
19565
  const target = `${run.targetKind} ${run.targetId}`;
@@ -19096,7 +19661,7 @@ var secretPattern, bearerPattern, coordinatePattern, nativeCredentialPattern, sa
19096
19661
  reportVersion: 1,
19097
19662
  run: options.run
19098
19663
  }), readPackageVersionForNativeReport = async (packageJsonPath) => {
19099
- const manifest = JSON.parse(await readFile20(packageJsonPath, "utf8"));
19664
+ const manifest = JSON.parse(await readFile21(packageJsonPath, "utf8"));
19100
19665
  if (typeof manifest !== "object" || manifest === null)
19101
19666
  return "unknown";
19102
19667
  const version2 = Reflect.get(manifest, "version");
@@ -19132,13 +19697,13 @@ Replace each \`NOT_RUN\` with \`PASS\`, \`FAIL\`, or \`SKIPPED\` after completin
19132
19697
  ${table(report.manualChecks)}
19133
19698
  `;
19134
19699
  }, writeAbsoluteNativeTestReport = async (directory, report) => {
19135
- await mkdir13(directory, { recursive: true });
19136
- const jsonPath = join52(directory, "report.json");
19137
- const markdownPath = join52(directory, "report.md");
19700
+ await mkdir14(directory, { recursive: true });
19701
+ const jsonPath = join53(directory, "report.json");
19702
+ const markdownPath = join53(directory, "report.md");
19138
19703
  await Promise.all([
19139
- writeFile15(jsonPath, `${JSON.stringify(report, null, 2)}
19704
+ writeFile16(jsonPath, `${JSON.stringify(report, null, 2)}
19140
19705
  `),
19141
- writeFile15(markdownPath, renderAbsoluteNativeTestReport(report))
19706
+ writeFile16(markdownPath, renderAbsoluteNativeTestReport(report))
19142
19707
  ]);
19143
19708
  return { directory, jsonPath, markdownPath };
19144
19709
  };
@@ -19352,8 +19917,8 @@ var init_androidTestReport = __esm(() => {
19352
19917
  });
19353
19918
 
19354
19919
  // src/mobile/releasePublisher.ts
19355
- import { access as access11 } from "fs/promises";
19356
- import { isAbsolute as isAbsolute8, relative as relative27, resolve as resolve41, sep as sep7 } from "path";
19920
+ import { access as access12 } from "fs/promises";
19921
+ import { isAbsolute as isAbsolute8, relative as relative28, resolve as resolve42, sep as sep7 } from "path";
19357
19922
  import { pathToFileURL as pathToFileURL2 } from "url";
19358
19923
  var prepareAbsoluteIosRelease = async (publisher, options) => {
19359
19924
  if (typeof publisher.prepareIosRelease !== "function") {
@@ -19375,16 +19940,16 @@ var prepareAbsoluteIosRelease = async (publisher, options) => {
19375
19940
  }
19376
19941
  return versionCode;
19377
19942
  }, isRecord14 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), isPublisher = (value) => isRecord14(value) && typeof value.publish === "function", publisherModulePath = (projectRoot, requested) => {
19378
- const root = resolve41(projectRoot);
19379
- const path = resolve41(root, requested);
19380
- const projectRelative = relative27(root, path);
19943
+ const root = resolve42(projectRoot);
19944
+ const path = resolve42(root, requested);
19945
+ const projectRelative = relative28(root, path);
19381
19946
  if (projectRelative === ".." || projectRelative.startsWith(`..${sep7}`) || isAbsolute8(projectRelative)) {
19382
19947
  throw new TypeError("mobile publish --registry must remain inside the project.");
19383
19948
  }
19384
19949
  return path;
19385
19950
  }, loadAbsoluteNativeReleasePublisher = async (projectRoot, requestedModulePath) => {
19386
19951
  const modulePath = publisherModulePath(projectRoot, requestedModulePath);
19387
- await access11(modulePath).catch(() => {
19952
+ await access12(modulePath).catch(() => {
19388
19953
  throw new TypeError(`Native release registry module does not exist: ${modulePath}`);
19389
19954
  });
19390
19955
  const loaded = await import(pathToFileURL2(modulePath).href);
@@ -19445,20 +20010,20 @@ var prepareAbsoluteIosRelease = async (publisher, options) => {
19445
20010
  var init_releasePublisher = () => {};
19446
20011
 
19447
20012
  // src/mobile/mobileInspect.ts
19448
- import { access as access12, readFile as readFile21 } from "fs/promises";
19449
- import { join as join53, relative as relative28, resolve as resolve42 } from "path";
20013
+ import { access as access13, readFile as readFile22 } from "fs/promises";
20014
+ import { join as join54, relative as relative29, resolve as resolve43 } from "path";
19450
20015
  var ABSOLUTE_MOBILE_INSPECTION_FORMAT = 1, MOBILE_PACKAGE_NAMES, isObject3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), portablePath2 = (projectRoot, path) => {
19451
- const value = relative28(resolve42(projectRoot), resolve42(path)).replaceAll("\\", "/");
20016
+ const value = relative29(resolve43(projectRoot), resolve43(path)).replaceAll("\\", "/");
19452
20017
  return value || ".";
19453
20018
  }, pathExists8 = async (path) => {
19454
20019
  try {
19455
- await access12(path);
20020
+ await access13(path);
19456
20021
  return true;
19457
20022
  } catch {
19458
20023
  return false;
19459
20024
  }
19460
20025
  }, readObject2 = async (path) => {
19461
- const value = JSON.parse(await readFile21(path, "utf8"));
20026
+ const value = JSON.parse(await readFile22(path, "utf8"));
19462
20027
  if (!isObject3(value))
19463
20028
  throw new TypeError("JSON root must be an object.");
19464
20029
  return value;
@@ -19468,13 +20033,13 @@ var ABSOLUTE_MOBILE_INSPECTION_FORMAT = 1, MOBILE_PACKAGE_NAMES, isObject3 = (va
19468
20033
  for (const [name, declared] of Object.entries(value).filter((entry) => typeof entry[1] === "string"))
19469
20034
  declarations.set(name, declared);
19470
20035
  }, packageInspections = async (projectRoot, additionalNames) => {
19471
- const project = await readObject2(join53(projectRoot, "package.json"));
20036
+ const project = await readObject2(join54(projectRoot, "package.json"));
19472
20037
  const declarations = new Map;
19473
20038
  for (const field of ["dependencies", "devDependencies"])
19474
20039
  addPackageDeclarations(declarations, project[field]);
19475
20040
  const names = [...new Set([...declarations.keys(), ...additionalNames])].filter((name) => MOBILE_PACKAGE_NAMES.has(name) || name.startsWith("@capacitor/") || additionalNames.includes(name)).sort();
19476
20041
  return Promise.all(names.map(async (name) => {
19477
- const installedManifest = await readObject2(join53(projectRoot, "node_modules", name, "package.json")).catch(() => {
20042
+ const installedManifest = await readObject2(join54(projectRoot, "node_modules", name, "package.json")).catch(() => {
19478
20043
  return;
19479
20044
  });
19480
20045
  const installed = installedManifest?.version;
@@ -19523,7 +20088,7 @@ var ABSOLUTE_MOBILE_INSPECTION_FORMAT = 1, MOBILE_PACKAGE_NAMES, isObject3 = (va
19523
20088
  },
19524
20089
  format: ABSOLUTE_MOBILE_INSPECTION_FORMAT,
19525
20090
  nativeProjects: await Promise.all(config.platforms.map(async (platform6) => {
19526
- const path = join53(config.nativeProjectDirectory, platform6);
20091
+ const path = join54(config.nativeProjectDirectory, platform6);
19527
20092
  return {
19528
20093
  initialized: await pathExists8(path),
19529
20094
  path: portablePath2(projectRoot, path),
@@ -19594,19 +20159,19 @@ var init_mobileInspect = __esm(() => {
19594
20159
 
19595
20160
  // src/mobile/ciWorkflow.ts
19596
20161
  import { existsSync as existsSync42 } from "fs";
19597
- import { access as access13, mkdir as mkdir14, readFile as readFile22, writeFile as writeFile16 } from "fs/promises";
19598
- import { dirname as dirname31, extname as extname9, relative as relative29, resolve as resolve43, sep as sep8 } from "path";
19599
- var ABSOLUTE_MOBILE_CI_WORKFLOW_FORMAT = 1, SECRET_NAME_PATTERN, CI_ENV_INDENTATION = 6, RESERVED_SECRET_NAMES, exists3 = async (path) => {
20162
+ import { access as access14, mkdir as mkdir15, readFile as readFile23, writeFile as writeFile17 } from "fs/promises";
20163
+ import { dirname as dirname32, extname as extname9, relative as relative30, resolve as resolve44, sep as sep8 } from "path";
20164
+ var ABSOLUTE_MOBILE_CI_WORKFLOW_FORMAT = 1, SECRET_NAME_PATTERN, CI_ENV_INDENTATION = 6, RESERVED_SECRET_NAMES, exists4 = async (path) => {
19600
20165
  try {
19601
- await access13(path);
20166
+ await access14(path);
19602
20167
  return true;
19603
20168
  } catch {
19604
20169
  return false;
19605
20170
  }
19606
20171
  }, yamlString = (value) => `'${value.replaceAll("'", "''")}'`, projectPath = (projectRoot, value, field, options = {}) => {
19607
- const root = resolve43(projectRoot);
19608
- const path = resolve43(root, value);
19609
- const portable = relative29(root, path).replaceAll("\\", "/");
20172
+ const root = resolve44(projectRoot);
20173
+ const path = resolve44(root, value);
20174
+ const portable = relative30(root, path).replaceAll("\\", "/");
19610
20175
  if (portable === ".." || portable.startsWith(`..${sep8}`) || portable.startsWith("../") || portable === "") {
19611
20176
  throw new TypeError(`${field} must remain inside the project root.`);
19612
20177
  }
@@ -19616,10 +20181,10 @@ var ABSOLUTE_MOBILE_CI_WORKFLOW_FORMAT = 1, SECRET_NAME_PATTERN, CI_ENV_INDENTAT
19616
20181
  throw new TypeError(`${field} does not exist inside the project.`);
19617
20182
  return portable;
19618
20183
  }, workflowOutputPath = (projectRoot, value) => {
19619
- const root = resolve43(projectRoot);
19620
- const workflows = resolve43(root, ".github/workflows");
19621
- const path = resolve43(root, value ?? ".github/workflows/absolute-mobile.yml");
19622
- const portable = relative29(workflows, path);
20184
+ const root = resolve44(projectRoot);
20185
+ const workflows = resolve44(root, ".github/workflows");
20186
+ const path = resolve44(root, value ?? ".github/workflows/absolute-mobile.yml");
20187
+ const portable = relative30(workflows, path);
19623
20188
  if (portable === ".." || portable.startsWith(`..${sep8}`) || extname9(path) !== ".yml" && extname9(path) !== ".yaml") {
19624
20189
  throw new TypeError("mobile ci github --output must be a .yml or .yaml file inside .github/workflows.");
19625
20190
  }
@@ -20008,12 +20573,12 @@ ${bundleAuditSteps}${platforms.includes("android") ? androidJob({ customSecrets,
20008
20573
  }, writeAbsoluteMobileGithubWorkflow = async (options) => {
20009
20574
  const path = workflowOutputPath(options.projectRoot, options.outputPath);
20010
20575
  const generated = createAbsoluteMobileGithubWorkflow(options);
20011
- const previous = await exists3(path) ? await readFile22(path, "utf8") : undefined;
20576
+ const previous = await exists4(path) ? await readFile23(path, "utf8") : undefined;
20012
20577
  if (previous !== undefined && previous !== generated.workflow && !options.force)
20013
- throw new TypeError(`${relative29(options.projectRoot, path)} already exists and differs. Rerun with --force to replace the generated workflow.`);
20578
+ throw new TypeError(`${relative30(options.projectRoot, path)} already exists and differs. Rerun with --force to replace the generated workflow.`);
20014
20579
  if (previous !== generated.workflow) {
20015
- await mkdir14(dirname31(path), { recursive: true });
20016
- await writeFile16(path, generated.workflow);
20580
+ await mkdir15(dirname32(path), { recursive: true });
20581
+ await writeFile17(path, generated.workflow);
20017
20582
  }
20018
20583
  return {
20019
20584
  changed: previous !== generated.workflow,
@@ -20075,11 +20640,11 @@ var exports_mobile = {};
20075
20640
  __export(exports_mobile, {
20076
20641
  runMobile: () => runMobile
20077
20642
  });
20078
- import { access as access14, mkdir as mkdir15, readFile as readFile23, writeFile as writeFile17 } from "fs/promises";
20079
- import { join as join54, relative as relative30, resolve as resolve44 } from "path";
20643
+ import { access as access15, mkdir as mkdir16, readFile as readFile24, writeFile as writeFile18 } from "fs/promises";
20644
+ import { join as join55, relative as relative31, resolve as resolve45 } from "path";
20080
20645
  import { createInterface } from "readline/promises";
20081
20646
  var NOT_FOUND4 = -1, isRecord15 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), CAPACITOR_PACKAGES, CAPACITOR_PACKAGE_SPECS, CAPACITOR_SYNC_PACKAGE_SPECS, packageNameFromSpec = (spec) => spec.slice(0, spec.lastIndexOf("@")), directProjectPackages = async (projectRoot) => {
20082
- const manifest = JSON.parse(await readFile23(join54(projectRoot, "package.json"), "utf8"));
20647
+ const manifest = JSON.parse(await readFile24(join55(projectRoot, "package.json"), "utf8"));
20083
20648
  if (!isRecord15(manifest))
20084
20649
  throw new TypeError("Application package.json must contain an object.");
20085
20650
  const names = new Set;
@@ -20092,7 +20657,7 @@ var NOT_FOUND4 = -1, isRecord15 = (value) => typeof value === "object" && value
20092
20657
  return names;
20093
20658
  }, resolvedPackageVersion = async (projectRoot, packageName) => {
20094
20659
  try {
20095
- const manifest = JSON.parse(await readFile23(join54(projectRoot, "node_modules", packageName, "package.json"), "utf8"));
20660
+ const manifest = JSON.parse(await readFile24(join55(projectRoot, "node_modules", packageName, "package.json"), "utf8"));
20096
20661
  return isRecord15(manifest) && typeof manifest.version === "string" ? manifest.version : undefined;
20097
20662
  } catch {
20098
20663
  return;
@@ -20133,9 +20698,9 @@ var NOT_FOUND4 = -1, isRecord15 = (value) => typeof value === "object" && value
20133
20698
  }
20134
20699
  return value;
20135
20700
  }, capacitorExecutable = async (projectRoot) => {
20136
- const executable = join54(projectRoot, "node_modules", ".bin", "cap");
20701
+ const executable = join55(projectRoot, "node_modules", ".bin", "cap");
20137
20702
  try {
20138
- await access14(executable);
20703
+ await access15(executable);
20139
20704
  return executable;
20140
20705
  } catch {
20141
20706
  throw new TypeError(`Capacitor is not installed in this app. Run: bun add ${CAPACITOR_PACKAGES.join(" ")}`);
@@ -20152,13 +20717,54 @@ var NOT_FOUND4 = -1, isRecord15 = (value) => typeof value === "object" && value
20152
20717
  if (exitCode !== 0) {
20153
20718
  throw new TypeError(`Capacitor exited with status ${exitCode}.`);
20154
20719
  }
20155
- }, runCapacitorForPlatforms = (projectRoot, command, platforms) => platforms.reduce((pending, platform6) => pending.then(() => runCapacitor(projectRoot, [command, platform6])), Promise.resolve()), loadMobile = async (configPath2) => {
20720
+ }, runCapacitorForPlatforms = (projectRoot, command, platforms) => platforms.reduce((pending, platform6) => pending.then(() => runCapacitor(projectRoot, [command, platform6])), Promise.resolve()), expoExecutable = async (project) => {
20721
+ const executable = join55(project, "node_modules", ".bin", "expo");
20722
+ try {
20723
+ await access15(executable);
20724
+ return executable;
20725
+ } catch {
20726
+ throw new TypeError("Expo dependencies are not installed in the generated shell. Run `absolute mobile init --yes`.");
20727
+ }
20728
+ }, runExpo = async (project, args) => {
20729
+ const executable = await expoExecutable(project);
20730
+ const process2 = Bun.spawn([executable, ...args], {
20731
+ cwd: project,
20732
+ stderr: "inherit",
20733
+ stdin: "inherit",
20734
+ stdout: "inherit"
20735
+ });
20736
+ const exitCode = await process2.exited;
20737
+ if (exitCode !== 0)
20738
+ throw new TypeError(`Expo exited with status ${exitCode}.`);
20739
+ }, ensureExpoPackages = async (project, args) => {
20740
+ try {
20741
+ await access15(join55(project, "node_modules", "expo", "package.json"));
20742
+ return;
20743
+ } catch {}
20744
+ const approved = args.includes("--yes") || await confirmInstall("The experimental Expo shell dependencies are missing. Install the pinned Expo SDK 57 toolchain now?");
20745
+ if (!approved)
20746
+ throw new TypeError(`Expo initialization requires running \`bun install\` in ${project}.`);
20747
+ const process2 = Bun.spawn(["bun", "install"], {
20748
+ cwd: project,
20749
+ stderr: "inherit",
20750
+ stdin: "inherit",
20751
+ stdout: "inherit"
20752
+ });
20753
+ const exitCode = await process2.exited;
20754
+ if (exitCode !== 0)
20755
+ throw new TypeError(`Expo dependency installation exited with status ${exitCode}.`);
20756
+ }, loadMobile = async (configPath2) => {
20156
20757
  const projectRoot = process.cwd();
20157
20758
  const config = await loadConfig(configPath2);
20158
20759
  const mobile = normalizeAbsoluteMobileConfig(requireMobileConfig(config.mobile), projectRoot);
20159
20760
  return { mobile, projectRoot };
20761
+ }, requireCapacitorEngine = (mobile, command) => {
20762
+ if (mobile.engine === "capacitor")
20763
+ return;
20764
+ throw new TypeError(`${command} is not available for the experimental Expo engine yet. Use mobile init/sync and Expo CLI from the generated shell; Capacitor remains the release-capable engine.`);
20160
20765
  }, inspectMobile = async (args) => {
20161
20766
  const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
20767
+ requireCapacitorEngine(mobile, "mobile inspect");
20162
20768
  const report = await inspectAbsoluteMobileProject(mobile, projectRoot, {
20163
20769
  absolutejsVersion: await absolutejsVersionForReport()
20164
20770
  });
@@ -20213,6 +20819,24 @@ var NOT_FOUND4 = -1, isRecord15 = (value) => typeof value === "object" && value
20213
20819
  console.log(removed ? `Removed remote Mac profile ${args[1]}.` : `Remote Mac profile ${args[1]} was not found.`);
20214
20820
  }, initialize = async (args) => {
20215
20821
  const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
20822
+ if (mobile.engine === "expo") {
20823
+ console.warn("Experimental: Expo Auth, Sync, release publishing, and physical-device acceptance are not complete.");
20824
+ const generated2 = await writeAbsoluteExpoProject(mobile, {
20825
+ force: args.includes("--force"),
20826
+ projectRoot
20827
+ });
20828
+ console.log(`${generated2.changed > 0 ? "Generated" : "Verified"} Expo shell ${generated2.path}`);
20829
+ await ensureExpoPackages(generated2.path, args);
20830
+ if (args.includes("--no-native"))
20831
+ return;
20832
+ await runExpo(generated2.path, [
20833
+ "prebuild",
20834
+ "--no-install",
20835
+ "--platform",
20836
+ mobile.platforms.length === 2 ? "all" : mobile.platforms[0] ?? "all"
20837
+ ]);
20838
+ return;
20839
+ }
20216
20840
  await ensureCapacitorPackages(projectRoot, args);
20217
20841
  const generated = await writeAbsoluteCapacitorConfig(mobile, {
20218
20842
  force: args.includes("--force"),
@@ -20227,6 +20851,25 @@ var NOT_FOUND4 = -1, isRecord15 = (value) => typeof value === "object" && value
20227
20851
  await applyAbsoluteNativeBackgroundSync(projectRoot, mobile);
20228
20852
  }, sync = async (args) => {
20229
20853
  const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
20854
+ if (mobile.engine === "expo") {
20855
+ console.warn("Experimental: syncing the Expo CNG shell and embedded AbsoluteJS bundle.");
20856
+ await writeAbsoluteExpoProject(mobile, {
20857
+ force: args.includes("--force"),
20858
+ projectRoot
20859
+ });
20860
+ await ensureExpoPackages(mobile.nativeProjectDirectory, args);
20861
+ const assets = await syncAbsoluteExpoWebAssets(mobile);
20862
+ console.log(`Synced ${assets.assets} embedded AbsoluteJS assets for ${assets.appBuild}.`);
20863
+ const platform7 = args.find((value) => value === "android" || value === "ios");
20864
+ const platforms2 = platform7 ? [platform7] : mobile.platforms;
20865
+ await runExpo(mobile.nativeProjectDirectory, [
20866
+ "prebuild",
20867
+ "--no-install",
20868
+ "--platform",
20869
+ platforms2.length === 2 ? "all" : platforms2[0] ?? "all"
20870
+ ]);
20871
+ return;
20872
+ }
20230
20873
  await ensureCapacitorPackages(projectRoot, args);
20231
20874
  const platform6 = args.find((value) => value === "android" || value === "ios");
20232
20875
  const platforms = platform6 ? [platform6] : mobile.platforms;
@@ -20240,7 +20883,7 @@ var NOT_FOUND4 = -1, isRecord15 = (value) => typeof value === "object" && value
20240
20883
  await applyAbsoluteNativeBackgroundSync(projectRoot, mobile, platforms);
20241
20884
  }, associations = async (args) => {
20242
20885
  const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
20243
- const outputDirectory = resolve44(projectRoot, valueAfter(args, "--outdir") ?? ".absolutejs/mobile/associations");
20886
+ const outputDirectory = resolve45(projectRoot, valueAfter(args, "--outdir") ?? ".absolutejs/mobile/associations");
20244
20887
  if (args.includes("--verify")) {
20245
20888
  const result2 = await verifyAbsoluteMobileAssociationFiles(mobile);
20246
20889
  console.log(`Verified ${result2.results.length} hosted association files`);
@@ -20271,6 +20914,7 @@ var NOT_FOUND4 = -1, isRecord15 = (value) => typeof value === "object" && value
20271
20914
  throw new TypeError("Usage: absolute mobile ci github [server-entry] [--publish] [--registry module] [--secret-env NAME] [--output path] [--force] [--json] [--config path]");
20272
20915
  const configPath2 = valueAfter(args, "--config");
20273
20916
  const { mobile, projectRoot } = await loadMobile(configPath2);
20917
+ requireCapacitorEngine(mobile, "mobile ci github");
20274
20918
  const result = await writeAbsoluteMobileGithubWorkflow({
20275
20919
  config: mobile,
20276
20920
  configPath: configPath2,
@@ -20290,7 +20934,7 @@ var NOT_FOUND4 = -1, isRecord15 = (value) => typeof value === "object" && value
20290
20934
  const publicResult = {
20291
20935
  changed: result.changed,
20292
20936
  format: result.format,
20293
- path: relative30(projectRoot, result.path).replaceAll("\\", "/"),
20937
+ path: relative31(projectRoot, result.path).replaceAll("\\", "/"),
20294
20938
  platforms: result.platforms,
20295
20939
  publishing: result.publishing,
20296
20940
  requiredSecrets: result.requiredSecrets
@@ -20336,6 +20980,7 @@ var NOT_FOUND4 = -1, isRecord15 = (value) => typeof value === "object" && value
20336
20980
  }
20337
20981
  }, runReleaseDoctor = async (args) => {
20338
20982
  const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
20983
+ requireCapacitorEngine(mobile, "mobile doctor release");
20339
20984
  const platform6 = args.find((value) => value === "android" || value === "ios");
20340
20985
  const effectiveMobile = platform6 ? { ...mobile, platforms: [platform6] } : mobile;
20341
20986
  const result = await inspectAbsoluteMobileRelease(effectiveMobile, projectRoot);
@@ -20520,6 +21165,7 @@ Mobile release security and compliance checks failed.`);
20520
21165
  }, buildAndroid = async (args, prepareVersionCode) => {
20521
21166
  const configPath2 = valueAfter(args, "--config");
20522
21167
  const { mobile, projectRoot } = await loadMobile(configPath2);
21168
+ requireCapacitorEngine(mobile, "mobile build android");
20523
21169
  if (!mobile.platforms.includes("android")) {
20524
21170
  throw new TypeError("mobile build android requires android in mobile.platforms.");
20525
21171
  }
@@ -20550,7 +21196,7 @@ Mobile release security and compliance checks failed.`);
20550
21196
  const durationMs = Math.round(performance.now() - startedAt);
20551
21197
  console.log(`Built ${release.metadata.signed ? "signed" : "unsigned"} Android App Bundle in ${getDurationString(durationMs)}.`);
20552
21198
  console.log(`Artifact: ${release.artifactPath}`);
20553
- console.log(`Metadata: ${join54(release.releaseRoot, "release.json")}`);
21199
+ console.log(`Metadata: ${join55(release.releaseRoot, "release.json")}`);
20554
21200
  return release;
20555
21201
  } finally {
20556
21202
  sendTelemetryEvent("mobile:android-release-build", {
@@ -20573,6 +21219,7 @@ Mobile release security and compliance checks failed.`);
20573
21219
  const configPath2 = valueAfter(args, "--config");
20574
21220
  const googlePlay = googlePlayTarget(args);
20575
21221
  const { mobile, projectRoot } = await loadMobile(configPath2);
21222
+ requireCapacitorEngine(mobile, "mobile publish android");
20576
21223
  const startedAt = performance.now();
20577
21224
  let reused = false;
20578
21225
  let success = false;
@@ -20626,6 +21273,7 @@ Mobile release security and compliance checks failed.`);
20626
21273
  }, buildIos = async (args, prepareBuildNumber) => {
20627
21274
  const configPath2 = valueAfter(args, "--config");
20628
21275
  const { mobile, projectRoot } = await loadMobile(configPath2);
21276
+ requireCapacitorEngine(mobile, "mobile build ios");
20629
21277
  if (!mobile.platforms.includes("ios")) {
20630
21278
  throw new TypeError("mobile build ios requires ios in mobile.platforms.");
20631
21279
  }
@@ -20654,7 +21302,7 @@ Mobile release security and compliance checks failed.`);
20654
21302
  const durationMs = Math.round(performance.now() - startedAt);
20655
21303
  console.log(`Built ${release.metadata.signed ? "signed" : "unsigned"} iOS IPA ${release.metadata.marketingVersion}${release.metadata.buildNumber ? ` (${release.metadata.buildNumber})` : ""} in ${getDurationString(durationMs)}.`);
20656
21304
  console.log(`Artifact: ${release.artifactPath}`);
20657
- console.log(`Metadata: ${join54(release.releaseRoot, "release.json")}`);
21305
+ console.log(`Metadata: ${join55(release.releaseRoot, "release.json")}`);
20658
21306
  return release;
20659
21307
  } finally {
20660
21308
  sendTelemetryEvent("mobile:ios-release-build", {
@@ -20672,6 +21320,7 @@ Mobile release security and compliance checks failed.`);
20672
21320
  const configPath2 = valueAfter(args, "--config");
20673
21321
  const appStoreConnect = appStoreConnectTarget(args);
20674
21322
  const { mobile, projectRoot } = await loadMobile(configPath2);
21323
+ requireCapacitorEngine(mobile, "mobile publish ios");
20675
21324
  const startedAt = performance.now();
20676
21325
  let reused = false;
20677
21326
  let success = false;
@@ -20761,7 +21410,7 @@ Mobile release security and compliance checks failed.`);
20761
21410
  checks.push({
20762
21411
  id: "sync.storage-schema",
20763
21412
  label: `Offline schema ${schema.components.map((component2) => `${component2.id}@${component2.version}`).join(", ")}`,
20764
- path: join54(projectRoot, "package.json"),
21413
+ path: join55(projectRoot, "package.json"),
20765
21414
  platform: "host",
20766
21415
  status: "pass"
20767
21416
  });
@@ -20769,7 +21418,7 @@ Mobile release security and compliance checks failed.`);
20769
21418
  checks.push({
20770
21419
  id: "sync.storage-schema",
20771
21420
  label: "Offline schema metadata is invalid",
20772
- path: join54(projectRoot, "package.json"),
21421
+ path: join55(projectRoot, "package.json"),
20773
21422
  platform: "host",
20774
21423
  remediation: error instanceof Error ? error.message : String(error),
20775
21424
  status: "fail"
@@ -20854,7 +21503,7 @@ Emulator setup verification:`);
20854
21503
  }
20855
21504
  return { https: args.includes("--https"), port };
20856
21505
  }
20857
- const instances = listLiveInstances().filter((instance2) => resolve44(instance2.cwd) === resolve44(projectRoot) && instance2.source === "dev" && instance2.port !== null);
21506
+ const instances = listLiveInstances().filter((instance2) => resolve45(instance2.cwd) === resolve45(projectRoot) && instance2.source === "dev" && instance2.port !== null);
20858
21507
  if (instances.length !== 1) {
20859
21508
  throw new TypeError(instances.length === 0 ? "No running AbsoluteJS dev server was found for this project. Start `bun dev`, wait for Android to report ready, then run `absolute mobile test android`." : "Multiple dev servers are running for this project. Select one with mobile test android --port <port>.");
20860
21509
  }
@@ -20897,8 +21546,8 @@ Emulator setup verification:`);
20897
21546
  }
20898
21547
  return selected;
20899
21548
  }, safeArtifactRoot = (projectRoot, value) => {
20900
- const root = resolve44(projectRoot, value ?? ".absolutejs/mobile/test-artifacts");
20901
- if (root !== projectRoot && !root.startsWith(`${resolve44(projectRoot)}/`)) {
21549
+ const root = resolve45(projectRoot, value ?? ".absolutejs/mobile/test-artifacts");
21550
+ if (root !== projectRoot && !root.startsWith(`${resolve45(projectRoot)}/`)) {
20902
21551
  throw new TypeError("mobile test --artifacts must remain inside the project.");
20903
21552
  }
20904
21553
  return root;
@@ -20922,12 +21571,12 @@ Emulator setup verification:`);
20922
21571
  timeoutMs
20923
21572
  });
20924
21573
  }, writeAndroidFailureArtifacts = async (options) => {
20925
- await mkdir15(options.artifactRoot, { recursive: true });
20926
- const screenshot = options.session ? await options.session.screenshot(join54(options.artifactRoot, "android-failure.png")).catch(() => {
21574
+ await mkdir16(options.artifactRoot, { recursive: true });
21575
+ const screenshot = options.session ? await options.session.screenshot(join55(options.artifactRoot, "android-failure.png")).catch(() => {
20927
21576
  return;
20928
21577
  }) : undefined;
20929
- const diagnosticPath = join54(options.artifactRoot, "android-failure.json");
20930
- await writeFile17(diagnosticPath, `${JSON.stringify({
21578
+ const diagnosticPath = join55(options.artifactRoot, "android-failure.json");
21579
+ await writeFile18(diagnosticPath, `${JSON.stringify({
20931
21580
  diagnostics: options.session?.diagnostics ?? [],
20932
21581
  error: options.error instanceof Error ? options.error.message : String(options.error),
20933
21582
  platform: "android",
@@ -20940,6 +21589,7 @@ Emulator setup verification:`);
20940
21589
  return { diagnosticPath, screenshot };
20941
21590
  }, testAndroid = async (args) => {
20942
21591
  const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
21592
+ requireCapacitorEngine(mobile, "mobile test android");
20943
21593
  if (!mobile.platforms.includes("android")) {
20944
21594
  throw new TypeError("mobile test android requires android in mobile.platforms.");
20945
21595
  }
@@ -20990,7 +21640,7 @@ Emulator setup verification:`);
20990
21640
  console.log(JSON.stringify(report, null, 2));
20991
21641
  else
20992
21642
  printAndroidTestReport(report);
20993
- const screenshot = reportRoot ? await session.screenshot(join54(artifactRoot, "android-emulator.png")) : undefined;
21643
+ const screenshot = reportRoot ? await session.screenshot(join55(artifactRoot, "android-emulator.png")) : undefined;
20994
21644
  await writeRequestedAndroidReport({
20995
21645
  adb,
20996
21646
  args,
@@ -21058,14 +21708,14 @@ Emulator setup verification:`);
21058
21708
  const port = Number(explicit);
21059
21709
  if (!Number.isInteger(port) || port < 1 || port > 65535)
21060
21710
  throw new TypeError("mobile test --port must be a valid TCP port.");
21061
- const instance2 = listLiveInstances().find((candidate) => resolve44(candidate.cwd) === resolve44(projectRoot) && candidate.source === "dev" && candidate.port === port);
21711
+ const instance2 = listLiveInstances().find((candidate) => resolve45(candidate.cwd) === resolve45(projectRoot) && candidate.source === "dev" && candidate.port === port);
21062
21712
  return {
21063
21713
  https: instance2?.https ?? args.includes("--https"),
21064
21714
  instance: instance2,
21065
21715
  port
21066
21716
  };
21067
21717
  }
21068
- const instances = listLiveInstances().filter((instance2) => resolve44(instance2.cwd) === resolve44(projectRoot) && instance2.source === "dev" && instance2.port !== null);
21718
+ const instances = listLiveInstances().filter((instance2) => resolve45(instance2.cwd) === resolve45(projectRoot) && instance2.source === "dev" && instance2.port !== null);
21069
21719
  if (instances.length !== 1)
21070
21720
  throw new TypeError(instances.length === 0 ? "No running AbsoluteJS dev server was found for this project. Start `bun dev`, wait for iOS to report ready, then run `absolute mobile test ios`." : "Multiple dev servers are running for this project. Select one with mobile test ios --port <port>.");
21071
21721
  const [instance] = instances;
@@ -21179,8 +21829,8 @@ Emulator setup verification:`);
21179
21829
  throw new Error(`${label} failed: ${result.stderr.trim() || result.stdout.trim() || `status ${result.exitCode}`}`);
21180
21830
  return result;
21181
21831
  }, writeIosFailureArtifacts = async (options) => {
21182
- await mkdir15(options.artifactRoot, { recursive: true });
21183
- const screenshot = join54(options.artifactRoot, "ios-failure.png");
21832
+ await mkdir16(options.artifactRoot, { recursive: true });
21833
+ const screenshot = join55(options.artifactRoot, "ios-failure.png");
21184
21834
  const screenshotResult = captureCommand4([
21185
21835
  options.xcrun,
21186
21836
  "simctl",
@@ -21189,8 +21839,8 @@ Emulator setup verification:`);
21189
21839
  "screenshot",
21190
21840
  screenshot
21191
21841
  ]);
21192
- const diagnosticPath = join54(options.artifactRoot, "ios-failure.json");
21193
- await writeFile17(diagnosticPath, `${JSON.stringify({
21842
+ const diagnosticPath = join55(options.artifactRoot, "ios-failure.json");
21843
+ await writeFile18(diagnosticPath, `${JSON.stringify({
21194
21844
  appId: options.appId,
21195
21845
  error: options.error instanceof Error ? options.error.message : String(options.error),
21196
21846
  platform: "ios",
@@ -21215,8 +21865,8 @@ Emulator setup verification:`);
21215
21865
  }, absolutejsVersionForReport = async () => {
21216
21866
  let absolutejsVersion = process.env.ABSOLUTE_VERSION ?? "unknown";
21217
21867
  const versions = await Promise.all([
21218
- resolve44(import.meta.dir, "..", "..", "package.json"),
21219
- resolve44(import.meta.dir, "..", "..", "..", "package.json")
21868
+ resolve45(import.meta.dir, "..", "..", "package.json"),
21869
+ resolve45(import.meta.dir, "..", "..", "..", "package.json")
21220
21870
  ].map((candidate) => readPackageVersionForIosReport(candidate).catch(() => "unknown")));
21221
21871
  for (const version2 of versions) {
21222
21872
  if (version2 === "unknown")
@@ -21376,6 +22026,7 @@ Emulator setup verification:`);
21376
22026
  }
21377
22027
  }, testIos = async (args) => {
21378
22028
  const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
22029
+ requireCapacitorEngine(mobile, "mobile test ios");
21379
22030
  const { https, instance, port } = requireIosTestContext(args, projectRoot);
21380
22031
  if (!mobile.platforms.includes("ios"))
21381
22032
  throw new TypeError("mobile test ios requires ios in mobile.platforms.");
@@ -21434,8 +22085,8 @@ Emulator setup verification:`);
21434
22085
  mobile.appId
21435
22086
  ], "iOS app launch");
21436
22087
  await waitForIosHmrClient({ https, port, timeoutMs });
21437
- await mkdir15(artifactRoot, { recursive: true });
21438
- const screenshot = join54(artifactRoot, "ios-simulator.png");
22088
+ await mkdir16(artifactRoot, { recursive: true });
22089
+ const screenshot = join55(artifactRoot, "ios-simulator.png");
21439
22090
  requireCapturedCommand([xcrun, "simctl", "io", simulator.udid, "screenshot", screenshot], "iOS simulator screenshot");
21440
22091
  const hmrApply = await waitForRequestedIosHmr(args, instance, timeoutMs);
21441
22092
  const report = {
@@ -21585,6 +22236,7 @@ Emulator setup verification:`);
21585
22236
  var init_mobile = __esm(() => {
21586
22237
  init_dependencies();
21587
22238
  init_capacitorProject();
22239
+ init_expoProject();
21588
22240
  init_config();
21589
22241
  init_nativeDeepLinks();
21590
22242
  init_nativeDeviceCapabilities();
@@ -21651,10 +22303,10 @@ var exports_typecheck = {};
21651
22303
  __export(exports_typecheck, {
21652
22304
  typecheck: () => typecheck
21653
22305
  });
21654
- import { resolve as resolve45, join as join55 } from "path";
22306
+ import { resolve as resolve46, join as join56 } from "path";
21655
22307
  import { existsSync as existsSync43, readFileSync as readFileSync40 } from "fs";
21656
- import { mkdir as mkdir16, writeFile as writeFile18 } from "fs/promises";
21657
- var isCommandService3 = (service) => service.kind === "command" || Array.isArray(service.command), resolveConfigPath = (configPath2) => resolve45(configPath2 ?? process.env.ABSOLUTE_CONFIG ?? "absolute.config.ts"), getTypecheckTargets = async (configPath2) => {
22308
+ import { mkdir as mkdir17, writeFile as writeFile19 } from "fs/promises";
22309
+ var isCommandService3 = (service) => service.kind === "command" || Array.isArray(service.command), resolveConfigPath = (configPath2) => resolve46(configPath2 ?? process.env.ABSOLUTE_CONFIG ?? "absolute.config.ts"), getTypecheckTargets = async (configPath2) => {
21658
22310
  if (!existsSync43(resolveConfigPath(configPath2))) {
21659
22311
  const defaultService = {};
21660
22312
  return [defaultService];
@@ -21676,7 +22328,7 @@ var isCommandService3 = (service) => service.kind === "command" || Array.isArray
21676
22328
  const exitCode = await proc.exited;
21677
22329
  return { exitCode, name, output: (stdout + stderr).trim() };
21678
22330
  }, shellEscape = (value) => `'${value.replaceAll("'", "'\\''")}'`, runShell = async (name, command) => run(name, ["/bin/bash", "-lc", command]), findBin = (name) => {
21679
- const local = resolve45("node_modules", ".bin", name);
22331
+ const local = resolve46("node_modules", ".bin", name);
21680
22332
  return existsSync43(local) ? local : null;
21681
22333
  }, ANSI_COLOR_REGEX, ANSI_PURPLE_REGEX, ANSI_CYAN_REGEX, ANSI_TOKEN_END_REGEX, stripAnsi4 = (str) => str.replace(ANSI_COLOR_REGEX, ""), formatSvelteOutput = (output) => {
21682
22334
  const cwd = `${process.cwd()}/`;
@@ -21724,15 +22376,15 @@ Found ${errorCount} error${suffix}.`;
21724
22376
  return formatted;
21725
22377
  }, ABSOLUTE_INTERNAL_EXCLUDES, resolveAbsoluteTypeFile = (fileName) => {
21726
22378
  const candidates = [
21727
- resolve45("node_modules/@absolutejs/absolute/dist/types", fileName),
21728
- resolve45(import.meta.dir, "../types", fileName),
21729
- resolve45(import.meta.dir, "../../types", fileName),
21730
- resolve45(import.meta.dir, "../../../types", fileName)
22379
+ resolve46("node_modules/@absolutejs/absolute/dist/types", fileName),
22380
+ resolve46(import.meta.dir, "../types", fileName),
22381
+ resolve46(import.meta.dir, "../../types", fileName),
22382
+ resolve46(import.meta.dir, "../../../types", fileName)
21731
22383
  ];
21732
22384
  return candidates.find((candidate) => existsSync43(candidate)) ?? candidates[0];
21733
22385
  }, ABSOLUTE_TYPECHECK_FILES, readProjectTsconfig = () => {
21734
22386
  try {
21735
- return JSON.parse(readFileSync40(resolve45("tsconfig.json"), "utf-8"));
22387
+ return JSON.parse(readFileSync40(resolve46("tsconfig.json"), "utf-8"));
21736
22388
  } catch {
21737
22389
  return {};
21738
22390
  }
@@ -21760,27 +22412,27 @@ Found ${errorCount} error${suffix}.`;
21760
22412
  console.error("\x1B[31m\u2717\x1B[0m vue-tsc is required for Vue type checking. Install it: bun add -d vue-tsc");
21761
22413
  process.exit(1);
21762
22414
  }
21763
- const vueTsconfigPath = join55(cacheDir, "tsconfig.vue-check.json");
21764
- await writeFile18(vueTsconfigPath, JSON.stringify({
22415
+ const vueTsconfigPath = join56(cacheDir, "tsconfig.vue-check.json");
22416
+ await writeFile19(vueTsconfigPath, JSON.stringify({
21765
22417
  compilerOptions: {
21766
22418
  rootDir: ".."
21767
22419
  },
21768
22420
  exclude: getProjectTypecheckExcludes(),
21769
- extends: resolve45("tsconfig.json"),
22421
+ extends: resolve46("tsconfig.json"),
21770
22422
  include: getProjectTypecheckIncludes()
21771
22423
  }, null, "\t"));
21772
22424
  const base = [
21773
22425
  vueTscBin,
21774
22426
  "--noEmit",
21775
22427
  "--project",
21776
- resolve45(vueTsconfigPath),
22428
+ resolve46(vueTsconfigPath),
21777
22429
  "--pretty"
21778
22430
  ];
21779
22431
  const cached = await run("vue-tsc", [
21780
22432
  ...base,
21781
22433
  "--incremental",
21782
22434
  "--tsBuildInfoFile",
21783
- join55(cacheDir, "vue-tsc.tsbuildinfo")
22435
+ join56(cacheDir, "vue-tsc.tsbuildinfo")
21784
22436
  ]);
21785
22437
  if (cached.exitCode === 0 || cached.output.length > 0)
21786
22438
  return cached;
@@ -21791,8 +22443,8 @@ Found ${errorCount} error${suffix}.`;
21791
22443
  console.error("\x1B[31m\u2717\x1B[0m @angular/compiler-cli is required for Angular type checking. Install it: bun add -d @angular/compiler-cli");
21792
22444
  process.exit(1);
21793
22445
  }
21794
- const angularTsconfigPath = join55(cacheDir, "tsconfig.angular-check.json");
21795
- await writeFile18(angularTsconfigPath, JSON.stringify({
22446
+ const angularTsconfigPath = join56(cacheDir, "tsconfig.angular-check.json");
22447
+ await writeFile19(angularTsconfigPath, JSON.stringify({
21796
22448
  angularCompilerOptions: {
21797
22449
  strictTemplates: true
21798
22450
  },
@@ -21801,32 +22453,32 @@ Found ${errorCount} error${suffix}.`;
21801
22453
  rootDir: ".."
21802
22454
  },
21803
22455
  exclude: ABSOLUTE_INTERNAL_EXCLUDES.map(toGeneratedConfigPath),
21804
- extends: resolve45("tsconfig.json"),
22456
+ extends: resolve46("tsconfig.json"),
21805
22457
  include: [`../${angularDir}/**/*`]
21806
22458
  }, null, "\t"));
21807
- return runShell("ngc", `${shellEscape(ngcBin)} -p ${shellEscape(resolve45(angularTsconfigPath))}`);
22459
+ return runShell("ngc", `${shellEscape(ngcBin)} -p ${shellEscape(resolve46(angularTsconfigPath))}`);
21808
22460
  }, buildTscCheck = (cacheDir) => {
21809
22461
  const tscBin = findBin("tsc");
21810
22462
  if (!tscBin) {
21811
22463
  console.error("\x1B[31m\u2717\x1B[0m typescript is required for type checking. Install it: bun add -d typescript");
21812
22464
  process.exit(1);
21813
22465
  }
21814
- const tscConfigPath = join55(cacheDir, "tsconfig.typecheck.json");
21815
- return writeFile18(tscConfigPath, JSON.stringify({
22466
+ const tscConfigPath = join56(cacheDir, "tsconfig.typecheck.json");
22467
+ return writeFile19(tscConfigPath, JSON.stringify({
21816
22468
  compilerOptions: {
21817
22469
  rootDir: ".."
21818
22470
  },
21819
22471
  exclude: getProjectTypecheckExcludes(),
21820
- extends: resolve45("tsconfig.json"),
22472
+ extends: resolve46("tsconfig.json"),
21821
22473
  include: getProjectTypecheckIncludes()
21822
22474
  }, null, "\t")).then(() => run("tsc", [
21823
22475
  tscBin,
21824
22476
  "--noEmit",
21825
22477
  "--project",
21826
- resolve45(tscConfigPath),
22478
+ resolve46(tscConfigPath),
21827
22479
  "--incremental",
21828
22480
  "--tsBuildInfoFile",
21829
- join55(cacheDir, "tsc.tsbuildinfo"),
22481
+ join56(cacheDir, "tsc.tsbuildinfo"),
21830
22482
  "--pretty"
21831
22483
  ]));
21832
22484
  }, buildSvelteCheck = async (cacheDir, svelteDir) => {
@@ -21835,16 +22487,16 @@ Found ${errorCount} error${suffix}.`;
21835
22487
  console.error("\x1B[31m\u2717\x1B[0m svelte-check is required for Svelte type checking. Install it: bun add -d svelte-check");
21836
22488
  process.exit(1);
21837
22489
  }
21838
- const svelteTsconfigPath = join55(cacheDir, "tsconfig.svelte-check.json");
21839
- await writeFile18(svelteTsconfigPath, JSON.stringify({
21840
- extends: resolve45("tsconfig.json"),
22490
+ const svelteTsconfigPath = join56(cacheDir, "tsconfig.svelte-check.json");
22491
+ await writeFile19(svelteTsconfigPath, JSON.stringify({
22492
+ extends: resolve46("tsconfig.json"),
21841
22493
  files: ABSOLUTE_TYPECHECK_FILES,
21842
22494
  include: [`../${svelteDir}/**/*`]
21843
22495
  }, null, "\t"));
21844
22496
  return run("svelte-check", [
21845
22497
  svelteBin,
21846
22498
  "--tsconfig",
21847
- resolve45(svelteTsconfigPath),
22499
+ resolve46(svelteTsconfigPath),
21848
22500
  "--threshold",
21849
22501
  "error",
21850
22502
  "--compiler-warnings",
@@ -21865,7 +22517,7 @@ Found ${errorCount} error${suffix}.`;
21865
22517
  ...new Set(targets.map((config) => config.angularDirectory).filter((dir) => typeof dir === "string" && dir.length > 0))
21866
22518
  ];
21867
22519
  const cacheDir = ".absolutejs";
21868
- await mkdir16(cacheDir, { recursive: true });
22520
+ await mkdir17(cacheDir, { recursive: true });
21869
22521
  const checks = [];
21870
22522
  checks.push(hasVue ? buildVueTscCheck(cacheDir) : buildTscCheck(cacheDir));
21871
22523
  for (const svelteDir of hasSvelte ? svelteDirs : []) {
@@ -22038,11 +22690,11 @@ var DEFAULT_RELAY_PORT = 8787, DEFAULT_REQUEST_TIMEOUT_MS = 30000, headersToObje
22038
22690
  url: url.pathname + url.search,
22039
22691
  ...bodyBytes && bodyBytes.length > 0 ? { bodyBase64: Buffer.from(bodyBytes).toString("base64") } : {}
22040
22692
  };
22041
- const responsePromise = new Promise((resolve46) => {
22042
- pending.set(id, resolve46);
22693
+ const responsePromise = new Promise((resolve47) => {
22694
+ pending.set(id, resolve47);
22043
22695
  });
22044
22696
  client.send(encodeTunnelMessage(message));
22045
- const timeout = new Promise((resolve46) => setTimeout(() => resolve46({ id, message: "timeout", type: "error" }), requestTimeoutMs));
22697
+ const timeout = new Promise((resolve47) => setTimeout(() => resolve47({ id, message: "timeout", type: "error" }), requestTimeoutMs));
22046
22698
  const result = await Promise.race([responsePromise, timeout]);
22047
22699
  pending.delete(id);
22048
22700
  if (result.type === "error") {
@@ -23015,7 +23667,9 @@ var dev = async (serverEntry, configPath2, options = {}) => {
23015
23667
  if (mobileConfig && mobileInteractive) {
23016
23668
  try {
23017
23669
  const normalized = normalizeAbsoluteMobileConfig(mobileConfig, process.cwd());
23018
- if (normalized.platforms.includes("android")) {
23670
+ if (normalized.engine === "expo") {
23671
+ console.log(cliTag("\x1B[35m", "Expo hybrid support is experimental. AbsoluteJS web development is running; start Metro from .absolutejs/mobile/expo for the native shell."));
23672
+ } else if (normalized.platforms.includes("android")) {
23019
23673
  const androidTarget = options.androidDevice ? "device" : "emulator";
23020
23674
  let ready = androidToolchainReady(await inspectAbsoluteMobileToolchain(), androidTarget);
23021
23675
  if (!ready) {
@@ -23042,7 +23696,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
23042
23696
  }
23043
23697
  }
23044
23698
  }
23045
- if (normalized.platforms.includes("ios")) {
23699
+ if (normalized.engine === "capacitor" && normalized.platforms.includes("ios")) {
23046
23700
  if (detectAbsoluteMobileHost() !== "macos") {
23047
23701
  const remote = selectedRemoteMacProfile ?? await getAbsoluteRemoteMacProfile();
23048
23702
  if (!remote) {
@@ -24406,7 +25060,7 @@ import {
24406
25060
  writeFileSync as writeFileSync6
24407
25061
  } from "fs";
24408
25062
  import { createConnection } from "net";
24409
- import { resolve as resolve22 } from "path";
25063
+ import { resolve as resolve23 } from "path";
24410
25064
 
24411
25065
  // src/cli/workspaceTui.ts
24412
25066
  init_constants();
@@ -24968,18 +25622,18 @@ var createWorkspaceTui = ({
24968
25622
 
24969
25623
  // src/cli/scripts/workspace.ts
24970
25624
  init_utils();
24971
- var sourceServerBootstrap2 = resolve22(import.meta.dir, "../../dev/serverBootstrap.ts");
24972
- var serverBootstrap2 = existsSync12(sourceServerBootstrap2) ? sourceServerBootstrap2 : resolve22(import.meta.dir, "../dev/serverBootstrap.js");
25625
+ var sourceServerBootstrap2 = resolve23(import.meta.dir, "../../dev/serverBootstrap.ts");
25626
+ var serverBootstrap2 = existsSync12(sourceServerBootstrap2) ? sourceServerBootstrap2 : resolve23(import.meta.dir, "../dev/serverBootstrap.js");
24973
25627
  var ANSI_REGEX2 = new RegExp(`${String.fromCharCode(ANSI_ESCAPE_CODE)}\\[[0-?]*[ -/]*[@-~]`, "g");
24974
25628
  var sleep = (durationMs) => Bun.sleep(durationMs);
24975
25629
  var stripAnsi3 = (value) => value.replace(ANSI_REGEX2, "");
24976
25630
  var sanitizeLogFileName = (value) => value.replace(/[^a-zA-Z0-9._-]/g, "_") || "unknown";
24977
25631
  var createWorkspaceLogSink = (appendLog) => {
24978
- const logDirectory = resolve22(".absolutejs", "workspace", "logs");
25632
+ const logDirectory = resolve23(".absolutejs", "workspace", "logs");
24979
25633
  mkdirSync7(logDirectory, { recursive: true });
24980
- readdirSync2(logDirectory).filter((file) => file.endsWith(".log")).forEach((file) => unlinkSync3(resolve22(logDirectory, file)));
24981
- writeFileSync6(resolve22(logDirectory, "all.log"), "");
24982
- writeFileSync6(resolve22(logDirectory, "workspace.log"), "");
25634
+ readdirSync2(logDirectory).filter((file) => file.endsWith(".log")).forEach((file) => unlinkSync3(resolve23(logDirectory, file)));
25635
+ writeFileSync6(resolve23(logDirectory, "all.log"), "");
25636
+ writeFileSync6(resolve23(logDirectory, "workspace.log"), "");
24983
25637
  const initializedSources = new Set(["workspace"]);
24984
25638
  const writeLog = (source, message, level) => {
24985
25639
  const cleanMessage = stripAnsi3(message).trimEnd();
@@ -24989,13 +25643,13 @@ var createWorkspaceLogSink = (appendLog) => {
24989
25643
  const timestamp = new Date().toISOString();
24990
25644
  const line = `[${timestamp}] [${level}] [${source}] ${cleanMessage}
24991
25645
  `;
24992
- const sourceFile = resolve22(logDirectory, `${sanitizeLogFileName(source)}.log`);
25646
+ const sourceFile = resolve23(logDirectory, `${sanitizeLogFileName(source)}.log`);
24993
25647
  if (!initializedSources.has(source)) {
24994
25648
  writeFileSync6(sourceFile, "");
24995
25649
  initializedSources.add(source);
24996
25650
  }
24997
25651
  appendFileSync(sourceFile, line);
24998
- appendFileSync(resolve22(logDirectory, "all.log"), line);
25652
+ appendFileSync(resolve23(logDirectory, "all.log"), line);
24999
25653
  };
25000
25654
  return {
25001
25655
  appendLog: (source, message, level = "info") => {
@@ -25019,9 +25673,9 @@ var readPackageVersion3 = (candidate) => {
25019
25673
  };
25020
25674
  var resolvePackageVersion2 = () => {
25021
25675
  const candidates = [
25022
- resolve22(import.meta.dir, "..", "..", "package.json"),
25023
- resolve22(import.meta.dir, "..", "..", "..", "package.json"),
25024
- resolve22(import.meta.dir, "..", "..", "..", "..", "package.json")
25676
+ resolve23(import.meta.dir, "..", "..", "package.json"),
25677
+ resolve23(import.meta.dir, "..", "..", "..", "package.json"),
25678
+ resolve23(import.meta.dir, "..", "..", "..", "..", "package.json")
25025
25679
  ];
25026
25680
  for (const candidate of candidates) {
25027
25681
  const version2 = readPackageVersion3(candidate);
@@ -25375,15 +26029,15 @@ var createWorkspaceServiceEnv = (services) => {
25375
26029
  var getDefinedProcessEnv = () => Object.fromEntries(Object.entries(process.env).filter((entry) => typeof entry[1] === "string"));
25376
26030
  var resolveAbsoluteServiceConfigPath = (service, cwd, options) => {
25377
26031
  if (service.config)
25378
- return resolve22(cwd, service.config);
26032
+ return resolve23(cwd, service.config);
25379
26033
  if (options.configPath)
25380
- return resolve22(options.configPath);
26034
+ return resolve23(options.configPath);
25381
26035
  if (process.env.ABSOLUTE_CONFIG)
25382
- return resolve22(process.env.ABSOLUTE_CONFIG);
26036
+ return resolve23(process.env.ABSOLUTE_CONFIG);
25383
26037
  return;
25384
26038
  };
25385
26039
  var resolveService = (name, service, workspaceEnv, options) => {
25386
- const cwd = resolve22(service.cwd ?? ".");
26040
+ const cwd = resolve23(service.cwd ?? ".");
25387
26041
  const envVars = Object.assign(getDefinedProcessEnv(), workspaceEnv, service.port ? { PORT: String(service.port) } : {}, service.env, {
25388
26042
  ABSOLUTE_INSTANCE_MANAGED: "1",
25389
26043
  ABSOLUTE_WORKSPACE_MANAGED: "1",
@@ -25395,7 +26049,7 @@ var resolveService = (name, service, workspaceEnv, options) => {
25395
26049
  if (isAbsoluteService(service)) {
25396
26050
  const configPath2 = resolveAbsoluteServiceConfigPath(service, cwd, options);
25397
26051
  Object.assign(envVars, configPath2 ? { ABSOLUTE_CONFIG: configPath2 } : {}, {
25398
- ABSOLUTE_SERVER_ENTRY: resolve22(cwd, service.entry ?? DEFAULT_SERVER_ENTRY)
26052
+ ABSOLUTE_SERVER_ENTRY: resolve23(cwd, service.entry ?? DEFAULT_SERVER_ENTRY)
25399
26053
  });
25400
26054
  const command = [
25401
26055
  process.execPath,
@@ -25425,8 +26079,8 @@ var resolveService = (name, service, workspaceEnv, options) => {
25425
26079
  var resolveServiceBuildDirectory = (service) => {
25426
26080
  if (!isAbsoluteService(service))
25427
26081
  return null;
25428
- const cwd = resolve22(service.cwd ?? ".");
25429
- return resolve22(cwd, service.buildDirectory ?? "build");
26082
+ const cwd = resolve23(service.cwd ?? ".");
26083
+ return resolve23(cwd, service.buildDirectory ?? "build");
25430
26084
  };
25431
26085
  var findSharedWorkspaceBuildDirectories = (services) => {
25432
26086
  const byBuildDirectory = new Map;
@@ -25644,7 +26298,7 @@ var workspace = async (subcommand, options) => {
25644
26298
  frameworks: [],
25645
26299
  host: getServicePublicHost(resolved.service),
25646
26300
  https: getServiceProtocol(resolved.service) === "https",
25647
- logFile: resolve22(workspaceLogs.logDirectory, `${sanitizeLogFileName(name)}.log`),
26301
+ logFile: resolve23(workspaceLogs.logDirectory, `${sanitizeLogFileName(name)}.log`),
25648
26302
  name,
25649
26303
  pid: processHandle.pid,
25650
26304
  port: resolved.service.port ?? null,
@@ -25955,7 +26609,7 @@ if (command === "dev") {
25955
26609
  console.error(" prepare [entry] [--outdir dir] Build production assets and server without launching");
25956
26610
  console.error(" start [entry] [--outdir dir] [--prebuilt] Start production server");
25957
26611
  console.error(" compile [entry] [--outdir dir] [--outfile path] Compile standalone executable");
25958
- console.error(" mobile <init|sync|inspect|ci|pair|remotes|doctor|test> Manage Capacitor projects, CI, simulators, physical devices, Remote Macs, guided setup, and deep links");
26612
+ console.error(" mobile <init|sync|inspect|ci|pair|remotes|doctor|test> Manage Capacitor apps and the experimental Expo hybrid shell");
25959
26613
  console.error(" config [--port n] Open the unified config UI (ESLint, tsconfig, Prettier)");
25960
26614
  console.error(" db <backup|restore|seed> Backup/restore any Postgres DB (ORM-agnostic, upsert by PK) or run the seed script");
25961
26615
  console.error(" doctor [--fix] [--json] Diagnose the project (bun, type graph, config, framework dirs, env, port)");