54 lines
1.6 KiB
TypeScript
54 lines
1.6 KiB
TypeScript
import Fastify from 'fastify';
|
|
import path from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
import fastifyStatic from '@fastify/static';
|
|
import { AppStatus } from '@ludops/shared';
|
|
import { db } from './db/index.js';
|
|
import { visits } from './db/schemas.js';
|
|
import { sql } from 'drizzle-orm';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
const fastify = Fastify({ logger: true });
|
|
|
|
// API Route
|
|
fastify.get('/api/status', async (): Promise<AppStatus> => {
|
|
const [result] = await db.select({ count: sql<number>`count(*)` }).from(visits);
|
|
|
|
return { status: 'OK', version: '1.0.0', database: true, totalVisits: Number(result.count) };
|
|
});
|
|
|
|
// Serve Frontend (Vite Dist)
|
|
const webDistPath = process.env.NODE_ENV === 'production'
|
|
? path.join(__dirname, '../web-dist') // Adjusted for the flattened Docker structure
|
|
: path.join(__dirname, '../../web/dist');
|
|
|
|
fastify.register(fastifyStatic, {
|
|
root: webDistPath,
|
|
prefix: '/',
|
|
});
|
|
|
|
// SPA Routing: Redirect everything else to index.html
|
|
fastify.setNotFoundHandler((req, reply) => {
|
|
if (req.url.startsWith('/api')) {
|
|
reply.code(404).send({ error: 'Not Found' });
|
|
} else {
|
|
reply.sendFile('index.html');
|
|
}
|
|
});
|
|
|
|
fastify.listen({ port: 3000, host: '0.0.0.0' });
|
|
|
|
fastify.addHook('onRequest', async (request) => {
|
|
try {
|
|
if (request.url.startsWith('/api')) {
|
|
await db.insert(visits).values({
|
|
ip: request.ip,
|
|
userAgent: request.headers['user-agent'] || '',
|
|
});
|
|
}
|
|
} catch (error) {
|
|
fastify.log.error(`Failed to log visit: ${error}`);
|
|
}
|
|
}); |