Files
2026-10-06 22:25:34 -04:00

52 lines
1.9 KiB
JavaScript

import { createHash } from "node:crypto";
import { mkdir, readFile, writeFile } from "node:fs/promises";
import path from "node:path";
import { ensureWithinProject } from "./native-water-build-utils.mjs";
const sha256 = (bytes) => createHash("sha256").update(bytes).digest("hex");
async function writeOrVerify(file, bytes, expectedHash) {
await mkdir(path.dirname(file), { recursive: true });
try {
await writeFile(file, bytes, { flag: "wx" });
} catch (error) {
if (error.code !== "EEXIST") throw error;
}
const persisted = await readFile(file);
const actualHash = sha256(persisted);
if (actualHash !== expectedHash || !persisted.equals(bytes)) {
throw new Error(`Refusing to replace non-identical native water audit-cache alias: ${file}`);
}
return { sha256: actualHash, bytes: persisted.length };
}
/** Write exact source and prepared-frame aliases for the environment-quality audit. */
export async function writeNativeWaterAuditCacheAliases({
projectRoot,
auditCacheRoot,
variantName,
ddsBytes,
pngBytes,
}) {
if (!auditCacheRoot) return null;
if (!/^[a-z\d][a-z\d_-]*$/i.test(variantName)) {
throw new Error(`Native water audit alias must be a safe texture basename: ${variantName}`);
}
ensureWithinProject(projectRoot, auditCacheRoot);
const root = path.resolve(auditCacheRoot);
const ddsHash = sha256(ddsBytes);
const pngHash = sha256(pngBytes);
const ddsFile = path.join(root, "raw", "textures", `${variantName}.dds`);
const pngFile = path.join(root, "prepared", "textures", `${variantName}.png`);
const [dds, png] = await Promise.all([
writeOrVerify(ddsFile, ddsBytes, ddsHash),
writeOrVerify(pngFile, pngBytes, pngHash),
]);
const relative = (file) => path.relative(projectRoot, file).replaceAll("\\", "/");
return {
textureBasename: variantName,
rawDds: { path: relative(ddsFile), ...dds },
preparedPng: { path: relative(pngFile), ...png },
};
}