zurri / src /app.ts
nexusbert's picture
push
8058f3a
import express, { Application } from 'express';
import cors from 'cors';
import path from 'path';
import swaggerUi from 'swagger-ui-express';
import { swaggerSpec } from './docs/swagger';
// Routes
import authRoutes from './routes/authRoutes';
import creatorAuthRoutes from './routes/creatorAuthRoutes';
import agentRoutes from './routes/agentRoutes';
import chatRoutes from './routes/chatRoutes';
import subscriptionRoutes from './routes/subscriptionRoutes';
import walletRoutes from './routes/walletRoutes';
import userRoutes from './routes/userRoutes';
import creatorRoutes from './routes/creatorRoutes';
import adminRoutes from './routes/adminRoutes';
const app: Application = express();
// Trust proxy for Hugging Face Spaces
app.set('trust proxy', 1);
// Simple CORS - allow all
app.use(cors());
// Body parsing
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
app.get('/', (req, res) => {
res.json({
name: 'Zurri API',
version: '1.0.0',
description: 'Zurri Agents Marketplace API with Wallet Point System',
status: 'running',
timestamp: new Date().toISOString(),
endpoints: {
docs: '/docs',
health: '/health',
api: '/api',
},
note: 'Frontend will be built in a separate milestone',
});
});
app.get('/health', (req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});
app.use('/docs', swaggerUi.serve);
app.get('/docs', swaggerUi.setup(swaggerSpec, {
explorer: true,
customCss: '.swagger-ui .topbar { display: none }',
customSiteTitle: 'Zurri API Documentation',
swaggerOptions: {
persistAuthorization: true,
},
}));
app.use('/api/auth', authRoutes);
app.use('/api/creator-auth', creatorAuthRoutes);
app.use('/api/users', userRoutes);
app.use('/api/creators', creatorRoutes);
app.use('/api/admin', adminRoutes);
app.use('/api/agents', agentRoutes);
app.use('/api/chat', chatRoutes);
app.use('/api/subscriptions', subscriptionRoutes);
app.use('/api/wallet', walletRoutes);
// Serve frontend static files if they exist
const frontendPath = path.join(__dirname, '../../zurri-mock-frontend/dist');
let frontendExists = false;
try {
const fs = require('fs');
if (fs.existsSync(frontendPath) && fs.existsSync(path.join(frontendPath, 'index.html'))) {
app.use(express.static(frontendPath));
frontendExists = true;
}
} catch (error) {
// Frontend not available, continue without it
}
// Serve React app for all non-API routes (SPA routing)
// This must come after all API routes but before 404 handler
if (frontendExists) {
app.get('*', (req, res, next) => {
// Skip if it's an API, docs, health, or root route
if (req.path.startsWith('/api') || req.path.startsWith('/docs') || req.path.startsWith('/health') || req.path === '/') {
return next();
}
// Serve React app for all other routes (dashboard, wallet, etc.)
res.sendFile(path.join(frontendPath, 'index.html'));
});
}
// 404 handler - only for API routes or if frontend doesn't exist
app.use((req, res) => {
if (req.path.startsWith('/api')) {
res.status(404).json({ error: 'Route not found' });
} else if (!frontendExists) {
res.status(404).send('Not found');
}
});
// Simplified error handler (must be last)
app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
if (process.env.NODE_ENV === 'development') {
console.error('Error:', err.message);
}
if (req.path.startsWith('/api')) {
res.status(500).json({ error: 'Server error' });
} else {
res.status(500).send('Server error');
}
});
export default app;