Add capacitorjs runtime

This commit is contained in:
olcxja 2026-05-03 17:09:55 +02:00
commit f90c0e6c40
8362 changed files with 1502407 additions and 1 deletions

35
node_modules/native-run/dist/ios/help.js generated vendored Normal file
View file

@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.run = void 0;
const help = `
Usage: native-run ios [options]
Run an .app or .ipa on a device or simulator target
Targets are selected as follows:
1) --target using device/simulator UUID
2) A connected device, unless --virtual is used
3) A running simulator
If the above criteria are not met, the app is run on the default simulator
(the last simulator in the list).
Use --list to list available targets.
Options:
--list ............... Print available targets, then quit
--json ............... Output JSON
--app <path> ......... Deploy specified .app or .ipa file
--device ............. Use a device if available
With --list prints connected devices
--virtual ............ Prefer a simulator
With --list prints available simulators
--target <id> ........ Use a specific target
--connect ............ Tie process to app process
`;
async function run() {
process.stdout.write(`${help}\n`);
}
exports.run = run;

17
node_modules/native-run/dist/ios/index.js generated vendored Normal file
View file

@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.run = void 0;
async function run(args) {
let cmd;
if (args.includes('--help') || args.includes('-h')) {
cmd = await Promise.resolve().then(() => require('./help'));
return cmd.run(args);
}
if (args.includes('--list') || args.includes('-l')) {
cmd = await Promise.resolve().then(() => require('./list'));
return cmd.run(args);
}
cmd = await Promise.resolve().then(() => require('./run'));
await cmd.run(args);
}
exports.run = run;

164
node_modules/native-run/dist/ios/lib/client/afc.js generated vendored Normal file
View file

@ -0,0 +1,164 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AFCClient = void 0;
const Debug = require("debug");
const fs = require("fs");
const path = require("path");
const util_1 = require("util");
const afc_1 = require("../protocol/afc");
const client_1 = require("./client");
const debug = Debug('native-run:ios:lib:client:afc');
const MAX_OPEN_FILES = 240;
class AFCClient extends client_1.ServiceClient {
constructor(socket) {
super(socket, new afc_1.AFCProtocolClient(socket));
this.socket = socket;
}
async getFileInfo(path) {
debug(`getFileInfo: ${path}`);
const resp = await this.protocolClient.sendMessage({
operation: afc_1.AFC_OPS.GET_FILE_INFO,
data: toCString(path),
});
const strings = [];
let currentString = '';
const tokens = resp.data;
tokens.forEach((token) => {
if (token === 0) {
strings.push(currentString);
currentString = '';
}
else {
currentString += String.fromCharCode(token);
}
});
return strings;
}
async writeFile(fd, data) {
debug(`writeFile: ${Array.prototype.toString.call(fd)}`);
return this.protocolClient.sendMessage({
operation: afc_1.AFC_OPS.FILE_WRITE,
data: fd,
payload: data,
});
}
async openFile(path) {
debug(`openFile: ${path}`);
// mode + path + null terminator
const data = Buffer.alloc(8 + Buffer.byteLength(path) + 1);
// write mode
data.writeUInt32LE(afc_1.AFC_FILE_OPEN_FLAGS.WRONLY, 0);
// then path to file
toCString(path).copy(data, 8);
const resp = await this.protocolClient.sendMessage({
operation: afc_1.AFC_OPS.FILE_OPEN,
data,
});
if (resp.operation === afc_1.AFC_OPS.FILE_OPEN_RES) {
return resp.data;
}
throw new Error(`There was an unknown error opening file ${path}, response: ${Array.prototype.toString.call(resp.data)}`);
}
async closeFile(fd) {
debug(`closeFile fd: ${Array.prototype.toString.call(fd)}`);
return this.protocolClient.sendMessage({
operation: afc_1.AFC_OPS.FILE_CLOSE,
data: fd,
});
}
async uploadFile(srcPath, destPath) {
debug(`uploadFile: ${srcPath}`);
// read local file and get fd of destination
const [srcFile, destFile] = await Promise.all([
await (0, util_1.promisify)(fs.readFile)(srcPath),
await this.openFile(destPath),
]);
try {
await this.writeFile(destFile, srcFile);
await this.closeFile(destFile);
}
catch (err) {
await this.closeFile(destFile);
throw err;
}
}
async makeDirectory(path) {
debug(`makeDirectory: ${path}`);
return this.protocolClient.sendMessage({
operation: afc_1.AFC_OPS.MAKE_DIR,
data: toCString(path),
});
}
async uploadDirectory(srcPath, destPath) {
debug(`uploadDirectory: ${srcPath}`);
await this.makeDirectory(destPath);
// AFC doesn't seem to give out more than 240 file handles,
// so we delay any requests that would push us over until more open up
let numOpenFiles = 0;
const pendingFileUploads = [];
const _this = this;
return uploadDir(srcPath);
async function uploadDir(dirPath) {
const promises = [];
for (const file of fs.readdirSync(dirPath)) {
const filePath = path.join(dirPath, file);
const remotePath = path.join(destPath, path.relative(srcPath, filePath));
if (fs.lstatSync(filePath).isDirectory()) {
promises.push(_this.makeDirectory(remotePath).then(() => uploadDir(filePath)));
}
else {
// Create promise to add to promises array
// this way it can be resolved once a pending upload has finished
let resolve;
let reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
promises.push(promise);
// wrap upload in a function in case we need to save it for later
const uploadFile = (tries = 0) => {
numOpenFiles++;
_this
.uploadFile(filePath, remotePath)
.then(() => {
resolve();
numOpenFiles--;
const fn = pendingFileUploads.pop();
if (fn) {
fn();
}
})
.catch((err) => {
// Couldn't get fd for whatever reason, try again
// # of retries is arbitrary and can be adjusted
if (err.status === afc_1.AFC_STATUS.NO_RESOURCES && tries < 10) {
debug(`Received NO_RESOURCES from AFC, retrying ${filePath} upload. ${tries}`);
uploadFile(tries++);
}
else {
numOpenFiles--;
reject(err);
}
});
};
if (numOpenFiles < MAX_OPEN_FILES) {
uploadFile();
}
else {
debug(`numOpenFiles >= ${MAX_OPEN_FILES}, adding to pending queue. Length: ${pendingFileUploads.length}`);
pendingFileUploads.push(uploadFile);
}
}
}
await Promise.all(promises);
}
}
}
exports.AFCClient = AFCClient;
function toCString(s) {
const buf = Buffer.alloc(Buffer.byteLength(s) + 1);
const len = buf.write(s);
buf.writeUInt8(0, len);
return buf;
}

17
node_modules/native-run/dist/ios/lib/client/client.js generated vendored Normal file
View file

@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ResponseError = exports.ServiceClient = void 0;
class ServiceClient {
constructor(socket, protocolClient) {
this.socket = socket;
this.protocolClient = protocolClient;
}
}
exports.ServiceClient = ServiceClient;
class ResponseError extends Error {
constructor(msg, response) {
super(msg);
this.response = response;
}
}
exports.ResponseError = ResponseError;

View file

@ -0,0 +1,66 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DebugserverClient = void 0;
const Debug = require("debug");
const path = require("path");
const gdb_1 = require("../protocol/gdb");
const client_1 = require("./client");
const debug = Debug('native-run:ios:lib:client:debugserver');
class DebugserverClient extends client_1.ServiceClient {
constructor(socket) {
super(socket, new gdb_1.GDBProtocolClient(socket));
this.socket = socket;
}
async setMaxPacketSize(size) {
return this.sendCommand('QSetMaxPacketSize:', [size.toString()]);
}
async setWorkingDir(workingDir) {
return this.sendCommand('QSetWorkingDir:', [workingDir]);
}
async checkLaunchSuccess() {
return this.sendCommand('qLaunchSuccess', []);
}
async attachByName(name) {
const hexName = Buffer.from(name).toString('hex');
return this.sendCommand(`vAttachName;${hexName}`, []);
}
async continue() {
return this.sendCommand('c', []);
}
halt() {
// ^C
debug('Sending ^C to debugserver');
return this.protocolClient.socket.write('\u0003');
}
async kill() {
const msg = { cmd: 'k', args: [] };
return this.protocolClient.sendMessage(msg, (resp, resolve, reject) => {
this.protocolClient.socket.write('+');
const parts = resp.split(';');
for (const part of parts) {
if (part.includes('description')) {
// description:{hex encoded message like: "Terminated with signal 9"}
resolve(Buffer.from(part.split(':')[1], 'hex').toString('ascii'));
}
}
});
}
// TODO support app args
// https://sourceware.org/gdb/onlinedocs/gdb/Packets.html#Packets
// A arglen,argnum,arg,
async launchApp(appPath, executableName) {
const fullPath = path.join(appPath, executableName);
const hexAppPath = Buffer.from(fullPath).toString('hex');
const appCommand = `A${hexAppPath.length},0,${hexAppPath}`;
return this.sendCommand(appCommand, []);
}
async sendCommand(cmd, args) {
const msg = { cmd, args };
debug(`Sending command: ${cmd}, args: ${args}`);
const resp = await this.protocolClient.sendMessage(msg);
// we need to ACK as well
this.protocolClient.socket.write('+');
return resp;
}
}
exports.DebugserverClient = DebugserverClient;

10
node_modules/native-run/dist/ios/lib/client/index.js generated vendored Normal file
View file

