zurri / src /docs /swagger.ts
nexusbert's picture
push
f5035b9
import swaggerJSDoc from 'swagger-jsdoc';
import path from 'path';
import fs from 'fs';
// Swagger JSDoc needs the source TypeScript files (not compiled JS) to read JSDoc comments
// When running from dist/, we need to look for src/ at the project root
// When running from src/, we use relative path
// Check if we're running from dist (compiled) or src (development)
const isRunningFromDist = __dirname.includes('dist');
const projectRoot = isRunningFromDist
? path.resolve(__dirname, '../..') // Go up from dist/docs to project root
: path.resolve(__dirname, '..'); // Go up from src/docs to project root
// Always use source TypeScript files from src/routes
const routesPath = path.join(projectRoot, 'src/routes/*.ts');
console.log(`πŸ” Swagger looking for routes at: ${routesPath}`);
console.log(`πŸ“‚ Running from: ${isRunningFromDist ? 'dist' : 'src'}`);
console.log(`πŸ“‚ Project root: ${projectRoot}`);
// Check if route files exist (for debugging)
try {
const routesDir = path.join(projectRoot, 'src/routes');
if (fs.existsSync(routesDir)) {
const files = fs.readdirSync(routesDir);
console.log(`πŸ“ Found ${files.length} route files in ${routesDir}`);
const tsFiles = files.filter(f => f.endsWith('.ts'));
console.log(`πŸ“„ TypeScript route files: ${tsFiles.length}`);
} else {
console.warn(`⚠️ Routes directory not found: ${routesDir}`);
}
// Also check if the glob pattern resolves correctly
const testPattern = path.join(projectRoot, 'src/routes/*.ts');
console.log(`πŸ” Using pattern: ${testPattern}`);
} catch (error) {
console.warn('⚠️ Could not check routes directory:', error);
}
export const swaggerSpec = swaggerJSDoc({
definition: {
openapi: '3.0.0',
info: {
title: 'Zurri API',
version: '1.0.0',
description: 'Zurri Agents Marketplace API with Wallet Point System',
},
servers: [
{
url: process.env.API_BASE_URL || '/api',
description: 'API Server'
},
],
components: {
securitySchemes: {
bearerAuth: {
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
},
},
schemas: {
Agent: {
type: 'object',
properties: {
id: {
type: 'string',
format: 'uuid',
},
name: {
type: 'string',
example: 'PixelPainter',
},
description: {
type: 'string',
example: 'I turn prompts into AI art!',
},
endpoint: {
type: 'string',
format: 'uri',
example: 'https://api.pixelpainter.ai/run',
},
avatar: {
type: 'string',
format: 'uri',
nullable: true,
description: 'IPFS gateway URL for avatar image',
},
category: {
type: 'string',
example: 'image generation',
},
reputation: {
type: 'number',
format: 'float',
example: 4.8,
},
capabilities: {
type: 'array',
items: {
type: 'string',
},
example: ['text-to-image', 'image-editing'],
},
pointsPerTask: {
type: 'number',
format: 'float',
example: 10,
},
status: {
type: 'string',
enum: ['pending', 'approved', 'rejected', 'suspended'],
},
usageCount: {
type: 'integer',
example: 0,
},
rating: {
type: 'number',
format: 'float',
nullable: true,
},
ratingCount: {
type: 'integer',
example: 0,
},
creatorId: {
type: 'string',
format: 'uuid',
},
createdAt: {
type: 'string',
format: 'date-time',
},
updatedAt: {
type: 'string',
format: 'date-time',
},
},
},
ChatMessage: {
type: 'object',
properties: {
id: {
type: 'string',
format: 'uuid',
},
role: {
type: 'string',
enum: ['user', 'assistant', 'system'],
description: 'Message role (user = user message, assistant = agent response, system = system message)',
},
content: {
type: 'string',
description: 'Message content',
},
agentId: {
type: 'string',
format: 'uuid',
},
userId: {
type: 'string',
format: 'uuid',
nullable: true,
},
conversationId: {
type: 'string',
nullable: true,
description: 'Conversation ID this message belongs to',
},
metadata: {
type: 'object',
description: 'Additional message metadata (files, IPFS hashes, etc.)',
additionalProperties: true,
},
createdAt: {
type: 'string',
format: 'date-time',
},
},
},
ChatResponse: {
type: 'object',
properties: {
response: {
type: 'string',
description: 'Agent\'s response message',
},
conversationId: {
type: 'string',
description: 'Conversation ID for this chat session',
},
metadata: {
type: 'object',
description: 'Additional response metadata from agent',
additionalProperties: true,
},
},
},
User: {
type: 'object',
properties: {
id: {
type: 'string',
format: 'uuid',
description: 'User ID',
},
email: {
type: 'string',
format: 'email',
description: 'User email address',
},
name: {
type: 'string',
nullable: true,
description: 'User display name',
},
isAdmin: {
type: 'boolean',
default: false,
description: 'Whether user has admin privileges',
},
isCreator: {
type: 'boolean',
default: false,
description: 'Whether user can create and manage agents',
},
isActive: {
type: 'boolean',
default: true,
description: 'Whether user account is active',
},
createdAt: {
type: 'string',
format: 'date-time',
description: 'Account creation timestamp',
},
updatedAt: {
type: 'string',
format: 'date-time',
description: 'Last update timestamp',
},
},
},
},
},
security: [{ bearerAuth: [] }],
},
apis: [routesPath],
});
// Log Swagger spec generation
try {
const spec = swaggerSpec as any; // Type assertion for logging
const paths = spec.paths ? Object.keys(spec.paths) : [];
console.log(`πŸ“š Swagger spec generated with ${paths.length} endpoints`);
if (paths.length === 0) {
console.warn('⚠️ No endpoints found in Swagger spec. Check route files.');
}
} catch (error) {
console.error('❌ Error generating Swagger spec:', error);
}