Files
bitvid/scripts/hash-dist.mjs
T
google-labs-jules[bot]andPR0M3TH3AN 80f6aba4a8 feat: display version hash and build date in footer
Refactored scripts/hash-dist.mjs to export buildHashState and support module import.
Modified scripts/build-dist.mjs to calculate the dist hash after asset rewriting and inject it along with the current date into dist/index.html below the tagline.
Verified with Playwright screenshot.

Co-authored-by: PR0M3TH3AN <[email protected]>
2026-02-10 19:19:43 +00:00

119 lines
2.9 KiB
JavaScript

#!/usr/bin/env node
import fs from 'node:fs';
import path from 'node:path';
import crypto from 'node:crypto';
import { fileURLToPath } from 'node:url';
function parseArgs(argv) {
const args = {
distDir: 'dist',
output: null,
pretty: true
};
for (let i = 0; i < argv.length; i += 1) {
const arg = argv[i];
if (arg === '--dist') {
args.distDir = argv[i + 1] ?? args.distDir;
i += 1;
continue;
}
if (arg === '--output') {
args.output = argv[i + 1] ?? args.output;
i += 1;
continue;
}
if (arg === '--compact') {
args.pretty = false;
continue;
}
if (arg === '--help' || arg === '-h') {
console.log('Usage: node scripts/hash-dist.mjs [--dist <dir>] [--output <file>] [--compact]');
process.exit(0);
}
throw new Error(`Unknown argument: ${arg}`);
}
return args;
}
function toPosixRelative(baseDir, filePath) {
return path.relative(baseDir, filePath).split(path.sep).join('/');
}
function walkFiles(rootDir) {
const files = [];
const stack = [rootDir];
while (stack.length > 0) {
const currentDir = stack.pop();
const entries = fs.readdirSync(currentDir, { withFileTypes: true })
.sort((a, b) => a.name.localeCompare(b.name));
for (const entry of entries) {
const fullPath = path.join(currentDir, entry.name);
if (entry.isDirectory()) {
stack.push(fullPath);
continue;
}
if (entry.isFile()) {
files.push(fullPath);
}
}
}
return files.sort((a, b) => toPosixRelative(rootDir, a).localeCompare(toPosixRelative(rootDir, b)));
}
function hashBuffer(buffer) {
return crypto.createHash('sha256').update(buffer).digest('hex');
}
export function buildHashState(distDir) {
const resolvedDistDir = path.resolve(distDir);
if (!fs.existsSync(resolvedDistDir)) {
throw new Error(`Dist directory does not exist: ${resolvedDistDir}`);
}
const files = walkFiles(resolvedDistDir).map((filePath) => {
const contents = fs.readFileSync(filePath);
return {
path: toPosixRelative(resolvedDistDir, filePath),
sha256: hashBuffer(contents)
};
});
const combinedInput = files
.map((entry) => `${entry.path}:${entry.sha256}`)
.join('\n');
return {
combined: hashBuffer(Buffer.from(combinedInput, 'utf8')),
files
};
}
function main() {
const args = parseArgs(process.argv.slice(2));
const hashState = buildHashState(args.distDir);
const serialized = JSON.stringify(hashState, null, args.pretty ? 2 : 0);
if (args.output) {
const outputPath = path.resolve(args.output);
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
fs.writeFileSync(outputPath, `${serialized}\n`);
console.log(`Wrote hash state to ${outputPath}`);
return;
}
console.log(serialized);
}
if (process.argv[1] === fileURLToPath(import.meta.url)) {
main();
}