All checks were successful
Build and Push Docker Image / build (push) Successful in 15s
all server output now prefixed with ISO timestamp and level [INFO/WARN/ERROR]. logs requests, scan start/complete, job lifecycle, errors. skips noisy SSE endpoints. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
78 lines
3.1 KiB
TypeScript
78 lines
3.1 KiB
TypeScript
import { Hono } from 'hono';
|
|
import { serveStatic } from 'hono/bun';
|
|
import { cors } from 'hono/cors';
|
|
import { getDb, getConfig } from './db/index';
|
|
import { log } from './lib/log';
|
|
|
|
import setupRoutes from './api/setup';
|
|
import scanRoutes from './api/scan';
|
|
import reviewRoutes from './api/review';
|
|
import executeRoutes from './api/execute';
|
|
import nodesRoutes from './api/nodes';
|
|
import subtitlesRoutes from './api/subtitles';
|
|
import dashboardRoutes from './api/dashboard';
|
|
|
|
const app = new Hono();
|
|
|
|
// ─── CORS (dev: Vite on :5173 talks to Hono on :3000) ────────────────────────
|
|
|
|
app.use('/api/*', cors({ origin: ['http://localhost:5173', 'http://localhost:3000'] }));
|
|
|
|
// ─── Request logging ──────────────────────────────────────────────────────────
|
|
|
|
app.use('/api/*', async (c, next) => {
|
|
const start = Date.now();
|
|
await next();
|
|
const ms = Date.now() - start;
|
|
// Skip noisy SSE/polling endpoints
|
|
if (c.req.path.endsWith('/events')) return;
|
|
log(`${c.req.method} ${c.req.path} → ${c.res.status} (${ms}ms)`);
|
|
});
|
|
|
|
// ─── API routes ───────────────────────────────────────────────────────────────
|
|
|
|
import pkg from '../package.json';
|
|
|
|
app.get('/api/version', (c) => c.json({ version: pkg.version }));
|
|
app.route('/api/dashboard', dashboardRoutes);
|
|
app.route('/api/setup', setupRoutes);
|
|
app.route('/api/scan', scanRoutes);
|
|
app.route('/api/review', reviewRoutes);
|
|
app.route('/api/execute', executeRoutes);
|
|
app.route('/api/subtitles', subtitlesRoutes);
|
|
app.route('/api/nodes', nodesRoutes);
|
|
|
|
// ─── Static assets (production: serve Vite build) ────────────────────────────
|
|
|
|
app.use('/assets/*', serveStatic({ root: './dist' }));
|
|
app.use('/favicon.ico', serveStatic({ path: './dist/favicon.ico' }));
|
|
|
|
// ─── SPA fallback ─────────────────────────────────────────────────────────────
|
|
// All non-API routes serve the React index.html so TanStack Router handles them.
|
|
|
|
app.get('*', (c) => {
|
|
const accept = c.req.header('Accept') ?? '';
|
|
if (c.req.path.startsWith('/api/')) return c.notFound();
|
|
// In dev the Vite server handles the SPA. In production serve dist/index.html.
|
|
try {
|
|
const html = Bun.file('./dist/index.html').text();
|
|
return html.then((text) => c.html(text));
|
|
} catch {
|
|
return c.text('Run `bun build` first to generate the frontend.', 503);
|
|
}
|
|
});
|
|
|
|
// ─── Start ────────────────────────────────────────────────────────────────────
|
|
|
|
const port = Number(process.env.PORT ?? '3000');
|
|
|
|
log(`netfelix-audio-fix v${pkg.version} starting on http://localhost:${port}`);
|
|
|
|
getDb();
|
|
|
|
export default {
|
|
port,
|
|
fetch: app.fetch,
|
|
idleTimeout: 0,
|
|
};
|