openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
54 lines (53 loc) • 2.98 kB
JavaScript
import fs from "node:fs";
import path from "node:path";
import { createHash } from "node:crypto";
//#region src/infra/package-update-activation-paths.ts
const PACKAGE_ACTIVATION_PREFIX = ".openclaw.package-activation-";
function resolvePackageActivationAnchor(installKey) {
const key = createHash("sha256").update(installKey).digest("hex").slice(0, 24);
return path.join(path.dirname(installKey), `${PACKAGE_ACTIVATION_PREFIX}${key}`);
}
function isPackageActivationControlName(name) {
return name.startsWith(PACKAGE_ACTIVATION_PREFIX) && /^[a-f0-9]{24}\.control$/u.test(name.slice(29));
}
function resolvePackageActivationControl(anchor) {
return `${anchor}.control`;
}
function resolvePackageActivationJournalPath(anchor) {
return path.join(resolvePackageActivationControl(anchor), "operation.sqlite");
}
function resolvePackageActivationHelper(anchor) {
return path.join(resolvePackageActivationControl(anchor), "recovery.mjs");
}
function packageActivationIdentity(file, directory) {
const stat = fs.lstatSync(file, { bigint: true });
if (stat.ino === 0n || !(directory === "launcher" ? stat.isSymbolicLink() || stat.isFile() : directory ? stat.isDirectory() && !stat.isSymbolicLink() : stat.isFile()) || process.getuid && stat.uid !== BigInt(process.getuid())) throw new Error("Package publication object has an unsafe identity");
return `${stat.dev}:${stat.ino}`;
}
function privatePackageActivationIdentity(file, directory) {
const value = packageActivationIdentity(file, directory);
const stat = fs.lstatSync(file);
if ((stat.mode & 63) !== 0 || !directory && stat.nlink !== 1) throw new Error("Package publication recovery permissions are unsafe");
return value;
}
function assertPackageActivationLayout(anchor) {
if ([
path.join(anchor, "operation.sqlite"),
`${anchor}.sqlite`,
`${anchor}.recovery.mjs`
].some((file) => fs.lstatSync(file, { throwIfNoEntry: false }))) throw new Error("Legacy package activation artifacts require their original recovery owner; no migration is performed.");
}
/** A receipt is a read-only completion fact, never a grant for another effect. */
function isPackageActivationComplete(anchor, record) {
if (record.phase !== "anchor-retired" || record.intent?.kind !== "unlink-helper") return false;
if (record.intent.identity !== record.descriptor.helperIdentity) throw new Error("Final helper unlink identity is invalid.");
for (const file of [anchor, resolvePackageActivationHelper(anchor)]) try {
fs.lstatSync(file);
return false;
} catch (error) {
if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) throw error;
}
return true;
}
//#endregion
export { privatePackageActivationIdentity as a, resolvePackageActivationHelper as c, packageActivationIdentity as i, resolvePackageActivationJournalPath as l, isPackageActivationComplete as n, resolvePackageActivationAnchor as o, isPackageActivationControlName as r, resolvePackageActivationControl as s, assertPackageActivationLayout as t };