a reactive (signals based) hypermedia web framework (wip)
stormlightlabs.github.io/volt/
hypermedia
frontend
signals
1import { mkdir, readFile, writeFile } from "node:fs/promises";
2import path from "node:path";
3
4/**
5 * Version history entry for a single version
6 */
7export type VersionHistoryEntry = {
8 version: string;
9 date: string;
10 hash: string;
11 added: number;
12 removed: number;
13 edited: number;
14};
15
16/**
17 * Complete metadata for a single document
18 */
19export type DocMetadata = {
20 version: string;
21 updated: string;
22 hash: string;
23 sections: string[];
24 history: VersionHistoryEntry[];
25};
26
27/**
28 * Complete metadata storage for all documents by mapping relative file paths to their metadata
29 */
30export type VersionsMetadata = Record<string, DocMetadata>;
31
32const METADATA_PATH = path.join(process.cwd(), "..", "docs", ".versions.json");
33
34/**
35 * Load the complete versions metadata from disk
36 */
37export async function loadMetadata(): Promise<VersionsMetadata> {
38 try {
39 const content = await readFile(METADATA_PATH, "utf8");
40 return JSON.parse(content);
41 } catch (error) {
42 if ((error as NodeJS.ErrnoException).code === "ENOENT") {
43 return {};
44 }
45 throw error;
46 }
47}
48
49/**
50 * Save the complete versions metadata to disk & creates the docs directory if it doesn't exist
51 */
52export async function saveMetadata(metadata: VersionsMetadata): Promise<void> {
53 const docsDir = path.dirname(METADATA_PATH);
54 await mkdir(docsDir, { recursive: true });
55 await writeFile(METADATA_PATH, JSON.stringify(metadata, null, 2), "utf8");
56}
57
58/**
59 * Get metadata for a specific document
60 */
61export async function getDocMetadata(relativePath: string): Promise<DocMetadata | undefined> {
62 const metadata = await loadMetadata();
63 return metadata[relativePath];
64}
65
66/**
67 * Update metadata for a specific document or creates a new entry if document hasn't been versioned yet
68 */
69export async function updateDocMetadata(relativePath: string, docMeta: DocMetadata): Promise<void> {
70 const metadata = await loadMetadata();
71 metadata[relativePath] = docMeta;
72 await saveMetadata(metadata);
73}