Skip to main content
Glama
validators.ts4.15 kB
/** * Common validation functions for entity fields */ const VALID_EFFORT_UNITS = ['hours', 'days', 'weeks', 'story-points'] as const; const VALID_CONFIDENCE_LEVELS = ['low', 'medium', 'high'] as const; const VALID_ARTIFACT_TYPES = ['code', 'config', 'migration', 'documentation', 'test', 'script', 'other'] as const; const VALID_FILE_ACTIONS = ['create', 'modify', 'delete'] as const; export function validateEffortEstimate(effort: unknown, fieldName = 'effortEstimate'): void { if (effort === undefined || effort === null) { return; // Optional field } const e = effort as Record<string, unknown>; // Check for invalid legacy format { hours: X, complexity: Y } if ('hours' in e || 'complexity' in e) { throw new Error( `Invalid ${fieldName} format: found legacy { hours, complexity } format. ` + `Expected { value: number, unit: 'hours'|'days'|'weeks'|'story-points', confidence: 'low'|'medium'|'high' }` ); } // Validate required fields if (typeof e.value !== 'number') { throw new Error(`Invalid ${fieldName}: 'value' must be a number`); } if (!VALID_EFFORT_UNITS.includes(e.unit as typeof VALID_EFFORT_UNITS[number])) { throw new Error( `Invalid ${fieldName}: 'unit' must be one of: ${VALID_EFFORT_UNITS.join(', ')}` ); } if (!VALID_CONFIDENCE_LEVELS.includes(e.confidence as typeof VALID_CONFIDENCE_LEVELS[number])) { throw new Error( `Invalid ${fieldName}: 'confidence' must be one of: ${VALID_CONFIDENCE_LEVELS.join(', ')}` ); } } export function validateAlternativesConsidered(alternatives: unknown[]): void { if (!Array.isArray(alternatives)) { return; } for (let i = 0; i < alternatives.length; i++) { const alt = alternatives[i] as Record<string, unknown>; if (typeof alt.option !== 'string' || !alt.option) { throw new Error( `Invalid alternativesConsidered at index ${i}: 'option' must be a non-empty string` ); } if (typeof alt.reasoning !== 'string' || !alt.reasoning) { throw new Error( `Invalid alternativesConsidered at index ${i}: 'reasoning' must be a non-empty string` ); } } } export function validateTags(tags: unknown[]): void { if (!Array.isArray(tags)) { return; } for (let i = 0; i < tags.length; i++) { const tag = tags[i] as Record<string, unknown>; if (typeof tag.key !== 'string' || !tag.key) { throw new Error( `Invalid tag at index ${i}: 'key' must be a non-empty string` ); } if (typeof tag.value !== 'string') { throw new Error( `Invalid tag at index ${i}: 'value' must be a string` ); } } } export function validateCodeExamples(examples: unknown[]): void { if (!Array.isArray(examples)) { return; } for (let i = 0; i < examples.length; i++) { const ex = examples[i] as Record<string, unknown>; if (typeof ex.language !== 'string' || !ex.language) { throw new Error( `Invalid codeExample at index ${i}: 'language' must be a non-empty string` ); } if (typeof ex.code !== 'string') { throw new Error( `Invalid codeExample at index ${i}: 'code' must be a string` ); } } } export function validateArtifactType(artifactType: unknown): void { if (!VALID_ARTIFACT_TYPES.includes(artifactType as typeof VALID_ARTIFACT_TYPES[number])) { throw new Error( `Invalid artifactType: must be one of: ${VALID_ARTIFACT_TYPES.join(', ')}` ); } } export function validateFileTable(fileTable: unknown[]): void { if (!Array.isArray(fileTable)) { return; } for (let i = 0; i < fileTable.length; i++) { const entry = fileTable[i] as Record<string, unknown>; if (typeof entry.path !== 'string' || !entry.path) { throw new Error( `Invalid fileTable entry at index ${i}: 'path' must be a non-empty string` ); } if (!VALID_FILE_ACTIONS.includes(entry.action as typeof VALID_FILE_ACTIONS[number])) { throw new Error( `Invalid fileTable entry at index ${i}: 'action' must be one of: ${VALID_FILE_ACTIONS.join(', ')}` ); } } }

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/cppmyjob/cpp-mcp-planner'

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