spb/earth-now Public License
earth-now.co — real-time planetary dashboard: live world metrics modeled, not streamed.
TypeScript 93%
Shell 2.3%
SQL 1.4%
JavaScript 1.3%
Dockerfile 1.2%
CSS 0.8%
1/**2 * earth-now.co3 * Author: Simon-Pierre Boucher4 * Contact: contact@spboucher.ai5 * File: packages/registry/src/load.ts6 * Purpose: Load and validate the metric YAML files and JSON fixtures from disk (server-side only)7 */89import { readFileSync, readdirSync } from "node:fs";10import { dirname, join } from "node:path";11import { fileURLToPath } from "node:url";12import { parse as parseYaml } from "yaml";13import {14 type MetricEntry,15 type MetricFixture,16 fixturesFileSchema,17 metricsFileSchema,18} from "./schema.js";1920// load.js lives in <pkg>/dist (built) or <pkg>/src (tests) — the package root is one level up.21const PACKAGE_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..");2223export interface Registry {24 metrics: MetricEntry[];25 byId: Map<string, MetricEntry>;26}2728/** Load every metrics/*.yaml file, validate, and check cross-references. */29export function loadRegistry(rootDir: string = PACKAGE_ROOT): Registry {30 const metricsDir = join(rootDir, "metrics");31 const files = readdirSync(metricsDir).filter((f) => f.endsWith(".yaml") || f.endsWith(".yml"));32 const metrics: MetricEntry[] = [];33 for (const file of files.sort()) {34 // merge: true enables YAML 1.1 merge keys (<<: *anchor) used by grouped35 // metric families like the top-10 country populations.36 const doc: unknown = parseYaml(readFileSync(join(metricsDir, file), "utf8"), { merge: true });37 const parsed = metricsFileSchema.safeParse(doc);38 if (!parsed.success) {39 throw new Error(`Registry file ${file} is invalid:\n${parsed.error.message}`);40 }41 metrics.push(...parsed.data.metrics);42 }4344 const byId = new Map<string, MetricEntry>();45 for (const m of metrics) {46 if (byId.has(m.id)) throw new Error(`Duplicate metric id in registry: ${m.id}`);47 byId.set(m.id, m);48 }49 // Derived metrics must reference declared metrics.50 for (const m of metrics) {51 if (m.derived) {52 for (const input of m.derived.inputs) {53 if (!byId.has(input.id)) {54 throw new Error(`Metric ${m.id} derives from undeclared metric ${input.id}`);55 }56 }57 }58 }59 return { metrics, byId };60}6162/** Load every fixtures/*.json file (keyed by metric id) and validate. */63export function loadFixtures(rootDir: string = PACKAGE_ROOT): Map<string, MetricFixture> {64 const fixturesDir = join(rootDir, "fixtures");65 const files = readdirSync(fixturesDir).filter((f) => f.endsWith(".json"));66 const out = new Map<string, MetricFixture>();67 for (const file of files.sort()) {68 const doc: unknown = JSON.parse(readFileSync(join(fixturesDir, file), "utf8"));69 const parsed = fixturesFileSchema.safeParse(doc);70 if (!parsed.success) {71 throw new Error(`Fixture file ${file} is invalid:\n${parsed.error.message}`);72 }73 for (const [metricId, fixture] of Object.entries(parsed.data)) {74 if (out.has(metricId)) throw new Error(`Duplicate fixture for metric ${metricId} in ${file}`);75 out.set(metricId, fixture);76 }77 }78 return out;79}80