npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mcesystems/usbmuxd-instance-manager

v1.0.85

Published

Multi-instance manager for usbmuxd-win-mce - manages multiple usbmuxd processes with batch device allocation

Downloads

1,366

Readme

usbmuxd Instance Manager

Multi-instance manager for usbmuxd-win-mce

Automatically manages multiple usbmuxd instances with intelligent batch device allocation to prevent freezing when handling many iOS devices simultaneously.

Features

  • Automatic Device Detection: Uses usb-device-listener to detect iOS device connections
  • Batch Allocation: Groups devices (default: 4 per instance) for optimal resource usage
  • Dynamic Scaling: Spawns new instances as needed, terminates when empty
  • Isolated Failures: One instance crash doesn't affect others
  • Zero Configuration: Works out-of-the-box with sensible defaults

Architecture

┌──────────────────────────────────────────────────────────────┐
│  Windows Host                                                │
│  ┌────────────────────────────────────────────────────────┐  │
│  │  usbmuxd-instance-manager (Node.js)                    │  │
│  │  ┌──────────────────────────────────────────────────┐  │  │
│  │  │  usb-device-listener                             │  │  │
│  │  │  Detects iOS devices (VID: 0x05AC)              │  │  │
│  │  └──────────────┬───────────────────────────────────┘  │  │
│  │                 │                                        │  │
│  │  ┌──────────────▼───────────────────────────────────┐  │  │
│  │  │  InstanceManager                                  │  │  │
│  │  │  - Batch allocation (4 devices per instance)     │  │  │
│  │  │  - Port assignment (27015, 27016, 27017...)      │  │  │
│  │  │  - Spawns via WSL2                                │  │  │
│  │  └──────────────┬───────────────────────────────────┘  │  │
│  └─────────────────┼──────────────────────────────────────┘  │
│                    │ wsl -d usbmuxd-alpine usbmuxd ...       │
│  ┌─────────────────▼──────────────────────────────────────┐  │
│  │  WSL2 - Alpine Linux (26MB)                            │  │
│  │  ┌──────────────────┐  ┌──────────────────┐           │  │
│  │  │ usbmuxd instance │  │ usbmuxd instance │           │  │
│  │  │ Port: 27015      │  │ Port: 27016      │  ...      │  │
│  │  │ Devices 1-4      │  │ Devices 5-8      │           │  │
│  │  └──────────────────┘  └──────────────────┘           │  │
│  └─────────────────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────────┘

Installation

# From workspace root
pnpm install

# Build the package
pnpm --filter @mcesystems/usbmuxd-instance-manager build

Usage

CLI

# Run with defaults
pnpm --filter @mcesystems/usbmuxd-instance-manager dev

# Or after building
node dist/cli.js

# With custom options
node dist/cli.js --batchSize 6 --basePort 27020

Programmatic API

import { UsbmuxdService } from '@mcesystems/usbmuxd-instance-manager';

const service = new UsbmuxdService({
	batchSize: 4,
	basePort: 27015,
	maxInstances: 20,
	usbmuxdPath: 'usbmuxd', // Path inside WSL2
	wslDistribution: 'usbmuxd-alpine', // Alpine WSL2 distro
	verboseLogging: true,
});

// Start monitoring
service.start();

// Get device port mapping
const port = service.getDevicePort('00008030-001234567890402E');
console.log(`Device is on port ${port}`);

// Get statistics
const stats = service.getStats();
console.log(`Managing ${stats.deviceCount} devices across ${stats.instanceCount} instances`);

// Stop when done
await service.stop();

Configuration

| Option | Type | Default | Description | |--------|------|---------|-------------| | batchSize | number | 4 | Devices per instance | | basePort | number | 27015 | Starting TCP port | | maxInstances | number | 20 | Maximum instances | | usbmuxdPath | string | usbmuxd | Path to usbmuxd inside WSL2 | | wslDistribution | string | usbmuxd-alpine | Alpine WSL2 distribution name | | verboseLogging | boolean | true | Enable verbose output | | appleVendorId | string | '05AC' | Apple vendor ID (hex) |

