@mcesystems/apple-kit 1.0.60 → 1.0.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -33389,6 +33389,17 @@ function parseWifiEapType(value) {
33389
33389
  // src/logic/iosCli.ts
33390
33390
  import { spawn } from "node:child_process";
33391
33391
  import { join as join5 } from "node:path";
33392
+ var ios;
33393
+ function iosCli() {
33394
+ const iosBinaryPath = resolveIosBinaryPath();
33395
+ if (!iosBinaryPath) {
33396
+ throw new Error("iosBinaryPath is required. Provide iosBinaryPath or resourcesDir.");
33397
+ }
33398
+ return createIosCli(iosBinaryPath);
33399
+ }
33400
+ if (!ios) {
33401
+ ios = iosCli();
33402
+ }
33392
33403
  function runIosCommand(iosBinaryPath, args) {
33393
33404
  return new Promise((resolve2, reject) => {
33394
33405
  const child = spawn(iosBinaryPath, args, {
@@ -33583,11 +33594,11 @@ function createIosCli(iosBinaryPath) {
33583
33594
  }
33584
33595
  };
33585
33596
  }
33597
+ var iosCli_default = ios;
33586
33598
 
33587
33599
  // src/logic/activationFlow.ts
33588
33600
  var DEFAULT_RETRIES = 150;
33589
33601
  var DEFAULT_RETRY_DELAY_MS = 1e3;
33590
- var MCE_MDM_PROFILE_PREFIX = "com.mce.mdm";
33591
33602
  var ActivationFlow = class {
33592
33603
  iosCli;
33593
33604
  mdmClientPromise;
@@ -33601,38 +33612,12 @@ var ActivationFlow = class {
33601
33612
  }
33602
33613
  async run(udid) {
33603
33614
  logTask(`Starting activation flow for device ${udid}`);
33604
- const activationState = await this.getActivationState(udid);
33605
- if (activationState === "Activated") {
33606
- const isEnrolled = await this.isEnrolledToMceMdm(udid);
33607
- if (isEnrolled) {
33608
- logInfo("Device already activated and enrolled to MCE MDM. Skipping activation flow.");
33609
- return async () => {
33610
- };
33611
- }
33612
- } else if (activationState) {
33613
- logInfo(`Activation state is ${activationState}, activating device`);
33614
- await this.retryActivateCommand("activate device", () => this.iosCli.activate(udid));
33615
- } else {
33616
- await this.retryIosCommand("wipe", () => this.iosCli.wipe(udid));
33617
- return void 0;
33618
- }
33615
+ await this.retryActivateCommand("activate device", () => this.iosCli.activate(udid));
33619
33616
  const wifiProfileIdentifier = await this.installWifiProfile(udid);
33620
33617
  await this.installMdmProfile(udid);
33621
33618
  await this.retryIosCommand("skip steps", () => this.iosCli.skipSteps(udid));
33622
33619
  return () => this.removeWifiProfile(udid, wifiProfileIdentifier);
33623
33620
  }
33624
- async isEnrolledToMceMdm(udid) {
33625
- const profiles = await this.listProfiles(udid);
33626
- return profiles.some((profile) => isMceMdmProfile(profile));
33627
- }
33628
- async listProfiles(udid) {
33629
- const result = await this.retry(
33630
- "list profiles",
33631
- () => this.iosCli.listProfiles(udid),
33632
- (response) => response.raw.exitCode === 0
33633
- );
33634
- return result.profiles;
33635
- }
33636
33621
  async installWifiProfile(udid) {
33637
33622
  const wifiProfile = await generateWifiProfileFromEnv();
33638
33623
  if (!wifiProfile) {
@@ -33647,14 +33632,6 @@ var ActivationFlow = class {
33647
33632
  await removeTempFile(wifiProfilePath, "wifi profile");
33648
33633
  return wifiProfileIdentifier;
33649
33634
  }
33650
- async getActivationState(udid) {
33651
- const infoResult = await this.retryIosCommand("device info", () => this.iosCli.info(udid));
33652
- const activationState = getActivationState2(infoResult.output);
33653
- if (!activationState) {
33654
- logInfo("Activation state not found");
33655
- }
33656
- return activationState;
33657
- }
33658
33635
  async installMdmProfile(udid) {
33659
33636
  const client = await this.requireMdmClient();
33660
33637
  logTask("Installing MDM enrollment profile");
@@ -33696,7 +33673,7 @@ var ActivationFlow = class {
33696
33673
  async retryActivateCommand(label, command) {
33697
33674
  return this.retry(label, command, (result) => isActivationSuccess(result));
33698
33675
  }
33699
- async retry(label, command, isSuccess, retries = DEFAULT_RETRIES, retryDelayMs = DEFAULT_RETRY_DELAY_MS) {
33676
+ async retry(label, command, isSuccess, retries = +(process.env.DEFAULT_RETRIES ?? DEFAULT_RETRIES), retryDelayMs = +(process.env.DEFAULT_RETRY_DELAY_MS ?? DEFAULT_RETRY_DELAY_MS)) {
33700
33677
  for (let attempt = 0; attempt < retries; attempt += 1) {
33701
33678
  try {
33702
33679
  const result = await command();
@@ -33746,25 +33723,6 @@ function resolveIosBinaryPath() {
33746
33723
  const binaryName = platform === "win32" ? "ios.exe" : "ios";
33747
33724
  return join6(getResourcesBinPath(), binaryName);
33748
33725
  }
33749
- function getActivationState2(output) {
33750
- if (!Array.isArray(output) || output.length === 0) {
33751
- return void 0;
33752
- }
33753
- for (const item of output) {
33754
- if (!item || typeof item !== "object") {
33755
- continue;
33756
- }
33757
- if ("ActivationState" in item) {
33758
- const value = item.ActivationState;
33759
- return typeof value === "string" ? value : void 0;
33760
- }
33761
- if ("activationState" in item) {
33762
- const value = item.activationState;
33763
- return typeof value === "string" ? value : void 0;
33764
- }
33765
- }
33766
- return void 0;
33767
- }
33768
33726
  function isActivationSuccess(result) {
33769
33727
  if (result.exitCode !== 0) {
33770
33728
  return false;
@@ -33775,19 +33733,6 @@ function isActivationSuccess(result) {
33775
33733
  const hasFatal = result.logMessages.some((log) => log.level === "error");
33776
33734
  return !hasFatal;
33777
33735
  }
33778
- function isMceMdmProfile(profile) {
33779
- const identifier = profile.Identifier;
33780
- if (!identifier) {
33781
- return false;
33782
- }
33783
- if (!identifier.startsWith(MCE_MDM_PROFILE_PREFIX)) {
33784
- return false;
33785
- }
33786
- if (profile.Manifest?.IsActive === false) {
33787
- return false;
33788
- }
33789
- return true;
33790
- }
33791
33736
 
33792
33737
  // src/logic/dataParser.ts
33793
33738
  function parsePlistOutput(output) {
@@ -33854,13 +33799,34 @@ async function info(udid) {
33854
33799
  if (!iosBinaryPath) {
33855
33800
  throw new Error("iosBinaryPath is required. Provide iosBinaryPath or resourcesDir.");
33856
33801
  }
33857
- const iosCli = createIosCli(iosBinaryPath);
33858
- const result = await iosCli.info(udid);
33802
+ const iosCli2 = createIosCli(iosBinaryPath);
33803
+ const result = await iosCli2.info(udid);
33859
33804
  if (!result) {
33860
33805
  throw new Error("Failed to get device info");
33861
33806
  }
33862
33807
  return result.output[0];
33863
33808
  }
33809
+ async function wipeDevice(udid) {
33810
+ if (!iosCli_default) {
33811
+ throw new Error("ios is not initialized");
33812
+ }
33813
+ logTask(`Wiping device ${udid}`);
33814
+ await iosCli_default.wipe(udid);
33815
+ }
33816
+ async function removeProfile(profileIdentifier, udid) {
33817
+ if (!iosCli_default) {
33818
+ throw new Error("ios is not initialized");
33819
+ }
33820
+ logTask(`Removing profile ${profileIdentifier} from device ${udid}`);
33821
+ await iosCli_default.removeProfile(udid, profileIdentifier);
33822
+ }
33823
+ async function listProfiles(udid) {
33824
+ if (!iosCli_default) {
33825
+ throw new Error("ios is not initialized");
33826
+ }
33827
+ logTask(`Listing profiles for device ${udid}`);
33828
+ return iosCli_default.listProfiles(udid);
33829
+ }
33864
33830
 
33865
33831
  // src/logic/actions/pair.ts
33866
33832
  async function isPaired(udid) {
@@ -33984,160 +33950,8 @@ async function isAppInstalled(bundleId, udid) {
33984
33950
  const apps = await listApps(udid);
33985
33951
  return apps.some((app) => app.bundleId === bundleId);
33986
33952
  }
33987
- async function wakeDevice(udid) {
33988
- try {
33989
- logInfo("Attempting to wake device screen...");
33990
- await runIDeviceTool("ideviceinfo", ["-u", udid, "-k", "DeviceName"]);
33991
- try {
33992
- await runIDeviceTool("ideviceinfo", ["-u", udid, "-k", "ActivationState"]);
33993
- } catch {
33994
- }
33995
- try {
33996
- await runIDeviceTool("idevicepair", ["-u", udid, "validate"]);
33997
- } catch {
33998
- }
33999
- await new Promise((resolve2) => setTimeout(resolve2, 1e3));
34000
- logInfo("Device wake attempt completed");
34001
- } catch (error) {
34002
- logInfo(
34003
- `Device wake attempt failed (non-critical): ${error instanceof Error ? error.message : String(error)}`
34004
- );
34005
- }
34006
- }
34007
- async function launchApp(bundleId, args, udid) {
33953
+ async function launchApp(bundleId, _args, udid) {
34008
33954
  logTask(`Launching app ${bundleId} on device ${udid}`);
34009
- if (!await isPaired(udid)) {
34010
- await waitForPairing(udid, 1e4);
34011
- }
34012
- const installed = await isAppInstalled(bundleId, udid);
34013
- if (!installed) {
34014
- throw new Error(
34015
- `App "${bundleId}" is not installed on the device. Install the app first or verify the bundle identifier is correct.`
34016
- );
34017
- }
34018
- await wakeDevice(udid);
34019
- try {
34020
- logInfo(`Attempting to launch ${bundleId} using idevicedebug...`);
34021
- const result = await runIDeviceTool("idevicedebug", ["-u", udid, "run", bundleId, ...args]);
34022
- const output = (result?.stdout ?? "") + (result?.stderr ?? "");
34023
- if (output.trim()) {
34024
- logInfo(`idevicedebug output: ${output.substring(0, 200)}`);
34025
- }
34026
- if (output.toLowerCase().includes("could not start") && output.toLowerCase().includes("debugserver")) {
34027
- logInfo("idevicedebug requires debugserver, falling back to pymobiledevice3...");
34028
- throw new Error("debugserver_not_available");
34029
- }
34030
- logInfo(`App ${bundleId} launched successfully using idevicedebug`);
34031
- await new Promise((resolve2) => setTimeout(resolve2, 1e3));
34032
- return;
34033
- } catch (error) {
34034
- const errorMsg = error instanceof Error ? error.message : String(error);
34035
- if (errorMsg.includes("debugserver_not_available") || errorMsg.toLowerCase().includes("could not start") || errorMsg.toLowerCase().includes("debugserver")) {
34036
- logInfo("idevicedebug failed, trying pymobiledevice3 for iOS 17+...");
34037
- await launchAppWithPymobiledevice3(bundleId, args, udid);
34038
- return;
34039
- }
34040
- throw error;
34041
- }
34042
- }
34043
- async function launchAppWithPymobiledevice3(bundleId, args, udid) {
34044
- logTask(`Launching app ${bundleId} using pymobiledevice3`);
34045
- const { exec } = await import("node:child_process");
34046
- const { promisify: promisify3 } = await import("node:util");
34047
- const execAsync2 = promisify3(exec);
34048
- try {
34049
- let cmdArgs = [
34050
- "-m",
34051
- "pymobiledevice3",
34052
- "developer",
34053
- "dvt",
34054
- "launch",
34055
- "--udid",
34056
- udid,
34057
- "--kill-existing",
34058
- // Kill existing instance to bring app to foreground
34059
- bundleId,
34060
- ...args
34061
- ];
34062
- let command = `python ${cmdArgs.map((a) => `"${a}"`).join(" ")}`;
34063
- logInfo(`Executing: ${command}`);
34064
- const result = await execAsync2(command, {
34065
- windowsHide: true,
34066
- encoding: "utf8",
34067
- timeout: 3e4
34068
- // 30 second timeout
34069
- });
34070
- const output = result.stdout.toString() + result.stderr.toString();
34071
- if (output.trim()) {
34072
- logInfo(`pymobiledevice3 output: ${output.substring(0, 200)}`);
34073
- }
34074
- if (output.toLowerCase().includes("developer mode") && output.toLowerCase().includes("not enabled")) {
34075
- throw new Error(
34076
- "Developer Mode is not enabled on the device.\nPlease enable it: Settings \u2192 Privacy & Security \u2192 Developer Mode \u2192 Enable"
34077
- );
34078
- }
34079
- if (output.toLowerCase().includes("tunneld") && (output.toLowerCase().includes("unable to connect") || output.toLowerCase().includes("invalidserviceerror"))) {
34080
- logInfo("Tunnel required, retrying with tunnel option...");
34081
- cmdArgs = [
34082
- "-m",
34083
- "pymobiledevice3",
34084
- "developer",
34085
- "dvt",
34086
- "launch",
34087
- "--udid",
34088
- udid,
34089
- "--tunnel",
34090
- udid,
34091
- // Use UDID for tunnel
34092
- "--kill-existing",
34093
- bundleId,
34094
- ...args
34095
- ];
34096
- command = `python ${cmdArgs.map((a) => `"${a}"`).join(" ")}`;
34097
- logInfo(`Retrying with tunnel: ${command}`);
34098
- try {
34099
- const retryResult = await execAsync2(command, {
34100
- windowsHide: true,
34101
- encoding: "utf8",
34102
- timeout: 3e4
34103
- });
34104
- const retryOutput = retryResult.stdout.toString() + retryResult.stderr.toString();
34105
- if (retryOutput.trim()) {
34106
- logInfo(`pymobiledevice3 retry output: ${retryOutput.substring(0, 200)}`);
34107
- }
34108
- if (retryOutput.toLowerCase().includes("tunneld") && retryOutput.toLowerCase().includes("unable to connect")) {
34109
- throw new Error(
34110
- "Tunnel connection failed. For iOS 17+, you may need to start tunneld:\n python -m pymobiledevice3 remote tunneld\nOr ensure Developer Mode is enabled and device is unlocked."
34111
- );
34112
- }
34113
- logInfo(`App ${bundleId} launched successfully using pymobiledevice3 with tunnel`);
34114
- await new Promise((resolve2) => setTimeout(resolve2, 500));
34115
- return;
34116
- } catch {
34117
- throw new Error(
34118
- "Tunnel connection failed. For iOS 17+, you may need to start tunneld:\n python -m pymobiledevice3 remote tunneld\nOr ensure Developer Mode is enabled and device is unlocked."
34119
- );
34120
- }
34121
- }
34122
- if (output.toLowerCase().includes("not found") || output.toLowerCase().includes("command not found") || output.toLowerCase().includes("cannot find")) {
34123
- throw new Error(
34124
- "pymobiledevice3 is not installed.\nInstall it with: python -m pip install --user pymobiledevice3"
34125
- );
34126
- }
34127
- if (output.toLowerCase().includes("error") && !output.toLowerCase().includes("warning")) {
34128
- logInfo(`Warning: pymobiledevice3 reported errors: ${output.substring(0, 300)}`);
34129
- }
34130
- logInfo(`App ${bundleId} launched successfully using pymobiledevice3`);
34131
- await new Promise((resolve2) => setTimeout(resolve2, 1e3));
34132
- } catch (error) {
34133
- const errorMsg = error instanceof Error ? error.message : String(error);
34134
- if (errorMsg.includes("not found") || errorMsg.includes("command not found") || errorMsg.includes("cannot find") || errorMsg.includes("No module named")) {
34135
- throw new Error(
34136
- "pymobiledevice3 is not installed or Python is not available.\nInstall it with: python -m pip install --user pymobiledevice3\nFor iOS 17+, Developer Mode must also be enabled on the device."
34137
- );
34138
- }
34139
- throw error;
34140
- }
34141
33955
  }
34142
33956
 
34143
33957
  // src/logic/actions/proxy.ts
@@ -34396,6 +34210,18 @@ var AppleDeviceKit = class {
34396
34210
  this.ensureNotDisposed();
34397
34211
  return getActivationState(this.deviceId);
34398
34212
  }
34213
+ /**
34214
+ * Wipe the device
34215
+ */
34216
+ async wipe() {
34217
+ return wipeDevice(this.deviceId);
34218
+ }
34219
+ removeProfile(profileIdentifier) {
34220
+ return removeProfile(profileIdentifier, this.deviceId);
34221
+ }
34222
+ listProfiles() {
34223
+ return listProfiles(this.deviceId);
34224
+ }
34399
34225
  /**
34400
34226
  * Activate the device using the activation flow.
34401
34227
  *