# @mcesystems/apple-kit

iOS device management toolkit using libimobiledevice command-line tools. Provides device detection, app installation/uninstallation, port forwarding, activation, and device property access.

## Features

- **Device Detection**: Monitor iOS device connections via USB plug-and-play
- **App Management**: Install and uninstall iOS applications (.ipa files)
- **Launch Apps**: Start applications on the device
- **Port Forwarding**: Forward local ports to device ports (for debugging, etc.)
- **Device Activation**: Check and manage device activation state
- **Trust/Pairing**: Handle device trust and pairing
- **Device Info**: Access device properties (name, model, iOS version, UDID, etc.)
- **Cross-platform**: Works on Windows, macOS, and Linux

## Installation

```bash
npm install @mcesystems/apple-kit
```

## Requirements

- Node.js 18+
- iOS device connected via USB
- Device must be trusted/paired with the computer
- libimobiledevice binaries (included for Windows, see BUILD.md for other platforms)
- iTunes installed OR run the bundled `usbmuxd` (see below)

## Usage

### Device Monitoring

```typescript
import { DevicesMonitor } from '@mcesystems/apple-kit';

const monitor = new DevicesMonitor({
  logicalPortMap: {
    "Port_#0005.Hub_#0002": 1,
    "Port_#0006.Hub_#0002": 2
  }
});

const events = await monitor.startTracking();

events.on('added', async (deviceKit) => {
  console.log(`iOS device connected: ${deviceKit.getDeviceId()}`);
  const info = await deviceKit.getDeviceInfo();
  console.log(`  ${info.deviceName} - iOS ${info.productVersion}`);
});

events.on('removed', (deviceId, port) => {
  console.log(`iOS device disconnected: ${deviceId}`);
});

// Later: stop monitoring
await monitor.stopTracking();
```

### Install/Uninstall Agent

```typescript
import { AppleDeviceKit } from '@mcesystems/apple-kit';

const device = new AppleDeviceKit('device-udid', 1);

// Install an agent/app
await device.installApp('/path/to/agent.ipa');

// Check if installed
const isInstalled = await device.isAppInstalled('com.example.agent');

// List all installed apps
const apps = await device.listApps();

// Uninstall an agent/app
await device.uninstallApp('com.example.agent');
```

### Device Info

```typescript
const device = new AppleDeviceKit('device-udid', 1);

const info = await device.getDeviceInfo();
console.log(`Device: ${info.deviceName}`);
console.log(`Model: ${info.productType}`);
console.log(`iOS: ${info.productVersion} (${info.buildVersion})`);
console.log(`Serial: ${info.serialNumber}`);
console.log(`UDID: ${info.udid}`);
```

### Trust/Pairing

```typescript
const device = new AppleDeviceKit('device-udid', 1);

// Check if device is trusted
const isPaired = await device.isPaired();

// Initiate pairing (user must accept on device)
await device.pair();

// Wait for user to accept trust dialog
await device.waitForPairing(60000); // 60 second timeout

// Unpair device
await device.unpair();
```

### Launch Application

```typescript
const device = new AppleDeviceKit('device-udid', 1);

// Launch an app
await device.launchApp('com.example.myapp');

// Launch with arguments
await device.launchApp('com.example.myapp', ['--debug', '--port=8080']);
```

### Port Forwarding

```typescript
const device = new AppleDeviceKit('device-udid', 1);

// Forward local port 8080 to device port 8080
const forward = device.startPortForward(8080, 8080);

// Use the forwarded connection...
// connect to localhost:8080 to reach device:8080

// Stop forwarding when done
forward.stop();

// Or use async version that waits for ready
const forwardAsync = await device.startPortForwardAsync(8080, 8080);
```

### Activation

```typescript
const device = new AppleDeviceKit('device-udid', 1);

// Get activation state
const state = await device.getActivationState();
console.log(`Activated: ${state.isActivated}`);
console.log(`State: ${state.activationState}`);

// Activate device (requires valid activation record)
await device.activate();

// Deactivate device
await device.deactivate();
```

### Running Without iTunes (usbmuxd)

On Windows, iTunes provides the Apple Mobile Device Service for USB communication. If you don't have iTunes installed, you can run the bundled `usbmuxd`:

```typescript
import { startUsbmuxd, stopUsbmuxd, ensureUsbmuxd } from '@mcesystems/apple-kit';

// Start usbmuxd daemon (required if iTunes is not installed)
const daemon = startUsbmuxd();

// Or ensure it's running (starts if not already running)
ensureUsbmuxd();

// Now you can use device operations...
const devices = await AppleDeviceKit.listDevices();

// When done, stop the daemon
stopUsbmuxd();
// or
daemon.stop();
```

**Note:** The usbmuxd daemon must be running before connecting devices. Start it before plugging in your iOS device.

## API Reference

### AppleDeviceKit

**Static methods:**
- `listDevices()`: Get all connected iOS devices

**Device Info:**
- `getDeviceInfo()`: Get device properties
- `getDeviceId()`: Get the device UDID
- `getPort()`: Get the logical port number

**App Management:**
- `installApp(ipaPath)`: Install an IPA file
- `uninstallApp(bundleId)`: Uninstall an app by bundle ID
- `isAppInstalled(bundleId)`: Check if app is installed
- `listApps()`: List all installed user apps
- `launchApp(bundleId, args?)`: Launch an application

**Trust/Pairing:**
- `isPaired()`: Check if device is paired/trusted
- `pair()`: Initiate pairing (user must accept on device)
- `unpair()`: Remove pairing/trust
- `waitForPairing(timeout?)`: Wait for device to be paired

**Port Forwarding:**
- `startPortForward(localPort, devicePort)`: Start port forwarding
- `startPortForwardAsync(localPort, devicePort)`: Start and wait for ready

**Activation:**
- `getActivationState()`: Get activation state
- `activate()`: Activate the device
- `deactivate()`: Deactivate the device

### DevicesMonitor

- `startTracking()`: Start monitoring for iOS device connections
- `stopTracking()`: Stop monitoring
- `getKits()`: Get all currently tracked devices
- `getKit(udid)`: Get a specific device kit by UDID

### usbmuxd Functions

- `startUsbmuxd(foreground?)`: Start the usbmuxd daemon
- `stopUsbmuxd()`: Stop the daemon
- `isUsbmuxdRunning()`: Check if daemon is running
- `ensureUsbmuxd()`: Start if not already running

### Types

```typescript
interface PortForwardHandle {
  stop: () => void;
  localPort: number;
  devicePort: number;
  process: ChildProcess;
}

interface ActivationState {
  isActivated: boolean;
  activationState: string;
}
```

## License

ISC

libimobiledevice is licensed under LGPL-2.1.
