@absolutejs/absolute 0.20.0-beta.32 → 0.20.0-beta.34

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.
@@ -2580,17 +2580,134 @@ var waitForAbsoluteIosHmrLog = async (options) => {
2580
2580
  return poll();
2581
2581
  };
2582
2582
  // src/mobile/iosSimulatorController.ts
2583
- import { createHash as createHash6, randomUUID as randomUUID2 } from "crypto";
2583
+ import { createHash as createHash6, randomUUID as randomUUID3 } from "crypto";
2584
2584
  import {
2585
2585
  access as access6,
2586
2586
  copyFile as copyFile4,
2587
2587
  mkdir as mkdir5,
2588
- readFile as readFile7,
2588
+ readFile as readFile8,
2589
2589
  rename as rename6,
2590
2590
  rm as rm5,
2591
2591
  writeFile as writeFile6
2592
2592
  } from "fs/promises";
2593
+ import { isIP as isIP2 } from "net";
2593
2594
  import { dirname as dirname4, isAbsolute as isAbsolute4, join as join6, relative as relative5, resolve as resolve5, sep as sep4 } from "path";
2595
+
2596
+ // src/mobile/iosPhysicalDeviceTransport.ts
2597
+ import { randomUUID as randomUUID2, X509Certificate } from "crypto";
2598
+ import { createServer } from "http";
2599
+ import {
2600
+ connect as connectTcp,
2601
+ createServer as createTcpServer,
2602
+ isIP
2603
+ } from "net";
2604
+ import { readFile as readFile7 } from "fs/promises";
2605
+ var closeServer = (server) => new Promise((resolve5, reject) => {
2606
+ server.close((error) => {
2607
+ if (error)
2608
+ reject(error);
2609
+ else
2610
+ resolve5();
2611
+ });
2612
+ });
2613
+ var listen = (server, port) => new Promise((resolve5, reject) => {
2614
+ server.once("error", reject);
2615
+ server.listen(port, "0.0.0.0", () => {
2616
+ server.off("error", reject);
2617
+ const address = server.address();
2618
+ if (!address || typeof address === "string") {
2619
+ reject(new Error("Could not determine the iOS device helper port."));
2620
+ return;
2621
+ }
2622
+ resolve5(address.port);
2623
+ });
2624
+ });
2625
+ var findEphemeralPort = async () => {
2626
+ const probe = createTcpServer();
2627
+ const port = await new Promise((resolve5, reject) => {
2628
+ probe.once("error", reject);
2629
+ probe.listen(0, "127.0.0.1", () => {
2630
+ const address = probe.address();
2631
+ if (!address || typeof address === "string") {
2632
+ reject(new Error("Could not allocate the iOS CA enrollment port."));
2633
+ return;
2634
+ }
2635
+ resolve5(address.port);
2636
+ });
2637
+ });
2638
+ await closeServer(probe);
2639
+ return port;
2640
+ };
2641
+ var normalizeAbsoluteIosDeviceHost = (value) => {
2642
+ const normalized = value.trim();
2643
+ if (!normalized || normalized.length > 253 || /[\0\s/?#]/u.test(normalized))
2644
+ throw new TypeError("Physical iOS development requires a valid LAN host.");
2645
+ return normalized;
2646
+ };
2647
+ var normalizeAbsoluteIosDeviceIdentifier = (value) => {
2648
+ const normalized = value.trim();
2649
+ if (!normalized || normalized.length > 256 || /[\0\r\n]/u.test(normalized))
2650
+ throw new TypeError("--ios-device requires a valid Xcode device identifier or name.");
2651
+ return normalized;
2652
+ };
2653
+ var urlForHost = (protocol, host, port) => {
2654
+ const url = new URL(`${protocol}://localhost:${port}`);
2655
+ const normalizedHost = normalizeAbsoluteIosDeviceHost(host);
2656
+ url.hostname = isIP(normalizedHost) === 6 ? `[${normalizedHost}]` : normalizedHost;
2657
+ return url;
2658
+ };
2659
+ var startAbsoluteIosCaEnrollmentServer = async (options) => {
2660
+ const certificate = new X509Certificate(await readFile7(options.certificateAuthorityPath));
2661
+ const certificateBytes = certificate.raw;
2662
+ const token = randomUUID2().replaceAll("-", "");
2663
+ const certificatePath = `/${token}/absolutejs-development-ca.cer`;
2664
+ const server = createServer((request, response) => {
2665
+ if (request.method !== "GET" || request.url !== certificatePath) {
2666
+ response.writeHead(404, {
2667
+ "Cache-Control": "no-store",
2668
+ "Content-Type": "text/plain; charset=utf-8"
2669
+ });
2670
+ response.end("Not found.");
2671
+ return;
2672
+ }
2673
+ response.writeHead(200, {
2674
+ "Cache-Control": "no-store",
2675
+ "Content-Disposition": 'attachment; filename="absolutejs-development-ca.cer"',
2676
+ "Content-Length": String(certificateBytes.byteLength),
2677
+ "Content-Type": "application/x-x509-ca-cert",
2678
+ "X-Content-Type-Options": "nosniff"
2679
+ });
2680
+ response.end(certificateBytes);
2681
+ });
2682
+ const port = await findEphemeralPort();
2683
+ await listen(server, port);
2684
+ const url = urlForHost("http", options.displayHost, port);
2685
+ url.pathname = certificatePath;
2686
+ return {
2687
+ url: url.href,
2688
+ close: () => closeServer(server)
2689
+ };
2690
+ };
2691
+ var startAbsoluteIosTcpRelay = async (options) => {
2692
+ const server = createTcpServer((downstream) => {
2693
+ const upstream = connectTcp({
2694
+ host: "127.0.0.1",
2695
+ port: options.targetPort
2696
+ });
2697
+ downstream.pipe(upstream);
2698
+ upstream.pipe(downstream);
2699
+ const closePeer = () => {
2700
+ downstream.destroy();
2701
+ upstream.destroy();
2702
+ };
2703
+ downstream.once("error", closePeer);
2704
+ upstream.once("error", closePeer);
2705
+ });
2706
+ await listen(server, options.listenPort);
2707
+ return { close: () => closeServer(server) };
2708
+ };
2709
+
2710
+ // src/mobile/iosSimulatorController.ts
2594
2711
  init_getDurationString();
2595
2712
  var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone";
2596
2713
  var BOOT_TIMEOUT_MS = 180000;
@@ -2700,6 +2817,40 @@ var requireSuccess2 = async (command, label, run, options) => {
2700
2817
  if (exitCode !== 0)
2701
2818
  throw new Error(`${label} failed with status ${exitCode}.`);
2702
2819
  };
2820
+ var trustIosSimulatorDevelopmentCa = async (options, udid, run, log) => {
2821
+ if (!options.https)
2822
+ return;
2823
+ if (!options.certificateAuthorityPath) {
2824
+ throw new Error("iOS Simulator HTTPS requires the AbsoluteJS development CA certificate.");
2825
+ }
2826
+ await requireSuccess2([
2827
+ options.project.xcrun,
2828
+ "simctl",
2829
+ "keychain",
2830
+ udid,
2831
+ "add-root-cert",
2832
+ options.certificateAuthorityPath
2833
+ ], "iOS Simulator development CA trust", run, { signal: options.signal });
2834
+ log("Installed the AbsoluteJS development CA into this iOS Simulator trust store.");
2835
+ };
2836
+ var iosLaunchCommand = (project, udid, physical) => physical ? [
2837
+ project.xcrun,
2838
+ "devicectl",
2839
+ "device",
2840
+ "process",
2841
+ "launch",
2842
+ "--terminate-existing",
2843
+ "--device",
2844
+ udid,
2845
+ project.config.appId
2846
+ ] : [
2847
+ project.xcrun,
2848
+ "simctl",
2849
+ "launch",
2850
+ "--terminate-running-process",
2851
+ udid,
2852
+ project.config.appId
2853
+ ];
2703
2854
  var requireCapturedSuccess = (result, label) => {
2704
2855
  if (result.exitCode !== 0) {
2705
2856
  throw new Error(`${label} failed: ${result.stderr.trim() || result.stdout.trim() || `status ${result.exitCode}`}`);
@@ -2837,7 +2988,7 @@ var repairAbsoluteIosDevSession = async (projectRoot) => {
2837
2988
  await rm5(paths.root, { force: true, recursive: true });
2838
2989
  return false;
2839
2990
  }
2840
- const journal = await readFile7(paths.journal, "utf8").then((source) => parseJournal(JSON.parse(source))).catch(() => null);
2991
+ const journal = await readFile8(paths.journal, "utf8").then((source) => parseJournal(JSON.parse(source))).catch(() => null);
2841
2992
  if (!journal || !isInside(projectRoot, journal.nativeConfigPath) || !isInside(projectRoot, journal.infoPath) || !isInside(paths.root, journal.configBackupPath) || !isInside(paths.root, journal.infoBackupPath)) {
2842
2993
  throw new Error(`Refusing unsafe or invalid iOS dev journal at ${paths.journal}.`);
2843
2994
  }
@@ -2868,14 +3019,14 @@ var iosDevelopmentInfoPlist = (source, cleartext) => {
2868
3019
  <true/>
2869
3020
  </dict>`);
2870
3021
  };
2871
- var writeDevProjection = async (project, port, https) => {
3022
+ var writeDevProjection = async (project, port, https, serverHost = "localhost") => {
2872
3023
  const paths = journalPaths(project.projectRoot);
2873
3024
  await repairAbsoluteIosDevSession(project.projectRoot);
2874
3025
  const nativeConfigPath = join6(project.nativeDirectory, "App", "App", "capacitor.config.json");
2875
3026
  const infoPath = join6(project.nativeDirectory, "App", "App", "Info.plist");
2876
3027
  const [configSource, infoSource] = await Promise.all([
2877
- readFile7(nativeConfigPath, "utf8"),
2878
- readFile7(infoPath, "utf8")
3028
+ readFile8(nativeConfigPath, "utf8"),
3029
+ readFile8(infoPath, "utf8")
2879
3030
  ]);
2880
3031
  const parsed = JSON.parse(configSource);
2881
3032
  if (!isRecord3(parsed))
@@ -2897,6 +3048,7 @@ var writeDevProjection = async (project, port, https) => {
2897
3048
  flag: "wx"
2898
3049
  });
2899
3050
  const developmentUrl = new URL(`${https ? "https" : "http"}://localhost:${port}${project.config.entry}`);
3051
+ developmentUrl.hostname = isIP2(serverHost) === 6 ? `[${serverHost}]` : serverHost;
2900
3052
  developmentUrl.searchParams.set("__absolute_target", "capacitor-ios");
2901
3053
  const existingServer = parsed.server;
2902
3054
  parsed.server = {
@@ -2926,10 +3078,10 @@ var parseNativeCache = (value) => {
2926
3078
  ]))
2927
3079
  };
2928
3080
  };
2929
- var readNativeCache = (projectRoot) => readFile7(nativeCachePath(projectRoot), "utf8").then((source) => parseNativeCache(JSON.parse(source))).catch(() => null);
3081
+ var readNativeCache = (projectRoot) => readFile8(nativeCachePath(projectRoot), "utf8").then((source) => parseNativeCache(JSON.parse(source))).catch(() => null);
2930
3082
  var writeNativeCache = async (projectRoot, cache) => {
2931
3083
  const destination = nativeCachePath(projectRoot);
2932
- const temporary = `${destination}.${process.pid}.${randomUUID2()}.tmp`;
3084
+ const temporary = `${destination}.${process.pid}.${randomUUID3()}.tmp`;
2933
3085
  await mkdir5(dirname4(destination), { recursive: true });
2934
3086
  try {
2935
3087
  await writeFile6(temporary, `${JSON.stringify(cache, null, "\t")}
@@ -3018,6 +3170,31 @@ var installedAppIdentity = (project, udid, capture) => {
3018
3170
  ]);
3019
3171
  return result.exitCode === 0 && result.stdout.trim() ? result.stdout.trim() : undefined;
3020
3172
  };
3173
+ var validatePhysicalIosDevice = (project, identifier, capture) => {
3174
+ const result = capture([
3175
+ project.xcrun,
3176
+ "devicectl",
3177
+ "device",
3178
+ "info",
3179
+ "details",
3180
+ "--device",
3181
+ identifier
3182
+ ]);
3183
+ if (result.exitCode !== 0)
3184
+ throw new Error(`Physical iOS device ${JSON.stringify(identifier)} is unavailable: ${result.stderr.trim() || result.stdout.trim() || "pair it in Xcode Device Hub, trust this Mac, unlock it, and enable Developer Mode."}`);
3185
+ };
3186
+ var physicalIosAppIsInstalled = (project, identifier, capture) => {
3187
+ const result = capture([
3188
+ project.xcrun,
3189
+ "devicectl",
3190
+ "device",
3191
+ "info",
3192
+ "apps",
3193
+ "--device",
3194
+ identifier
3195
+ ]);
3196
+ return result.exitCode === 0 && result.stdout.includes(project.config.appId);
3197
+ };
3021
3198
  var buildIosDebugApp = async (project, udid, fingerprint, run, signal) => {
3022
3199
  const derivedDataPath = join6(project.projectRoot, ".absolutejs", "mobile", "ios-derived-data", createHash6("sha256").update(project.config.appId).digest("hex").slice(0, 16));
3023
3200
  await mkdir5(derivedDataPath, { recursive: true });
@@ -3040,6 +3217,61 @@ var buildIosDebugApp = async (project, udid, fingerprint, run, signal) => {
3040
3217
  throw new Error(`Xcode did not produce the simulator app at ${appPath}.`);
3041
3218
  return appPath;
3042
3219
  };
3220
+ var buildPhysicalIosDebugApp = async (project, identifier, run, signal) => {
3221
+ const derivedDataPath = join6(project.projectRoot, ".absolutejs", "mobile", "ios-derived-data", createHash6("sha256").update(project.config.appId).digest("hex").slice(0, 16));
3222
+ await mkdir5(derivedDataPath, { recursive: true });
3223
+ await requireSuccess2([
3224
+ project.xcodebuild,
3225
+ "-workspace",
3226
+ join6(project.nativeDirectory, "App", "App.xcworkspace"),
3227
+ "-scheme",
3228
+ "App",
3229
+ "-configuration",
3230
+ "Debug",
3231
+ "-destination",
3232
+ `platform=iOS,id=${identifier}`,
3233
+ "-derivedDataPath",
3234
+ derivedDataPath,
3235
+ "-allowProvisioningUpdates",
3236
+ "build"
3237
+ ], "iOS physical-device build (configure automatic signing and a Development Team in Xcode if this is the first run)", run, { cwd: project.nativeDirectory, signal });
3238
+ const appPath = join6(derivedDataPath, "Build", "Products", "Debug-iphoneos", "App.app");
3239
+ if (!await pathExists5(appPath))
3240
+ throw new Error(`Xcode did not produce the physical-device app at ${appPath}.`);
3241
+ return appPath;
3242
+ };
3243
+ var ensurePhysicalIosDebugApp = async (options) => {
3244
+ const cacheHit = options.cache?.appId === options.project.config.appId && options.cache.fingerprint === options.fingerprint && options.cache.installations[options.identifier] === options.fingerprint && physicalIosAppIsInstalled(options.project, options.identifier, options.capture);
3245
+ if (cacheHit) {
3246
+ options.log(`iOS native app is unchanged on the selected physical device; skipped Xcode build and install.`);
3247
+ return true;
3248
+ }
3249
+ options.log("iOS native inputs changed or the physical-device install is stale; rebuilding.");
3250
+ options.transition("building");
3251
+ const appPath = await buildPhysicalIosDebugApp(options.project, options.identifier, options.run, options.signal);
3252
+ throwIfAborted2(options.signal);
3253
+ options.transition("installing");
3254
+ await requireSuccess2([
3255
+ options.project.xcrun,
3256
+ "devicectl",
3257
+ "device",
3258
+ "install",
3259
+ "app",
3260
+ "--device",
3261
+ options.identifier,
3262
+ appPath
3263
+ ], "iOS physical-device app installation", options.run, { signal: options.signal });
3264
+ await writeNativeCache(options.project.projectRoot, {
3265
+ appId: options.project.config.appId,
3266
+ fingerprint: options.fingerprint,
3267
+ format: NATIVE_CACHE_FORMAT,
3268
+ installations: {
3269
+ ...options.cache?.appId === options.project.config.appId ? options.cache.installations : {},
3270
+ [options.identifier]: options.fingerprint
3271
+ }
3272
+ }).catch((error) => options.log(`iOS native cache could not be saved: ${error instanceof Error ? error.message : String(error)}`));
3273
+ return false;
3274
+ };
3043
3275
  var ensureIosDebugApp = async (options) => {
3044
3276
  const installed = installedAppIdentity(options.project, options.udid, options.capture);
3045
3277
  const cacheHit = options.cache?.appId === options.project.config.appId && options.cache.fingerprint === options.fingerprint && installed !== undefined && options.cache.installations[options.udid] === installed;
@@ -3086,7 +3318,18 @@ var attachNativeLogs = (project, udid, options) => {
3086
3318
  if (!options.nativeLog)
3087
3319
  return null;
3088
3320
  const start = options.startNativeLogs ?? defaultStartNativeLogs;
3089
- return start([
3321
+ const command = options.deviceIdentifier ? [
3322
+ project.xcrun,
3323
+ "devicectl",
3324
+ "device",
3325
+ "process",
3326
+ "launch",
3327
+ "--console",
3328
+ "--terminate-existing",
3329
+ "--device",
3330
+ udid,
3331
+ project.config.appId
3332
+ ] : [
3090
3333
  project.xcrun,
3091
3334
  "simctl",
3092
3335
  "spawn",
@@ -3099,7 +3342,8 @@ var attachNativeLogs = (project, udid, options) => {
3099
3342
  "debug",
3100
3343
  "--predicate",
3101
3344
  'process == "App"'
3102
- ], { signal: options.signal }, (line) => {
3345
+ ];
3346
+ return start(command, { signal: options.signal }, (line) => {
3103
3347
  const entry = parseAbsoluteIosLogLine(line);
3104
3348
  if (entry)
3105
3349
  options.nativeLog?.(entry);
@@ -3111,6 +3355,7 @@ var IOS_TIMING_PHASES = [
3111
3355
  ["fingerprinting", "fingerprint"],
3112
3356
  ["booting", "simulator"],
3113
3357
  ["connecting", "device ready"],
3358
+ ["enrolling-trust", "HTTPS trust"],
3114
3359
  ["checking-native", "app check"],
3115
3360
  ["building", "Xcode"],
3116
3361
  ["installing", "install"],
@@ -3123,12 +3368,13 @@ var timingSummary = (timings) => IOS_TIMING_PHASES.map(([phase, label]) => {
3123
3368
  }).filter((value) => value !== null).join(", ");
3124
3369
  var prepareAbsoluteIosDevProject = async (config, options) => {
3125
3370
  if (detectAbsoluteMobileHost() !== "macos")
3126
- throw new Error("iOS simulation requires macOS and Xcode.");
3371
+ throw new Error("iOS development requires macOS and Xcode.");
3372
+ const target = options.target ?? "simulator";
3127
3373
  const projectRoot = resolve5(options.projectRoot);
3128
3374
  const checks = await inspectAbsoluteMobileToolchain({ host: "macos" });
3129
- const failed = checks.filter((check) => check.platform === "ios" && (check.status === "fail" || check.status === "warn"));
3375
+ const failed = checks.filter((check) => check.platform === "ios" && !(target === "device" && check.id === "ios.runtime") && (check.status === "fail" || check.status === "warn"));
3130
3376
  if (failed.length > 0)
3131
- throw new Error(`iOS simulation is not ready: ${failed.map(({ label }) => label).join(", ")}.`);
3377
+ throw new Error(`iOS ${target} development is not ready: ${failed.map(({ label }) => label).join(", ")}.`);
3132
3378
  const xcrun = checks.find((check) => check.id === "ios.xcrun")?.path;
3133
3379
  const xcodebuild = checks.find((check) => check.id === "ios.xcodebuild")?.path;
3134
3380
  if (!xcrun || !xcodebuild)
@@ -3159,8 +3405,55 @@ var prepareAbsoluteIosDevProject = async (config, options) => {
3159
3405
  xcrun
3160
3406
  };
3161
3407
  };
3408
+ var preparePhysicalIosTarget = async (options) => {
3409
+ options.transition("connecting");
3410
+ validatePhysicalIosDevice(options.project, options.deviceIdentifier, options.capture);
3411
+ if (!options.startOptions.https)
3412
+ return {
3413
+ caEnrollmentServer: null,
3414
+ startedSimulator: false,
3415
+ udid: options.deviceIdentifier
3416
+ };
3417
+ if (!options.startOptions.certificateAuthorityPath)
3418
+ throw new Error("Physical iOS HTTPS development requires the AbsoluteJS development CA certificate.");
3419
+ options.transition("enrolling-trust");
3420
+ const startEnrollment = options.startOptions.startCaEnrollmentServer ?? startAbsoluteIosCaEnrollmentServer;
3421
+ const caEnrollmentServer = await startEnrollment({
3422
+ certificateAuthorityPath: options.startOptions.certificateAuthorityPath,
3423
+ displayHost: options.serverHost
3424
+ });
3425
+ options.log(`On the iOS device, open ${caEnrollmentServer.url}, install the AbsoluteJS development CA profile, then enable it under Settings > General > About > Certificate Trust Settings. This public CA endpoint exists only for this dev session.`);
3426
+ return {
3427
+ caEnrollmentServer,
3428
+ startedSimulator: false,
3429
+ udid: options.deviceIdentifier
3430
+ };
3431
+ };
3432
+ var prepareIosSimulatorTarget = async (options) => {
3433
+ options.transition("booting");
3434
+ const managed = await ensureManagedSimulator(options.project, options.capture);
3435
+ const { device } = managed;
3436
+ const startedSimulator = managed.created || device.state !== "Booted";
3437
+ bootSimulator(options.project, device, options.capture);
3438
+ options.spawn([
3439
+ "open",
3440
+ "-a",
3441
+ "Simulator",
3442
+ "--args",
3443
+ "-CurrentDeviceUDID",
3444
+ device.udid
3445
+ ]);
3446
+ options.transition("connecting");
3447
+ await waitForBootedSimulator(options.project, device.udid, options.capture, options.sleep, options.startOptions.signal);
3448
+ await requireSuccess2([options.project.xcrun, "simctl", "bootstatus", device.udid, "-b"], "iOS simulator boot readiness", options.run, { signal: options.startOptions.signal });
3449
+ await trustIosSimulatorDevelopmentCa(options.startOptions, device.udid, options.run, options.log);
3450
+ return { caEnrollmentServer: null, startedSimulator, udid: device.udid };
3451
+ };
3162
3452
  var startAbsoluteIosDevSession = async (options) => {
3163
3453
  const { project } = options;
3454
+ const deviceIdentifier = options.deviceIdentifier ? normalizeAbsoluteIosDeviceIdentifier(options.deviceIdentifier) : undefined;
3455
+ const targetKind = deviceIdentifier ? "device" : "simulator";
3456
+ const serverHost = deviceIdentifier ? normalizeAbsoluteIosDeviceHost(options.serverHost ?? "") : "localhost";
3164
3457
  const capture = options.capture ?? defaultCapture3;
3165
3458
  const run = options.run ?? defaultRun2;
3166
3459
  const sleep = options.sleep ?? Bun.sleep;
@@ -3188,6 +3481,7 @@ var startAbsoluteIosDevSession = async (options) => {
3188
3481
  options.onStateChange?.(next);
3189
3482
  };
3190
3483
  let nativeLogs = null;
3484
+ let caEnrollmentServer = null;
3191
3485
  const closeLogs = async () => {
3192
3486
  const stream = nativeLogs;
3193
3487
  nativeLogs = null;
@@ -3195,38 +3489,66 @@ var startAbsoluteIosDevSession = async (options) => {
3195
3489
  return;
3196
3490
  });
3197
3491
  };
3492
+ const relaunchTarget = async (udid) => {
3493
+ if (deviceIdentifier && options.nativeLog) {
3494
+ await closeLogs();
3495
+ nativeLogs = attachNativeLogs(project, udid, options);
3496
+ return;
3497
+ }
3498
+ await requireSuccess2(iosLaunchCommand(project, udid, deviceIdentifier !== undefined), "iOS app relaunch", run, { signal: options.signal });
3499
+ };
3198
3500
  try {
3199
3501
  await repairAbsoluteIosDevSession(project.projectRoot);
3200
3502
  throwIfAborted2(options.signal);
3201
3503
  transition("syncing");
3202
3504
  await requireSuccess2([project.cap, "sync", "ios"], "Capacitor iOS synchronization", run, { cwd: project.projectRoot, signal: options.signal });
3203
3505
  transition("configuring");
3204
- await writeDevProjection(project, options.port, options.https === true);
3506
+ await writeDevProjection(project, options.port, options.https === true, serverHost);
3205
3507
  throwIfAborted2(options.signal);
3206
3508
  const fingerprintStartedAt = performance.now();
3207
3509
  const fingerprintPromise = fingerprintAbsoluteIosDevProject(project).then((fingerprint2) => {
3208
3510
  timings.fingerprinting = performance.now() - fingerprintStartedAt;
3209
3511
  return fingerprint2;
3210
3512
  });
3211
- transition("booting");
3212
- const { created, device } = await ensureManagedSimulator(project, capture);
3213
- const startedSimulator = created || device.state !== "Booted";
3214
- bootSimulator(project, device, capture);
3215
- spawn([
3216
- "open",
3217
- "-a",
3218
- "Simulator",
3219
- "--args",
3220
- "-CurrentDeviceUDID",
3221
- device.udid
3222
- ]);
3223
- transition("connecting");
3224
- await waitForBootedSimulator(project, device.udid, capture, sleep, options.signal);
3225
- await requireSuccess2([project.xcrun, "simctl", "bootstatus", device.udid, "-b"], "iOS simulator boot readiness", run, { signal: options.signal });
3513
+ const target = deviceIdentifier ? await preparePhysicalIosTarget({
3514
+ capture,
3515
+ deviceIdentifier,
3516
+ log,
3517
+ project,
3518
+ serverHost,
3519
+ startOptions: options,
3520
+ transition
3521
+ }) : await prepareIosSimulatorTarget({
3522
+ capture,
3523
+ log,
3524
+ project,
3525
+ run,
3526
+ sleep,
3527
+ spawn,
3528
+ startOptions: options,
3529
+ transition
3530
+ });
3531
+ const {
3532
+ caEnrollmentServer: targetCaEnrollmentServer,
3533
+ startedSimulator,
3534
+ udid
3535
+ } = target;
3536
+ caEnrollmentServer = targetCaEnrollmentServer;
3226
3537
  const fingerprint = await fingerprintPromise;
3227
3538
  transition("checking-native");
3228
- const nativeCacheHit = await ensureIosDebugApp({
3229
- cache: await readNativeCache(project.projectRoot),
3539
+ const cache = await readNativeCache(project.projectRoot);
3540
+ const nativeCacheHit = deviceIdentifier ? await ensurePhysicalIosDebugApp({
3541
+ cache,
3542
+ capture,
3543
+ fingerprint,
3544
+ identifier: deviceIdentifier,
3545
+ log,
3546
+ project,
3547
+ run,
3548
+ signal: options.signal,
3549
+ transition
3550
+ }) : await ensureIosDebugApp({
3551
+ cache,
3230
3552
  capture,
3231
3553
  fingerprint,
3232
3554
  log,
@@ -3234,24 +3556,18 @@ var startAbsoluteIosDevSession = async (options) => {
3234
3556
  run,
3235
3557
  signal: options.signal,
3236
3558
  transition,
3237
- udid: device.udid
3559
+ udid
3238
3560
  });
3239
3561
  throwIfAborted2(options.signal);
3240
3562
  if (options.nativeLog)
3241
3563
  transition("streaming-logs");
3242
- nativeLogs = attachNativeLogs(project, device.udid, options);
3564
+ nativeLogs = attachNativeLogs(project, udid, options);
3243
3565
  transition("launching");
3244
- await requireSuccess2([
3245
- project.xcrun,
3246
- "simctl",
3247
- "launch",
3248
- "--terminate-running-process",
3249
- device.udid,
3250
- project.config.appId
3251
- ], "iOS app launch", run, { signal: options.signal });
3566
+ if (!deviceIdentifier || !nativeLogs)
3567
+ await requireSuccess2(iosLaunchCommand(project, udid, deviceIdentifier !== undefined), "iOS app launch", run, { signal: options.signal });
3252
3568
  transition("ready");
3253
3569
  timings.total = performance.now() - startedAt;
3254
- log(`iOS simulator connected (${device.udid}) with HMR on port ${options.port} in ${getDurationString(timings.total)} (${nativeCacheHit ? "native cache hit" : "native build installed"}).`);
3570
+ log(`iOS ${targetKind} connected with HMR on port ${options.port} in ${getDurationString(timings.total)} (${nativeCacheHit ? "native cache hit" : "native build installed"}).`);
3255
3571
  log(`iOS startup: ${timingSummary(timings)}.`);
3256
3572
  let closed = false;
3257
3573
  const close = async () => {
@@ -3260,6 +3576,10 @@ var startAbsoluteIosDevSession = async (options) => {
3260
3576
  closed = true;
3261
3577
  transition("closing");
3262
3578
  await closeLogs();
3579
+ await caEnrollmentServer?.close().catch(() => {
3580
+ return;
3581
+ });
3582
+ caEnrollmentServer = null;
3263
3583
  await repairAbsoluteIosDevSession(project.projectRoot);
3264
3584
  transition("closed");
3265
3585
  };
@@ -3267,8 +3587,9 @@ var startAbsoluteIosDevSession = async (options) => {
3267
3587
  close,
3268
3588
  nativeCacheHit,
3269
3589
  startedSimulator,
3590
+ targetKind,
3270
3591
  timings: { ...timings },
3271
- udid: device.udid,
3592
+ udid,
3272
3593
  rebuild: async () => {
3273
3594
  if (closed)
3274
3595
  throw new Error("iOS development session is closed.");
@@ -3281,22 +3602,17 @@ var startAbsoluteIosDevSession = async (options) => {
3281
3602
  throw new Error("iOS development session is closed.");
3282
3603
  transition("launching");
3283
3604
  try {
3284
- await requireSuccess2([
3285
- project.xcrun,
3286
- "simctl",
3287
- "launch",
3288
- "--terminate-running-process",
3289
- device.udid,
3290
- project.config.appId
3291
- ], "iOS app relaunch", run, { signal: options.signal });
3605
+ await relaunchTarget(udid);
3292
3606
  transition("ready");
3293
- log(`iOS app relaunched on ${device.udid}.`);
3607
+ log(`iOS app relaunched on the selected ${targetKind}.`);
3294
3608
  } catch (error) {
3295
3609
  transition("failed");
3296
3610
  throw error;
3297
3611
  }
3298
3612
  },
3299
3613
  screenshot: async (destination) => {
3614
+ if (deviceIdentifier)
3615
+ throw new Error("Physical iOS screenshots are captured in Xcode Device Hub; the CLI never records a device screen automatically.");
3300
3616
  const resolved = resolve5(project.projectRoot, destination);
3301
3617
  if (!isInside(project.projectRoot, resolved))
3302
3618
  throw new Error("iOS screenshot destination must remain inside the project.");
@@ -3305,7 +3621,7 @@ var startAbsoluteIosDevSession = async (options) => {
3305
3621
  project.xcrun,
3306
3622
  "simctl",
3307
3623
  "io",
3308
- device.udid,
3624
+ udid,
3309
3625
  "screenshot",
3310
3626
  resolved
3311
3627
  ], "iOS simulator screenshot", run, { signal: options.signal });
@@ -3318,6 +3634,9 @@ var startAbsoluteIosDevSession = async (options) => {
3318
3634
  } catch (error) {
3319
3635
  transition("failed");
3320
3636
  await closeLogs();
3637
+ await caEnrollmentServer?.close().catch(() => {
3638
+ return;
3639
+ });
3321
3640
  await repairAbsoluteIosDevSession(project.projectRoot);
3322
3641
  throw error;
3323
3642
  }
@@ -3416,9 +3735,10 @@ var createAbsoluteIosNativeWatcher = async (options) => {
3416
3735
  };
3417
3736
  var isAbsoluteIosNativeRootInput = (path) => ROOT_NATIVE_INPUTS.has(basename(path));
3418
3737
  // src/mobile/remoteMacProtocol.ts
3419
- import { createHash as createHash7, randomUUID as randomUUID3 } from "crypto";
3420
- import { chmod, mkdir as mkdir6, readFile as readFile8, rename as rename7, writeFile as writeFile7 } from "fs/promises";
3738
+ import { createHash as createHash7, randomUUID as randomUUID4 } from "crypto";
3739
+ import { chmod, mkdir as mkdir6, readFile as readFile9, rename as rename7, writeFile as writeFile7 } from "fs/promises";
3421
3740
  import { homedir as homedir2 } from "os";
3741
+ import { isIP as isIP3 } from "net";
3422
3742
  import {
3423
3743
  dirname as dirname5,
3424
3744
  isAbsolute as isAbsolute5,
@@ -3445,7 +3765,7 @@ var emptyStore = () => ({
3445
3765
  });
3446
3766
  var loadStore = async (path = defaultProfilePath()) => {
3447
3767
  try {
3448
- const parsed = JSON.parse(await readFile8(path, "utf8"));
3768
+ const parsed = JSON.parse(await readFile9(path, "utf8"));
3449
3769
  if (parsed.format !== PROFILE_FORMAT || typeof parsed.profiles !== "object" || parsed.profiles === null || Array.isArray(parsed.profiles))
3450
3770
  throw new Error("Unsupported remote Mac profile format.");
3451
3771
  for (const [key, profile] of Object.entries(parsed.profiles)) {
@@ -3463,7 +3783,7 @@ var loadStore = async (path = defaultProfilePath()) => {
3463
3783
  };
3464
3784
  var saveStore = async (store, path = defaultProfilePath()) => {
3465
3785
  await mkdir6(dirname5(path), { recursive: true });
3466
- const temporary = `${path}.${randomUUID3()}.tmp`;
3786
+ const temporary = `${path}.${randomUUID4()}.tmp`;
3467
3787
  await writeFile7(temporary, `${JSON.stringify(store, null, 2)}
3468
3788
  `, {
3469
3789
  mode: 384
@@ -3564,6 +3884,19 @@ var inspectAbsoluteRemoteMac = async (destination, options = {}) => {
3564
3884
  throw new Error("The remote Mac must have full Xcode installed and selected.");
3565
3885
  return { bunPath, home, os: operatingSystem, xcodeVersion };
3566
3886
  };
3887
+ var inspectAbsoluteRemoteMacLanHost = async (profile, transport) => {
3888
+ const capture = transport?.capture ?? defaultTransport.capture;
3889
+ const script = `default_interface="$(/sbin/route -n get default 2>/dev/null | /usr/bin/awk '/interface:/{print $2; exit}')"; for interface in "$default_interface" en0 en1; do [ -n "$interface" ] || continue; address="$(/usr/sbin/ipconfig getifaddr "$interface" 2>/dev/null || true)"; if [ -n "$address" ]; then printf '%s\\n' "$address"; exit 0; fi; done; exit 1`;
3890
+ const result = await capture([
3891
+ ...absoluteRemoteMacSshBase(profile),
3892
+ "/bin/sh -lc",
3893
+ shellQuote(script)
3894
+ ]);
3895
+ const host = requireRemoteSuccess(result, "Remote Mac LAN address discovery").trim();
3896
+ if (isIP3(host) === 0)
3897
+ throw new Error("The Remote Mac did not report a device-reachable LAN address.");
3898
+ return host;
3899
+ };
3567
3900
  var listAbsoluteRemoteMacProfiles = async (profilePath) => {
3568
3901
  const store = await loadStore(profilePath);
3569
3902
  return {
@@ -3635,7 +3968,7 @@ var installAbsoluteRemoteMacAgent = async (project) => {
3635
3968
  ]);
3636
3969
  if (verified.exitCode === 0)
3637
3970
  return { ...artifact, remotePath, uploaded: false };
3638
- const temporary = posix.join(directory, `.agent-${randomUUID3()}.tmp`);
3971
+ const temporary = posix.join(directory, `.agent-${randomUUID4()}.tmp`);
3639
3972
  const installScript = [
3640
3973
  "set -eu",
3641
3974
  "umask 077",
@@ -3726,7 +4059,7 @@ var portableMobileConfig = (project) => ({
3726
4059
  var absoluteRemoteProjectSyncCommands = (project) => {
3727
4060
  const current = project.remoteProjectRoot;
3728
4061
  const parent = posix.dirname(current);
3729
- const staging = posix.join(parent, `.incoming-${randomUUID3()}`);
4062
+ const staging = posix.join(parent, `.incoming-${randomUUID4()}`);
3730
4063
  const previous = posix.join(parent, ".previous");
3731
4064
  const script = [
3732
4065
  "set -eu",
@@ -3818,6 +4151,13 @@ var startAbsoluteRemoteIosDevSession = async (options) => {
3818
4151
  await syncProject(options.project);
3819
4152
  const syncDuration = performance.now() - syncStartedAt;
3820
4153
  const encodedConfig = Buffer.from(JSON.stringify(portableMobileConfig(options.project))).toString("base64url");
4154
+ const encodedCertificateAuthority = options.certificateAuthorityPath ? (await readFile9(options.certificateAuthorityPath)).toString("base64url") : undefined;
4155
+ const physicalDevice = options.deviceIdentifier !== undefined;
4156
+ let relayPort;
4157
+ if (physicalDevice)
4158
+ relayPort = options.port <= 49151 ? options.port + 16384 : options.port - 16384;
4159
+ if (physicalDevice && !options.serverHost)
4160
+ throw new Error("Remote physical iOS development requires the Remote Mac LAN host.");
3821
4161
  const remoteCommand = [
3822
4162
  `cd ${shellQuote(options.project.remoteProjectRoot)}`,
3823
4163
  "&&",
@@ -3828,14 +4168,26 @@ var startAbsoluteRemoteIosDevSession = async (options) => {
3828
4168
  String(options.port),
3829
4169
  "--mobile-config",
3830
4170
  shellQuote(encodedConfig),
3831
- ...options.https ? ["--https"] : []
4171
+ ...encodedCertificateAuthority ? [
4172
+ "--certificate-authority",
4173
+ shellQuote(encodedCertificateAuthority)
4174
+ ] : [],
4175
+ ...options.https ? ["--https"] : [],
4176
+ ...options.deviceIdentifier ? [
4177
+ "--ios-device",
4178
+ shellQuote(options.deviceIdentifier),
4179
+ "--server-host",
4180
+ shellQuote(options.serverHost ?? ""),
4181
+ "--relay-port",
4182
+ String(relayPort)
4183
+ ] : []
3832
4184
  ].join(" ");
3833
4185
  const command = [
3834
4186
  ...absoluteRemoteMacSshBase(options.project.profile),
3835
4187
  "-o",
3836
4188
  "ExitOnForwardFailure=yes",
3837
4189
  "-R",
3838
- `${options.port}:127.0.0.1:${options.port}`,
4190
+ physicalDevice ? `127.0.0.1:${relayPort}:127.0.0.1:${options.port}` : `${options.port}:127.0.0.1:${options.port}`,
3839
4191
  "/bin/sh -lc",
3840
4192
  shellQuote(remoteCommand)
3841
4193
  ];
@@ -3923,7 +4275,7 @@ var startAbsoluteRemoteIosDevSession = async (options) => {
3923
4275
  };
3924
4276
  options.log?.(`Remote Mac connected (${options.project.profile.name}); agent ${agent.uploaded ? "uploaded" : "cache hit"}, project synced, and iOS ready in ${totalDuration.toFixed(2)}ms.`);
3925
4277
  const request = (commandName) => {
3926
- const id = randomUUID3();
4278
+ const id = randomUUID4();
3927
4279
  const response = new Promise((resolve6, reject) => pending.set(id, { reject, resolve: resolve6 }));
3928
4280
  process2.stdin.write(`${JSON.stringify({ command: commandName, id, v: 1 })}
3929
4281
  `);
@@ -3956,6 +4308,7 @@ var startAbsoluteRemoteIosDevSession = async (options) => {
3956
4308
  close,
3957
4309
  nativeCacheHit: currentReady.nativeCacheHit,
3958
4310
  startedSimulator: currentReady.startedSimulator,
4311
+ targetKind: currentReady.targetKind,
3959
4312
  timings: currentReady.timings,
3960
4313
  udid: currentReady.udid,
3961
4314
  rebuild: async () => {
@@ -3997,7 +4350,7 @@ var startAbsoluteRemoteIosDevSession = async (options) => {
3997
4350
  import {
3998
4351
  access as access7,
3999
4352
  mkdir as mkdir7,
4000
- readFile as readFile9,
4353
+ readFile as readFile10,
4001
4354
  rename as rename8,
4002
4355
  rm as rm6,
4003
4356
  writeFile as writeFile8
@@ -4203,7 +4556,7 @@ var createAbsoluteMobileAssociationPlugin = (mobile, projectRoot, options = {})
4203
4556
  var writeAtomic = async (path, source) => {
4204
4557
  let current;
4205
4558
  try {
4206
- current = await readFile9(path, "utf8");
4559
+ current = await readFile10(path, "utf8");
4207
4560
  } catch (error) {
4208
4561
  if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
4209
4562
  throw error;
@@ -4228,7 +4581,7 @@ var assertOwnedOutput = async (root) => {
4228
4581
  const path = resolve7(root, OWNERSHIP_FILE);
4229
4582
  let ownership;
4230
4583
  try {
4231
- ownership = JSON.parse(await readFile9(path, "utf8"));
4584
+ ownership = JSON.parse(await readFile10(path, "utf8"));
4232
4585
  } catch {
4233
4586
  throw new TypeError(`Association output ${root} already exists and is not owned by AbsoluteJS.`);
4234
4587
  }
@@ -4364,13 +4717,13 @@ var parseAbsoluteMobileBuildPageMetadata = (value) => {
4364
4717
  };
4365
4718
  };
4366
4719
  // src/mobile/buildPipeline.ts
4367
- import { readFile as readFile13 } from "fs/promises";
4720
+ import { readFile as readFile14 } from "fs/promises";
4368
4721
  import { join as join14, resolve as resolve12 } from "path";
4369
4722
  import { pathToFileURL as pathToFileURL2 } from "url";
4370
4723
 
4371
4724
  // src/mobile/buildRelease.ts
4372
4725
  import { createHash as createHash8 } from "crypto";
4373
- import { mkdir as mkdir8, readFile as readFile10, writeFile as writeFile9 } from "fs/promises";
4726
+ import { mkdir as mkdir8, readFile as readFile11, writeFile as writeFile9 } from "fs/promises";
4374
4727
  import { basename as basename2, dirname as dirname6, extname, join as join8, relative as relative7, resolve as resolve8 } from "path";
4375
4728
  var sha256 = (bytes) => createHash8("sha256").update(bytes).digest("hex");
4376
4729
  var STATIC_SCRIPT_PATTERN = /(<script\b[^>]*?\bsrc\s*=\s*["'])(\/[^"']+\.(?:js|ts))(["'][^>]*>)/giu;
@@ -4397,7 +4750,7 @@ var pageFor = async (metadata, manifest, buildDirectory) => {
4397
4750
  }
4398
4751
  let resolvedAssetPath = resolveAssetPath(buildDirectory, assetPath);
4399
4752
  if (metadata.framework === "html" || metadata.framework === "htmx") {
4400
- const source = await readFile10(resolvedAssetPath, "utf8");
4753
+ const source = await readFile11(resolvedAssetPath, "utf8");
4401
4754
  const rewritten = rewriteStaticScriptPaths(source, manifest);
4402
4755
  const documentHash = sha256(new TextEncoder().encode(rewritten));
4403
4756
  resolvedAssetPath = join8(buildDirectory, ".absolutejs", "mobile-pages", `${documentHash}.html`);
@@ -4411,8 +4764,8 @@ var pageFor = async (metadata, manifest, buildDirectory) => {
4411
4764
  ].map((key) => manifest[key]).find((path) => typeof path === "string");
4412
4765
  const resolvedStylePath = styleAssetPath ? resolveAssetPath(buildDirectory, styleAssetPath) : undefined;
4413
4766
  const [bytes, styleBytes] = await Promise.all([
4414
- readFile10(resolvedAssetPath),
4415
- resolvedStylePath ? readFile10(resolvedStylePath) : undefined
4767
+ readFile11(resolvedAssetPath),
4768
+ resolvedStylePath ? readFile11(resolvedStylePath) : undefined
4416
4769
  ]);
4417
4770
  const bundlePath = `/${relative7(resolve8(buildDirectory), resolvedAssetPath).replaceAll("\\", "/")}`;
4418
4771
  const styleBundlePath = resolvedStylePath ? `/${relative7(resolve8(buildDirectory), resolvedStylePath).replaceAll("\\", "/")}` : undefined;
@@ -4432,7 +4785,7 @@ var pageFor = async (metadata, manifest, buildDirectory) => {
4432
4785
  var buildAbsoluteMobileCompatibilityRelease = async (options) => {
4433
4786
  const [captured, producerBytes] = await Promise.all([
4434
4787
  captureAbsoluteMobileRouteGraph(options.app),
4435
- readFile10(options.producerPath)
4788
+ readFile11(options.producerPath)
4436
4789
  ]);
4437
4790
  if (captured.length === 0) {
4438
4791
  throw new TypeError("No instrumented AbsoluteJS mobile page routes were found in the finalized Elysia route graph.");
@@ -4524,7 +4877,7 @@ import {
4524
4877
  copyFile as copyFile5,
4525
4878
  mkdir as mkdir9,
4526
4879
  mkdtemp as mkdtemp4,
4527
- readFile as readFile11,
4880
+ readFile as readFile12,
4528
4881
  rename as rename9,
4529
4882
  rm as rm7,
4530
4883
  writeFile as writeFile10
@@ -5054,7 +5407,7 @@ var resolveProjectImport = async (projectRoot, specifier) => {
5054
5407
  const packageName = specifier.startsWith("@") ? segments.slice(0, 2).join("/") : segments[0] ?? "";
5055
5408
  const subpath = specifier.slice(packageName.length);
5056
5409
  const packageDirectory = join9(resolve9(projectRoot), "node_modules", packageName);
5057
- const manifest = JSON.parse(await readFile11(join9(packageDirectory, "package.json"), "utf8"));
5410
+ const manifest = JSON.parse(await readFile12(join9(packageDirectory, "package.json"), "utf8"));
5058
5411
  const exports = typeof manifest === "object" && manifest !== null ? Reflect.get(manifest, "exports") : undefined;
5059
5412
  const entry = typeof exports === "object" && exports !== null ? Reflect.get(exports, subpath ? `.${subpath}` : ".") : undefined;
5060
5413
  const target = importEntryTarget(entry);
@@ -5162,7 +5515,7 @@ var copyClientPage = async (page, buildDirectory, staging, copiedDependencies) =
5162
5515
  };
5163
5516
  };
5164
5517
  var absoluteClientImports = async (sourcePath, buildDirectory) => {
5165
- const source = await readFile11(sourcePath, "utf8");
5518
+ const source = await readFile12(sourcePath, "utf8");
5166
5519
  const extension = extname2(sourcePath).toLowerCase();
5167
5520
  let scriptLoader;
5168
5521
  if (extension === ".tsx")
@@ -5273,7 +5626,7 @@ import {
5273
5626
  access as access8,
5274
5627
  mkdir as mkdir10,
5275
5628
  mkdtemp as mkdtemp5,
5276
- readFile as readFile12,
5629
+ readFile as readFile13,
5277
5630
  rename as rename10,
5278
5631
  rm as rm8,
5279
5632
  writeFile as writeFile11
@@ -5370,7 +5723,7 @@ var resolveProducerHandler = (loaded, exportName) => {
5370
5723
  };
5371
5724
  var loadAbsoluteMobileMaterializedBundle = async (root) => {
5372
5725
  const resolvedRoot = resolvePath3(root);
5373
- const serialized = await readFile12(join10(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
5726
+ const serialized = await readFile13(join10(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
5374
5727
  const parsed = JSON.parse(serialized);
5375
5728
  const index = parseBundleIndex(parsed);
5376
5729
  const bundleRoot = join10(resolvedRoot, BUNDLES_DIRECTORY, index.bundleId);
@@ -5425,7 +5778,7 @@ var materializeAbsoluteMobileCompatibilityBundle = async (input) => {
5425
5778
  var readAbsoluteMobileMaterializedReleases = async (root) => {
5426
5779
  const resolvedRoot = resolvePath3(root);
5427
5780
  try {
5428
- const serialized = await readFile12(join10(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
5781
+ const serialized = await readFile13(join10(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
5429
5782
  const parsed = JSON.parse(serialized);
5430
5783
  const index = parseBundleIndex(parsed);
5431
5784
  const bundleRoot = join10(resolvedRoot, BUNDLES_DIRECTORY, index.bundleId);
@@ -5536,7 +5889,7 @@ var finalizeAbsoluteMobileCompatibilityBuild = async (options) => {
5536
5889
  const mobile = normalizeAbsoluteMobileConfig(options.mobile, options.projectRoot);
5537
5890
  const root = join14(buildDirectory, ".absolutejs", "mobile-compatibility");
5538
5891
  const [manifestSource, previous] = await Promise.all([
5539
- readFile13(join14(buildDirectory, "manifest.json"), "utf8"),
5892
+ readFile14(join14(buildDirectory, "manifest.json"), "utf8"),
5540
5893
  readAbsoluteMobileMaterializedReleases(root)
5541
5894
  ]);
5542
5895
  const manifest = JSON.parse(manifestSource);
@@ -5935,7 +6288,7 @@ var createAbsoluteMobilePreviewPlugin = (mobile) => {
5935
6288
  });
5936
6289
  };
5937
6290
  // src/mobile/nativeDeepLinks.ts
5938
- import { readFile as readFile14, rename as rename11, writeFile as writeFile12 } from "fs/promises";
6291
+ import { readFile as readFile15, rename as rename11, writeFile as writeFile12 } from "fs/promises";
5939
6292
  import { join as join17 } from "path";
5940
6293
  var START_MARKER = "<!-- absolutejs:deep-links:start -->";
5941
6294
  var END_MARKER = "<!-- absolutejs:deep-links:end -->";
@@ -5943,7 +6296,7 @@ var IOS_ENTITLEMENTS = "App/AbsoluteJS.entitlements";
5943
6296
  var NOT_FOUND = -1;
5944
6297
  var escapeXml = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
5945
6298
  var writeChangedFile = async (path, source) => {
5946
- const current = await readFile14(path, "utf8");
6299
+ const current = await readFile15(path, "utf8");
5947
6300
  if (current === source)
5948
6301
  return false;
5949
6302
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
@@ -5994,7 +6347,7 @@ ${hosts}
5994
6347
  };
5995
6348
  var configureAndroid = async (config) => {
5996
6349
  const path = join17(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
5997
- const source = await readFile14(path, "utf8");
6350
+ const source = await readFile15(path, "utf8");
5998
6351
  const mainActivity = source.indexOf('android:name=".MainActivity"');
5999
6352
  if (mainActivity === NOT_FOUND) {
6000
6353
  throw new TypeError("Android MainActivity was not found.");
@@ -6020,7 +6373,7 @@ var iosSchemeRegion = (scheme) => ` ${START_MARKER}
6020
6373
  `;
6021
6374
  var configureIosInfo = async (config) => {
6022
6375
  const path = join17(config.nativeProjectDirectory, "ios/App/App/Info.plist");
6023
- const source = await readFile14(path, "utf8");
6376
+ const source = await readFile15(path, "utf8");
6024
6377
  const region = config.deepLinkScheme ? iosSchemeRegion(config.deepLinkScheme) : ` ${START_MARKER}
6025
6378
  ${END_MARKER}
6026
6379
  `;
@@ -6046,7 +6399,7 @@ var configureIosEntitlements = async (config) => {
6046
6399
  const path = join17(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
6047
6400
  let current = "";
6048
6401
  try {
6049
- current = await readFile14(path, "utf8");
6402
+ current = await readFile15(path, "utf8");
6050
6403
  } catch (error) {
6051
6404
  if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
6052
6405
  throw error;
@@ -6062,7 +6415,7 @@ var configureIosEntitlements = async (config) => {
6062
6415
  };
6063
6416
  var configureIosProject = async (config) => {
6064
6417
  const path = join17(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
6065
- const source = await readFile14(path, "utf8");
6418
+ const source = await readFile15(path, "utf8");
6066
6419
  const declarations = [
6067
6420
  ...source.matchAll(/CODE_SIGN_ENTITLEMENTS = ([^;]+);/g)
6068
6421
  ].map((match) => match[1]);
@@ -6101,7 +6454,7 @@ var applyAbsoluteNativeDeepLinks = async (config, platforms = config.platforms)
6101
6454
  };
6102
6455
  // src/mobile/nativeDeviceCapabilities.ts
6103
6456
  init_deviceCapabilities();
6104
- import { readFile as readFile15, rename as rename12, writeFile as writeFile13 } from "fs/promises";
6457
+ import { readFile as readFile16, rename as rename12, writeFile as writeFile13 } from "fs/promises";
6105
6458
  import { join as join18 } from "path";
6106
6459
  var START_MARKER2 = "<!-- absolutejs:device-capabilities:start -->";
6107
6460
  var END_MARKER2 = "<!-- absolutejs:device-capabilities:end -->";
@@ -6112,7 +6465,7 @@ var PUSH_START_MARKER = "absolutejs:push-notifications:start";
6112
6465
  var PUSH_END_MARKER = "absolutejs:push-notifications:end";
6113
6466
  var escapeXml2 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
6114
6467
  var writeChangedFile2 = async (path, source) => {
6115
- const current = await readFile15(path, "utf8");
6468
+ const current = await readFile16(path, "utf8");
6116
6469
  if (current === source)
6117
6470
  return false;
6118
6471
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
@@ -6132,7 +6485,7 @@ var writeOptionalChangedFile = async (path, source) => {
6132
6485
  };
6133
6486
  var optionalSource = async (path) => {
6134
6487
  try {
6135
- return await readFile15(path, "utf8");
6488
+ return await readFile16(path, "utf8");
6136
6489
  } catch (error) {
6137
6490
  if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "ENOENT")
6138
6491
  return null;
@@ -6253,7 +6606,7 @@ var configureIosPrivacyProject = async (config, requirements) => {
6253
6606
  if (requirements.iosPrivacyAccessedApis.length === 0)
6254
6607
  return false;
6255
6608
  const projectPath = join18(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
6256
- const project = await readFile15(projectPath, "utf8");
6609
+ const project = await readFile16(projectPath, "utf8");
6257
6610
  return writeChangedFile2(projectPath, addIosPrivacyProjectReference(project));
6258
6611
  };
6259
6612
  var addIosPrivacyProjectReference = (source) => {
@@ -6306,7 +6659,7 @@ ${next.slice(index)}`;
6306
6659
  };
6307
6660
  var configureIos2 = async (config, plan) => {
6308
6661
  const path = join18(config.nativeProjectDirectory, "ios/App/App/Info.plist");
6309
- const source = await readFile15(path, "utf8");
6662
+ const source = await readFile16(path, "utf8");
6310
6663
  const requirements = absoluteDeviceNativeRequirements(plan);
6311
6664
  const existingSystemBars = source.match(/<key>UIViewControllerBasedStatusBarAppearance<\/key>\s*<(true|false)\s*\/>/u);
6312
6665
  const ownedStart = source.indexOf(START_MARKER2);
@@ -6399,7 +6752,7 @@ var replacePushRegion = (source, region, insertion) => {
6399
6752
  };
6400
6753
  var configureAndroid2 = async (config, plan) => {
6401
6754
  const path = join18(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
6402
- const source = await readFile15(path, "utf8");
6755
+ const source = await readFile16(path, "utf8");
6403
6756
  const permissions = absoluteDeviceNativeRequirements(plan).androidPermissions;
6404
6757
  const content = permissions.map((permission) => ` <uses-permission android:name="${escapeXml2(permission)}" />`).join(`
6405
6758
  `);
@@ -7288,7 +7641,9 @@ export {
7288
7641
  validateAbsoluteRemoteMacProfileName,
7289
7642
  syncAbsoluteRemoteMacProject,
7290
7643
  startAbsoluteRemoteIosDevSession,
7644
+ startAbsoluteIosTcpRelay,
7291
7645
  startAbsoluteIosDevSession,
7646
+ startAbsoluteIosCaEnrollmentServer,
7292
7647
  serializeAbsoluteMobileAuthEnvironment,
7293
7648
  runWithAbsoluteMobileProducer,
7294
7649
  runAbsoluteAndroidUpgradeConformance,
@@ -7323,6 +7678,8 @@ export {
7323
7678
  parseAbsoluteAndroidInstalledApp,
7324
7679
  pairAbsoluteRemoteMac,
7325
7680
  normalizeAbsoluteMobileConfig,
7681
+ normalizeAbsoluteIosDeviceIdentifier,
7682
+ normalizeAbsoluteIosDeviceHost,
7326
7683
  navigateAbsoluteMobilePage,
7327
7684
  missingAbsoluteDeviceCapabilityPackages,
7328
7685
  materializeAbsoluteRemoteMacAgent,
@@ -7339,6 +7696,7 @@ export {
7339
7696
  installAbsoluteMobileSyncRemediation,
7340
7697
  installAbsoluteMobileShellHttp,
7341
7698
  installAbsoluteMobileAuthEnvironment,
7699
+ inspectAbsoluteRemoteMacLanHost,
7342
7700
  inspectAbsoluteRemoteMac,
7343
7701
  inspectAbsoluteMobileRouteMetadata,
7344
7702
  inspectAbsoluteAndroidInstalledApp,
@@ -7408,5 +7766,5 @@ export {
7408
7766
  ABSOLUTE_ANDROID_RELEASE_FORMAT
7409
7767
  };
7410
7768
 
7411
- //# debugId=A29607482483B57664756E2164756E21
7769
+ //# debugId=ED7CBBBE08CD962364756E2164756E21
7412
7770
  //# sourceMappingURL=index.js.map