@ebowwa/ios-devices 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/device-ctl.d.ts +128 -0
- package/dist/device-ctl.d.ts.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5365 -0
- package/dist/index.js.map +22 -0
- package/dist/lib-imobiledevice.d.ts +162 -0
- package/dist/lib-imobiledevice.d.ts.map +1 -0
- package/dist/sim-ctl.d.ts +216 -0
- package/dist/sim-ctl.d.ts.map +1 -0
- package/dist/types.d.ts +487 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/unified-api.d.ts +122 -0
- package/dist/unified-api.d.ts.map +1 -0
- package/dist/utils.d.ts +47 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +49 -0
- package/src/device-ctl.ts +547 -0
- package/src/index.ts +8 -0
- package/src/lib-imobiledevice.ts +404 -0
- package/src/shell-quote.d.ts +5 -0
- package/src/sim-ctl.ts +502 -0
- package/src/types.ts +315 -0
- package/src/unified-api.ts +578 -0
- package/src/utils.ts +174 -0
package/src/utils.ts
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command execution utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { spawn } from 'child_process';
|
|
6
|
+
import { parse as parseArgs } from 'shell-quote';
|
|
7
|
+
import { CommandResultSchema, type CommandResult } from './types.js';
|
|
8
|
+
|
|
9
|
+
export interface ExecOptions {
|
|
10
|
+
timeout?: number;
|
|
11
|
+
jsonOutput?: boolean;
|
|
12
|
+
cwd?: string;
|
|
13
|
+
env?: Record<string, string>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Execute a command and return structured result
|
|
18
|
+
*/
|
|
19
|
+
export async function exec(
|
|
20
|
+
command: string,
|
|
21
|
+
args: string[] = [],
|
|
22
|
+
options: ExecOptions = {}
|
|
23
|
+
): Promise<CommandResult> {
|
|
24
|
+
const { timeout = 60000, cwd, env } = options;
|
|
25
|
+
|
|
26
|
+
return new Promise((resolve) => {
|
|
27
|
+
const proc = spawn(command, args, {
|
|
28
|
+
cwd,
|
|
29
|
+
env: { ...process.env, ...env },
|
|
30
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
let stdout = '';
|
|
34
|
+
let stderr = '';
|
|
35
|
+
|
|
36
|
+
proc.stdout?.on('data', (data) => {
|
|
37
|
+
stdout += data.toString();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
proc.stderr?.on('data', (data) => {
|
|
41
|
+
stderr += data.toString();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const timer = setTimeout(() => {
|
|
45
|
+
proc.kill('SIGTERM');
|
|
46
|
+
stderr += '\nCommand timed out';
|
|
47
|
+
}, timeout);
|
|
48
|
+
|
|
49
|
+
proc.on('close', (code) => {
|
|
50
|
+
clearTimeout(timer);
|
|
51
|
+
const result: CommandResult = {
|
|
52
|
+
success: code === 0,
|
|
53
|
+
stdout,
|
|
54
|
+
stderr,
|
|
55
|
+
exitCode: code ?? 1,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Try to parse JSON if output looks like JSON
|
|
59
|
+
const trimmed = stdout.trim();
|
|
60
|
+
if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
|
|
61
|
+
try {
|
|
62
|
+
result.json = JSON.parse(trimmed);
|
|
63
|
+
} catch {
|
|
64
|
+
// Not valid JSON
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
resolve(CommandResultSchema.parse(result));
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
proc.on('error', (err) => {
|
|
72
|
+
clearTimeout(timer);
|
|
73
|
+
resolve({
|
|
74
|
+
success: false,
|
|
75
|
+
stdout,
|
|
76
|
+
stderr: err.message,
|
|
77
|
+
exitCode: 1,
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Execute xcrun devicectl with JSON output
|
|
85
|
+
*/
|
|
86
|
+
export async function execDeviceCtl(
|
|
87
|
+
subcommand: string[],
|
|
88
|
+
options: ExecOptions = {}
|
|
89
|
+
): Promise<CommandResult> {
|
|
90
|
+
const args = ['devicectl', ...subcommand];
|
|
91
|
+
|
|
92
|
+
// Add JSON output for stable parsing
|
|
93
|
+
if (!args.includes('--json-output')) {
|
|
94
|
+
args.push('--json-output', '-');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const result = await exec('xcrun', args, options);
|
|
98
|
+
|
|
99
|
+
// devicectl writes JSON to stderr when using --json-output -
|
|
100
|
+
// but also check stdout
|
|
101
|
+
if (result.stderr && result.stderr.startsWith('{')) {
|
|
102
|
+
try {
|
|
103
|
+
result.json = JSON.parse(result.stderr);
|
|
104
|
+
} catch {
|
|
105
|
+
// Not valid JSON
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Execute libimobiledevice tool
|
|
114
|
+
*/
|
|
115
|
+
export async function execILDevice(
|
|
116
|
+
tool: string,
|
|
117
|
+
args: string[] = [],
|
|
118
|
+
options: ExecOptions = {}
|
|
119
|
+
): Promise<CommandResult> {
|
|
120
|
+
return exec(tool, args, options);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Execute xcrun simctl
|
|
125
|
+
*/
|
|
126
|
+
export async function execSimCtl(
|
|
127
|
+
subcommand: string[],
|
|
128
|
+
options: ExecOptions = {}
|
|
129
|
+
): Promise<CommandResult> {
|
|
130
|
+
return exec('xcrun', ['simctl', ...subcommand], options);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Parse command string into args
|
|
135
|
+
*/
|
|
136
|
+
export function parseCommand(command: string): string[] {
|
|
137
|
+
return parseArgs(command).filter((arg): arg is string => typeof arg === 'string');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Build device identifier argument
|
|
142
|
+
*/
|
|
143
|
+
export function buildDeviceArg(identifier: string): string[] {
|
|
144
|
+
return ['--device', identifier];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Check if a command exists
|
|
149
|
+
*/
|
|
150
|
+
export async function commandExists(command: string): Promise<boolean> {
|
|
151
|
+
const result = await exec('which', [command], { timeout: 5000 });
|
|
152
|
+
return result.success && result.stdout.trim().length > 0;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Check available tools
|
|
157
|
+
*/
|
|
158
|
+
export async function checkAvailableTools(): Promise<{
|
|
159
|
+
devicectl: boolean;
|
|
160
|
+
simctl: boolean;
|
|
161
|
+
libimobiledevice: boolean;
|
|
162
|
+
}> {
|
|
163
|
+
const [devicectl, simctl, libimobiledevice] = await Promise.all([
|
|
164
|
+
commandExists('xcrun').then((exists) => exists && exec('xcrun', ['devicectl', '--version'], { timeout: 5000 }).then((r) => r.success)),
|
|
165
|
+
commandExists('xcrun').then((exists) => exists && exec('xcrun', ['simctl', 'help'], { timeout: 5000 }).then((r) => r.success)),
|
|
166
|
+
commandExists('idevicesyslog'),
|
|
167
|
+
]);
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
devicectl,
|
|
171
|
+
simctl,
|
|
172
|
+
libimobiledevice,
|
|
173
|
+
};
|
|
174
|
+
}
|