@mcesystems/apple-kit 1.0.5 → 1.0.8

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/index.mjs ADDED
@@ -0,0 +1,586 @@
1
+ // src/utils/debug.ts
2
+ import createDebug from "debug";
3
+ var debug = createDebug("apple-kit");
4
+ var debugTask = createDebug("apple-kit:task");
5
+ var debugWarning = createDebug("apple-kit:warning");
6
+ var debugError = createDebug("apple-kit:error");
7
+ function logInfo(message) {
8
+ debug(message);
9
+ }
10
+ function logTask(message) {
11
+ debugTask(message);
12
+ }
13
+
14
+ // src/logic/actions/device.ts
15
+ import { exec as execCallback } from "node:child_process";
16
+ import { existsSync } from "node:fs";
17
+ import { join } from "node:path";
18
+ import { promisify } from "node:util";
19
+
20
+ // src/logic/dataParser.ts
21
+ function parsePlistOutput(output) {
22
+ const result = {};
23
+ const lines = output.split("\n");
24
+ for (const line of lines) {
25
+ const colonIndex = line.indexOf(":");
26
+ if (colonIndex > 0) {
27
+ const key = line.substring(0, colonIndex).trim();
28
+ const value = line.substring(colonIndex + 1).trim();
29
+ result[key] = value;
30
+ }
31
+ }
32
+ return result;
33
+ }
34
+ function parseAppList(output) {
35
+ const apps = [];
36
+ const lines = output.trim().split("\n");
37
+ for (const line of lines) {
38
+ const match = line.match(/^([^,]+),\s*([^,]+),\s*"?([^"]+)"?/);
39
+ if (match) {
40
+ apps.push({
41
+ bundleId: match[1].trim(),
42
+ version: match[2].trim(),
43
+ displayName: match[3].trim(),
44
+ bundleVersion: ""
45
+ });
46
+ }
47
+ }
48
+ return apps;
49
+ }
50
+
51
+ // src/logic/actions/device.ts
52
+ var execAsync = promisify(execCallback);
53
+ async function getDeviceInfo(udid) {
54
+ logTask(`Getting device info for ${udid}`);
55
+ const result = await runIDeviceTool("ideviceinfo", ["-u", udid]);
56
+ if (!result) {
57
+ throw new Error("Failed to get device info");
58
+ }
59
+ const props = parsePlistOutput(result.stdout);
60
+ return {
61
+ deviceName: props.DeviceName || "",
62
+ productType: props.ProductType || "",
63
+ productVersion: props.ProductVersion || "",
64
+ buildVersion: props.BuildVersion || "",
65
+ serialNumber: props.SerialNumber || "",
66
+ udid: props.UniqueDeviceID || udid,
67
+ wifiAddress: props.WiFiAddress || "",
68
+ bluetoothAddress: props.BluetoothAddress || "",
69
+ phoneNumber: props.PhoneNumber || "",
70
+ cpuArchitecture: props.CPUArchitecture || "",
71
+ hardwareModel: props.HardwareModel || "",
72
+ modelNumber: props.ModelNumber || "",
73
+ regionInfo: props.RegionInfo || "",
74
+ timeZone: props.TimeZone || "",
75
+ uniqueChipID: props.UniqueChipID || "",
76
+ isPaired: true
77
+ // If we can get info, device is paired
78
+ };
79
+ }
80
+ async function runIDeviceTool(toolName, args = [], options = {}) {
81
+ const command = `"${toolName}${process.platform === "win32" ? ".exe" : ""}" ${args.map((a) => `"${a}"`).join(" ")}`;
82
+ return execIDevice(command, options);
83
+ }
84
+ async function execIDevice(command, options = {}) {
85
+ const binPath = getIDeviceBinPath();
86
+ options.cwd = binPath;
87
+ const result = await execAsync(command, {
88
+ ...options,
89
+ env: process.env,
90
+ windowsHide: true,
91
+ encoding: "utf8"
92
+ });
93
+ return {
94
+ stdout: result.stdout.toString(),
95
+ stderr: result.stderr.toString()
96
+ };
97
+ }
98
+ function getResourcesBinPath() {
99
+ const binPath = process.env.IDeviceBinPath;
100
+ if (!binPath) {
101
+ throw new Error("IDeviceBinPath is not set");
102
+ }
103
+ return binPath;
104
+ }
105
+ function getIDeviceBinPath() {
106
+ return getResourcesBinPath();
107
+ }
108
+
109
+ // src/logic/actions/activation.ts
110
+ async function getActivationState(udid) {
111
+ logTask(`Getting activation state for device ${udid}`);
112
+ try {
113
+ const result = await runIDeviceTool("ideviceinfo", ["-u", udid, "-k", "ActivationState"]);
114
+ if (!result) {
115
+ return {
116
+ isActivated: false,
117
+ activationState: "Unknown"
118
+ };
119
+ }
120
+ const { stdout } = result;
121
+ const state = stdout.trim();
122
+ return {
123
+ isActivated: state === "Activated",
124
+ activationState: state
125
+ };
126
+ } catch {
127
+ return {
128
+ isActivated: false,
129
+ activationState: "Unknown"
130
+ };
131
+ }
132
+ }
133
+ async function activate(udid) {
134
+ logTask(`Activating device ${udid}`);
135
+ try {
136
+ const result = await runIDeviceTool("ideviceactivation", ["-u", udid, "activate"]);
137
+ if (!result) {
138
+ return false;
139
+ }
140
+ return result.stdout.toLowerCase().includes("success") || result.stdout.toLowerCase().includes("activated");
141
+ } catch (error) {
142
+ const errorMsg = error instanceof Error ? error.message : String(error);
143
+ throw new Error(`Activation failed: ${errorMsg}`);
144
+ }
145
+ }
146
+
147
+ // src/logic/actions/pair.ts
148
+ async function isPaired(udid) {
149
+ logTask(`Checking pairing status for ${udid}`);
150
+ try {
151
+ const result = await runIDeviceTool("idevicepair", ["-u", udid, "validate"]);
152
+ if (!result) {
153
+ return false;
154
+ }
155
+ return result.stdout.toLowerCase().includes("success");
156
+ } catch {
157
+ return false;
158
+ }
159
+ }
160
+ async function trustDevice(udid, timeout = 6e4, onWaitingForTrust) {
161
+ logTask(`Trusting device ${udid}`);
162
+ if (await isPaired(udid)) {
163
+ logInfo(`Device ${udid} is already trusted`);
164
+ return true;
165
+ }
166
+ logInfo(`Initiating pairing for device ${udid}`);
167
+ const pairResult = await pair(udid);
168
+ if (pairResult) {
169
+ logInfo(`Device ${udid} paired successfully`);
170
+ return true;
171
+ }
172
+ logInfo("Please accept the trust dialog on the device...");
173
+ onWaitingForTrust?.();
174
+ try {
175
+ await waitForPairing(udid, timeout, 1e3);
176
+ logInfo(`Device ${udid} is now trusted`);
177
+ return true;
178
+ } catch {
179
+ logInfo(`Timeout waiting for trust acceptance on device ${udid}`);
180
+ return false;
181
+ }
182
+ }
183
+ async function waitForPairing(udid, timeout = 12e4, pollInterval = 1e3) {
184
+ logTask(`Waiting for pairing on device ${udid}`);
185
+ const startTime = Date.now();
186
+ while (Date.now() - startTime < timeout) {
187
+ if (await isPaired(udid)) {
188
+ logInfo(`Device ${udid} is now paired`);
189
+ return true;
190
+ }
191
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
192
+ }
193
+ throw new Error(`Timeout waiting for device pairing after ${timeout}ms`);
194
+ }
195
+ async function pair(udid) {
196
+ logTask(`Initiating pairing for device ${udid}`);
197
+ try {
198
+ const result = await runIDeviceTool("idevicepair", ["-u", udid, "pair"]);
199
+ if (!result) {
200
+ return false;
201
+ }
202
+ return result.stdout.toLowerCase().includes("success");
203
+ } catch (error) {
204
+ const errorMsg = error instanceof Error ? error.message : String(error);
205
+ if (errorMsg.includes("Please accept the trust dialog")) {
206
+ return false;
207
+ }
208
+ throw error;
209
+ }
210
+ }
211
+ async function unpair(udid) {
212
+ logTask(`Un-pairing device ${udid}`);
213
+ try {
214
+ const result = await runIDeviceTool("idevicepair", ["-u", udid, "unpair"]);
215
+ if (!result) {
216
+ return false;
217
+ }
218
+ return result.stdout.toLowerCase().includes("success");
219
+ } catch {
220
+ return false;
221
+ }
222
+ }
223
+
224
+ // src/logic/actions/install.ts
225
+ async function installApp(ipaPath, udid) {
226
+ logTask(`Installing app ${ipaPath} on device ${udid}`);
227
+ if (!await isPaired(udid)) {
228
+ await waitForPairing(udid, 1e4);
229
+ }
230
+ await runIDeviceTool("ideviceinstaller", ["-u", udid, "-i", ipaPath]);
231
+ }
232
+ async function uninstallApp(bundleId, udid) {
233
+ logTask(`Uninstalling app ${bundleId} from device ${udid}`);
234
+ if (!await isPaired(udid)) {
235
+ await waitForPairing(udid, 1e4);
236
+ }
237
+ await runIDeviceTool("ideviceinstaller", ["-u", udid, "-U", bundleId]);
238
+ }
239
+ async function listApps(udid) {
240
+ logTask(`Listing apps on device ${udid}`);
241
+ if (!await isPaired(udid)) {
242
+ await waitForPairing(udid, 1e4);
243
+ }
244
+ try {
245
+ const result = await runIDeviceTool("ideviceinstaller", ["-u", udid, "-l"]);
246
+ if (!result) {
247
+ return [];
248
+ }
249
+ const { stdout } = result;
250
+ return parseAppList(stdout);
251
+ } catch {
252
+ return [];
253
+ }
254
+ }
255
+ async function isAppInstalled(bundleId, udid) {
256
+ logTask(`Checking if app ${bundleId} is installed on device ${udid}`);
257
+ const apps = await listApps(udid);
258
+ return apps.some((app) => app.bundleId === bundleId);
259
+ }
260
+ async function wakeDevice(udid) {
261
+ try {
262
+ logInfo("Attempting to wake device screen...");
263
+ await runIDeviceTool("ideviceinfo", ["-u", udid, "-k", "DeviceName"]);
264
+ try {
265
+ await runIDeviceTool("ideviceinfo", ["-u", udid, "-k", "ActivationState"]);
266
+ } catch {
267
+ }
268
+ try {
269
+ await runIDeviceTool("idevicepair", ["-u", udid, "validate"]);
270
+ } catch {
271
+ }
272
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
273
+ logInfo("Device wake attempt completed");
274
+ } catch (error) {
275
+ logInfo(
276
+ `Device wake attempt failed (non-critical): ${error instanceof Error ? error.message : String(error)}`
277
+ );
278
+ }
279
+ }
280
+ async function launchApp(bundleId, args, udid) {
281
+ logTask(`Launching app ${bundleId} on device ${udid}`);
282
+ if (!await isPaired(udid)) {
283
+ await waitForPairing(udid, 1e4);
284
+ }
285
+ await wakeDevice(udid);
286
+ try {
287
+ logInfo(`Attempting to launch ${bundleId} using idevicedebug...`);
288
+ const result = await runIDeviceTool("idevicedebug", ["-u", udid, "run", bundleId, ...args]);
289
+ const output = (result?.stdout ?? "") + (result?.stderr ?? "");
290
+ if (output.trim()) {
291
+ logInfo(`idevicedebug output: ${output.substring(0, 200)}`);
292
+ }
293
+ if (output.toLowerCase().includes("could not start") && output.toLowerCase().includes("debugserver")) {
294
+ logInfo("idevicedebug requires debugserver, falling back to pymobiledevice3...");
295
+ throw new Error("debugserver_not_available");
296
+ }
297
+ logInfo(`App ${bundleId} launched successfully using idevicedebug`);
298
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
299
+ return;
300
+ } catch (error) {
301
+ const errorMsg = error instanceof Error ? error.message : String(error);
302
+ if (errorMsg.includes("debugserver_not_available") || errorMsg.toLowerCase().includes("could not start") || errorMsg.toLowerCase().includes("debugserver")) {
303
+ logInfo("idevicedebug failed, trying pymobiledevice3 for iOS 17+...");
304
+ await launchAppWithPymobiledevice3(bundleId, args, udid);
305
+ return;
306
+ }
307
+ throw error;
308
+ }
309
+ }
310
+ async function launchAppWithPymobiledevice3(bundleId, args, udid) {
311
+ logTask(`Launching app ${bundleId} using pymobiledevice3`);
312
+ const { exec } = await import("node:child_process");
313
+ const { promisify: promisify2 } = await import("node:util");
314
+ const execAsync2 = promisify2(exec);
315
+ try {
316
+ let cmdArgs = [
317
+ "-m",
318
+ "pymobiledevice3",
319
+ "developer",
320
+ "dvt",
321
+ "launch",
322
+ "--udid",
323
+ udid,
324
+ "--kill-existing",
325
+ // Kill existing instance to bring app to foreground
326
+ bundleId,
327
+ ...args
328
+ ];
329
+ let command = `python ${cmdArgs.map((a) => `"${a}"`).join(" ")}`;
330
+ logInfo(`Executing: ${command}`);
331
+ const result = await execAsync2(command, {
332
+ windowsHide: true,
333
+ encoding: "utf8",
334
+ timeout: 3e4
335
+ // 30 second timeout
336
+ });
337
+ const output = result.stdout.toString() + result.stderr.toString();
338
+ if (output.trim()) {
339
+ logInfo(`pymobiledevice3 output: ${output.substring(0, 200)}`);
340
+ }
341
+ if (output.toLowerCase().includes("developer mode") && output.toLowerCase().includes("not enabled")) {
342
+ throw new Error(
343
+ "Developer Mode is not enabled on the device.\nPlease enable it: Settings \u2192 Privacy & Security \u2192 Developer Mode \u2192 Enable"
344
+ );
345
+ }
346
+ if (output.toLowerCase().includes("tunneld") && (output.toLowerCase().includes("unable to connect") || output.toLowerCase().includes("invalidserviceerror"))) {
347
+ logInfo("Tunnel required, retrying with tunnel option...");
348
+ cmdArgs = [
349
+ "-m",
350
+ "pymobiledevice3",
351
+ "developer",
352
+ "dvt",
353
+ "launch",
354
+ "--udid",
355
+ udid,
356
+ "--tunnel",
357
+ udid,
358
+ // Use UDID for tunnel
359
+ "--kill-existing",
360
+ bundleId,
361
+ ...args
362
+ ];
363
+ command = `python ${cmdArgs.map((a) => `"${a}"`).join(" ")}`;
364
+ logInfo(`Retrying with tunnel: ${command}`);
365
+ try {
366
+ const retryResult = await execAsync2(command, {
367
+ windowsHide: true,
368
+ encoding: "utf8",
369
+ timeout: 3e4
370
+ });
371
+ const retryOutput = retryResult.stdout.toString() + retryResult.stderr.toString();
372
+ if (retryOutput.trim()) {
373
+ logInfo(`pymobiledevice3 retry output: ${retryOutput.substring(0, 200)}`);
374
+ }
375
+ if (retryOutput.toLowerCase().includes("tunneld") && retryOutput.toLowerCase().includes("unable to connect")) {
376
+ throw new Error(
377
+ "Tunnel connection failed. For iOS 17+, you may need to start tunneld:\n python -m pymobiledevice3 remote tunneld\nOr ensure Developer Mode is enabled and device is unlocked."
378
+ );
379
+ }
380
+ logInfo(`App ${bundleId} launched successfully using pymobiledevice3 with tunnel`);
381
+ await new Promise((resolve) => setTimeout(resolve, 500));
382
+ return;
383
+ } catch {
384
+ throw new Error(
385
+ "Tunnel connection failed. For iOS 17+, you may need to start tunneld:\n python -m pymobiledevice3 remote tunneld\nOr ensure Developer Mode is enabled and device is unlocked."
386
+ );
387
+ }
388
+ }
389
+ if (output.toLowerCase().includes("not found") || output.toLowerCase().includes("command not found") || output.toLowerCase().includes("cannot find")) {
390
+ throw new Error(
391
+ "pymobiledevice3 is not installed.\nInstall it with: python -m pip install --user pymobiledevice3"
392
+ );
393
+ }
394
+ if (output.toLowerCase().includes("error") && !output.toLowerCase().includes("warning")) {
395
+ logInfo(`Warning: pymobiledevice3 reported errors: ${output.substring(0, 300)}`);
396
+ }
397
+ logInfo(`App ${bundleId} launched successfully using pymobiledevice3`);
398
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
399
+ } catch (error) {
400
+ const errorMsg = error instanceof Error ? error.message : String(error);
401
+ if (errorMsg.includes("not found") || errorMsg.includes("command not found") || errorMsg.includes("cannot find") || errorMsg.includes("No module named")) {
402
+ throw new Error(
403
+ "pymobiledevice3 is not installed or Python is not available.\nInstall it with: python -m pip install --user pymobiledevice3\nFor iOS 17+, Developer Mode must also be enabled on the device."
404
+ );
405
+ }
406
+ throw error;
407
+ }
408
+ }
409
+
410
+ // src/logic/actions/proxy.ts
411
+ async function startPortForward(localPort, devicePort, udid) {
412
+ logTask(`Starting port forward ${localPort} -> ${devicePort} for device ${udid}`);
413
+ const result = await runIDeviceTool("iproxy", [
414
+ localPort.toString(),
415
+ devicePort.toString(),
416
+ "-u",
417
+ udid
418
+ ]);
419
+ return {
420
+ localPort,
421
+ devicePort,
422
+ ...result
423
+ };
424
+ }
425
+ async function startPortForwardAsync(localPort, devicePort, udid, _timeout = 5e3) {
426
+ const result = await startPortForward(localPort, devicePort, udid);
427
+ await new Promise((resolve) => setTimeout(resolve, 500));
428
+ if (result.stdout.includes("error") || result.stderr.includes("error")) {
429
+ throw new Error("Port forwarding failed to start");
430
+ }
431
+ return result;
432
+ }
433
+ async function closePortForward(udid) {
434
+ logTask(`Closing port forward for device ${udid}`);
435
+ await runIDeviceTool("iproxy", ["-u", udid, "-c"]);
436
+ }
437
+
438
+ // src/logic/appleDeviceKit.ts
439
+ var AppleDeviceKit = class {
440
+ constructor(udid, port) {
441
+ this.port = port;
442
+ this.deviceId = udid;
443
+ logInfo(`AppleDeviceKit initialized for device: ${this.deviceId}`);
444
+ }
445
+ deviceId;
446
+ /**
447
+ * Get detailed device information
448
+ */
449
+ async getDeviceInfo() {
450
+ return getDeviceInfo(this.deviceId);
451
+ }
452
+ /**
453
+ * Check if device is paired/trusted with this computer
454
+ */
455
+ async isPaired() {
456
+ return isPaired(this.deviceId);
457
+ }
458
+ /**
459
+ * Wait for device to be paired
460
+ * Polls the pairing status until successful or timeout
461
+ *
462
+ * @param timeout Timeout in milliseconds (default: 120000)
463
+ * @param pollInterval Poll interval in milliseconds (default: 1000)
464
+ */
465
+ async waitForPairing(timeout = 12e4, pollInterval = 1e3) {
466
+ return waitForPairing(this.deviceId, timeout, pollInterval);
467
+ }
468
+ /**
469
+ * Attempt to pair/trust the device
470
+ * User must accept the trust dialog on the device
471
+ */
472
+ async pair() {
473
+ return pair(this.deviceId);
474
+ }
475
+ /**
476
+ * Trust/pair the device - initiates pairing and waits for user to accept
477
+ *
478
+ * This is the recommended method for establishing trust with a device.
479
+ * It will:
480
+ * 1. Check if already paired
481
+ * 2. If not, initiate pairing (shows "Trust This Computer?" on device)
482
+ * 3. Wait for user to accept the trust dialog
483
+ *
484
+ * @param timeout Timeout in milliseconds to wait for user acceptance (default: 60000)
485
+ * @param onWaitingForTrust Callback when waiting for user to accept trust dialog
486
+ * @returns true if device is now trusted
487
+ */
488
+ async trustDevice(timeout = 6e4, onWaitingForTrust) {
489
+ return trustDevice(this.deviceId, timeout, onWaitingForTrust);
490
+ }
491
+ /**
492
+ * Unpair/untrust the device
493
+ */
494
+ async unpair() {
495
+ return unpair(this.deviceId);
496
+ }
497
+ /**
498
+ * Install an IPA file on the device (install agent)
499
+ *
500
+ * @param ipaPath Path to the IPA file
501
+ */
502
+ async installApp(ipaPath) {
503
+ installApp(ipaPath, this.deviceId);
504
+ }
505
+ /**
506
+ * Uninstall an app by bundle ID (uninstall agent)
507
+ *
508
+ * @param bundleId Application bundle identifier
509
+ */
510
+ async uninstallApp(bundleId) {
511
+ uninstallApp(bundleId, this.deviceId);
512
+ }
513
+ /**
514
+ * Check if an app is installed on the device
515
+ *
516
+ * @param bundleId Application bundle identifier
517
+ */
518
+ async isAppInstalled(bundleId) {
519
+ return isAppInstalled(bundleId, this.deviceId);
520
+ }
521
+ /**
522
+ * List all installed user applications
523
+ */
524
+ async listApps() {
525
+ return listApps(this.deviceId);
526
+ }
527
+ /**
528
+ * Launch an application on the device
529
+ *
530
+ * @param bundleId Application bundle identifier
531
+ * @param args Application arguments
532
+ */
533
+ async launchApp(bundleId, args = []) {
534
+ return launchApp(bundleId, args, this.deviceId);
535
+ }
536
+ /**
537
+ * Start port forwarding and wait for it to be ready.
538
+ * we need port forwarding to be able to connect to the device from the computer
539
+ * and communicate with it using the local port.
540
+ *
541
+ * @param localPort Local port to listen on
542
+ * @param devicePort Device port to forward to
543
+ * @param _timeout Timeout in milliseconds (reserved for future use)
544
+ */
545
+ async startPortForwardAsync(localPort, devicePort, _timeout = 5e3) {
546
+ return startPortForwardAsync(localPort, devicePort, this.deviceId);
547
+ }
548
+ /**
549
+ * Get the activation state of the device
550
+ */
551
+ async getActivationState() {
552
+ return getActivationState(this.deviceId);
553
+ }
554
+ /**
555
+ * Activate the device (register in apple servers), an activated device belongs to someone (a user/company).
556
+ * A device that is on hello screen cannot pass the wifi step unless it is activated.
557
+ * the activate save us the need of the device to be connected to the internet to do the activation
558
+ * and register in apple servers.
559
+ *
560
+ * Note: This requires a valid activation record or Apple server access
561
+ *
562
+ * precondition: the device must be paired and trusted
563
+ */
564
+ async activate() {
565
+ return activate(this.deviceId);
566
+ }
567
+ /**
568
+ * Get the device UDID
569
+ */
570
+ getDeviceId() {
571
+ return this.deviceId;
572
+ }
573
+ /**
574
+ * Get the logical port number
575
+ */
576
+ getPort() {
577
+ return this.port;
578
+ }
579
+ async closePortForward() {
580
+ return closePortForward(this.deviceId);
581
+ }
582
+ };
583
+ export {
584
+ AppleDeviceKit
585
+ };
586
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/utils/debug.ts", "../src/logic/actions/device.ts", "../src/logic/dataParser.ts", "../src/logic/actions/activation.ts", "../src/logic/actions/pair.ts", "../src/logic/actions/install.ts", "../src/logic/actions/proxy.ts", "../src/logic/appleDeviceKit.ts"],
4
+ "sourcesContent": ["import createDebug from \"debug\";\n\nconst debug = createDebug(\"apple-kit\");\nconst debugTask = createDebug(\"apple-kit:task\");\nconst debugWarning = createDebug(\"apple-kit:warning\");\nconst debugError = createDebug(\"apple-kit:error\");\n\n/**\n * Log general information\n */\nexport function logInfo(message: string): void {\n\tdebug(message);\n}\n\n/**\n * Log task-specific information\n */\nexport function logTask(message: string): void {\n\tdebugTask(message);\n}\n\n/**\n * Log warning messages\n */\nexport function logWarning(message: string): void {\n\tdebugWarning(message);\n}\n\n/**\n * Log error messages\n */\nexport function logError(message: string): void {\n\tdebugError(message);\n}\n", "import { type ExecOptions, exec as execCallback } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport type { AppleToolType, DeviceListEntry } from \"@/types\";\nimport type { iOSDeviceInfo } from \"@/types\";\nimport { logTask } from \"@/utils/debug\";\nimport { parseDeviceList, parsePlistOutput } from \"../dataParser\";\n\nconst execAsync = promisify(execCallback);\n\nexport interface ExecResult {\n\tstdout: string;\n\tstderr: string;\n}\n\nexport async function getDeviceInfo(udid: string): Promise<iOSDeviceInfo> {\n\tlogTask(`Getting device info for ${udid}`);\n\n\tconst result = await runIDeviceTool(\"ideviceinfo\", [\"-u\", udid]);\n\tif (!result) {\n\t\tthrow new Error(\"Failed to get device info\");\n\t}\n\n\tconst props = parsePlistOutput(result.stdout);\n\n\treturn {\n\t\tdeviceName: props.DeviceName || \"\",\n\t\tproductType: props.ProductType || \"\",\n\t\tproductVersion: props.ProductVersion || \"\",\n\t\tbuildVersion: props.BuildVersion || \"\",\n\t\tserialNumber: props.SerialNumber || \"\",\n\t\tudid: props.UniqueDeviceID || udid,\n\t\twifiAddress: props.WiFiAddress || \"\",\n\t\tbluetoothAddress: props.BluetoothAddress || \"\",\n\t\tphoneNumber: props.PhoneNumber || \"\",\n\t\tcpuArchitecture: props.CPUArchitecture || \"\",\n\t\thardwareModel: props.HardwareModel || \"\",\n\t\tmodelNumber: props.ModelNumber || \"\",\n\t\tregionInfo: props.RegionInfo || \"\",\n\t\ttimeZone: props.TimeZone || \"\",\n\t\tuniqueChipID: props.UniqueChipID || \"\",\n\t\tisPaired: true, // If we can get info, device is paired\n\t};\n}\n\nexport async function listDevices(): Promise<DeviceListEntry[]> {\n\ttry {\n\t\tconst result = await runIDeviceTool(\"idevice_id\", [\"-l\"]);\n\t\tif (!result) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn parseDeviceList(result.stdout);\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n/**\n * Execute an idevice tool command\n */\nexport async function runIDeviceTool(\n\ttoolName: AppleToolType,\n\targs: string[] = [],\n\toptions: ExecOptions = {}\n): Promise<ExecResult> {\n\tconst command = `\"${toolName}${process.platform === \"win32\" ? \".exe\" : \"\"}\" ${args.map((a) => `\"${a}\"`).join(\" \")}`;\n\treturn execIDevice(command, options);\n}\n\n/**\n * Execute a command with idevice tools in PATH\n */\nasync function execIDevice(command: string, options: ExecOptions = {}): Promise<ExecResult> {\n\tconst binPath = getIDeviceBinPath();\n\n\toptions.cwd = binPath;\n\n\tconst result = await execAsync(command, {\n\t\t...options,\n\t\tenv: process.env,\n\t\twindowsHide: true,\n\t\tencoding: \"utf8\",\n\t});\n\n\treturn {\n\t\tstdout: result.stdout.toString(),\n\t\tstderr: result.stderr.toString(),\n\t};\n}\n\n/**\n * Get the path to idevice binaries from resources\n */\nfunction getResourcesBinPath(): string {\n\tconst binPath = process.env.IDeviceBinPath;\n\tif (!binPath) {\n\t\tthrow new Error(\"IDeviceBinPath is not set\");\n\t}\n\treturn binPath;\n}\n\n/**\n * Get the path to a specific idevice tool\n */\nfunction getIDeviceToolPath(toolName: string): string | null {\n\tconst binPath = getResourcesBinPath();\n\tconst ext = process.platform === \"win32\" ? \".exe\" : \"\";\n\tconst toolPath = join(binPath, `${toolName}${ext}`);\n\n\tif (existsSync(toolPath)) {\n\t\treturn toolPath;\n\t}\n\n\treturn null;\n}\n\n/**\n * Get paths to all required idevice tools\n */\nexport function getIDeviceTools() {\n\treturn {\n\t\tidevice_id: getIDeviceToolPath(\"idevice_id\"),\n\t\tideviceinfo: getIDeviceToolPath(\"ideviceinfo\"),\n\t\tideviceinstaller: getIDeviceToolPath(\"ideviceinstaller\"),\n\t\tidevicepair: getIDeviceToolPath(\"idevicepair\"),\n\t\tidevicename: getIDeviceToolPath(\"idevicename\"),\n\t\tidevicedebug: getIDeviceToolPath(\"idevicedebug\"),\n\t\tiproxy: getIDeviceToolPath(\"iproxy\"),\n\t\tideviceactivation: getIDeviceToolPath(\"ideviceactivation\"),\n\t};\n}\n\n/**\n * Get the bin path for PATH environment variable\n */\nfunction getIDeviceBinPath(): string {\n\treturn getResourcesBinPath();\n}\n", "import type { AppInfo, DeviceListEntry } from \"../types\";\n\n/**\n * Parse plist-style output from ideviceinfo\n *\n * @param output ideviceinfo output\n * @returns Plist output\n */\nexport function parsePlistOutput(output: string): Record<string, string> {\n\tconst result: Record<string, string> = {};\n\tconst lines = output.split(\"\\n\");\n\n\tfor (const line of lines) {\n\t\tconst colonIndex = line.indexOf(\":\");\n\t\tif (colonIndex > 0) {\n\t\t\tconst key = line.substring(0, colonIndex).trim();\n\t\t\tconst value = line.substring(colonIndex + 1).trim();\n\t\t\tresult[key] = value;\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Parse idevice_id output\n *\n * @param output idevice_id output\n * @returns Device list\n */\nexport function parseDeviceList(output: string): DeviceListEntry[] {\n\tconst devices: DeviceListEntry[] = [];\n\tconst lines = output.trim().split(\"\\n\");\n\n\tfor (const line of lines) {\n\t\tconst trimmed = line.trim();\n\t\tif (trimmed) {\n\t\t\t// Format: \"UDID (connection type)\" or just \"UDID\"\n\t\t\tconst match = trimmed.match(/^([A-Fa-f0-9-]+)(?:\\s+\\((\\w+)\\))?/);\n\t\t\tif (match) {\n\t\t\t\tdevices.push({\n\t\t\t\t\tudid: match[1],\n\t\t\t\t\tconnectionType: match[2] === \"Network\" ? 2 : 1,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn devices;\n}\n\n/**\n * Parse ideviceinstaller list output\n *\n * @param output ideviceinstaller list output\n * @returns App list\n */\nexport function parseAppList(output: string): AppInfo[] {\n\tconst apps: AppInfo[] = [];\n\tconst lines = output.trim().split(\"\\n\");\n\n\tfor (const line of lines) {\n\t\t// Format: \"com.example.app, Version, \"Display Name\"\"\n\t\tconst match = line.match(/^([^,]+),\\s*([^,]+),\\s*\"?([^\"]+)\"?/);\n\t\tif (match) {\n\t\t\tapps.push({\n\t\t\t\tbundleId: match[1].trim(),\n\t\t\t\tversion: match[2].trim(),\n\t\t\t\tdisplayName: match[3].trim(),\n\t\t\t\tbundleVersion: \"\",\n\t\t\t});\n\t\t}\n\t}\n\n\treturn apps;\n}\n", "import type { ActivationState } from \"@/types\";\nimport { logTask } from \"@/utils/debug\";\nimport { runIDeviceTool } from \"./device\";\n\nexport async function getActivationState(udid: string): Promise<ActivationState> {\n\tlogTask(`Getting activation state for device ${udid}`);\n\n\ttry {\n\t\tconst result = await runIDeviceTool(\"ideviceinfo\", [\"-u\", udid, \"-k\", \"ActivationState\"]);\n\t\tif (!result) {\n\t\t\treturn {\n\t\t\t\tisActivated: false,\n\t\t\t\tactivationState: \"Unknown\",\n\t\t\t};\n\t\t}\n\n\t\tconst { stdout } = result;\n\t\tconst state = stdout.trim();\n\n\t\treturn {\n\t\t\tisActivated: state === \"Activated\",\n\t\t\tactivationState: state,\n\t\t};\n\t} catch {\n\t\treturn {\n\t\t\tisActivated: false,\n\t\t\tactivationState: \"Unknown\",\n\t\t};\n\t}\n}\n\nexport async function activate(udid: string): Promise<boolean> {\n\tlogTask(`Activating device ${udid}`);\n\n\ttry {\n\t\tconst result = await runIDeviceTool(\"ideviceactivation\", [\"-u\", udid, \"activate\"]);\n\t\tif (!result) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn (\n\t\t\tresult.stdout.toLowerCase().includes(\"success\") ||\n\t\t\tresult.stdout.toLowerCase().includes(\"activated\")\n\t\t);\n\t} catch (error) {\n\t\tconst errorMsg = error instanceof Error ? error.message : String(error);\n\t\tthrow new Error(`Activation failed: ${errorMsg}`);\n\t}\n}\n\nexport interface ApplicationConfig {\n\tname: string;\n\tbundleId: string;\n\tversion: string;\n\tbuild: string;\n\ticon: string;\n\ticonData: Buffer;\n}\n", "import { logInfo, logTask } from \"@/utils/debug\";\nimport { runIDeviceTool } from \"./device\";\n\nexport async function isPaired(udid: string): Promise<boolean> {\n\tlogTask(`Checking pairing status for ${udid}`);\n\n\ttry {\n\t\tconst result = await runIDeviceTool(\"idevicepair\", [\"-u\", udid, \"validate\"]);\n\t\tif (!result) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn result.stdout.toLowerCase().includes(\"success\");\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport async function trustDevice(\n\tudid: string,\n\ttimeout = 60000,\n\tonWaitingForTrust?: () => void\n): Promise<boolean> {\n\tlogTask(`Trusting device ${udid}`);\n\n\t// Check if already paired\n\tif (await isPaired(udid)) {\n\t\tlogInfo(`Device ${udid} is already trusted`);\n\t\treturn true;\n\t}\n\n\t// Initiate pairing - this shows the trust dialog on the device\n\tlogInfo(`Initiating pairing for device ${udid}`);\n\tconst pairResult = await pair(udid);\n\n\tif (pairResult) {\n\t\tlogInfo(`Device ${udid} paired successfully`);\n\t\treturn true;\n\t}\n\n\t// Pairing initiated but user needs to accept on device\n\tlogInfo(\"Please accept the trust dialog on the device...\");\n\tonWaitingForTrust?.();\n\n\t// Wait for user to accept\n\ttry {\n\t\tawait waitForPairing(udid, timeout, 1000);\n\t\tlogInfo(`Device ${udid} is now trusted`);\n\t\treturn true;\n\t} catch {\n\t\tlogInfo(`Timeout waiting for trust acceptance on device ${udid}`);\n\t\treturn false;\n\t}\n}\n\nexport async function waitForPairing(\n\tudid: string,\n\ttimeout = 120000,\n\tpollInterval = 1000\n): Promise<boolean> {\n\tlogTask(`Waiting for pairing on device ${udid}`);\n\n\tconst startTime = Date.now();\n\n\twhile (Date.now() - startTime < timeout) {\n\t\tif (await isPaired(udid)) {\n\t\t\tlogInfo(`Device ${udid} is now paired`);\n\t\t\treturn true;\n\t\t}\n\n\t\tawait new Promise((resolve) => setTimeout(resolve, pollInterval));\n\t}\n\n\tthrow new Error(`Timeout waiting for device pairing after ${timeout}ms`);\n}\n\nexport async function pair(udid: string): Promise<boolean> {\n\tlogTask(`Initiating pairing for device ${udid}`);\n\n\ttry {\n\t\tconst result = await runIDeviceTool(\"idevicepair\", [\"-u\", udid, \"pair\"]);\n\t\tif (!result) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn result.stdout.toLowerCase().includes(\"success\");\n\t} catch (error) {\n\t\tconst errorMsg = error instanceof Error ? error.message : String(error);\n\t\tif (errorMsg.includes(\"Please accept the trust dialog\")) {\n\t\t\t// Pairing dialog shown on device\n\t\t\treturn false;\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nexport async function unpair(udid: string): Promise<boolean> {\n\tlogTask(`Un-pairing device ${udid}`);\n\n\ttry {\n\t\tconst result = await runIDeviceTool(\"idevicepair\", [\"-u\", udid, \"unpair\"]);\n\t\tif (!result) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn result.stdout.toLowerCase().includes(\"success\");\n\t} catch {\n\t\treturn false;\n\t}\n}\n", "import type { AppInfo } from \"@/types\";\nimport { logInfo, logTask } from \"@/utils/debug\";\nimport { parseAppList } from \"../dataParser\";\nimport { runIDeviceTool } from \"./device\";\nimport { isPaired, waitForPairing } from \"./pair\";\n\nexport async function installApp(ipaPath: string, udid: string): Promise<void> {\n\tlogTask(`Installing app ${ipaPath} on device ${udid}`);\n\n\tif (!(await isPaired(udid))) {\n\t\tawait waitForPairing(udid, 10000);\n\t}\n\n\tawait runIDeviceTool(\"ideviceinstaller\", [\"-u\", udid, \"-i\", ipaPath]);\n}\n\nexport async function uninstallApp(bundleId: string, udid: string): Promise<void> {\n\tlogTask(`Uninstalling app ${bundleId} from device ${udid}`);\n\n\tif (!(await isPaired(udid))) {\n\t\tawait waitForPairing(udid, 10000);\n\t}\n\n\tawait runIDeviceTool(\"ideviceinstaller\", [\"-u\", udid, \"-U\", bundleId]);\n}\n\nexport async function listApps(udid: string): Promise<AppInfo[]> {\n\tlogTask(`Listing apps on device ${udid}`);\n\n\tif (!(await isPaired(udid))) {\n\t\tawait waitForPairing(udid, 10000);\n\t}\n\n\ttry {\n\t\tconst result = await runIDeviceTool(\"ideviceinstaller\", [\"-u\", udid, \"-l\"]);\n\t\tif (!result) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst { stdout } = result;\n\t\treturn parseAppList(stdout);\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nexport async function isAppInstalled(bundleId: string, udid: string): Promise<boolean> {\n\tlogTask(`Checking if app ${bundleId} is installed on device ${udid}`);\n\n\tconst apps = await listApps(udid);\n\treturn apps.some((app) => app.bundleId === bundleId);\n}\n\nexport async function wakeDevice(udid: string): Promise<void> {\n\ttry {\n\t\tlogInfo(\"Attempting to wake device screen...\");\n\n\t\t// Try multiple methods to wake the device\n\t\t// Method 1: Query device info (wakes some devices)\n\t\tawait runIDeviceTool(\"ideviceinfo\", [\"-u\", udid, \"-k\", \"DeviceName\"]);\n\n\t\t// Method 2: Try to get activation state (another wake trigger)\n\t\ttry {\n\t\t\tawait runIDeviceTool(\"ideviceinfo\", [\"-u\", udid, \"-k\", \"ActivationState\"]);\n\t\t} catch {\n\t\t\t// Ignore\n\t\t}\n\n\t\t// Method 3: Try to validate pairing (another interaction that might wake)\n\t\ttry {\n\t\t\tawait runIDeviceTool(\"idevicepair\", [\"-u\", udid, \"validate\"]);\n\t\t} catch {\n\t\t\t// Ignore\n\t\t}\n\n\t\t// Longer delay to let screen wake and stabilize\n\t\tawait new Promise((resolve) => setTimeout(resolve, 1000));\n\n\t\tlogInfo(\"Device wake attempt completed\");\n\t} catch (error) {\n\t\t// Log but don't fail - waking is best effort\n\t\tlogInfo(\n\t\t\t`Device wake attempt failed (non-critical): ${error instanceof Error ? error.message : String(error)}`\n\t\t);\n\t}\n}\n\nexport async function launchApp(bundleId: string, args: string[], udid: string): Promise<void> {\n\tlogTask(`Launching app ${bundleId} on device ${udid}`);\n\n\tif (!(await isPaired(udid))) {\n\t\tawait waitForPairing(udid, 10000);\n\t}\n\n\t// Wake device screen first to ensure app appears\n\tawait wakeDevice(udid);\n\n\t// Try idevicedebug first (works for iOS 16 and earlier)\n\ttry {\n\t\tlogInfo(`Attempting to launch ${bundleId} using idevicedebug...`);\n\t\tconst result = await runIDeviceTool(\"idevicedebug\", [\"-u\", udid, \"run\", bundleId, ...args]);\n\t\tconst output = (result?.stdout ?? \"\") + (result?.stderr ?? \"\");\n\n\t\t// Log output for debugging\n\t\tif (output.trim()) {\n\t\t\tlogInfo(`idevicedebug output: ${output.substring(0, 200)}`);\n\t\t}\n\n\t\t// Check if it failed due to missing debugserver\n\t\tif (\n\t\t\toutput.toLowerCase().includes(\"could not start\") &&\n\t\t\toutput.toLowerCase().includes(\"debugserver\")\n\t\t) {\n\t\t\tlogInfo(\"idevicedebug requires debugserver, falling back to pymobiledevice3...\");\n\t\t\tthrow new Error(\"debugserver_not_available\");\n\t\t}\n\n\t\t// Success - app should be launched\n\t\tlogInfo(`App ${bundleId} launched successfully using idevicedebug`);\n\n\t\t// Additional delay to ensure app appears\n\t\tawait new Promise((resolve) => setTimeout(resolve, 1000));\n\t\treturn;\n\t} catch (error) {\n\t\tconst errorMsg = error instanceof Error ? error.message : String(error);\n\n\t\t// If debugserver is not available, try pymobiledevice3 (iOS 17+)\n\t\tif (\n\t\t\terrorMsg.includes(\"debugserver_not_available\") ||\n\t\t\terrorMsg.toLowerCase().includes(\"could not start\") ||\n\t\t\terrorMsg.toLowerCase().includes(\"debugserver\")\n\t\t) {\n\t\t\tlogInfo(\"idevicedebug failed, trying pymobiledevice3 for iOS 17+...\");\n\t\t\tawait launchAppWithPymobiledevice3(bundleId, args, udid);\n\t\t\treturn;\n\t\t}\n\n\t\t// Re-throw other errors\n\t\tthrow error;\n\t}\n}\n\nexport async function launchAppWithPymobiledevice3(\n\tbundleId: string,\n\targs: string[],\n\tudid: string\n): Promise<void> {\n\tlogTask(`Launching app ${bundleId} using pymobiledevice3`);\n\n\tconst { exec } = await import(\"node:child_process\");\n\tconst { promisify } = await import(\"node:util\");\n\tconst execAsync = promisify(exec);\n\n\ttry {\n\t\t// Build command: python -m pymobiledevice3 developer dvt launch --udid <UDID> --tunnel \"\" --kill-existing <bundle-id> [args...]\n\t\t// Use --tunnel \"\" to auto-detect/create tunnel for iOS 17+\n\t\t// Use --kill-existing to ensure app comes to foreground\n\t\t// Use python -m to avoid PATH issues\n\t\t// Try without tunnel first (works for some iOS versions)\n\t\t// If that fails, we'll try with tunnel\n\t\tlet cmdArgs = [\n\t\t\t\"-m\",\n\t\t\t\"pymobiledevice3\",\n\t\t\t\"developer\",\n\t\t\t\"dvt\",\n\t\t\t\"launch\",\n\t\t\t\"--udid\",\n\t\t\tudid,\n\t\t\t\"--kill-existing\", // Kill existing instance to bring app to foreground\n\t\t\tbundleId,\n\t\t\t...args,\n\t\t];\n\n\t\tlet command = `python ${cmdArgs.map((a) => `\"${a}\"`).join(\" \")}`;\n\n\t\tlogInfo(`Executing: ${command}`);\n\n\t\tconst result = await execAsync(command, {\n\t\t\twindowsHide: true,\n\t\t\tencoding: \"utf8\",\n\t\t\ttimeout: 30000, // 30 second timeout\n\t\t});\n\n\t\tconst output = result.stdout.toString() + result.stderr.toString();\n\n\t\t// Log output for debugging\n\t\tif (output.trim()) {\n\t\t\tlogInfo(`pymobiledevice3 output: ${output.substring(0, 200)}`);\n\t\t}\n\n\t\t// Check for common errors\n\t\tif (\n\t\t\toutput.toLowerCase().includes(\"developer mode\") &&\n\t\t\toutput.toLowerCase().includes(\"not enabled\")\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Developer Mode is not enabled on the device.\\n\" +\n\t\t\t\t\t\"Please enable it: Settings \u2192 Privacy & Security \u2192 Developer Mode \u2192 Enable\"\n\t\t\t);\n\t\t}\n\n\t\t// If tunnel error, try again with tunnel option\n\t\tif (\n\t\t\toutput.toLowerCase().includes(\"tunneld\") &&\n\t\t\t(output.toLowerCase().includes(\"unable to connect\") ||\n\t\t\t\toutput.toLowerCase().includes(\"invalidserviceerror\"))\n\t\t) {\n\t\t\tlogInfo(\"Tunnel required, retrying with tunnel option...\");\n\n\t\t\t// Retry with tunnel\n\t\t\tcmdArgs = [\n\t\t\t\t\"-m\",\n\t\t\t\t\"pymobiledevice3\",\n\t\t\t\t\"developer\",\n\t\t\t\t\"dvt\",\n\t\t\t\t\"launch\",\n\t\t\t\t\"--udid\",\n\t\t\t\tudid,\n\t\t\t\t\"--tunnel\",\n\t\t\t\tudid, // Use UDID for tunnel\n\t\t\t\t\"--kill-existing\",\n\t\t\t\tbundleId,\n\t\t\t\t...args,\n\t\t\t];\n\n\t\t\tcommand = `python ${cmdArgs.map((a) => `\"${a}\"`).join(\" \")}`;\n\t\t\tlogInfo(`Retrying with tunnel: ${command}`);\n\n\t\t\ttry {\n\t\t\t\tconst retryResult = await execAsync(command, {\n\t\t\t\t\twindowsHide: true,\n\t\t\t\t\tencoding: \"utf8\",\n\t\t\t\t\ttimeout: 30000,\n\t\t\t\t});\n\n\t\t\t\tconst retryOutput = retryResult.stdout.toString() + retryResult.stderr.toString();\n\t\t\t\tif (retryOutput.trim()) {\n\t\t\t\t\tlogInfo(`pymobiledevice3 retry output: ${retryOutput.substring(0, 200)}`);\n\t\t\t\t}\n\n\t\t\t\t// Check if still failing\n\t\t\t\tif (\n\t\t\t\t\tretryOutput.toLowerCase().includes(\"tunneld\") &&\n\t\t\t\t\tretryOutput.toLowerCase().includes(\"unable to connect\")\n\t\t\t\t) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"Tunnel connection failed. For iOS 17+, you may need to start tunneld:\\n\" +\n\t\t\t\t\t\t\t\" python -m pymobiledevice3 remote tunneld\\n\" +\n\t\t\t\t\t\t\t\"Or ensure Developer Mode is enabled and device is unlocked.\"\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Success on retry\n\t\t\t\tlogInfo(`App ${bundleId} launched successfully using pymobiledevice3 with tunnel`);\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 500));\n\t\t\t\treturn;\n\t\t\t} catch {\n\t\t\t\t// If retry also fails, throw the original tunnel error\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Tunnel connection failed. For iOS 17+, you may need to start tunneld:\\n\" +\n\t\t\t\t\t\t\" python -m pymobiledevice3 remote tunneld\\n\" +\n\t\t\t\t\t\t\"Or ensure Developer Mode is enabled and device is unlocked.\"\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (\n\t\t\toutput.toLowerCase().includes(\"not found\") ||\n\t\t\toutput.toLowerCase().includes(\"command not found\") ||\n\t\t\toutput.toLowerCase().includes(\"cannot find\")\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t\"pymobiledevice3 is not installed.\\n\" +\n\t\t\t\t\t\"Install it with: python -m pip install --user pymobiledevice3\"\n\t\t\t);\n\t\t}\n\n\t\t// Check if there are any errors in output\n\t\tif (output.toLowerCase().includes(\"error\") && !output.toLowerCase().includes(\"warning\")) {\n\t\t\t// Some errors might be non-fatal, but log them\n\t\t\tlogInfo(`Warning: pymobiledevice3 reported errors: ${output.substring(0, 300)}`);\n\t\t}\n\n\t\tlogInfo(`App ${bundleId} launched successfully using pymobiledevice3`);\n\n\t\t// Longer delay to ensure app appears on screen and device wakes\n\t\tawait new Promise((resolve) => setTimeout(resolve, 1000));\n\t} catch (error) {\n\t\tconst errorMsg = error instanceof Error ? error.message : String(error);\n\n\t\t// Check if it's a command not found error\n\t\tif (\n\t\t\terrorMsg.includes(\"not found\") ||\n\t\t\terrorMsg.includes(\"command not found\") ||\n\t\t\terrorMsg.includes(\"cannot find\") ||\n\t\t\terrorMsg.includes(\"No module named\")\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t\"pymobiledevice3 is not installed or Python is not available.\\n\" +\n\t\t\t\t\t\"Install it with: python -m pip install --user pymobiledevice3\\n\" +\n\t\t\t\t\t\"For iOS 17+, Developer Mode must also be enabled on the device.\"\n\t\t\t);\n\t\t}\n\n\t\tthrow error;\n\t}\n}\n", "import type { PortForwardResult } from \"@/types\";\nimport { logTask } from \"@/utils/debug\";\nimport { runIDeviceTool } from \"./device\";\n\nasync function startPortForward(\n\tlocalPort: number,\n\tdevicePort: number,\n\tudid: string\n): Promise<PortForwardResult> {\n\tlogTask(`Starting port forward ${localPort} -> ${devicePort} for device ${udid}`);\n\n\tconst result = await runIDeviceTool(\"iproxy\", [\n\t\tlocalPort.toString(),\n\t\tdevicePort.toString(),\n\t\t\"-u\",\n\t\tudid,\n\t]);\n\n\treturn {\n\t\tlocalPort,\n\t\tdevicePort,\n\t\t...result,\n\t};\n}\n\nexport async function startPortForwardAsync(\n\tlocalPort: number,\n\tdevicePort: number,\n\tudid: string,\n\t_timeout = 5000\n): Promise<PortForwardResult> {\n\tconst result = await startPortForward(localPort, devicePort, udid);\n\n\t// Give iproxy a moment to start\n\tawait new Promise((resolve) => setTimeout(resolve, 500));\n\n\t// Check if process is still running\n\tif (result.stdout.includes(\"error\") || result.stderr.includes(\"error\")) {\n\t\tthrow new Error(\"Port forwarding failed to start\");\n\t}\n\n\treturn result;\n}\n\nexport async function closePortForward(udid: string): Promise<void> {\n\tlogTask(`Closing port forward for device ${udid}`);\n\tawait runIDeviceTool(\"iproxy\", [\"-u\", udid, \"-c\"]);\n}\n", "import type { ActivationState, AppInfo, PortForwardResult, iOSDeviceInfo } from \"../types\";\nimport { logInfo } from \"../utils/debug\";\nimport { activate, getActivationState } from \"./actions/activation\";\nimport { getDeviceInfo } from \"./actions/device\";\nimport { installApp, isAppInstalled, launchApp, listApps, uninstallApp } from \"./actions/install\";\nimport { isPaired, pair, trustDevice, unpair, waitForPairing } from \"./actions/pair\";\nimport { closePortForward, startPortForwardAsync } from \"./actions/proxy\";\n\n/**\n * AppleDeviceKit - iOS device operations wrapper\n *\n * Uses idevice command-line tools for iOS device operations.\n * Each instance is associated with a specific device by UDID.\n */\nexport class AppleDeviceKit {\n\tprivate deviceId: string;\n\n\tconstructor(\n\t\tudid: string,\n\t\tprivate readonly port: number\n\t) {\n\t\tthis.deviceId = udid;\n\t\tlogInfo(`AppleDeviceKit initialized for device: ${this.deviceId}`);\n\t}\n\n\t/**\n\t * Get detailed device information\n\t */\n\tpublic async getDeviceInfo(): Promise<iOSDeviceInfo> {\n\t\treturn getDeviceInfo(this.deviceId);\n\t}\n\n\t/**\n\t * Check if device is paired/trusted with this computer\n\t */\n\tpublic async isPaired(): Promise<boolean> {\n\t\treturn isPaired(this.deviceId);\n\t}\n\n\t/**\n\t * Wait for device to be paired\n\t * Polls the pairing status until successful or timeout\n\t *\n\t * @param timeout Timeout in milliseconds (default: 120000)\n\t * @param pollInterval Poll interval in milliseconds (default: 1000)\n\t */\n\tpublic async waitForPairing(timeout = 120000, pollInterval = 1000): Promise<boolean> {\n\t\treturn waitForPairing(this.deviceId, timeout, pollInterval);\n\t}\n\n\t/**\n\t * Attempt to pair/trust the device\n\t * User must accept the trust dialog on the device\n\t */\n\tpublic async pair(): Promise<boolean> {\n\t\treturn pair(this.deviceId);\n\t}\n\n\t/**\n\t * Trust/pair the device - initiates pairing and waits for user to accept\n\t *\n\t * This is the recommended method for establishing trust with a device.\n\t * It will:\n\t * 1. Check if already paired\n\t * 2. If not, initiate pairing (shows \"Trust This Computer?\" on device)\n\t * 3. Wait for user to accept the trust dialog\n\t *\n\t * @param timeout Timeout in milliseconds to wait for user acceptance (default: 60000)\n\t * @param onWaitingForTrust Callback when waiting for user to accept trust dialog\n\t * @returns true if device is now trusted\n\t */\n\tpublic async trustDevice(timeout = 60000, onWaitingForTrust?: () => void): Promise<boolean> {\n\t\treturn trustDevice(this.deviceId, timeout, onWaitingForTrust);\n\t}\n\n\t/**\n\t * Unpair/untrust the device\n\t */\n\tpublic async unpair(): Promise<boolean> {\n\t\treturn unpair(this.deviceId);\n\t}\n\n\t/**\n\t * Install an IPA file on the device (install agent)\n\t *\n\t * @param ipaPath Path to the IPA file\n\t */\n\tpublic async installApp(ipaPath: string): Promise<void> {\n\t\tinstallApp(ipaPath, this.deviceId);\n\t}\n\n\t/**\n\t * Uninstall an app by bundle ID (uninstall agent)\n\t *\n\t * @param bundleId Application bundle identifier\n\t */\n\tpublic async uninstallApp(bundleId: string): Promise<void> {\n\t\tuninstallApp(bundleId, this.deviceId);\n\t}\n\n\t/**\n\t * Check if an app is installed on the device\n\t *\n\t * @param bundleId Application bundle identifier\n\t */\n\tpublic async isAppInstalled(bundleId: string): Promise<boolean> {\n\t\treturn isAppInstalled(bundleId, this.deviceId);\n\t}\n\n\t/**\n\t * List all installed user applications\n\t */\n\tpublic async listApps(): Promise<AppInfo[]> {\n\t\treturn listApps(this.deviceId);\n\t}\n\n\t/**\n\t * Launch an application on the device\n\t *\n\t * @param bundleId Application bundle identifier\n\t * @param args Application arguments\n\t */\n\tpublic async launchApp(bundleId: string, args: string[] = []): Promise<void> {\n\t\treturn launchApp(bundleId, args, this.deviceId);\n\t}\n\n\t/**\n\t * Start port forwarding and wait for it to be ready.\n\t * we need port forwarding to be able to connect to the device from the computer\n\t * and communicate with it using the local port.\n\t *\n\t * @param localPort Local port to listen on\n\t * @param devicePort Device port to forward to\n\t * @param _timeout Timeout in milliseconds (reserved for future use)\n\t */\n\tpublic async startPortForwardAsync(\n\t\tlocalPort: number,\n\t\tdevicePort: number,\n\t\t_timeout = 5000\n\t): Promise<PortForwardResult> {\n\t\treturn startPortForwardAsync(localPort, devicePort, this.deviceId);\n\t}\n\n\t/**\n\t * Get the activation state of the device\n\t */\n\tpublic async getActivationState(): Promise<ActivationState> {\n\t\treturn getActivationState(this.deviceId);\n\t}\n\n\t/**\n\t * Activate the device (register in apple servers), an activated device belongs to someone (a user/company).\n\t * A device that is on hello screen cannot pass the wifi step unless it is activated.\n\t * the activate save us the need of the device to be connected to the internet to do the activation\n\t * and register in apple servers.\n\t *\n\t * Note: This requires a valid activation record or Apple server access\n\t *\n\t * precondition: the device must be paired and trusted\n\t */\n\tpublic async activate(): Promise<boolean> {\n\t\treturn activate(this.deviceId);\n\t}\n\n\t/**\n\t * Get the device UDID\n\t */\n\tpublic getDeviceId(): string {\n\t\treturn this.deviceId;\n\t}\n\n\t/**\n\t * Get the logical port number\n\t */\n\tpublic getPort(): number {\n\t\treturn this.port;\n\t}\n\n\tpublic async closePortForward(): Promise<void> {\n\t\treturn closePortForward(this.deviceId);\n\t}\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["promisify", "execAsync"]
7
+ }