@absolutejs/absolute 0.20.0-beta.33 → 0.20.0-beta.35

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;
@@ -2716,6 +2833,24 @@ var trustIosSimulatorDevelopmentCa = async (options, udid, run, log) => {
2716
2833
  ], "iOS Simulator development CA trust", run, { signal: options.signal });
2717
2834
  log("Installed the AbsoluteJS development CA into this iOS Simulator trust store.");
2718
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
+ ];
2719
2854
  var requireCapturedSuccess = (result, label) => {
2720
2855
  if (result.exitCode !== 0) {
2721
2856
  throw new Error(`${label} failed: ${result.stderr.trim() || result.stdout.trim() || `status ${result.exitCode}`}`);
@@ -2853,7 +2988,7 @@ var repairAbsoluteIosDevSession = async (projectRoot) => {
2853
2988
  await rm5(paths.root, { force: true, recursive: true });
2854
2989
  return false;
2855
2990
  }
2856
- 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);
2857
2992
  if (!journal || !isInside(projectRoot, journal.nativeConfigPath) || !isInside(projectRoot, journal.infoPath) || !isInside(paths.root, journal.configBackupPath) || !isInside(paths.root, journal.infoBackupPath)) {
2858
2993
  throw new Error(`Refusing unsafe or invalid iOS dev journal at ${paths.journal}.`);
2859
2994
  }
@@ -2884,14 +3019,14 @@ var iosDevelopmentInfoPlist = (source, cleartext) => {
2884
3019
  <true/>
2885
3020
  </dict>`);
2886
3021
  };
2887
- var writeDevProjection = async (project, port, https) => {
3022
+ var writeDevProjection = async (project, port, https, serverHost = "localhost") => {
2888
3023
  const paths = journalPaths(project.projectRoot);
2889
3024
  await repairAbsoluteIosDevSession(project.projectRoot);
2890
3025
  const nativeConfigPath = join6(project.nativeDirectory, "App", "App", "capacitor.config.json");
2891
3026
  const infoPath = join6(project.nativeDirectory, "App", "App", "Info.plist");
2892
3027
  const [configSource, infoSource] = await Promise.all([
2893
- readFile7(nativeConfigPath, "utf8"),
2894
- readFile7(infoPath, "utf8")
3028
+ readFile8(nativeConfigPath, "utf8"),
3029
+ readFile8(infoPath, "utf8")
2895
3030
  ]);
2896
3031
  const parsed = JSON.parse(configSource);
2897
3032
  if (!isRecord3(parsed))
@@ -2913,6 +3048,7 @@ var writeDevProjection = async (project, port, https) => {
2913
3048
  flag: "wx"
2914
3049
  });
2915
3050
  const developmentUrl = new URL(`${https ? "https" : "http"}://localhost:${port}${project.config.entry}`);
3051
+ developmentUrl.hostname = isIP2(serverHost) === 6 ? `[${serverHost}]` : serverHost;
2916
3052
  developmentUrl.searchParams.set("__absolute_target", "capacitor-ios");
2917
3053
  const existingServer = parsed.server;
2918
3054
  parsed.server = {
@@ -2942,10 +3078,10 @@ var parseNativeCache = (value) => {
2942
3078
  ]))
2943
3079
  };
2944
3080
  };
