require('dotenv').config(); const Fastify = require('fastify'); const cors = require('@fastify/cors'); const swagger = require('@fastify/swagger'); const swaggerUi = require('@fastify/swagger-ui'); const accountRoutes = require('./routes/accounts'); const domainRoutes = require('./routes/domains'); const dnsRoutes = require('./routes/dns'); const { startTokenScheduler } = require('../lib/token-scheduler'); const { startWorker } = require('../lib/job-worker'); const { execSync } = require('child_process'); async function setupDatabase() { console.log('Setting up database...'); try { execSync('npx prisma generate', { stdio: 'inherit' }); execSync('npx prisma db push --accept-data-loss', { stdio: 'inherit' }); console.log('Database setup complete'); } catch (err) { console.error('Database setup failed:', err.message); throw err; } } const fastify = Fastify({ logger: true }); async function build() { await fastify.register(cors, { origin: true }); await fastify.register(swagger, { openapi: { info: { title: 'Zone.ID Domain Registration API', description: 'API for managing zone.id and nett.to domain registrations and DNS records', version: '1.0.0' }, servers: [ { url: 'http://localhost:5000', description: 'Development server' } ], components: { securitySchemes: { apiKey: { type: 'apiKey', name: 'X-API-Key', in: 'header' } } } } }); await fastify.register(swaggerUi, { routePrefix: '/docs', uiConfig: { docExpansion: 'list', deepLinking: false } }); fastify.addHook('onRequest', async (request, reply) => { const publicRoutes = ['/docs', '/docs/', '/docs/json', '/docs/yaml', '/health', '/']; const isPublic = publicRoutes.some(route => request.url.startsWith(route)); if (isPublic) return; const expectedApiKey = process.env.API_KEY; if (!expectedApiKey) { return; } const apiKey = request.headers['x-api-key']; if (!apiKey || apiKey !== expectedApiKey) { reply.code(401).send({ error: 'Invalid or missing API key' }); return; } }); fastify.get('/', { schema: { hide: true } }, async () => { return { name: 'Zone.ID Domain Registration API', version: '1.0.0', docs: '/docs' }; }); fastify.get('/health', { schema: { hide: true } }, async () => { return { status: 'ok' }; }); await fastify.register(accountRoutes, { prefix: '/api/accounts' }); await fastify.register(domainRoutes, { prefix: '/api/domains' }); await fastify.register(dnsRoutes, { prefix: '/api/dns' }); return fastify; } async function start() { try { await setupDatabase(); const port = parseInt(process.env.PORT) || 5000; const host = process.env.HOST || '0.0.0.0'; const server = await build(); await server.listen({ port, host }); console.log(`Server running at http://${host}:${port}`); console.log(`API Documentation at http://${host}:${port}/docs`); startTokenScheduler(); console.log('Token auto-refresh scheduler started (checks every 6 hours)'); startWorker(); console.log('Domain job worker started (polling every 5 seconds)'); } catch (err) { console.error(err); process.exit(1); } } start();