@mcesystems/apple-kit 1.0.55 → 1.0.56

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
@@ -32425,6 +32425,131 @@ async function getActivationState(udid) {
32425
32425
  }
32426
32426
  }
32427
32427
 
32428
+ // src/logic/actions/pair.ts
32429
+ async function isPaired(udid) {
32430
+ logTask(`Checking pairing status for ${udid}`);
32431
+ try {
32432
+ const result = await runIDeviceTool("idevicepair", ["-u", udid, "validate"]);
32433
+ if (!result) {
32434
+ return false;
32435
+ }
32436
+ return result.stdout.toLowerCase().includes("success");
32437
+ } catch {
32438
+ return false;
32439
+ }
32440
+ }
32441
+ async function trustDevice(udid, timeout2 = 6e4, onWaitingForTrust) {
32442
+ logTask(`Trusting device ${udid}`);
32443
+ if (await isPaired(udid)) {
32444
+ logInfo(`Device ${udid} is already trusted`);
32445
+ return true;
32446
+ }
32447
+ logInfo(`Initiating pairing for device ${udid}`);
32448
+ try {
32449
+ const pairResult = await pair(udid);
32450
+ if (pairResult) {
32451
+ logInfo(`Device ${udid} paired successfully`);
32452
+ return true;
32453
+ }
32454
+ } catch (error) {
32455
+ logError(`Pairing failed with ${udid}: ${error}`);
32456
+ }
32457
+ logInfo("Please accept the trust dialog on the device...");
32458
+ onWaitingForTrust?.();
32459
+ try {
32460
+ await waitForPairing(udid, timeout2, 1e3);
32461
+ logInfo(`Device ${udid} is now trusted`);
32462
+ return true;
32463
+ } catch {
32464
+ logInfo(`Timeout waiting for trust acceptance on device ${udid}`);
32465
+ return false;
32466
+ }
32467
+ }
32468
+ async function waitForPairing(udid, timeout2 = 12e4, pollInterval = 1e3) {
32469
+ logTask(`Waiting for pairing on device ${udid}`);
32470
+ const startTime = Date.now();
32471
+ while (Date.now() - startTime < timeout2) {
32472
+ if (await isPaired(udid)) {
32473
+ logInfo(`Device ${udid} is now paired`);
32474
+ return true;
32475
+ }
32476
+ await new Promise((resolve5) => setTimeout(resolve5, pollInterval));
32477
+ }
32478
+ throw new Error(`Timeout waiting for device pairing after ${timeout2}ms`);
32479
+ }
32480
+ async function pair(udid) {
32481
+ logTask(`Initiating pairing for device ${udid}`);
32482
+ try {
32483
+ const result = await runIDeviceTool("idevicepair", ["-u", udid, "pair"]);
32484
+ if (!result) {
32485
+ return false;
32486
+ }
32487
+ return result.stdout.toLowerCase().includes("success");
32488
+ } catch (error) {
32489
+ const errorMsg = error instanceof Error ? error.message : String(error);
32490
+ if (errorMsg.includes("Please accept the trust dialog")) {
32491
+ return false;
32492
+ }
32493
+ throw error;
32494
+ }
32495
+ }
32496
+ async function unpair(udid) {
32497
+ logTask(`Un-pairing device ${udid}`);
32498
+ try {
32499
+ const result = await runIDeviceTool("idevicepair", ["-u", udid, "unpair"]);
32500
+ if (!result) {
32501
+ return false;
32502
+ }
32503
+ return result.stdout.toLowerCase().includes("success");
32504
+ } catch {
32505
+ return false;
32506
+ }
32507
+ }
32508
+
32509
+ // src/logic/actions/appState.ts
32510
+ var FRONTMOST_KEYS = [
32511
+ "FrontmostApplicationBundleID",
32512
+ "FrontmostApplicationBundleId",
32513
+ "FrontmostAppBundleIdentifier",
32514
+ "ForegroundApplicationBundleID",
32515
+ "ForegroundApplicationBundleId",
32516
+ "ForegroundAppBundleId",
32517
+ "ApplicationBundleIdentifier",
32518
+ "BundleIdentifier",
32519
+ "bundleIdentifier",
32520
+ "bundleId"
32521
+ ];
32522
+ async function isAppOpened(bundleId, udid) {
32523
+ logTask(`Checking if app ${bundleId} is opened on device ${udid}`);
32524
+ if (!await isPaired(udid)) {
32525
+ await waitForPairing(udid, 1e4);
32526
+ }
32527
+ try {
32528
+ for (const key of FRONTMOST_KEYS) {
32529
+ const result = await runIDeviceTool("ideviceinfo", ["-u", udid, "-k", key]);
32530
+ const output = result?.stdout?.trim() ?? "";
32531
+ if (!output) {
32532
+ continue;
32533
+ }
32534
+ if (isBundleIdMatch(output, bundleId)) {
32535
+ return true;
32536
+ }
32537
+ }
32538
+ } catch (error) {
32539
+ const errorMsg = error instanceof Error ? error.message : String(error);
32540
+ logInfo(`isAppOpened failed: ${errorMsg}`);
32541
+ }
32542
+ return false;
32543
+ }
32544
+ function isBundleIdMatch(value, bundleId) {
32545
+ if (value === bundleId) {
32546
+ return true;
32547
+ }
32548
+ const escaped = bundleId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
32549
+ const matcher = new RegExp(`(^|[^A-Za-z0-9_.-])${escaped}($|[^A-Za-z0-9_.-])`);
32550
+ return matcher.test(value);
32551
+ }
32552
+
32428
32553
  // src/logic/actions/device.ts