@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
tslib_1.__exportStar(require("./client"), exports);
tslib_1.__exportStar(require("./afc"), exports);
tslib_1.__exportStar(require("./debugserver"), exports);
tslib_1.__exportStar(require("./installation_proxy"), exports);
tslib_1.__exportStar(require("./lockdownd"), exports);
tslib_1.__exportStar(require("./mobile_image_mounter"), exports);
tslib_1.__exportStar(require("./usbmuxd"), exports);

View file

@ -0,0 +1,72 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InstallationProxyClient = void 0;
const Debug = require("debug");
const lockdown_1 = require("../protocol/lockdown");
const client_1 = require("./client");
const debug = Debug('native-run:ios:lib:client:installation_proxy');
function isIPLookupResponse(resp) {
return resp.length && resp[0].LookupResult !== undefined;
}
function isIPInstallPercentCompleteResponse(resp) {
return resp.length && resp[0].PercentComplete !== undefined;
}
function isIPInstallCFBundleIdentifierResponse(resp) {
return resp.length && resp[0].CFBundleIdentifier !== undefined;
}
function isIPInstallCompleteResponse(resp) {
return resp.length && resp[0].Status === 'Complete';
}
class InstallationProxyClient extends client_1.ServiceClient {
constructor(socket) {
super(socket, new lockdown_1.LockdownProtocolClient(socket));
this.socket = socket;
}
async lookupApp(bundleIds, options = {
ReturnAttributes: ['Path', 'Container', 'CFBundleExecutable', 'CFBundleIdentifier'],
ApplicationsType: 'Any',
}) {
debug(`lookupApp, options: ${JSON.stringify(options)}`);
const resp = await this.protocolClient.sendMessage({
Command: 'Lookup',
ClientOptions: {
BundleIDs: bundleIds,
...options,
},
});
if (isIPLookupResponse(resp)) {
return resp[0].LookupResult;
}
else {
throw new client_1.ResponseError(`There was an error looking up app`, resp);
}
}
async installApp(packagePath, bundleId, options = {
ApplicationsType: 'Any',
PackageType: 'Developer',
}) {
debug(`installApp, packagePath: ${packagePath}, bundleId: ${bundleId}`);
return this.protocolClient.sendMessage({
Command: 'Install',
PackagePath: packagePath,
ClientOptions: {
CFBundleIdentifier: bundleId,
...options,
},
}, (resp, resolve, reject) => {
if (isIPInstallCompleteResponse(resp)) {
resolve();
}
else if (isIPInstallPercentCompleteResponse(resp)) {
debug(`Installation status: ${resp[0].Status}, %${resp[0].PercentComplete}`);
}
else if (isIPInstallCFBundleIdentifierResponse(resp)) {
debug(`Installed app: ${resp[0].CFBundleIdentifier}`);
}
else {
reject(new client_1.ResponseError('There was an error installing app', resp));
}
});
}
}
exports.InstallationProxyClient = InstallationProxyClient;

View file

@ -0,0 +1,111 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LockdowndClient = void 0;
const Debug = require("debug");
const tls = require("tls");
const lockdown_1 = require("../protocol/lockdown");
const client_1 = require("./client");
const debug = Debug('native-run:ios:lib:client:lockdownd');
function isLockdowndServiceResponse(resp) {
return resp.Request === 'StartService' && resp.Service !== undefined && resp.Port !== undefined;
}
function isLockdowndSessionResponse(resp) {
return resp.Request === 'StartSession';
}
function isLockdowndAllValuesResponse(resp) {
return resp.Request === 'GetValue' && resp.Value !== undefined;
}
function isLockdowndValueResponse(resp) {
return resp.Request === 'GetValue' && resp.Key !== undefined && typeof resp.Value === 'string';
}
function isLockdowndQueryTypeResponse(resp) {
return resp.Request === 'QueryType' && resp.Type !== undefined;
}
class LockdowndClient extends client_1.ServiceClient {
constructor(socket) {
super(socket, new lockdown_1.LockdownProtocolClient(socket));
this.socket = socket;
}
async startService(name) {
debug(`startService: ${name}`);
const resp = await this.protocolClient.sendMessage({
Request: 'StartService',
Service: name,
});
if (isLockdowndServiceResponse(resp)) {
return { port: resp.Port, enableServiceSSL: !!resp.EnableServiceSSL };
}
else {
throw new client_1.ResponseError(`Error starting service ${name}`, resp);
}
}
async startSession(pairRecord) {
debug(`startSession: ${pairRecord}`);
const resp = await this.protocolClient.sendMessage({
Request: 'StartSession',
HostID: pairRecord.HostID,
SystemBUID: pairRecord.SystemBUID,
});
if (isLockdowndSessionResponse(resp)) {
if (resp.EnableSessionSSL) {
this.protocolClient.socket = new tls.TLSSocket(this.protocolClient.socket, {
secureContext: tls.createSecureContext({
secureProtocol: 'TLSv1_2_method',
cert: pairRecord.RootCertificate,
key: pairRecord.RootPrivateKey,
}),
});
debug(`Socket upgraded to TLS connection`);
}
// TODO: save sessionID for StopSession?
}
else {
throw new client_1.ResponseError('Error starting session', resp);
}
}
async getAllValues() {
debug(`getAllValues`);
const resp = await this.protocolClient.sendMessage({ Request: 'GetValue' });
if (isLockdowndAllValuesResponse(resp)) {
return resp.Value;
}
else {
throw new client_1.ResponseError('Error getting lockdown value', resp);
}
}
async getValue(val) {
debug(`getValue: ${val}`);
const resp = await this.protocolClient.sendMessage({
Request: 'GetValue',
Key: val,
});
if (isLockdowndValueResponse(resp)) {
return resp.Value;
}
else {
throw new client_1.ResponseError('Error getting lockdown value', resp);
}
}
async queryType() {
debug('queryType');
const resp = await this.protocolClient.sendMessage({
Request: 'QueryType',
});
if (isLockdowndQueryTypeResponse(resp)) {
return resp.Type;
}
else {
throw new client_1.ResponseError('Error getting lockdown query type', resp);
}
}
async doHandshake(pairRecord) {
debug('doHandshake');
// if (await this.lockdownQueryType() !== 'com.apple.mobile.lockdown') {
// throw new Error('Invalid type received from lockdown handshake');
// }
// await this.getLockdownValue('ProductVersion');
// TODO: validate pair and pair
await this.startSession(pairRecord);
}
}
exports.LockdowndClient = LockdowndClient;

View file

@ -0,0 +1,61 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MobileImageMounterClient = void 0;
const Debug = require("debug");
const fs = require("fs");
const lockdown_1 = require("../protocol/lockdown");
const client_1 = require("./client");
const debug = Debug('native-run:ios:lib:client:mobile_image_mounter');
function isMIMUploadCompleteResponse(resp) {
return resp.Status === 'Complete';
}
function isMIMUploadReceiveBytesResponse(resp) {
return resp.Status === 'ReceiveBytesAck';
}
class MobileImageMounterClient extends client_1.ServiceClient {
constructor(socket) {
super(socket, new lockdown_1.LockdownProtocolClient(socket));
}
async mountImage(imagePath, imageSig) {
debug(`mountImage: ${imagePath}`);
const resp = await this.protocolClient.sendMessage({
Command: 'MountImage',
ImagePath: imagePath,
ImageSignature: imageSig,
ImageType: 'Developer',
});
if (!(0, lockdown_1.isLockdownResponse)(resp) || resp.Status !== 'Complete') {
throw new client_1.ResponseError(`There was an error mounting ${imagePath} on device`, resp);
}
}
async uploadImage(imagePath, imageSig) {
debug(`uploadImage: ${imagePath}`);
const imageSize = fs.statSync(imagePath).size;
return this.protocolClient.sendMessage({
Command: 'ReceiveBytes',
ImageSize: imageSize,
ImageSignature: imageSig,
ImageType: 'Developer',
}, (resp, resolve, reject) => {
if (isMIMUploadReceiveBytesResponse(resp)) {
const imageStream = fs.createReadStream(imagePath);
imageStream.pipe(this.protocolClient.socket, { end: false });
imageStream.on('error', (err) => reject(err));
}
else if (isMIMUploadCompleteResponse(resp)) {
resolve();
}
else {
reject(new client_1.ResponseError(`There was an error uploading image ${imagePath} to the device`, resp));
}
});
}
async lookupImage() {
debug('lookupImage');
return this.protocolClient.sendMessage({
Command: 'LookupImage',
ImageType: 'Developer',
});
}
}
exports.MobileImageMounterClient = MobileImageMounterClient;

103
node_modules/native-run/dist/ios/lib/client/usbmuxd.js generated vendored Normal file
View file

