@elpapi42/pi-fleet 0.1.0-beta.1 → 0.1.0-beta.2
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/CHANGELOG.md +27 -0
- package/README.md +6 -3
- package/dist/cli-meta.json +8 -8
- package/dist/cli.mjs +137 -13
- package/dist/cli.mjs.map +3 -3
- package/dist/installer-meta.json +4 -4
- package/dist/installer.mjs +116 -11
- package/dist/installer.mjs.map +3 -3
- package/dist/runtime-manifest.json +24 -24
- package/dist/runtime-meta.json +12 -12
- package/dist/runtime.mjs +149 -46
- package/dist/runtime.mjs.map +2 -2
- package/dist/sqlite-worker-meta.json +4 -4
- package/dist/sqlite-worker.mjs +45 -38
- package/dist/sqlite-worker.mjs.map +2 -2
- package/package.json +4 -1
package/dist/installer-meta.json
CHANGED
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"format": "esm"
|
|
65
65
|
},
|
|
66
66
|
"src/platform/install/runtime-release.ts": {
|
|
67
|
-
"bytes":
|
|
67
|
+
"bytes": 9583,
|
|
68
68
|
"imports": [
|
|
69
69
|
{
|
|
70
70
|
"path": "node:crypto",
|
|
@@ -152,7 +152,7 @@
|
|
|
152
152
|
"imports": [],
|
|
153
153
|
"exports": [],
|
|
154
154
|
"inputs": {},
|
|
155
|
-
"bytes":
|
|
155
|
+
"bytes": 37234
|
|
156
156
|
},
|
|
157
157
|
"dist/installer.mjs": {
|
|
158
158
|
"imports": [
|
|
@@ -259,7 +259,7 @@
|
|
|
259
259
|
"bytesInOutput": 1889
|
|
260
260
|
},
|
|
261
261
|
"src/platform/install/runtime-release.ts": {
|
|
262
|
-
"bytesInOutput":
|
|
262
|
+
"bytesInOutput": 8512
|
|
263
263
|
},
|
|
264
264
|
"src/platform/install/tree-integrity.ts": {
|
|
265
265
|
"bytesInOutput": 1890
|
|
@@ -268,7 +268,7 @@
|
|
|
268
268
|
"bytesInOutput": 1207
|
|
269
269
|
}
|
|
270
270
|
},
|
|
271
|
-
"bytes":
|
|
271
|
+
"bytes": 19836
|
|
272
272
|
}
|
|
273
273
|
}
|
|
274
274
|
}
|
package/dist/installer.mjs
CHANGED
|
@@ -156,8 +156,8 @@ async function atomicWrite(path, contents) {
|
|
|
156
156
|
|
|
157
157
|
// src/platform/install/runtime-release.ts
|
|
158
158
|
import { createHash as createHash2, randomUUID } from "node:crypto";
|
|
159
|
-
import { chmod as chmod2, cp, lstat as lstat2, mkdir as mkdir2, readFile as readFile3, rename as rename2, rm as rm2
|
|
160
|
-
import { join as join3, resolve as resolve2, sep as sep2 } from "node:path";
|
|
159
|
+
import { chmod as chmod2, cp, lstat as lstat2, mkdir as mkdir2, readFile as readFile3, rename as rename2, rm as rm2 } from "node:fs/promises";
|
|
160
|
+
import { join as join3, posix, resolve as resolve2, sep as sep2 } from "node:path";
|
|
161
161
|
|
|
162
162
|
// src/platform/install/tree-integrity.ts
|
|
163
163
|
import { createHash } from "node:crypto";
|
|
@@ -211,12 +211,21 @@ async function collectFiles(root, directory) {
|
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
// src/platform/install/runtime-release.ts
|
|
214
|
+
var requiredRuntimeArtifacts = /* @__PURE__ */ new Set([
|
|
215
|
+
"package.json",
|
|
216
|
+
"bin/pifleet.mjs",
|
|
217
|
+
"bin/pifleet-runtime.mjs",
|
|
218
|
+
"dist/cli.mjs",
|
|
219
|
+
"dist/runtime.mjs",
|
|
220
|
+
"dist/sqlite-worker.mjs"
|
|
221
|
+
]);
|
|
214
222
|
async function materializeRuntime(options) {
|
|
215
223
|
const sourceRoot = resolve2(options.sourceRoot);
|
|
224
|
+
const manifestBytes = await readFile3(join3(sourceRoot, "dist", "runtime-manifest.json"));
|
|
225
|
+
const manifest = await parseRuntimeManifest(manifestBytes, sourceRoot);
|
|
226
|
+
await verifyRuntime(sourceRoot, manifest);
|
|
216
227
|
const applicationRoot = resolve2(options.applicationRoot);
|
|
217
228
|
await ensurePrivateDirectory(applicationRoot);
|
|
218
|
-
const manifestBytes = await readFile3(join3(sourceRoot, "dist", "runtime-manifest.json"));
|
|
219
|
-
const manifest = JSON.parse(manifestBytes.toString("utf8"));
|
|
220
229
|
const manifestHash = createHash2("sha256").update(manifestBytes).digest("hex").slice(0, 16);
|
|
221
230
|
const releasesRoot = join3(applicationRoot, "releases");
|
|
222
231
|
await ensurePrivateDirectory(releasesRoot);
|
|
@@ -242,21 +251,30 @@ async function materializeRuntime(options) {
|
|
|
242
251
|
}
|
|
243
252
|
await verifyRuntime(staging, manifest);
|
|
244
253
|
await chmod2(staging, 448);
|
|
245
|
-
|
|
254
|
+
try {
|
|
255
|
+
await rename2(staging, destination);
|
|
256
|
+
} catch (error) {
|
|
257
|
+
if (!isDestinationRace(error) || !await pathExists(destination)) throw error;
|
|
258
|
+
await verifyRuntime(destination, manifest);
|
|
259
|
+
}
|
|
246
260
|
return destination;
|
|
247
|
-
}
|
|
261
|
+
} finally {
|
|
248
262
|
await rm2(staging, { recursive: true, force: true });
|
|
249
|
-
throw error;
|
|
250
263
|
}
|
|
251
264
|
}
|
|
252
265
|
async function verifyRuntime(root, manifest) {
|
|
253
|
-
const expected = manifest ?? JSON.parse(
|
|
254
|
-
await readFile3(join3(root, "dist", "runtime-manifest.json"), "utf8")
|
|
255
|
-
);
|
|
256
266
|
const resolvedRoot = resolve2(root);
|
|
267
|
+
const expected = manifest ?? await parseRuntimeManifest(
|
|
268
|
+
await readFile3(join3(resolvedRoot, "dist", "runtime-manifest.json")),
|
|
269
|
+
resolvedRoot
|
|
270
|
+
);
|
|
271
|
+
if (manifest !== void 0) await validateRuntimeManifest(manifest, resolvedRoot);
|
|
257
272
|
for (const file of expected.files) {
|
|
258
273
|
const path = resolveInside(resolvedRoot, file.path);
|
|
259
|
-
const info = await
|
|
274
|
+
const info = await lstat2(path);
|
|
275
|
+
if (info.isSymbolicLink()) {
|
|
276
|
+
throw new Error(`Runtime artifact ${file.path} must not be a symbolic link`);
|
|
277
|
+
}
|
|
260
278
|
if (!info.isFile() || info.size !== file.bytes) {
|
|
261
279
|
throw new Error(`Runtime artifact ${file.path} has changed`);
|
|
262
280
|
}
|
|
@@ -273,13 +291,100 @@ async function verifyRuntime(root, manifest) {
|
|
|
273
291
|
}
|
|
274
292
|
}
|
|
275
293
|
}
|
|
294
|
+
async function parseRuntimeManifest(bytes, root) {
|
|
295
|
+
let candidate;
|
|
296
|
+
try {
|
|
297
|
+
candidate = JSON.parse(bytes.toString("utf8"));
|
|
298
|
+
} catch {
|
|
299
|
+
throw new Error("Runtime manifest is not valid JSON");
|
|
300
|
+
}
|
|
301
|
+
await validateRuntimeManifest(candidate, root);
|
|
302
|
+
return candidate;
|
|
303
|
+
}
|
|
304
|
+
async function validateRuntimeManifest(candidate, root) {
|
|
305
|
+
if (!isRecord(candidate) || candidate.schemaVersion !== 2) {
|
|
306
|
+
throw new Error("Runtime manifest has an unsupported schema version");
|
|
307
|
+
}
|
|
308
|
+
if (!isRecord(candidate.package) || typeof candidate.package.name !== "string" || typeof candidate.package.version !== "string") {
|
|
309
|
+
throw new Error("Runtime manifest has an invalid package identity");
|
|
310
|
+
}
|
|
311
|
+
const packageIdentity = await readPackageIdentity(root);
|
|
312
|
+
if (candidate.package.name !== packageIdentity.name || candidate.package.version !== packageIdentity.version) {
|
|
313
|
+
throw new Error("Runtime manifest package identity does not match package.json");
|
|
314
|
+
}
|
|
315
|
+
if (!Array.isArray(candidate.files) || !Array.isArray(candidate.trees)) {
|
|
316
|
+
throw new Error("Runtime manifest has invalid artifact lists");
|
|
317
|
+
}
|
|
318
|
+
const filePaths = /* @__PURE__ */ new Set();
|
|
319
|
+
for (const file of candidate.files) {
|
|
320
|
+
if (!isRecord(file) || !isManifestPath(file.path) || !isValidSize(file.bytes) || !isSha256(file.sha256)) {
|
|
321
|
+
throw new Error("Runtime manifest contains an invalid artifact");
|
|
322
|
+
}
|
|
323
|
+
if (filePaths.has(file.path))
|
|
324
|
+
throw new Error(`Runtime manifest has duplicate path ${file.path}`);
|
|
325
|
+
filePaths.add(file.path);
|
|
326
|
+
}
|
|
327
|
+
for (const required of requiredRuntimeArtifacts) {
|
|
328
|
+
if (!filePaths.has(required)) {
|
|
329
|
+
throw new Error(`Runtime manifest is missing required artifact ${required}`);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
const treePaths = /* @__PURE__ */ new Set();
|
|
333
|
+
for (const tree of candidate.trees) {
|
|
334
|
+
if (!isRecord(tree) || !isManifestPath(tree.path) || !isValidSize(tree.files) || !isValidSize(tree.bytes) || !isSha256(tree.sha256)) {
|
|
335
|
+
throw new Error("Runtime manifest contains an invalid dependency tree");
|
|
336
|
+
}
|
|
337
|
+
if (treePaths.has(tree.path))
|
|
338
|
+
throw new Error(`Runtime manifest has duplicate path ${tree.path}`);
|
|
339
|
+
treePaths.add(tree.path);
|
|
340
|
+
}
|
|
341
|
+
const allPaths = [...filePaths, ...treePaths];
|
|
342
|
+
for (let index = 0; index < allPaths.length; index += 1) {
|
|
343
|
+
for (let other = index + 1; other < allPaths.length; other += 1) {
|
|
344
|
+
const left = allPaths[index];
|
|
345
|
+
const right = allPaths[other];
|
|
346
|
+
if (left === right || left.startsWith(`${right}/`) || right.startsWith(`${left}/`)) {
|
|
347
|
+
throw new Error(`Runtime manifest has overlapping paths ${left} and ${right}`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
async function readPackageIdentity(root) {
|
|
353
|
+
let candidate;
|
|
354
|
+
try {
|
|
355
|
+
candidate = JSON.parse(await readFile3(join3(root, "package.json"), "utf8"));
|
|
356
|
+
} catch {
|
|
357
|
+
throw new Error("Runtime package.json is not valid JSON");
|
|
358
|
+
}
|
|
359
|
+
if (!isRecord(candidate) || typeof candidate.name !== "string" || typeof candidate.version !== "string") {
|
|
360
|
+
throw new Error("Runtime package.json has an invalid identity");
|
|
361
|
+
}
|
|
362
|
+
return { name: candidate.name, version: candidate.version };
|
|
363
|
+
}
|
|
276
364
|
function resolveInside(root, path) {
|
|
365
|
+
if (!isManifestPath(path)) throw new Error(`Runtime manifest contains an unsafe path ${path}`);
|
|
277
366
|
const resolved = resolve2(root, path);
|
|
278
367
|
if (!resolved.startsWith(`${root}${sep2}`)) {
|
|
279
368
|
throw new Error(`Runtime manifest contains an unsafe path ${path}`);
|
|
280
369
|
}
|
|
281
370
|
return resolved;
|
|
282
371
|
}
|
|
372
|
+
function isRecord(value) {
|
|
373
|
+
return typeof value === "object" && value !== null;
|
|
374
|
+
}
|
|
375
|
+
function isManifestPath(value) {
|
|
376
|
+
return typeof value === "string" && value.length > 0 && !value.includes("\\") && !value.startsWith("/") && posix.normalize(value) === value && value.split("/").every((part) => part.length > 0 && part !== "." && part !== "..");
|
|
377
|
+
}
|
|
378
|
+
function isValidSize(value) {
|
|
379
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
380
|
+
}
|
|
381
|
+
function isSha256(value) {
|
|
382
|
+
return typeof value === "string" && /^[a-f0-9]{64}$/.test(value);
|
|
383
|
+
}
|
|
384
|
+
function isDestinationRace(error) {
|
|
385
|
+
const code = error.code;
|
|
386
|
+
return code === "EEXIST" || code === "ENOTEMPTY";
|
|
387
|
+
}
|
|
283
388
|
async function ensurePrivateDirectory(path) {
|
|
284
389
|
await mkdir2(path, { recursive: true, mode: 448 });
|
|
285
390
|
const info = await lstat2(path);
|
package/dist/installer.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/entry/installer.ts", "../src/platform/install/service-installer.ts", "../src/platform/install/service-definition.ts", "../src/platform/install/runtime-release.ts", "../src/platform/install/tree-integrity.ts", "../src/platform/shared/paths.ts"],
|
|
4
|
-
"sourcesContent": ["import { execFile } from \"node:child_process\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport { promisify } from \"node:util\";\n\nimport {\n installUserService,\n uninstallUserService,\n type CommandExecutor,\n} from \"../platform/install/service-installer.js\";\nimport { materializeRuntime } from \"../platform/install/runtime-release.js\";\nimport { resolveApplicationRoot, resolveFleetPaths } from \"../platform/shared/paths.js\";\n\nconst executor: CommandExecutor = {\n async run(command, args) {\n await promisify(execFile)(command, [...args]);\n },\n};\n\nexport async function installRuntimeService(): Promise<string> {\n return installMaterializedService(resolveFleetPaths().stateRoot);\n}\n\nexport async function repairRuntimeService(): Promise<string> {\n return installMaterializedService(process.env.PIFLEET_STATE_ROOT);\n}\n\nasync function installMaterializedService(stateRoot: string | undefined): Promise<string> {\n const sourceRoot = dirname(dirname(fileURLToPath(import.meta.url)));\n const release = await materializeRuntime({\n sourceRoot,\n applicationRoot: resolveApplicationRoot(),\n });\n return installUserService({\n platform: process.platform,\n definition: {\n nodePath: process.execPath,\n runtimePath: join(release, \"bin\", \"pifleet-runtime.mjs\"),\n ...(stateRoot === undefined ? {} : { stateRoot }),\n },\n executor,\n });\n}\n\nexport async function uninstallRuntimeService(): Promise<void> {\n await uninstallUserService({ platform: process.platform, executor });\n}\n\nasync function main(): Promise<void> {\n const command = process.argv[2];\n if (command === \"install\") {\n process.stdout.write(`${await installRuntimeService()}\\n`);\n return;\n }\n if (command === \"repair\") {\n process.stdout.write(`${await repairRuntimeService()}\\n`);\n return;\n }\n if (command === \"uninstall\") {\n await uninstallRuntimeService();\n return;\n }\n throw new Error(\"Usage: node dist/installer.mjs <install|repair|uninstall>\");\n}\n\nif (process.argv[1] !== undefined && import.meta.url === pathToFileURL(process.argv[1]).href) {\n await main();\n}\n", "import { constants } from \"node:fs\";\nimport { access, chmod, mkdir, readFile, rename, rm, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nimport {\n launchdAgentPlist,\n systemdUserUnit,\n type ServiceDefinitionOptions,\n} from \"./service-definition.js\";\n\nexport interface CommandExecutor {\n run(command: string, args: readonly string[]): Promise<void>;\n}\n\nexport async function installUserService(options: {\n readonly platform: NodeJS.Platform;\n readonly definition: ServiceDefinitionOptions;\n readonly executor: CommandExecutor;\n readonly home?: string;\n readonly uid?: number;\n}): Promise<string> {\n const home = options.home ?? homedir();\n if (options.platform === \"linux\") {\n const path = join(home, \".config\", \"systemd\", \"user\", \"pi-fleet.service\");\n const effectiveDefinition = await preserveInstalledStateRoot(path, options.definition, \"linux\");\n const definition = systemdUserUnit(effectiveDefinition);\n const needsRepair = await serviceDefinitionNeedsRepair(path, definition, effectiveDefinition);\n if (needsRepair) {\n await atomicWrite(path, definition);\n await options.executor.run(\"systemctl\", [\"--user\", \"daemon-reload\"]);\n }\n await options.executor.run(\"systemctl\", [\"--user\", \"enable\", \"--now\", \"pi-fleet.service\"]);\n if (needsRepair) {\n await options.executor.run(\"systemctl\", [\"--user\", \"restart\", \"pi-fleet.service\"]);\n }\n return path;\n }\n if (options.platform === \"darwin\") {\n const path = join(home, \"Library\", \"LaunchAgents\", \"works.elpapi.pifleet.plist\");\n const effectiveDefinition = await preserveInstalledStateRoot(\n path,\n options.definition,\n \"darwin\",\n );\n await atomicWrite(path, launchdAgentPlist(effectiveDefinition));\n const domain = `gui/${options.uid ?? process.getuid?.() ?? 0}`;\n await options.executor.run(\"launchctl\", [\"bootout\", domain, path]).catch(() => undefined);\n await options.executor.run(\"launchctl\", [\"bootstrap\", domain, path]);\n await options.executor.run(\"launchctl\", [\"kickstart\", `${domain}/works.elpapi.pifleet`]);\n return path;\n }\n throw new Error(`Native Pi Fleet supervision is unsupported on ${options.platform}`);\n}\n\nexport async function uninstallUserService(options: {\n readonly platform: NodeJS.Platform;\n readonly executor: CommandExecutor;\n readonly home?: string;\n readonly uid?: number;\n}): Promise<void> {\n const home = options.home ?? homedir();\n if (options.platform === \"linux\") {\n const path = join(home, \".config\", \"systemd\", \"user\", \"pi-fleet.service\");\n await options.executor.run(\"systemctl\", [\"--user\", \"disable\", \"--now\", \"pi-fleet.service\"]);\n await rm(path, { force: true });\n await options.executor.run(\"systemctl\", [\"--user\", \"daemon-reload\"]);\n return;\n }\n if (options.platform === \"darwin\") {\n const path = join(home, \"Library\", \"LaunchAgents\", \"works.elpapi.pifleet.plist\");\n const domain = `gui/${options.uid ?? process.getuid?.() ?? 0}`;\n await options.executor.run(\"launchctl\", [\"bootout\", domain, path]).catch(() => undefined);\n await rm(path, { force: true });\n return;\n }\n throw new Error(`Native Pi Fleet supervision is unsupported on ${options.platform}`);\n}\n\nexport async function serviceDefinitionNeedsRepair(\n path: string,\n expectedContents: string,\n definition: ServiceDefinitionOptions,\n): Promise<boolean> {\n const current = await readFile(path, \"utf8\").catch((error: NodeJS.ErrnoException) => {\n if (error.code === \"ENOENT\") return null;\n throw error;\n });\n if (current !== expectedContents) return true;\n try {\n await access(definition.nodePath, constants.X_OK);\n await access(definition.runtimePath, constants.R_OK);\n return false;\n } catch {\n return true;\n }\n}\n\nasync function preserveInstalledStateRoot(\n path: string,\n definition: ServiceDefinitionOptions,\n platform: \"linux\" | \"darwin\",\n): Promise<ServiceDefinitionOptions> {\n if (definition.stateRoot !== undefined) return definition;\n const current = await readFile(path, \"utf8\").catch((error: NodeJS.ErrnoException) => {\n if (error.code === \"ENOENT\") return null;\n throw error;\n });\n if (current === null) return definition;\n const encoded =\n platform === \"linux\"\n ? /^Environment=PIFLEET_STATE_ROOT=(.+)$/m.exec(current)?.[1]\n : /<key>PIFLEET_STATE_ROOT<\\/key><string>([^<]+)<\\/string>/.exec(current)?.[1];\n if (encoded === undefined) return definition;\n const stateRoot =\n platform === \"linux\"\n ? encoded\n : encoded\n .replaceAll(\"'\", \"'\")\n .replaceAll(\""\", '\"')\n .replaceAll(\">\", \">\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\"&\", \"&\");\n return { ...definition, stateRoot };\n}\n\nasync function atomicWrite(path: string, contents: string): Promise<void> {\n await mkdir(dirname(path), { recursive: true, mode: 0o700 });\n const temporary = `${path}.tmp-${process.pid}`;\n await writeFile(temporary, contents, { mode: 0o600 });\n await chmod(temporary, 0o600);\n await rename(temporary, path);\n}\n", "import { isAbsolute } from \"node:path\";\n\nexport interface ServiceDefinitionOptions {\n readonly nodePath: string;\n readonly runtimePath: string;\n readonly stateRoot?: string;\n}\n\nexport function systemdUserUnit(options: ServiceDefinitionOptions): string {\n validate(options);\n const environment =\n options.stateRoot === undefined\n ? \"\"\n : `Environment=PIFLEET_STATE_ROOT=${systemdEscape(options.stateRoot)}\\n`;\n return `[Unit]\nDescription=Pi Fleet user runtime\nAfter=default.target\n\n[Service]\nType=simple\nExecStart=${systemdEscape(options.nodePath)} ${systemdEscape(options.runtimePath)}\n${environment}Restart=on-failure\nRestartSec=1\nTimeoutStopSec=10\nUMask=0077\nKillMode=control-group\n\n[Install]\nWantedBy=default.target\n`;\n}\n\nexport function launchdAgentPlist(options: ServiceDefinitionOptions): string {\n validate(options);\n const environment =\n options.stateRoot === undefined\n ? \"\"\n : ` <key>EnvironmentVariables</key>\n <dict><key>PIFLEET_STATE_ROOT</key><string>${xmlEscape(options.stateRoot)}</string></dict>\n`;\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key><string>works.elpapi.pifleet</string>\n <key>ProgramArguments</key>\n <array>\n <string>${xmlEscape(options.nodePath)}</string>\n <string>${xmlEscape(options.runtimePath)}</string>\n </array>\n${environment} <key>RunAtLoad</key><true/>\n <key>KeepAlive</key><dict><key>SuccessfulExit</key><false/></dict>\n <key>ProcessType</key><string>Background</string>\n</dict>\n</plist>\n`;\n}\n\nfunction validate(options: ServiceDefinitionOptions): void {\n if (!isAbsolute(options.nodePath) || !isAbsolute(options.runtimePath)) {\n throw new Error(\"Service executables must use absolute paths\");\n }\n}\n\nfunction systemdEscape(value: string): string {\n if (!/^[A-Za-z0-9_./:@-]+$/.test(value)) throw new Error(`Unsafe systemd path ${value}`);\n return value;\n}\n\nfunction xmlEscape(value: string): string {\n return value\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\")\n .replaceAll(\"'\", \"'\");\n}\n", "import { createHash, randomUUID } from \"node:crypto\";\nimport { chmod, cp, lstat, mkdir, readFile, rename, rm, stat } from \"node:fs/promises\";\nimport { join, resolve, sep } from \"node:path\";\n\nimport { hashDirectoryTree, type TreeIntegrity } from \"./tree-integrity.js\";\n\ninterface RuntimeManifest {\n readonly schemaVersion: 2;\n readonly package: { readonly name: string; readonly version: string };\n readonly files: readonly {\n readonly path: string;\n readonly bytes: number;\n readonly sha256: string;\n }[];\n readonly trees: readonly TreeIntegrity[];\n}\n\nexport async function materializeRuntime(options: {\n readonly sourceRoot: string;\n readonly applicationRoot: string;\n}): Promise<string> {\n const sourceRoot = resolve(options.sourceRoot);\n const applicationRoot = resolve(options.applicationRoot);\n await ensurePrivateDirectory(applicationRoot);\n const manifestBytes = await readFile(join(sourceRoot, \"dist\", \"runtime-manifest.json\"));\n const manifest = JSON.parse(manifestBytes.toString(\"utf8\")) as RuntimeManifest;\n const manifestHash = createHash(\"sha256\").update(manifestBytes).digest(\"hex\").slice(0, 16);\n const releasesRoot = join(applicationRoot, \"releases\");\n await ensurePrivateDirectory(releasesRoot);\n const destination = join(releasesRoot, `${manifest.package.version}-${manifestHash}`);\n\n if (await pathExists(destination)) {\n await verifyRuntime(destination, manifest);\n return destination;\n }\n\n const staging = join(releasesRoot, `.staging-${randomUUID()}`);\n await mkdir(staging, { mode: 0o700 });\n try {\n await cp(join(sourceRoot, \"dist\"), join(staging, \"dist\"), {\n recursive: true,\n dereference: true,\n });\n await cp(join(sourceRoot, \"bin\"), join(staging, \"bin\"), { recursive: true, dereference: true });\n await cp(join(sourceRoot, \"package.json\"), join(staging, \"package.json\"));\n for (const tree of manifest.trees) {\n const source = resolveInside(sourceRoot, tree.path);\n const destination = resolveInside(staging, tree.path);\n await mkdir(resolve(destination, \"..\"), { recursive: true, mode: 0o700 });\n await cp(source, destination, { recursive: true, dereference: true });\n }\n await verifyRuntime(staging, manifest);\n await chmod(staging, 0o700);\n await rename(staging, destination);\n return destination;\n } catch (error: unknown) {\n await rm(staging, { recursive: true, force: true });\n throw error;\n }\n}\n\nexport async function verifyRuntime(root: string, manifest?: RuntimeManifest): Promise<void> {\n const expected =\n manifest ??\n (JSON.parse(\n await readFile(join(root, \"dist\", \"runtime-manifest.json\"), \"utf8\"),\n ) as RuntimeManifest);\n const resolvedRoot = resolve(root);\n for (const file of expected.files) {\n const path = resolveInside(resolvedRoot, file.path);\n const info = await stat(path);\n if (!info.isFile() || info.size !== file.bytes) {\n throw new Error(`Runtime artifact ${file.path} has changed`);\n }\n const hash = createHash(\"sha256\")\n .update(await readFile(path))\n .digest(\"hex\");\n if (hash !== file.sha256) {\n throw new Error(`Runtime artifact ${file.path} failed verification`);\n }\n }\n for (const expectedTree of expected.trees) {\n const treeRoot = resolveInside(resolvedRoot, expectedTree.path);\n const actualTree = await hashDirectoryTree(treeRoot, expectedTree.path);\n if (\n actualTree.files !== expectedTree.files ||\n actualTree.bytes !== expectedTree.bytes ||\n actualTree.sha256 !== expectedTree.sha256\n ) {\n throw new Error(`Runtime dependency tree ${expectedTree.path} failed verification`);\n }\n }\n}\n\nfunction resolveInside(root: string, path: string): string {\n const resolved = resolve(root, path);\n if (!resolved.startsWith(`${root}${sep}`)) {\n throw new Error(`Runtime manifest contains an unsafe path ${path}`);\n }\n return resolved;\n}\n\nasync function ensurePrivateDirectory(path: string): Promise<void> {\n await mkdir(path, { recursive: true, mode: 0o700 });\n const info = await lstat(path);\n if (!info.isDirectory() || info.isSymbolicLink()) {\n throw new Error(`Refusing unsafe runtime release path ${path}`);\n }\n if (typeof process.getuid === \"function\" && info.uid !== process.getuid()) {\n throw new Error(`Runtime release path ${path} is not owned by the current user`);\n }\n await chmod(path, 0o700);\n}\n\nasync function pathExists(path: string): Promise<boolean> {\n try {\n await lstat(path);\n return true;\n } catch (error: unknown) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n throw error;\n }\n}\n", "import { createHash } from \"node:crypto\";\nimport { lstat, readFile, readdir, stat } from \"node:fs/promises\";\nimport { join, relative, resolve, sep } from \"node:path\";\n\nexport interface TreeIntegrity {\n readonly path: string;\n readonly files: number;\n readonly bytes: number;\n readonly sha256: string;\n}\n\nexport async function hashDirectoryTree(\n root: string,\n manifestPath: string,\n): Promise<TreeIntegrity> {\n const resolvedRoot = resolve(root);\n const entries = await collectFiles(resolvedRoot, resolvedRoot);\n const hash = createHash(\"sha256\");\n let bytes = 0;\n for (const entry of entries) {\n const contents = await readFile(entry.absolutePath);\n bytes += contents.length;\n hash.update(entry.relativePath);\n hash.update(\"\\0\");\n hash.update(String(contents.length));\n hash.update(\"\\0\");\n hash.update(contents);\n hash.update(\"\\0\");\n }\n return {\n path: manifestPath,\n files: entries.length,\n bytes,\n sha256: hash.digest(\"hex\"),\n };\n}\n\nasync function collectFiles(\n root: string,\n directory: string,\n): Promise<Array<{ readonly absolutePath: string; readonly relativePath: string }>> {\n const output: Array<{ absolutePath: string; relativePath: string }> = [];\n for (const name of (await readdir(directory)).sort()) {\n const absolutePath = join(directory, name);\n const linkInfo = await lstat(absolutePath);\n const info = linkInfo.isSymbolicLink() ? await stat(absolutePath) : linkInfo;\n if (info.isDirectory()) {\n if (linkInfo.isSymbolicLink()) {\n throw new Error(`Runtime dependency tree contains a directory symlink: ${absolutePath}`);\n }\n output.push(...(await collectFiles(root, absolutePath)));\n continue;\n }\n if (!info.isFile()) {\n throw new Error(`Runtime dependency tree contains an unsupported entry: ${absolutePath}`);\n }\n const relativePath = relative(root, absolutePath).split(sep).join(\"/\");\n if (relativePath.length === 0 || relativePath.startsWith(\"../\")) {\n throw new Error(`Runtime dependency path escapes its root: ${absolutePath}`);\n }\n output.push({ absolutePath, relativePath });\n }\n return output.sort((left, right) => left.relativePath.localeCompare(right.relativePath));\n}\n", "import { homedir, tmpdir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\n\nexport interface FleetPaths {\n readonly runtimeRoot: string;\n readonly stateRoot: string;\n readonly socketPath: string;\n readonly databasePath: string;\n}\n\nexport function resolveApplicationRoot(env: NodeJS.ProcessEnv = process.env): string {\n return (\n env.PIFLEET_APPLICATION_ROOT ??\n (process.platform === \"darwin\"\n ? join(homedir(), \"Library\", \"Application Support\", \"Pi Fleet\", \"runtime\")\n : join(env.XDG_DATA_HOME ?? join(homedir(), \".local\", \"share\"), \"pi-fleet\"))\n );\n}\n\nexport function resolveFleetPaths(env: NodeJS.ProcessEnv = process.env): FleetPaths {\n const explicitRoot = env.PIFLEET_STATE_ROOT;\n if (explicitRoot !== undefined) {\n const root = resolve(explicitRoot);\n return {\n runtimeRoot: root,\n stateRoot: root,\n socketPath: join(root, \"control.sock\"),\n databasePath: join(root, \"fleet.sqlite\"),\n };\n }\n\n const runtimeRoot = join(\n env.XDG_RUNTIME_DIR ?? tmpdir(),\n `pifleet-${process.getuid?.() ?? \"user\"}`,\n );\n const stateRoot =\n process.platform === \"darwin\"\n ? join(homedir(), \"Library\", \"Application Support\", \"Pi Fleet\")\n : join(env.XDG_STATE_HOME ?? join(homedir(), \".local\", \"state\"), \"pi-fleet\");\n return {\n runtimeRoot,\n stateRoot,\n socketPath: join(runtimeRoot, \"control.sock\"),\n databasePath: join(stateRoot, \"fleet.sqlite\"),\n };\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["dirname", "join", "createHash", "chmod", "lstat", "mkdir", "readFile", "rename", "rm", "
|
|
4
|
+
"sourcesContent": ["import { execFile } from \"node:child_process\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport { promisify } from \"node:util\";\n\nimport {\n installUserService,\n uninstallUserService,\n type CommandExecutor,\n} from \"../platform/install/service-installer.js\";\nimport { materializeRuntime } from \"../platform/install/runtime-release.js\";\nimport { resolveApplicationRoot, resolveFleetPaths } from \"../platform/shared/paths.js\";\n\nconst executor: CommandExecutor = {\n async run(command, args) {\n await promisify(execFile)(command, [...args]);\n },\n};\n\nexport async function installRuntimeService(): Promise<string> {\n return installMaterializedService(resolveFleetPaths().stateRoot);\n}\n\nexport async function repairRuntimeService(): Promise<string> {\n return installMaterializedService(process.env.PIFLEET_STATE_ROOT);\n}\n\nasync function installMaterializedService(stateRoot: string | undefined): Promise<string> {\n const sourceRoot = dirname(dirname(fileURLToPath(import.meta.url)));\n const release = await materializeRuntime({\n sourceRoot,\n applicationRoot: resolveApplicationRoot(),\n });\n return installUserService({\n platform: process.platform,\n definition: {\n nodePath: process.execPath,\n runtimePath: join(release, \"bin\", \"pifleet-runtime.mjs\"),\n ...(stateRoot === undefined ? {} : { stateRoot }),\n },\n executor,\n });\n}\n\nexport async function uninstallRuntimeService(): Promise<void> {\n await uninstallUserService({ platform: process.platform, executor });\n}\n\nasync function main(): Promise<void> {\n const command = process.argv[2];\n if (command === \"install\") {\n process.stdout.write(`${await installRuntimeService()}\\n`);\n return;\n }\n if (command === \"repair\") {\n process.stdout.write(`${await repairRuntimeService()}\\n`);\n return;\n }\n if (command === \"uninstall\") {\n await uninstallRuntimeService();\n return;\n }\n throw new Error(\"Usage: node dist/installer.mjs <install|repair|uninstall>\");\n}\n\nif (process.argv[1] !== undefined && import.meta.url === pathToFileURL(process.argv[1]).href) {\n await main();\n}\n", "import { constants } from \"node:fs\";\nimport { access, chmod, mkdir, readFile, rename, rm, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nimport {\n launchdAgentPlist,\n systemdUserUnit,\n type ServiceDefinitionOptions,\n} from \"./service-definition.js\";\n\nexport interface CommandExecutor {\n run(command: string, args: readonly string[]): Promise<void>;\n}\n\nexport async function installUserService(options: {\n readonly platform: NodeJS.Platform;\n readonly definition: ServiceDefinitionOptions;\n readonly executor: CommandExecutor;\n readonly home?: string;\n readonly uid?: number;\n}): Promise<string> {\n const home = options.home ?? homedir();\n if (options.platform === \"linux\") {\n const path = join(home, \".config\", \"systemd\", \"user\", \"pi-fleet.service\");\n const effectiveDefinition = await preserveInstalledStateRoot(path, options.definition, \"linux\");\n const definition = systemdUserUnit(effectiveDefinition);\n const needsRepair = await serviceDefinitionNeedsRepair(path, definition, effectiveDefinition);\n if (needsRepair) {\n await atomicWrite(path, definition);\n await options.executor.run(\"systemctl\", [\"--user\", \"daemon-reload\"]);\n }\n await options.executor.run(\"systemctl\", [\"--user\", \"enable\", \"--now\", \"pi-fleet.service\"]);\n if (needsRepair) {\n await options.executor.run(\"systemctl\", [\"--user\", \"restart\", \"pi-fleet.service\"]);\n }\n return path;\n }\n if (options.platform === \"darwin\") {\n const path = join(home, \"Library\", \"LaunchAgents\", \"works.elpapi.pifleet.plist\");\n const effectiveDefinition = await preserveInstalledStateRoot(\n path,\n options.definition,\n \"darwin\",\n );\n await atomicWrite(path, launchdAgentPlist(effectiveDefinition));\n const domain = `gui/${options.uid ?? process.getuid?.() ?? 0}`;\n await options.executor.run(\"launchctl\", [\"bootout\", domain, path]).catch(() => undefined);\n await options.executor.run(\"launchctl\", [\"bootstrap\", domain, path]);\n await options.executor.run(\"launchctl\", [\"kickstart\", `${domain}/works.elpapi.pifleet`]);\n return path;\n }\n throw new Error(`Native Pi Fleet supervision is unsupported on ${options.platform}`);\n}\n\nexport async function uninstallUserService(options: {\n readonly platform: NodeJS.Platform;\n readonly executor: CommandExecutor;\n readonly home?: string;\n readonly uid?: number;\n}): Promise<void> {\n const home = options.home ?? homedir();\n if (options.platform === \"linux\") {\n const path = join(home, \".config\", \"systemd\", \"user\", \"pi-fleet.service\");\n await options.executor.run(\"systemctl\", [\"--user\", \"disable\", \"--now\", \"pi-fleet.service\"]);\n await rm(path, { force: true });\n await options.executor.run(\"systemctl\", [\"--user\", \"daemon-reload\"]);\n return;\n }\n if (options.platform === \"darwin\") {\n const path = join(home, \"Library\", \"LaunchAgents\", \"works.elpapi.pifleet.plist\");\n const domain = `gui/${options.uid ?? process.getuid?.() ?? 0}`;\n await options.executor.run(\"launchctl\", [\"bootout\", domain, path]).catch(() => undefined);\n await rm(path, { force: true });\n return;\n }\n throw new Error(`Native Pi Fleet supervision is unsupported on ${options.platform}`);\n}\n\nexport async function serviceDefinitionNeedsRepair(\n path: string,\n expectedContents: string,\n definition: ServiceDefinitionOptions,\n): Promise<boolean> {\n const current = await readFile(path, \"utf8\").catch((error: NodeJS.ErrnoException) => {\n if (error.code === \"ENOENT\") return null;\n throw error;\n });\n if (current !== expectedContents) return true;\n try {\n await access(definition.nodePath, constants.X_OK);\n await access(definition.runtimePath, constants.R_OK);\n return false;\n } catch {\n return true;\n }\n}\n\nasync function preserveInstalledStateRoot(\n path: string,\n definition: ServiceDefinitionOptions,\n platform: \"linux\" | \"darwin\",\n): Promise<ServiceDefinitionOptions> {\n if (definition.stateRoot !== undefined) return definition;\n const current = await readFile(path, \"utf8\").catch((error: NodeJS.ErrnoException) => {\n if (error.code === \"ENOENT\") return null;\n throw error;\n });\n if (current === null) return definition;\n const encoded =\n platform === \"linux\"\n ? /^Environment=PIFLEET_STATE_ROOT=(.+)$/m.exec(current)?.[1]\n : /<key>PIFLEET_STATE_ROOT<\\/key><string>([^<]+)<\\/string>/.exec(current)?.[1];\n if (encoded === undefined) return definition;\n const stateRoot =\n platform === \"linux\"\n ? encoded\n : encoded\n .replaceAll(\"'\", \"'\")\n .replaceAll(\""\", '\"')\n .replaceAll(\">\", \">\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\"&\", \"&\");\n return { ...definition, stateRoot };\n}\n\nasync function atomicWrite(path: string, contents: string): Promise<void> {\n await mkdir(dirname(path), { recursive: true, mode: 0o700 });\n const temporary = `${path}.tmp-${process.pid}`;\n await writeFile(temporary, contents, { mode: 0o600 });\n await chmod(temporary, 0o600);\n await rename(temporary, path);\n}\n", "import { isAbsolute } from \"node:path\";\n\nexport interface ServiceDefinitionOptions {\n readonly nodePath: string;\n readonly runtimePath: string;\n readonly stateRoot?: string;\n}\n\nexport function systemdUserUnit(options: ServiceDefinitionOptions): string {\n validate(options);\n const environment =\n options.stateRoot === undefined\n ? \"\"\n : `Environment=PIFLEET_STATE_ROOT=${systemdEscape(options.stateRoot)}\\n`;\n return `[Unit]\nDescription=Pi Fleet user runtime\nAfter=default.target\n\n[Service]\nType=simple\nExecStart=${systemdEscape(options.nodePath)} ${systemdEscape(options.runtimePath)}\n${environment}Restart=on-failure\nRestartSec=1\nTimeoutStopSec=10\nUMask=0077\nKillMode=control-group\n\n[Install]\nWantedBy=default.target\n`;\n}\n\nexport function launchdAgentPlist(options: ServiceDefinitionOptions): string {\n validate(options);\n const environment =\n options.stateRoot === undefined\n ? \"\"\n : ` <key>EnvironmentVariables</key>\n <dict><key>PIFLEET_STATE_ROOT</key><string>${xmlEscape(options.stateRoot)}</string></dict>\n`;\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key><string>works.elpapi.pifleet</string>\n <key>ProgramArguments</key>\n <array>\n <string>${xmlEscape(options.nodePath)}</string>\n <string>${xmlEscape(options.runtimePath)}</string>\n </array>\n${environment} <key>RunAtLoad</key><true/>\n <key>KeepAlive</key><dict><key>SuccessfulExit</key><false/></dict>\n <key>ProcessType</key><string>Background</string>\n</dict>\n</plist>\n`;\n}\n\nfunction validate(options: ServiceDefinitionOptions): void {\n if (!isAbsolute(options.nodePath) || !isAbsolute(options.runtimePath)) {\n throw new Error(\"Service executables must use absolute paths\");\n }\n}\n\nfunction systemdEscape(value: string): string {\n if (!/^[A-Za-z0-9_./:@-]+$/.test(value)) throw new Error(`Unsafe systemd path ${value}`);\n return value;\n}\n\nfunction xmlEscape(value: string): string {\n return value\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\")\n .replaceAll(\"'\", \"'\");\n}\n", "import { createHash, randomUUID } from \"node:crypto\";\nimport { chmod, cp, lstat, mkdir, readFile, rename, rm } from \"node:fs/promises\";\nimport { join, posix, resolve, sep } from \"node:path\";\n\nimport { hashDirectoryTree, type TreeIntegrity } from \"./tree-integrity.js\";\n\ninterface RuntimeManifestFile {\n readonly path: string;\n readonly bytes: number;\n readonly sha256: string;\n}\n\ninterface RuntimeManifest {\n readonly schemaVersion: 2;\n readonly package: { readonly name: string; readonly version: string };\n readonly files: readonly RuntimeManifestFile[];\n readonly trees: readonly TreeIntegrity[];\n}\n\nconst requiredRuntimeArtifacts = new Set([\n \"package.json\",\n \"bin/pifleet.mjs\",\n \"bin/pifleet-runtime.mjs\",\n \"dist/cli.mjs\",\n \"dist/runtime.mjs\",\n \"dist/sqlite-worker.mjs\",\n]);\n\nexport async function materializeRuntime(options: {\n readonly sourceRoot: string;\n readonly applicationRoot: string;\n}): Promise<string> {\n const sourceRoot = resolve(options.sourceRoot);\n const manifestBytes = await readFile(join(sourceRoot, \"dist\", \"runtime-manifest.json\"));\n const manifest = await parseRuntimeManifest(manifestBytes, sourceRoot);\n await verifyRuntime(sourceRoot, manifest);\n\n const applicationRoot = resolve(options.applicationRoot);\n await ensurePrivateDirectory(applicationRoot);\n const manifestHash = createHash(\"sha256\").update(manifestBytes).digest(\"hex\").slice(0, 16);\n const releasesRoot = join(applicationRoot, \"releases\");\n await ensurePrivateDirectory(releasesRoot);\n const destination = join(releasesRoot, `${manifest.package.version}-${manifestHash}`);\n\n if (await pathExists(destination)) {\n await verifyRuntime(destination, manifest);\n return destination;\n }\n\n const staging = join(releasesRoot, `.staging-${randomUUID()}`);\n await mkdir(staging, { mode: 0o700 });\n try {\n await cp(join(sourceRoot, \"dist\"), join(staging, \"dist\"), {\n recursive: true,\n dereference: true,\n });\n await cp(join(sourceRoot, \"bin\"), join(staging, \"bin\"), { recursive: true, dereference: true });\n await cp(join(sourceRoot, \"package.json\"), join(staging, \"package.json\"));\n for (const tree of manifest.trees) {\n const source = resolveInside(sourceRoot, tree.path);\n const destination = resolveInside(staging, tree.path);\n await mkdir(resolve(destination, \"..\"), { recursive: true, mode: 0o700 });\n await cp(source, destination, { recursive: true, dereference: true });\n }\n await verifyRuntime(staging, manifest);\n await chmod(staging, 0o700);\n try {\n await rename(staging, destination);\n } catch (error: unknown) {\n if (!isDestinationRace(error) || !(await pathExists(destination))) throw error;\n await verifyRuntime(destination, manifest);\n }\n return destination;\n } finally {\n await rm(staging, { recursive: true, force: true });\n }\n}\n\nexport async function verifyRuntime(root: string, manifest?: RuntimeManifest): Promise<void> {\n const resolvedRoot = resolve(root);\n const expected =\n manifest ??\n (await parseRuntimeManifest(\n await readFile(join(resolvedRoot, \"dist\", \"runtime-manifest.json\")),\n resolvedRoot,\n ));\n if (manifest !== undefined) await validateRuntimeManifest(manifest, resolvedRoot);\n\n for (const file of expected.files) {\n const path = resolveInside(resolvedRoot, file.path);\n const info = await lstat(path);\n if (info.isSymbolicLink()) {\n throw new Error(`Runtime artifact ${file.path} must not be a symbolic link`);\n }\n if (!info.isFile() || info.size !== file.bytes) {\n throw new Error(`Runtime artifact ${file.path} has changed`);\n }\n const hash = createHash(\"sha256\")\n .update(await readFile(path))\n .digest(\"hex\");\n if (hash !== file.sha256) {\n throw new Error(`Runtime artifact ${file.path} failed verification`);\n }\n }\n for (const expectedTree of expected.trees) {\n const treeRoot = resolveInside(resolvedRoot, expectedTree.path);\n const actualTree = await hashDirectoryTree(treeRoot, expectedTree.path);\n if (\n actualTree.files !== expectedTree.files ||\n actualTree.bytes !== expectedTree.bytes ||\n actualTree.sha256 !== expectedTree.sha256\n ) {\n throw new Error(`Runtime dependency tree ${expectedTree.path} failed verification`);\n }\n }\n}\n\nasync function parseRuntimeManifest(bytes: Buffer, root: string): Promise<RuntimeManifest> {\n let candidate: unknown;\n try {\n candidate = JSON.parse(bytes.toString(\"utf8\"));\n } catch {\n throw new Error(\"Runtime manifest is not valid JSON\");\n }\n await validateRuntimeManifest(candidate, root);\n return candidate as RuntimeManifest;\n}\n\nasync function validateRuntimeManifest(candidate: unknown, root: string): Promise<void> {\n if (!isRecord(candidate) || candidate.schemaVersion !== 2) {\n throw new Error(\"Runtime manifest has an unsupported schema version\");\n }\n if (\n !isRecord(candidate.package) ||\n typeof candidate.package.name !== \"string\" ||\n typeof candidate.package.version !== \"string\"\n ) {\n throw new Error(\"Runtime manifest has an invalid package identity\");\n }\n const packageIdentity = await readPackageIdentity(root);\n if (\n candidate.package.name !== packageIdentity.name ||\n candidate.package.version !== packageIdentity.version\n ) {\n throw new Error(\"Runtime manifest package identity does not match package.json\");\n }\n if (!Array.isArray(candidate.files) || !Array.isArray(candidate.trees)) {\n throw new Error(\"Runtime manifest has invalid artifact lists\");\n }\n\n const filePaths = new Set<string>();\n for (const file of candidate.files) {\n if (\n !isRecord(file) ||\n !isManifestPath(file.path) ||\n !isValidSize(file.bytes) ||\n !isSha256(file.sha256)\n ) {\n throw new Error(\"Runtime manifest contains an invalid artifact\");\n }\n if (filePaths.has(file.path))\n throw new Error(`Runtime manifest has duplicate path ${file.path}`);\n filePaths.add(file.path);\n }\n for (const required of requiredRuntimeArtifacts) {\n if (!filePaths.has(required)) {\n throw new Error(`Runtime manifest is missing required artifact ${required}`);\n }\n }\n\n const treePaths = new Set<string>();\n for (const tree of candidate.trees) {\n if (\n !isRecord(tree) ||\n !isManifestPath(tree.path) ||\n !isValidSize(tree.files) ||\n !isValidSize(tree.bytes) ||\n !isSha256(tree.sha256)\n ) {\n throw new Error(\"Runtime manifest contains an invalid dependency tree\");\n }\n if (treePaths.has(tree.path))\n throw new Error(`Runtime manifest has duplicate path ${tree.path}`);\n treePaths.add(tree.path);\n }\n const allPaths = [...filePaths, ...treePaths];\n for (let index = 0; index < allPaths.length; index += 1) {\n for (let other = index + 1; other < allPaths.length; other += 1) {\n const left = allPaths[index]!;\n const right = allPaths[other]!;\n if (left === right || left.startsWith(`${right}/`) || right.startsWith(`${left}/`)) {\n throw new Error(`Runtime manifest has overlapping paths ${left} and ${right}`);\n }\n }\n }\n}\n\nasync function readPackageIdentity(root: string): Promise<{ name: string; version: string }> {\n let candidate: unknown;\n try {\n candidate = JSON.parse(await readFile(join(root, \"package.json\"), \"utf8\"));\n } catch {\n throw new Error(\"Runtime package.json is not valid JSON\");\n }\n if (\n !isRecord(candidate) ||\n typeof candidate.name !== \"string\" ||\n typeof candidate.version !== \"string\"\n ) {\n throw new Error(\"Runtime package.json has an invalid identity\");\n }\n return { name: candidate.name, version: candidate.version };\n}\n\nfunction resolveInside(root: string, path: string): string {\n if (!isManifestPath(path)) throw new Error(`Runtime manifest contains an unsafe path ${path}`);\n const resolved = resolve(root, path);\n if (!resolved.startsWith(`${root}${sep}`)) {\n throw new Error(`Runtime manifest contains an unsafe path ${path}`);\n }\n return resolved;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction isManifestPath(value: unknown): value is string {\n return (\n typeof value === \"string\" &&\n value.length > 0 &&\n !value.includes(\"\\\\\") &&\n !value.startsWith(\"/\") &&\n posix.normalize(value) === value &&\n value.split(\"/\").every((part) => part.length > 0 && part !== \".\" && part !== \"..\")\n );\n}\n\nfunction isValidSize(value: unknown): value is number {\n return typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0;\n}\n\nfunction isSha256(value: unknown): value is string {\n return typeof value === \"string\" && /^[a-f0-9]{64}$/.test(value);\n}\n\nfunction isDestinationRace(error: unknown): boolean {\n const code = (error as NodeJS.ErrnoException).code;\n return code === \"EEXIST\" || code === \"ENOTEMPTY\";\n}\n\nasync function ensurePrivateDirectory(path: string): Promise<void> {\n await mkdir(path, { recursive: true, mode: 0o700 });\n const info = await lstat(path);\n if (!info.isDirectory() || info.isSymbolicLink()) {\n throw new Error(`Refusing unsafe runtime release path ${path}`);\n }\n if (typeof process.getuid === \"function\" && info.uid !== process.getuid()) {\n throw new Error(`Runtime release path ${path} is not owned by the current user`);\n }\n await chmod(path, 0o700);\n}\n\nasync function pathExists(path: string): Promise<boolean> {\n try {\n await lstat(path);\n return true;\n } catch (error: unknown) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n throw error;\n }\n}\n", "import { createHash } from \"node:crypto\";\nimport { lstat, readFile, readdir, stat } from \"node:fs/promises\";\nimport { join, relative, resolve, sep } from \"node:path\";\n\nexport interface TreeIntegrity {\n readonly path: string;\n readonly files: number;\n readonly bytes: number;\n readonly sha256: string;\n}\n\nexport async function hashDirectoryTree(\n root: string,\n manifestPath: string,\n): Promise<TreeIntegrity> {\n const resolvedRoot = resolve(root);\n const entries = await collectFiles(resolvedRoot, resolvedRoot);\n const hash = createHash(\"sha256\");\n let bytes = 0;\n for (const entry of entries) {\n const contents = await readFile(entry.absolutePath);\n bytes += contents.length;\n hash.update(entry.relativePath);\n hash.update(\"\\0\");\n hash.update(String(contents.length));\n hash.update(\"\\0\");\n hash.update(contents);\n hash.update(\"\\0\");\n }\n return {\n path: manifestPath,\n files: entries.length,\n bytes,\n sha256: hash.digest(\"hex\"),\n };\n}\n\nasync function collectFiles(\n root: string,\n directory: string,\n): Promise<Array<{ readonly absolutePath: string; readonly relativePath: string }>> {\n const output: Array<{ absolutePath: string; relativePath: string }> = [];\n for (const name of (await readdir(directory)).sort()) {\n const absolutePath = join(directory, name);\n const linkInfo = await lstat(absolutePath);\n const info = linkInfo.isSymbolicLink() ? await stat(absolutePath) : linkInfo;\n if (info.isDirectory()) {\n if (linkInfo.isSymbolicLink()) {\n throw new Error(`Runtime dependency tree contains a directory symlink: ${absolutePath}`);\n }\n output.push(...(await collectFiles(root, absolutePath)));\n continue;\n }\n if (!info.isFile()) {\n throw new Error(`Runtime dependency tree contains an unsupported entry: ${absolutePath}`);\n }\n const relativePath = relative(root, absolutePath).split(sep).join(\"/\");\n if (relativePath.length === 0 || relativePath.startsWith(\"../\")) {\n throw new Error(`Runtime dependency path escapes its root: ${absolutePath}`);\n }\n output.push({ absolutePath, relativePath });\n }\n return output.sort((left, right) => left.relativePath.localeCompare(right.relativePath));\n}\n", "import { homedir, tmpdir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\n\nexport interface FleetPaths {\n readonly runtimeRoot: string;\n readonly stateRoot: string;\n readonly socketPath: string;\n readonly databasePath: string;\n}\n\nexport function resolveApplicationRoot(env: NodeJS.ProcessEnv = process.env): string {\n return (\n env.PIFLEET_APPLICATION_ROOT ??\n (process.platform === \"darwin\"\n ? join(homedir(), \"Library\", \"Application Support\", \"Pi Fleet\", \"runtime\")\n : join(env.XDG_DATA_HOME ?? join(homedir(), \".local\", \"share\"), \"pi-fleet\"))\n );\n}\n\nexport function resolveFleetPaths(env: NodeJS.ProcessEnv = process.env): FleetPaths {\n const explicitRoot = env.PIFLEET_STATE_ROOT;\n if (explicitRoot !== undefined) {\n const root = resolve(explicitRoot);\n return {\n runtimeRoot: root,\n stateRoot: root,\n socketPath: join(root, \"control.sock\"),\n databasePath: join(root, \"fleet.sqlite\"),\n };\n }\n\n const runtimeRoot = join(\n env.XDG_RUNTIME_DIR ?? tmpdir(),\n `pifleet-${process.getuid?.() ?? \"user\"}`,\n );\n const stateRoot =\n process.platform === \"darwin\"\n ? join(homedir(), \"Library\", \"Application Support\", \"Pi Fleet\")\n : join(env.XDG_STATE_HOME ?? join(homedir(), \".local\", \"state\"), \"pi-fleet\");\n return {\n runtimeRoot,\n stateRoot,\n socketPath: join(runtimeRoot, \"control.sock\"),\n databasePath: join(stateRoot, \"fleet.sqlite\"),\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["dirname", "join", "createHash", "chmod", "lstat", "mkdir", "readFile", "rename", "rm", "join", "resolve", "sep", "readFile", "join", "resolve", "readFile", "join", "createHash", "mkdir", "destination", "chmod", "rename", "rm", "lstat", "sep", "homedir", "join", "resolve", "dirname", "join"]
|
|
7
7
|
}
|
|
@@ -2,69 +2,69 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": {
|
|
4
4
|
"name": "@elpapi42/pi-fleet",
|
|
5
|
-
"version": "0.1.0-beta.
|
|
5
|
+
"version": "0.1.0-beta.2"
|
|
6
6
|
},
|
|
7
7
|
"managedPi": "@earendil-works/pi-coding-agent@0.80.10",
|
|
8
8
|
"files": [
|
|
9
9
|
{
|
|
10
10
|
"path": "dist/cli-meta.json",
|
|
11
11
|
"bytes": 21246,
|
|
12
|
-
"sha256": "
|
|
12
|
+
"sha256": "a8ff1d8172d10a74c0a2b3a1c01b814551f8a32d28154cb44859a4af1cb6d361"
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"path": "dist/cli.mjs",
|
|
16
|
-
"bytes":
|
|
17
|
-
"sha256": "
|
|
16
|
+
"bytes": 144920,
|
|
17
|
+
"sha256": "e1ac407f4123f3990bb22d6978307d7f8a70f05faf41399c755a21929dc5d9f5"
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
"path": "dist/cli.mjs.map",
|
|
21
|
-
"bytes":
|
|
22
|
-
"sha256": "
|
|
21
|
+
"bytes": 260315,
|
|
22
|
+
"sha256": "4d77fe125e07ce2d12b7b33ca60617860c57783363b882c2981f6926e244e945"
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
25
|
"path": "dist/installer-meta.json",
|
|
26
26
|
"bytes": 6625,
|
|
27
|
-
"sha256": "
|
|
27
|
+
"sha256": "c7570b9253ca9335bf5a074e2467eedac63ce5bef25296694f8faa50c381353d"
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
"path": "dist/installer.mjs",
|
|
31
|
-
"bytes":
|
|
32
|
-
"sha256": "
|
|
31
|
+
"bytes": 19836,
|
|
32
|
+
"sha256": "8cbd21b9134c025581e2ae61105e35687b4ff008faa3ac50b40ba8f1865794fd"
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
"path": "dist/installer.mjs.map",
|
|
36
|
-
"bytes":
|
|
37
|
-
"sha256": "
|
|
36
|
+
"bytes": 37234,
|
|
37
|
+
"sha256": "1253445c252391fe33f5bfebbc31f6cf6167a21ec24c50b2423f5f7108d44812"
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
40
|
"path": "dist/runtime-meta.json",
|
|
41
41
|
"bytes": 241009,
|
|
42
|
-
"sha256": "
|
|
42
|
+
"sha256": "ddefdd94b406d38ccac9293b83718dd4ef52c3a0e8b7122ec5720d443167cbfb"
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
"path": "dist/runtime.mjs",
|
|
46
|
-
"bytes":
|
|
47
|
-
"sha256": "
|
|
46
|
+
"bytes": 318107,
|
|
47
|
+
"sha256": "cbd2a3de2b5e12cc55d478ddf60ba367a2d21faa24e6a4a658c6128607cfd5f7"
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
50
|
"path": "dist/runtime.mjs.map",
|
|
51
|
-
"bytes":
|
|
52
|
-
"sha256": "
|
|
51
|
+
"bytes": 695723,
|
|
52
|
+
"sha256": "7ca452f3b15d7bd73de52c210591dbd8df14a6284902379306833dc6ad0b8010"
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
"path": "dist/sqlite-worker-meta.json",
|
|
56
|
-
"bytes":
|
|
57
|
-
"sha256": "
|
|
56
|
+
"bytes": 1846,
|
|
57
|
+
"sha256": "24f692498f5620279d8e2c1ca995175ba01b02b9af87fcec27aaebe2190f962e"
|
|
58
58
|
},
|
|
59
59
|
{
|
|
60
60
|
"path": "dist/sqlite-worker.mjs",
|
|
61
|
-
"bytes":
|
|
62
|
-
"sha256": "
|
|
61
|
+
"bytes": 12446,
|
|
62
|
+
"sha256": "56abddba47342e493e36905e86224c506cf90ec8568977c402b177db288050aa"
|
|
63
63
|
},
|
|
64
64
|
{
|
|
65
65
|
"path": "dist/sqlite-worker.mjs.map",
|
|
66
|
-
"bytes":
|
|
67
|
-
"sha256": "
|
|
66
|
+
"bytes": 21104,
|
|
67
|
+
"sha256": "d4f9cce1fe557178fa914ca8314d67dd1463efdb09a2acfd7143f879a8c13459"
|
|
68
68
|
},
|
|
69
69
|
{
|
|
70
70
|
"path": "bin/pifleet-runtime.mjs",
|
|
@@ -78,8 +78,8 @@
|
|
|
78
78
|
},
|
|
79
79
|
{
|
|
80
80
|
"path": "package.json",
|
|
81
|
-
"bytes":
|
|
82
|
-
"sha256": "
|
|
81
|
+
"bytes": 2375,
|
|
82
|
+
"sha256": "967198e3cf00529d57adbe818c27a800727f410552b17aa951e03666082b4c92"
|
|
83
83
|
}
|
|
84
84
|
],
|
|
85
85
|
"trees": [
|
package/dist/runtime-meta.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"format": "esm"
|
|
7
7
|
},
|
|
8
8
|
"src/pi/process.ts": {
|
|
9
|
-
"bytes":
|
|
9
|
+
"bytes": 8414,
|
|
10
10
|
"imports": [
|
|
11
11
|
{
|
|
12
12
|
"path": "node:crypto",
|
|
@@ -6177,7 +6177,7 @@
|
|
|
6177
6177
|
"format": "esm"
|
|
6178
6178
|
},
|
|
6179
6179
|
"src/runtime/control-server.ts": {
|
|
6180
|
-
"bytes":
|
|
6180
|
+
"bytes": 10823,
|
|
6181
6181
|
"imports": [
|
|
6182
6182
|
{
|
|
6183
6183
|
"path": "node:events",
|
|
@@ -6244,7 +6244,7 @@
|
|
|
6244
6244
|
"format": "esm"
|
|
6245
6245
|
},
|
|
6246
6246
|
"src/runtime/agent-coordinator.ts": {
|
|
6247
|
-
"bytes":
|
|
6247
|
+
"bytes": 7786,
|
|
6248
6248
|
"imports": [
|
|
6249
6249
|
{
|
|
6250
6250
|
"path": "src/platform/runtime/process-tree.ts",
|
|
@@ -6266,7 +6266,7 @@
|
|
|
6266
6266
|
"format": "esm"
|
|
6267
6267
|
},
|
|
6268
6268
|
"src/runtime/fleet-service.ts": {
|
|
6269
|
-
"bytes":
|
|
6269
|
+
"bytes": 34550,
|
|
6270
6270
|
"imports": [
|
|
6271
6271
|
{
|
|
6272
6272
|
"path": "node:crypto",
|
|
@@ -6312,7 +6312,7 @@
|
|
|
6312
6312
|
"format": "esm"
|
|
6313
6313
|
},
|
|
6314
6314
|
"src/store/worker-store.ts": {
|
|
6315
|
-
"bytes":
|
|
6315
|
+
"bytes": 4643,
|
|
6316
6316
|
"imports": [
|
|
6317
6317
|
{
|
|
6318
6318
|
"path": "node:crypto",
|
|
@@ -6379,7 +6379,7 @@
|
|
|
6379
6379
|
"imports": [],
|
|
6380
6380
|
"exports": [],
|
|
6381
6381
|
"inputs": {},
|
|
6382
|
-
"bytes":
|
|
6382
|
+
"bytes": 695723
|
|
6383
6383
|
},
|
|
6384
6384
|
"dist/runtime.mjs": {
|
|
6385
6385
|
"imports": [
|
|
@@ -6468,7 +6468,7 @@
|
|
|
6468
6468
|
"bytesInOutput": 1362
|
|
6469
6469
|
},
|
|
6470
6470
|
"src/pi/process.ts": {
|
|
6471
|
-
"bytesInOutput":
|
|
6471
|
+
"bytesInOutput": 6698
|
|
6472
6472
|
},
|
|
6473
6473
|
"src/platform/runtime/process-tree.ts": {
|
|
6474
6474
|
"bytesInOutput": 993
|
|
@@ -6483,7 +6483,7 @@
|
|
|
6483
6483
|
"bytesInOutput": 878
|
|
6484
6484
|
},
|
|
6485
6485
|
"src/runtime/control-server.ts": {
|
|
6486
|
-
"bytesInOutput":
|
|
6486
|
+
"bytesInOutput": 8998
|
|
6487
6487
|
},
|
|
6488
6488
|
"node_modules/@sinclair/typebox/build/esm/value/guard/guard.mjs": {
|
|
6489
6489
|
"bytesInOutput": 1876
|
|
@@ -6939,7 +6939,7 @@
|
|
|
6939
6939
|
"bytesInOutput": 108
|
|
6940
6940
|
},
|
|
6941
6941
|
"src/runtime/fleet-service.ts": {
|
|
6942
|
-
"bytesInOutput":
|
|
6942
|
+
"bytesInOutput": 29674
|
|
6943
6943
|
},
|
|
6944
6944
|
"src/pi/session-selector.ts": {
|
|
6945
6945
|
"bytesInOutput": 2113
|
|
@@ -6948,16 +6948,16 @@
|
|
|
6948
6948
|
"bytesInOutput": 2665
|
|
6949
6949
|
},
|
|
6950
6950
|
"src/runtime/agent-coordinator.ts": {
|
|
6951
|
-
"bytesInOutput":
|
|
6951
|
+
"bytesInOutput": 6762
|
|
6952
6952
|
},
|
|
6953
6953
|
"src/runtime/session-tail-subscription.ts": {
|
|
6954
6954
|
"bytesInOutput": 4844
|
|
6955
6955
|
},
|
|
6956
6956
|
"src/store/worker-store.ts": {
|
|
6957
|
-
"bytesInOutput":
|
|
6957
|
+
"bytesInOutput": 3543
|
|
6958
6958
|
}
|
|
6959
6959
|
},
|
|
6960
|
-
"bytes":
|
|
6960
|
+
"bytes": 318107
|
|
6961
6961
|
}
|
|
6962
6962
|
}
|
|
6963
6963
|
}
|