Complete application scaffolding with: - Backend: Node.js + Fastify + sql.js (SQLite) - Frontend: SvelteKit + Tailwind CSS - Scraper engine with parallel fan-out, rate limiting, cheerio-based parsing - Store management with CSS selector config and per-store test pages - Docker setup for single-command deployment Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
38 lines
1.1 KiB
TypeScript
38 lines
1.1 KiB
TypeScript
import type { FastifyPluginAsync } from 'fastify';
|
|
import fs from 'node:fs';
|
|
import { config } from '../config.js';
|
|
import { getDatabase } from '../db/connection.js';
|
|
|
|
function queryOne(sql: string, params: any[] = []): any | undefined {
|
|
const db = getDatabase();
|
|
const stmt = db.prepare(sql);
|
|
if (params.length) stmt.bind(params);
|
|
let result: any;
|
|
if (stmt.step()) {
|
|
result = stmt.getAsObject();
|
|
}
|
|
stmt.free();
|
|
return result;
|
|
}
|
|
|
|
export const healthRoutes: FastifyPluginAsync = async (app) => {
|
|
app.get('/health', async () => {
|
|
const storeCount = queryOne('SELECT COUNT(*) as count FROM stores')?.count ?? 0;
|
|
const enabledCount = queryOne('SELECT COUNT(*) as count FROM stores WHERE enabled = 1')?.count ?? 0;
|
|
|
|
let dbSizeBytes = 0;
|
|
try {
|
|
const stats = fs.statSync(config.databasePath);
|
|
dbSizeBytes = stats.size;
|
|
} catch {
|
|
// DB file may not exist yet
|
|
}
|
|
|
|
return {
|
|
status: 'ok',
|
|
stores: { total: storeCount, enabled: enabledCount },
|
|
database: { sizeBytes: dbSizeBytes, sizeMB: Math.round(dbSizeBytes / 1024 / 1024 * 100) / 100 },
|
|
};
|
|
});
|
|
};
|