@ -0,0 +1,103 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.UsbmuxdClient = void 0;
const Debug = require("debug");
const net = require("net");
const plist = require("plist");
const usbmux_1 = require("../protocol/usbmux");
const client_1 = require("./client");
const debug = Debug('native-run:ios:lib:client:usbmuxd');
function isUsbmuxdConnectResponse(resp) {
return resp.MessageType === 'Result' && resp.Number !== undefined;
}
function isUsbmuxdDeviceResponse(resp) {
return resp.DeviceList !== undefined;
}
function isUsbmuxdPairRecordResponse(resp) {
return resp.PairRecordData !== undefined;
}
class UsbmuxdClient extends client_1.ServiceClient {
constructor(socket) {
super(socket, new usbmux_1.UsbmuxProtocolClient(socket));
this.socket = socket;
}
static connectUsbmuxdSocket() {
debug('connectUsbmuxdSocket');
if ('win32' === process.platform) {
return net.connect({ port: 27015, host: 'localhost' });
}
else {
return net.connect({ path: '/var/run/usbmuxd' });
}
}
async connect(device, port) {
debug(`connect: ${device.DeviceID} on port ${port}`);
const resp = await this.protocolClient.sendMessage({
messageType: 'Connect',
extraFields: {
DeviceID: device.DeviceID,
PortNumber: htons(port),
},
});
if (isUsbmuxdConnectResponse(resp) && resp.Number === 0) {
return this.protocolClient.socket;
}
else {
throw new client_1.ResponseError(`There was an error connecting to ${device.DeviceID} on port ${port}`, resp);
}
}
async getDevices() {
debug('getDevices');
const resp = await this.protocolClient.sendMessage({
messageType: 'ListDevices',
});
if (isUsbmuxdDeviceResponse(resp)) {
return resp.DeviceList;
}
else {
throw new client_1.ResponseError('Invalid response from getDevices', resp);
}
}
async getDevice(udid) {
debug(`getDevice ${udid ? 'udid: ' + udid : ''}`);
const devices = await this.getDevices();
if (!devices.length) {
throw new Error('No devices found');
}
if (!udid) {
return devices[0];
}
for (const device of devices) {
if (device.Properties && device.Properties.SerialNumber === udid) {
return device;
}
}
throw new Error(`No device with udid ${udid} found`);
}
async readPairRecord(udid) {
debug(`readPairRecord: ${udid}`);
const resp = await this.protocolClient.sendMessage({
messageType: 'ReadPairRecord',
extraFields: { PairRecordID: udid },
});
if (isUsbmuxdPairRecordResponse(resp)) {
// the pair record can be created as a binary plist
const BPLIST_MAGIC = Buffer.from('bplist00');
if (BPLIST_MAGIC.compare(resp.PairRecordData, 0, 8) === 0) {
debug('Binary plist pair record detected.');
const bplistParser = await Promise.resolve().then(() => require('bplist-parser'));
return bplistParser.parseBuffer(resp.PairRecordData)[0];
}
else {
return plist.parse(resp.PairRecordData.toString()); // TODO: type guard
}
}
else {
throw new client_1.ResponseError(`There was an error reading pair record for udid: ${udid}`, resp);
}
}
}
exports.UsbmuxdClient = UsbmuxdClient;
function htons(n) {
return ((n & 0xff) << 8) | ((n >> 8) & 0xff);
}

6
node_modules/native-run/dist/ios/lib/index.js generated vendored Normal file
View file

@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
tslib_1.__exportStar(require("./client"), exports);
tslib_1.__exportStar(require("./protocol"), exports);
tslib_1.__exportStar(require("./manager"), exports);

10
node_modules/native-run/dist/ios/lib/lib-errors.js generated vendored Normal file
View file

@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.IOSLibError = void 0;
class IOSLibError extends Error {
constructor(message, code) {
super(message);
this.code = code;
}
}
exports.IOSLibError = IOSLibError;

139
node_modules/native-run/dist/ios/lib/manager.js generated vendored Normal file
View file

@ -0,0 +1,139 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClientManager = void 0;
const stream_1 = require("stream");
const tls = require("tls");
const afc_1 = require("./client/afc");
const debugserver_1 = require("./client/debugserver");
const installation_proxy_1 = require("./client/installation_proxy");
const lockdownd_1 = require("./client/lockdownd");
const mobile_image_mounter_1 = require("./client/mobile_image_mounter");
const usbmuxd_1 = require("./client/usbmuxd");
class ClientManager {
constructor(pairRecord, device, lockdowndClient) {
this.pairRecord = pairRecord;
this.device = device;
this.lockdowndClient = lockdowndClient;
this.connections = [lockdowndClient.socket];
}
static async create(udid) {
const usbmuxClient = new usbmuxd_1.UsbmuxdClient(usbmuxd_1.UsbmuxdClient.connectUsbmuxdSocket());
const device = await usbmuxClient.getDevice(udid);
const pairRecord = await usbmuxClient.readPairRecord(device.Properties.SerialNumber);
const lockdownSocket = await usbmuxClient.connect(device, 62078);
const lockdownClient = new lockdownd_1.LockdowndClient(lockdownSocket);
await lockdownClient.doHandshake(pairRecord);
return new ClientManager(pairRecord, device, lockdownClient);
}
async getUsbmuxdClient() {
const usbmuxClient = new usbmuxd_1.UsbmuxdClient(usbmuxd_1.UsbmuxdClient.connectUsbmuxdSocket());
this.connections.push(usbmuxClient.socket);
return usbmuxClient;
}
async getLockdowndClient() {
const usbmuxClient = new usbmuxd_1.UsbmuxdClient(usbmuxd_1.UsbmuxdClient.connectUsbmuxdSocket());
const lockdownSocket = await usbmuxClient.connect(this.device, 62078);
const lockdownClient = new lockdownd_1.LockdowndClient(lockdownSocket);
this.connections.push(lockdownClient.socket);
return lockdownClient;
}
async getLockdowndClientWithHandshake() {
const lockdownClient = await this.getLockdowndClient();
await lockdownClient.doHandshake(this.pairRecord);
return lockdownClient;
}
async getAFCClient() {
return this.getServiceClient('com.apple.afc', afc_1.AFCClient);
}
async getInstallationProxyClient() {
return this.getServiceClient('com.apple.mobile.installation_proxy', installation_proxy_1.InstallationProxyClient);
}
async getMobileImageMounterClient() {
return this.getServiceClient('com.apple.mobile.mobile_image_mounter', mobile_image_mounter_1.MobileImageMounterClient);
}
async getDebugserverClient() {
try {
// iOS 14 added support for a secure debug service so try to connect to that first
return await this.getServiceClient('com.apple.debugserver.DVTSecureSocketProxy', debugserver_1.DebugserverClient);
}
catch {
// otherwise, fall back to the previous implementation
return this.getServiceClient('com.apple.debugserver', debugserver_1.DebugserverClient, true);
}
}
async getServiceClient(name, ServiceType, disableSSL = false) {
const { port: servicePort, enableServiceSSL } = await this.lockdowndClient.startService(name);
const usbmuxClient = new usbmuxd_1.UsbmuxdClient(usbmuxd_1.UsbmuxdClient.connectUsbmuxdSocket());
let usbmuxdSocket = await usbmuxClient.connect(this.device, servicePort);
if (enableServiceSSL) {
const tlsOptions = {
rejectUnauthorized: false,
secureContext: tls.createSecureContext({
secureProtocol: 'TLSv1_2_method',
cert: this.pairRecord.RootCertificate,
key: this.pairRecord.RootPrivateKey,
}),
};
// Some services seem to not support TLS/SSL after the initial handshake
// More info: https://github.com/libimobiledevice/libimobiledevice/issues/793
if (disableSSL) {
// According to https://nodejs.org/api/tls.html#tls_tls_connect_options_callback we can
// pass any Duplex in to tls.connect instead of a Socket. So we'll use our proxy to keep
// the TLS wrapper and underlying usbmuxd socket separate.
const proxy = new UsbmuxdProxy(usbmuxdSocket);
tlsOptions.socket = proxy;
await new Promise((res, rej) => {
const timeoutId = setTimeout(() => {
rej('The TLS handshake failed to complete after 5s.');
}, 5000);
tls.connect(tlsOptions, function () {
clearTimeout(timeoutId);
// After the handshake, we don't need TLS or the proxy anymore,
// since we'll just pass in the naked usbmuxd socket to the service client
this.destroy();
res();
});
});
}
else {
tlsOptions.socket = usbmuxdSocket;
usbmuxdSocket = tls.connect(tlsOptions);
}
}
const client = new ServiceType(usbmuxdSocket);
this.connections.push(client.socket);
return client;
}
end() {
for (const socket of this.connections) {
// may already be closed
try {
socket.end();
}
catch (err) {
// ignore
}
}
}
}
exports.ClientManager = ClientManager;
class UsbmuxdProxy extends stream_1.Duplex {
constructor(usbmuxdSock) {
super();
this.usbmuxdSock = usbmuxdSock;
this.usbmuxdSock.on('data', (data) => {
this.push(data);
});
}
_write(chunk, encoding, callback) {
this.usbmuxdSock.write(chunk);
callback();
}
_read(size) {
// Stub so we don't error, since we push everything we get from usbmuxd as it comes in.
// TODO: better way to do this?
}
_destroy() {
this.usbmuxdSock.removeAllListeners();
}
}

373
node_modules/native-run/dist/ios/lib/protocol/afc.js generated vendored Normal file
View file

