From 2a8d2cb06abf16939f42c30b44bb32e67c3f307f Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 21 Jan 2026 11:18:13 -0800 Subject: [PATCH] app -> ts --- server/package-lock.json | 47 +++++++++++++++++ server/package.json | 4 ++ server/src/{app.js => app.ts} | 25 +++++++-- server/src/config/controllers.ts | 51 +++++++++++-------- server/src/config/index.ts | 25 --------- server/src/config/services.ts | 12 +++-- server/src/{index.js => index.ts} | 6 +-- .../service/infrastructure/bufferService.ts | 6 +-- ...{settingsService.js => settingsService.ts} | 47 +++++++++-------- server/src/utils/logger.ts | 18 +++++-- 10 files changed, 152 insertions(+), 89 deletions(-) rename server/src/{app.js => app.ts} (69%) delete mode 100644 server/src/config/index.ts rename server/src/{index.js => index.ts} (92%) rename server/src/service/system/{settingsService.js => settingsService.ts} (65%) diff --git a/server/package-lock.json b/server/package-lock.json index 2dd8d23e7..3f5b824b0 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -45,6 +45,9 @@ }, "devDependencies": { "@eslint/js": "^9.17.0", + "@types/compression": "1.8.1", + "@types/cookie-parser": "1.4.10", + "@types/cors": "2.8.19", "@types/dockerode": "^4.0.0", "@types/express": "5.0.3", "@types/gamedig": "^5.0.3", @@ -57,6 +60,7 @@ "@types/nodemailer": "7.0.1", "@types/papaparse": "^5.5.2", "@types/ping": "0.4.4", + "@types/swagger-ui-express": "4.1.8", "c8": "10.1.3", "eslint": "^9.17.0", "eslint-plugin-mocha": "^10.5.0", @@ -4323,6 +4327,17 @@ "@types/node": "*" } }, + "node_modules/@types/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-kCFuWS0ebDbmxs0AXYn6e2r2nrGAb5KwQhknjSPSPgJcGd8+HVSILlUyFhGqML2gk39HcG7D1ydW9/qpYkN00Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/node": "*" + } + }, "node_modules/@types/connect": { "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", @@ -4333,6 +4348,26 @@ "@types/node": "*" } }, + "node_modules/@types/cookie-parser": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.10.tgz", + "integrity": "sha512-B4xqkqfZ8Wek+rCOeRxsjMS9OgvzebEzzLYw7NHYuvzb7IdxOkI0ZHGgeEBX4PUM7QGVvNSK60T3OvWj3YfBRg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/docker-modem": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/@types/docker-modem/-/docker-modem-3.0.6.tgz", @@ -4369,6 +4404,7 @@ "integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", @@ -4649,6 +4685,17 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/swagger-ui-express": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@types/swagger-ui-express/-/swagger-ui-express-4.1.8.tgz", + "integrity": "sha512-AhZV8/EIreHFmBV5wAs0gzJUNq9JbbSXgJLQubCC0jtIo6prnI9MIRRxnU4MZX9RB9yXxF1V4R7jtLl/Wcj31g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/serve-static": "*" + } + }, "node_modules/@types/tough-cookie": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", diff --git a/server/package.json b/server/package.json index 2cbacea39..2421aeb1c 100755 --- a/server/package.json +++ b/server/package.json @@ -57,6 +57,9 @@ }, "devDependencies": { "@eslint/js": "^9.17.0", + "@types/compression": "1.8.1", + "@types/cookie-parser": "1.4.10", + "@types/cors": "2.8.19", "@types/dockerode": "^4.0.0", "@types/express": "5.0.3", "@types/gamedig": "^5.0.3", @@ -69,6 +72,7 @@ "@types/nodemailer": "7.0.1", "@types/papaparse": "^5.5.2", "@types/ping": "0.4.4", + "@types/swagger-ui-express": "4.1.8", "c8": "10.1.3", "eslint": "^9.17.0", "eslint-plugin-mocha": "^10.5.0", diff --git a/server/src/app.js b/server/src/app.ts similarity index 69% rename from server/src/app.js rename to server/src/app.ts index c83726a49..04699964d 100644 --- a/server/src/app.js +++ b/server/src/app.ts @@ -5,12 +5,27 @@ import helmet from "helmet"; import compression from "compression"; import cookieParser from "cookie-parser"; import swaggerUi from "swagger-ui-express"; -import { handleErrors } from "./middleware/handleErrors.js"; -import { setupRoutes } from "./config/routes.js"; -import { generalApiLimiter } from "./middleware/rateLimiter.js"; -import { sanitizeBody, sanitizeQuery } from "./middleware/sanitization.js"; +import { handleErrors } from "@/middleware/handleErrors.js"; +import { generalApiLimiter } from "@/middleware/rateLimiter.js"; +import { sanitizeBody, sanitizeQuery } from "@/middleware/sanitization.js"; +import { setupRoutes } from "@/config/routes.js"; +import { InitializedServices } from "@/config/services.js"; +import { InitializedControllers } from "@/config/controllers.js"; +import { EnvConfig } from "@/service/system/settingsService.js"; -export const createApp = ({ services, controllers, envSettings, frontendPath, openApiSpec }) => { +export const createApp = ({ + services, + controllers, + envSettings, + frontendPath, + openApiSpec, +}: { + services: InitializedServices; + controllers: InitializedControllers; + envSettings: EnvConfig; + frontendPath: string; + openApiSpec: any; +}) => { const allowedOrigin = envSettings.clientHost; const app = express(); app.use(generalApiLimiter); diff --git a/server/src/config/controllers.ts b/server/src/config/controllers.ts index 5ddbf2a06..d72e4f76f 100644 --- a/server/src/config/controllers.ts +++ b/server/src/config/controllers.ts @@ -10,26 +10,35 @@ import StatusPageController from "../controllers/statusPageController.js"; import NotificationController from "../controllers/notificationController.js"; import DiagnosticController from "../controllers/diagnosticController.js"; import IncidentController from "../controllers/incidentController.js"; -import type { InitializedSerivces } from "@/config/services.js"; -export const initializeControllers = (services: InitializedSerivces) => { - const controllers: Record = {}; +import type { InitializedServices } from "@/config/services.js"; - controllers.authController = new AuthController(services.userService); - - controllers.monitorController = new MonitorController(services.monitorService); - - controllers.settingsController = new SettingsController(services.settingsService, services.emailService, services.db); - controllers.checkController = new CheckController(services.checkService); - controllers.inviteController = new InviteController(services.inviteService); - - controllers.maintenanceWindowController = new MaintenanceWindowController(services.maintenanceWindowService); - controllers.queueController = new QueueController(services.jobQueue); - controllers.logController = new LogController(services.logger); - controllers.statusPageController = new StatusPageController(services.db); - controllers.notificationController = new NotificationController(services.notificationsService, services.db, services.monitorsRepository); - controllers.diagnosticController = new DiagnosticController(services.diagnosticService); - - controllers.incidentController = new IncidentController(services.incidentService); - - return controllers; +export interface InitializedControllers { + authController: AuthController; + monitorController: MonitorController; + settingsController: SettingsController; + checkController: CheckController; + inviteController: InviteController; + maintenanceWindowController: MaintenanceWindowController; + queueController: QueueController; + logController: LogController; + statusPageController: StatusPageController; + notificationController: NotificationController; + diagnosticController: DiagnosticController; + incidentController: IncidentController; +} +export const initializeControllers = (services: InitializedServices): InitializedControllers => { + return { + authController: new AuthController(services.userService), + monitorController: new MonitorController(services.monitorService), + settingsController: new SettingsController(services.settingsService, services.emailService, services.db), + checkController: new CheckController(services.checkService), + inviteController: new InviteController(services.inviteService), + maintenanceWindowController: new MaintenanceWindowController(services.maintenanceWindowService), + queueController: new QueueController(services.jobQueue), + logController: new LogController(services.logger), + statusPageController: new StatusPageController(services.db), + notificationController: new NotificationController(services.notificationsService, services.db, services.monitorsRepository), + diagnosticController: new DiagnosticController(services.diagnosticService), + incidentController: new IncidentController(services.incidentService), + }; }; diff --git a/server/src/config/index.ts b/server/src/config/index.ts deleted file mode 100644 index 7ace6f99c..000000000 --- a/server/src/config/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -import dotenv from "dotenv"; - -export interface IEevConfig { - NODE_ENV: string; - JWT_SECRET: string; - PORT: number; - PAGESPEED_API_KEY: string; - SMTP_HOST: string; - SMTP_PORT: number; - SMTP_USER: string; - SMTP_PASS: string; -} - -dotenv.config(); - -export const config: IEevConfig = { - NODE_ENV: process.env.NODE_ENV || "development", - JWT_SECRET: process.env.JWT_SECRET || "your_jwt_secret", - PORT: process.env.PORT ? parseInt(process.env.PORT, 10) : 3000, - PAGESPEED_API_KEY: process.env.PAGESPEED_API_KEY || "", - SMTP_HOST: process.env.SMTP_HOST || "smtp.example.com", - SMTP_PORT: process.env.SMTP_PORT ? parseInt(process.env.SMTP_PORT, 10) : 587, - SMTP_USER: process.env.SMTP_USER || "user@example.com", - SMTP_PASS: process.env.SMTP_PASS || "your_smtp_password", -}; diff --git a/server/src/config/services.ts b/server/src/config/services.ts index 423e23ca5..0cf55590b 100644 --- a/server/src/config/services.ts +++ b/server/src/config/services.ts @@ -92,8 +92,10 @@ import { INotificationsRepository, IIncidentsRepository, } from "@/repositories/index.js"; +import { ILogger } from "@/utils/logger.js"; +import { EnvConfig } from "@/service/system/settingsService.js"; -export type InitializedSerivces = { +export type InitializedServices = { //v1 settingsService: any; translationService: any; @@ -132,10 +134,10 @@ export const initializeServices = async ({ envSettings, settingsService, }: { - logger: any; - envSettings: any; + logger: ILogger; + envSettings: EnvConfig; settingsService: any; -}): Promise => { +}): Promise => { const translationService = new TranslationService(logger); await translationService.initialize(); @@ -205,7 +207,7 @@ export const initializeServices = async ({ checksRepository, }); - const bufferService = new BufferService({ logger, checkService }); + const bufferService = new BufferService({ logger, checkService, settingsService }); const statusService = new StatusService({ db, logger, buffer: bufferService, monitorsRepository }); diff --git a/server/src/index.js b/server/src/index.ts similarity index 92% rename from server/src/index.js rename to server/src/index.ts index 28dc5e8fd..b74404228 100755 --- a/server/src/index.js +++ b/server/src/index.ts @@ -7,12 +7,12 @@ import path from "path"; import fs from "fs"; import { runMigrations } from "./db/migration/index.js"; -import Logger from "./utils/logger.js"; -import SettingsService from "./service/system/settingsService.js"; +import Logger, { ILogger } from "@/utils/logger.js"; +import SettingsService from "@/service/system/settingsService.js"; import AppSettings from "./db/models/AppSettings.js"; const SERVICE_NAME = "Server"; -let logger; +let logger: ILogger; const startApp = async () => { // FE path diff --git a/server/src/service/infrastructure/bufferService.ts b/server/src/service/infrastructure/bufferService.ts index 89cd6a55f..461001800 100755 --- a/server/src/service/infrastructure/bufferService.ts +++ b/server/src/service/infrastructure/bufferService.ts @@ -1,4 +1,3 @@ -import { config } from "@/config/index.js"; import type { Check } from "@/types/index.js"; const SERVICE_NAME = "BufferService"; @@ -12,8 +11,9 @@ class BufferService { private bufferTimer: NodeJS.Timeout | null = null; private checksService: any; - constructor({ logger, checkService }: { logger: any; checkService: any }) { - this.BUFFER_TIMEOUT = config.NODE_ENV === "development" ? 10 : 1000 * 60 * 1; // 1 minute + constructor({ logger, checkService, settingsService }: { logger: any; checkService: any; settingsService: any }) { + this.BUFFER_TIMEOUT = settingsService.getSettings().nodeEnv === "development" ? 10 : 1000 * 60 * 1; // 1 minute + console.log(this.BUFFER_TIMEOUT); this.logger = logger; this.checksService = checkService; this.SERVICE_NAME = SERVICE_NAME; diff --git a/server/src/service/system/settingsService.js b/server/src/service/system/settingsService.ts similarity index 65% rename from server/src/service/system/settingsService.js rename to server/src/service/system/settingsService.ts index cea46f7ed..15f86995d 100755 --- a/server/src/service/system/settingsService.js +++ b/server/src/service/system/settingsService.ts @@ -1,6 +1,17 @@ const SERVICE_NAME = "SettingsService"; -const envConfig = { +export type EnvConfig = { + jwtSecret: string | undefined; + jwtTTL: string | undefined; + systemEmailHost: string | undefined; + nodeEnv: string | undefined; + logLevel: string | undefined; + clientHost: string | undefined; + dbConnectionString: string | undefined; + port: string | undefined; +}; + +const envConfig: EnvConfig = { jwtSecret: process.env.JWT_SECRET, jwtTTL: process.env.TOKEN_TTL, systemEmailHost: process.env.SYSTEM_EMAIL_HOST, @@ -10,19 +21,20 @@ const envConfig = { dbConnectionString: process.env.DB_CONNECTION_STRING, port: process.env.PORT, }; -/** - * SettingsService - * - * This service is responsible for loading and managing the application settings. - */ -class SettingsService { - static SERVICE_NAME = "SettingsService"; - /** - * Constructs a new SettingsService - * @constructor - * @throws {Error} - */ constructor(AppSettings) { +export interface ISettingsService { + readonly serviceName: string; + loadSettings(): EnvConfig; + getSettings(): EnvConfig; + getDBSettings(): Promise>; +} + +class SettingsService implements ISettingsService { + static SERVICE_NAME = "SettingsService"; + private AppSettings: any; + private settings: EnvConfig; + + constructor(AppSettings: any) { this.AppSettings = AppSettings; this.settings = { ...envConfig }; } @@ -31,19 +43,10 @@ class SettingsService { return SettingsService.SERVICE_NAME; } - /** - * Load settings from env settings - * @returns {Object>} The settings. - */ loadSettings() { return this.settings; } - /** - * Get the current settings. - * @returns {Object} The current settings. - * @throws Will throw an error if settings have not been loaded. - */ getSettings() { if (!this.settings) { throw new Error("Settings have not been loaded"); diff --git a/server/src/utils/logger.ts b/server/src/utils/logger.ts index ac1cbbf7c..4053f4a82 100755 --- a/server/src/utils/logger.ts +++ b/server/src/utils/logger.ts @@ -1,6 +1,7 @@ import { createLogger, format, transports, Logger as WinstonLogger } from "winston"; import type { Logform } from "winston"; import dotenv from "dotenv"; +import { EnvConfig } from "@/service/system/settingsService.js"; dotenv.config(); const SERVICE_NAME = "Logger"; @@ -18,19 +19,26 @@ interface LogEntry extends LogConfig { timestamp: string; } -interface EnvSettings { - logLevel?: string; +export interface ILogger { + readonly serviceName: string; + info(config: LogConfig): void; + warn(config: LogConfig): void; + error(config: LogConfig): void; + debug(config: LogConfig): void; + cacheLog(entry: LogEntry): void; + getLogs(): LogEntry[]; + buildLogEntry(level: string, config: LogConfig): LogEntry; } -class Logger { +class Logger implements ILogger { static SERVICE_NAME = SERVICE_NAME; private logger: WinstonLogger; - private envSettings: EnvSettings; + private envSettings: Partial; private logCache: LogEntry[]; private maxCacheSize: number; - constructor({ envSettings }: { envSettings: EnvSettings }) { + constructor({ envSettings }: { envSettings: Partial }) { this.envSettings = envSettings; this.logCache = []; this.maxCacheSize = 1000;