@ricsam/r5d-macos-vm 0.0.0 → 0.0.55

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.
@@ -0,0 +1,464 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var native_runtime_exports = {};
30
+ __export(native_runtime_exports, {
31
+ codeSignatureUsesHardenedRuntime: () => codeSignatureUsesHardenedRuntime,
32
+ defaultCacheRoot: () => defaultCacheRoot,
33
+ downloadNativeArtifact: () => downloadNativeArtifact,
34
+ ensureNativeRuntime: () => ensureNativeRuntime,
35
+ inspectMachOExecutable: () => inspectMachOExecutable,
36
+ nativeExecutablePath: () => nativeExecutablePath,
37
+ pruneObsoleteNativeRuntimes: () => pruneObsoleteNativeRuntimes,
38
+ runCommand: () => runCommand,
39
+ runtimeDirectory: () => runtimeDirectory,
40
+ verifyNativeApp: () => verifyNativeApp
41
+ });
42
+ module.exports = __toCommonJS(native_runtime_exports);
43
+ var import_node_crypto = __toESM(require("node:crypto"), 1);
44
+ var import_node_fs = __toESM(require("node:fs"), 1);
45
+ var import_node_os = __toESM(require("node:os"), 1);
46
+ var import_node_path = __toESM(require("node:path"), 1);
47
+ var import_node_child_process = require("node:child_process");
48
+ const LOCK_OWNER_FILE = "owner.json";
49
+ const TEMPORARY_ARCHIVE_SUFFIX = ".download";
50
+ async function ensurePrivateDirectory(directory, description) {
51
+ try {
52
+ await import_node_fs.default.promises.mkdir(directory, { recursive: true, mode: 448 });
53
+ } catch (error) {
54
+ if (error.code !== "EEXIST") throw error;
55
+ }
56
+ const stat = await import_node_fs.default.promises.lstat(directory);
57
+ if (!stat.isDirectory() || stat.isSymbolicLink()) {
58
+ throw new Error(`Refusing to use ${description} because it is not a regular directory: ${directory}`);
59
+ }
60
+ const currentUid = process.getuid?.();
61
+ if (currentUid !== void 0 && stat.uid !== currentUid) {
62
+ throw new Error(`Refusing to use ${description} because it is not owned by the current user: ${directory}`);
63
+ }
64
+ await import_node_fs.default.promises.chmod(directory, 448);
65
+ }
66
+ function defaultCacheRoot() {
67
+ return import_node_path.default.join(import_node_os.default.homedir(), "Library", "Caches", "dev.r5d.macos-vm");
68
+ }
69
+ function runtimeDirectory(cacheRoot, manifest) {
70
+ return import_node_path.default.join(cacheRoot, "runtimes", manifest.packageVersion);
71
+ }
72
+ function nativeExecutablePath(runtimeDir, manifest) {
73
+ return import_node_path.default.join(runtimeDir, manifest.appName, "Contents", "MacOS", manifest.executableName);
74
+ }
75
+ async function pruneObsoleteNativeRuntimes(currentExecutable, cacheRoot = defaultCacheRoot()) {
76
+ const runtimesRoot = import_node_path.default.resolve(cacheRoot, "runtimes");
77
+ const currentRuntime = import_node_path.default.resolve(currentExecutable, "../../../../");
78
+ if (import_node_path.default.dirname(currentRuntime) !== runtimesRoot) {
79
+ throw new Error("Refusing to prune native runtimes because the active runtime is outside the managed cache.");
80
+ }
81
+ await ensurePrivateDirectory(import_node_path.default.resolve(cacheRoot), "native runtime cache");
82
+ await ensurePrivateDirectory(runtimesRoot, "native runtimes directory");
83
+ let entries;
84
+ try {
85
+ entries = await import_node_fs.default.promises.readdir(runtimesRoot, { withFileTypes: true });
86
+ } catch (error) {
87
+ if (error.code === "ENOENT") return [];
88
+ throw error;
89
+ }
90
+ const removed = [];
91
+ const runtimeNamePattern = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
92
+ for (const entry of entries) {
93
+ if (!entry.isDirectory() || entry.isSymbolicLink() || !runtimeNamePattern.test(entry.name)) continue;
94
+ const candidate = import_node_path.default.resolve(runtimesRoot, entry.name);
95
+ if (candidate === currentRuntime || import_node_path.default.dirname(candidate) !== runtimesRoot) continue;
96
+ const quarantine = import_node_path.default.join(runtimesRoot, `.prune-${process.pid}-${import_node_crypto.default.randomUUID()}`);
97
+ try {
98
+ await import_node_fs.default.promises.rename(candidate, quarantine);
99
+ } catch (error) {
100
+ if (error.code === "ENOENT") continue;
101
+ throw error;
102
+ }
103
+ await import_node_fs.default.promises.rm(quarantine, { recursive: true, force: true });
104
+ removed.push(entry.name);
105
+ }
106
+ return removed;
107
+ }
108
+ function delay(milliseconds) {
109
+ return new Promise((resolve) => setTimeout(resolve, milliseconds));
110
+ }
111
+ async function removeStaleLock(lockPath, staleLockMs) {
112
+ let stat;
113
+ try {
114
+ stat = await import_node_fs.default.promises.stat(lockPath);
115
+ } catch (error) {
116
+ if (error.code === "ENOENT") return true;
117
+ throw error;
118
+ }
119
+ if (Date.now() - stat.mtimeMs < staleLockMs) return false;
120
+ let ownerPid = null;
121
+ try {
122
+ const owner = JSON.parse(await import_node_fs.default.promises.readFile(import_node_path.default.join(lockPath, LOCK_OWNER_FILE), "utf8"));
123
+ if (Number.isSafeInteger(owner.pid) && owner.pid > 0) ownerPid = owner.pid;
124
+ } catch {
125
+ }
126
+ if (ownerPid !== null) {
127
+ try {
128
+ process.kill(ownerPid, 0);
129
+ return false;
130
+ } catch (error) {
131
+ if (error.code === "EPERM") return false;
132
+ }
133
+ }
134
+ const stalePath = `${lockPath}.stale-${process.pid}-${import_node_crypto.default.randomUUID()}`;
135
+ try {
136
+ await import_node_fs.default.promises.rename(lockPath, stalePath);
137
+ } catch (error) {
138
+ if (error.code === "ENOENT") return true;
139
+ return false;
140
+ }
141
+ await import_node_fs.default.promises.rm(stalePath, { recursive: true, force: true });
142
+ return true;
143
+ }
144
+ async function withDirectoryLock(lockPath, action, options) {
145
+ const startedAt = Date.now();
146
+ await ensurePrivateDirectory(import_node_path.default.dirname(lockPath), "native runtime lock directory");
147
+ while (true) {
148
+ try {
149
+ await import_node_fs.default.promises.mkdir(lockPath, { mode: 448 });
150
+ await import_node_fs.default.promises.chmod(lockPath, 448);
151
+ await import_node_fs.default.promises.writeFile(
152
+ import_node_path.default.join(lockPath, LOCK_OWNER_FILE),
153
+ `${JSON.stringify({ pid: process.pid, createdAt: (/* @__PURE__ */ new Date()).toISOString() })}
154
+ `,
155
+ { mode: 384 }
156
+ );
157
+ break;
158
+ } catch (error) {
159
+ if (error.code !== "EEXIST") throw error;
160
+ if (await removeStaleLock(lockPath, options.staleLockMs)) continue;
161
+ if (Date.now() - startedAt >= options.timeoutMs) {
162
+ throw new Error(`Timed out waiting for native runtime installation lock at ${lockPath}.`);
163
+ }
164
+ await delay(options.pollMs);
165
+ }
166
+ }
167
+ try {
168
+ return await action();
169
+ } finally {
170
+ await import_node_fs.default.promises.rm(lockPath, { recursive: true, force: true });
171
+ }
172
+ }
173
+ const runCommand = (executable, args) => new Promise((resolve, reject) => {
174
+ const child = (0, import_node_child_process.spawn)(executable, [...args], {
175
+ stdio: ["ignore", "pipe", "pipe"],
176
+ env: { ...process.env, LANG: "C", LC_ALL: "C" },
177
+ shell: false
178
+ });
179
+ let stdout = "";
180
+ let stderr = "";
181
+ child.stdout.setEncoding("utf8").on("data", (chunk) => stdout += chunk);
182
+ child.stderr.setEncoding("utf8").on("data", (chunk) => stderr += chunk);
183
+ child.once("error", reject);
184
+ child.once("close", (code) => resolve({ exitCode: code ?? 1, stdout, stderr }));
185
+ });
186
+ async function requireSuccessfulCommand(runner, executable, args, description) {
187
+ const result = await runner(executable, args);
188
+ if (result.exitCode !== 0) {
189
+ const detail = `${result.stdout}
190
+ ${result.stderr}`.trim();
191
+ throw new Error(`${description} failed${detail ? `: ${detail}` : "."}`);
192
+ }
193
+ return result;
194
+ }
195
+ async function downloadNativeArtifact(manifest, destination) {
196
+ const temporaryDestination = `${destination}${TEMPORARY_ARCHIVE_SUFFIX}`;
197
+ await import_node_fs.default.promises.rm(temporaryDestination, { force: true });
198
+ const controller = new AbortController();
199
+ const timeout = setTimeout(() => controller.abort(), 5 * 6e4);
200
+ let response;
201
+ try {
202
+ response = await fetch(manifest.url, {
203
+ signal: controller.signal,
204
+ redirect: "follow",
205
+ headers: { "user-agent": `@ricsam/r5d-macos-vm/${manifest.packageVersion}` }
206
+ });
207
+ } catch (error) {
208
+ clearTimeout(timeout);
209
+ throw new Error(`Unable to download the native runtime: ${error instanceof Error ? error.message : String(error)}`);
210
+ }
211
+ try {
212
+ if (!response.ok || !response.body) throw new Error(`Native runtime download returned HTTP ${response.status}.`);
213
+ const contentLength = response.headers.get("content-length");
214
+ if (contentLength !== null && Number(contentLength) !== manifest.byteLength) {
215
+ throw new Error(`Native runtime download length ${contentLength} does not match expected ${manifest.byteLength}.`);
216
+ }
217
+ const file = await import_node_fs.default.promises.open(temporaryDestination, "wx", 384);
218
+ const hash = import_node_crypto.default.createHash("sha256");
219
+ let byteLength = 0;
220
+ try {
221
+ for await (const value of response.body) {
222
+ const chunk = Buffer.from(value);
223
+ byteLength += chunk.byteLength;
224
+ if (byteLength > manifest.byteLength) throw new Error("Native runtime download exceeded its signed byte length.");
225
+ hash.update(chunk);
226
+ await file.write(chunk);
227
+ }
228
+ } finally {
229
+ await file.close();
230
+ }
231
+ if (byteLength !== manifest.byteLength) {
232
+ throw new Error(`Native runtime download contained ${byteLength} bytes; expected ${manifest.byteLength}.`);
233
+ }
234
+ const digest = hash.digest("hex");
235
+ if (!import_node_crypto.default.timingSafeEqual(Buffer.from(digest, "hex"), Buffer.from(manifest.sha256, "hex"))) {
236
+ throw new Error("Native runtime checksum verification failed.");
237
+ }
238
+ await import_node_fs.default.promises.rename(temporaryDestination, destination);
239
+ } finally {
240
+ clearTimeout(timeout);
241
+ await import_node_fs.default.promises.rm(temporaryDestination, { force: true });
242
+ }
243
+ }
244
+ function decodePackedVersion(value) {
245
+ const major = value >>> 16;
246
+ const minor = value >>> 8 & 255;
247
+ const patch = value & 255;
248
+ return patch === 0 ? `${major}.${minor}` : `${major}.${minor}.${patch}`;
249
+ }
250
+ function inspectMachOExecutable(filePath) {
251
+ const data = import_node_fs.default.readFileSync(filePath);
252
+ if (data.byteLength < 32 || data.readUInt32LE(0) !== 4277009103) {
253
+ throw new Error("Native runtime executable is not a thin 64-bit Mach-O file.");
254
+ }
255
+ if (data.readInt32LE(4) !== 16777228) throw new Error("Native runtime executable is not arm64.");
256
+ if (data.readUInt32LE(12) !== 2) throw new Error("Native runtime Mach-O is not an executable.");
257
+ const commandCount = data.readUInt32LE(16);
258
+ const commandBytes = data.readUInt32LE(20);
259
+ if (32 + commandBytes > data.byteLength) throw new Error("Native runtime Mach-O load commands are truncated.");
260
+ let offset = 32;
261
+ let minimumMacOSVersion = null;
262
+ for (let index = 0; index < commandCount; index += 1) {
263
+ if (offset + 8 > data.byteLength) throw new Error("Native runtime Mach-O load command is truncated.");
264
+ const command = data.readUInt32LE(offset);
265
+ const commandSize = data.readUInt32LE(offset + 4);
266
+ if (commandSize < 8 || offset + commandSize > data.byteLength) throw new Error("Native runtime Mach-O load command is invalid.");
267
+ if (command === 50) {
268
+ if (commandSize < 24) throw new Error("Native runtime LC_BUILD_VERSION command is invalid.");
269
+ if (data.readUInt32LE(offset + 8) !== 1) throw new Error("Native runtime was not built for macOS.");
270
+ minimumMacOSVersion = decodePackedVersion(data.readUInt32LE(offset + 12));
271
+ } else if (command === 36 && minimumMacOSVersion === null) {
272
+ if (commandSize < 16) throw new Error("Native runtime LC_VERSION_MIN_MACOSX command is invalid.");
273
+ minimumMacOSVersion = decodePackedVersion(data.readUInt32LE(offset + 8));
274
+ }
275
+ offset += commandSize;
276
+ }
277
+ if (minimumMacOSVersion === null) throw new Error("Native runtime does not declare a minimum macOS version.");
278
+ return { architecture: "arm64", minimumMacOSVersion };
279
+ }
280
+ function normalizeVersion(value) {
281
+ const parts = value.trim().split(".").map(Number);
282
+ while (parts.length > 2 && parts.at(-1) === 0) parts.pop();
283
+ return parts.join(".");
284
+ }
285
+ function requireRegularFile(filePath, description) {
286
+ const stat = import_node_fs.default.lstatSync(filePath);
287
+ if (!stat.isFile() || stat.isSymbolicLink()) throw new Error(`${description} is not a regular file.`);
288
+ }
289
+ function parseSigningValue(output, key) {
290
+ const line = output.split(/\r?\n/).find((candidate) => candidate.startsWith(`${key}=`));
291
+ return line ? line.slice(key.length + 1).trim() : null;
292
+ }
293
+ function codeSignatureUsesHardenedRuntime(output) {
294
+ const codeDirectoryLine = output.split(/\r?\n/).find((line) => line.startsWith("CodeDirectory "));
295
+ if (!codeDirectoryLine) return false;
296
+ const flags = /\bflags=0x[0-9a-f]+\(([^)]*)\)/i.exec(codeDirectoryLine)?.[1];
297
+ return flags?.split(",").some((flag) => flag.trim() === "runtime") ?? false;
298
+ }
299
+ async function verifyNativeApp(appPath, manifest, runner = runCommand) {
300
+ const appStat = import_node_fs.default.lstatSync(appPath);
301
+ if (!appStat.isDirectory() || appStat.isSymbolicLink()) throw new Error("Native runtime app is not a regular bundle directory.");
302
+ const infoPlistPath = import_node_path.default.join(appPath, "Contents", "Info.plist");
303
+ const executablePath = import_node_path.default.join(appPath, "Contents", "MacOS", manifest.executableName);
304
+ requireRegularFile(infoPlistPath, "Native runtime Info.plist");
305
+ requireRegularFile(executablePath, "Native runtime executable");
306
+ const machO = inspectMachOExecutable(executablePath);
307
+ if (machO.architecture !== manifest.architecture) throw new Error("Native runtime architecture does not match its manifest.");
308
+ if (normalizeVersion(machO.minimumMacOSVersion) !== normalizeVersion(manifest.minimumMacOSVersion)) {
309
+ throw new Error(`Native runtime minimum macOS version ${machO.minimumMacOSVersion} does not match ${manifest.minimumMacOSVersion}.`);
310
+ }
311
+ const identifier = await requireSuccessfulCommand(
312
+ runner,
313
+ "/usr/bin/plutil",
314
+ ["-extract", "CFBundleIdentifier", "raw", "-o", "-", infoPlistPath],
315
+ "Reading native runtime bundle identifier"
316
+ );
317
+ if (identifier.stdout.trim() !== manifest.bundleIdentifier) throw new Error("Native runtime bundle identifier is invalid.");
318
+ const minimumVersion = await requireSuccessfulCommand(
319
+ runner,
320
+ "/usr/bin/plutil",
321
+ ["-extract", "LSMinimumSystemVersion", "raw", "-o", "-", infoPlistPath],
322
+ "Reading native runtime deployment target"
323
+ );
324
+ if (normalizeVersion(minimumVersion.stdout) !== normalizeVersion(manifest.minimumMacOSVersion)) {
325
+ throw new Error("Native runtime Info.plist deployment target is invalid.");
326
+ }
327
+ await requireSuccessfulCommand(
328
+ runner,
329
+ "/usr/bin/codesign",
330
+ ["--verify", "--deep", "--strict", "--verbose=2", appPath],
331
+ "Native runtime code-signature verification"
332
+ );
333
+ const signature = await requireSuccessfulCommand(
334
+ runner,
335
+ "/usr/bin/codesign",
336
+ ["--display", "--verbose=4", appPath],
337
+ "Reading native runtime code signature"
338
+ );
339
+ const signatureOutput = `${signature.stdout}
340
+ ${signature.stderr}`;
341
+ if (parseSigningValue(signatureOutput, "Identifier") !== manifest.bundleIdentifier) {
342
+ throw new Error("Native runtime code-signing identifier is invalid.");
343
+ }
344
+ if (parseSigningValue(signatureOutput, "TeamIdentifier") !== manifest.teamIdentifier) {
345
+ throw new Error("Native runtime Apple Team ID is invalid.");
346
+ }
347
+ if (!codeSignatureUsesHardenedRuntime(signatureOutput)) {
348
+ throw new Error("Native runtime is not signed with the hardened runtime.");
349
+ }
350
+ if (parseSigningValue(signatureOutput, "Notarization Ticket") !== "stapled") {
351
+ throw new Error("Native runtime does not contain a stapled notarization ticket.");
352
+ }
353
+ const entitlements = await requireSuccessfulCommand(
354
+ runner,
355
+ "/usr/bin/codesign",
356
+ ["--display", "--entitlements", ":-", appPath],
357
+ "Reading native runtime entitlements"
358
+ );
359
+ const entitlementOutput = `${entitlements.stdout}
360
+ ${entitlements.stderr}`;
361
+ const entitlementKeys = [...entitlementOutput.matchAll(/<key>([^<]+)<\/key>/g)].map((match) => match[1]);
362
+ if (entitlementKeys.length !== 1 || entitlementKeys[0] !== "com.apple.security.virtualization") {
363
+ throw new Error("Native runtime contains entitlements other than com.apple.security.virtualization.");
364
+ }
365
+ if (!/<key>com\.apple\.security\.virtualization<\/key>\s*<true\s*\/>/s.test(entitlementOutput)) {
366
+ throw new Error("Native runtime is missing the virtualization entitlement.");
367
+ }
368
+ const gatekeeper = await requireSuccessfulCommand(
369
+ runner,
370
+ "/usr/sbin/spctl",
371
+ ["--assess", "--type", "execute", "--verbose=4", appPath],
372
+ "Native runtime Gatekeeper assessment"
373
+ );
374
+ const gatekeeperOutput = `${gatekeeper.stdout}
375
+ ${gatekeeper.stderr}`;
376
+ if (!/source=Notarized Developer ID/.test(gatekeeperOutput)) {
377
+ throw new Error("Native runtime does not have an accepted Apple notarization assessment.");
378
+ }
379
+ }
380
+ async function installRuntime(runtimeDir, manifest, dependencies) {
381
+ const runtimesRoot = import_node_path.default.dirname(runtimeDir);
382
+ await ensurePrivateDirectory(runtimesRoot, "native runtimes directory");
383
+ const workDir = await import_node_fs.default.promises.mkdtemp(import_node_path.default.join(runtimesRoot, ".install-"));
384
+ try {
385
+ const archivePath = import_node_path.default.join(workDir, manifest.archiveName);
386
+ await dependencies.download(manifest, archivePath);
387
+ const extractDir = import_node_path.default.join(workDir, "extract");
388
+ await import_node_fs.default.promises.mkdir(extractDir, { mode: 448 });
389
+ await requireSuccessfulCommand(
390
+ dependencies.commandRunner,
391
+ "/usr/bin/ditto",
392
+ ["-x", "-k", "--noqtn", archivePath, extractDir],
393
+ "Extracting native runtime"
394
+ );
395
+ const entries = await import_node_fs.default.promises.readdir(extractDir);
396
+ if (entries.length !== 1 || entries[0] !== manifest.appName) {
397
+ throw new Error(`Native runtime archive must contain only ${manifest.appName}.`);
398
+ }
399
+ const extractedApp = import_node_path.default.join(extractDir, manifest.appName);
400
+ await verifyNativeApp(extractedApp, manifest, dependencies.commandRunner);
401
+ const readyDir = import_node_path.default.join(workDir, "ready");
402
+ await import_node_fs.default.promises.mkdir(readyDir, { mode: 448 });
403
+ await import_node_fs.default.promises.rename(extractedApp, import_node_path.default.join(readyDir, manifest.appName));
404
+ await import_node_fs.default.promises.writeFile(
405
+ import_node_path.default.join(readyDir, "runtime.json"),
406
+ `${JSON.stringify({ packageVersion: manifest.packageVersion, sha256: manifest.sha256 }, null, 2)}
407
+ `,
408
+ { mode: 384 }
409
+ );
410
+ await import_node_fs.default.promises.rename(readyDir, runtimeDir);
411
+ } finally {
412
+ await import_node_fs.default.promises.rm(workDir, { recursive: true, force: true });
413
+ }
414
+ }
415
+ async function cachedRuntimeIsValid(runtimeDir, manifest, runner) {
416
+ try {
417
+ const marker = JSON.parse(await import_node_fs.default.promises.readFile(import_node_path.default.join(runtimeDir, "runtime.json"), "utf8"));
418
+ if (marker.packageVersion !== manifest.packageVersion || marker.sha256 !== manifest.sha256) return false;
419
+ await verifyNativeApp(import_node_path.default.join(runtimeDir, manifest.appName), manifest, runner);
420
+ return true;
421
+ } catch {
422
+ return false;
423
+ }
424
+ }
425
+ async function ensureNativeRuntime(manifest, dependencies = {}) {
426
+ const cacheRoot = dependencies.cacheRoot ?? defaultCacheRoot();
427
+ const commandRunner = dependencies.commandRunner ?? runCommand;
428
+ const download = dependencies.download ?? downloadNativeArtifact;
429
+ const destination = runtimeDirectory(cacheRoot, manifest);
430
+ await ensurePrivateDirectory(cacheRoot, "native runtime cache");
431
+ await ensurePrivateDirectory(import_node_path.default.dirname(destination), "native runtimes directory");
432
+ if (await cachedRuntimeIsValid(destination, manifest, commandRunner)) {
433
+ return nativeExecutablePath(destination, manifest);
434
+ }
435
+ const lockPath = import_node_path.default.join(cacheRoot, "locks", `${manifest.packageVersion}.lock`);
436
+ return withDirectoryLock(
437
+ lockPath,
438
+ async () => {
439
+ if (!await cachedRuntimeIsValid(destination, manifest, commandRunner)) {
440
+ await import_node_fs.default.promises.rm(destination, { recursive: true, force: true });
441
+ await installRuntime(destination, manifest, { commandRunner, download });
442
+ }
443
+ return nativeExecutablePath(destination, manifest);
444
+ },
445
+ {
446
+ pollMs: dependencies.lockPollMs ?? 100,
447
+ timeoutMs: dependencies.lockTimeoutMs ?? 5 * 6e4,
448
+ staleLockMs: dependencies.staleLockMs ?? 10 * 6e4
449
+ }
450
+ );
451
+ }
452
+ // Annotate the CommonJS export names for ESM import in node:
453
+ 0 && (module.exports = {
454
+ codeSignatureUsesHardenedRuntime,
455
+ defaultCacheRoot,
456
+ downloadNativeArtifact,
457
+ ensureNativeRuntime,
458
+ inspectMachOExecutable,
459
+ nativeExecutablePath,
460
+ pruneObsoleteNativeRuntimes,
461
+ runCommand,
462
+ runtimeDirectory,
463
+ verifyNativeApp
464
+ });
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "@ricsam/r5d-macos-vm",
3
+ "version": "0.0.55",
4
+ "type": "commonjs"
5
+ }
@@ -0,0 +1,176 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ const MACOS_VM_PACKAGE_NAME = "@ricsam/r5d-macos-vm";
4
+ const NATIVE_ARCHIVE_NAME = "R5DMacOSVM.app.zip";
5
+ const NATIVE_APP_NAME = "R5DMacOSVM.app";
6
+ const NATIVE_EXECUTABLE_NAME = "R5DMacOSVM";
7
+ const NATIVE_BUNDLE_IDENTIFIER = "dev.r5d.macos-vm";
8
+ const NATIVE_MINIMUM_MACOS_VERSION = "14.0";
9
+ const NATIVE_ARTIFACT_HOST = "downloads.r5d.dev";
10
+ const FORBIDDEN_VM_ARTIFACT_BASENAMES = /* @__PURE__ */ new Set([
11
+ "auxiliarystorage",
12
+ "disk.img",
13
+ "hardwaremodel",
14
+ "machineidentifier",
15
+ "restoreimage.ipsw",
16
+ "savefile.vzvmsave"
17
+ ]);
18
+ const FORBIDDEN_VM_ARTIFACT_EXTENSION = /\.(?:img|ipsw|r5dvm|vzvmsave)$/i;
19
+ function expectedArtifactUrl(version) {
20
+ return `https://${NATIVE_ARTIFACT_HOST}/r5d-macos-vm/${encodeURIComponent(version)}/${NATIVE_ARCHIVE_NAME}`;
21
+ }
22
+ function isForbiddenVirtualMachineArtifactPath(filePath) {
23
+ const normalized = filePath.replaceAll("\\", "/").replace(/\/+$/, "");
24
+ const basename = normalized.slice(normalized.lastIndexOf("/") + 1).toLowerCase();
25
+ return FORBIDDEN_VM_ARTIFACT_BASENAMES.has(basename) || FORBIDDEN_VM_ARTIFACT_EXTENSION.test(basename);
26
+ }
27
+ function findForbiddenVirtualMachineArtifactPaths(paths) {
28
+ return paths.filter(isForbiddenVirtualMachineArtifactPath);
29
+ }
30
+ function requireObject(value) {
31
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
32
+ throw new Error("The native artifact manifest must contain a JSON object.");
33
+ }
34
+ return value;
35
+ }
36
+ function requireString(value, field) {
37
+ if (typeof value !== "string" || value.length === 0) {
38
+ throw new Error(`The native artifact manifest field '${field}' must be a non-empty string.`);
39
+ }
40
+ return value;
41
+ }
42
+ function parseNativeArtifactManifest(value, expectedPackageVersion) {
43
+ const input = requireObject(value);
44
+ if (input.schemaVersion !== 1) throw new Error("Unsupported native artifact manifest schema.");
45
+ const packageVersion = requireString(input.packageVersion, "packageVersion");
46
+ if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(packageVersion)) {
47
+ throw new Error("Native artifact packageVersion must be a semantic version.");
48
+ }
49
+ if (packageVersion !== expectedPackageVersion) {
50
+ throw new Error(`Native artifact version ${packageVersion} does not match package version ${expectedPackageVersion}.`);
51
+ }
52
+ const url = requireString(input.url, "url");
53
+ if (url !== expectedArtifactUrl(packageVersion)) {
54
+ throw new Error(`Native artifact URL must be ${expectedArtifactUrl(packageVersion)}.`);
55
+ }
56
+ const sha256 = requireString(input.sha256, "sha256").toLowerCase();
57
+ if (!/^[0-9a-f]{64}$/.test(sha256)) throw new Error("Native artifact sha256 must contain 64 hexadecimal characters.");
58
+ const byteLength = input.byteLength;
59
+ if (!Number.isSafeInteger(byteLength) || byteLength <= 0 || byteLength > 100 * 1024 * 1024) {
60
+ throw new Error("Native artifact byteLength must be between 1 byte and 100 MiB.");
61
+ }
62
+ const teamIdentifier = requireString(input.teamIdentifier, "teamIdentifier");
63
+ if (!/^[A-Z0-9]{10}$/.test(teamIdentifier)) {
64
+ throw new Error("Native artifact teamIdentifier must be a 10-character Apple Team ID.");
65
+ }
66
+ const fixedFields = {
67
+ archiveName: NATIVE_ARCHIVE_NAME,
68
+ appName: NATIVE_APP_NAME,
69
+ executableName: NATIVE_EXECUTABLE_NAME,
70
+ bundleIdentifier: NATIVE_BUNDLE_IDENTIFIER,
71
+ architecture: "arm64",
72
+ minimumMacOSVersion: NATIVE_MINIMUM_MACOS_VERSION
73
+ };
74
+ for (const [field, expected] of Object.entries(fixedFields)) {
75
+ if (input[field] !== expected) throw new Error(`Native artifact ${field} must be ${expected}.`);
76
+ }
77
+ return {
78
+ schemaVersion: 1,
79
+ packageVersion,
80
+ url,
81
+ sha256,
82
+ byteLength,
83
+ archiveName: NATIVE_ARCHIVE_NAME,
84
+ appName: NATIVE_APP_NAME,
85
+ executableName: NATIVE_EXECUTABLE_NAME,
86
+ bundleIdentifier: NATIVE_BUNDLE_IDENTIFIER,
87
+ teamIdentifier,
88
+ architecture: "arm64",
89
+ minimumMacOSVersion: NATIVE_MINIMUM_MACOS_VERSION
90
+ };
91
+ }
92
+ function readNativeArtifactManifest(filePath, expectedPackageVersion) {
93
+ let value;
94
+ try {
95
+ value = JSON.parse(fs.readFileSync(filePath, "utf8"));
96
+ } catch (error) {
97
+ throw new Error(`Unable to read native artifact manifest at ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
98
+ }
99
+ return parseNativeArtifactManifest(value, expectedPackageVersion);
100
+ }
101
+ function findFileUpward(startPath, fileName) {
102
+ let current = path.resolve(startPath);
103
+ try {
104
+ if (!fs.statSync(current).isDirectory()) current = path.dirname(current);
105
+ } catch {
106
+ current = path.dirname(current);
107
+ }
108
+ while (true) {
109
+ const candidate = path.join(current, fileName);
110
+ if (fs.existsSync(candidate)) return candidate;
111
+ const parent = path.dirname(current);
112
+ if (parent === current) return null;
113
+ current = parent;
114
+ }
115
+ }
116
+ function findPackageRoot(startPath) {
117
+ let current = path.resolve(startPath);
118
+ try {
119
+ if (!fs.statSync(current).isDirectory()) current = path.dirname(current);
120
+ } catch {
121
+ current = path.dirname(current);
122
+ }
123
+ let sourceRoot = null;
124
+ while (true) {
125
+ const packageJsonPath = path.join(current, "package.json");
126
+ if (fs.existsSync(packageJsonPath)) {
127
+ try {
128
+ const value = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
129
+ if (value.name === MACOS_VM_PACKAGE_NAME && typeof value.bin?.["r5d-macos-vm"] === "string") return current;
130
+ } catch {
131
+ }
132
+ }
133
+ if (path.basename(current) === "r5d-macos-vm" && fs.existsSync(path.join(path.dirname(current), "VERSION.txt"))) {
134
+ sourceRoot = current;
135
+ }
136
+ const parent = path.dirname(current);
137
+ if (parent === current) return sourceRoot;
138
+ current = parent;
139
+ }
140
+ }
141
+ function findPackageVersion(startPath) {
142
+ const packageRoot = findPackageRoot(startPath);
143
+ if (packageRoot) {
144
+ const packageJsonPath = path.join(packageRoot, "package.json");
145
+ if (fs.existsSync(packageJsonPath)) {
146
+ try {
147
+ const value = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
148
+ if (value.name === MACOS_VM_PACKAGE_NAME && typeof value.version === "string") return value.version;
149
+ } catch {
150
+ }
151
+ }
152
+ const localVersionPath = path.join(path.dirname(packageRoot), "VERSION.txt");
153
+ if (fs.existsSync(localVersionPath)) {
154
+ const version = fs.readFileSync(localVersionPath, "utf8").trim();
155
+ if (/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(version)) return version;
156
+ }
157
+ }
158
+ throw new Error(`Unable to determine the installed ${MACOS_VM_PACKAGE_NAME} version.`);
159
+ }
160
+ export {
161
+ MACOS_VM_PACKAGE_NAME,
162
+ NATIVE_APP_NAME,
163
+ NATIVE_ARCHIVE_NAME,
164
+ NATIVE_ARTIFACT_HOST,
165
+ NATIVE_BUNDLE_IDENTIFIER,
166
+ NATIVE_EXECUTABLE_NAME,
167
+ NATIVE_MINIMUM_MACOS_VERSION,
168
+ expectedArtifactUrl,
169
+ findFileUpward,
170
+ findForbiddenVirtualMachineArtifactPaths,
171
+ findPackageRoot,
172
+ findPackageVersion,
173
+ isForbiddenVirtualMachineArtifactPath,
174
+ parseNativeArtifactManifest,
175
+ readNativeArtifactManifest
176
+ };