Skip to main content
Glama
diagram-service.ts4.39 kB
/** * Diagram Service * Single Responsibility: Business logic for diagram data access and management */ import { readdir, stat } from "fs/promises"; import { join } from "path"; import { getLiveDir, validatePreviewId, getDiagramFilePath, deleteDiagram as deleteDiagramFiles, } from "./file-utils.js"; import { DIAGRAM_FORMATS } from "./constants.js"; import { DiagramInfo } from "./types.js"; import { webLogger } from "./logger.js"; /** * Lists all diagrams in the live directory * @returns Array of diagram info sorted by modification time (newest first) */ export async function listDiagrams(): Promise<DiagramInfo[]> { try { const liveDir = getLiveDir(); const entries = await readdir(liveDir, { withFileTypes: true }); const diagrams: DiagramInfo[] = []; for (const entry of entries) { if (!entry.isDirectory()) { continue; } try { // Validate the directory name is a valid preview ID validatePreviewId(entry.name); const info = await getDiagramInfo(entry.name); if (info) { diagrams.push(info); } } catch (error) { // Skip invalid or inaccessible diagrams webLogger.debug(`Skipping diagram directory: ${entry.name}`, { error: error instanceof Error ? error.message : String(error), }); } } // Sort by modification time (newest first) diagrams.sort((a, b) => b.modifiedAt.getTime() - a.modifiedAt.getTime()); webLogger.debug(`Listed ${diagrams.length} diagrams`); return diagrams; } catch (error) { webLogger.error("Failed to list diagrams", { error: error instanceof Error ? error.message : String(error), }); return []; } } /** * Gets detailed information about a specific diagram * @param previewId The diagram ID * @returns Diagram info or null if not found */ export async function getDiagramInfo(previewId: string): Promise<DiagramInfo | null> { try { validatePreviewId(previewId); // Try each format to find the diagram for (const format of Object.values(DIAGRAM_FORMATS)) { try { const filePath = getDiagramFilePath(previewId, format); const stats = await stat(filePath); return { id: previewId, format, modifiedAt: stats.mtime, sizeBytes: stats.size, }; } catch { // Try next format continue; } } webLogger.debug(`Diagram not found: ${previewId}`); return null; } catch (error) { webLogger.error(`Error getting diagram info: ${previewId}`, { error: error instanceof Error ? error.message : String(error), }); return null; } } /** * Searches diagrams by ID * @param query Search query (case-insensitive) * @returns Filtered array of diagram info */ export async function searchDiagrams(query: string): Promise<DiagramInfo[]> { if (!query || !query.trim()) { return listDiagrams(); } const allDiagrams = await listDiagrams(); const normalizedQuery = query.toLowerCase().trim(); return allDiagrams.filter((diagram) => diagram.id.toLowerCase().includes(normalizedQuery)); } /** * Checks if a diagram exists * @param previewId The diagram ID * @returns True if diagram exists */ export async function diagramExists(previewId: string): Promise<boolean> { try { validatePreviewId(previewId); const info = await getDiagramInfo(previewId); return info !== null; } catch { return false; } } /** * Gets the count of diagrams * @returns Total number of diagrams */ export async function getDiagramCount(): Promise<number> { const diagrams = await listDiagrams(); return diagrams.length; } /** * Deletes a diagram and all its associated files * @param previewId The diagram ID */ export async function deleteDiagram(previewId: string): Promise<void> { try { validatePreviewId(previewId); // Check if diagram exists const info = await getDiagramInfo(previewId); if (!info) { throw new Error(`Diagram not found: ${previewId}`); } // Delete the diagram await deleteDiagramFiles(previewId); webLogger.info(`Deleted diagram: ${previewId}`); } catch (error) { webLogger.error(`Error deleting diagram: ${previewId}`, { error: error instanceof Error ? error.message : String(error), }); throw error; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/veelenga/claude-mermaid'

If you have feedback or need assistance with the MCP directory API, please join our Discord server