@vfarcic/dot-ai
Version:
AI-powered development productivity platform that enhances software development workflows through intelligent automation and AI-driven assistance
470 lines (469 loc) • 17.2 kB
JavaScript
"use strict";
/**
* REST API Route Definitions
*
* Central registration of all REST API routes with their Zod schemas.
* This is the single source of truth for routing, OpenAPI generation, and fixture validation.
*
* PRD #354: REST API Route Registry with Auto-Generated OpenAPI and Test Fixtures
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.routeDefinitions = void 0;
exports.registerAllRoutes = registerAllRoutes;
exports.getRouteCount = getRouteCount;
const zod_1 = require("zod");
const schemas_1 = require("../schemas");
/**
* Query parameter schemas for various endpoints
*/
const ToolDiscoveryQuerySchema = zod_1.z.object({
category: zod_1.z.string().optional().describe('Filter tools by category'),
tag: zod_1.z.string().optional().describe('Filter tools by tag'),
search: zod_1.z.string().optional().describe('Search tools by name or description'),
});
const ResourceSearchQuerySchema = zod_1.z.object({
q: zod_1.z.string().describe('Search query'),
limit: zod_1.z.coerce
.number()
.optional()
.default(20)
.describe('Maximum results to return'),
offset: zod_1.z.coerce
.number()
.optional()
.default(0)
.describe('Offset for pagination'),
});
const ResourceListQuerySchema = zod_1.z.object({
kind: zod_1.z.string().describe('Resource kind (e.g., Pod, Deployment)'),
apiVersion: zod_1.z.string().describe('API version (e.g., v1, apps/v1)'),
namespace: zod_1.z.string().optional().describe('Filter by namespace'),
limit: zod_1.z.coerce.number().optional().describe('Maximum results to return'),
offset: zod_1.z.coerce.number().optional().describe('Offset for pagination'),
});
const SingleResourceQuerySchema = zod_1.z.object({
kind: zod_1.z.string().describe('Resource kind'),
apiVersion: zod_1.z.string().describe('API version'),
name: zod_1.z.string().describe('Resource name'),
namespace: zod_1.z
.string()
.optional()
.describe('Namespace (for namespaced resources)'),
});
const ResourceKindsQuerySchema = zod_1.z.object({
namespace: zod_1.z.string().optional().describe('Filter kinds by namespace'),
});
const EventsQuerySchema = zod_1.z.object({
name: zod_1.z.string().describe('Resource name'),
kind: zod_1.z.string().describe('Resource kind'),
namespace: zod_1.z.string().optional().describe('Resource namespace'),
});
const LogsQuerySchema = zod_1.z.object({
name: zod_1.z.string().describe('Pod name'),
namespace: zod_1.z.string().describe('Pod namespace'),
container: zod_1.z
.string()
.optional()
.describe('Container name (defaults to first container)'),
tailLines: zod_1.z.coerce.number().optional().describe('Number of lines from end'),
previous: zod_1.z.coerce
.boolean()
.optional()
.describe('Get logs from previous container instance'),
});
const VisualizationQuerySchema = zod_1.z.object({
reload: zod_1.z.coerce
.boolean()
.optional()
.describe('Force regeneration of visualization'),
});
/**
* Path parameter schemas
*/
const ToolNameParamsSchema = zod_1.z.object({
toolName: zod_1.z.string().describe('Name of the tool to execute'),
});
const PromptNameParamsSchema = zod_1.z.object({
promptName: zod_1.z.string().describe('Name of the prompt'),
});
const SessionIdParamsSchema = zod_1.z.object({
sessionId: zod_1.z.string().describe('Session ID'),
});
const SourceIdentifierParamsSchema = zod_1.z.object({
sourceIdentifier: zod_1.z
.string()
.describe('Source identifier (e.g., namespace/name of GitKnowledgeSource CR)'),
});
const KnowledgeAskBodySchema = zod_1.z.object({
query: zod_1.z
.string()
.min(1)
.describe('The question to answer from the knowledge base'),
limit: zod_1.z.coerce
.number()
.optional()
.default(20)
.describe('Maximum chunks to retrieve per search (default: 20)'),
uriFilter: zod_1.z
.string()
.optional()
.describe('Optional: filter searches to specific document URI'),
});
/**
* OpenAPI schema placeholder - returns raw OpenAPI spec object
*/
const OpenApiResponseSchema = zod_1.z
.object({
openapi: zod_1.z.string(),
info: zod_1.z.object({
title: zod_1.z.string(),
description: zod_1.z.string(),
version: zod_1.z.string(),
}),
paths: zod_1.z.record(zod_1.z.string(), zod_1.z.any()),
})
.passthrough();
/**
* All route definitions for the REST API
*/
exports.routeDefinitions = [
// ============================================
// Tool Endpoints
// ============================================
{
path: '/api/v1/tools',
method: 'GET',
description: 'Discover available tools with optional filtering by category, tag, or search term',
tags: ['Tools'],
query: ToolDiscoveryQuerySchema,
response: schemas_1.ToolDiscoveryResponseSchema,
errorResponses: {
500: schemas_1.InternalServerErrorSchema,
},
},
{
path: '/api/v1/tools/:toolName',
method: 'POST',
description: 'Execute a tool with the provided parameters',
tags: ['Tools'],
params: ToolNameParamsSchema,
body: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).describe('Tool execution parameters'),
response: schemas_1.ToolExecutionResponseSchema,
errorResponses: {
400: schemas_1.InvalidToolRequestErrorSchema,
404: schemas_1.ToolNotFoundErrorSchema,
500: schemas_1.ToolExecutionErrorSchema,
},
},
// ============================================
// OpenAPI Endpoint
// ============================================
{
path: '/api/v1/openapi',
method: 'GET',
description: 'Get the OpenAPI 3.0 specification for this API',
tags: ['Documentation'],
response: OpenApiResponseSchema,
errorResponses: {
500: schemas_1.InternalServerErrorSchema,
},
},
// ============================================
// Resource Endpoints
// ============================================
{
path: '/api/v1/resources',
method: 'GET',
description: 'List resources filtered by kind and optional namespace',
tags: ['Resources'],
query: ResourceListQuerySchema,
response: schemas_1.ResourceListResponseSchema,
errorResponses: {
400: schemas_1.ResourceBadRequestErrorSchema,
503: schemas_1.ResourcePluginUnavailableErrorSchema,
500: schemas_1.InternalServerErrorSchema,
},
},
{
path: '/api/v1/resources/kinds',
method: 'GET',
description: 'List all resource kinds available in the cluster with counts',
tags: ['Resources'],
query: ResourceKindsQuerySchema,
response: schemas_1.ResourceKindsResponseSchema,
errorResponses: {
503: schemas_1.ResourcePluginUnavailableErrorSchema,
500: schemas_1.InternalServerErrorSchema,
},
},
{
path: '/api/v1/resources/search',
method: 'GET',
description: 'Search for resources using semantic search',
tags: ['Resources'],
query: ResourceSearchQuerySchema,
response: schemas_1.ResourceSearchResponseSchema,
errorResponses: {
400: schemas_1.ResourceBadRequestErrorSchema,
503: schemas_1.ResourcePluginUnavailableErrorSchema,
500: schemas_1.InternalServerErrorSchema,
},
},
{
path: '/api/v1/resources/sync',
method: 'POST',
description: 'Sync resources from the Kubernetes controller',
tags: ['Resources'],
body: schemas_1.ResourceSyncRequestSchema,
response: schemas_1.ResourceSyncResponseSchema,
errorResponses: {
400: schemas_1.ResourceBadRequestErrorSchema,
500: schemas_1.InternalServerErrorSchema,
},
},
{
path: '/api/v1/resource',
method: 'GET',
description: 'Get a single resource with full details including live status',
tags: ['Resources'],
query: SingleResourceQuerySchema,
response: schemas_1.SingleResourceResponseSchema,
errorResponses: {
400: schemas_1.ResourceBadRequestErrorSchema,
404: schemas_1.NotFoundErrorSchema,
503: schemas_1.ResourcePluginUnavailableErrorSchema,
500: schemas_1.InternalServerErrorSchema,
},
},
{
path: '/api/v1/namespaces',
method: 'GET',
description: 'List all namespaces in the cluster',
tags: ['Resources'],
response: schemas_1.NamespacesResponseSchema,
errorResponses: {
503: schemas_1.ResourcePluginUnavailableErrorSchema,
500: schemas_1.InternalServerErrorSchema,
},
},
// ============================================
// Events Endpoint
// ============================================
{
path: '/api/v1/events',
method: 'GET',
description: 'Get Kubernetes events for a specific resource',
tags: ['Observability'],
query: EventsQuerySchema,
response: schemas_1.EventsResponseSchema,
errorResponses: {
400: schemas_1.EventsBadRequestErrorSchema,
503: schemas_1.EventsPluginUnavailableErrorSchema,
500: schemas_1.InternalServerErrorSchema,
},
},
// ============================================
// Logs Endpoint
// ============================================
{
path: '/api/v1/logs',
method: 'GET',
description: 'Get container logs from a pod',
tags: ['Observability'],
query: LogsQuerySchema,
response: schemas_1.LogsResponseSchema,
errorResponses: {
400: schemas_1.LogsBadRequestErrorSchema,
503: schemas_1.LogsPluginUnavailableErrorSchema,
500: schemas_1.InternalServerErrorSchema,
},
},
// ============================================
// Prompts Endpoints
// ============================================
{
path: '/api/v1/prompts',
method: 'GET',
description: 'List all available prompts',
tags: ['Prompts'],
response: schemas_1.PromptsListResponseSchema,
errorResponses: {
500: schemas_1.InternalServerErrorSchema,
},
},
{
path: '/api/v1/prompts/refresh',
method: 'POST',
description: 'Force-refresh the prompts cache by pulling latest from the git repository',
tags: ['Prompts'],
response: schemas_1.PromptsCacheRefreshResponseSchema,
errorResponses: {
500: schemas_1.PromptsCacheRefreshErrorSchema,
},
},
{
path: '/api/v1/prompts/:promptName',
method: 'POST',
description: 'Get a prompt with rendered template arguments',
tags: ['Prompts'],
params: PromptNameParamsSchema,
body: schemas_1.PromptGetRequestSchema,
response: schemas_1.PromptGetResponseSchema,
errorResponses: {
404: schemas_1.PromptNotFoundErrorSchema,
500: schemas_1.InternalServerErrorSchema,
},
},
// ============================================
// Visualization Endpoint
// ============================================
{
path: '/api/v1/visualize/:sessionId',
method: 'GET',
description: 'Get structured visualization data for a session',
tags: ['Visualization'],
params: SessionIdParamsSchema,
query: VisualizationQuerySchema,
response: schemas_1.VisualizationResponseSchema,
errorResponses: {
404: schemas_1.VisualizationNotFoundErrorSchema,
503: schemas_1.VisualizationServiceUnavailableErrorSchema,
500: schemas_1.InternalServerErrorSchema,
},
},
// ============================================
// Sessions Endpoints
// ============================================
{
path: '/api/v1/sessions',
method: 'GET',
description: 'List sessions with optional status filtering and pagination',
tags: ['Sessions'],
query: schemas_1.SessionListQuerySchema,
response: schemas_1.SessionListResponseSchema,
errorResponses: {
500: schemas_1.SessionListErrorSchema,
},
},
{
path: '/api/v1/sessions/:sessionId',
method: 'GET',
description: 'Get raw session data for any tool type (remediate, query, recommend, etc.)',
tags: ['Sessions'],
params: SessionIdParamsSchema,
response: schemas_1.SessionResponseSchema,
errorResponses: {
404: schemas_1.SessionNotFoundErrorSchema,
500: schemas_1.InternalServerErrorSchema,
},
},
// ============================================
// SSE Streaming Endpoints (PRD #425)
// ============================================
{
path: '/api/v1/events/remediations',
method: 'GET',
description: 'SSE stream for real-time remediation session events. Returns text/event-stream.',
tags: ['Sessions'],
response: schemas_1.RemediationSSEEventSchema,
errorResponses: {
500: schemas_1.InternalServerErrorSchema,
},
},
// ============================================
// Knowledge Base Endpoints (PRD #356)
// ============================================
{
path: '/api/v1/knowledge/source/:sourceIdentifier',
method: 'DELETE',
description: 'Delete all knowledge base chunks for a source identifier. Used by controller for GitKnowledgeSource cleanup.',
tags: ['Knowledge'],
params: SourceIdentifierParamsSchema,
response: schemas_1.DeleteBySourceResponseSchema,
errorResponses: {
503: schemas_1.DeleteBySourcePluginUnavailableErrorSchema,
500: schemas_1.DeleteBySourceErrorSchema,
},
},
{
path: '/api/v1/knowledge/ask',
method: 'POST',
description: 'Ask a question and receive an AI-synthesized answer from the knowledge base. Uses an agentic approach that can search multiple times with different phrasings for comprehensive answers.',
tags: ['Knowledge'],
body: KnowledgeAskBodySchema,
response: schemas_1.KnowledgeAskResponseSchema,
errorResponses: {
400: schemas_1.KnowledgeAskBadRequestErrorSchema,
503: schemas_1.ServiceUnavailableErrorSchema,
500: schemas_1.KnowledgeAskErrorSchema,
},
},
// ============================================
// Embeddings Endpoint (PRD #384)
// ============================================
{
path: '/api/v1/embeddings/migrate',
method: 'POST',
description: 'Migrate embedding vectors when switching between embedding providers. Re-embeds all data using the current provider.',
tags: ['Embeddings'],
body: schemas_1.EmbeddingMigrationRequestSchema,
response: schemas_1.EmbeddingMigrationResponseSchema,
errorResponses: {
400: schemas_1.EmbeddingMigrationBadRequestErrorSchema,
503: schemas_1.EmbeddingMigrationServiceUnavailableErrorSchema,
500: schemas_1.EmbeddingMigrationErrorSchema,
},
},
// ============================================
// User Management Endpoints (PRD #380 Task 2.5)
// ============================================
{
path: '/api/v1/users',
method: 'POST',
description: 'Create a new Dex static user',
tags: ['Users'],
body: schemas_1.UserCreateRequestSchema,
response: schemas_1.UserCreateResponseSchema,
errorResponses: {
400: schemas_1.UserBadRequestErrorSchema,
409: schemas_1.UserConflictErrorSchema,
500: schemas_1.UserManagementErrorSchema,
},
},
{
path: '/api/v1/users',
method: 'GET',
description: 'List all Dex static users (emails only)',
tags: ['Users'],
response: schemas_1.UserListResponseSchema,
errorResponses: {
500: schemas_1.UserManagementErrorSchema,
},
},
{
path: '/api/v1/users/:email',
method: 'DELETE',
description: 'Delete a Dex static user by email',
tags: ['Users'],
params: schemas_1.UserEmailParamsSchema,
response: schemas_1.UserDeleteResponseSchema,
errorResponses: {
404: schemas_1.UserNotFoundErrorSchema,
500: schemas_1.UserManagementErrorSchema,
},
},
];
/**
* Register all routes with the provided registry
*/
function registerAllRoutes(registry) {
for (const route of exports.routeDefinitions) {
registry.register(route);
}
}
/**
* Get route count - useful for validation
*/
function getRouteCount() {
return exports.routeDefinitions.length;
}