// File helpers: content hashing, relative-path normalization, reading bytes. const crypto = require("crypto"); const fs = require("fs"); // SHA-256 of the file's contents, returned as lowercase hex. const sha256File = async (absPath) => { return new Promise((resolve, reject) => { const hash = crypto.createHash("sha256"); const stream = fs.createReadStream(absPath); stream.on("data", (chunk) => hash.update(chunk)); stream.on("end", () => resolve(hash.digest("hex"))); stream.on("error", reject); }); }; const sha256Buffer = (buf) => { return crypto.createHash("sha256").update(buf).digest("hex"); }; // Convert Saltcorn's absolute file location to a tenant-relative serve path, // using File.absPathToServePath. The relative path is what we transport // between instances (each has a different file_store root). const toRelativePath = (File, absPath) => { if (!absPath) return ""; return File.absPathToServePath(absPath); }; // Convert a relative serve path back to the absolute path on this instance. const toAbsolutePath = (File, db, relPath) => { const path = require("path"); const tenant = db.getTenantSchema(); return path.join(db.connectObj.file_store, tenant, relPath); }; const readFileBytes = async (absPath) => { return await fs.promises.readFile(absPath); }; const writeFileBytes = async (absPath, buf) => { const path = require("path"); await fs.promises.mkdir(path.dirname(absPath), { recursive: true }); await fs.promises.writeFile(absPath, buf); }; module.exports = { sha256File, sha256Buffer, toRelativePath, toAbsolutePath, readFileBytes, writeFileBytes };