First cut
This commit is contained in:
35
src/lib/site-bundle.ts
Normal file
35
src/lib/site-bundle.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import {
|
||||
siteContextSchema,
|
||||
eventsFileSchema,
|
||||
sectionFileSchema,
|
||||
type SiteContext,
|
||||
type SectionFile,
|
||||
type EventsFile,
|
||||
} from '@dynamic-sites/shared';
|
||||
|
||||
export interface SiteBundle {
|
||||
siteContext: SiteContext;
|
||||
sections: SectionFile[];
|
||||
events: EventsFile;
|
||||
}
|
||||
|
||||
export function parseSiteBundle(
|
||||
siteContextRaw: unknown,
|
||||
eventsRaw: unknown,
|
||||
sectionRaws: unknown[]
|
||||
): SiteBundle {
|
||||
const siteContext = siteContextSchema.parse(siteContextRaw);
|
||||
const events = eventsFileSchema.parse(eventsRaw);
|
||||
|
||||
const sections: SectionFile[] = [];
|
||||
for (const raw of sectionRaws) {
|
||||
const result = sectionFileSchema.safeParse(raw);
|
||||
if (result.success && result.data.visible) {
|
||||
sections.push(result.data);
|
||||
}
|
||||
}
|
||||
// Sort by order, then id as tiebreaker
|
||||
sections.sort((a, b) => a.order - b.order || a.id.localeCompare(b.id));
|
||||
|
||||
return { siteContext, sections, events };
|
||||
}
|
||||
39
src/lib/site-data.ts
Normal file
39
src/lib/site-data.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { parseSiteBundle, type SiteBundle } from './site-bundle.ts';
|
||||
|
||||
const REPO_ROOT = process.env.REPO_ROOT || '.';
|
||||
const TTL = parseInt(process.env.SITE_DATA_TTL_MS || '2000', 10);
|
||||
|
||||
let cached: { data: SiteBundle; loadedAt: number } | null = null;
|
||||
|
||||
export function loadSiteData(): SiteBundle {
|
||||
const now = Date.now();
|
||||
if (cached && now - cached.loadedAt < TTL) {
|
||||
return cached.data;
|
||||
}
|
||||
|
||||
const siteContextRaw = JSON.parse(
|
||||
fs.readFileSync(path.join(REPO_ROOT, 'site-context.json'), 'utf-8')
|
||||
);
|
||||
|
||||
const eventsRaw = JSON.parse(
|
||||
fs.readFileSync(path.join(REPO_ROOT, 'content/events.json'), 'utf-8')
|
||||
);
|
||||
|
||||
const sectionsDir = path.join(REPO_ROOT, 'content/sections');
|
||||
const sectionRaws: unknown[] = [];
|
||||
if (fs.existsSync(sectionsDir)) {
|
||||
for (const file of fs.readdirSync(sectionsDir).filter(f => f.endsWith('.json'))) {
|
||||
try {
|
||||
sectionRaws.push(JSON.parse(fs.readFileSync(path.join(sectionsDir, file), 'utf-8')));
|
||||
} catch {
|
||||
// skip invalid files
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const data = parseSiteBundle(siteContextRaw, eventsRaw, sectionRaws);
|
||||
cached = { data, loadedAt: now };
|
||||
return data;
|
||||
}
|
||||
Reference in New Issue
Block a user