// Writes app/build-info.ts: a content hash of the app + assets (the cache/update version), // the git commit the build was made from, and the build time. import { createHash } from 'node:crypto' import { readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs' import { execSync } from 'node:child_process' import { join } from 'node:path' const files = [] const walk = (d) => { for (const f of readdirSync(d).sort()) { const p = join(d, f); statSync(p).isDirectory() ? walk(p) : files.push(p) } } walk('app'); walk('public') // Embed public/ files into app/assets.ts so the router serves them itself (no separate asset host). const types = { '.png': 'image/png', '.jpg': 'image/jpeg', '.svg': 'image/svg+xml' } const assets = {} for (const f of files) if (f.startsWith('public' + '/')) { const ext = f.slice(f.lastIndexOf('.')); if (types[ext]) assets[f.slice('public'.length)] = { type: types[ext], b64: readFileSync(f).toString('base64') } } writeFileSync('app/assets.ts', '// Generated by scripts/build-info.mjs from public/. Do not edit by hand.\nexport const ASSETS: Record = ' + JSON.stringify(assets) + '\n') const h = createHash('sha256') for (const f of files) if (f !== join('app', 'build-info.ts') && f !== join('app', 'assets.ts')) h.update(f).update(readFileSync(f)) const buildId = h.digest('hex').slice(0, 12) let sourceCommit = '' try { sourceCommit = execSync('git rev-parse HEAD', { stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim() } catch {} const builtAt = process.env.BUILD_TIME || new Date().toISOString() writeFileSync('app/build-info.ts', `// Generated by scripts/build-info.mjs. Do not edit by hand.\nexport const BUILD = ${JSON.stringify({ buildId, sourceCommit, builtAt }, null, '\t')} as const\n`) console.log('build', buildId, 'from', sourceCommit.slice(0, 7), 'at', builtAt)