/** * Prepares a local development Site so `npm run dev` has a working admin * without anyone hand-building a password hash. * * Development only: the file it writes is gitignored, holds a fixed well-known * password, and the dev server runs with SECURE_COOKIES=false over http. */ import { mkdir, readdir, readFile, writeFile } from 'node:fs/promises'; import { randomBytes } from 'node:crypto'; import path from 'node:path'; import { hashPassword } from '../src/auth.ts'; const DEV_PASSWORD = process.env['DEV_ADMIN_PASSWORD'] ?? 'menu-dev-password'; const root = path.resolve(process.env['MENU_ROOT'] ?? '.dev'); const envFile = path.join(root, 'site.env'); async function exists(target: string): Promise { try { await readFile(target); return true; } catch { return false; } } async function hasContent(dir: string): Promise { try { return (await readdir(dir)).length > 0; } catch { return false; } } if (await exists(envFile)) { console.log(`${envFile} already exists — using it (delete the file to reset the dev password)`); } else { await mkdir(root, { recursive: true }); const hash = await hashPassword(DEV_PASSWORD); const secret = randomBytes(32).toString('base64url'); await writeFile( envFile, [ '# Development only, created by scripts/dev-env.ts. Gitignored.', `ADMIN_PASSWORD_HASH=${hash}`, `SESSION_SECRET=${secret}`, '', ].join('\n'), { mode: 0o600 }, ); console.log(`wrote ${envFile}`); console.log(` admin password: ${DEV_PASSWORD} (override with DEV_ADMIN_PASSWORD=...)`); } if (!(await hasContent(path.join(root, 'data', 'published')))) { console.log('no published menus yet — run `npm run seed` for placeholder ones'); }