Initial Commit
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { resolve, join } from 'node:path';
|
||||
import { Database } from 'bun:sqlite';
|
||||
import { SqliteReferenceRepository } from '../src/lib/server/reference/repository';
|
||||
|
||||
const directory = resolve(process.env.REFERENCE_DIR ?? 'data/reference-live');
|
||||
const manifest = await Bun.file(join(directory, 'manifest.json')).json();
|
||||
assert.equal(manifest.active?.profile, 'production', 'live catalog must have a production profile');
|
||||
const repository = new SqliteReferenceRepository(directory, 'production');
|
||||
const db = new Database(repository.databasePath, { readonly: true, strict: true });
|
||||
try {
|
||||
const names = new Map((await repository.types([34, 587])).map(type => [type.id, type.name]));
|
||||
assert.equal(names.get(34), 'Tritanium');
|
||||
assert.equal(names.get(587), 'Rifter');
|
||||
const counts: Record<string, number> = {};
|
||||
for (const table of ['types', 'blueprints', 'systems', 'gates', 'unresolved_references']) {
|
||||
const row = db.query<{ n: number }, []>(`SELECT COUNT(*) AS n FROM ${table}`).get();
|
||||
counts[table] = Number(row?.n);
|
||||
assert.equal(counts[table], manifest.active.counts[table], `${table} must match the published manifest`);
|
||||
}
|
||||
assert(counts.types > 50_000);
|
||||
assert(counts.systems > 5_000);
|
||||
assert(counts.blueprints > 0);
|
||||
assert(counts.gates > 0);
|
||||
const integrity = db.query<{ integrity_check: string }, []>('PRAGMA integrity_check').all();
|
||||
assert.deepEqual(integrity.map(row => row.integrity_check), ['ok']);
|
||||
assert.deepEqual(db.query('PRAGMA foreign_key_check').all(), []);
|
||||
console.log(JSON.stringify({ productionReference: 'passed', directory, version: await repository.version(), counts }));
|
||||
} finally { db.close(); repository.close(); }
|
||||
@@ -0,0 +1,81 @@
|
||||
import { resolve } from 'node:path';
|
||||
import { ReferenceCompiler } from '../src/lib/server/reference/index';
|
||||
import { fixtureSources } from '../src/lib/server/reference/sources';
|
||||
import { productionSources } from '../src/lib/server/reference/production';
|
||||
import type { BuildProfile } from '../src/lib/server/reference/types';
|
||||
|
||||
const HELP = `Reference data compiler (fixture/offline only when explicitly selected)
|
||||
|
||||
Usage:
|
||||
bun workers/reference.ts --fixture [--directory DIR]
|
||||
bun workers/reference.ts --production [--archive-dir DIR] [--directory DIR]
|
||||
bun workers/reference.ts --check [--fixture|--production] [--directory DIR]
|
||||
bun workers/reference.ts --rollback [--directory DIR]
|
||||
|
||||
Options:
|
||||
--fixture Use the checked-in, tiny fixture adapters (never downloads).
|
||||
--production Download and compile the pinned public production archives.
|
||||
--archive-dir Archive staging/cache directory (default: data/reference-live).
|
||||
--offline Parse archives already present in --archive-dir; no network.
|
||||
--check Check configured source metadata only; never downloads archives.
|
||||
--rollback Atomically switch ACTIVE to PREVIOUS.
|
||||
--directory Reference directory (default: REFERENCE_DIR or data/reference).
|
||||
--help Show this help.
|
||||
|
||||
Production imports stream downloads and archive members with bounded limits. --check never downloads archives.
|
||||
`;
|
||||
|
||||
function valueAfter(args: string[], flag: string): string | undefined { const index = args.indexOf(flag); return index >= 0 ? args[index + 1] : undefined; }
|
||||
|
||||
export function validateArguments(args: string[]): void {
|
||||
const flags = new Set(['--fixture', '--production', '--offline', '--check', '--rollback']);
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
if (args[i] === '--directory' || args[i] === '--archive-dir') {
|
||||
if (!args[i + 1] || args[i + 1].startsWith('-')) throw new Error('A reference directory option is missing its value');
|
||||
i++;
|
||||
} else if (!flags.has(args[i])) throw new Error('Unknown reference compiler option');
|
||||
}
|
||||
if (args.includes('--fixture') && args.includes('--production')) throw new Error('Choose either --fixture or --production, not both');
|
||||
if (args.includes('--check') && args.includes('--rollback')) throw new Error('Choose either --check or --rollback, not both');
|
||||
if (args.includes('--offline') && args.includes('--fixture')) throw new Error('--offline is for production archives; fixtures are always offline');
|
||||
}
|
||||
|
||||
async function main(args: string[]): Promise<void> {
|
||||
if (!args.length || args.includes('--help') || args.includes('-h')) { console.log(HELP); return; }
|
||||
try { validateArguments(args); }
|
||||
catch (error) { console.error(error instanceof Error ? error.message : 'Invalid reference compiler options'); process.exitCode = 2; return; }
|
||||
const fixture = args.includes('--fixture');
|
||||
const production = args.includes('--production');
|
||||
// REFERENCE_DIR is the shared application artifact mount. REFERENCE_LIVE_DIR
|
||||
// controls archive storage only and must never redirect published artifacts.
|
||||
const directory = resolve(valueAfter(args, '--directory') ?? process.env.REFERENCE_DIR ?? (production ? 'data/reference-live' : 'data/reference'));
|
||||
const profile: BuildProfile = fixture ? 'fixture' : 'production';
|
||||
const archiveDir = resolve(valueAfter(args, '--archive-dir') ?? process.env.REFERENCE_LIVE_DIR ?? 'data/reference-live');
|
||||
const compiler = new ReferenceCompiler({ directory, profile, sources: fixture ? fixtureSources() : (production || args.includes('--check')) ? productionSources({ archiveDir, offline: args.includes('--offline') }) : {} });
|
||||
if (args.includes('--check')) {
|
||||
if (fixture) {
|
||||
const results = await compiler.checkSources();
|
||||
console.log(JSON.stringify({ directory, profile, archiveFetch: false, results }, null, 2));
|
||||
if (results.some((result) => result.error)) process.exitCode = 1;
|
||||
} else {
|
||||
const results = await compiler.checkSources();
|
||||
console.log(JSON.stringify({ directory, profile, archiveFetch: false, results }, null, 2));
|
||||
if (results.some((result) => result.error)) process.exitCode = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (args.includes('--rollback')) {
|
||||
try { console.log(JSON.stringify(await compiler.rollback(), null, 2)); } catch (error) { process.exitCode = 1; console.error(error instanceof Error ? error.message : String(error)); }
|
||||
return;
|
||||
}
|
||||
if (fixture || production) {
|
||||
const result = await compiler.compile();
|
||||
console.log(JSON.stringify(result, null, 2));
|
||||
if (result.status === 'failed') process.exitCode = 1;
|
||||
return;
|
||||
}
|
||||
console.error('No build mode selected. Use --fixture, --check, --rollback, or --help.');
|
||||
process.exitCode = 2;
|
||||
}
|
||||
|
||||
if (import.meta.main) await main(process.argv.slice(2));
|
||||
Reference in New Issue
Block a user