Restore reproducible isolated UI fixtures

This commit is contained in:
2026-10-07 20:08:02 -04:00
parent 70185eb98c
commit 5b3e8cb1a3
6 changed files with 632 additions and 1 deletions
+53
View File
@@ -0,0 +1,53 @@
import { mkdir, open, realpath, rm } from 'node:fs/promises';
import { basename, dirname, isAbsolute, join, resolve } from 'node:path';
export interface FixtureOptions { dbPath: string; now: number; watch: boolean }
export function parseFixtureOptions(args: string[], clock = Date.now()): FixtureOptions {
let dbPath = '', now = clock, watch = false, explicitTime = false;
const seen = new Set<string>();
for (let index = 0; index < args.length; index++) {
const option = args[index];
if (seen.has(option)) throw new Error(`Duplicate option: ${option}`);
seen.add(option);
if (option === '--watch') { watch = true; continue; }
if (option !== '--db' && option !== '--now') throw new Error(`Unknown option: ${option}`);
const value = args[++index];
if (!value || value.startsWith('--')) throw new Error(`Missing value for ${option}.`);
if (option === '--db') dbPath = value;
else {
if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/.test(value)
|| !Number.isFinite(Date.parse(value))) throw new Error('--now must be an ISO timestamp with a timezone.');
now = Date.parse(value); explicitTime = true;
}
}
if (!dbPath || !isAbsolute(dbPath)) throw new Error('Provide --db with an absolute path inside a new fixture directory. DB_PATH is never used.');
if (!Number.isFinite(now)) throw new Error('Invalid fixture clock.');
if (watch && explicitTime) throw new Error('Use --watch for live time or --now for a fixed snapshot, separately.');
return { dbPath: resolve(dbPath), now, watch };
}
/** An atomic new-directory reservation rejects existing DBs, sidecars and symlinks together. */
export async function reserveFixture(dbPath: string): Promise<{ root: string; dbPath: string }> {
if (!isAbsolute(dbPath)) throw new Error('Fixture database path must be absolute.');
const requested = resolve(dbPath);
const requestedRoot = dirname(requested);
// The destination's parent must already exist. Canonicalize /tmp on macOS,
// but never follow a pre-existing fixture directory or database symlink.
const parent = await realpath(dirname(requestedRoot));
const root = join(parent, basename(requestedRoot));
try { await mkdir(root, { mode: 0o700 }); }
catch (cause) {
if ((cause as NodeJS.ErrnoException).code === 'EEXIST') throw new Error('Fixture directory already exists. Choose a new directory; existing data is never overwritten.');
throw cause;
}
const target = join(root, basename(requested));
try {
const file = await open(target, 'wx', 0o600);
await file.close();
} catch (error) {
await rm(root, { recursive: true, force: true });
throw error;
}
return { root, dbPath: target };
}