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