Lockdown sync

The manager automatically syncs lockdown (pairing) files between the native Apple/iTunes lockdown directory and Alpine so devices that were already paired on Windows can be used without pairing again in WSL.

The lockdown directory is resolved per platform:

  • Windows: C:\ProgramData\Apple\Lockdown (same directory used by iTunes / Apple Mobile Device)
  • macOS: /var/db/lockdown
  • Linux: /var/lib/lockdown

Sync behavior:

  • To Alpine: When a device is assigned, that device's plist ({UDID}.plist) and SystemConfiguration.plist are copied from the Apple lockdown directory to Alpine /var/lib/lockdown.
  • From Alpine: When the service stops, plists for all devices that were assigned this session (plus SystemConfiguration.plist if present) are copied from Alpine back to the Apple lockdown directory so they are available for the next run.

Alpine permissions: /var/lib/lockdown is often root-owned. The sync tries a normal copy first; if that fails (e.g. permission denied), it retries with sudo cp. Ensure the WSL user has passwordless sudo for these commands, or that the Alpine image has /var/lib/lockdown writable by the default user. If both fail, a warning is logged and device assignment continues (pairing can still be done manually).

CLI Options

Usage: usbmuxd-instance-manager [OPTIONS]

Options:
  --batchSize <n>        Number of devices per instance (default: 4)
  --basePort <port>      Base TCP port for first instance (default: 27015)
  --maxInstances <n>     Maximum number of instances (default: 20)
  --usbmuxdPath <path>   Path to usbmuxd executable (WSL: default usbmuxd)
  --wslDistribution <n>  WSL distribution name (default: alpine-usbmuxd-build)
  --verbose <true|false> Enable verbose logging (default: true)
  --appleVid <vid>       Apple Vendor ID in hex (default: 05AC)
  -h, --help             Show this help message

Events

The InstanceManager and UsbmuxdService emit events for monitoring:

service.manager.on('instance-started', (instance) => {
	console.log(`Instance ${instance.id} started on port ${instance.port}`);
});

service.manager.on('instance-stopped', (instance) => {
	console.log(`Instance ${instance.id} stopped`);
});

Example Scenario

12 Devices Connected

Instance 1 (port 27015): iPhone-1, iPhone-2, iPhone-3, iPhone-4
Instance 2 (port 27016): iPhone-5, iPhone-6, iPhone-7, iPhone-8
Instance 3 (port 27017): iPhone-9, iPhone-10, iPhone-11, iPhone-12

Device Disconnects

When iPhone-3 disconnects:

  • Instance 1 now has 3 devices
  • Next device connects → assigned to Instance 1 (has capacity)

When all devices disconnect from Instance 2:

  • Instance 2 automatically terminates
  • Frees resources

Flow: Working with usbipd and WSL

On Windows, the same physical USB device can be used by either Windows (e.g. iTunes, Apple Mobile Device) or WSL (usbmuxd), not both. usbipd-win is what moves the device between the two.

Device ownership

| State | Who has the device | iTunes / Windows | usbmuxd (WSL) | |-------|--------------------|------------------|---------------| | Not shared | Windows | ✓ | ✗ | | Bound + attached to WSL | WSL | ✗ | ✓ | | Bound but detached | Neither (held by usbipd) | ✗ | ✗ |

Giving the device to usbmuxd (instance manager)

  1. WSL must be running (e.g. the manager starts it, or run wsl -d alpine-usbmuxd-build -- echo ok).
  2. Bind the device (take it from Windows):
    usbipd bind --busid <BUSID> --force
  3. Attach to WSL:
    usbipd attach --wsl=<distro> --busid=<BUSID>

The instance manager does steps 2–3 automatically when it sees an iOS device. You can also use the script:

# From packages/usbmuxd-instance-manager
.\scripts\attach-device.ps1

Giving the device back to Windows (e.g. for iTunes)

  1. Detach from WSL (stops forwarding to Linux):
    usbipd detach --busid <BUSID>
    Or detach all:
    usbipd detach -a
  2. Unbind so Windows gets the device back:
    usbipd unbind --busid <BUSID>

