appium-ios-remotexpc 5.19.0 → 5.19.2
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/CHANGELOG.md +12 -0
- package/README.md +18 -22
- package/package.json +1 -1
- package/scripts/lib/registry-port.mjs +39 -0
- package/scripts/start-appletv-tunnel.mjs +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [5.19.2](https://github.com/appium/appium-ios-remotexpc/compare/v5.19.1...v5.19.2) (2026-09-16)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
* **scripts:** fall back to a free registry port when starting the Apple TV tunnel ([#327](https://github.com/appium/appium-ios-remotexpc/issues/327)) ([84dccad](https://github.com/appium/appium-ios-remotexpc/commit/84dccad88e3f52effc54f62130f33ab400f146de))
|
|
6
|
+
|
|
7
|
+
## [5.19.1](https://github.com/appium/appium-ios-remotexpc/compare/v5.19.0...v5.19.1) (2026-09-15)
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **test:** stop registry server spec from overwriting the persisted tunnel port ([#326](https://github.com/appium/appium-ios-remotexpc/issues/326)) ([0b62a88](https://github.com/appium/appium-ios-remotexpc/commit/0b62a8889dfd1f9ac7c09fc7d5eeb7c3935a6d8e))
|
|
12
|
+
|
|
1
13
|
## [5.19.0](https://github.com/appium/appium-ios-remotexpc/compare/v5.18.9...v5.19.0) (2026-09-08)
|
|
2
14
|
|
|
3
15
|
### Features
|
package/README.md
CHANGED
|
@@ -102,7 +102,7 @@ The `appium-ios-tuntap (previously tuntap-bridge)` module plays a crucial role i
|
|
|
102
102
|
5. **Service Access**: Enables access to iOS shim services through the tunnel
|
|
103
103
|
|
|
104
104
|
**Technical Details:**
|
|
105
|
-
- **Platform Support**: Works on
|
|
105
|
+
- **Platform Support**: Works on macOS, Linux, and Windows (Windows uses WinTun and requires an elevated shell)
|
|
106
106
|
- **IPv6 Support**: Creates IPv6 tunnels for modern iOS communication
|
|
107
107
|
- **Packet Handling**: Manages packet routing between virtual interface and device
|
|
108
108
|
- **Automatic Cleanup**: Properly closes tunnels and cleans up interfaces
|
|
@@ -118,7 +118,7 @@ The `appium-ios-tuntap (previously tuntap-bridge)` module plays a crucial role i
|
|
|
118
118
|
```typescript
|
|
119
119
|
import {
|
|
120
120
|
createLockdownServiceByUDID,
|
|
121
|
-
|
|
121
|
+
discoverServices,
|
|
122
122
|
startCoreDeviceProxyTcp,
|
|
123
123
|
TunnelManager,
|
|
124
124
|
} from 'appium-ios-remotexpc';
|
|
@@ -137,21 +137,13 @@ const { socket, cert, key } = await startCoreDeviceProxyTcp(
|
|
|
137
137
|
const tunnel = await TunnelManager.getTunnel(socket, { cert, key });
|
|
138
138
|
console.log(`Tunnel created at ${tunnel.Address} with RSD port ${tunnel.RsdPort}`);
|
|
139
139
|
|
|
140
|
-
// Discover RSD services (
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
);
|
|
148
|
-
try {
|
|
149
|
-
console.log(remoteXPC.getServices());
|
|
150
|
-
} finally {
|
|
151
|
-
await remoteXPC.close();
|
|
152
|
-
}
|
|
153
|
-
},
|
|
154
|
-
);
|
|
140
|
+
// Discover RSD services (concurrent calls for the same device are coalesced;
|
|
141
|
+
// the RSD connection is closed before the promise resolves)
|
|
142
|
+
if (!tunnel.RsdPort) {
|
|
143
|
+
throw new Error('Tunnel did not report an RSD port');
|
|
144
|
+
}
|
|
145
|
+
const services = await discoverServices(udid, tunnel.Address, tunnel.RsdPort);
|
|
146
|
+
console.log(services);
|
|
155
147
|
```
|
|
156
148
|
|
|
157
149
|
### iPhone / iPad over WiFi (usbmuxd “network” devices)
|
|
@@ -166,7 +158,7 @@ There is no separate “WiFi API” in this library: call `createUsbmux()` → `
|
|
|
166
158
|
2. Allow the device to connect over WiFi (e.g. in Finder under the device, enable **Show this [device] when on WiFi**, or use Xcode **Devices and Simulators** with the equivalent option so lockdown can reach the device without USB).
|
|
167
159
|
3. Confirm **usbmuxd** reports the device with **`ConnectionType: Network`**—for example by logging the result of `listDevices()` from this library, or by checking another usbmuxd client’s device list while the device is on the same network and not on USB.
|
|
168
160
|
|
|
169
|
-
For an end-to-end tunnel smoke test with the tunnel registry HTTP API, use `npm run tunnel-creation`
|
|
161
|
+
For an end-to-end tunnel smoke test with the tunnel registry HTTP API, use `npm run tunnel-creation` (see `scripts/tunnel-creation.mjs`), usually with **sudo** for TUN/TAP.
|
|
170
162
|
|
|
171
163
|
### Apple TV / tvOS over WiFi
|
|
172
164
|
|
|
@@ -219,12 +211,13 @@ All pull requests must pass these checks before merging. The workflows are defin
|
|
|
219
211
|
- `npm run lint` - Run lint
|
|
220
212
|
- `npm run format` - Run format
|
|
221
213
|
- `npm run lint:fix` - Run lint with auto-fix
|
|
222
|
-
- `npm test` - Run tests
|
|
214
|
+
- `npm test` - Run unit tests
|
|
215
|
+
- `npm run test:all` - Run unit and integration tests (see [Testing](#testing) for integration test requirements)
|
|
223
216
|
|
|
224
217
|
CLI helpers under `scripts/` are ESM (`.mjs`) and load the library via the package entrypoint. Run `npm run build` before using them so `appium-ios-remotexpc` resolves to `build/`.
|
|
225
218
|
|
|
226
|
-
- `npm run tunnel-creation`
|
|
227
|
-
- `npm run
|
|
219
|
+
- `npm run tunnel-creation` — Create USB tunnels and start the tunnel registry HTTP API (requires `sudo`)
|
|
220
|
+
- `npm run tunnel-creation -- --keep-open` — Same as above with `--keep-open` (for inspecting open sockets)
|
|
228
221
|
- `npm run pair-appletv` — Pair an Apple TV over WiFi for Remote XPC (requires `sudo`)
|
|
229
222
|
- `npm run start-appletv-tunnel` — Start an Apple TV WiFi tunnel and tunnel registry (requires `sudo`)
|
|
230
223
|
|
|
@@ -250,8 +243,11 @@ Pass `--help` after `--` to any of these npm scripts to see CLI flags (for examp
|
|
|
250
243
|
## Testing
|
|
251
244
|
|
|
252
245
|
```bash
|
|
253
|
-
# Run
|
|
246
|
+
# Run unit tests
|
|
254
247
|
npm test
|
|
248
|
+
|
|
249
|
+
# Run unit and integration tests
|
|
250
|
+
npm run test:all
|
|
255
251
|
```
|
|
256
252
|
|
|
257
253
|
Note: Integration tests require:
|
package/package.json
CHANGED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import net from 'node:net';
|
|
2
|
+
|
|
3
|
+
const TUNNEL_REGISTRY_HOST = '127.0.0.1';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Binds to `port` (0 = OS-assigned), then releases it and resolves the bound port.
|
|
7
|
+
* @param {number} port
|
|
8
|
+
* @returns {Promise<number>}
|
|
9
|
+
*/
|
|
10
|
+
function bindFreePort(port) {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
const probe = net.createServer();
|
|
13
|
+
probe.once('error', reject);
|
|
14
|
+
probe.listen(port, TUNNEL_REGISTRY_HOST, () => {
|
|
15
|
+
const address = probe.address();
|
|
16
|
+
if (!address || typeof address === 'string') {
|
|
17
|
+
probe.close(() => reject(new Error('Could not resolve a free port')));
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
probe.close((err) => (err ? reject(err) : resolve(address.port)));
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Returns `preferredPort` if free, else a free port chosen by the OS.
|
|
27
|
+
* @param {number} preferredPort
|
|
28
|
+
* @param {{warn: (message: string) => void}} log
|
|
29
|
+
* @returns {Promise<number>}
|
|
30
|
+
*/
|
|
31
|
+
export async function resolveAvailableRegistryPort(preferredPort, log) {
|
|
32
|
+
try {
|
|
33
|
+
return await bindFreePort(preferredPort);
|
|
34
|
+
} catch {
|
|
35
|
+
const port = await bindFreePort(0);
|
|
36
|
+
log.warn(`Tunnel registry port ${preferredPort} is in use; using ${port} instead`);
|
|
37
|
+
return port;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -21,6 +21,7 @@ import {Command} from 'commander';
|
|
|
21
21
|
import {DEFAULT_TUNNEL_REGISTRY_PORT, DEFAULT_WIRELESS_APPLETV_DISCOVERY_TIMEOUT_MS} from './lib/constants.mjs';
|
|
22
22
|
import {parseNonNegativeIntegerOption, parsePortOption, parsePositiveIntegerOption} from './lib/options.mjs';
|
|
23
23
|
import {startTimeoutProgressLogger} from './lib/progress.mjs';
|
|
24
|
+
import {resolveAvailableRegistryPort} from './lib/registry-port.mjs';
|
|
24
25
|
import {assertRoot} from './lib/root.mjs';
|
|
25
26
|
import {sleep} from './lib/timers.mjs';
|
|
26
27
|
import {
|
|
@@ -432,7 +433,8 @@ async function main() {
|
|
|
432
433
|
program.parse(process.argv);
|
|
433
434
|
const options = program.opts();
|
|
434
435
|
const deviceIdentifier = program.args[0];
|
|
435
|
-
const registryPort =
|
|
436
|
+
const registryPort =
|
|
437
|
+
options.tunnelRegistryPort ?? (await resolveAvailableRegistryPort(DEFAULT_TUNNEL_REGISTRY_PORT, log));
|
|
436
438
|
|
|
437
439
|
await assertRoot(path.join('scripts', path.basename(fileURLToPath(import.meta.url))));
|
|
438
440
|
|