@ -0,0 +1,373 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AFCProtocolWriter = exports.AFCProtocolReader = exports.AFCProtocolClient = exports.AFCError = exports.AFC_FILE_OPEN_FLAGS = exports.AFC_STATUS = exports.AFC_OPS = exports.AFC_HEADER_SIZE = exports.AFC_MAGIC = void 0;
const Debug = require("debug");
const protocol_1 = require("./protocol");
const debug = Debug('native-run:ios:lib:protocol:afc');
exports.AFC_MAGIC = 'CFA6LPAA';
exports.AFC_HEADER_SIZE = 40;
/**
* AFC Operations
*/
var AFC_OPS;
(function (AFC_OPS) {
/**
* Invalid
*/
AFC_OPS[AFC_OPS["INVALID"] = 0] = "INVALID";
/**
* Status
*/
AFC_OPS[AFC_OPS["STATUS"] = 1] = "STATUS";
/**
* Data
*/
AFC_OPS[AFC_OPS["DATA"] = 2] = "DATA";
/**
* ReadDir
*/
AFC_OPS[AFC_OPS["READ_DIR"] = 3] = "READ_DIR";
/**
* ReadFile
*/
AFC_OPS[AFC_OPS["READ_FILE"] = 4] = "READ_FILE";
/**
* WriteFile
*/
AFC_OPS[AFC_OPS["WRITE_FILE"] = 5] = "WRITE_FILE";
/**
* WritePart
*/
AFC_OPS[AFC_OPS["WRITE_PART"] = 6] = "WRITE_PART";
/**
* TruncateFile
*/
AFC_OPS[AFC_OPS["TRUNCATE"] = 7] = "TRUNCATE";
/**
* RemovePath
*/
AFC_OPS[AFC_OPS["REMOVE_PATH"] = 8] = "REMOVE_PATH";
/**
* MakeDir
*/
AFC_OPS[AFC_OPS["MAKE_DIR"] = 9] = "MAKE_DIR";
/**
* GetFileInfo
*/
AFC_OPS[AFC_OPS["GET_FILE_INFO"] = 10] = "GET_FILE_INFO";
/**
* GetDeviceInfo
*/
AFC_OPS[AFC_OPS["GET_DEVINFO"] = 11] = "GET_DEVINFO";
/**
* WriteFileAtomic (tmp file+rename)
*/
AFC_OPS[AFC_OPS["WRITE_FILE_ATOM"] = 12] = "WRITE_FILE_ATOM";
/**
* FileRefOpen
*/
AFC_OPS[AFC_OPS["FILE_OPEN"] = 13] = "FILE_OPEN";
/**
* FileRefOpenResult
*/
AFC_OPS[AFC_OPS["FILE_OPEN_RES"] = 14] = "FILE_OPEN_RES";
/**
* FileRefRead
*/
AFC_OPS[AFC_OPS["FILE_READ"] = 15] = "FILE_READ";
/**
* FileRefWrite
*/
AFC_OPS[AFC_OPS["FILE_WRITE"] = 16] = "FILE_WRITE";
/**
* FileRefSeek
*/
AFC_OPS[AFC_OPS["FILE_SEEK"] = 17] = "FILE_SEEK";
/**
* FileRefTell
*/
AFC_OPS[AFC_OPS["FILE_TELL"] = 18] = "FILE_TELL";
/**
* FileRefTellResult
*/
AFC_OPS[AFC_OPS["FILE_TELL_RES"] = 19] = "FILE_TELL_RES";
/**
* FileRefClose
*/
AFC_OPS[AFC_OPS["FILE_CLOSE"] = 20] = "FILE_CLOSE";
/**
* FileRefSetFileSize (ftruncate)
*/
AFC_OPS[AFC_OPS["FILE_SET_SIZE"] = 21] = "FILE_SET_SIZE";
/**
* GetConnectionInfo
*/
AFC_OPS[AFC_OPS["GET_CON_INFO"] = 22] = "GET_CON_INFO";
/**
* SetConnectionOptions
*/
AFC_OPS[AFC_OPS["SET_CON_OPTIONS"] = 23] = "SET_CON_OPTIONS";
/**
* RenamePath
*/
AFC_OPS[AFC_OPS["RENAME_PATH"] = 24] = "RENAME_PATH";
/**
* SetFSBlockSize (0x800000)
*/
AFC_OPS[AFC_OPS["SET_FS_BS"] = 25] = "SET_FS_BS";
/**
* SetSocketBlockSize (0x800000)
*/
AFC_OPS[AFC_OPS["SET_SOCKET_BS"] = 26] = "SET_SOCKET_BS";
/**
* FileRefLock
*/
AFC_OPS[AFC_OPS["FILE_LOCK"] = 27] = "FILE_LOCK";
/**
* MakeLink
*/
AFC_OPS[AFC_OPS["MAKE_LINK"] = 28] = "MAKE_LINK";
/**
* GetFileHash
*/
AFC_OPS[AFC_OPS["GET_FILE_HASH"] = 29] = "GET_FILE_HASH";
/**
* SetModTime
*/
AFC_OPS[AFC_OPS["SET_FILE_MOD_TIME"] = 30] = "SET_FILE_MOD_TIME";
/**
* GetFileHashWithRange
*/
AFC_OPS[AFC_OPS["GET_FILE_HASH_RANGE"] = 31] = "GET_FILE_HASH_RANGE";
// iOS 6+
/**
* FileRefSetImmutableHint
*/
AFC_OPS[AFC_OPS["FILE_SET_IMMUTABLE_HINT"] = 32] = "FILE_SET_IMMUTABLE_HINT";
/**
* GetSizeOfPathContents
*/
AFC_OPS[AFC_OPS["GET_SIZE_OF_PATH_CONTENTS"] = 33] = "GET_SIZE_OF_PATH_CONTENTS";
/**
* RemovePathAndContents
*/
AFC_OPS[AFC_OPS["REMOVE_PATH_AND_CONTENTS"] = 34] = "REMOVE_PATH_AND_CONTENTS";
/**
* DirectoryEnumeratorRefOpen
*/
AFC_OPS[AFC_OPS["DIR_OPEN"] = 35] = "DIR_OPEN";
/**
* DirectoryEnumeratorRefOpenResult
*/
AFC_OPS[AFC_OPS["DIR_OPEN_RESULT"] = 36] = "DIR_OPEN_RESULT";
/**
* DirectoryEnumeratorRefRead
*/
AFC_OPS[AFC_OPS["DIR_READ"] = 37] = "DIR_READ";
/**
* DirectoryEnumeratorRefClose
*/
AFC_OPS[AFC_OPS["DIR_CLOSE"] = 38] = "DIR_CLOSE";
// iOS 7+
/**
* FileRefReadWithOffset
*/
AFC_OPS[AFC_OPS["FILE_READ_OFFSET"] = 39] = "FILE_READ_OFFSET";
/**
* FileRefWriteWithOffset
*/
AFC_OPS[AFC_OPS["FILE_WRITE_OFFSET"] = 40] = "FILE_WRITE_OFFSET";
})(AFC_OPS = exports.AFC_OPS || (exports.AFC_OPS = {}));
/**
* Error Codes
*/
var AFC_STATUS;
(function (AFC_STATUS) {
AFC_STATUS[AFC_STATUS["SUCCESS"] = 0] = "SUCCESS";
AFC_STATUS[AFC_STATUS["UNKNOWN_ERROR"] = 1] = "UNKNOWN_ERROR";
AFC_STATUS[AFC_STATUS["OP_HEADER_INVALID"] = 2] = "OP_HEADER_INVALID";
AFC_STATUS[AFC_STATUS["NO_RESOURCES"] = 3] = "NO_RESOURCES";
AFC_STATUS[AFC_STATUS["READ_ERROR"] = 4] = "READ_ERROR";
AFC_STATUS[AFC_STATUS["WRITE_ERROR"] = 5] = "WRITE_ERROR";
AFC_STATUS[AFC_STATUS["UNKNOWN_PACKET_TYPE"] = 6] = "UNKNOWN_PACKET_TYPE";
AFC_STATUS[AFC_STATUS["INVALID_ARG"] = 7] = "INVALID_ARG";
AFC_STATUS[AFC_STATUS["OBJECT_NOT_FOUND"] = 8] = "OBJECT_NOT_FOUND";
AFC_STATUS[AFC_STATUS["OBJECT_IS_DIR"] = 9] = "OBJECT_IS_DIR";
AFC_STATUS[AFC_STATUS["PERM_DENIED"] = 10] = "PERM_DENIED";
AFC_STATUS[AFC_STATUS["SERVICE_NOT_CONNECTED"] = 11] = "SERVICE_NOT_CONNECTED";
AFC_STATUS[AFC_STATUS["OP_TIMEOUT"] = 12] = "OP_TIMEOUT";
AFC_STATUS[AFC_STATUS["TOO_MUCH_DATA"] = 13] = "TOO_MUCH_DATA";
AFC_STATUS[AFC_STATUS["END_OF_DATA"] = 14] = "END_OF_DATA";
AFC_STATUS[AFC_STATUS["OP_NOT_SUPPORTED"] = 15] = "OP_NOT_SUPPORTED";
AFC_STATUS[AFC_STATUS["OBJECT_EXISTS"] = 16] = "OBJECT_EXISTS";
AFC_STATUS[AFC_STATUS["OBJECT_BUSY"] = 17] = "OBJECT_BUSY";
AFC_STATUS[AFC_STATUS["NO_SPACE_LEFT"] = 18] = "NO_SPACE_LEFT";
AFC_STATUS[AFC_STATUS["OP_WOULD_BLOCK"] = 19] = "OP_WOULD_BLOCK";
AFC_STATUS[AFC_STATUS["IO_ERROR"] = 20] = "IO_ERROR";
AFC_STATUS[AFC_STATUS["OP_INTERRUPTED"] = 21] = "OP_INTERRUPTED";
AFC_STATUS[AFC_STATUS["OP_IN_PROGRESS"] = 22] = "OP_IN_PROGRESS";
AFC_STATUS[AFC_STATUS["INTERNAL_ERROR"] = 23] = "INTERNAL_ERROR";
AFC_STATUS[AFC_STATUS["MUX_ERROR"] = 30] = "MUX_ERROR";
AFC_STATUS[AFC_STATUS["NO_MEM"] = 31] = "NO_MEM";
AFC_STATUS[AFC_STATUS["NOT_ENOUGH_DATA"] = 32] = "NOT_ENOUGH_DATA";
AFC_STATUS[AFC_STATUS["DIR_NOT_EMPTY"] = 33] = "DIR_NOT_EMPTY";
AFC_STATUS[AFC_STATUS["FORCE_SIGNED_TYPE"] = -1] = "FORCE_SIGNED_TYPE";
})(AFC_STATUS = exports.AFC_STATUS || (exports.AFC_STATUS = {}));
var AFC_FILE_OPEN_FLAGS;
(function (AFC_FILE_OPEN_FLAGS) {
/**
* r (O_RDONLY)
*/
AFC_FILE_OPEN_FLAGS[AFC_FILE_OPEN_FLAGS["RDONLY"] = 1] = "RDONLY";
/**
* r+ (O_RDWR | O_CREAT)
*/
AFC_FILE_OPEN_FLAGS[AFC_FILE_OPEN_FLAGS["RW"] = 2] = "RW";
/**
* w (O_WRONLY | O_CREAT | O_TRUNC)
*/
AFC_FILE_OPEN_FLAGS[AFC_FILE_OPEN_FLAGS["WRONLY"] = 3] = "WRONLY";
/**
* w+ (O_RDWR | O_CREAT | O_TRUNC)
*/
AFC_FILE_OPEN_FLAGS[AFC_FILE_OPEN_FLAGS["WR"] = 4] = "WR";
/**
* a (O_WRONLY | O_APPEND | O_CREAT)
*/
AFC_FILE_OPEN_FLAGS[AFC_FILE_OPEN_FLAGS["APPEND"] = 5] = "APPEND";
/**
* a+ (O_RDWR | O_APPEND | O_CREAT)
*/
AFC_FILE_OPEN_FLAGS[AFC_FILE_OPEN_FLAGS["RDAPPEND"] = 6] = "RDAPPEND";
})(AFC_FILE_OPEN_FLAGS = exports.AFC_FILE_OPEN_FLAGS || (exports.AFC_FILE_OPEN_FLAGS = {}));
function isAFCResponse(resp) {
return AFC_OPS[resp.operation] !== undefined && resp.id !== undefined && resp.data !== undefined;
}
function isStatusResponse(resp) {
return isAFCResponse(resp) && resp.operation === AFC_OPS.STATUS;
}
function isErrorStatusResponse(resp) {
return isStatusResponse(resp) && resp.data !== AFC_STATUS.SUCCESS;
}
class AFCInternalError extends Error {
constructor(msg, requestId) {
super(msg);
this.requestId = requestId;
}
}
class AFCError extends Error {
constructor(msg, status) {
super(msg);
this.status = status;
}
}
exports.AFCError = AFCError;
class AFCProtocolClient extends protocol_1.ProtocolClient {
constructor(socket) {
super(socket, new protocol_1.ProtocolReaderFactory(AFCProtocolReader), new AFCProtocolWriter());
this.requestId = 0;
this.requestCallbacks = {};
const reader = this.readerFactory.create((resp, err) => {
if (err && err instanceof AFCInternalError) {
this.requestCallbacks[err.requestId](resp, err);
}
else if (isErrorStatusResponse(resp)) {
this.requestCallbacks[resp.id](resp, new AFCError(AFC_STATUS[resp.data], resp.data));
}
else {
this.requestCallbacks[resp.id](resp);
}
});
socket.on('data', reader.onData);
}
sendMessage(msg) {
return new Promise((resolve, reject) => {
const requestId = this.requestId++;
this.requestCallbacks[requestId] = async (resp, err) => {
if (err) {
reject(err);
return;
}
if (isAFCResponse(resp)) {
resolve(resp);
}
else {
reject(new Error('Malformed AFC response'));
}
};
this.writer.write(this.socket, { ...msg, requestId });
});
}
}
exports.AFCProtocolClient = AFCProtocolClient;
class AFCProtocolReader extends protocol_1.ProtocolReader {
constructor(callback) {
super(exports.AFC_HEADER_SIZE, callback);
}
parseHeader(data) {
const magic = data.slice(0, 8).toString('ascii');
if (magic !== exports.AFC_MAGIC) {
throw new AFCInternalError(`Invalid AFC packet received (magic != ${exports.AFC_MAGIC})`, data.readUInt32LE(24));
}
// technically these are uint64
this.header = {
magic,
totalLength: data.readUInt32LE(8),
headerLength: data.readUInt32LE(16),
requestId: data.readUInt32LE(24),
operation: data.readUInt32LE(32),
};
debug(`parse header: ${JSON.stringify(this.header)}`);
if (this.header.headerLength < exports.AFC_HEADER_SIZE) {
throw new AFCInternalError('Invalid AFC header', this.header.requestId);
}
return this.header.totalLength - exports.AFC_HEADER_SIZE;
}
parseBody(data) {
const body = {
operation: this.header.operation,
id: this.header.requestId,
data,
};
if (isStatusResponse(body)) {
const status = data.readUInt32LE(0);
debug(`${AFC_OPS[this.header.operation]} response: ${AFC_STATUS[status]}`);
body.data = status;
}
else if (data.length <= 8) {
debug(`${AFC_OPS[this.header.operation]} response: ${Array.prototype.toString.call(body)}`);
}
else {
debug(`${AFC_OPS[this.header.operation]} response length: ${data.length} bytes`);
}
return body;
}
}
exports.AFCProtocolReader = AFCProtocolReader;
class AFCProtocolWriter {
write(socket, msg) {
const { data, payload, operation, requestId } = msg;
const dataLength = data ? data.length : 0;
const payloadLength = payload ? payload.length : 0;
const header = Buffer.alloc(exports.AFC_HEADER_SIZE);
const magic = Buffer.from(exports.AFC_MAGIC);
magic.copy(header);
header.writeUInt32LE(exports.AFC_HEADER_SIZE + dataLength + payloadLength, 8);
header.writeUInt32LE(exports.AFC_HEADER_SIZE + dataLength, 16);
header.writeUInt32LE(requestId, 24);
header.writeUInt32LE(operation, 32);
socket.write(header);
socket.write(data);
if (data.length <= 8) {
debug(`socket write, header: { requestId: ${requestId}, operation: ${AFC_OPS[operation]}}, body: ${Array.prototype.toString.call(data)}`);
}
else {
debug(`socket write, header: { requestId: ${requestId}, operation: ${AFC_OPS[operation]}}, body: ${data.length} bytes`);
}
debug(`socket write, bytes written ${header.length} (header), ${data.length} (body)`);
if (payload) {
socket.write(payload);
}
}
}
exports.AFCProtocolWriter = AFCProtocolWriter;

