From 6cd46445d272030cab45fceb333e85b2ebd73505 Mon Sep 17 00:00:00 2001 From: Nico <47644445+nicotsx@users.noreply.github.com> Date: Mon, 22 Dec 2025 17:34:27 +0100 Subject: [PATCH] feat: server timeout env (#219) * feat: increase server idle timeout and allow to modify it via env * chore(app): move auth middleware to individual controller To clean up de main app.ts file * chore: remove console.log --- app/server/app.ts | 6 ------ app/server/core/config.ts | 5 ++++- app/server/index.ts | 12 +++++++++++- app/server/modules/backups/backups.controller.ts | 2 ++ app/server/modules/events/events.controller.ts | 3 ++- .../notifications/notifications.controller.ts | 2 ++ .../modules/repositories/repositories.controller.ts | 2 ++ app/server/modules/system/system.controller.ts | 2 +- app/server/modules/volumes/volume.controller.ts | 2 ++ 9 files changed, 26 insertions(+), 10 deletions(-) diff --git a/app/server/app.ts b/app/server/app.ts index b2d12d0..93ed52a 100644 --- a/app/server/app.ts +++ b/app/server/app.ts @@ -55,12 +55,6 @@ export const createApp = () => { ) .get("healthcheck", (c) => c.json({ status: "ok" })) .route("/api/v1/auth", authController) - .use("/api/v1/volumes/*", requireAuth) - .use("/api/v1/repositories/*", requireAuth) - .use("/api/v1/backups/*", requireAuth) - .use("/api/v1/notifications/*", requireAuth) - .use("/api/v1/system/*", requireAuth) - .use("/api/v1/events/*", requireAuth) .route("/api/v1/volumes", volumeController) .route("/api/v1/repositories", repositoriesController) .route("/api/v1/backups", backupScheduleController) diff --git a/app/server/core/config.ts b/app/server/core/config.ts index 356b341..81320db 100644 --- a/app/server/core/config.ts +++ b/app/server/core/config.ts @@ -4,17 +4,20 @@ import "dotenv/config"; const envSchema = type({ NODE_ENV: type.enumerated("development", "production", "test").default("production"), SERVER_IP: 'string = "localhost"', + SERVER_IDLE_TIMEOUT: 'string.integer.parse = "60"', }).pipe((s) => ({ __prod__: s.NODE_ENV === "production", environment: s.NODE_ENV, serverIp: s.SERVER_IP, + serverIdleTimeout: s.SERVER_IDLE_TIMEOUT, })); const parseConfig = (env: unknown) => { const result = envSchema(env); if (result instanceof type.errors) { - throw new Error(`Invalid environment variables: ${result.toString()}`); + console.error(`Environment variable validation failed: ${result.toString()}`); + throw new Error("Invalid environment variables"); } return result; diff --git a/app/server/index.ts b/app/server/index.ts index d1c3209..5e290a6 100644 --- a/app/server/index.ts +++ b/app/server/index.ts @@ -7,6 +7,7 @@ import { shutdown } from "./modules/lifecycle/shutdown"; import { REQUIRED_MIGRATIONS } from "./core/constants"; import { validateRequiredMigrations } from "./modules/lifecycle/checkpoint"; import { createApp } from "./app"; +import { config } from "./core/config"; const app = createApp(); @@ -33,4 +34,13 @@ process.on("SIGINT", async () => { process.exit(0); }); -export default await createHonoServer({ app, port: 4096 }); +export default await createHonoServer({ + app, + port: 4096, + customBunServer: { + idleTimeout: config.serverIdleTimeout, + error(err) { + logger.error(`[Bun.serve] Server error: ${err.message}`); + }, + }, +}); diff --git a/app/server/modules/backups/backups.controller.ts b/app/server/modules/backups/backups.controller.ts index e9fa9f7..fefeacb 100644 --- a/app/server/modules/backups/backups.controller.ts +++ b/app/server/modules/backups/backups.controller.ts @@ -41,8 +41,10 @@ import { type UpdateScheduleNotificationsDto, } from "../notifications/notifications.dto"; import { notificationsService } from "../notifications/notifications.service"; +import { requireAuth } from "../auth/auth.middleware"; export const backupScheduleController = new Hono() + .use(requireAuth) .get("/", listBackupSchedulesDto, async (c) => { const schedules = await backupsService.listSchedules(); diff --git a/app/server/modules/events/events.controller.ts b/app/server/modules/events/events.controller.ts index cd40b84..4661e13 100644 --- a/app/server/modules/events/events.controller.ts +++ b/app/server/modules/events/events.controller.ts @@ -2,8 +2,9 @@ import { Hono } from "hono"; import { streamSSE } from "hono/streaming"; import { logger } from "../../utils/logger"; import { serverEvents } from "../../core/events"; +import { requireAuth } from "../auth/auth.middleware"; -export const eventsController = new Hono().get("/", (c) => { +export const eventsController = new Hono().use(requireAuth).get("/", (c) => { logger.info("Client connected to SSE endpoint"); return streamSSE(c, async (stream) => { diff --git a/app/server/modules/notifications/notifications.controller.ts b/app/server/modules/notifications/notifications.controller.ts index 643d03b..42a4b0e 100644 --- a/app/server/modules/notifications/notifications.controller.ts +++ b/app/server/modules/notifications/notifications.controller.ts @@ -17,8 +17,10 @@ import { type UpdateDestinationDto, } from "./notifications.dto"; import { notificationsService } from "./notifications.service"; +import { requireAuth } from "../auth/auth.middleware"; export const notificationsController = new Hono() + .use(requireAuth) .get("/destinations", listDestinationsDto, async (c) => { const destinations = await notificationsService.listDestinations(); return c.json(destinations, 200); diff --git a/app/server/modules/repositories/repositories.controller.ts b/app/server/modules/repositories/repositories.controller.ts index a53a3a2..0023dfa 100644 --- a/app/server/modules/repositories/repositories.controller.ts +++ b/app/server/modules/repositories/repositories.controller.ts @@ -31,8 +31,10 @@ import { } from "./repositories.dto"; import { repositoriesService } from "./repositories.service"; import { getRcloneRemoteInfo, listRcloneRemotes } from "../../utils/rclone"; +import { requireAuth } from "../auth/auth.middleware"; export const repositoriesController = new Hono() + .use(requireAuth) .get("/", listRepositoriesDto, async (c) => { const repositories = await repositoriesService.listRepositories(); diff --git a/app/server/modules/system/system.controller.ts b/app/server/modules/system/system.controller.ts index 62d7aad..58dbcc0 100644 --- a/app/server/modules/system/system.controller.ts +++ b/app/server/modules/system/system.controller.ts @@ -14,6 +14,7 @@ import { usersTable } from "../../db/schema"; import { eq } from "drizzle-orm"; export const systemController = new Hono() + .use(requireAuth) .get("/info", systemInfoDto, async (c) => { const info = await systemService.getSystemInfo(); @@ -22,7 +23,6 @@ export const systemController = new Hono() .post( "/restic-password", downloadResticPasswordDto, - requireAuth, validator("json", downloadResticPasswordBodySchema), async (c) => { const user = c.get("user"); diff --git a/app/server/modules/volumes/volume.controller.ts b/app/server/modules/volumes/volume.controller.ts index 7c97260..ccffeb1 100644 --- a/app/server/modules/volumes/volume.controller.ts +++ b/app/server/modules/volumes/volume.controller.ts @@ -24,8 +24,10 @@ import { } from "./volume.dto"; import { volumeService } from "./volume.service"; import { getVolumePath } from "./helpers"; +import { requireAuth } from "../auth/auth.middleware"; export const volumeController = new Hono() + .use(requireAuth) .get("/", listVolumesDto, async (c) => { const volumes = await volumeService.listVolumes();