Until you unbind, the device stays "Shared (forced)" and Windows/iTunes will not see it.

Useful usbipd commands

$usbipd = "C:\Program Files\usbipd-win\usbipd.exe"

# List devices and their state (Shared / Not shared, Attached / Not attached)
& $usbipd list

# Detach from WSL (device still bound to usbipd)
& $usbipd detach --busid 2-5
& $usbipd detach -a

# Unbind so Windows can use the device again (e.g. iTunes)
& $usbipd unbind --busid 2-5

Quick reference

  • Use device with usbmuxd-instance-manager → bind + attach (manager or script does this when you connect a device).
  • Use device with iTunes on Windows → detach then unbind for that bus ID; then iTunes will see it.

Requirements

Runtime

  • Node.js: 18+
  • Windows: 10/11 with WSL2
  • Alpine WSL2 image: usbmuxd-alpine distribution imported
  • USB/IP: usbipd-win for USB device forwarding to WSL2

Build

  • pnpm: Workspace package manager
  • TypeScript: 5.9+
  • esbuild: For bundling

Development

# Install dependencies
pnpm install

# Run in dev mode (with auto-reload)
pnpm --filter @mcesystems/usbmuxd-instance-manager dev

# Build
pnpm --filter @mcesystems/usbmuxd-instance-manager build

# Type check
pnpm --filter @mcesystems/usbmuxd-instance-manager check:types

# Clean
pnpm --filter @mcesystems/usbmuxd-instance-manager clean

Troubleshooting

Service Won't Start

  • Check usbmuxd path: Ensure usbmuxdPath points to valid executable
  • Check permissions: Run as Administrator if needed
  • Check ports: Ensure ports 27015+ are not in use

Devices Not Detected

  • Check USB drivers: iOS devices need WinUSB driver (install via Zadig)
  • Check VID: Ensure appleVendorId is correct ('05AC' for Apple)
  • Check logs: Run with verbose logging enabled

Instance Crashes

  • Check usbmuxd logs: Look at instance output in console
  • Check USB driver: Device might need driver reinstall
  • Restart service: Service will spawn new instance for remaining devices

Seeing running usbmuxd

To verify that usbmuxd is running inside the WSL distribution, run ps -ef in that distro (use the same distribution name as in your config, e.g. alpine-usbmuxd-build):

PS C:\WINDOWS\system32> wsl -d alpine-usbmuxd-build -e ps -ef
PID   USER     TIME  COMMAND
    1 root      0:00 {init(alpine-usb} /init
    4 root      0:00 {init} plan9 --control-socket 6 --log-level 4 --server-fd 7 --pipe-fd 9 --log-truncate
    7 root      0:00 {SessionLeader} /init
    8 root      0:00 {Relay(9)} /init
    9 root      0:00 /bin/sh
   36 root      0:00 {Relay(37)} /init
   37 root      0:00 /bin/sh
   38 root      0:00 usbmuxd -f -v -S 0.0.0.0:27015 --pidfile NONE
   43 root      0:00 {SessionLeader} /init
   44 root      0:00 {Relay(45)} /init
   45 root      0:00 ps -ef

The usbmuxd daemon appears as PID 38 (or similar) with arguments like usbmuxd -f -v -S 0.0.0.0:27015 --pidfile NONE.

Performance

Resource Usage (20 devices, 5 instances)

  • CPU: 15-20%
  • Memory: ~400MB total (~80MB per instance)
  • Startup Time: ~500ms per instance

vs. Single Instance (iTunes-style)

| Metric | Single Instance | Multi-Instance (5x) | |--------|----------------|---------------------| | CPU | 25-40% | 15-20% | | Memory | 800MB | 400MB | | Freezing | Frequent | None | | Crash Impact | All devices | 4 devices max |

License

UNLICENSED - Private/Proprietary

This package is separate from the GPL-licensed usbmuxd-win-mce fork and remains proprietary.

See Also