@mcesystems/apple-kit 1.0.59 → 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.js CHANGED
@@ -33399,6 +33399,17 @@ function parseWifiEapType(value) {
33399
33399
  // src/logic/iosCli.ts
33400
33400
  var import_node_child_process2 = require("node:child_process");
33401
33401
  var import_node_path5 = require("node:path");
33402
+ var ios;
33403
+ function iosCli() {
33404
+ const iosBinaryPath = resolveIosBinaryPath();
33405
+ if (!iosBinaryPath) {
33406
+ throw new Error("iosBinaryPath is required. Provide iosBinaryPath or resourcesDir.");
33407
+ }
33408
+ return createIosCli(iosBinaryPath);
33409
+ }
33410
+ if (!ios) {
33411
+ ios = iosCli();
33412
+ }
33402
33413
  function runIosCommand(iosBinaryPath, args) {
33403
33414
  return new Promise((resolve2, reject) => {
33404
33415
  const child = (0, import_node_child_process2.spawn)(iosBinaryPath, args, {
@@ -33593,11 +33604,11 @@ function createIosCli(iosBinaryPath) {
33593
33604
  }
33594
33605
  };
33595
33606
  }
33607
+ var iosCli_default = ios;
33596
33608
 
33597
33609
  // src/logic/activationFlow.ts
33598
33610
  var DEFAULT_RETRIES = 150;
33599
33611
  var DEFAULT_RETRY_DELAY_MS = 1e3;
33600
- var MCE_MDM_PROFILE_PREFIX = "com.mce.mdm";
33601
33612
  var ActivationFlow = class {
33602
33613
  iosCli;
33603
33614
  mdmClientPromise;
@@ -33611,38 +33622,12 @@ var ActivationFlow = class {
33611
33622
  }
33612
33623
  async run(udid) {
33613
33624
  logTask(`Starting activation flow for device ${udid}`);
33614
- const activationState = await this.getActivationState(udid);
33615
- if (activationState === "Activated") {
33616
- const isEnrolled = await this.isEnrolledToMceMdm(udid);
33617
- if (isEnrolled) {
33618
- logInfo("Device already activated and enrolled to MCE MDM. Skipping activation flow.");
33619
- return async () => {
33620
- };
33621
- }
33622
- } else if (activationState) {
33623
- logInfo(`Activation state is ${activationState}, activating device`);
33624
- await this.retryActivateCommand("activate device", () => this.iosCli.activate(udid));
33625
- } else {
33626
- await this.retryIosCommand("wipe", () => this.iosCli.wipe(udid));
33627
- return void 0;
33628
- }
33625
+ await this.retryActivateCommand("activate device", () => this.iosCli.activate(udid));
33629
33626
  const wifiProfileIdentifier = await this.installWifiProfile(udid);
33630
33627
  await this.installMdmProfile(udid);
33631
33628
  await this.retryIosCommand("skip steps", () => this.iosCli.skipSteps(udid));
33632
33629
  return () => this.removeWifiProfile(udid, wifiProfileIdentifier);
33633
33630
  }
33634
- async isEnrolledToMceMdm(udid) {
33635
- const profiles = await this.listProfiles(udid);
33636
- return profiles.some((profile) => isMceMdmProfile(profile));
33637
- }
33638
- async listProfiles(udid) {
33639
- const result = await this.retry(
33640
- "list profiles",
33641
- () => this.iosCli.listProfiles(udid),
33642
- (response) => response.raw.exitCode === 0
33643
- );
33644
- return result.profiles;
33645
- }
33646
33631
  async installWifiProfile(udid) {
33647
33632
  const wifiProfile = await generateWifiProfileFromEnv();
33648
33633
  if (!wifiProfile) {
@@ -33657,14 +33642,6 @@ var ActivationFlow = class {
33657
33642
  await removeTempFile(wifiProfilePath, "wifi profile");
33658
33643
  return wifiProfileIdentifier;
33659
33644
  }
33660
- async getActivationState(udid) {
33661
- const infoResult = await this.retryIosCommand("device info", () => this.iosCli.info(udid));
33662
- const activationState = getActivationState2(infoResult.output);
33663
- if (!activationState) {
33664
- logInfo("Activation state not found");
33665
- }
33666
- return activationState;
33667
- }
33668
33645
  async installMdmProfile(udid) {
33669
33646
  const client = await this.requireMdmClient();
33670
33647
  logTask("Installing MDM enrollment profile");
@@ -33706,7 +33683,7 @@ var ActivationFlow = class {
33706
33683
  async retryActivateCommand(label, command) {
33707
33684
  return this.retry(label, command, (result) => isActivationSuccess(result));
33708
33685
  }
33709
- async retry(label, command, isSuccess, retries = DEFAULT_RETRIES, retryDelayMs = DEFAULT_RETRY_DELAY_MS) {
33686
+ async retry(label, command, isSuccess, retries = +(process.env.DEFAULT_RETRIES ?? DEFAULT_RETRIES), retryDelayMs = +(process.env.DEFAULT_RETRY_DELAY_MS ?? DEFAULT_RETRY_DELAY_MS)) {
33710
33687
  for (let attempt = 0; attempt < retries; attempt += 1) {
33711
33688
  try {
33712
33689
  const result = await command();
@@ -33756,25 +33733,6 @@ function resolveIosBinaryPath() {
33756
33733
  const binaryName = platform === "win32" ? "ios.exe" : "ios";
33757
33734
  return (0, import_node_path6.join)(getResourcesBinPath(), binaryName);
33758
33735
  }
33759
- function getActivationState2(output) {
33760
- if (!Array.isArray(output) || output.length === 0) {
33761
- return void 0;
33762
- }
33763
- for (const item of output) {
33764
- if (!item || typeof item !== "object") {
33765
- continue;
33766
- }
33767
- if ("ActivationState" in item) {
33768
- const value = item.ActivationState;
33769
- return typeof value === "string" ? value : void 0;
33770
- }
33771
- if ("activationState" in item) {
33772
- const value = item.activationState;
33773
- return typeof value === "string" ? value : void 0;
33774
- }
33775
- }
33776
- return void 0;
33777
- }
33778
33736
  function isActivationSuccess(result) {
33779
33737
  if (result.exitCode !== 0) {
33780
33738
  return false;
@@ -33785,19 +33743,6 @@ function isActivationSuccess(result) {
33785
33743
  const hasFatal = result.logMessages.some((log) => log.level === "error");
33786
33744
  return !hasFatal;
33787
33745
  }
33788
- function isMceMdmProfile(profile) {
33789
- const identifier = profile.Identifier;
33790
- if (!identifier) {
33791
- return false;
33792
- }
33793
- if (!identifier.startsWith(MCE_MDM_PROFILE_PREFIX)) {
33794
- return false;
33795
- }
33796
- if (profile.Manifest?.IsActive === false) {
33797
- return false;
33798
- }
33799
- return true;
33800
- }
33801
33746
 
33802
33747
  // src/logic/dataParser.ts
33803
33748
  function parsePlistOutput(output) {
@@ -33864,13 +33809,34 @@ async function info(udid) {
33864
33809
  if (!iosBinaryPath) {
33865
33810
  throw new Error("iosBinaryPath is required. Provide iosBinaryPath or resourcesDir.");
33866
33811
  }
33867
- const iosCli = createIosCli(iosBinaryPath);
33868
- const result = await iosCli.info(udid);
33812
+ const iosCli2 = createIosCli(iosBinaryPath);
33813
+ const result = await iosCli2.info(udid);
33869
33814
  if (!result) {
33870
33815
  throw new Error("Failed to get device info");
33871
33816
  }
33872
33817
  return result.output[0];
33873
33818
  }
33819
+ async function wipeDevice(udid) {
33820
+ if (!iosCli_default) {
33821
+ throw new Error("ios is not initialized");
33822
+ }
33823
+ logTask(`Wiping device ${udid}`);
33824
+ await iosCli_default.wipe(udid);
33825
+ }
33826
+ async function removeProfile(profileIdentifier, udid) {
33827
+ if (!iosCli_default) {
33828
+ throw new Error("ios is not initialized");
33829
+ }
33830
+ logTask(`Removing profile ${profileIdentifier} from device ${udid}`);
33831
+ await iosCli_default.removeProfile(udid, profileIdentifier);
33832
+ }
33833
+ async function listProfiles(udid) {
33834
+ if (!iosCli_default) {
33835
+ throw new Error("ios is not initialized");
33836
+ }
33837
+ logTask(`Listing profiles for device ${udid}`);
33838
+ return iosCli_default.listProfiles(udid);
33839
+ }
33874
33840
 
33875
33841
  // src/logic/actions/pair.ts
33876
33842
  async function isPaired(udid) {
@@ -33958,11 +33924,10 @@ async function installLocalApp(ipaPath, udid) {
33958
33924
  logTask(`Installing app ${ipaPath} on device ${udid}`);
33959
33925
  await runIDeviceTool("ideviceinstaller", ["-u", udid, "install", ipaPath]);
33960
33926
  }
33961
- async function installManagedApp(ipaPath, udid, timeBetweenInstalls, options) {
33927
+ async function installManagedApp(ipaPath, udid, options) {
33962
33928
  await installLocalApp(ipaPath, udid);
33963
33929
  const client = await createMDMClient();
33964
33930
  logTask("Installing app via MDM for management takeover");
33965
- await new Promise((resolve2) => setTimeout(resolve2, timeBetweenInstalls));
33966
33931
  if (client) {
33967
33932
  client.installApp(udid, options);
33968
33933
  }
@@ -33995,160 +33960,8 @@ async function isAppInstalled(bundleId, udid) {
33995
33960
  const apps = await listApps(udid);
33996
33961
  return apps.some((app) => app.bundleId === bundleId);
33997
33962
  }
33998
- async function wakeDevice(udid) {
33999
- try {
34000
- logInfo("Attempting to wake device screen...");
34001
- await runIDeviceTool("ideviceinfo", ["-u", udid, "-k", "DeviceName"]);
34002
- try {
34003
- await runIDeviceTool("ideviceinfo", ["-u", udid, "-k", "ActivationState"]);
34004
- } catch {
34005
- }
34006
- try {
34007
- await runIDeviceTool("idevicepair", ["-u", udid, "validate"]);
34008
- } catch {
34009
- }
34010
- await new Promise((resolve2) => setTimeout(resolve2, 1e3));
34011
- logInfo("Device wake attempt completed");
34012
- } catch (error) {
34013
- logInfo(
34014
- `Device wake attempt failed (non-critical): ${error instanceof Error ? error.message : String(error)}`
34015
- );
34016
- }
34017
- }
34018
- async function launchApp(bundleId, args, udid) {
33963
+ async function launchApp(bundleId, _args, udid) {
34019
33964
  logTask(`Launching app ${bundleId} on device ${udid}`);
34020
- if (!await isPaired(udid)) {
34021
- await waitForPairing(udid, 1e4);
34022
- }
34023
- const installed = await isAppInstalled(bundleId, udid);
34024
- if (!installed) {
34025
- throw new Error(
34026
- `App "${bundleId}" is not installed on the device. Install the app first or verify the bundle identifier is correct.`
34027
- );
34028
- }
34029
- await wakeDevice(udid);
34030
- try {
34031
- logInfo(`Attempting to launch ${bundleId} using idevicedebug...`);
34032
- const result = await runIDeviceTool("idevicedebug", ["-u", udid, "run", bundleId, ...args]);
34033
- const output = (result?.stdout ?? "") + (result?.stderr ?? "");
34034
- if (output.trim()) {
34035
- logInfo(`idevicedebug output: ${output.substring(0, 200)}`);
34036
- }
34037
- if (output.toLowerCase().includes("could not start") && output.toLowerCase().includes("debugserver")) {
34038
- logInfo("idevicedebug requires debugserver, falling back to pymobiledevice3...");
34039
- throw new Error("debugserver_not_available");
34040
- }
34041
- logInfo(`App ${bundleId} launched successfully using idevicedebug`);
34042
- await new Promise((resolve2) => setTimeout(resolve2, 1e3));
34043
- return;
34044
- } catch (error) {
34045
- const errorMsg = error instanceof Error ? error.message : String(error);
34046
- if (errorMsg.includes("debugserver_not_available") || errorMsg.toLowerCase().includes("could not start") || errorMsg.toLowerCase().includes("debugserver")) {
34047
- logInfo("idevicedebug failed, trying pymobiledevice3 for iOS 17+...");
34048
- await launchAppWithPymobiledevice3(bundleId, args, udid);
34049
- return;
34050
- }
34051
- throw error;
34052
- }
34053
- }
34054
- async function launchAppWithPymobiledevice3(bundleId, args, udid) {
34055
- logTask(`Launching app ${bundleId} using pymobiledevice3`);
34056
- const { exec } = await import("node:child_process");
34057
- const { promisify: promisify3 } = await import("node:util");
34058
- const execAsync2 = promisify3(exec);
34059
- try {
34060
- let cmdArgs = [
34061
- "-m",
34062
- "pymobiledevice3",
34063
- "developer",
34064
- "dvt",
34065
- "launch",
34066
- "--udid",
34067
- udid,
34068
- "--kill-existing",
34069
- // Kill existing instance to bring app to foreground
34070
- bundleId,
34071
- ...args
34072
- ];
34073
- let command = `python ${cmdArgs.map((a) => `"${a}"`).join(" ")}`;
34074
- logInfo(`Executing: ${command}`);
34075
- const result = await execAsync2(command, {
34076
- windowsHide: true,
34077
- encoding: "utf8",
34078
- timeout: 3e4
34079
- // 30 second timeout
34080
- });
34081
- const output = result.stdout.toString() + result.stderr.toString();
34082
- if (output.trim()) {
34083
- logInfo(`pymobiledevice3 output: ${output.substring(0, 200)}`);
34084
- }
34085
- if (output.toLowerCase().includes("developer mode") && output.toLowerCase().includes("not enabled")) {
34086
- throw new Error(
34087
- "Developer Mode is not enabled on the device.\nPlease enable it: Settings \u2192 Privacy & Security \u2192 Developer Mode \u2192 Enable"
34088
- );
34089
- }
34090
- if (output.toLowerCase().includes("tunneld") && (output.toLowerCase().includes("unable to connect") || output.toLowerCase().includes("invalidserviceerror"))) {
34091
- logInfo("Tunnel required, retrying with tunnel option...");
34092
- cmdArgs = [
34093
- "-m",
34094
- "pymobiledevice3",
34095
- "developer",
34096
- "dvt",
34097
- "launch",
34098
- "--udid",
34099
- udid,
34100
- "--tunnel",
34101
- udid,
34102
- // Use UDID for tunnel
34103
- "--kill-existing",
34104
- bundleId,
34105
- ...args
34106
- ];
34107
- command = `python ${cmdArgs.map((a) => `"${a}"`).join(" ")}`;
34108
- logInfo(`Retrying with tunnel: ${command}`);
34109
- try {
34110
- const retryResult = await execAsync2(command, {
34111
- windowsHide: true,
34112
- encoding: "utf8",
34113
- timeout: 3e4
34114
- });
34115
- const retryOutput = retryResult.stdout.toString() + retryResult.stderr.toString();
34116
- if (retryOutput.trim()) {
34117
- logInfo(`pymobiledevice3 retry output: ${retryOutput.substring(0, 200)}`);
34118
- }
34119
- if (retryOutput.toLowerCase().includes("tunneld") && retryOutput.toLowerCase().includes("unable to connect")) {
34120
- throw new Error(
34121
- "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."
34122
- );
34123
- }
34124
- logInfo(`App ${bundleId} launched successfully using pymobiledevice3 with tunnel`);
34125
- await new Promise((resolve2) => setTimeout(resolve2, 500));
34126
- return;
34127
- } catch {
34128
- throw new Error(
34129
- "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."
34130
- );
34131
- }
34132
- }
34133
- if (output.toLowerCase().includes("not found") || output.toLowerCase().includes("command not found") || output.toLowerCase().includes("cannot find")) {
34134
- throw new Error(
34135
- "pymobiledevice3 is not installed.\nInstall it with: python -m pip install --user pymobiledevice3"
34136
- );
34137
- }
34138
- if (output.toLowerCase().includes("error") && !output.toLowerCase().includes("warning")) {
34139
- logInfo(`Warning: pymobiledevice3 reported errors: ${output.substring(0, 300)}`);
34140
- }
34141
- logInfo(`App ${bundleId} launched successfully using pymobiledevice3`);
34142
- await new Promise((resolve2) => setTimeout(resolve2, 1e3));
34143
- } catch (error) {
34144
- const errorMsg = error instanceof Error ? error.message : String(error);
34145
- if (errorMsg.includes("not found") || errorMsg.includes("command not found") || errorMsg.includes("cannot find") || errorMsg.includes("No module named")) {
34146
- throw new Error(
34147
- "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."
34148
- );
34149
- }
34150
- throw error;
34151
- }
34152
33965
  }
34153
33966
 
34154
33967
  // src/logic/actions/proxy.ts
@@ -34316,9 +34129,9 @@ var AppleDeviceKit = class {
34316
34129
  *
34317
34130
  * @param ipaPath Path to the IPA file
34318
34131
  */
34319
- async installApp(ipaPath, options, timeBetweenInstalls = 1e4) {
34132
+ async installApp(ipaPath, options) {
34320
34133
  this.ensureNotDisposed();
34321
- return installManagedApp(ipaPath, this.deviceId, timeBetweenInstalls, options);
34134
+ return installManagedApp(ipaPath, this.deviceId, options);
34322
34135
  }
34323
34136
  /**
34324
34137
  * Uninstall an app by bundle ID (uninstall agent)
@@ -34407,6 +34220,18 @@ var AppleDeviceKit = class {
34407
34220
  this.ensureNotDisposed();
34408
34221
  return getActivationState(this.deviceId);
34409
34222
  }
34223
+ /**
34224
+ * Wipe the device
34225
+ */
34226
+ async wipe() {
34227
+ return wipeDevice(this.deviceId);
34228
+ }
34229
+ removeProfile(profileIdentifier) {
34230
+ return removeProfile(profileIdentifier, this.deviceId);
34231
+ }
34232
+ listProfiles() {
34233
+ return listProfiles(this.deviceId);
34234
+ }
34410
34235
  /**
34411
34236
  * Activate the device using the activation flow.
34412
34237
  *