stim 1.0.0 → 1.1.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/README.md +22 -10
- package/dist/android-CC5bUer7.mjs +204 -0
- package/dist/android-DnZlT3aU.mjs +2279 -0
- package/dist/android-cas-DGlTStWu.mjs +1078 -0
- package/dist/android-cas-compiler.mjs +1 -1
- package/dist/android-xmyGBNy5.mjs +665 -0
- package/dist/app-install-oZIQRbdD.mjs +1141 -0
- package/dist/build-lock-vE45ZzJZ.mjs +645 -0
- package/dist/build-slots-CgacA9zQ.mjs +152 -0
- package/dist/{cache-manifest-4tH64LQ9.mjs → cache-manifest-oeH18ERr.mjs} +2 -2
- package/dist/cache-manifest.mjs +1 -1
- package/dist/cli.mjs +24 -27166
- package/dist/collector-run.mjs +6 -4
- package/dist/command-output-8wHMEde0.mjs +289 -0
- package/dist/{config-7kmtuhO2.mjs → config-D7uu8Gbq.mjs} +43 -12
- package/dist/deps-64wVnpZc.mjs +435 -0
- package/dist/dev-client-Bvky1hya.mjs +557 -0
- package/dist/device-DJKv5Qej.mjs +250 -0
- package/dist/device-lease-D-G3SgVe.mjs +335 -0
- package/dist/device-pool-BlHXnYYs.mjs +408 -0
- package/dist/device-remote-CCgkG82J.mjs +1209 -0
- package/dist/doctor-BRF9aAJ3.mjs +530 -0
- package/dist/doctor-DlVxTtMq.mjs +1137 -0
- package/dist/error-diagnostics-B5IJwv3-.mjs +636 -0
- package/dist/gc-DhXdgSdt.mjs +1651 -0
- package/dist/guide-DrhrDBo5.mjs +4319 -0
- package/dist/ios-BZxKPuqP.mjs +382 -0
- package/dist/ios-CK1Vrk6Q.mjs +2721 -0
- package/dist/ios-device-CYbuRNXR.mjs +81 -0
- package/dist/ios-device-CdSm0GDw.mjs +413 -0
- package/dist/logs-Dxoy16Qv.mjs +176 -0
- package/dist/logs-query-oqn47Ffx.mjs +273 -0
- package/dist/metro-B01H3EuD.mjs +184 -0
- package/dist/metro-store-CDDZHtPl.mjs +92 -0
- package/dist/ownership-B9QIdQOw.mjs +475 -0
- package/dist/ownership-D8HmSv2E.mjs +60 -0
- package/dist/ownership-claim-CeJLEpjD.mjs +569 -0
- package/dist/{project-Dit1CckW.mjs → project-COj6nzzh.mjs} +12 -3
- package/dist/reclaim-BPvN2HlP.mjs +347 -0
- package/dist/reload-DYZEBbZy.mjs +332 -0
- package/dist/remote-cache-DOi5-zLj.mjs +934 -0
- package/dist/{server-bare-BmTVVmBB.mjs → server-bare-BYHqEeyw.mjs} +3 -2
- package/dist/{server-expo-CHJe1r6j.mjs → server-expo-BEMr_m6p.mjs} +5 -4
- package/dist/server-expo-rb0k-0w7.mjs +2 -0
- package/dist/settings-BSwrY4FZ.mjs +687 -0
- package/dist/spawn-entry-nCE6m770.mjs +14 -0
- package/dist/start-ByCylYtB.mjs +822 -0
- package/dist/{state-2nush3MK.mjs → state-IYEY-zi8.mjs} +21 -22
- package/dist/stats-DZ4Q5J-7.mjs +62 -0
- package/dist/stats-wqxPm7Tv.mjs +307 -0
- package/dist/status-Dia0XTqG.mjs +363 -0
- package/dist/stop-BApyaF21.mjs +591 -0
- package/dist/stop-D6o5zAdm.mjs +3 -0
- package/dist/supervisor-run.d.mts +0 -1
- package/dist/supervisor-run.mjs +4 -4
- package/dist/workspace-process-lock-CxOO9-pf.mjs +47 -0
- package/dist/worktree-Dx3ZC5lS.mjs +539 -0
- package/dist/worktree-DxEmUI_n.mjs +1322 -0
- package/dist/xcode-CDB6fytw.mjs +1705 -0
- package/package.json +5 -5
- package/dist/android-jc8MnUyL.mjs +0 -514
- package/dist/metro-store-COLl1pOk.mjs +0 -1249
- package/dist/server-expo-BZJm--wA.mjs +0 -2
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
import { t as getExecutor } from "./exec-bsN9MJXb.mjs";
|
|
2
|
+
import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-C7IlIzd7.mjs";
|
|
3
|
+
import { mkdtempSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
//#region src/sim/ios.ts
|
|
7
|
+
function parseSimctlList(jsonOutput, { includeUnavailable = false } = {}) {
|
|
8
|
+
const parsed = JSON.parse(jsonOutput);
|
|
9
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("Expected simctl list to return a JSON object with a devices object.");
|
|
10
|
+
const data = parsed;
|
|
11
|
+
if (data.devices === null || typeof data.devices !== "object" || Array.isArray(data.devices)) throw new Error("Expected simctl list to return a JSON object with a devices object.");
|
|
12
|
+
const sims = [];
|
|
13
|
+
for (const [runtime, devices] of Object.entries(data.devices)) {
|
|
14
|
+
if (!Array.isArray(devices)) throw new Error(`Expected simctl devices for ${runtime} to be an array.`);
|
|
15
|
+
if (!/\.iOS-/.test(runtime)) continue;
|
|
16
|
+
for (const dev of devices) {
|
|
17
|
+
if (dev === null || typeof dev !== "object" || Array.isArray(dev)) throw new Error(`Expected every simctl device for ${runtime} to be an object.`);
|
|
18
|
+
const record = dev;
|
|
19
|
+
for (const field of [
|
|
20
|
+
"udid",
|
|
21
|
+
"name",
|
|
22
|
+
"state",
|
|
23
|
+
"deviceTypeIdentifier"
|
|
24
|
+
]) if (typeof record[field] !== "string" || record[field].length === 0) throw new Error(`Expected simctl device field ${field} for ${runtime} to be a non-empty string.`);
|
|
25
|
+
if (typeof record.isAvailable !== "boolean") throw new Error(`Expected simctl device field isAvailable for ${runtime} to be a boolean.`);
|
|
26
|
+
if (record.dataPath !== void 0 && typeof record.dataPath !== "string") throw new Error(`Expected simctl device field dataPath for ${runtime} to be a string.`);
|
|
27
|
+
if (record.dataPathSize !== void 0 && (typeof record.dataPathSize !== "number" || !Number.isFinite(record.dataPathSize))) throw new Error(`Expected simctl device field dataPathSize for ${runtime} to be a finite number.`);
|
|
28
|
+
const typed = record;
|
|
29
|
+
const available = Boolean(typed.isAvailable);
|
|
30
|
+
if (!available && !includeUnavailable) continue;
|
|
31
|
+
sims.push({
|
|
32
|
+
udid: typed.udid,
|
|
33
|
+
name: typed.name,
|
|
34
|
+
state: typed.state,
|
|
35
|
+
runtime,
|
|
36
|
+
deviceTypeIdentifier: typed.deviceTypeIdentifier,
|
|
37
|
+
available,
|
|
38
|
+
...typed.dataPath !== void 0 ? { dataPath: typed.dataPath } : {},
|
|
39
|
+
...typed.dataPathSize !== void 0 ? { dataPathSize: typed.dataPathSize } : {}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return sims;
|
|
44
|
+
}
|
|
45
|
+
function listAllIosSims({ timeoutMs, includeUnavailable = false } = {}) {
|
|
46
|
+
return parseSimctlList(getExecutor().run("xcrun simctl list devices --json", { timeoutMs }), { includeUnavailable });
|
|
47
|
+
}
|
|
48
|
+
function parseRuntimeVersion(runtimeId) {
|
|
49
|
+
const m = runtimeId.match(/iOS-(\d+)(?:-(\d+))?$/);
|
|
50
|
+
if (!m) return runtimeId;
|
|
51
|
+
const major = m[1];
|
|
52
|
+
if (major === void 0) return runtimeId;
|
|
53
|
+
const minor = m[2];
|
|
54
|
+
return minor ? `${major}.${minor}` : major;
|
|
55
|
+
}
|
|
56
|
+
const IOS_BOOT_TIMEOUT_MS = 6e5;
|
|
57
|
+
const BOOTSTATUS_ATTEMPT_MS = 24e4;
|
|
58
|
+
const BOOTSTATUS_ATTEMPT_FLOOR_MS = 1e3;
|
|
59
|
+
const BOOT_STATE_LIST_TIMEOUT_MS = 3e4;
|
|
60
|
+
function bootstatusTimeout(udid) {
|
|
61
|
+
const e = /* @__PURE__ */ new Error(`xcrun simctl bootstatus ${udid} -b timed out`);
|
|
62
|
+
e.code = "ETIMEDOUT";
|
|
63
|
+
return e;
|
|
64
|
+
}
|
|
65
|
+
async function awaitBootstatus(udid, attemptMs) {
|
|
66
|
+
const lines = [];
|
|
67
|
+
const reader = createLineReader((raw) => {
|
|
68
|
+
const line = stripAnsi(raw).trim();
|
|
69
|
+
if (!line) return;
|
|
70
|
+
lines.push(line);
|
|
71
|
+
if (lines.length > 10) lines.shift();
|
|
72
|
+
});
|
|
73
|
+
const child = getExecutor().spawn("xcrun", [
|
|
74
|
+
"simctl",
|
|
75
|
+
"bootstatus",
|
|
76
|
+
udid,
|
|
77
|
+
"-b"
|
|
78
|
+
], { stdio: [
|
|
79
|
+
"ignore",
|
|
80
|
+
"pipe",
|
|
81
|
+
"pipe"
|
|
82
|
+
] });
|
|
83
|
+
child.stdout?.on("data", (chunk) => reader.push(chunk));
|
|
84
|
+
child.stderr?.on("data", (chunk) => reader.push(chunk));
|
|
85
|
+
let timer;
|
|
86
|
+
const attempt = new Promise((resolve) => {
|
|
87
|
+
timer = setTimeout(() => resolve("timeout"), attemptMs);
|
|
88
|
+
});
|
|
89
|
+
const result = await Promise.race([waitForChild(child), attempt]);
|
|
90
|
+
clearTimeout(timer);
|
|
91
|
+
reader.flush();
|
|
92
|
+
if (result === "timeout") {
|
|
93
|
+
child.kill("SIGKILL");
|
|
94
|
+
throw bootstatusTimeout(udid);
|
|
95
|
+
}
|
|
96
|
+
if (result.error) throw result.error;
|
|
97
|
+
if (result.code === 0) return;
|
|
98
|
+
const detail = lines.length ? `: ${lines.join(" | ")}` : "";
|
|
99
|
+
throw new Error(`xcrun simctl bootstatus ${udid} -b failed with exit code ${result.code ?? "unknown"}${detail}`);
|
|
100
|
+
}
|
|
101
|
+
async function bootIosSim(udid, { timeoutMs = IOS_BOOT_TIMEOUT_MS, attemptMs = BOOTSTATUS_ATTEMPT_MS } = {}) {
|
|
102
|
+
const exec = getExecutor();
|
|
103
|
+
try {
|
|
104
|
+
exec.run(`xcrun simctl boot ${udid}`);
|
|
105
|
+
} catch (e) {
|
|
106
|
+
if (!String(e?.message || e).includes("Booted")) throw e;
|
|
107
|
+
}
|
|
108
|
+
const deadline = Date.now() + timeoutMs;
|
|
109
|
+
for (;;) {
|
|
110
|
+
const remaining = deadline - Date.now();
|
|
111
|
+
if (remaining > 0) try {
|
|
112
|
+
await awaitBootstatus(udid, Math.min(Math.max(remaining, BOOTSTATUS_ATTEMPT_FLOOR_MS), attemptMs));
|
|
113
|
+
break;
|
|
114
|
+
} catch (e) {
|
|
115
|
+
if (e?.code !== "ETIMEDOUT") throw e;
|
|
116
|
+
}
|
|
117
|
+
let state;
|
|
118
|
+
try {
|
|
119
|
+
state = listAllIosSims({ timeoutMs: BOOT_STATE_LIST_TIMEOUT_MS }).find((s) => s.udid === udid)?.state ?? null;
|
|
120
|
+
} catch {
|
|
121
|
+
state = void 0;
|
|
122
|
+
}
|
|
123
|
+
if (state === "Booted") break;
|
|
124
|
+
const waited = Math.round((timeoutMs - Math.max(0, deadline - Date.now())) / 1e3);
|
|
125
|
+
if (state !== "Booting" && state !== void 0) throw new Error(`Simulator ${udid} reports "${state ?? "missing"}" after ${waited}s of boot wait.`);
|
|
126
|
+
if (deadline - Date.now() <= 0) throw new Error(`Simulator ${udid} did not finish booting within ${Math.round(timeoutMs / 1e3)}s.`);
|
|
127
|
+
}
|
|
128
|
+
exec.runQuiet("open -a Simulator");
|
|
129
|
+
}
|
|
130
|
+
function shutdownIosSim(udid) {
|
|
131
|
+
getExecutor().runQuiet(`xcrun simctl shutdown ${udid}`);
|
|
132
|
+
}
|
|
133
|
+
function listIosDeviceTypes() {
|
|
134
|
+
const out = getExecutor().run("xcrun simctl list devicetypes --json");
|
|
135
|
+
return (JSON.parse(out).devicetypes || []).map((dt) => ({
|
|
136
|
+
identifier: dt.identifier,
|
|
137
|
+
name: dt.name
|
|
138
|
+
}));
|
|
139
|
+
}
|
|
140
|
+
function rankIphone(name) {
|
|
141
|
+
const gen = /^iPhone\s+(\d+)/i.exec(name);
|
|
142
|
+
return {
|
|
143
|
+
gen: gen ? Number(gen[1]) : -1,
|
|
144
|
+
variant: -name.length
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function iosRuntimeMatches(runtime, requested) {
|
|
148
|
+
return runtime.version === requested || runtime.name === requested;
|
|
149
|
+
}
|
|
150
|
+
function pickDefaultIosCreation(_deviceTypes, runtimes, { deviceType, runtime } = {}) {
|
|
151
|
+
const rts = runtimes.toSorted((a, b) => String(b.version).localeCompare(String(a.version), void 0, { numeric: true }));
|
|
152
|
+
const wantedRts = runtime ? rts.filter((r) => iosRuntimeMatches(r, runtime)) : rts;
|
|
153
|
+
for (const rt of wantedRts) {
|
|
154
|
+
const supported = (rt.supportedDeviceTypes || []).filter((d) => deviceType ? d.name === deviceType : /^iPhone/i.test(d.name));
|
|
155
|
+
if (supported.length === 0) continue;
|
|
156
|
+
const best = supported.toSorted((a, b) => {
|
|
157
|
+
const ra = rankIphone(a.name), rb = rankIphone(b.name);
|
|
158
|
+
return rb.gen - ra.gen || rb.variant - ra.variant || b.name.localeCompare(a.name, void 0, { numeric: true });
|
|
159
|
+
})[0];
|
|
160
|
+
if (best === void 0) continue;
|
|
161
|
+
return {
|
|
162
|
+
deviceTypeId: best.identifier,
|
|
163
|
+
runtimeId: rt.identifier
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
function sanitizeDeviceLabel(label) {
|
|
169
|
+
return String(label).replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
170
|
+
}
|
|
171
|
+
const SIM_NAME_MAX = 60;
|
|
172
|
+
const PARKED_SIM_LABEL = "parked";
|
|
173
|
+
function fitSimName(label, { model, runtime }, suffix = "", preserveLabel = false) {
|
|
174
|
+
const version = runtime ?? "";
|
|
175
|
+
const modelName = model ?? "";
|
|
176
|
+
if (!version && !modelName) return `stim-${label}${suffix}`;
|
|
177
|
+
let over = `stim-`.length + 2 + 1 + 1 + version.length + suffix.length + label.length + modelName.length - SIM_NAME_MAX;
|
|
178
|
+
let shortLabel = label;
|
|
179
|
+
if (over > 0 && !preserveLabel) {
|
|
180
|
+
const cut = Math.min(over, label.length);
|
|
181
|
+
shortLabel = label.slice(0, label.length - cut).replace(/[._-]+$/g, "");
|
|
182
|
+
over -= cut;
|
|
183
|
+
}
|
|
184
|
+
const shortModel = over > 0 ? modelName.slice(0, Math.max(0, modelName.length - over)) : modelName;
|
|
185
|
+
return `stim-${shortLabel} (${shortModel} ${version})${suffix}`;
|
|
186
|
+
}
|
|
187
|
+
function ownedSimName(label, model = {
|
|
188
|
+
model: null,
|
|
189
|
+
runtime: null
|
|
190
|
+
}, suffix = "") {
|
|
191
|
+
const clean = sanitizeDeviceLabel(label);
|
|
192
|
+
return fitSimName(clean.startsWith("stim-") ? clean.slice(5) : clean, model, suffix);
|
|
193
|
+
}
|
|
194
|
+
function parkedSimName(udid, model) {
|
|
195
|
+
return fitSimName(PARKED_SIM_LABEL, model, ` ${udid.replace(/-/g, "").slice(0, 4).toLowerCase()}`, true);
|
|
196
|
+
}
|
|
197
|
+
function resolveIosCreation({ deviceType, runtime } = {}) {
|
|
198
|
+
const deviceTypes = listIosDeviceTypes();
|
|
199
|
+
const runtimes = listIosRuntimes();
|
|
200
|
+
const pick = pickDefaultIosCreation(deviceTypes, runtimes, {
|
|
201
|
+
deviceType,
|
|
202
|
+
runtime
|
|
203
|
+
});
|
|
204
|
+
if (!pick) throw new Error("No matching simulator device type / runtime is installed. Install one via Xcode, or pass --device-type / --runtime.");
|
|
205
|
+
return {
|
|
206
|
+
deviceTypeId: pick.deviceTypeId,
|
|
207
|
+
runtimeId: pick.runtimeId,
|
|
208
|
+
deviceType: deviceTypes.find((d) => d.identifier === pick.deviceTypeId)?.name ?? null,
|
|
209
|
+
runtime: runtimes.find((r) => r.identifier === pick.runtimeId)?.version ?? null
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function createOwnedIosSim(label, { deviceType, runtime, suffix = "" } = {}, choice = resolveIosCreation({
|
|
213
|
+
deviceType,
|
|
214
|
+
runtime
|
|
215
|
+
})) {
|
|
216
|
+
const name = ownedSimName(label, {
|
|
217
|
+
model: choice.deviceType,
|
|
218
|
+
runtime: choice.runtime
|
|
219
|
+
}, suffix);
|
|
220
|
+
return {
|
|
221
|
+
udid: getExecutor().run(`xcrun simctl create "${name}" "${choice.deviceTypeId}" "${choice.runtimeId}"`).trim(),
|
|
222
|
+
name,
|
|
223
|
+
deviceType: choice.deviceType,
|
|
224
|
+
runtime: choice.runtime
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
function renameIosSim(udid, name) {
|
|
228
|
+
getExecutor().runFile("xcrun", [
|
|
229
|
+
"simctl",
|
|
230
|
+
"rename",
|
|
231
|
+
udid,
|
|
232
|
+
name
|
|
233
|
+
]);
|
|
234
|
+
}
|
|
235
|
+
function resetIosPrivacy(udid) {
|
|
236
|
+
getExecutor().runFile("xcrun", [
|
|
237
|
+
"simctl",
|
|
238
|
+
"privacy",
|
|
239
|
+
udid,
|
|
240
|
+
"reset",
|
|
241
|
+
"all"
|
|
242
|
+
]);
|
|
243
|
+
}
|
|
244
|
+
function resetIosKeychain(udid) {
|
|
245
|
+
getExecutor().runFile("xcrun", [
|
|
246
|
+
"simctl",
|
|
247
|
+
"keychain",
|
|
248
|
+
udid,
|
|
249
|
+
"reset"
|
|
250
|
+
]);
|
|
251
|
+
}
|
|
252
|
+
function uninstallIosApp(udid, bundleId) {
|
|
253
|
+
getExecutor().runFile("xcrun", [
|
|
254
|
+
"simctl",
|
|
255
|
+
"uninstall",
|
|
256
|
+
udid,
|
|
257
|
+
bundleId
|
|
258
|
+
]);
|
|
259
|
+
}
|
|
260
|
+
function parseUserApps(jsonOutput) {
|
|
261
|
+
const data = JSON.parse(jsonOutput);
|
|
262
|
+
if (data === null || typeof data !== "object" || Array.isArray(data)) throw new Error("Expected simctl listapps to convert to a JSON object.");
|
|
263
|
+
const userApps = [];
|
|
264
|
+
for (const [bundleId, app] of Object.entries(data)) {
|
|
265
|
+
if (app === null || typeof app !== "object" || Array.isArray(app)) throw new Error(`Expected simctl listapps entry ${JSON.stringify(bundleId)} to be an object.`);
|
|
266
|
+
const applicationType = app.ApplicationType;
|
|
267
|
+
if (applicationType !== "User" && applicationType !== "System") throw new Error(`Expected simctl listapps entry ${JSON.stringify(bundleId)} to name a known ApplicationType.`);
|
|
268
|
+
if (applicationType === "User") userApps.push(bundleId);
|
|
269
|
+
}
|
|
270
|
+
return userApps;
|
|
271
|
+
}
|
|
272
|
+
const LISTAPPS_TIMEOUT_MS = 6e4;
|
|
273
|
+
function listUserApps(udid) {
|
|
274
|
+
const exec = getExecutor();
|
|
275
|
+
const dir = mkdtempSync(join(tmpdir(), "stim-listapps-"));
|
|
276
|
+
const plist = join(dir, "apps.plist");
|
|
277
|
+
try {
|
|
278
|
+
writeFileSync(plist, exec.runFile("xcrun", [
|
|
279
|
+
"simctl",
|
|
280
|
+
"listapps",
|
|
281
|
+
udid
|
|
282
|
+
], { timeoutMs: LISTAPPS_TIMEOUT_MS }));
|
|
283
|
+
return parseUserApps(exec.runFile("plutil", [
|
|
284
|
+
"-convert",
|
|
285
|
+
"json",
|
|
286
|
+
"-o",
|
|
287
|
+
"-",
|
|
288
|
+
plist
|
|
289
|
+
]));
|
|
290
|
+
} finally {
|
|
291
|
+
rmSync(dir, {
|
|
292
|
+
recursive: true,
|
|
293
|
+
force: true
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
const CONTAINER_METADATA = ".com.apple.mobile_container_manager.metadata.plist";
|
|
298
|
+
const CLEARED_CONTAINER_DIRS = [
|
|
299
|
+
"Documents",
|
|
300
|
+
"Library",
|
|
301
|
+
"tmp",
|
|
302
|
+
"SystemData"
|
|
303
|
+
];
|
|
304
|
+
const PLUTIL_TIMEOUT_MS = 1e4;
|
|
305
|
+
function findAppDataContainer(dataPath, bundleId) {
|
|
306
|
+
const root = join(dataPath, "Containers", "Data", "Application");
|
|
307
|
+
let entries;
|
|
308
|
+
try {
|
|
309
|
+
entries = readdirSync(root);
|
|
310
|
+
} catch (error) {
|
|
311
|
+
if (error?.code === "ENOENT") return null;
|
|
312
|
+
throw error;
|
|
313
|
+
}
|
|
314
|
+
const exec = getExecutor();
|
|
315
|
+
for (const entry of entries) {
|
|
316
|
+
const dir = join(root, entry);
|
|
317
|
+
if (exec.runFile("plutil", [
|
|
318
|
+
"-extract",
|
|
319
|
+
"MCMMetadataIdentifier",
|
|
320
|
+
"raw",
|
|
321
|
+
join(dir, CONTAINER_METADATA)
|
|
322
|
+
], { timeoutMs: PLUTIL_TIMEOUT_MS }).trim() === bundleId) return dir;
|
|
323
|
+
}
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
function clearAppDataContainer(container) {
|
|
327
|
+
for (const name of CLEARED_CONTAINER_DIRS) {
|
|
328
|
+
const dir = join(container, name);
|
|
329
|
+
let children;
|
|
330
|
+
try {
|
|
331
|
+
if (!statSync(dir).isDirectory()) throw new Error(`Expected app data path ${dir} to be a directory.`);
|
|
332
|
+
children = readdirSync(dir);
|
|
333
|
+
} catch (error) {
|
|
334
|
+
if (error?.code === "ENOENT") continue;
|
|
335
|
+
throw error;
|
|
336
|
+
}
|
|
337
|
+
for (const child of children) rmSync(join(dir, child), {
|
|
338
|
+
recursive: true,
|
|
339
|
+
force: true
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
function resolveOwnedIosSim(udid) {
|
|
344
|
+
const sim = listAllIosSims().find((s) => s.udid === udid);
|
|
345
|
+
if (!sim) return { missing: true };
|
|
346
|
+
if (!sim.name?.startsWith("stim-")) return { notOwned: sim.name };
|
|
347
|
+
return { sim };
|
|
348
|
+
}
|
|
349
|
+
function deleteIosSim(udid) {
|
|
350
|
+
const result = resolveOwnedIosSim(udid);
|
|
351
|
+
if (result.missing) return;
|
|
352
|
+
if (result.notOwned) throw new Error(`Refusing to delete simulator "${result.notOwned}" (${udid}): not a Stim-owned sim (name must start with "stim-").`);
|
|
353
|
+
getExecutor().run(`xcrun simctl delete ${udid}`);
|
|
354
|
+
}
|
|
355
|
+
const PARKED_DELETE_TIMEOUT_MS = 3e4;
|
|
356
|
+
function deleteParkedIosSim(udid) {
|
|
357
|
+
const sim = listAllIosSims({
|
|
358
|
+
includeUnavailable: true,
|
|
359
|
+
timeoutMs: PARKED_DELETE_TIMEOUT_MS
|
|
360
|
+
}).find((entry) => entry.udid === udid);
|
|
361
|
+
if (!sim) return;
|
|
362
|
+
if (!sim.name.startsWith("stim-")) throw new Error(`Simulator ${udid} is now named "${sim.name}" and is not Stim-owned; refusing to delete it.`);
|
|
363
|
+
getExecutor().runFile("xcrun", [
|
|
364
|
+
"simctl",
|
|
365
|
+
"delete",
|
|
366
|
+
udid
|
|
367
|
+
], { timeoutMs: PARKED_DELETE_TIMEOUT_MS });
|
|
368
|
+
}
|
|
369
|
+
function listIosRuntimes() {
|
|
370
|
+
const out = getExecutor().run("xcrun simctl list runtimes --json");
|
|
371
|
+
return (JSON.parse(out).runtimes || []).filter((r) => r.isAvailable && r.platform === "iOS").map((r) => ({
|
|
372
|
+
identifier: r.identifier,
|
|
373
|
+
name: r.name,
|
|
374
|
+
version: r.version,
|
|
375
|
+
supportedDeviceTypes: (r.supportedDeviceTypes || []).map((d) => ({
|
|
376
|
+
identifier: d.identifier,
|
|
377
|
+
name: d.name
|
|
378
|
+
}))
|
|
379
|
+
}));
|
|
380
|
+
}
|
|
381
|
+
//#endregion
|
|
382
|
+
export { uninstallIosApp as C, shutdownIosSim as S, resetIosKeychain as _, deleteIosSim as a, resolveOwnedIosSim as b, iosRuntimeMatches as c, listIosRuntimes as d, listUserApps as f, renameIosSim as g, parseRuntimeVersion as h, createOwnedIosSim as i, listAllIosSims as l, parkedSimName as m, bootIosSim as n, deleteParkedIosSim as o, ownedSimName as p, clearAppDataContainer as r, findAppDataContainer as s, IOS_BOOT_TIMEOUT_MS as t, listIosDeviceTypes as u, resetIosPrivacy as v, sanitizeDeviceLabel as x, resolveIosCreation as y };
|