32429
32554
  var import_node_fs2 = require("node:fs");
32430
32555
  var import_node_path3 = require("node:path");
@@ -33287,87 +33412,6 @@ function resolveCredentialsPath(options) {
33287
33412
  return process.env.MDM_CRED_PATH ?? process.env.APP_CRED_PATH;
33288
33413
  }
33289
33414
 
33290
- // src/logic/actions/pair.ts
33291
- async function isPaired(udid) {
33292
- logTask(`Checking pairing status for ${udid}`);
33293
- try {
33294
- const result = await runIDeviceTool("idevicepair", ["-u", udid, "validate"]);
33295
- if (!result) {
33296
- return false;
33297
- }
33298
- return result.stdout.toLowerCase().includes("success");
33299
- } catch {
33300
- return false;
33301
- }
33302
- }
33303
- async function trustDevice(udid, timeout2 = 6e4, onWaitingForTrust) {
33304
- logTask(`Trusting device ${udid}`);
33305
- if (await isPaired(udid)) {
33306
- logInfo(`Device ${udid} is already trusted`);
33307
- return true;
33308
- }
33309
- logInfo(`Initiating pairing for device ${udid}`);
33310
- try {
33311
- const pairResult = await pair(udid);
33312
- if (pairResult) {
33313
- logInfo(`Device ${udid} paired successfully`);
33314
- return true;
33315
- }
33316
- } catch (error) {
33317
- logError(`Pairing failed with ${udid}: ${error}`);
33318
- }
33319
- logInfo("Please accept the trust dialog on the device...");
33320
- onWaitingForTrust?.();
33321
- try {
33322
- await waitForPairing(udid, timeout2, 1e3);
33323
- logInfo(`Device ${udid} is now trusted`);
33324
- return true;
33325
- } catch {
33326
- logInfo(`Timeout waiting for trust acceptance on device ${udid}`);
33327
- return false;
33328
- }
33329
- }
33330
- async function waitForPairing(udid, timeout2 = 12e4, pollInterval = 1e3) {
33331
- logTask(`Waiting for pairing on device ${udid}`);
33332
- const startTime = Date.now();
33333
- while (Date.now() - startTime < timeout2) {
33334
- if (await isPaired(udid)) {
33335
- logInfo(`Device ${udid} is now paired`);
33336
- return true;
33337
- }
33338
- await new Promise((resolve5) => setTimeout(resolve5, pollInterval));
33339
- }
33340
- throw new Error(`Timeout waiting for device pairing after ${timeout2}ms`);
33341
- }
33342
- async function pair(udid) {
33343
- logTask(`Initiating pairing for device ${udid}`);
33344
- try {
33345
- const result = await runIDeviceTool("idevicepair", ["-u", udid, "pair"]);
33346
- if (!result) {
33347
- return false;
33348
- }
33349
- return result.stdout.toLowerCase().includes("success");
33350
- } catch (error) {
33351
- const errorMsg = error instanceof Error ? error.message : String(error);
33352
- if (errorMsg.includes("Please accept the trust dialog")) {
33353
- return false;
33354
- }
33355
- throw error;
33356
- }
33357
- }
33358
- async function unpair(udid) {
33359
- logTask(`Un-pairing device ${udid}`);
33360
- try {
33361
- const result = await runIDeviceTool("idevicepair", ["-u", udid, "unpair"]);
33362
- if (!result) {
33363
- return false;
33364
- }
33365
- return result.stdout.toLowerCase().includes("success");
33366
- } catch {
33367
- return false;
33368
- }
33369
- }
33370
-
33371
33415
  // src/logic/actions/install.ts
