@mcesystems/apple-kit 1.0.61 → 1.0.62

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
@@ -32389,16 +32389,91 @@ async function getActivationState(udid) {
32389
32389
  }
32390
32390
 
32391
32391
  // src/logic/actions/device.ts
32392
- var import_node_fs3 = require("node:fs");
32393
- var import_node_path7 = require("node:path");
32392
+ var import_node_fs2 = require("node:fs");
32393
+ var import_node_path3 = require("node:path");
32394
32394
 
32395
- // src/logic/activationFlow.ts
32396
- var import_promises2 = require("node:fs/promises");
32397
- var import_node_os2 = require("node:os");
32398
- var import_node_path6 = require("node:path");
32395
+ // src/logic/dataParser.ts
32396
+ function parsePlistOutput(output) {
32397
+ const result = {};
32398
+ const lines = output.split("\n");
32399
+ for (const line of lines) {
32400
+ const colonIndex = line.indexOf(":");
32401
+ if (colonIndex > 0) {
32402
+ const key = line.substring(0, colonIndex).trim();
32403
+ const value = line.substring(colonIndex + 1).trim();
32404
+ result[key] = value;
32405
+ }
32406
+ }
32407
+ return result;
32408
+ }
32409
+ function parseAppList(output) {
32410
+ const apps = [];
32411
+ const lines = output.trim().split("\n");
32412
+ for (const line of lines) {
32413
+ const match = line.match(/^([^,]+),\s*([^,]+),\s*"?([^"]+)"?/);
32414
+ if (match) {
32415
+ apps.push({
32416
+ bundleId: match[1].trim(),
32417
+ version: match[2].trim(),
32418
+ displayName: match[3].trim(),
32419
+ bundleVersion: ""
32420
+ });
32421
+ }
32422
+ }
32423
+ return apps;
32424
+ }
32425
+
32426
+ // src/logic/actions/device.ts
32427
+ async function getDeviceInfo(udid) {
32428
+ logTask(`Getting device info for ${udid}`);
32429
+ const result = await runIDeviceTool("ideviceinfo", ["-u", udid]);
32430
+ if (!result) {
32431
+ throw new Error("Failed to get device info");
32432
+ }
32433
+ const props = parsePlistOutput(result.stdout);
32434
+ return {
32435
+ deviceName: props.DeviceName || "",
32436
+ productType: props.ProductType || "",
32437
+ productVersion: props.ProductVersion || "",
32438
+ buildVersion: props.BuildVersion || "",
32439
+ serialNumber: props.SerialNumber || "",
32440
+ udid: props.UniqueDeviceID || udid,
32441
+ wifiAddress: props.WiFiAddress || "",
32442
+ bluetoothAddress: props.BluetoothAddress || "",
32443
+ phoneNumber: props.PhoneNumber || "",
32444
+ cpuArchitecture: props.CPUArchitecture || "",
32445
+ hardwareModel: props.HardwareModel || "",
32446
+ modelNumber: props.ModelNumber || "",
32447
+ regionInfo: props.RegionInfo || "",
32448
+ timeZone: props.TimeZone || "",
32449
+ uniqueChipID: props.UniqueChipID || "",
32450
+ isPaired: true
32451
+ // If we can get info, device is paired
32452
+ };
32453
+ }
32454
+ async function info(udid, iosCli2) {
32455
+ logTask(`Getting device info for ${udid}`);
32456
+ const result = await iosCli2.info(udid);
32457
+ if (!result) {
32458
+ throw new Error("Failed to get device info");
32459
+ }
32460
+ return result.output[0];
32461
+ }
32462
+ async function wipeDevice(udid, iosCli2) {
32463
+ logTask(`Wiping device ${udid}`);
32464
+ await iosCli2.wipe(udid);
32465
+ }
32466
+ async function removeProfile(profileIdentifier, udid, iosCli2) {
32467
+ logTask(`Removing profile ${profileIdentifier} from device ${udid}`);
32468
+ await iosCli2.removeProfile(udid, profileIdentifier);
32469
+ }
32470
+ async function listProfiles(udid, iosCli2) {
32471
+ logTask(`Listing profiles for device ${udid}`);
32472
+ return iosCli2.listProfiles(udid);
32473
+ }
32399
32474
 
32400
32475
  // src/utils/mdmClient.ts
32401
- var import_node_path3 = require("node:path");
32476
+ var import_node_path4 = require("node:path");
32402
32477
 
32403
32478
  // ../../node_modules/.pnpm/graphql-request@5.2.0_encoding@0.1.13_graphql@14.7.0/node_modules/graphql-request/build/esm/defaultJsonSerializer.js
32404
32479
  var defaultJsonSerializer = {
@@ -33168,7 +33243,7 @@ function createMdmClient(config) {
33168
33243
  }
33169
33244
  async function createMDMClient() {
33170
33245
  const endpoint = process.env.MDM_ENDPOINT;
33171
- const credPath = (0, import_node_path3.join)(getResourcesPath(), "@clientLocal.json");
33246
+ const credPath = (0, import_node_path4.join)(getResourcesPath(), "@clientLocal.json");
33172
33247
  if (!endpoint || !credPath) {
33173
33248
  return void 0;
33174
33249
  }
@@ -33181,106 +33256,312 @@ async function createMDMClient() {
33181
33256
  });
33182
33257
  }
33183
33258
 
