← Files ModRetro Chromatic PluginARCHIVED FILE
dist/recording-maintenance.js
20.6 KB · Oct 2, 2026 · 00:37 UTC
import { createHash, randomUUID } from "node:crypto";
import { closeSync, constants, fstatSync, lstatSync, mkdirSync, openSync, readdirSync, readSync, realpathSync, renameSync, unlinkSync, writeFileSync, } from "node:fs";
import { dirname, join, relative, resolve, sep } from "node:path";
import { recordingInventory } from "./recording-location.js";
import { readRecording } from "./recording-archive.js";
import { MAX_RECORDING_BYTES, MAX_SIBLING_RECORDINGS, MAX_SIBLING_RESERVED_BYTES, boundedInteger } from "./recording-common.js";
const POINTER = ".recording-archive.json";
const MAX_ENTRIES = 20_000;
const inside = (root, path) => path === root || path.startsWith(root + sep);
const absent = (path) => {
try {
lstatSync(path);
return false;
}
catch (error) {
if (error.code === "ENOENT")
return true;
throw error;
}
};
function same(a, b) {
return ["dev", "ino", "mode", "uid", "gid", "nlink", "size", "mtimeMs", "ctimeMs"].every(key => a[key] === b[key]);
}
function owned(entry) {
if ((process.getuid && entry.uid !== process.getuid()) || (entry.mode & 0o022) !== 0 || (entry.mode & 0o7000) !== 0) {
throw new Error("Recording maintenance requires owned paths without special or writable-by-others permission bits");
}
}
function file(path, maximum, expected) {
const before = lstatSync(path);
owned(before);
if (expected !== undefined && !same(expected, before))
throw new Error("Recording file changed before opening");
if (!before.isFile() || before.isSymbolicLink() || before.nlink !== 1 || before.size > maximum) {
throw new Error("Unsafe or oversized recording maintenance file");
}
const fd = openSync(path, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0));
try {
if (!same(before, fstatSync(fd)))
throw new Error("Recording file identity changed");
const buffer = Buffer.alloc(before.size + 1);
let size = 0;
let n;
while ((n = readSync(fd, buffer, size, buffer.length - size, null)) > 0) {
size += n;
if (size > before.size)
throw new Error("Recording file grew");
}
const bytes = buffer.subarray(0, size);
if (bytes.length !== before.size || !same(before, fstatSync(fd)) || !same(before, lstatSync(path))) {
throw new Error("Recording file changed during reading");
}
return bytes;
}
finally {
closeSync(fd);
}
}
function failureDetails(error) {
const value = error;
const code = typeof value?.code === "string" && /^E[A-Z0-9_]{1,40}$/.test(value.code) ? value.code : undefined;
const errno = Number.isSafeInteger(value?.errno) ? value.errno : undefined;
const category = code === "EEXIST" ? "already-exists"
: code === "EACCES" || code === "EPERM" ? "permission-denied"
: code === "ENOSPC" || code === "EDQUOT" ? "storage-capacity"
: code === "EROFS" ? "read-only-filesystem"
: code === "ENOENT" || code === "ENOTDIR" || code === "ELOOP" ? "path-error"
: code === undefined ? "unknown" : "filesystem-error";
return { category, ...(code === undefined ? {} : { code }), ...(errno === undefined ? {} : { errno }) };
}
export class RecordingAccessError extends Error {
failure;
constructor(cause) {
super("Recording access is live or unresolved; close its owning client before maintenance", { cause });
this.failure = { operation: "create-exclusive-lease", observedAt: new Date().toISOString(), ...failureDetails(cause) };
}
}
function identity(entry) {
return { dev: entry.dev, ino: entry.ino, uid: entry.uid, gid: entry.gid, mode: entry.mode,
nlink: entry.nlink, size: entry.size, mtimeMs: entry.mtimeMs, ctimeMs: entry.ctimeMs };
}
class AccessSnapshotError extends Error {
reason;
constructor(reason) {
super(reason);
this.reason = reason;
}
}
/** Filesystem-only maintenance. No ROM, interpreter, or native core is opened. */
export class RecordingMaintenance {
project;
#leased = false;
#incomplete = false;
#serviceInstanceId = randomUUID();
#createdAt = new Date().toISOString();
#lastAcquisitionFailure;
#savedLease;
constructor(project) { this.project = realpathSync(project); }
/** Observe only the fixed access metadata. Never acquires access, starts a worker, or reads a recording. */
accessDiagnostic() {
const common = {
schemaVersion: 1, observedAt: new Date().toISOString(), scope: "authorized-root-recording-access",
readOnly: true, processLiveness: "unobserved", recoveryAuthorized: false,
localService: { instanceId: this.#serviceInstanceId, createdAt: this.#createdAt, pid: process.pid,
leaseCapabilityRetained: this.#leased, maintenanceIncomplete: this.#incomplete,
...(this.#savedLease === undefined ? {} : { acquiredAt: this.#savedLease.acquiredAt }) },
acquisitionFailureHistory: this.#lastAcquisitionFailure === undefined
? { status: "unavailable-in-this-service" }
: { status: "recorded", failure: { ...this.#lastAcquisitionFailure } },
};
if (!process.getuid)
return { ...common, lease: { status: "unresolved", reason: "unsupported-platform" } };
const directories = [];
let stage = "authorized-root";
const verifyDirectories = () => {
for (const dir of directories) {
if (!same(dir.stat, lstatSync(dir.path)) || realpathSync(dir.path) !== dir.path)
throw new AccessSnapshotError("changed");
}
};
try {
for (const [label, path] of [
["authorized-root", this.project], ["artifacts", join(this.project, "artifacts")],
["access-directory", join(this.project, "artifacts", ".recording-access")],
]) {
stage = label;
let st;
try {
st = lstatSync(path);
}
catch (error) {
if (error.code !== "ENOENT" || label === "authorized-root")
throw error;
verifyDirectories();
return { ...common, lease: { status: "absent-observed", missing: label } };
}
if (!st.isDirectory() || st.isSymbolicLink() || realpathSync(path) !== path
|| st.uid !== process.getuid() || (st.mode & 0o7022) !== 0)
throw new AccessSnapshotError("unsafe-path");
directories.push({ path, stat: st });
}
stage = "lease-file";
const path = join(this.project, "artifacts", ".recording-access", "lease.json");
let st;
try {
st = lstatSync(path);
}
catch (error) {
if (error.code !== "ENOENT")
throw error;
verifyDirectories();
return { ...common, lease: { status: "absent-observed", missing: "lease-file" } };
}
if (!st.isFile() || st.isSymbolicLink() || st.nlink !== 1 || st.uid !== process.getuid()
|| (st.mode & 0o7777) !== 0o600 || st.size > 4096 || realpathSync(path) !== path)
throw new AccessSnapshotError("unsafe-file");
const raw = file(path, 4096, st);
if (!same(st, lstatSync(path)))
throw new AccessSnapshotError("changed");
stage = "lease-schema";
let parsed;
try {
parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(raw));
}
catch {
throw new AccessSnapshotError("invalid-record");
}
const record = parsed;
if (record === null || typeof record !== "object" || Array.isArray(record)
|| Object.keys(record).sort().join(",") !== "pid,schemaVersion,token" || record.schemaVersion !== 1
|| !Number.isSafeInteger(record.pid) || record.pid <= 0
|| typeof record.token !== "string" || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(record.token)) {
throw new AccessSnapshotError("invalid-record");
}
const sha256 = createHash("sha256").update(raw).digest("hex");
verifyDirectories();
if (!same(st, lstatSync(path)))
throw new AccessSnapshotError("changed");
const matchesSavedLease = this.#leased && this.#savedLease !== undefined
&& same(st, this.#savedLease.identity) && sha256 === this.#savedLease.sha256;
return { ...common, lease: { status: "present-unverified", sha256, identity: identity(st),
ownerPidClaim: record.pid, ownerProcessStart: "unrecorded", ownerReachability: "unknown",
relation: matchesSavedLease ? "matches-this-services-saved-lease" : "not-established" } };
}
catch (error) {
return { ...common, lease: { status: "unresolved", stage,
reason: error instanceof AccessSnapshotError ? error.reason : "observation-failed", ...failureDetails(error) } };
}
}
resolvePath = (value, { existing }) => {
if (typeof value !== "string")
throw new Error("A recording path is required");
const path = resolve(this.project, value);
if (!inside(this.project, path))
throw new Error("Recording path is outside the authorized project");
let part = this.project;
for (const segment of relative(this.project, path).split(sep).filter(Boolean)) {
part = join(part, segment);
if (absent(part)) {
if (existing)
throw new Error("Recording path is missing");
continue;
}
const st = lstatSync(part);
owned(st);
if (st.isSymbolicLink() || realpathSync(part) !== part)
throw new Error("Recording path is redirected");
}
return path;
};
#directory(path) {
this.resolvePath(path, { existing: true });
if (!lstatSync(path).isDirectory())
throw new Error("Expected a recording directory");
}
#protectedDirectory(path) {
this.resolvePath(path, { existing: false });
if (absent(path))
mkdirSync(path, { mode: 0o700 });
this.#directory(path);
for (const marker of [".gitignore", ".npmignore"]) {
const name = join(path, marker);
if (absent(name))
writeFileSync(name, "*\n", { flag: "wx", mode: 0o600 });
if (!file(name, 2).equals(Buffer.from("*\n")))
throw new Error("Recording package-protection marker differs");
}
}
/** Advisory across supported clients. Stale/unresolved leases are never stolen. */
acquire() {
if (!process.getuid)
throw new Error("Recording maintenance requires supported POSIX ownership checks");
const artifacts = join(this.project, "artifacts");
this.resolvePath(artifacts, { existing: false });
if (absent(artifacts))
mkdirSync(artifacts, { mode: 0o700 });
this.#directory(artifacts);
const root = join(artifacts, ".recording-access");
this.#protectedDirectory(root);
const path = join(root, "lease.json");
const bytes = Buffer.from(JSON.stringify({ schemaVersion: 1, pid: process.pid, token: randomUUID() }) + "\n");
try {
writeFileSync(path, bytes, { flag: "wx", mode: 0o600 });
}
catch (error) {
const failure = new RecordingAccessError(error);
this.#lastAcquisitionFailure = failure.failure;
throw failure;
}
const identity = lstatSync(path);
this.#leased = true;
this.#savedLease = { identity, sha256: createHash("sha256").update(bytes).digest("hex"), acquiredAt: new Date().toISOString() };
return () => {
if (this.#incomplete)
throw new Error("Recording maintenance is incomplete; access lease retained for reconciliation");
if (!same(identity, lstatSync(path)) || !file(path, 4096).equals(bytes))
throw new Error("Recording access lease changed; closure is unresolved");
unlinkSync(path);
this.#leased = false;
this.#savedLease = undefined;
};
}
#snapshot(root) {
return recordingInventory(root, this.resolvePath);
}
#closed(root) {
const record = readRecording(root, this.resolvePath);
if (!["stopped", "cancelled", "failed"].includes(record.status) || !record.sourcePins.finalized || record.truncatedTail) {
throw new Error("Only a finalized recording with complete integrity is eligible; live or unresolved recordings cannot be archived");
}
return record;
}
#archiveRoot() { return join(this.project, "artifacts", "recording-archives"); }
#mapping(original) {
this.#directory(original);
const raw = file(join(original, POINTER), 4096);
const value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(raw));
if (value.schemaVersion !== 1 || value.originalPath !== original || typeof value.archivePath !== "string"
|| !/^[0-9a-f]{32}$/.test(value.sessionId) || !/^[0-9a-f]{64}$/.test(value.manifestSha256)
|| !inside(this.#archiveRoot(), value.archivePath) || dirname(dirname(value.archivePath)) !== this.#archiveRoot()
|| !/^[0-9a-f-]{36}$/.test(relative(this.#archiveRoot(), dirname(value.archivePath)))
|| value.archivePath !== join(dirname(value.archivePath), "recording"))
throw new Error("Invalid recording archive mapping");
if (JSON.stringify(readdirSync(original).sort()) !== JSON.stringify([".gitignore", ".npmignore", POINTER].sort()))
throw new Error("Archive reference directory has unexpected content");
for (const marker of [".gitignore", ".npmignore"])
if (!file(join(original, marker), 2).equals(Buffer.from("*\n")))
throw new Error("Archive reference marker differs");
if (!file(join(dirname(value.archivePath), "mapping.json"), 4096).equals(raw))
throw new Error("Archive mapping copies differ");
const current = this.#snapshot(value.archivePath);
if (JSON.stringify(current) !== JSON.stringify(value.inventory))
throw new Error("Archived recording bytes or modes changed");
const record = this.#closed(value.archivePath);
if (record.sessionId !== value.sessionId || record.sourcePins.manifest.sha256 !== value.manifestSha256)
throw new Error("Archived recording provenance changed");
return { raw, value };
}
retrieve(recordingPath) {
const original = this.resolvePath(recordingPath, { existing: true });
const { value } = this.#mapping(original);
return { ...value, status: "archived", reservationReleasedFrom: dirname(original), bytesReclaimed: 0 };
}
resolveRecording(recordingPath) {
const original = this.resolvePath(recordingPath, { existing: true });
if (this.isArchived(original)) {
const mapping = JSON.parse(file(join(dirname(original), "mapping.json"), 4096).toString("utf8"));
const verified = this.retrieve(mapping.originalPath);
if (verified.archivePath !== original)
throw new Error("Archive recording path differs");
return original;
}
return absent(join(original, POINTER)) ? original : this.retrieve(original).archivePath;
}
isArchived(path) { return inside(this.#archiveRoot(), path); }
archive(recordingPath) {
if (!this.#leased)
throw new Error("Recording maintenance requires exclusive access");
const original = this.resolvePath(recordingPath, { existing: true });
if (this.isArchived(original) || !absent(join(original, POINTER)) || original === this.project
|| inside(original, this.#archiveRoot()))
throw new Error("Recording archive source is not eligible");
const record = this.#closed(original);
const inventory = this.#snapshot(original);
const archiveRoot = this.#archiveRoot();
this.#protectedDirectory(archiveRoot);
if (lstatSync(original).dev !== lstatSync(archiveRoot).dev)
throw new Error("Archive must remain on the same filesystem");
const container = join(archiveRoot, randomUUID());
mkdirSync(container, { mode: 0o700 });
this.#protectedDirectory(container);
const archivePath = join(container, "recording");
const value = { schemaVersion: 1, originalPath: original, archivePath, sessionId: record.sessionId,
manifestSha256: record.sourcePins.manifest.sha256, inventory };
const raw = Buffer.from(JSON.stringify(value) + "\n");
writeFileSync(join(container, "mapping.json"), raw, { flag: "wx", mode: 0o600 });
if (JSON.stringify(this.#snapshot(original)) !== JSON.stringify(inventory) || !absent(archivePath))
throw new Error("Recording changed before archive");
this.#incomplete = true;
renameSync(original, archivePath);
// The original bytes remain intact even if subsequent publication fails.
// A partial operation is reported, never silently overwritten or replayed.
try {
mkdirSync(original, { mode: 0o700 });
this.#protectedDirectory(original);
writeFileSync(join(original, POINTER), raw, { flag: "wx", mode: 0o600 });
const result = this.retrieve(original);
this.#incomplete = false;
return result;
}
catch (error) {
throw new Error(`Archive publication incomplete; recording retained at ${archivePath}; original reference ${original} requires reconciliation`, { cause: error });
}
}
restore(recordingPath) {
if (!this.#leased)
throw new Error("Recording maintenance requires exclusive access");
const original = this.resolvePath(recordingPath, { existing: true });
const { value, raw } = this.#mapping(original);
const restored = this.#closed(value.archivePath);
let siblings = 0;
let reserved = 0;
const neighbors = readdirSync(dirname(original));
if (neighbors.length > MAX_ENTRIES)
throw new Error("Recording neighbor inventory exceeds its limit");
for (const name of neighbors) {
const sibling = join(dirname(original), name);
const st = lstatSync(sibling);
if (!st.isDirectory() || st.isSymbolicLink() || absent(join(sibling, "recording.json")))
continue;
const record = JSON.parse(file(join(sibling, "recording.json"), 1024 * 1024).toString("utf8"));
if (!record || typeof record !== "object" || Array.isArray(record))
throw new Error("Invalid neighboring recording quota metadata");
if (record.kind !== "gb-studio-playtest")
continue;
siblings++;
reserved += boundedInteger(record.limits?.maxBytes, "recording reservation", 64 * 1024, MAX_RECORDING_BYTES);
}
if (siblings >= MAX_SIBLING_RECORDINGS || reserved + restored.limits.maxBytes > MAX_SIBLING_RESERVED_BYTES) {
throw new Error("Restoring this recording would exceed retained recording quota");
}
// Move the exact reference directory out of the way, retaining it for
// recovery. Never rename over an existing destination, even an empty one.
const parked = join(dirname(value.archivePath), "original-reference");
if (!absent(parked))
throw new Error("Recording restoration is already pending");
if (!file(join(original, POINTER), 4096).equals(raw))
throw new Error("Archive reference changed");
this.#incomplete = true;
renameSync(original, parked);
if (!absent(original))
throw new Error("Original recording destination was replaced");
renameSync(value.archivePath, original);
if (JSON.stringify(this.#snapshot(original)) !== JSON.stringify(value.inventory))
throw new Error("Restored recording integrity differs");
this.#closed(original);
this.#incomplete = false;
return { ...value, status: "restored", recordingPath: original, reservationReleasedFrom: null, bytesReclaimed: 0 };
}
}
//# sourceMappingURL=recording-maintenance.js.mapSHA-256: b291c870bbfd1cecb64cf355dba49b5b3e66d31703cae72a6cf34b5c6612fa71