import Fastify from "fastify"; import cors from "@fastify/cors"; import rateLimit from "@fastify/rate-limit"; import type { AppConfig } from "./config.js"; import { corePlugin } from "./plugins/core.js"; import { authPlugin } from "./plugins/auth.js"; import { storagePlugin } from "./plugins/storage.js"; import { healthRoutes } from "./routes/health.js"; import { authRoutes } from "./routes/auth.js"; import { meRoutes } from "./routes/me.js"; import { householdRoutes } from "./routes/households.js"; import { inventoryRoutes } from "./routes/inventory.js"; import { scanRoutes } from "./routes/scans.js"; import { recipeRoutes } from "./routes/recipes.js"; import { mealRoutes } from "./routes/meals.js"; import { shoppingRoutes } from "./routes/shopping.js"; import { planningRoutes } from "./routes/planning.js"; import { recommendationRoutes } from "./routes/recommendations.js"; import { memoryRoutes } from "./routes/memory.js"; import { budgetRoutes } from "./routes/budget.js"; import { subscriptionRoutes } from "./routes/subscriptions.js"; import { communityRoutes } from "./routes/community.js"; import { adminRoutes } from "./routes/admin.js"; import { adminAnalyticsRoutes } from "./routes/admin-analytics.js"; import { analyticsRoutes } from "./routes/analytics.js"; declare module "fastify" { interface FastifyInstance { routeCatalog: Array<{ method: string; url: string }>; } } export async function buildServer(config: AppConfig) { const app = Fastify({ logger: { level: config.LOG_LEVEL, redact: ["req.headers.authorization", "req.headers.cookie"], }, trustProxy: true, bodyLimit: 1024 * 1024, }); // Endpointkatalog för /docs – hooken måste ligga före route-registreringen. const routeCatalog: Array<{ method: string; url: string }> = []; app.decorate("routeCatalog", routeCatalog); app.addHook("onRoute", (route) => { const methods = Array.isArray(route.method) ? route.method : [route.method]; for (const method of methods) { if (method === "HEAD" || method === "OPTIONS") continue; routeCatalog.push({ method, url: route.url }); } }); await app.register(corePlugin, { config }); await app.register(cors, { origin: config.CORS_ORIGINS.split(",").map((o) => o.trim()), credentials: true, }); await app.register(rateLimit, { global: true, // Överstyrbar för lasttest (scripts/loadtest.mjs) – produktion använder default 300/min. max: Number(process.env.RATE_LIMIT_MAX ?? 300), timeWindow: "1 minute", keyGenerator: (req) => `${req.ip}`, }); await app.register(authPlugin); await app.register(storagePlugin); await app.register(healthRoutes); await app.register(authRoutes); await app.register(meRoutes); await app.register(householdRoutes); await app.register(inventoryRoutes); await app.register(scanRoutes); await app.register(recipeRoutes); await app.register(mealRoutes); await app.register(shoppingRoutes); await app.register(planningRoutes); await app.register(recommendationRoutes); await app.register(memoryRoutes); await app.register(budgetRoutes); await app.register(subscriptionRoutes); await app.register(communityRoutes); await app.register(adminRoutes); await app.register(adminAnalyticsRoutes); await app.register(analyticsRoutes); return app; }