33184
- // src/utils/wifiProfile.ts
33185
- var import_node_crypto2 = require("node:crypto");
33186
-
33187
- // src/utils/templateLoader.ts
33188
- var import_node_fs2 = require("node:fs");
33189
- var import_promises = require("node:fs/promises");
33190
- var import_node_path4 = require("node:path");
33191
- var import_node_url = require("node:url");
33192
- var import_meta = {};
33193
- function resolveEnvPlistDir() {
33194
- const envPath = (0, import_node_path4.join)(getResourcesPath(), "plist");
33195
- if (!(0, import_node_fs2.existsSync)(envPath)) {
33196
- return null;
33197
- }
33198
- const absolutePath = (0, import_node_path4.isAbsolute)(envPath) ? envPath : (0, import_node_path4.join)(process.cwd(), envPath);
33199
- if ((0, import_node_fs2.existsSync)(absolutePath)) {
33200
- return absolutePath;
33259
+ // src/logic/actions/pair.ts
33260
+ async function isPaired(udid) {
33261
+ logTask(`Checking pairing status for ${udid}`);
33262
+ try {
33263
+ const result = await runIDeviceTool("idevicepair", ["-u", udid, "validate"]);
33264
+ if (!result) {
33265
+ return false;
33266
+ }
33267
+ return result.stdout.toLowerCase().includes("success");
33268
+ } catch {
33269
+ return false;
33201
33270
  }
33202
- return null;
33203
33271
  }
33204
- function getPlistDir(overrideDir) {
33205
- if (overrideDir) {
33206
- return (0, import_node_path4.resolve)(overrideDir);
33207
- }
33208
- const envPlistDir = resolveEnvPlistDir();
33209
- if (envPlistDir) {
33210
- return envPlistDir;
33272
+ async function trustDevice(udid, timeout2 = 6e4, onWaitingForTrust) {
33273
+ logTask(`Trusting device ${udid}`);
33274
+ if (await isPaired(udid)) {
33275
+ logInfo(`Device ${udid} is already trusted`);
33276
+ return true;
33211
33277
  }
33212
- let baseDir;
33278
+ logInfo(`Initiating pairing for device ${udid}`);
33213
33279
  try {
33214
- if (typeof import_meta !== "undefined" && import_meta.url) {
33215
- const currentFile = (0, import_node_url.fileURLToPath)(import_meta.url);
33216
- baseDir = (0, import_node_path4.dirname)(currentFile);
33217
- } else {
33218
- baseDir = typeof __dirname !== "undefined" ? __dirname : process.cwd();
33280
+ const pairResult = await pair(udid);
33281
+ if (pairResult) {
33282
+ logInfo(`Device ${udid} paired successfully`);
33283
+ return true;
33219
33284
  }
33220
- } catch {
33221
- baseDir = process.cwd();
33285
+ } catch (error) {
33286
+ logError(`Pairing failed with ${udid}: ${error}`);
33222
33287
  }
33223
- const sourcePlistDir = (0, import_node_path4.join)(baseDir, "../plist");
33224
- if ((0, import_node_fs2.existsSync)(sourcePlistDir)) {
33225
- return sourcePlistDir;
33288
+ logInfo("Please accept the trust dialog on the device...");
33289
+ onWaitingForTrust?.();
33290
+ try {
33291
+ await waitForPairing(udid, timeout2, 1e3);
33292
+ logInfo(`Device ${udid} is now trusted`);
33293
+ return true;
33294
+ } catch {
33295
+ logInfo(`Timeout waiting for trust acceptance on device ${udid}`);
33296
+ return false;
33226
33297
  }
33227
- const distPlistDir = (0, import_node_path4.join)(baseDir, "../plist");
33228
- if ((0, import_node_fs2.existsSync)(distPlistDir)) {
33229
- return distPlistDir;
33298
+ }
33299
+ async function waitForPairing(udid, timeout2 = 12e4, pollInterval = 1e3) {
33300
+ logTask(`Waiting for pairing on device ${udid}`);
33301
+ const startTime = Date.now();
33302
+ while (Date.now() - startTime < timeout2) {
33303
+ if (await isPaired(udid)) {
33304
+ logInfo(`Device ${udid} is now paired`);
33305
+ return true;
33306
+ }
33307
+ await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
33230
33308
  }
33231
- const distPlistDir2 = (0, import_node_path4.join)(baseDir, "../dist/plist");
33232
- if ((0, import_node_fs2.existsSync)(distPlistDir2)) {
33233
- return distPlistDir2;
33309
+ throw new Error(`Timeout waiting for device pairing after ${timeout2}ms`);
33310
+ }
33311
+ async function pair(udid) {
33312
+ logTask(`Initiating pairing for device ${udid}`);
33313
+ try {
33314
+ const result = await runIDeviceTool("idevicepair", ["-u", udid, "pair"]);
33315
+ if (!result) {
33316
+ return false;
33317
+ }
33318
+ return result.stdout.toLowerCase().includes("success");
33319
+ } catch (error) {
33320
+ const errorMsg = error instanceof Error ? error.message : String(error);
33321
+ if (errorMsg.includes("Please accept the trust dialog")) {
33322
+ return false;
33323
+ }
33324
+ throw error;
33234
33325
  }
33235
- const srcPlistFallback = (0, import_node_path4.join)(process.cwd(), "src/plist");
33236
- if ((0, import_node_fs2.existsSync)(srcPlistFallback)) {
33237
- return srcPlistFallback;
33326
+ }
33327
+ async function unpair(udid) {
33328
+ logTask(`Un-pairing device ${udid}`);
33329
+ try {
33330
+ const result = await runIDeviceTool("idevicepair", ["-u", udid, "unpair"]);
33331
+ if (!result) {
33332
+ return false;
33333
+ }
33334
+ return result.stdout.toLowerCase().includes("success");
33335
+ } catch {
33336
+ return false;
33238
33337
  }
33239
- const distPlistFallback = (0, import_node_path4.join)(process.cwd(), "dist/plist");
33240
- if ((0, import_node_fs2.existsSync)(distPlistFallback)) {
33241
- return distPlistFallback;
33338
+ }
33339
+
33340
+ // src/logic/actions/install.ts
33341
+ async function installLocalApp(ipaPath, udid) {
33342
+ logTask(`Installing app ${ipaPath} on device ${udid}`);
33343
+ await runIDeviceTool("ideviceinstaller", ["-u", udid, "install", ipaPath]);
33344
+ }
33345
+ async function installManagedApp(ipaPath, udid, options) {
33346
+ await installLocalApp(ipaPath, udid);
33347
+ const client = await createMDMClient();
33348
+ logTask("Installing app via MDM for management takeover");
33349
+ if (client) {
33350
+ client.installApp(udid, options);
33242
33351
  }
33243
- return (0, import_node_path4.join)(process.cwd(), "src/plist");
33244
33352
  }
33245
- async function loadTemplate(templateName, plistDir) {
33246
- const templatePath = (0, import_node_path4.join)(getPlistDir(plistDir), templateName);
33247
- const content = await (0, import_promises.readFile)(templatePath, "utf-8");
33248
- return content;
33353
+ async function uninstallApp(bundleId, udid) {
33354
+ logTask(`Uninstalling app ${bundleId} from device ${udid}`);
33355
+ if (!await isPaired(udid)) {
33356
+ await waitForPairing(udid, 1e4);
33357
+ }
33358
+ await runIDeviceTool("ideviceinstaller", ["-u", udid, "uninstall", bundleId]);
33249
33359
  }
33250
- function processTemplate(template, variables) {
33251
- let result = template;
33252
- result = result.replace(/\{\{#if\s+(\w+)\}\}([\s\S]*?)\{\{\/if\}\}/g, (_match, key, content) => {
33253
- const value = variables[key];
33254
- if (value && value !== false && value !== "" && value !== null && value !== void 0) {
33255
- return processTemplate(content, variables);
33256
- }
33257
- return "";
33258
- });
33259
- result = result.replace(/\{\{(\w+)\}\}/g, (_match, key) => {
33260
- const value = variables[key];
33261
- if (value === void 0 || value === null) {
33262
- return "";
33263
- }
33264
- if (typeof value === "boolean") {
33265
- return value ? "true" : "false";
33360
+ async function listApps(udid) {
33361
+ logTask(`Listing apps on device ${udid}`);
33362
+ if (!await isPaired(udid)) {
33363
+ await waitForPairing(udid, 1e4);
33364
+ }
33365
+ try {
33366
+ const result = await runIDeviceTool("ideviceinstaller", ["-u", udid, "list"]);
33367
+ if (!result) {
33368
+ return [];
33266
33369
  }
33267
- return escapeXml(String(value));
33268
- });
33269
- return result;
33370
+ const { stdout } = result;
33371
+ return parseAppList(stdout);
33372
+ } catch {
33373
+ return [];
33374
+ }
33270
33375
  }
33271
- function escapeXml(str) {
33272
- return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
33376
+ async function isAppInstalled(bundleId, udid) {
33377
+ logTask(`Checking if app ${bundleId} is installed on device ${udid}`);
33378
+ const apps = await listApps(udid);
33379
+ return apps.some((app) => app.bundleId === bundleId);
33380
+ }
33381
+ async function launchApp(bundleId, _args, udid) {
33382
+ logTask(`Launching app ${bundleId} on device ${udid}`);
33273
33383
  }
33274
33384
 
33275
- // src/utils/wifiProfile.ts
33276
- async function generateWifiProfile(config, options) {
33277
- const {
33278
- ssid,
33279
- password,
33280
- encryptionType = "WPA2",
33281
- autoJoin = true,
33282
- hiddenNetwork = false,
33283
- organizationName = "MCE Systems",
33385
+ // src/logic/actions/proxy.ts
33386
+ var import_node_child_process2 = require("node:child_process");
33387
+ var import_node_path5 = require("node:path");
33388
+ function startPortForward(localPort, devicePort, udid, startupTimeout = 500) {
33389
+ return new Promise((resolve2, reject) => {
33390
+ logTask(`Starting port forward ${localPort} -> ${devicePort} for device ${udid}`);
33391
+ const binPath = getResourcesBinPath();
33392
+ const ext = process.platform === "win32" ? ".exe" : "";
33393
+ const toolPath = binPath ? (0, import_node_path5.join)(binPath, `iproxy${ext}`) : `iproxy${ext}`;
33394
+ const spawnOptions = {
33395
+ windowsHide: true,
33396
+ stdio: ["ignore", "pipe", "pipe"]
33397
+ };
33398
+ if (binPath) {
33399
+ spawnOptions.cwd = binPath;
33400
+ }
33401
+ logInfo(`Spawning iproxy with path: ${toolPath}`);
33402
+ logInfo(`Arguments: ${[localPort.toString(), devicePort.toString(), "-u", udid].join(" ")}`);
33403
+ logInfo(`Options: ${JSON.stringify(spawnOptions)}`);
33404
+ const child = (0, import_node_child_process2.spawn)(
33405
+ toolPath,
33406
+ [localPort.toString(), devicePort.toString(), "-u", udid],
33407
+ spawnOptions
33408
+ );
33409
+ let hasResolved = false;
33410
+ let stderrOutput = "";
33411
+ child.stdout?.on("data", (data) => {
33412
+ logTask(`${data.toString()}`);
33413
+ });
33414
+ child.stderr?.on("data", (data) => {
33415
+ logError(`${data.toString()}`);
33416
+ const msg = data.toString();
33417
+ stderrOutput += msg;
33418
+ if (msg.toLowerCase().includes("error") && !hasResolved) {
33419
+ hasResolved = true;
33420
+ child.kill();
33421
+ reject(new Error(`Port forwarding failed: ${msg}`));
33422
+ }
33423
+ });
33424
+ child.on("error", (error) => {
33425
+ if (!hasResolved) {
33426
+ hasResolved = true;
33427
+ reject(new Error(`Failed to start iproxy: ${error.message}`));
33428
+ }
33429
+ });
33430
+ child.on("exit", (code) => {
33431
+ if (!hasResolved) {
33432
+ hasResolved = true;
33433
+ if (code !== 0 && code !== null) {
33434
+ reject(new Error(`iproxy exited with code ${code}: ${stderrOutput}`));
33435
+ }
33436
+ }
33437
+ });
33438
+ setTimeout(() => {
33439
+ if (!hasResolved) {
33440
+ hasResolved = true;
33441
+ logTask(`Port forward started: ${localPort} -> ${devicePort} for device ${udid}`);
33442
+ resolve2({
33443
+ result: {
33444
+ localPort,
33445
+ devicePort
33446
+ },
33447
+ process: child
33448
+ });
33449
+ }
33450
+ }, startupTimeout);
33451
+ });
33452
+ }
33453
+ function killPortForwardProcess(process2) {
33454
+ if (process2 && !process2.killed) {
33455
+ logTask("Killing port forward process");
33456
+ process2.kill();
33457
+ }
33458
+ }
33459
+
33460
+ // src/logic/activationFlow.ts
33461
+ var import_promises2 = require("node:fs/promises");
33462
+ var import_node_os2 = require("node:os");
33463
+ var import_node_path7 = require("node:path");
33464
+
33465
+ // src/utils/wifiProfile.ts
33466
+ var import_node_crypto2 = require("node:crypto");
33467
+
33468
+ // src/utils/templateLoader.ts
33469
+ var import_node_fs3 = require("node:fs");
33470
+ var import_promises = require("node:fs/promises");
33471
+ var import_node_path6 = require("node:path");
33472
+ var import_node_url = require("node:url");
33473
+ var import_meta = {};
33474
+ function resolveEnvPlistDir() {
33475
+ const envPath = (0, import_node_path6.join)(getResourcesPath(), "plist");
33476
+ if (!(0, import_node_fs3.existsSync)(envPath)) {
33477
+ return null;
33478
+ }
33479
+ const absolutePath = (0, import_node_path6.isAbsolute)(envPath) ? envPath : (0, import_node_path6.join)(process.cwd(), envPath);
33480
+ if ((0, import_node_fs3.existsSync)(absolutePath)) {
33481
+ return absolutePath;
33482
+ }
33483
+ return null;
33484
+ }
33485
+ function getPlistDir(overrideDir) {
33486
+ if (overrideDir) {
33487
+ return (0, import_node_path6.resolve)(overrideDir);
33488
+ }
33489
+ const envPlistDir = resolveEnvPlistDir();
33490
+ if (envPlistDir) {
33491
+ return envPlistDir;
33492
+ }
33493
+ let baseDir;
33494
+ try {
33495
+ if (typeof import_meta !== "undefined" && import_meta.url) {
33496
+ const currentFile = (0, import_node_url.fileURLToPath)(import_meta.url);
33497
+ baseDir = (0, import_node_path6.dirname)(currentFile);
33498
+ } else {
33499
+ baseDir = typeof __dirname !== "undefined" ? __dirname : process.cwd();
33500
+ }
33501
+ } catch {
33502
+ baseDir = process.cwd();
33503
+ }
33504
+ const sourcePlistDir = (0, import_node_path6.join)(baseDir, "../plist");
33505
+ if ((0, import_node_fs3.existsSync)(sourcePlistDir)) {
33506
+ return sourcePlistDir;
33507
+ }
33508
+ const distPlistDir = (0, import_node_path6.join)(baseDir, "../plist");
33509
+ if ((0, import_node_fs3.existsSync)(distPlistDir)) {
33510
+ return distPlistDir;
33511
+ }
33512
+ const distPlistDir2 = (0, import_node_path6.join)(baseDir, "../dist/plist");
33513
+ if ((0, import_node_fs3.existsSync)(distPlistDir2)) {
33514
+ return distPlistDir2;
33515
+ }
33516
+ const srcPlistFallback = (0, import_node_path6.join)(process.cwd(), "src/plist");
33517
+ if ((0, import_node_fs3.existsSync)(srcPlistFallback)) {
33518
+ return srcPlistFallback;
33519
+ }
33520
+ const distPlistFallback = (0, import_node_path6.join)(process.cwd(), "dist/plist");
33521
+ if ((0, import_node_fs3.existsSync)(distPlistFallback)) {
33522
+ return distPlistFallback;
33523
+ }
33524
+ return (0, import_node_path6.join)(process.cwd(), "src/plist");
33525
+ }
33526
+ async function loadTemplate(templateName, plistDir) {
33527
+ const templatePath = (0, import_node_path6.join)(getPlistDir(plistDir), templateName);
33528
+ const content = await (0, import_promises.readFile)(templatePath, "utf-8");
33529
+ return content;
33530
+ }
33531
+ function processTemplate(template, variables) {
33532
+ let result = template;
33533
+ result = result.replace(/\{\{#if\s+(\w+)\}\}([\s\S]*?)\{\{\/if\}\}/g, (_match, key, content) => {
33534
+ const value = variables[key];
33535
+ if (value && value !== false && value !== "" && value !== null && value !== void 0) {
33536
+ return processTemplate(content, variables);
33537
+ }
33538
+ return "";
33539
+ });
33540
+ result = result.replace(/\{\{(\w+)\}\}/g, (_match, key) => {
33541
+ const value = variables[key];
33542
+ if (value === void 0 || value === null) {
33543
+ return "";
33544
+ }
33545
+ if (typeof value === "boolean") {
33546
+ return value ? "true" : "false";
33547
+ }
33548
+ return escapeXml(String(value));
33549
+ });
33550
+ return result;
33551
+ }
33552
+ function escapeXml(str) {
33553
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
33554
+ }
33555
+
33556
+ // src/utils/wifiProfile.ts
33557
+ async function generateWifiProfile(config, options) {
33558
+ const {
33559
+ ssid,
33560
+ password,
33561
+ encryptionType = "WPA2",
33562
+ autoJoin = true,
33563
+ hiddenNetwork = false,
33564
+ organizationName = "MCE Systems",
33284
33565
  displayName = `WiFi - ${ssid}`,
33285
33566
  enterprise = false,
33286
33567
  username,
@@ -33396,91 +33677,225 @@ function parseWifiEapType(value) {
33396
33677
  }
33397
33678
  }
33398
33679
 
33399
- // src/logic/iosCli.ts
33400
- var import_node_child_process2 = require("node:child_process");
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
- }
33413
- function runIosCommand(iosBinaryPath, args) {
33414
- return new Promise((resolve2, reject) => {
33415
- const child = (0, import_node_child_process2.spawn)(iosBinaryPath, args, {
33416
- windowsHide: true,
33417
- stdio: ["ignore", "pipe", "pipe"]
33418
- });
33419
- let stdout = "";
33420
- let stderr = "";
33421
- child.stdout?.on("data", (data) => {
33422
- stdout += data.toString();
33423
- });
33424
- child.stderr?.on("data", (data) => {
33425
- stderr += data.toString();
33426
- });
33427
- child.on("error", (error) => {
33428
- reject(error);
33429
- });
33430
- child.on("close", (code) => {
33431
- console.log(`stdout: ${stdout}`);
33432
- console.log(`stderr: ${stderr}`);
33433
- console.log(`exitCode: ${code}`);
33434
- const output = stdout.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => safeParseJson(line)).filter((item) => Boolean(item));
33435
- const logMessages = stderr.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => safeParseJson(line)).filter((item) => Boolean(item)).map((lineJson) => ({
33436
- level: lineJson.level,
33437
- msg: lineJson.msg,
33438
- timestamp: lineJson.timestamp
33439
- }));
33440
- resolve2({
33441
- command: iosBinaryPath,
33442
- args,
33443
- output,
33444
- logMessages,
33445
- exitCode: code ?? 0
33446
- });
33447
- });
33448
- });
33449
- }
33450
- function safeParseJson(line) {
33451
- try {
33452
- const parsed = JSON.parse(line);
33453
- return parsed && typeof parsed === "object" ? parsed : void 0;
33454
- } catch {
33455
- return void 0;
33680
+ // src/logic/activationFlow.ts
33681
+ var DEFAULT_RETRIES = 150;
33682
+ var DEFAULT_RETRY_DELAY_MS = 1e3;
33683
+ var ActivationFlow = class {
33684
+ iosCli;
33685
+ mdmClientPromise;
33686
+ constructor(iosCli2) {
33687
+ this.iosCli = iosCli2;
33688
+ this.mdmClientPromise = createMDMClient();
33456
33689
  }
33457
- }
33458
- function isRecord(value) {
33459
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
33460
- }
33461
- function getStringField(record, key) {
33462
- const value = record[key];
33463
- return typeof value === "string" ? value : void 0;
33464
- }
33465
- function getBooleanField(record, key) {
33466
- const value = record[key];
33467
- return typeof value === "boolean" ? value : void 0;
33468
- }
33469
- function getNumberField(record, key) {
33470
- const value = record[key];
33471
- return typeof value === "number" ? value : void 0;
33472
- }
33473
- function getRecordField(record, key) {
33474
- const value = record[key];
33475
- return isRecord(value) ? value : void 0;
33476
- }
33477
- function toProfileManifest(record) {
33478
- if (!record) {
33479
- return void 0;
33690
+ async run(udid) {
33691
+ logTask(`Starting activation flow for device ${udid}`);
33692
+ await this.retryActivateCommand("activate device", () => this.iosCli.activate(udid));
33693
+ const wifiProfileIdentifier = await this.installWifiProfile(udid);
33694
+ await this.installMdmProfile(udid);
33695
+ await this.retryIosCommand("skip steps", () => this.iosCli.skipSteps(udid));
33696
+ return () => this.removeWifiProfile(udid, wifiProfileIdentifier);
33480
33697
  }
33481
- const description = getStringField(record, "Description");
33482
- const isActive = getBooleanField(record, "IsActive");
33483
- if (description === void 0 && isActive === void 0) {
33698
+ async installWifiProfile(udid) {
33699
+ const wifiProfile = await generateWifiProfileFromEnv();
33700
+ if (!wifiProfile) {
33701
+ return void 0;
33702
+ }
33703
+ const wifiProfilePath = await saveWifiProfileToTemp(wifiProfile);
33704
+ const wifiProfileIdentifier = getProfileIdentifierFromProfile(wifiProfile);
33705
+ await this.retryIosCommand(
33706
+ "install wifi profile",
33707
+ () => this.iosCli.installProfile(udid, wifiProfilePath)
33708
+ );
33709
+ await removeTempFile(wifiProfilePath, "wifi profile");
33710
+ return wifiProfileIdentifier;
33711
+ }
33712
+ async installMdmProfile(udid) {
33713
+ const client = await this.requireMdmClient();
33714
+ logTask("Installing MDM enrollment profile");
33715
+ const enrollmentProfile = await this.retry(
33716
+ "generate mdm enrollment profile",
33717
+ () => client.generateEnrollmentProfile(udid),
33718
+ (result) => result.status === "OK" && Boolean(result.profile)
33719
+ );
33720
+ if (!enrollmentProfile.profile) {
33721
+ throw new Error("MDM enrollment profile missing from response");
33722
+ }
33723
+ const profilePath = await saveProfileToTemp(enrollmentProfile.profile, "mdm_profile");
33724
+ await this.retryIosCommand(
33725
+ "install mdm profile",
33726
+ () => this.iosCli.installProfile(udid, profilePath)
33727
+ );
33728
+ await removeTempFile(profilePath, "mdm profile");
33729
+ }
33730
+ async removeWifiProfile(udid, profileIdentifier) {
33731
+ if (!profileIdentifier) {
33732
+ return;
33733
+ }
33734
+ logTask("Removing WiFi profile");
33735
+ await this.retryIosCommand(
33736
+ "remove wifi profile",
33737
+ () => this.iosCli.removeProfile(udid, profileIdentifier)
33738
+ );
33739
+ }
33740
+ async requireMdmClient() {
33741
+ const client = await this.mdmClientPromise;
33742
+ if (!client) {
33743
+ throw new Error("MDM client not configured. Set mdm endpoint and credential path.");
33744
+ }
33745
+ return client;
33746
+ }
33747
+ async retryIosCommand(label, command) {
33748
+ return this.retry(label, command, (result) => result.exitCode === 0);
33749
+ }
33750
+ async retryActivateCommand(label, command) {
33751
+ return this.retry(label, command, (result) => isActivationSuccess(result));
33752
+ }
33753
+ async retry(label, command, isSuccess, retries = +(process.env.DEFAULT_RETRIES ?? DEFAULT_RETRIES), retryDelayMs = +(process.env.DEFAULT_RETRY_DELAY_MS ?? DEFAULT_RETRY_DELAY_MS)) {
33754
+ for (let attempt = 0; attempt < retries; attempt += 1) {
33755
+ try {
33756
+ const result = await command();
33757
+ if (isSuccess(result)) {
33758
+ return result;
33759
+ }
33760
+ } catch (error) {
33761
+ const errorMsg = error instanceof Error ? error.message : String(error);
33762
+ logError(`${label} failed: ${errorMsg}`);
33763
+ }
33764
+ logInfo(`Retrying ${label}... ${attempt + 1} of ${retries}`);
33765
+ await new Promise((resolve2) => setTimeout(resolve2, retryDelayMs));
33766
+ }
33767
+ throw new Error(`Failed to ${label} after ${retries} attempts`);
33768
+ }
33769
+ };
33770
+ async function saveProfileToTemp(profile, prefix) {
33771
+ const tempFilePath = (0, import_node_path7.join)((0, import_node_os2.tmpdir)(), `mce_${prefix}_${Date.now()}.mobileconfig`);
33772
+ await (0, import_promises2.writeFile)(tempFilePath, profile, "utf-8");
33773
+ logInfo(`Profile saved to: ${tempFilePath}`);
33774
+ return tempFilePath;
33775
+ }
33776
+ async function removeTempFile(filePath, label) {
33777
+ try {
33778
+ await (0, import_promises2.unlink)(filePath);
33779
+ logInfo(`Removed ${label} temp file: ${filePath}`);
33780
+ } catch (error) {
33781
+ const errorMsg = error instanceof Error ? error.message : String(error);
33782
+ logError(`Failed to remove ${label} temp file: ${errorMsg}`);
33783
+ }
33784
+ }
33785
+ function getProfileIdentifierFromProfile(profile) {
33786
+ const pattern = /<key>PayloadIdentifier<\/key>\s*<string>([^<]+)<\/string>/g;
33787
+ const matches = [];
33788
+ let match = pattern.exec(profile);
33789
+ while (match) {
33790
+ matches.push(match[1].trim());
33791
+ match = pattern.exec(profile);
33792
+ }
33793
+ if (matches.length === 0) {
33794
+ return void 0;
33795
+ }
33796
+ return matches[matches.length - 1];
33797
+ }
33798
+ function resolveIosBinaryPath() {
33799
+ const platform = process.platform;
33800
+ const binaryName = platform === "win32" ? "ios.exe" : "ios";
33801
+ return (0, import_node_path7.join)(getResourcesBinPath(), binaryName);
33802
+ }
33803
+ function isActivationSuccess(result) {
33804
+ if (result.exitCode !== 0) {
33805
+ return false;
33806
+ }
33807
+ if (result.logMessages.length === 0) {
33808
+ return true;
33809
+ }
33810
+ const hasFatal = result.logMessages.some((log) => log.level === "error");
33811
+ return !hasFatal;
33812
+ }
33813
+
33814
+ // src/logic/iosCli.ts
33815
+ var import_node_child_process3 = require("node:child_process");
33816
+ var import_node_path8 = require("node:path");
33817
+ var ios;
33818
+ function iosCli() {
33819
+ const iosBinaryPath = resolveIosBinaryPath();
33820
+ if (!iosBinaryPath) {
33821
+ throw new Error("iosBinaryPath is required. Provide iosBinaryPath or resourcesDir.");
33822
+ }
33823
+ return createIosCli(iosBinaryPath);
33824
+ }
33825
+ if (!ios) {
33826
+ ios = iosCli();
33827
+ }
33828
+ function runIosCommand(iosBinaryPath, args) {
33829
+ return new Promise((resolve2, reject) => {
33830
+ const child = (0, import_node_child_process3.spawn)(iosBinaryPath, args, {
33831
+ windowsHide: true,
33832
+ stdio: ["ignore", "pipe", "pipe"]
33833
+ });
33834
+ let stdout = "";
33835
+ let stderr = "";
33836
+ child.stdout?.on("data", (data) => {
33837
+ stdout += data.toString();
33838
+ });
33839
+ child.stderr?.on("data", (data) => {
33840
+ stderr += data.toString();
33841
+ });
33842
+ child.on("error", (error) => {
33843
+ reject(error);
33844
+ });
33845
+ child.on("close", (code) => {
33846
+ console.log(`stdout: ${stdout}`);
33847
+ console.log(`stderr: ${stderr}`);
33848
+ console.log(`exitCode: ${code}`);
33849
+ const output = stdout.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => safeParseJson(line)).filter((item) => Boolean(item));
33850
+ const logMessages = stderr.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => safeParseJson(line)).filter((item) => Boolean(item)).map((lineJson) => ({
33851
+ level: lineJson.level,
33852
+ msg: lineJson.msg,
33853
+ timestamp: lineJson.timestamp
33854
+ }));
33855
+ resolve2({
33856
+ command: iosBinaryPath,
33857
+ args,
33858
+ output,
33859
+ logMessages,
33860
+ exitCode: code ?? 0
33861
+ });
33862
+ });
33863
+ });
33864
+ }
33865
+ function safeParseJson(line) {
33866
+ try {
33867
+ const parsed = JSON.parse(line);
33868
+ return parsed && typeof parsed === "object" ? parsed : void 0;
33869
+ } catch {
33870
+ return void 0;
33871
+ }
33872
+ }
33873
+ function isRecord(value) {
33874
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
33875
+ }
33876
+ function getStringField(record, key) {
33877
+ const value = record[key];
33878
+ return typeof value === "string" ? value : void 0;
33879
+ }
33880
+ function getBooleanField(record, key) {
33881
+ const value = record[key];
33882
+ return typeof value === "boolean" ? value : void 0;
33883
+ }
33884
+ function getNumberField(record, key) {
33885
+ const value = record[key];
33886
+ return typeof value === "number" ? value : void 0;
33887
+ }
33888
+ function getRecordField(record, key) {
33889
+ const value = record[key];
33890
+ return isRecord(value) ? value : void 0;
33891
+ }
33892
+ function toProfileManifest(record) {
33893
+ if (!record) {
33894
+ return void 0;
33895
+ }
33896
+ const description = getStringField(record, "Description");
33897
+ const isActive = getBooleanField(record, "IsActive");
33898
+ if (description === void 0 && isActive === void 0) {
33484
33899
  return void 0;
33485
33900
  }
33486
33901
  return {
@@ -33572,7 +33987,7 @@ function createIosCli(iosBinaryPath) {
33572
33987
  return runIosCommand(iosBinaryPath, [
33573
33988
  "prepare",
33574
33989
  "--skip-all",
33575
- `--certfile=${(0, import_node_path5.join)(resourcesDir2, "cert.der")}`,
33990
+ `--certfile=${(0, import_node_path8.join)(resourcesDir2, "cert.der")}`,
33576
33991
  `--orgname=${process.env.ORGANIZATION_NAME}`,
33577
33992
  "--udid",
33578
33993
  deviceId
@@ -33604,454 +34019,26 @@ function createIosCli(iosBinaryPath) {
33604
34019
  }
33605
34020
  };
33606
34021
  }
33607
- var iosCli_default = ios;
33608
34022
 
33609
- // src/logic/activationFlow.ts
33610
- var DEFAULT_RETRIES = 150;
33611
- var DEFAULT_RETRY_DELAY_MS = 1e3;
33612
- var ActivationFlow = class {
33613
- iosCli;
33614
- mdmClientPromise;
33615
- constructor() {
34023
+ // src/logic/appleDeviceKit.ts
34024
+ var AppleDeviceKit = class {
34025
+ constructor(udid, logicalPort) {
34026
+ this.logicalPort = logicalPort;
34027
+ this.deviceId = udid;
34028
+ logInfo(
34029
+ `AppleDeviceKit initialized for device: ${this.deviceId}, logical port: ${this.logicalPort}`
34030
+ );
33616
34031
  const iosBinaryPath = resolveIosBinaryPath();
33617
34032
  if (!iosBinaryPath) {
33618
34033
  throw new Error("iosBinaryPath is required. Provide iosBinaryPath or resourcesDir.");
33619
34034
  }
33620
34035
  this.iosCli = createIosCli(iosBinaryPath);
33621
- this.mdmClientPromise = createMDMClient();
33622
- }
33623
- async run(udid) {
33624
- logTask(`Starting activation flow for device ${udid}`);
33625
- await this.retryActivateCommand("activate device", () => this.iosCli.activate(udid));
33626
- const wifiProfileIdentifier = await this.installWifiProfile(udid);
33627
- await this.installMdmProfile(udid);
33628
- await this.retryIosCommand("skip steps", () => this.iosCli.skipSteps(udid));
33629
- return () => this.removeWifiProfile(udid, wifiProfileIdentifier);
33630
- }
33631
- async installWifiProfile(udid) {
33632
- const wifiProfile = await generateWifiProfileFromEnv();
33633
- if (!wifiProfile) {
33634
- return void 0;
33635
- }
33636
- const wifiProfilePath = await saveWifiProfileToTemp(wifiProfile);
33637
- const wifiProfileIdentifier = getProfileIdentifierFromProfile(wifiProfile);
33638
- await this.retryIosCommand(
33639
- "install wifi profile",
33640
- () => this.iosCli.installProfile(udid, wifiProfilePath)
33641
- );
33642
- await removeTempFile(wifiProfilePath, "wifi profile");
33643
- return wifiProfileIdentifier;
33644
- }
33645
- async installMdmProfile(udid) {
33646
- const client = await this.requireMdmClient();
33647
- logTask("Installing MDM enrollment profile");
33648
- const enrollmentProfile = await this.retry(
33649
- "generate mdm enrollment profile",
33650
- () => client.generateEnrollmentProfile(udid),
33651
- (result) => result.status === "OK" && Boolean(result.profile)
33652
- );
33653
- if (!enrollmentProfile.profile) {
33654
- throw new Error("MDM enrollment profile missing from response");
33655
- }
33656
- const profilePath = await saveProfileToTemp(enrollmentProfile.profile, "mdm_profile");
33657
- await this.retryIosCommand(
33658
- "install mdm profile",
33659
- () => this.iosCli.installProfile(udid, profilePath)
33660
- );
33661
- await removeTempFile(profilePath, "mdm profile");
33662
- }
33663
- async removeWifiProfile(udid, profileIdentifier) {
33664
- if (!profileIdentifier) {
33665
- return;
33666
- }
33667
- logTask("Removing WiFi profile");
33668
- await this.retryIosCommand(
33669
- "remove wifi profile",
33670
- () => this.iosCli.removeProfile(udid, profileIdentifier)
33671
- );
33672
- }
33673
- async requireMdmClient() {
33674
- const client = await this.mdmClientPromise;
33675
- if (!client) {
33676
- throw new Error("MDM client not configured. Set mdm endpoint and credential path.");
33677
- }
33678
- return client;
33679
- }
33680
- async retryIosCommand(label, command) {
33681
- return this.retry(label, command, (result) => result.exitCode === 0);
33682
- }
33683
- async retryActivateCommand(label, command) {
33684
- return this.retry(label, command, (result) => isActivationSuccess(result));
33685
- }
33686
- async retry(label, command, isSuccess, retries = +(process.env.DEFAULT_RETRIES ?? DEFAULT_RETRIES), retryDelayMs = +(process.env.DEFAULT_RETRY_DELAY_MS ?? DEFAULT_RETRY_DELAY_MS)) {
33687
- for (let attempt = 0; attempt < retries; attempt += 1) {
33688
- try {
33689
- const result = await command();
33690
- if (isSuccess(result)) {
33691
- return result;
33692
- }
33693
- } catch (error) {
33694
- const errorMsg = error instanceof Error ? error.message : String(error);
33695
- logError(`${label} failed: ${errorMsg}`);
33696
- }
33697
- logInfo(`Retrying ${label}... ${attempt + 1} of ${retries}`);
33698
- await new Promise((resolve2) => setTimeout(resolve2, retryDelayMs));
33699
- }
33700
- throw new Error(`Failed to ${label} after ${retries} attempts`);
33701
- }
33702
- };
33703
- async function saveProfileToTemp(profile, prefix) {
33704
- const tempFilePath = (0, import_node_path6.join)((0, import_node_os2.tmpdir)(), `mce_${prefix}_${Date.now()}.mobileconfig`);
33705
- await (0, import_promises2.writeFile)(tempFilePath, profile, "utf-8");
33706
- logInfo(`Profile saved to: ${tempFilePath}`);
33707
- return tempFilePath;
33708
- }
33709
- async function removeTempFile(filePath, label) {
33710
- try {
33711
- await (0, import_promises2.unlink)(filePath);
33712
- logInfo(`Removed ${label} temp file: ${filePath}`);
33713
- } catch (error) {
33714
- const errorMsg = error instanceof Error ? error.message : String(error);
33715
- logError(`Failed to remove ${label} temp file: ${errorMsg}`);
33716
- }
33717
- }
33718
- function getProfileIdentifierFromProfile(profile) {
33719
- const pattern = /<key>PayloadIdentifier<\/key>\s*<string>([^<]+)<\/string>/g;
33720
- const matches = [];
33721
- let match = pattern.exec(profile);
33722
- while (match) {
33723
- matches.push(match[1].trim());
33724
- match = pattern.exec(profile);
33725
- }
33726
- if (matches.length === 0) {
33727
- return void 0;
33728
- }
33729
- return matches[matches.length - 1];
33730
- }
33731
- function resolveIosBinaryPath() {
33732
- const platform = process.platform;
33733
- const binaryName = platform === "win32" ? "ios.exe" : "ios";
33734
- return (0, import_node_path6.join)(getResourcesBinPath(), binaryName);
33735
- }
33736
- function isActivationSuccess(result) {
33737
- if (result.exitCode !== 0) {
33738
- return false;
33739
- }
33740
- if (result.logMessages.length === 0) {
33741
- return true;
33742
- }
33743
- const hasFatal = result.logMessages.some((log) => log.level === "error");
33744
- return !hasFatal;
33745
- }
33746
-
33747
- // src/logic/dataParser.ts
33748
- function parsePlistOutput(output) {
33749
- const result = {};
33750
- const lines = output.split("\n");
33751
- for (const line of lines) {
33752
- const colonIndex = line.indexOf(":");
33753
- if (colonIndex > 0) {
33754
- const key = line.substring(0, colonIndex).trim();
33755
- const value = line.substring(colonIndex + 1).trim();
33756
- result[key] = value;
33757
- }
33758
- }
33759
- return result;
33760
- }
33761
- function parseAppList(output) {
33762
- const apps = [];
33763
- const lines = output.trim().split("\n");
33764
- for (const line of lines) {
33765
- const match = line.match(/^([^,]+),\s*([^,]+),\s*"?([^"]+)"?/);
33766
- if (match) {
33767
- apps.push({
33768
- bundleId: match[1].trim(),
33769
- version: match[2].trim(),
33770
- displayName: match[3].trim(),
33771
- bundleVersion: ""
33772
- });
33773
- }
33774
- }
33775
- return apps;
33776
- }
33777
-
33778
- // src/logic/actions/device.ts
33779
- async function getDeviceInfo(udid) {
33780
- logTask(`Getting device info for ${udid}`);
33781
- const result = await runIDeviceTool("ideviceinfo", ["-u", udid]);
33782
- if (!result) {
33783
- throw new Error("Failed to get device info");
33784
- }
33785
- const props = parsePlistOutput(result.stdout);
33786
- return {
33787
- deviceName: props.DeviceName || "",
33788
- productType: props.ProductType || "",
33789
- productVersion: props.ProductVersion || "",
33790
- buildVersion: props.BuildVersion || "",
33791
- serialNumber: props.SerialNumber || "",
33792
- udid: props.UniqueDeviceID || udid,
33793
- wifiAddress: props.WiFiAddress || "",
33794
- bluetoothAddress: props.BluetoothAddress || "",
33795
- phoneNumber: props.PhoneNumber || "",
33796
- cpuArchitecture: props.CPUArchitecture || "",
33797
- hardwareModel: props.HardwareModel || "",
33798
- modelNumber: props.ModelNumber || "",
33799
- regionInfo: props.RegionInfo || "",
33800
- timeZone: props.TimeZone || "",
33801
- uniqueChipID: props.UniqueChipID || "",
33802
- isPaired: true
33803
- // If we can get info, device is paired
33804
- };
33805
- }
33806
- async function info(udid) {
33807
- logTask(`Getting device info for ${udid}`);
33808
- const iosBinaryPath = resolveIosBinaryPath();
33809
- if (!iosBinaryPath) {
33810
- throw new Error("iosBinaryPath is required. Provide iosBinaryPath or resourcesDir.");
33811
- }
33812
- const iosCli2 = createIosCli(iosBinaryPath);
33813
- const result = await iosCli2.info(udid);
33814
- if (!result) {
33815
- throw new Error("Failed to get device info");
33816
- }
33817
- return result.output[0];
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
- }
33840
-
33841
- // src/logic/actions/pair.ts
33842
- async function isPaired(udid) {
33843
- logTask(`Checking pairing status for ${udid}`);
33844
- try {
33845
- const result = await runIDeviceTool("idevicepair", ["-u", udid, "validate"]);
33846
- if (!result) {
33847
- return false;
33848
- }
33849
- return result.stdout.toLowerCase().includes("success");
33850
- } catch {
33851
- return false;
33852
- }
33853
- }
33854
- async function trustDevice(udid, timeout2 = 6e4, onWaitingForTrust) {
33855
- logTask(`Trusting device ${udid}`);
33856
- if (await isPaired(udid)) {
33857
- logInfo(`Device ${udid} is already trusted`);
33858
- return true;
33859
- }
33860
- logInfo(`Initiating pairing for device ${udid}`);
33861
- try {
33862
- const pairResult = await pair(udid);
33863
- if (pairResult) {
33864
- logInfo(`Device ${udid} paired successfully`);
33865
- return true;
33866
- }
33867
- } catch (error) {
33868
- logError(`Pairing failed with ${udid}: ${error}`);
33869
- }
33870
- logInfo("Please accept the trust dialog on the device...");
33871
- onWaitingForTrust?.();
33872
- try {
33873
- await waitForPairing(udid, timeout2, 1e3);
33874
- logInfo(`Device ${udid} is now trusted`);
33875
- return true;
33876
- } catch {
33877
- logInfo(`Timeout waiting for trust acceptance on device ${udid}`);
33878
- return false;
33879
- }
33880
- }
33881
- async function waitForPairing(udid, timeout2 = 12e4, pollInterval = 1e3) {
33882
- logTask(`Waiting for pairing on device ${udid}`);
33883
- const startTime = Date.now();
33884
- while (Date.now() - startTime < timeout2) {
33885
- if (await isPaired(udid)) {
33886
- logInfo(`Device ${udid} is now paired`);
33887
- return true;
33888
- }
33889
- await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
33890
- }
33891
- throw new Error(`Timeout waiting for device pairing after ${timeout2}ms`);
33892
- }
33893
- async function pair(udid) {
33894
- logTask(`Initiating pairing for device ${udid}`);
33895
- try {
33896
- const result = await runIDeviceTool("idevicepair", ["-u", udid, "pair"]);
33897
- if (!result) {
33898
- return false;
33899
- }
33900
- return result.stdout.toLowerCase().includes("success");
33901
- } catch (error) {
33902
- const errorMsg = error instanceof Error ? error.message : String(error);
33903
- if (errorMsg.includes("Please accept the trust dialog")) {
33904
- return false;
33905
- }
33906
- throw error;
33907
- }
33908
- }
33909
- async function unpair(udid) {
33910
- logTask(`Un-pairing device ${udid}`);
33911
- try {
33912
- const result = await runIDeviceTool("idevicepair", ["-u", udid, "unpair"]);
33913
- if (!result) {
33914
- return false;
33915
- }
33916
- return result.stdout.toLowerCase().includes("success");
33917
- } catch {
33918
- return false;
33919
- }
33920
- }
33921
-
33922
- // src/logic/actions/install.ts
33923
- async function installLocalApp(ipaPath, udid) {
33924
- logTask(`Installing app ${ipaPath} on device ${udid}`);
33925
- await runIDeviceTool("ideviceinstaller", ["-u", udid, "install", ipaPath]);
33926
- }
33927
- async function installManagedApp(ipaPath, udid, options) {
33928
- await installLocalApp(ipaPath, udid);
33929
- const client = await createMDMClient();
33930
- logTask("Installing app via MDM for management takeover");
33931
- if (client) {
33932
- client.installApp(udid, options);
33933
- }
33934
- }
33935
- async function uninstallApp(bundleId, udid) {
33936
- logTask(`Uninstalling app ${bundleId} from device ${udid}`);
33937
- if (!await isPaired(udid)) {
33938
- await waitForPairing(udid, 1e4);
33939
- }
33940
- await runIDeviceTool("ideviceinstaller", ["-u", udid, "uninstall", bundleId]);
33941
- }
33942
- async function listApps(udid) {
33943
- logTask(`Listing apps on device ${udid}`);
33944
- if (!await isPaired(udid)) {
33945
- await waitForPairing(udid, 1e4);
33946
- }
33947
- try {
33948
- const result = await runIDeviceTool("ideviceinstaller", ["-u", udid, "list"]);
33949
- if (!result) {
33950
- return [];
33951
- }
33952
- const { stdout } = result;
33953
- return parseAppList(stdout);
33954
- } catch {
33955
- return [];
33956
- }
33957
- }
33958
- async function isAppInstalled(bundleId, udid) {
33959
- logTask(`Checking if app ${bundleId} is installed on device ${udid}`);
33960
- const apps = await listApps(udid);
33961
- return apps.some((app) => app.bundleId === bundleId);
33962
- }
33963
- async function launchApp(bundleId, _args, udid) {
33964
- logTask(`Launching app ${bundleId} on device ${udid}`);
33965
- }
33966
-
33967
- // src/logic/actions/proxy.ts
33968
- var import_node_child_process3 = require("node:child_process");
33969
- var import_node_path8 = require("node:path");
33970
- function startPortForward(localPort, devicePort, udid, startupTimeout = 500) {
33971
- return new Promise((resolve2, reject) => {
33972
- logTask(`Starting port forward ${localPort} -> ${devicePort} for device ${udid}`);
33973
- const binPath = getResourcesBinPath();
33974
- const ext = process.platform === "win32" ? ".exe" : "";
33975
- const toolPath = binPath ? (0, import_node_path8.join)(binPath, `iproxy${ext}`) : `iproxy${ext}`;
33976
- const spawnOptions = {
33977
- windowsHide: true,
33978
- stdio: ["ignore", "pipe", "pipe"]
33979
- };
33980
- if (binPath) {
33981
- spawnOptions.cwd = binPath;
33982
- }
33983
- logInfo(`Spawning iproxy with path: ${toolPath}`);
33984
- logInfo(`Arguments: ${[localPort.toString(), devicePort.toString(), "-u", udid].join(" ")}`);
33985
- logInfo(`Options: ${JSON.stringify(spawnOptions)}`);
33986
- const child = (0, import_node_child_process3.spawn)(
33987
- toolPath,
33988
- [localPort.toString(), devicePort.toString(), "-u", udid],
33989
- spawnOptions
33990
- );
33991
- let hasResolved = false;
33992
- let stderrOutput = "";
33993
- child.stdout?.on("data", (data) => {
33994
- logTask(`${data.toString()}`);
33995
- });
33996
- child.stderr?.on("data", (data) => {
33997
- logError(`${data.toString()}`);
33998
- const msg = data.toString();
33999
- stderrOutput += msg;
34000
- if (msg.toLowerCase().includes("error") && !hasResolved) {
34001
- hasResolved = true;
34002
- child.kill();
34003
- reject(new Error(`Port forwarding failed: ${msg}`));
34004
- }
34005
- });
34006
- child.on("error", (error) => {
34007
- if (!hasResolved) {
34008
- hasResolved = true;
34009
- reject(new Error(`Failed to start iproxy: ${error.message}`));
34010
- }
34011
- });
34012
- child.on("exit", (code) => {
34013
- if (!hasResolved) {
34014
- hasResolved = true;
34015
- if (code !== 0 && code !== null) {
34016
- reject(new Error(`iproxy exited with code ${code}: ${stderrOutput}`));
34017
- }
34018
- }
34019
- });
34020
- setTimeout(() => {
34021
- if (!hasResolved) {
34022
- hasResolved = true;
34023
- logTask(`Port forward started: ${localPort} -> ${devicePort} for device ${udid}`);
34024
- resolve2({
34025
- result: {
34026
- localPort,
34027
- devicePort
34028
- },
34029
- process: child
34030
- });
34031
- }
34032
- }, startupTimeout);
34033
- });
34034
- }
34035
- function killPortForwardProcess(process2) {
34036
- if (process2 && !process2.killed) {
34037
- logTask("Killing port forward process");
34038
- process2.kill();
34039
- }
34040
- }
34041
-
34042
- // src/logic/appleDeviceKit.ts
34043
- var AppleDeviceKit = class {
34044
- constructor(udid, logicalPort) {
34045
- this.logicalPort = logicalPort;
34046
- this.deviceId = udid;
34047
- logInfo(
34048
- `AppleDeviceKit initialized for device: ${this.deviceId}, logical port: ${this.logicalPort}`
34049
- );
34050
34036
  }
34051
34037
  deviceId;
34052
34038
  proxyProcess = null;
34053
34039
  localDevicePort = null;
34054
34040
  isDisposed = false;
34041
+ iosCli;
34055
34042
  static setResourcesDir(dir) {
34056
34043
  setResourcesDir(dir);
34057
34044
  }
@@ -34072,7 +34059,7 @@ var AppleDeviceKit = class {
34072
34059
  }
34073
34060
  async info() {
34074
34061
  this.ensureNotDisposed();
34075
- return info(this.deviceId);
34062
+ return info(this.deviceId, this.iosCli);
34076
34063
  }
34077
34064
  /**
34078
34065
  * Check if device is paired/trusted with this computer
@@ -34224,13 +34211,13 @@ var AppleDeviceKit = class {
34224
34211
  * Wipe the device
34225
34212
  */
34226
34213
  async wipe() {
34227
- return wipeDevice(this.deviceId);
34214
+ return wipeDevice(this.deviceId, this.iosCli);
34228
34215
  }
34229
- removeProfile(profileIdentifier) {
34230
- return removeProfile(profileIdentifier, this.deviceId);
34216
+ async removeProfile(profileIdentifier) {
34217
+ return removeProfile(profileIdentifier, this.deviceId, this.iosCli);
34231
34218
  }
34232
- listProfiles() {
34233
- return listProfiles(this.deviceId);
34219
+ async listProfiles() {
34220
+ return listProfiles(this.deviceId, this.iosCli);
34234
34221
  }
34235
34222
  /**
34236
34223
  * Activate the device using the activation flow.
@@ -34243,7 +34230,7 @@ var AppleDeviceKit = class {
34243
34230
  */
34244
34231
  async activate() {
34245
34232
  this.ensureNotDisposed();
34246
- const flow = new ActivationFlow();
34233
+ const flow = new ActivationFlow(this.iosCli);
34247
34234
  return await flow.run(this.deviceId);
34248
34235
  }
34249
34236
  /**