2945
- 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);
2946
3082
  var writeNativeCache = async (projectRoot, cache) => {
2947
3083
  const destination = nativeCachePath(projectRoot);
2948
- const temporary = `${destination}.${process.pid}.${randomUUID2()}.tmp`;
3084
+ const temporary = `${destination}.${process.pid}.${randomUUID3()}.tmp`;
2949
3085
  await mkdir5(dirname4(destination), { recursive: true });
2950
3086
  try {
2951
3087
  await writeFile6(temporary, `${JSON.stringify(cache, null, "\t")}
@@ -3034,6 +3170,31 @@ var installedAppIdentity = (project, udid, capture) => {
3034
3170
  ]);
3035
3171
  return result.exitCode === 0 && result.stdout.trim() ? result.stdout.trim() : undefined;
3036
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
+ };
3037
3198
  var buildIosDebugApp = async (project, udid, fingerprint, run, signal) => {
3038
3199
  const derivedDataPath = join6(project.projectRoot, ".absolutejs", "mobile", "ios-derived-data", createHash6("sha256").update(project.config.appId).digest("hex").slice(0, 16));
3039
3200
  await mkdir5(derivedDataPath, { recursive: true });
@@ -3056,6 +3217,61 @@ var buildIosDebugApp = async (project, udid, fingerprint, run, signal) => {
3056
3217
  throw new Error(`Xcode did not produce the simulator app at ${appPath}.`);
3057
3218
  return appPath;
3058
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
+ };
3059
3275
  var ensureIosDebugApp = async (options) => {
3060
3276
  const installed = installedAppIdentity(options.project, options.udid, options.capture);
3061
3277
  const cacheHit = options.cache?.appId === options.project.config.appId && options.cache.fingerprint === options.fingerprint && installed !== undefined && options.cache.installations[options.udid] === installed;
@@ -3102,7 +3318,18 @@ var attachNativeLogs = (project, udid, options) => {
3102
3318
  if (!options.nativeLog)
3103
3319
  return null;
3104
3320
  const start = options.startNativeLogs ?? defaultStartNativeLogs;
3105
- 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
+ ] : [
3106
3333
  project.xcrun,
3107
3334
  "simctl",
3108
3335
  "spawn",
@@ -3115,7 +3342,8 @@ var attachNativeLogs = (project, udid, options) => {
3115
3342
  "debug",
3116
3343
  "--predicate",
3117
3344
  'process == "App"'
3118
- ], { signal: options.signal }, (line) => {
3345
+ ];
3346
+ return start(command, { signal: options.signal }, (line) => {
3119
3347
  const entry = parseAbsoluteIosLogLine(line);
3120
3348
  if (entry)
3121
3349
  options.nativeLog?.(entry);
@@ -3127,6 +3355,7 @@ var IOS_TIMING_PHASES = [
3127
3355
  ["fingerprinting", "fingerprint"],
3128
3356
  ["booting", "simulator"],
3129
3357
  ["connecting", "device ready"],
3358
+ ["enrolling-trust", "HTTPS trust"],
3130
3359
  ["checking-native", "app check"],
3131
3360
  ["building", "Xcode"],
3132
3361
  ["installing", "install"],
@@ -3139,12 +3368,13 @@ var timingSummary = (timings) => IOS_TIMING_PHASES.map(([phase, label]) => {
3139
3368
  }).filter((value) => value !== null).join(", ");
3140
3369
  var prepareAbsoluteIosDevProject = async (config, options) => {
3141
3370
  if (detectAbsoluteMobileHost() !== "macos")
3142
- 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";
3143
3373
  const projectRoot = resolve5(options.projectRoot);
3144
3374
  const checks = await inspectAbsoluteMobileToolchain({ host: "macos" });
3145
- 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"));
3146
3376
  if (failed.length > 0)
3147
- 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(", ")}.`);
3148
3378
  const xcrun = checks.find((check) => check.id === "ios.xcrun")?.path;
3149
3379
  const xcodebuild = checks.find((check) => check.id === "ios.xcodebuild")?.path;
3150
3380
  if (!xcrun || !xcodebuild)
@@ -3175,8 +3405,55 @@ var prepareAbsoluteIosDevProject = async (config, options) => {
3175
3405
  xcrun
3176
3406
  };
3177
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
+ };
3178
3452
  var startAbsoluteIosDevSession = async (options) => {
3179
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";
3180
3457
  const capture = options.capture ?? defaultCapture3;
3181
3458
  const run = options.run ?? defaultRun2;
3182
3459
  const sleep = options.sleep ?? Bun.sleep;
@@ -3204,6 +3481,7 @@ var startAbsoluteIosDevSession = async (options) => {
3204
3481
  options.onStateChange?.(next);
3205
3482
  };
3206
3483
  let nativeLogs = null;
3484
+ let caEnrollmentServer = null;
3207
3485
  const closeLogs = async () => {
3208
3486
  const stream = nativeLogs;
3209
3487
  nativeLogs = null;
@@ -3211,39 +3489,66 @@ var startAbsoluteIosDevSession = async (options) => {
3211
3489
  return;
3212
3490
  });
3213
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
+ };
3214
3500
  try {
3215
3501
  await repairAbsoluteIosDevSession(project.projectRoot);
3216
3502
  throwIfAborted2(options.signal);
3217
3503
  transition("syncing");
3218
3504
  await requireSuccess2([project.cap, "sync", "ios"], "Capacitor iOS synchronization", run, { cwd: project.projectRoot, signal: options.signal });
3219
3505
  transition("configuring");
3220
- await writeDevProjection(project, options.port, options.https === true);
3506
+ await writeDevProjection(project, options.port, options.https === true, serverHost);
3221
3507
  throwIfAborted2(options.signal);
3222
3508
  const fingerprintStartedAt = performance.now();
3223
3509
  const fingerprintPromise = fingerprintAbsoluteIosDevProject(project).then((fingerprint2) => {
3224
3510
  timings.fingerprinting = performance.now() - fingerprintStartedAt;
3225
3511
  return fingerprint2;
3226
3512
  });
3227
- transition("booting");
3228
- const { created, device } = await ensureManagedSimulator(project, capture);
3229
- const startedSimulator = created || device.state !== "Booted";
3230
- bootSimulator(project, device, capture);
3231
- spawn([
3232
- "open",
3233
- "-a",
3234
- "Simulator",
3235
- "--args",
3236
- "-CurrentDeviceUDID",
3237
- device.udid
3238
- ]);
3239
- transition("connecting");
3240
- await waitForBootedSimulator(project, device.udid, capture, sleep, options.signal);
3241
- await requireSuccess2([project.xcrun, "simctl", "bootstatus", device.udid, "-b"], "iOS simulator boot readiness", run, { signal: options.signal });
3242
- await trustIosSimulatorDevelopmentCa(options, device.udid, run, log);
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;
3243
3537
  const fingerprint = await fingerprintPromise;
3244
3538
  transition("checking-native");
3245
- const nativeCacheHit = await ensureIosDebugApp({
3246
- 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,
3247
3552
  capture,
3248
3553
  fingerprint,
3249
3554
  log,
@@ -3251,24 +3556,18 @@ var startAbsoluteIosDevSession = async (options) => {
3251
3556
  run,
3252
3557
  signal: options.signal,
3253
3558
  transition,
3254
- udid: device.udid
3559
+ udid
3255
3560
  });
3256
3561
  throwIfAborted2(options.signal);
3257
3562
  if (options.nativeLog)
3258
3563
  transition("streaming-logs");
3259
- nativeLogs = attachNativeLogs(project, device.udid, options);
3564
+ nativeLogs = attachNativeLogs(project, udid, options);
3260
3565
  transition("launching");
3261
- await requireSuccess2([
3262
- project.xcrun,
3263
- "simctl",
3264
- "launch",
3265
- "--terminate-running-process",
3266
- device.udid,
3267
- project.config.appId
3268
- ], "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 });
3269
3568
  transition("ready");
3270
3569
  timings.total = performance.now() - startedAt;
3271
- 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"}).`);
3272
3571
  log(`iOS startup: ${timingSummary(timings)}.`);
3273
3572
  let closed = false;
3274
3573
  const close = async () => {
@@ -3277,6 +3576,10 @@ var startAbsoluteIosDevSession = async (options) => {
3277
3576
  closed = true;
3278
3577
  transition("closing");
3279
3578
  await closeLogs();
3579
+ await caEnrollmentServer?.close().catch(() => {
3580
+ return;
3581
+ });
3582
+ caEnrollmentServer = null;
3280
3583
  await repairAbsoluteIosDevSession(project.projectRoot);
3281
3584
  transition("closed");
3282
3585
  };
@@ -3284,8 +3587,9 @@ var startAbsoluteIosDevSession = async (options) => {
3284
3587
  close,
3285
3588
  nativeCacheHit,
3286
3589
  startedSimulator,
3590
+ targetKind,
3287
3591
  timings: { ...timings },
3288
- udid: device.udid,
3592
+ udid,
3289
3593
  rebuild: async () => {
3290
3594
  if (closed)
3291
3595
  throw new Error("iOS development session is closed.");
@@ -3298,22 +3602,17 @@ var startAbsoluteIosDevSession = async (options) => {
3298
3602
  throw new Error("iOS development session is closed.");
3299
3603
  transition("launching");
3300
3604
  try {
3301
- await requireSuccess2([
3302
- project.xcrun,
3303
- "simctl",
3304
- "launch",
3305
- "--terminate-running-process",
3306
- device.udid,
3307
- project.config.appId
3308
- ], "iOS app relaunch", run, { signal: options.signal });
3605
+ await relaunchTarget(udid);
3309
3606
  transition("ready");
3310
- log(`iOS app relaunched on ${device.udid}.`);
3607
+ log(`iOS app relaunched on the selected ${targetKind}.`);
3311
3608
  } catch (error) {
3312
3609
  transition("failed");
3313
3610
  throw error;
3314
3611
  }
3315
3612
  },
3316
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.");
3317
3616
  const resolved = resolve5(project.projectRoot, destination);
3318
3617
  if (!isInside(project.projectRoot, resolved))
3319
3618
  throw new Error("iOS screenshot destination must remain inside the project.");
@@ -3322,7 +3621,7 @@ var startAbsoluteIosDevSession = async (options) => {
3322
3621
  project.xcrun,
3323
3622
  "simctl",
3324
3623
  "io",
3325
- device.udid,
3624
+ udid,
3326
3625
  "screenshot",
3327
3626
  resolved
3328
3627
  ], "iOS simulator screenshot", run, { signal: options.signal });
@@ -3335,6 +3634,9 @@ var startAbsoluteIosDevSession = async (options) => {
3335
3634
  } catch (error) {
3336
3635
  transition("failed");
3337
3636
  await closeLogs();
3637
+ await caEnrollmentServer?.close().catch(() => {
3638
+ return;
3639
+ });
3338
3640
  await repairAbsoluteIosDevSession(project.projectRoot);
3339
3641
  throw error;
3340
3642
  }
@@ -3433,9 +3735,10 @@ var createAbsoluteIosNativeWatcher = async (options) => {
3433
3735
  };
3434
3736
  var isAbsoluteIosNativeRootInput = (path) => ROOT_NATIVE_INPUTS.has(basename(path));
3435
3737
  // src/mobile/remoteMacProtocol.ts
3436
- import { createHash as createHash7, randomUUID as randomUUID3 } from "crypto";
3437
- 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";
3438
3740
  import { homedir as homedir2 } from "os";
3741
+ import { isIP as isIP3 } from "net";
3439
3742
  import {
3440
3743
  dirname as dirname5,
3441
3744
  isAbsolute as isAbsolute5,
@@ -3462,7 +3765,7 @@ var emptyStore = () => ({
3462
3765
  });
3463
3766
  var loadStore = async (path = defaultProfilePath()) => {
3464
3767
  try {
3465
- const parsed = JSON.parse(await readFile8(path, "utf8"));
3768
+ const parsed = JSON.parse(await readFile9(path, "utf8"));
3466
3769
  if (parsed.format !== PROFILE_FORMAT || typeof parsed.profiles !== "object" || parsed.profiles === null || Array.isArray(parsed.profiles))
3467
3770
  throw new Error("Unsupported remote Mac profile format.");
3468
3771
  for (const [key, profile] of Object.entries(parsed.profiles)) {
@@ -3480,7 +3783,7 @@ var loadStore = async (path = defaultProfilePath()) => {
3480
3783
  };
3481
3784
  var saveStore = async (store, path = defaultProfilePath()) => {
3482
3785
  await mkdir6(dirname5(path), { recursive: true });
3483
- const temporary = `${path}.${randomUUID3()}.tmp`;
3786
+ const temporary = `${path}.${randomUUID4()}.tmp`;
3484
3787
  await writeFile7(temporary, `${JSON.stringify(store, null, 2)}
3485
3788
  `, {
3486
3789
  mode: 384
@@ -3548,6 +3851,18 @@ var requireRemoteSuccess = (result, label) => {
3548
3851
  throw new Error(`${label} failed: ${(result.stderr || result.stdout).trim() || `status ${result.exitCode}`}`);
3549
3852
  return result.stdout.trim();
3550
3853
  };
3854
+ var captureAbsoluteRemoteMacCommand = async (profile, command, transport) => {
3855
+ if (command.length === 0)
3856
+ throw new TypeError("A Remote Mac command cannot be empty.");
3857
+ if (command.some((argument) => /[\r\n\0]/u.test(argument)))
3858
+ throw new TypeError("Remote Mac command arguments cannot contain controls.");
3859
+ const capture = transport?.capture ?? defaultTransport.capture;
3860
+ return capture([
3861
+ ...absoluteRemoteMacSshBase(profile),
3862
+ "/bin/sh -lc",
3863
+ shellQuote(command.map((argument) => shellQuote(argument)).join(" "))
3864
+ ]);
3865
+ };
3551
3866
  var getAbsoluteRemoteMacProfile = async (name, profilePath) => {
3552
3867
  const store = await loadStore(profilePath);
3553
3868
  const selected = name ?? process.env.ABSOLUTE_IOS_REMOTE ?? store.defaultProfile;
@@ -3581,6 +3896,19 @@ var inspectAbsoluteRemoteMac = async (destination, options = {}) => {
3581
3896
  throw new Error("The remote Mac must have full Xcode installed and selected.");
3582
3897
  return { bunPath, home, os: operatingSystem, xcodeVersion };
3583
3898
  };
3899
+ var inspectAbsoluteRemoteMacLanHost = async (profile, transport) => {
3900
+ const capture = transport?.capture ?? defaultTransport.capture;
3901
+ 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`;
3902
+ const result = await capture([
3903
+ ...absoluteRemoteMacSshBase(profile),
3904
+ "/bin/sh -lc",
3905
+ shellQuote(script)
3906
+ ]);
3907
+ const host = requireRemoteSuccess(result, "Remote Mac LAN address discovery").trim();
3908
+ if (isIP3(host) === 0)
3909
+ throw new Error("The Remote Mac did not report a device-reachable LAN address.");
3910
+ return host;
3911
+ };
3584
3912
  var listAbsoluteRemoteMacProfiles = async (profilePath) => {
3585
3913
  const store = await loadStore(profilePath);
3586
3914
  return {
@@ -3652,7 +3980,7 @@ var installAbsoluteRemoteMacAgent = async (project) => {
3652
3980
  ]);
3653
3981
  if (verified.exitCode === 0)
3654
3982
  return { ...artifact, remotePath, uploaded: false };
3655
- const temporary = posix.join(directory, `.agent-${randomUUID3()}.tmp`);
3983
+ const temporary = posix.join(directory, `.agent-${randomUUID4()}.tmp`);
3656
3984
  const installScript = [
3657
3985
  "set -eu",
3658
3986
  "umask 077",
@@ -3743,7 +4071,7 @@ var portableMobileConfig = (project) => ({
3743
4071
  var absoluteRemoteProjectSyncCommands = (project) => {
3744
4072
  const current = project.remoteProjectRoot;
3745
4073
  const parent = posix.dirname(current);
3746
- const staging = posix.join(parent, `.incoming-${randomUUID3()}`);
4074
+ const staging = posix.join(parent, `.incoming-${randomUUID4()}`);
3747
4075
  const previous = posix.join(parent, ".previous");
3748
4076
  const script = [
3749
4077
  "set -eu",
@@ -3835,7 +4163,13 @@ var startAbsoluteRemoteIosDevSession = async (options) => {
3835
4163
  await syncProject(options.project);
3836
4164
  const syncDuration = performance.now() - syncStartedAt;
3837
4165
  const encodedConfig = Buffer.from(JSON.stringify(portableMobileConfig(options.project))).toString("base64url");
3838
- const encodedCertificateAuthority = options.certificateAuthorityPath ? (await readFile8(options.certificateAuthorityPath)).toString("base64url") : undefined;
4166
+ const encodedCertificateAuthority = options.certificateAuthorityPath ? (await readFile9(options.certificateAuthorityPath)).toString("base64url") : undefined;
4167
+ const physicalDevice = options.deviceIdentifier !== undefined;
4168
+ let relayPort;
4169
+ if (physicalDevice)
4170
+ relayPort = options.port <= 49151 ? options.port + 16384 : options.port - 16384;
4171
+ if (physicalDevice && !options.serverHost)
4172
+ throw new Error("Remote physical iOS development requires the Remote Mac LAN host.");
3839
4173
  const remoteCommand = [
3840
4174
  `cd ${shellQuote(options.project.remoteProjectRoot)}`,
3841
4175
  "&&",
@@ -3850,14 +4184,22 @@ var startAbsoluteRemoteIosDevSession = async (options) => {
3850
4184
  "--certificate-authority",
3851
4185
  shellQuote(encodedCertificateAuthority)
3852
4186
  ] : [],
3853
- ...options.https ? ["--https"] : []
4187
+ ...options.https ? ["--https"] : [],
4188
+ ...options.deviceIdentifier ? [
4189
+ "--ios-device",
4190
+ shellQuote(options.deviceIdentifier),
4191
+ "--server-host",
4192
+ shellQuote(options.serverHost ?? ""),
4193
+ "--relay-port",
4194
+ String(relayPort)
4195
+ ] : []
3854
4196
  ].join(" ");
3855
4197
  const command = [
3856
4198
  ...absoluteRemoteMacSshBase(options.project.profile),
3857
4199
  "-o",
3858
4200
  "ExitOnForwardFailure=yes",
3859
4201
  "-R",
3860
- `${options.port}:127.0.0.1:${options.port}`,
4202
+ physicalDevice ? `127.0.0.1:${relayPort}:127.0.0.1:${options.port}` : `${options.port}:127.0.0.1:${options.port}`,
3861
4203
  "/bin/sh -lc",
3862
4204
  shellQuote(remoteCommand)
3863
4205
  ];
@@ -3945,7 +4287,7 @@ var startAbsoluteRemoteIosDevSession = async (options) => {
3945
4287
  };
3946
4288
  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.`);
3947
4289
  const request = (commandName) => {
3948
- const id = randomUUID3();
4290
+ const id = randomUUID4();
3949
4291
  const response = new Promise((resolve6, reject) => pending.set(id, { reject, resolve: resolve6 }));
3950
4292
  process2.stdin.write(`${JSON.stringify({ command: commandName, id, v: 1 })}
3951
4293
  `);
@@ -3978,6 +4320,7 @@ var startAbsoluteRemoteIosDevSession = async (options) => {
3978
4320
  close,
3979
4321
  nativeCacheHit: currentReady.nativeCacheHit,
3980
4322
  startedSimulator: currentReady.startedSimulator,
4323
+ targetKind: currentReady.targetKind,
3981
4324
  timings: currentReady.timings,
3982
4325
  udid: currentReady.udid,
3983
4326
  rebuild: async () => {
@@ -4015,11 +4358,50 @@ var startAbsoluteRemoteIosDevSession = async (options) => {
4015
4358
  });
4016
4359
  return makeSession();
4017
4360
  };
4361
+ // src/mobile/iosDeviceAcceptance.ts
4362
+ var absoluteIosDeviceAcceptanceCommands = (options) => {
4363
+ const xcrun = options.xcrun ?? "/usr/bin/xcrun";
4364
+ const prefix = [xcrun, "devicectl", "device"];
4365
+ return {
4366
+ apps: [...prefix, "info", "apps", "--device", options.device],
4367
+ details: [...prefix, "info", "details", "--device", options.device],
4368
+ launch: [
4369
+ ...prefix,
4370
+ "process",
4371
+ "launch",
4372
+ "--terminate-existing",
4373
+ "--device",
4374
+ options.device,
4375
+ options.appId
4376
+ ]
4377
+ };
4378
+ };
4379
+ var requireSuccess3 = (result, message) => {
4380
+ if (result.exitCode !== 0)
4381
+ throw new Error(message);
4382
+ return result;
4383
+ };
4384
+ var testAbsoluteIosPhysicalDevice = async (options) => {
4385
+ const commands = absoluteIosDeviceAcceptanceCommands(options);
4386
+ requireSuccess3(await options.capture(commands.details), "The selected physical iOS device is unavailable. Pair it in Xcode Device Hub, trust this Mac, unlock it, and enable Developer Mode.");
4387
+ const apps = requireSuccess3(await options.capture(commands.apps), "AbsoluteJS could not inspect installed apps on the physical iOS device.");
4388
+ if (!apps.stdout.includes(options.appId))
4389
+ throw new Error("The AbsoluteJS app is not installed on the selected physical iOS device. Start bun dev with the same --ios-device value first.");
4390
+ const now = options.now ?? performance.now.bind(performance);
4391
+ const startedAt = now();
4392
+ requireSuccess3(await options.capture(commands.launch), "AbsoluteJS could not relaunch the app on the physical iOS device.");
4393
+ await options.waitForHmr();
4394
+ return {
4395
+ hmrConnected: true,
4396
+ installed: true,
4397
+ relaunchMs: Math.round(now() - startedAt)
4398
+ };
4399
+ };
4018
4400
  // src/mobile/associationFiles.ts
4019
4401
  import {
4020
4402
  access as access7,
4021
4403
  mkdir as mkdir7,
4022
- readFile as readFile9,
4404
+ readFile as readFile10,
4023
4405
  rename as rename8,
4024
4406
  rm as rm6,
4025
4407
  writeFile as writeFile8
@@ -4225,7 +4607,7 @@ var createAbsoluteMobileAssociationPlugin = (mobile, projectRoot, options = {})
4225
4607
  var writeAtomic = async (path, source) => {
4226
4608
  let current;
4227
4609
  try {
4228
- current = await readFile9(path, "utf8");
4610
+ current = await readFile10(path, "utf8");
4229
4611
  } catch (error) {
4230
4612
  if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
4231
4613
  throw error;
@@ -4250,7 +4632,7 @@ var assertOwnedOutput = async (root) => {
4250
4632
  const path = resolve7(root, OWNERSHIP_FILE);
4251
4633
  let ownership;
4252
4634
  try {
4253
- ownership = JSON.parse(await readFile9(path, "utf8"));
4635
+ ownership = JSON.parse(await readFile10(path, "utf8"));
4254
4636
  } catch {
4255
4637
  throw new TypeError(`Association output ${root} already exists and is not owned by AbsoluteJS.`);
4256
4638
  }
@@ -4386,13 +4768,13 @@ var parseAbsoluteMobileBuildPageMetadata = (value) => {
4386
4768
  };
4387
4769
  };
4388
4770
  // src/mobile/buildPipeline.ts
4389
- import { readFile as readFile13 } from "fs/promises";
4771
+ import { readFile as readFile14 } from "fs/promises";
4390
4772
  import { join as join14, resolve as resolve12 } from "path";
4391
4773
  import { pathToFileURL as pathToFileURL2 } from "url";
4392
4774
 
4393
4775
  // src/mobile/buildRelease.ts
4394
4776
  import { createHash as createHash8 } from "crypto";
4395
- import { mkdir as mkdir8, readFile as readFile10, writeFile as writeFile9 } from "fs/promises";
4777
+ import { mkdir as mkdir8, readFile as readFile11, writeFile as writeFile9 } from "fs/promises";
4396
4778
  import { basename as basename2, dirname as dirname6, extname, join as join8, relative as relative7, resolve as resolve8 } from "path";
4397
4779
  var sha256 = (bytes) => createHash8("sha256").update(bytes).digest("hex");
4398
4780
  var STATIC_SCRIPT_PATTERN = /(<script\b[^>]*?\bsrc\s*=\s*["'])(\/[^"']+\.(?:js|ts))(["'][^>]*>)/giu;
@@ -4419,7 +4801,7 @@ var pageFor = async (metadata, manifest, buildDirectory) => {
4419
4801
  }
4420
4802
  let resolvedAssetPath = resolveAssetPath(buildDirectory, assetPath);
4421
4803
  if (metadata.framework === "html" || metadata.framework === "htmx") {
4422
- const source = await readFile10(resolvedAssetPath, "utf8");
4804
+ const source = await readFile11(resolvedAssetPath, "utf8");
4423
4805
  const rewritten = rewriteStaticScriptPaths(source, manifest);
4424
4806
  const documentHash = sha256(new TextEncoder().encode(rewritten));
4425
4807
  resolvedAssetPath = join8(buildDirectory, ".absolutejs", "mobile-pages", `${documentHash}.html`);
@@ -4433,8 +4815,8 @@ var pageFor = async (metadata, manifest, buildDirectory) => {
4433
4815
  ].map((key) => manifest[key]).find((path) => typeof path === "string");
4434
4816
  const resolvedStylePath = styleAssetPath ? resolveAssetPath(buildDirectory, styleAssetPath) : undefined;
4435
4817
  const [bytes, styleBytes] = await Promise.all([
4436
- readFile10(resolvedAssetPath),
4437
- resolvedStylePath ? readFile10(resolvedStylePath) : undefined
4818
+ readFile11(resolvedAssetPath),
4819
+ resolvedStylePath ? readFile11(resolvedStylePath) : undefined
4438
4820
  ]);
4439
4821
  const bundlePath = `/${relative7(resolve8(buildDirectory), resolvedAssetPath).replaceAll("\\", "/")}`;
4440
4822
  const styleBundlePath = resolvedStylePath ? `/${relative7(resolve8(buildDirectory), resolvedStylePath).replaceAll("\\", "/")}` : undefined;
@@ -4454,7 +4836,7 @@ var pageFor = async (metadata, manifest, buildDirectory) => {
4454
4836
  var buildAbsoluteMobileCompatibilityRelease = async (options) => {
4455
4837
  const [captured, producerBytes] = await Promise.all([
4456
4838
  captureAbsoluteMobileRouteGraph(options.app),
4457
- readFile10(options.producerPath)
4839
+ readFile11(options.producerPath)
4458
4840
  ]);
4459
4841
  if (captured.length === 0) {
4460
4842
  throw new TypeError("No instrumented AbsoluteJS mobile page routes were found in the finalized Elysia route graph.");
@@ -4546,7 +4928,7 @@ import {
4546
4928
  copyFile as copyFile5,
4547
4929
  mkdir as mkdir9,
4548
4930
  mkdtemp as mkdtemp4,
4549
- readFile as readFile11,
4931
+ readFile as readFile12,
4550
4932
  rename as rename9,
4551
4933
  rm as rm7,
4552
4934
  writeFile as writeFile10
@@ -5076,7 +5458,7 @@ var resolveProjectImport = async (projectRoot, specifier) => {
5076
5458
  const packageName = specifier.startsWith("@") ? segments.slice(0, 2).join("/") : segments[0] ?? "";
5077
5459
  const subpath = specifier.slice(packageName.length);
5078
5460
  const packageDirectory = join9(resolve9(projectRoot), "node_modules", packageName);
5079
- const manifest = JSON.parse(await readFile11(join9(packageDirectory, "package.json"), "utf8"));
5461
+ const manifest = JSON.parse(await readFile12(join9(packageDirectory, "package.json"), "utf8"));
5080
5462
  const exports = typeof manifest === "object" && manifest !== null ? Reflect.get(manifest, "exports") : undefined;
5081
5463
  const entry = typeof exports === "object" && exports !== null ? Reflect.get(exports, subpath ? `.${subpath}` : ".") : undefined;
5082
5464
  const target = importEntryTarget(entry);
@@ -5184,7 +5566,7 @@ var copyClientPage = async (page, buildDirectory, staging, copiedDependencies) =
5184
5566
  };
5185
5567
  };
5186
5568
  var absoluteClientImports = async (sourcePath, buildDirectory) => {
5187
- const source = await readFile11(sourcePath, "utf8");
5569
+ const source = await readFile12(sourcePath, "utf8");
5188
5570
  const extension = extname2(sourcePath).toLowerCase();
5189
5571
  let scriptLoader;
5190
5572
  if (extension === ".tsx")
@@ -5295,7 +5677,7 @@ import {
5295
5677
  access as access8,
5296
5678
  mkdir as mkdir10,
5297
5679
  mkdtemp as mkdtemp5,
5298
- readFile as readFile12,
5680
+ readFile as readFile13,
5299
5681
  rename as rename10,
5300
5682
  rm as rm8,
5301
5683
  writeFile as writeFile11
@@ -5392,7 +5774,7 @@ var resolveProducerHandler = (loaded, exportName) => {
5392
5774
  };
5393
5775
  var loadAbsoluteMobileMaterializedBundle = async (root) => {
5394
5776
  const resolvedRoot = resolvePath3(root);
5395
- const serialized = await readFile12(join10(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
5777
+ const serialized = await readFile13(join10(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
5396
5778
  const parsed = JSON.parse(serialized);
5397
5779
  const index = parseBundleIndex(parsed);
5398
5780
  const bundleRoot = join10(resolvedRoot, BUNDLES_DIRECTORY, index.bundleId);
@@ -5447,7 +5829,7 @@ var materializeAbsoluteMobileCompatibilityBundle = async (input) => {
5447
5829
  var readAbsoluteMobileMaterializedReleases = async (root) => {
5448
5830
  const resolvedRoot = resolvePath3(root);
5449
5831
  try {
5450
- const serialized = await readFile12(join10(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
5832
+ const serialized = await readFile13(join10(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
5451
5833
  const parsed = JSON.parse(serialized);
5452
5834
  const index = parseBundleIndex(parsed);
5453
5835
  const bundleRoot = join10(resolvedRoot, BUNDLES_DIRECTORY, index.bundleId);
@@ -5558,7 +5940,7 @@ var finalizeAbsoluteMobileCompatibilityBuild = async (options) => {
5558
5940
  const mobile = normalizeAbsoluteMobileConfig(options.mobile, options.projectRoot);
5559
5941
  const root = join14(buildDirectory, ".absolutejs", "mobile-compatibility");
5560
5942
  const [manifestSource, previous] = await Promise.all([
5561
- readFile13(join14(buildDirectory, "manifest.json"), "utf8"),
5943
+ readFile14(join14(buildDirectory, "manifest.json"), "utf8"),
5562
5944
  readAbsoluteMobileMaterializedReleases(root)
5563
5945
  ]);
5564
5946
  const manifest = JSON.parse(manifestSource);
@@ -5957,7 +6339,7 @@ var createAbsoluteMobilePreviewPlugin = (mobile) => {
5957
6339
  });
5958
6340
  };
5959
6341
  // src/mobile/nativeDeepLinks.ts
5960
- import { readFile as readFile14, rename as rename11, writeFile as writeFile12 } from "fs/promises";
6342
+ import { readFile as readFile15, rename as rename11, writeFile as writeFile12 } from "fs/promises";
5961
6343
  import { join as join17 } from "path";
5962
6344
  var START_MARKER = "<!-- absolutejs:deep-links:start -->";
5963
6345
  var END_MARKER = "<!-- absolutejs:deep-links:end -->";
@@ -5965,7 +6347,7 @@ var IOS_ENTITLEMENTS = "App/AbsoluteJS.entitlements";
5965
6347
  var NOT_FOUND = -1;
5966
6348
  var escapeXml = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
5967
6349
  var writeChangedFile = async (path, source) => {
5968
- const current = await readFile14(path, "utf8");
6350
+ const current = await readFile15(path, "utf8");
5969
6351
  if (current === source)
5970
6352
  return false;
5971
6353
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
@@ -6016,7 +6398,7 @@ ${hosts}
6016
6398
  };
6017
6399
  var configureAndroid = async (config) => {
6018
6400
  const path = join17(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
6019
- const source = await readFile14(path, "utf8");
6401
+ const source = await readFile15(path, "utf8");
6020
6402
  const mainActivity = source.indexOf('android:name=".MainActivity"');
6021
6403
  if (mainActivity === NOT_FOUND) {
6022
6404
  throw new TypeError("Android MainActivity was not found.");
@@ -6042,7 +6424,7 @@ var iosSchemeRegion = (scheme) => ` ${START_MARKER}
6042
6424
  `;
6043
6425
  var configureIosInfo = async (config) => {
6044
6426
  const path = join17(config.nativeProjectDirectory, "ios/App/App/Info.plist");
6045
- const source = await readFile14(path, "utf8");
6427
+ const source = await readFile15(path, "utf8");
6046
6428
  const region = config.deepLinkScheme ? iosSchemeRegion(config.deepLinkScheme) : ` ${START_MARKER}
6047
6429
  ${END_MARKER}
6048
6430
  `;
@@ -6068,7 +6450,7 @@ var configureIosEntitlements = async (config) => {
6068
6450
  const path = join17(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
6069
6451
  let current = "";
6070
6452
  try {
6071
- current = await readFile14(path, "utf8");
6453
+ current = await readFile15(path, "utf8");
6072
6454
  } catch (error) {
6073
6455
  if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
6074
6456
  throw error;
@@ -6084,7 +6466,7 @@ var configureIosEntitlements = async (config) => {
6084
6466
  };
6085
6467
  var configureIosProject = async (config) => {
6086
6468
  const path = join17(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
6087
- const source = await readFile14(path, "utf8");
6469
+ const source = await readFile15(path, "utf8");
6088
6470
  const declarations = [
6089
6471
  ...source.matchAll(/CODE_SIGN_ENTITLEMENTS = ([^;]+);/g)
6090
6472
  ].map((match) => match[1]);
@@ -6123,7 +6505,7 @@ var applyAbsoluteNativeDeepLinks = async (config, platforms = config.platforms)
6123
6505
  };
6124
6506
  // src/mobile/nativeDeviceCapabilities.ts
6125
6507
  init_deviceCapabilities();
6126
- import { readFile as readFile15, rename as rename12, writeFile as writeFile13 } from "fs/promises";
6508
+ import { readFile as readFile16, rename as rename12, writeFile as writeFile13 } from "fs/promises";
6127
6509
  import { join as join18 } from "path";
6128
6510
  var START_MARKER2 = "<!-- absolutejs:device-capabilities:start -->";
6129
6511
  var END_MARKER2 = "<!-- absolutejs:device-capabilities:end -->";
@@ -6134,7 +6516,7 @@ var PUSH_START_MARKER = "absolutejs:push-notifications:start";
6134
6516
  var PUSH_END_MARKER = "absolutejs:push-notifications:end";
6135
6517
  var escapeXml2 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
6136
6518
  var writeChangedFile2 = async (path, source) => {
6137
- const current = await readFile15(path, "utf8");
6519
+ const current = await readFile16(path, "utf8");
6138
6520
  if (current === source)
6139
6521
  return false;
6140
6522
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
@@ -6154,7 +6536,7 @@ var writeOptionalChangedFile = async (path, source) => {
6154
6536
  };
6155
6537
  var optionalSource = async (path) => {
6156
6538
  try {
6157
- return await readFile15(path, "utf8");
6539
+ return await readFile16(path, "utf8");
6158
6540
  } catch (error) {
6159
6541
  if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "ENOENT")
6160
6542
  return null;
@@ -6275,7 +6657,7 @@ var configureIosPrivacyProject = async (config, requirements) => {
6275
6657
  if (requirements.iosPrivacyAccessedApis.length === 0)
6276
6658
  return false;
6277
6659
  const projectPath = join18(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
6278
- const project = await readFile15(projectPath, "utf8");
6660
+ const project = await readFile16(projectPath, "utf8");
6279
6661
  return writeChangedFile2(projectPath, addIosPrivacyProjectReference(project));
6280
6662
  };
6281
6663
  var addIosPrivacyProjectReference = (source) => {
@@ -6328,7 +6710,7 @@ ${next.slice(index)}`;
6328
6710
  };
6329
6711
  var configureIos2 = async (config, plan) => {
6330
6712
  const path = join18(config.nativeProjectDirectory, "ios/App/App/Info.plist");
6331
- const source = await readFile15(path, "utf8");
6713
+ const source = await readFile16(path, "utf8");
6332
6714
  const requirements = absoluteDeviceNativeRequirements(plan);
6333
6715
  const existingSystemBars = source.match(/<key>UIViewControllerBasedStatusBarAppearance<\/key>\s*<(true|false)\s*\/>/u);
6334
6716
  const ownedStart = source.indexOf(START_MARKER2);
@@ -6421,7 +6803,7 @@ var replacePushRegion = (source, region, insertion) => {
6421
6803
  };
6422
6804
  var configureAndroid2 = async (config, plan) => {
6423
6805
  const path = join18(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
6424
- const source = await readFile15(path, "utf8");
6806
+ const source = await readFile16(path, "utf8");
6425
6807
  const permissions = absoluteDeviceNativeRequirements(plan).androidPermissions;
6426
6808
  const content = permissions.map((permission) => ` <uses-permission android:name="${escapeXml2(permission)}" />`).join(`
6427
6809
  `);
@@ -7308,9 +7690,12 @@ export {
7308
7690
  verifyAbsoluteMobileAssociationFiles,
7309
7691
  validateAbsoluteSshDestination,
7310
7692
  validateAbsoluteRemoteMacProfileName,
7693
+ testAbsoluteIosPhysicalDevice,
7311
7694
  syncAbsoluteRemoteMacProject,
7312
7695
  startAbsoluteRemoteIosDevSession,
7696
+ startAbsoluteIosTcpRelay,
7313
7697
  startAbsoluteIosDevSession,
7698
+ startAbsoluteIosCaEnrollmentServer,
7314
7699
  serializeAbsoluteMobileAuthEnvironment,
7315
7700
  runWithAbsoluteMobileProducer,
7316
7701
  runAbsoluteAndroidUpgradeConformance,
@@ -7345,6 +7730,8 @@ export {
7345
7730
  parseAbsoluteAndroidInstalledApp,
7346
7731
  pairAbsoluteRemoteMac,
7347
7732
  normalizeAbsoluteMobileConfig,
7733
+ normalizeAbsoluteIosDeviceIdentifier,
7734
+ normalizeAbsoluteIosDeviceHost,
7348
7735
  navigateAbsoluteMobilePage,
7349
7736
  missingAbsoluteDeviceCapabilityPackages,
7350
7737
  materializeAbsoluteRemoteMacAgent,
@@ -7361,6 +7748,7 @@ export {
7361
7748
  installAbsoluteMobileSyncRemediation,
7362
7749
  installAbsoluteMobileShellHttp,
7363
7750
  installAbsoluteMobileAuthEnvironment,
7751
+ inspectAbsoluteRemoteMacLanHost,
7364
7752
  inspectAbsoluteRemoteMac,
7365
7753
  inspectAbsoluteMobileRouteMetadata,
7366
7754
  inspectAbsoluteAndroidInstalledApp,
@@ -7393,6 +7781,7 @@ export {
7393
7781
  createAbsoluteMobileAssociationDocuments,
7394
7782
  createAbsoluteIosNativeWatcher,
7395
7783
  carryForwardAbsoluteMobileCompatibilityReleases,
7784
+ captureAbsoluteRemoteMacCommand,
7396
7785
  captureAbsoluteMobileRouteGraph,
7397
7786
  buildAbsoluteMobileCompatibilityRelease,
7398
7787
  buildAbsoluteIosRelease,
@@ -7405,6 +7794,7 @@ export {
7405
7794
  absoluteRemoteProjectSyncCommands,
7406
7795
  absoluteRemoteMacSshBase,
7407
7796
  absoluteMobilePreviewDocument,
7797
+ absoluteIosDeviceAcceptanceCommands,
7408
7798
  absoluteDeviceNativeRequirements,
7409
7799
  MOBILE_PAGE_REQUEST_HEADERS,
7410
7800
  AbsoluteMobilePageProtocolError,
@@ -7430,5 +7820,5 @@ export {
7430
7820
  ABSOLUTE_ANDROID_RELEASE_FORMAT
7431
7821
  };
7432
7822
 
7433
- //# debugId=558FB72C0F151C5864756E2164756E21
7823
+ //# debugId=D998DAA8591F90D464756E2164756E21
7434
7824
  //# sourceMappingURL=index.js.map