verify reports integrity problems and repair rebuilds derivatives from the Originals, which is what makes the file layout trustworthy without a database. The image runs TypeScript on Node 24 with no build step, writes only under MENU_ROOT, and the provision script writes the untracked site.env using the image's own hasher so the server needs no Node.
34 lines
944 B
TypeScript
34 lines
944 B
TypeScript
import { readFile } from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
import { ConfigError, parseSiteConfig, type SiteConfig } from '../config.ts';
|
|
|
|
export interface CliSite {
|
|
config: SiteConfig;
|
|
root: string;
|
|
dataDir: string;
|
|
}
|
|
|
|
/** The same environment variables the server reads, for the CLI commands. */
|
|
export async function loadCliSite(): Promise<CliSite> {
|
|
const root = path.resolve(process.env['MENU_ROOT'] ?? '.dev');
|
|
const configPath = path.resolve(
|
|
process.env['MENU_SITE_CONFIG'] ?? 'config/hopsngrains.site.json',
|
|
);
|
|
let raw: unknown;
|
|
try {
|
|
raw = JSON.parse(await readFile(configPath, 'utf8'));
|
|
} catch (error) {
|
|
throw new ConfigError(`could not read ${configPath}: ${(error as Error).message}`);
|
|
}
|
|
return {
|
|
config: parseSiteConfig(raw),
|
|
root,
|
|
dataDir: path.join(root, 'data'),
|
|
};
|
|
}
|
|
|
|
export function fail(message: string): never {
|
|
console.error(message);
|
|
process.exit(1);
|
|
}
|