import { parseAllDocuments } from "yaml"; import { z } from "zod"; import type { WorkspaceDescriptor } from "./schema.js"; export const CATALOG_PATH = "thoth-workspaces.yaml"; export interface WorkspaceCatalogEntry { id: string; name: string; description?: string; } export interface WorkspaceCatalog { schema_version: 1; workspaces: WorkspaceCatalogEntry[]; } const workspaceId = z.string().trim().regex(/^[a-z][a-z0-9-]{2,62}$/, { message: "workspace id must match ^[a-z][a-z0-9-]{2,62}$", }).refine((value) => value !== "workspace-docs", { message: "workspace id is reserved", }); const catalogEntry = z.object({ id: workspaceId, name: z.string().trim().min(1), description: z.string().trim().min(1).optional(), }).strict(); const catalogSchema = z.object({ schema_version: z.literal(1), workspaces: z.array(catalogEntry), }).strict().superRefine((catalog, context) => { const seen = new Set(); catalog.workspaces.forEach((entry, index) => { if (seen.has(entry.id)) { context.addIssue({ code: "custom", path: ["workspaces", index, "id"], message: "workspace id is duplicated in the catalog", }); } seen.add(entry.id); }); }); function safeCatalogError(): Error { return new Error("Workspace catalog is invalid"); } export function parseWorkspaceCatalogYaml(source: string): WorkspaceCatalog { try { const documents = parseAllDocuments(source, { uniqueKeys: true }); if (documents.length !== 1) throw safeCatalogError(); const document = documents[0]; if (document.errors.length > 0 || document.warnings.length > 0) throw safeCatalogError(); return catalogSchema.parse(document.toJSON()) as WorkspaceCatalog; } catch (error) { if (error instanceof Error && error.message === "Workspace catalog is invalid") throw error; throw safeCatalogError(); } } export function assertCatalogMatchesDescriptor( entry: WorkspaceCatalogEntry, workspace: WorkspaceDescriptor, ): void { if ( entry.id !== workspace.workspace.id || entry.name !== workspace.workspace.name || entry.description !== workspace.workspace.description ) { throw new Error("Workspace catalog metadata does not match descriptor"); } }