112
node_modules/native-run/dist/ios/lib/protocol/gdb.js generated vendored Normal file
View file

@ -0,0 +1,112 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GDBProtocolWriter = exports.GDBProtocolReader = exports.GDBProtocolClient = void 0;
const Debug = require("debug");
const protocol_1 = require("./protocol");
const debug = Debug('native-run:ios:lib:protocol:gdb');
const ACK_SUCCESS = '+'.charCodeAt(0);
class GDBProtocolClient extends protocol_1.ProtocolClient {
constructor(socket) {
super(socket, new protocol_1.ProtocolReaderFactory(GDBProtocolReader), new GDBProtocolWriter());
}
}
exports.GDBProtocolClient = GDBProtocolClient;
class GDBProtocolReader extends protocol_1.ProtocolReader {
constructor(callback) {
super(1 /* "Header" is '+' or '-' */, callback);
}
onData(data) {
// the GDB protocol does not support body length in its header so we cannot rely on
// the parent implementation to determine when a payload is complete
try {
// if there's data, add it to the existing buffer
this.buffer = data ? Buffer.concat([this.buffer, data]) : this.buffer;
// do we have enough bytes to proceed
if (this.buffer.length < this.headerSize) {
return; // incomplete header, wait for more
}
// first, check the header
if (this.parseHeader(this.buffer) === -1) {
// we have a valid header so check the body. GDB packets will always be a leading '$', data bytes,
// a trailing '#', and a two digit checksum. minimum valid body is the empty response '$#00'
// https://developer.apple.com/library/archive/documentation/DeveloperTools/gdb/gdb/gdb_33.html
const packetData = this.buffer.toString().match('\\$.*#[0-9a-f]{2}');
if (packetData == null) {
return; // incomplete body, wait for more
}
// extract the body and update the buffer
const body = Buffer.from(packetData[0]);
this.buffer = this.buffer.slice(this.headerSize + body.length);
// parse the payload and recurse if there is more data to process
this.callback(this.parseBody(body));
if (this.buffer.length) {
this.onData();
}
}
}
catch (err) {
this.callback(null, err);
}
}
parseHeader(data) {
if (data[0] !== ACK_SUCCESS) {
throw new Error('Unsuccessful debugserver response');
} // TODO: retry?
return -1;
}
parseBody(buffer) {
debug(`Response body: ${buffer.toString()}`);
// check for checksum
const checksum = buffer.slice(-3).toString();
if (checksum.match(/#[0-9a-f]{2}/)) {
// remove '$' prefix and checksum
const msg = buffer.slice(1, -3).toString();
if (validateChecksum(checksum, msg)) {
return msg;
}
else {
throw new Error('Invalid checksum received from debugserver');
}
}
else {
throw new Error("Didn't receive checksum");
}
}
}
exports.GDBProtocolReader = GDBProtocolReader;
class GDBProtocolWriter {
write(socket, msg) {
const { cmd, args } = msg;
debug(`Socket write: ${cmd}, args: ${args}`);
// hex encode and concat all args
const encodedArgs = args
.map((arg) => Buffer.from(arg).toString('hex'))
.join()
.toUpperCase();
const checksumStr = calculateChecksum(cmd + encodedArgs);
const formattedCmd = `$${cmd}${encodedArgs}#${checksumStr}`;
socket.write(formattedCmd);
}
}
exports.GDBProtocolWriter = GDBProtocolWriter;
// hex value of (sum of cmd chars mod 256)
function calculateChecksum(cmdStr) {
let checksum = 0;
for (let i = 0; i < cmdStr.length; i++) {
checksum += cmdStr.charCodeAt(i);
}
let result = (checksum % 256).toString(16);
// pad if necessary
if (result.length === 1) {
result = `0${result}`;
}
return result;
}
function validateChecksum(checksum, msg) {
// remove '#' from checksum
const checksumVal = checksum.slice(1);
// remove '$' from msg and calculate its checksum
const computedChecksum = calculateChecksum(msg);
debug(`Checksum: ${checksumVal}, computed checksum: ${computedChecksum}`);
return checksumVal === computedChecksum;
}

View file

@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
tslib_1.__exportStar(require("./protocol"), exports);
tslib_1.__exportStar(require("./afc"), exports);
tslib_1.__exportStar(require("./gdb"), exports);
tslib_1.__exportStar(require("./lockdown"), exports);
tslib_1.__exportStar(require("./usbmux"), exports);

View file

@ -0,0 +1,57 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LockdownProtocolWriter = exports.LockdownProtocolReader = exports.LockdownProtocolClient = exports.isLockdownErrorResponse = exports.isLockdownResponse = exports.LOCKDOWN_HEADER_SIZE = void 0;
const Debug = require("debug");
const plist = require("plist");
const lib_errors_1 = require("../lib-errors");
const protocol_1 = require("./protocol");
const debug = Debug('native-run:ios:lib:protocol:lockdown');
exports.LOCKDOWN_HEADER_SIZE = 4;
function isDefined(val) {
return typeof val !== 'undefined';
}
function isLockdownResponse(resp) {
return isDefined(resp.Status);
}
exports.isLockdownResponse = isLockdownResponse;
function isLockdownErrorResponse(resp) {
return isDefined(resp.Error);
}
exports.isLockdownErrorResponse = isLockdownErrorResponse;
class LockdownProtocolClient extends protocol_1.ProtocolClient {
constructor(socket) {
super(socket, new protocol_1.ProtocolReaderFactory(LockdownProtocolReader), new LockdownProtocolWriter());
}
}
exports.LockdownProtocolClient = LockdownProtocolClient;
class LockdownProtocolReader extends protocol_1.PlistProtocolReader {
constructor(callback) {
super(exports.LOCKDOWN_HEADER_SIZE, callback);
}
parseHeader(data) {
return data.readUInt32BE(0);
}
parseBody(data) {
const resp = super.parseBody(data);
debug(`Response: ${JSON.stringify(resp)}`);
if (isLockdownErrorResponse(resp)) {
if (resp.Error === 'DeviceLocked') {
throw new lib_errors_1.IOSLibError('Device is currently locked.', 'DeviceLocked');
}
throw new Error(resp.Error);
}
return resp;
}
}
exports.LockdownProtocolReader = LockdownProtocolReader;
class LockdownProtocolWriter {
write(socket, plistData) {
debug(`socket write: ${JSON.stringify(plistData)}`);
const plistMessage = plist.build(plistData);
const header = Buffer.alloc(exports.LOCKDOWN_HEADER_SIZE);
header.writeUInt32BE(plistMessage.length, 0);
socket.write(header);
socket.write(plistMessage);
}
}
exports.LockdownProtocolWriter = LockdownProtocolWriter;

View file

@ -0,0 +1,111 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProtocolClient = exports.PlistProtocolReader = exports.ProtocolReader = exports.ProtocolReaderFactory = void 0;
const bplistParser = require("bplist-parser");
const plist = require("plist");
const BPLIST_MAGIC = Buffer.from('bplist00');
class ProtocolReaderFactory {
constructor(ProtocolReader) {
this.ProtocolReader = ProtocolReader;
}
create(callback) {
return new this.ProtocolReader(callback);
}
}
exports.ProtocolReaderFactory = ProtocolReaderFactory;
class ProtocolReader {
constructor(headerSize, callback) {
this.headerSize = headerSize;
this.callback = callback;
this.buffer = Buffer.alloc(0);
this.onData = this.onData.bind(this);
}
onData(data) {
try {
// if there's data, add it on to existing buffer
this.buffer = data ? Buffer.concat([this.buffer, data]) : this.buffer;
// we haven't gotten the body length from the header yet
if (!this.bodyLength) {
if (this.buffer.length < this.headerSize) {
// partial header, wait for rest
return;
}
this.bodyLength = this.parseHeader(this.buffer);
// move on to body
this.buffer = this.buffer.slice(this.headerSize);
if (!this.buffer.length) {
// only got header, wait for body
return;
}
}
if (this.buffer.length < this.bodyLength) {
// wait for rest of body
return;
}
if (this.bodyLength === -1) {
this.callback(this.parseBody(this.buffer));
this.buffer = Buffer.alloc(0);
}
else {
this.body = this.buffer.slice(0, this.bodyLength);
this.bodyLength -= this.body.length;
if (!this.bodyLength) {
this.callback(this.parseBody(this.body));
}
this.buffer = this.buffer.slice(this.body.length);
// There are multiple messages here, call parse again
if (this.buffer.length) {
this.onData();
}
}
}
catch (err) {
this.callback(null, err);
}
}
}
exports.ProtocolReader = ProtocolReader;
class PlistProtocolReader extends ProtocolReader {
parseBody(body) {
if (BPLIST_MAGIC.compare(body, 0, 8) === 0) {
return bplistParser.parseBuffer(body);
}
else {
return plist.parse(body.toString('utf8'));
}
}
}
exports.PlistProtocolReader = PlistProtocolReader;
class ProtocolClient {
constructor(socket, readerFactory, writer) {
this.socket = socket;
this.readerFactory = readerFactory;
this.writer = writer;
}
sendMessage(msg, callback) {
return new Promise((resolve, reject) => {
const reader = this.readerFactory.create(async (resp, err) => {
if (err) {
reject(err);
return;
}
if (callback) {
callback(resp, (value) => {
this.socket.removeListener('data', reader.onData);
resolve(value);
}, reject);
}
else {
this.socket.removeListener('data', reader.onData);
resolve(resp);
}
});
this.socket.on('error', (err) => {
throw err;
});
this.socket.on('data', reader.onData);
this.writer.write(this.socket, msg);
});
}
}
exports.ProtocolClient = ProtocolClient;

View file

@ -0,0 +1,57 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.UsbmuxProtocolWriter = exports.UsbmuxProtocolReader = exports.UsbmuxProtocolClient = exports.USBMUXD_HEADER_SIZE = void 0;
const Debug = require("debug");
const plist = require("plist");
const protocol_1 = require("./protocol");
const debug = Debug('native-run:ios:lib:protocol:usbmux');
exports.USBMUXD_HEADER_SIZE = 16;
class UsbmuxProtocolClient extends protocol_1.ProtocolClient {
constructor(socket) {
super(socket, new protocol_1.ProtocolReaderFactory(UsbmuxProtocolReader), new UsbmuxProtocolWriter());
}
}
exports.UsbmuxProtocolClient = UsbmuxProtocolClient;
class UsbmuxProtocolReader extends protocol_1.PlistProtocolReader {
constructor(callback) {
super(exports.USBMUXD_HEADER_SIZE, callback);
}
parseHeader(data) {
return data.readUInt32LE(0) - exports.USBMUXD_HEADER_SIZE;
}
parseBody(data) {
const resp = super.parseBody(data);
debug(`Response: ${JSON.stringify(resp)}`);
return resp;
}
}
exports.UsbmuxProtocolReader = UsbmuxProtocolReader;
class UsbmuxProtocolWriter {
constructor() {
this.useTag = 0;
}
write(socket, msg) {
// TODO Usbmux message type
debug(`socket write: ${JSON.stringify(msg)}`);
const { messageType, extraFields } = msg;
const plistMessage = plist.build({
BundleID: 'io.ionic.native-run',
ClientVersionString: 'usbmux.js',
MessageType: messageType,
ProgName: 'native-run',
kLibUSBMuxVersion: 3,
...extraFields,
});
const dataSize = plistMessage ? plistMessage.length : 0;
const protocolVersion = 1;
const messageCode = 8;
const header = Buffer.alloc(exports.USBMUXD_HEADER_SIZE);
header.writeUInt32LE(exports.USBMUXD_HEADER_SIZE + dataSize, 0);
header.writeUInt32LE(protocolVersion, 4);
header.writeUInt32LE(messageCode, 8);
header.writeUInt32LE(this.useTag++, 12); // TODO
socket.write(header);
socket.write(plistMessage);
}
}
exports.UsbmuxProtocolWriter = UsbmuxProtocolWriter;

55
node_modules/native-run/dist/ios/list.js generated vendored Normal file
View file

@ -0,0 +1,55 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.list = exports.run = void 0;
const list_1 = require("../utils/list");
const device_1 = require("./utils/device");
const simulator_1 = require("./utils/simulator");
async function run(args) {
const targets = await list(args);
process.stdout.write(`\n${(0, list_1.formatTargets)(args, targets)}\n`);
}
exports.run = run;
async function list(args) {
const errors = [];
const [devices, virtualDevices] = await Promise.all([
(async () => {
try {
const devices = await (0, device_1.getConnectedDevices)();
return devices.map(deviceToTarget);
}
catch (e) {
errors.push(e);
return [];
}
})(),
(async () => {
try {
const simulators = await (0, simulator_1.getSimulators)();
return simulators.map(simulatorToTarget);
}
catch (e) {
errors.push(e);
return [];
}
})(),
]);
return { devices, virtualDevices, errors };
}
exports.list = list;
function deviceToTarget(device) {
return {
platform: 'ios',
name: device.DeviceName,
model: device.ProductType,
sdkVersion: device.ProductVersion,
id: device.UniqueDeviceID,
};
}
function simulatorToTarget(simulator) {
return {
platform: 'ios',
name: simulator.name,
sdkVersion: simulator.runtime.version,
id: simulator.udid,
};
}

116
node_modules/native-run/dist/ios/run.js generated vendored Normal file
View file

@ -0,0 +1,116 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.run = void 0;
const utils_fs_1 = require("@ionic/utils-fs");
const Debug = require("debug");
const fs_1 = require("fs");
const path = require("path");
const errors_1 = require("../errors");
const cli_1 = require("../utils/cli");
const process_1 = require("../utils/process");
const lib_errors_1 = require("./lib/lib-errors");
const app_1 = require("./utils/app");
const device_1 = require("./utils/device");
const simulator_1 = require("./utils/simulator");
const debug = Debug('native-run:ios:run');
async function runIpaOrAppFile({ udid, devices, simulators, appPath, bundleId, waitForApp, preferSimulator, }) {
if (udid) {
if (devices.find((d) => d.UniqueDeviceID === udid)) {
await (0, device_1.runOnDevice)(udid, appPath, bundleId, waitForApp);
}
else if (simulators.find((s) => s.udid === udid)) {
await (0, simulator_1.runOnSimulator)(udid, appPath, bundleId, waitForApp);
}
else {
throw new errors_1.IOSRunException(`No device or simulator with UDID "${udid}" found`, errors_1.ERR_TARGET_NOT_FOUND);
}
}
else if (devices.length && !preferSimulator) {
// no udid, use first connected device
await (0, device_1.runOnDevice)(devices[0].UniqueDeviceID, appPath, bundleId, waitForApp);
}
else {
// use default sim
await (0, simulator_1.runOnSimulator)(simulators[simulators.length - 1].udid, appPath, bundleId, waitForApp);
}
}
async function runIpaOrAppFileOnInterval(config) {
const maxRetryCount = 12; // 1 minute
const retryInterval = 5000; // 5 seconds
let error;
let retryCount = 0;
const retry = async () => {
process.stderr.write('Please unlock your device. Waiting 5 seconds...\n');
retryCount++;
await (0, process_1.wait)(retryInterval);
await run();
};
const run = async () => {
try {
await runIpaOrAppFile(config);
}
catch (err) {
if (err instanceof lib_errors_1.IOSLibError && err.code == 'DeviceLocked' && retryCount < maxRetryCount) {
await retry();
}
else {
if (retryCount >= maxRetryCount) {
error = new errors_1.IOSRunException(`Device still locked after 1 minute. Aborting.`, errors_1.ERR_DEVICE_LOCKED);
}
else {
error = err;
}
}
}
};
await run();
if (error) {
throw error;
}
}
async function run(args) {
let appPath = (0, cli_1.getOptionValue)(args, '--app');
if (!appPath) {
throw new errors_1.CLIException('--app is required', errors_1.ERR_BAD_INPUT);
}
const udid = (0, cli_1.getOptionValue)(args, '--target');
const preferSimulator = args.includes('--virtual');
const waitForApp = args.includes('--connect');
const isIPA = appPath.endsWith('.ipa');
if (!(0, fs_1.existsSync)(appPath)) {
throw new errors_1.IOSRunException(`Path '${appPath}' not found`);
}
try {
if (isIPA) {
const { tmpdir } = await Promise.resolve().then(() => require('os'));
const tempDir = (0, fs_1.mkdtempSync)(`${tmpdir()}${path.sep}`);
debug(`Unzipping .ipa to ${tempDir}`);
const appDir = await (0, app_1.unzipIPA)(appPath, tempDir);
appPath = path.join(tempDir, appDir);
}
const bundleId = await (0, app_1.getBundleId)(appPath);
const [devices, simulators] = await Promise.all([(0, device_1.getConnectedDevices)(), (0, simulator_1.getSimulators)()]);
// try to run on device or simulator with udid
const config = {
udid,
devices,
simulators,
appPath,
bundleId,
waitForApp,
preferSimulator,
};
await runIpaOrAppFileOnInterval(config);
}
finally {
if (isIPA) {
try {
await (0, utils_fs_1.remove)(appPath);
}
catch {
// ignore
}
}
}
}
exports.run = run;

60
node_modules/native-run/dist/ios/utils/app.js generated vendored Normal file
View file

@ -0,0 +1,60 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.unzipIPA = exports.getBundleId = void 0;
const utils_fs_1 = require("@ionic/utils-fs");
const Debug = require("debug");
const fs_1 = require("fs");
const path = require("path");
const errors_1 = require("../../errors");
const process_1 = require("../../utils/process");
const unzip_1 = require("../../utils/unzip");
const debug = Debug('native-run:ios:utils:app');
// TODO: cross platform? Use plist/bplist
async function getBundleId(appPath) {
const plistPath = path.resolve(appPath, 'Info.plist');
try {
const { stdout } = await (0, process_1.execFile)('/usr/libexec/PlistBuddy', ['-c', 'Print :CFBundleIdentifier', plistPath], {
encoding: 'utf8',
});
if (stdout) {
return stdout.trim();
}
}
catch {
// ignore
}
throw new errors_1.Exception('Unable to get app bundle identifier');
}
exports.getBundleId = getBundleId;
async function unzipIPA(ipaPath, destPath) {
let error;
let appPath = '';
await (0, unzip_1.unzip)(ipaPath, async (entry, zipfile, openReadStream) => {
debug(`Unzip: ${entry.fileName}`);
const dest = path.join(destPath, entry.fileName);
if (entry.fileName.endsWith('/')) {
await (0, utils_fs_1.mkdirp)(dest);
if (entry.fileName.endsWith('.app/')) {
appPath = entry.fileName;
}
zipfile.readEntry();
}
else {
await (0, utils_fs_1.mkdirp)(path.dirname(dest));
const readStream = await openReadStream(entry);
readStream.on('error', (err) => (error = err));
readStream.on('end', () => {
zipfile.readEntry();
});
readStream.pipe((0, fs_1.createWriteStream)(dest));
}
});
if (error) {
throw error;
}
if (!appPath) {
throw new errors_1.Exception('Unable to determine .app directory from .ipa');
}
return appPath;
}
exports.unzipIPA = unzipIPA;

141
node_modules/native-run/dist/ios/utils/device.js generated vendored Normal file
View file

@ -0,0 +1,141 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.runOnDevice = exports.getConnectedDevices = void 0;
const child_process_1 = require("child_process");
const Debug = require("debug");
const fs_1 = require("fs");
const path = require("path");
const errors_1 = require("../../errors");
const process_1 = require("../../utils/process");
const lib_1 = require("../lib");
const xcode_1 = require("./xcode");
const debug = Debug('native-run:ios:utils:device');
async function getConnectedDevices() {
const usbmuxClient = new lib_1.UsbmuxdClient(lib_1.UsbmuxdClient.connectUsbmuxdSocket());
const usbmuxDevices = await usbmuxClient.getDevices();
usbmuxClient.socket.end();
return Promise.all(usbmuxDevices.map(async (d) => {
const socket = await new lib_1.UsbmuxdClient(lib_1.UsbmuxdClient.connectUsbmuxdSocket()).connect(d, 62078);
const device = await new lib_1.LockdowndClient(socket).getAllValues();
socket.end();
// For network-connected devices, UniqueDeviceID may not be present in lockdownd response
// Use SerialNumber from usbmuxd device info as fallback (they are the same value)
if (!device.UniqueDeviceID && d.Properties && d.Properties.SerialNumber) {
device.UniqueDeviceID = d.Properties.SerialNumber;
debug(`Using SerialNumber as UniqueDeviceID for network device: ${device.UniqueDeviceID}`);
}
return device;
}));
}
exports.getConnectedDevices = getConnectedDevices;
async function runOnDevice(udid, appPath, bundleId, waitForApp) {
const clientManager = await lib_1.ClientManager.create(udid);
try {
await mountDeveloperDiskImage(clientManager);
const packageName = path.basename(appPath);
const destPackagePath = path.join('PublicStaging', packageName);
await uploadApp(clientManager, appPath, destPackagePath);
const installer = await clientManager.getInstallationProxyClient();
await installer.installApp(destPackagePath, bundleId);
const { [bundleId]: appInfo } = await installer.lookupApp([bundleId]);
// launch fails with EBusy or ENotFound if you try to launch immediately after install
await (0, process_1.wait)(200);
try {
const debugServerClient = await launchApp(clientManager, appInfo);
if (waitForApp) {
(0, process_1.onBeforeExit)(async () => {
// causes continue() to return
debugServerClient.halt();
// give continue() time to return response
await (0, process_1.wait)(64);
});
debug(`Waiting for app to close...\n`);
const result = await debugServerClient.continue();
// TODO: I have no idea what this packet means yet (successful close?)
// if not a close (ie, most likely due to halt from onBeforeExit), then kill the app
if (result !== 'W00') {
await debugServerClient.kill();
}
}
}
catch {
// if launching app throws, try with devicectl, but requires Xcode 15
const [xcodeVersion] = (0, xcode_1.getXcodeVersionInfo)();
const xcodeMajorVersion = Number(xcodeVersion.split('.')[0]);
if (xcodeMajorVersion >= 15) {
const launchResult = (0, child_process_1.spawn)('xcrun', ['devicectl', 'device', 'process', 'launch', '--device', udid, bundleId]);
return new Promise((resolve, reject) => {
launchResult.on('close', (code) => {
if (code === 0) {
resolve();
}
else {
reject(new errors_1.Exception(`There was an error launching app on device`));
}
});
launchResult.on('error', (err) => {
reject(err);
});
});
}
else {
throw new errors_1.Exception(`running on iOS 17 devices requires Xcode 15 and later`);
}
}
}
finally {
clientManager.end();
}
}
exports.runOnDevice = runOnDevice;
async function mountDeveloperDiskImage(clientManager) {
const imageMounter = await clientManager.getMobileImageMounterClient();
// Check if already mounted. If not, mount.
if (!(await imageMounter.lookupImage()).ImageSignature) {
// verify DeveloperDiskImage exists (TODO: how does this work on Windows/Linux?)
// TODO: if windows/linux, download?
const version = await (await clientManager.getLockdowndClient()).getValue('ProductVersion');
const developerDiskImagePath = await (0, xcode_1.getDeveloperDiskImagePath)(version);
const developerDiskImageSig = (0, fs_1.readFileSync)(`${developerDiskImagePath}.signature`);
await imageMounter.uploadImage(developerDiskImagePath, developerDiskImageSig);
await imageMounter.mountImage(developerDiskImagePath, developerDiskImageSig);
}
}
async function uploadApp(clientManager, srcPath, destinationPath) {
const afcClient = await clientManager.getAFCClient();
try {
await afcClient.getFileInfo('PublicStaging');
}
catch (err) {
if (err instanceof lib_1.AFCError && err.status === lib_1.AFC_STATUS.OBJECT_NOT_FOUND) {
await afcClient.makeDirectory('PublicStaging');
}
else {
throw err;
}
}
await afcClient.uploadDirectory(srcPath, destinationPath);
}
async function launchApp(clientManager, appInfo) {
let tries = 0;
while (tries < 3) {
const debugServerClient = await clientManager.getDebugserverClient();
await debugServerClient.setMaxPacketSize(1024);
await debugServerClient.setWorkingDir(appInfo.Container);
await debugServerClient.launchApp(appInfo.Path, appInfo.CFBundleExecutable);
const result = await debugServerClient.checkLaunchSuccess();
if (result === 'OK') {
return debugServerClient;
}
else if (result === 'EBusy' || result === 'ENotFound') {
debug('Device busy or app not found, trying to launch again in .5s...');
tries++;
debugServerClient.socket.end();
await (0, process_1.wait)(500);
}
else {
throw new errors_1.Exception(`There was an error launching app: ${result}`);
}
}
throw new errors_1.Exception('Unable to launch app, number of tries exceeded');
}

90
node_modules/native-run/dist/ios/utils/simulator.js generated vendored Normal file
View file

@ -0,0 +1,90 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.runOnSimulator = exports.getSimulators = void 0;
const child_process_1 = require("child_process"); // TODO: need cross-spawn for windows?
const Debug = require("debug");
const errors_1 = require("../../errors");
const log_1 = require("../../utils/log");
const process_1 = require("../../utils/process");
const xcode_1 = require("./xcode");
const debug = Debug('native-run:ios:utils:simulator');
async function getSimulators() {
const simctl = (0, child_process_1.spawnSync)('xcrun', ['simctl', 'list', '--json'], {
encoding: 'utf8',
});
if (simctl.status) {
throw new errors_1.Exception(`Unable to retrieve simulator list: ${simctl.stderr}`);
}
try {
const output = JSON.parse(simctl.stdout);
return output.runtimes
.filter((runtime) => runtime.name.indexOf('watch') === -1 && runtime.name.indexOf('tv') === -1)
.map((runtime) => (output.devices[runtime.identifier] || output.devices[runtime.name])
.filter((device) => device.isAvailable)
.map((device) => ({ ...device, runtime })))
.reduce((prev, next) => prev.concat(next)) // flatten
.sort((a, b) => (a.name < b.name ? -1 : 1));
}
catch (err) {
throw new errors_1.Exception(`Unable to retrieve simulator list: ${err.message}`);
}
}
exports.getSimulators = getSimulators;
async function runOnSimulator(udid, appPath, bundleId, waitForApp) {
debug(`Booting simulator ${udid}`);
const bootResult = (0, child_process_1.spawnSync)('xcrun', ['simctl', 'boot', udid], {
encoding: 'utf8',
});
// TODO: is there a better way to check this?
if (bootResult.status && !bootResult.stderr.includes('Unable to boot device in current state: Booted')) {
throw new errors_1.Exception(`There was an error booting simulator: ${bootResult.stderr}`);
}
debug(`Installing ${appPath} on ${udid}`);
const installResult = (0, child_process_1.spawnSync)('xcrun', ['simctl', 'install', udid, appPath], { encoding: 'utf8' });
if (installResult.status) {
throw new errors_1.Exception(`There was an error installing app on simulator: ${installResult.stderr}`);
}
const xCodePath = await (0, xcode_1.getXCodePath)();
debug(`Running simulator ${udid}`);
const openResult = (0, child_process_1.spawnSync)('open', [`${xCodePath}/Applications/Simulator.app`, '--args', '-CurrentDeviceUDID', udid], { encoding: 'utf8' });
if (openResult.status) {
throw new errors_1.Exception(`There was an error opening simulator: ${openResult.stderr}`);
}
debug(`Launching ${appPath} on ${udid}`);
const launchResult = (0, child_process_1.spawnSync)('xcrun', ['simctl', 'launch', udid, bundleId], { encoding: 'utf8' });
if (launchResult.status) {
throw new errors_1.Exception(`There was an error launching app on simulator: ${launchResult.stderr}`);
}
if (waitForApp) {
(0, process_1.onBeforeExit)(async () => {
const terminateResult = (0, child_process_1.spawnSync)('xcrun', ['simctl', 'terminate', udid, bundleId], { encoding: 'utf8' });
if (terminateResult.status) {
debug('Unable to terminate app on simulator');
}
});
(0, log_1.log)(`Waiting for app to close...\n`);
await waitForSimulatorClose(udid, bundleId);
}
}
exports.runOnSimulator = runOnSimulator;
async function waitForSimulatorClose(udid, bundleId) {
return new Promise((resolve) => {
// poll service list for bundle id
const interval = setInterval(async () => {
try {
const data = (0, child_process_1.spawnSync)('xcrun', ['simctl', 'spawn', udid, 'launchctl', 'list'], { encoding: 'utf8' });
// if bundle id isn't in list, app isn't running
if (data.stdout.indexOf(bundleId) === -1) {
clearInterval(interval);
resolve();
}
}
catch (e) {
debug('Error received from launchctl: %O', e);
debug('App %s no longer found in process list for %s', bundleId, udid);
clearInterval(interval);
resolve();
}
}, 500);
});
}

54
node_modules/native-run/dist/ios/utils/xcode.js generated vendored Normal file
View file

@ -0,0 +1,54 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDeveloperDiskImagePath = exports.getXCodePath = exports.getXcodeVersionInfo = void 0;
const utils_fs_1 = require("@ionic/utils-fs");
const child_process_1 = require("child_process");
const errors_1 = require("../../errors");
const process_1 = require("../../utils/process");
function getXcodeVersionInfo() {
const xcodeVersionInfo = (0, child_process_1.spawnSync)('xcodebuild', ['-version'], {
encoding: 'utf8',
});
if (xcodeVersionInfo.error) {
throw xcodeVersionInfo.error;
}
try {
const trimmed = xcodeVersionInfo.stdout.trim().split('\n');
return ['Xcode ', 'Build version'].map((s, i) => trimmed[i].replace(s, ''));
}
catch (error) {
throw new errors_1.Exception(`There was an error trying to retrieve the Xcode version: ${xcodeVersionInfo.stderr}`);
}
}
exports.getXcodeVersionInfo = getXcodeVersionInfo;
async function getXCodePath() {
try {
const { stdout } = await (0, process_1.execFile)('xcode-select', ['-p'], {
encoding: 'utf8',
});
if (stdout) {
return stdout.trim();
}
}
catch {
// ignore
}
throw new errors_1.Exception('Unable to get Xcode location. Is Xcode installed?');
}
exports.getXCodePath = getXCodePath;
async function getDeveloperDiskImagePath(version) {
const xCodePath = await getXCodePath();
const versionDirs = await (0, utils_fs_1.readdir)(`${xCodePath}/Platforms/iPhoneOS.platform/DeviceSupport/`);
const versionPrefix = version.match(/\d+\.\d+/);
if (versionPrefix === null) {
throw new errors_1.Exception(`Invalid iOS version: ${version}`);
}
// Can look like "11.2 (15C107)"
for (const dir of versionDirs) {
if (dir.includes(versionPrefix[0])) {
return `${xCodePath}/Platforms/iPhoneOS.platform/DeviceSupport/${dir}/DeveloperDiskImage.dmg`;
}
}
throw new errors_1.Exception(`Unable to find Developer Disk Image path for SDK ${version}. Do you have the right version of Xcode?`);
}
exports.getDeveloperDiskImagePath = getDeveloperDiskImagePath;