33372
33416
  async function installLocalApp(ipaPath, udid) {
33373
33417
  logTask(`Installing app ${ipaPath} on device ${udid}`);
@@ -33936,6 +33980,99 @@ function safeParseJson(line) {
33936
33980
  return void 0;
33937
33981
  }
33938
33982
  }
33983
+ function isRecord(value) {
33984
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
33985
+ }
33986
+ function getStringField(record, key) {
33987
+ const value = record[key];
33988
+ return typeof value === "string" ? value : void 0;
33989
+ }
33990
+ function getBooleanField(record, key) {
33991
+ const value = record[key];
33992
+ return typeof value === "boolean" ? value : void 0;
33993
+ }
33994
+ function getNumberField(record, key) {
33995
+ const value = record[key];
33996
+ return typeof value === "number" ? value : void 0;
33997
+ }
33998
+ function getRecordField(record, key) {
33999
+ const value = record[key];
34000
+ return isRecord(value) ? value : void 0;
34001
+ }
34002
+ function toProfileManifest(record) {
34003
+ if (!record) {
34004
+ return void 0;
34005
+ }
34006
+ const description = getStringField(record, "Description");
34007
+ const isActive = getBooleanField(record, "IsActive");
34008
+ if (description === void 0 && isActive === void 0) {
34009
+ return void 0;
34010
+ }
34011
+ return {
34012
+ Description: description,
34013
+ IsActive: isActive
34014
+ };
34015
+ }
34016
+ function toProfileMetadata(record) {
34017
+ if (!record) {
34018
+ return void 0;
34019
+ }
34020
+ const payloadDescription = getStringField(record, "PayloadDescription");
34021
+ const payloadDisplayName = getStringField(record, "PayloadDisplayName");
34022
+ const payloadRemovalDisallowed = getBooleanField(record, "PayloadRemovalDisallowed");
34023
+ const payloadUuid = getStringField(record, "PayloadUUID");
34024
+ const payloadVersion = getNumberField(record, "PayloadVersion");
34025
+ if (payloadDescription === void 0 && payloadDisplayName === void 0 && payloadRemovalDisallowed === void 0 && payloadUuid === void 0 && payloadVersion === void 0) {
34026
+ return void 0;
34027
+ }
34028
+ return {
34029
+ PayloadDescription: payloadDescription,
34030
+ PayloadDisplayName: payloadDisplayName,
34031
+ PayloadRemovalDisallowed: payloadRemovalDisallowed,
34032
+ PayloadUUID: payloadUuid,
34033
+ PayloadVersion: payloadVersion
34034
+ };
34035
+ }
34036
+ function toProfileListEntry(item) {
34037
+ const identifier = getStringField(item, "Identifier");
34038
+ const manifest = toProfileManifest(getRecordField(item, "Manifest"));
34039
+ const metadata = toProfileMetadata(getRecordField(item, "Metadata"));
34040
+ const status = getStringField(item, "Status");
34041
+ if (!identifier && !manifest && !metadata && !status) {
34042
+ return void 0;
34043
+ }
34044
+ return {
34045
+ Identifier: identifier,
34046
+ Manifest: manifest,
34047
+ Metadata: metadata,
34048
+ Status: status
34049
+ };
34050
+ }
34051
+ function parseProfileListOutput(output) {
34052
+ const profiles = [];
34053
+ for (const item of output) {
34054
+ if (Array.isArray(item)) {
34055
+ for (const entry2 of item) {
34056
+ if (!isRecord(entry2)) {
34057
+ continue;
34058
+ }
34059
+ const profileEntry = toProfileListEntry(entry2);
34060
+ if (profileEntry) {
34061
+ profiles.push(profileEntry);
34062
+ }
34063
+ }
34064
+ continue;
34065
+ }
34066
+ if (!isRecord(item)) {
34067
+ continue;
34068
+ }
34069
+ const entry = toProfileListEntry(item);
34070
+ if (entry) {
34071
+ profiles.push(entry);
34072
+ }
34073
+ }
34074
+ return profiles;
34075
+ }
33939
34076
  function createIosCli(iosBinaryPath) {
33940
34077
  return {
33941
34078
  async listDevices() {
@@ -33974,6 +34111,13 @@ function createIosCli(iosBinaryPath) {
33974
34111
  },
33975
34112
  async info(deviceId) {
33976
34113
  return runIosCommand(iosBinaryPath, ["info", "--udid", deviceId]);
34114
+ },
34115
+ async listProfiles(deviceId) {
34116
+ const raw = await runIosCommand(iosBinaryPath, ["profile", "list", "--udid", deviceId]);
34117
+ return {
34118
+ profiles: parseProfileListOutput(raw.output),
34119
+ raw
34120
+ };
33977
34121
  }
33978
34122
  };
33979
34123
  }
@@ -33982,6 +34126,7 @@ function createIosCli(iosBinaryPath) {
33982
34126
  var import_meta3 = {};
33983
34127
  var DEFAULT_RETRIES = 150;
33984
34128
  var DEFAULT_RETRY_DELAY_MS = 1e3;
34129
+ var MCE_MDM_PROFILE_PREFIX = "com.mce.mdm";
33985
34130
  var ActivationFlow = class {
33986
34131
  iosCli;
33987
34132
  mdmClientPromise;
@@ -33996,7 +34141,14 @@ var ActivationFlow = class {
33996
34141
  async run(udid) {
33997
34142
  logTask(`Starting activation flow for device ${udid}`);
33998
34143
  const activationState = await this.getActivationState(udid);
33999
- if (activationState && activationState !== "Activated") {
34144
+ if (activationState === "Activated") {
34145
+ const isEnrolled = await this.isEnrolledToMceMdm(udid);
34146
+ if (isEnrolled) {
34147
+ logInfo("Device already activated and enrolled to MCE MDM. Skipping activation flow.");
34148
+ return async () => {
34149
+ };
34150
+ }
34151
+ } else if (activationState) {
34000
34152
  logInfo(`Activation state is ${activationState}, activating device`);
34001
34153
  await this.retryActivateCommand("activate device", () => this.iosCli.activate(udid));
34002
34154
  } else {
@@ -34008,6 +34160,18 @@ var ActivationFlow = class {
34008
34160
  await this.retryIosCommand("skip steps", () => this.iosCli.skipSteps(udid));
34009
34161
  return () => this.removeWifiProfile(udid, wifiProfileIdentifier);
34010
34162
  }
34163
+ async isEnrolledToMceMdm(udid) {
34164
+ const profiles = await this.listProfiles(udid);
34165
+ return profiles.some((profile) => isMceMdmProfile(profile));
34166
+ }
34167
+ async listProfiles(udid) {
34168
+ const result = await this.retry(
34169
+ "list profiles",
34170
+ () => this.iosCli.listProfiles(udid),
34171
+ (response) => response.raw.exitCode === 0
34172
+ );
34173
+ return result.profiles;
34174
+ }
34011
34175
  async installWifiProfile(udid) {
34012
34176
  const wifiProfile = await generateWifiProfileFromEnv();
34013
34177
  if (!wifiProfile) {
@@ -34165,6 +34329,19 @@ function isActivationSuccess(result) {
34165
34329
  const hasFatal = result.logMessages.some((log) => log.level === "error");
34166
34330
  return !hasFatal;
34167
34331
  }
34332
+ function isMceMdmProfile(profile) {
34333
+ const identifier = profile.Identifier;
34334
+ if (!identifier) {
34335
+ return false;
34336
+ }
34337
+ if (!identifier.startsWith(MCE_MDM_PROFILE_PREFIX)) {
34338
+ return false;
34339
+ }
34340
+ if (profile.Manifest?.IsActive === false) {
34341
+ return false;
34342
+ }
34343
+ return true;
34344
+ }
34168
34345
 
34169
34346
  // src/logic/appleDeviceKit.ts
34170
34347
  var AppleDeviceKit = class {
@@ -34271,6 +34448,15 @@ var AppleDeviceKit = class {
34271
34448
  this.ensureNotDisposed();
34272
34449
  return isAppInstalled(bundleId, this.deviceId);
34273
34450
  }
34451
+ /**
34452
+ * Check if an app is currently opened on the device
34453
+ *
34454
+ * @param bundleId Application bundle identifier
34455
+ */
34456
+ async isAppOpened(bundleId) {
34457
+ this.ensureNotDisposed();
34458
+ return isAppOpened(bundleId, this.deviceId);
34459
+ }
34274
34460
  /**
34275
34461
  * List all installed user applications
34276
34462
  */