@swipt/cli 0.1.0-nightly.46 → 0.1.0-nightly.48
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/coredevice.mjs +97 -39
- package/output.mjs +61 -0
- package/package.json +6 -4
- package/sideload/trust.js +188 -174
- package/sideload.mjs +565 -182
- package/swipt.mjs +20 -10
package/coredevice.mjs
CHANGED
|
@@ -1,30 +1,44 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
|
+
import { promisify } from "node:util";
|
|
5
6
|
|
|
6
7
|
import { label, sameName } from "./connection.mjs";
|
|
8
|
+
import { choose, step } from "./output.mjs";
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
const exec = promisify(execFile);
|
|
11
|
+
|
|
12
|
+
const xcodeMissing =
|
|
13
|
+
"Xcode is missing; install it from the App Store, open it once, and select it with xcode-select";
|
|
14
|
+
|
|
15
|
+
export async function devicectl(args, { parse = false } = {}) {
|
|
9
16
|
const output = parse
|
|
10
17
|
? path.join(os.tmpdir(), `devicectl-${process.pid}.json`)
|
|
11
18
|
: undefined;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
try {
|
|
20
|
+
await exec(
|
|
21
|
+
"xcrun",
|
|
22
|
+
["devicectl", ...args, ...(parse ? ["--json-output", output] : [])],
|
|
23
|
+
{ maxBuffer: Infinity },
|
|
24
|
+
);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
if (error.code === "ENOENT") {
|
|
27
|
+
throw new Error(xcodeMissing);
|
|
28
|
+
}
|
|
29
|
+
if (typeof error.code !== "number") {
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
const text = `${error.stdout}${error.stderr}`;
|
|
33
|
+
if (/^(xcrun|xcode-select): /m.test(text)) {
|
|
34
|
+
throw new Error(`${xcodeMissing} (${text.trim()})`);
|
|
35
|
+
}
|
|
22
36
|
if (text.includes("4016")) {
|
|
23
37
|
throw new Error(
|
|
24
38
|
"CoreDevice cannot reach the device while its loopback VPN is on; turn off Swipt's VPN on the device, then run this again",
|
|
25
39
|
);
|
|
26
40
|
}
|
|
27
|
-
throw new Error(text.trim() || `devicectl exited with ${
|
|
41
|
+
throw new Error(text.trim() || `devicectl exited with ${error.code}`);
|
|
28
42
|
}
|
|
29
43
|
if (!parse) {
|
|
30
44
|
return undefined;
|
|
@@ -34,41 +48,85 @@ export function devicectl(args, { parse = false } = {}) {
|
|
|
34
48
|
return parsed;
|
|
35
49
|
}
|
|
36
50
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
51
|
+
const reachability =
|
|
52
|
+
"unlock the device and connect it with USB or the same network as this Mac";
|
|
53
|
+
|
|
54
|
+
const deviceLine = (device) =>
|
|
55
|
+
` ${device.name} ${device.udid}${device.offline ? " (offline)" : ""}`;
|
|
56
|
+
|
|
57
|
+
export async function coreDevice(context, { required = true } = {}) {
|
|
58
|
+
const given = context.options.device;
|
|
59
|
+
const listed = await step(
|
|
60
|
+
"looking for devices",
|
|
61
|
+
() => devicectl(["list", "devices"], { parse: true }),
|
|
62
|
+
{ transient: true },
|
|
63
|
+
);
|
|
64
|
+
const paired = listed.result.devices
|
|
65
|
+
.filter(
|
|
40
66
|
(device) =>
|
|
41
67
|
device.hardwareProperties.platform === "iOS" &&
|
|
42
|
-
device.hardwareProperties.reality
|
|
68
|
+
["physical", undefined].includes(device.hardwareProperties.reality),
|
|
43
69
|
)
|
|
44
70
|
.map((device) => ({
|
|
45
71
|
name: device.deviceProperties.name,
|
|
46
72
|
udid: device.hardwareProperties.udid,
|
|
73
|
+
offline: device.connectionProperties.tunnelState === "unavailable",
|
|
47
74
|
}));
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
75
|
+
const named = (device) =>
|
|
76
|
+
sameName(device.udid, given) || sameName(label(device.name), label(given));
|
|
77
|
+
const devices = paired.filter((device) => !device.offline);
|
|
78
|
+
const matches = given ? devices.filter(named) : devices;
|
|
79
|
+
if ((given || !required) && matches.length === 1) {
|
|
80
|
+
return matches[0];
|
|
81
|
+
}
|
|
82
|
+
if (paired.length === 0) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
"no iOS device is paired with this Mac; connect one with USB, unlock it, and trust this Mac",
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
const offline = given && paired.find(named);
|
|
88
|
+
if (matches.length === 0 && offline) {
|
|
89
|
+
throw new Error(`${offline.name} is offline; ${reachability}`);
|
|
90
|
+
}
|
|
91
|
+
if (devices.length === 0) {
|
|
63
92
|
throw new Error(
|
|
64
|
-
|
|
65
|
-
? `${reason}; no iOS device is paired with this Mac`
|
|
66
|
-
: `${reason}; paired iOS devices:\n${devices.map((device) => ` ${device.name} ${device.udid}`).join("\n")}`,
|
|
93
|
+
`every paired iOS device is offline; ${reachability}:\n${paired.map(deviceLine).join("\n")}`,
|
|
67
94
|
);
|
|
68
95
|
}
|
|
69
|
-
|
|
96
|
+
const reason = !given
|
|
97
|
+
? "choose a device with -d NAME|UDID"
|
|
98
|
+
: matches.length === 0
|
|
99
|
+
? `no iOS device is named ${given}`
|
|
100
|
+
: `more than one iOS device is named ${given}; choose one by UDID`;
|
|
101
|
+
const failure = new Error(
|
|
102
|
+
`${reason}; paired iOS devices:\n${paired.map(deviceLine).join("\n")}`,
|
|
103
|
+
);
|
|
104
|
+
if (matches.length === 0) {
|
|
105
|
+
throw failure;
|
|
106
|
+
}
|
|
107
|
+
return choose(
|
|
108
|
+
context,
|
|
109
|
+
"Choose a device",
|
|
110
|
+
matches.map((device) => ({
|
|
111
|
+
name: `${device.name} ${device.udid}`,
|
|
112
|
+
short: device.name,
|
|
113
|
+
value: device,
|
|
114
|
+
})),
|
|
115
|
+
failure,
|
|
116
|
+
);
|
|
70
117
|
}
|
|
71
118
|
|
|
72
|
-
export const apps = (udid) =>
|
|
73
|
-
|
|
74
|
-
|
|
119
|
+
export const apps = async (udid) =>
|
|
120
|
+
(
|
|
121
|
+
await devicectl(["device", "info", "apps", "--device", udid], {
|
|
122
|
+
parse: true,
|
|
123
|
+
})
|
|
124
|
+
).result.apps;
|
|
125
|
+
|
|
126
|
+
export const provisioningProfiles = async (udid) =>
|
|
127
|
+
(
|
|
128
|
+
await devicectl(
|
|
129
|
+
["device", "profile", "list", "--type", "provisioning", "--device", udid],
|
|
130
|
+
{ parse: true },
|
|
131
|
+
)
|
|
132
|
+
).result.provisioningProfiles;
|
package/output.mjs
CHANGED
|
@@ -1,10 +1,71 @@
|
|
|
1
|
+
import { styleText } from "node:util";
|
|
2
|
+
|
|
1
3
|
import { timestampDate } from "@bufbuild/protobuf/wkt";
|
|
4
|
+
import select from "@inquirer/select";
|
|
2
5
|
|
|
3
6
|
import { LogLevel, LogLevelSchema } from "./proto/common_pb.js";
|
|
4
7
|
import { ServiceStatus, ServiceStatusSchema } from "./proto/swiplets_pb.js";
|
|
5
8
|
|
|
6
9
|
export class FalseResult extends Error {}
|
|
7
10
|
|
|
11
|
+
export const interactive = (context) =>
|
|
12
|
+
context.options.device === undefined &&
|
|
13
|
+
context.options.team === undefined &&
|
|
14
|
+
process.stdin.isTTY &&
|
|
15
|
+
process.stderr.isTTY;
|
|
16
|
+
|
|
17
|
+
export function choose(context, message, choices, failure) {
|
|
18
|
+
if (!interactive(context)) {
|
|
19
|
+
throw failure;
|
|
20
|
+
}
|
|
21
|
+
return select(
|
|
22
|
+
{ message, choices },
|
|
23
|
+
{ output: process.stderr, signal: context.signal },
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const spinner = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏";
|
|
28
|
+
|
|
29
|
+
export async function step(label, run, { transient = false } = {}) {
|
|
30
|
+
const stream = process.stderr;
|
|
31
|
+
if (!stream.isTTY) {
|
|
32
|
+
console.error(label);
|
|
33
|
+
return run(() => {});
|
|
34
|
+
}
|
|
35
|
+
const style = (format, text) => styleText(format, text, { stream });
|
|
36
|
+
const started = Date.now();
|
|
37
|
+
const elapsed = () => {
|
|
38
|
+
const seconds = Math.floor((Date.now() - started) / 1000);
|
|
39
|
+
return seconds > 0 ? style("dim", ` ${seconds}s`) : "";
|
|
40
|
+
};
|
|
41
|
+
const draw = (line) => stream.write(`\r\x1b[?7l\x1b[2K${line}\x1b[?7h`);
|
|
42
|
+
let detail = "";
|
|
43
|
+
let frame = 0;
|
|
44
|
+
const render = () => {
|
|
45
|
+
frame = (frame + 1) % spinner.length;
|
|
46
|
+
draw(
|
|
47
|
+
`${style("cyan", spinner[frame])} ${label}${detail && style("dim", ` ${detail}`)}${elapsed()}`,
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
stream.write("\x1b[?25l");
|
|
51
|
+
render();
|
|
52
|
+
const timer = setInterval(render, 80);
|
|
53
|
+
try {
|
|
54
|
+
const result = await run((text) => {
|
|
55
|
+
detail = text;
|
|
56
|
+
});
|
|
57
|
+
clearInterval(timer);
|
|
58
|
+
draw(transient ? "" : `${style("green", "✔")} ${label}${elapsed()}\n`);
|
|
59
|
+
return result;
|
|
60
|
+
} catch (error) {
|
|
61
|
+
clearInterval(timer);
|
|
62
|
+
draw(`${style("red", "✖")} ${label}${elapsed()}\n`);
|
|
63
|
+
throw error;
|
|
64
|
+
} finally {
|
|
65
|
+
stream.write("\x1b[?25h");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
8
69
|
export const enumText = (schema, value, prefix) =>
|
|
9
70
|
schema.value[value].name
|
|
10
71
|
.slice(prefix.length)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swipt/cli",
|
|
3
|
-
"version": "0.1.0-nightly.
|
|
3
|
+
"version": "0.1.0-nightly.48",
|
|
4
4
|
"license": "GPL-3.0-or-later",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
"@babel/runtime": "^7.29.10",
|
|
26
26
|
"@bufbuild/protobuf": "^2.16.0",
|
|
27
27
|
"@expo/env": "^2.5.3",
|
|
28
|
+
"@inquirer/password": "^5.2.5",
|
|
29
|
+
"@inquirer/select": "^5.2.8",
|
|
28
30
|
"babel-preset-expo": "~58.0.23",
|
|
29
31
|
"bonjour-service": "^1.4.4",
|
|
30
32
|
"esbuild": "^0.28.2",
|
|
@@ -32,11 +34,11 @@
|
|
|
32
34
|
"react-native-worklets": "0.13.0"
|
|
33
35
|
},
|
|
34
36
|
"peerDependencies": {
|
|
35
|
-
"@swipt/api": "0.1.0-nightly.
|
|
37
|
+
"@swipt/api": "0.1.0-nightly.48"
|
|
36
38
|
},
|
|
37
39
|
"optionalDependencies": {
|
|
38
|
-
"@swipt/server-darwin-arm64": "0.1.0-nightly.
|
|
39
|
-
"@swipt/server-darwin-x64": "0.1.0-nightly.
|
|
40
|
+
"@swipt/server-darwin-arm64": "0.1.0-nightly.48",
|
|
41
|
+
"@swipt/server-darwin-x64": "0.1.0-nightly.48"
|
|
40
42
|
},
|
|
41
43
|
"devDependencies": {
|
|
42
44
|
"@bufbuild/protoc-gen-es": "^2.16.0"
|