remove final js

This commit is contained in:
Alex Holliday committed 2026-01-22 21:49:49 +00:00
1 parent ce322a8e28
commit b511cde849
12 files changed
+53 -250

No files matched your search

+1 -14
View File
@@ -13,7 +13,6 @@ import {
MatrixProvider,
INotificationsService,
} from "@/service/index.js";
import ErrorService from "../service/infrastructure/errorService.js";
import SuperSimpleQueueHelper from "../service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js";
import SuperSimpleQueue from "../service/infrastructure/SuperSimpleQueue/SuperSimpleQueue.js";
import UserService from "../service/business/userService.js";
@@ -98,7 +97,6 @@ export type InitializedServices = {
maintenanceWindowService: any;
monitorService: any;
incidentService: any;
errorService: any;
logger: any;
notificationsService: INotificationsService;
statusPageService: IStatusPageService;
@@ -131,10 +129,7 @@ export const initializeServices = async ({
}): Promise<InitializedServices> => {
// Create DB
const db = new MongoDB({
logger,
envSettings,
});
const db = new MongoDB(logger, envSettings);
await db.connect();
@@ -165,18 +160,15 @@ export const initializeServices = async ({
settingsService,
});
const emailService = new EmailService(settingsService, fs, path, compile, mjml2html, nodemailer, logger);
const errorService = new ErrorService();
const incidentService = new IncidentService({
logger,
errorService,
incidentsRepository,
monitorsRepository,
usersRepository,
});
const checkService = new CheckService({
errorService,
monitorsRepository,
logger,
checksRepository,
@@ -229,7 +221,6 @@ export const initializeServices = async ({
settingsService,
logger,
jwt,
errorService,
jobQueue: superSimpleQueue,
monitorsRepository,
usersRepository,
@@ -244,10 +235,8 @@ export const initializeServices = async ({
invitesRepository,
settingsService,
emailService,
errorService,
});
const maintenanceWindowService = new MaintenanceWindowService({
errorService,
monitorsRepository,
maintenanceWindowsRepository,
});
@@ -255,7 +244,6 @@ export const initializeServices = async ({
jobQueue: superSimpleQueue,
emailService,
logger,
errorService,
games,
monitorsRepository,
checksRepository,
@@ -281,7 +269,6 @@ export const initializeServices = async ({
maintenanceWindowService,
monitorService,
incidentService,
errorService,
logger,
notificationsService,
statusPageService,
@@ -1,10 +1,16 @@
import mongoose from "mongoose";
import AppSettings from "./models/AppSettings.js";
import { runMigrations } from "./migration/index.js";
import { ILogger } from "@/utils/logger.js";
import { EnvConfig } from "@/service/system/settingsService.js";
const SERVICE_NAME = "MongoDB";
class MongoDB {
static SERVICE_NAME = "MongoDB";
static SERVICE_NAME = SERVICE_NAME;
constructor({ logger, envSettings }) {
private logger: ILogger;
private envSettings: EnvConfig;
constructor(logger: ILogger, envSettings: EnvConfig) {
this.logger = logger;
this.envSettings = envSettings;
}
@@ -35,15 +41,15 @@ class MongoDB {
this.logger.info({
message: "Connected to MongoDB",
service: this.SERVICE_NAME,
service: SERVICE_NAME,
method: "connect",
});
await runMigrations();
} catch (error) {
} catch (error: any) {
this.logger.error({
message: error.message,
service: this.SERVICE_NAME,
service: SERVICE_NAME,
method: "connect",
stack: error.stack,
});
@@ -53,14 +59,14 @@ class MongoDB {
disconnect = async () => {
try {
this.logger.info({ message: "Disconnecting from MongoDB" });
this.logger.info({ message: "Disconnecting from MongoDB", service: SERVICE_NAME, method: "disconnect" });
await mongoose.disconnect();
this.logger.info({ message: "Disconnected from MongoDB" });
this.logger.info({ message: "Disconnected from MongoDB", service: SERVICE_NAME, method: "disconnect" });
return;
} catch (error) {
} catch (error: any) {
this.logger.error({
message: error.message,
service: this.SERVICE_NAME,
service: SERVICE_NAME,
method: "disconnect",
stack: error.stack,
});
-75
View File
@@ -1,75 +0,0 @@
import Monitor from "../models/Monitor.js";
import Check from "../models/Check.js";
import { logger } from "../../../utils/logger.js";
const generateRandomUrl = () => {
const domains = ["example.com", "test.org", "demo.net", "sample.io", "mock.dev"];
const paths = ["api", "status", "health", "ping", "check"];
return `https://${domains[Math.floor(Math.random() * domains.length)]}/${paths[Math.floor(Math.random() * paths.length)]}`;
};
const generateChecks = (monitorId, teamId, count) => {
const checks = [];
const endTime = new Date(Date.now() - 10 * 60 * 1000); // 10 minutes ago
const startTime = new Date(endTime - count * 60 * 1000); // count minutes before endTime
for (let i = 0; i < count; i++) {
const timestamp = new Date(startTime.getTime() + i * 60 * 1000);
const status = Math.random() > 0.05; // 95% chance of being up
checks.push({
monitorId,
teamId,
status,
responseTime: Math.floor(Math.random() * 1000), // Random response time between 0-1000ms
createdAt: timestamp,
updatedAt: timestamp,
});
}
return checks;
};
const seedDb = async (userId, teamId) => {
try {
logger.info({
message: "Deleting all monitors and checks",
service: "seedDb",
method: "seedDb",
});
await Monitor.deleteMany({});
await Check.deleteMany({});
logger.info({
message: "Adding monitors",
service: "DB",
method: "seedDb",
});
for (let i = 0; i < 300; i++) {
const monitor = await Monitor.create({
name: `Monitor ${i}`,
url: generateRandomUrl(),
type: "http",
userId,
teamId,
interval: 60000,
active: false,
});
logger.info({
message: `Adding monitor and checks for monitor ${i}`,
service: "DB",
method: "seedDb",
});
const checks = generateChecks(monitor._id, teamId, 10000);
await Check.insertMany(checks);
}
} catch (error) {
logger.error({
message: "Error seeding DB",
service: "DB",
method: "seedDb",
stack: error.stack,
});
}
};
export default seedDb;
+8 -12
View File
@@ -1,3 +1,4 @@
import { requireTeamId } from "@/controllers/controllerUtils.js";
import { IChecksRepository, IMonitorsRepository } from "@/repositories/index.js";
import type { MonitorType, MonitorStatusResponse, CheckErrorInfo, Check } from "@/types/index.js";
import type { HardwareStatusPayload, PageSpeedStatusPayload } from "@/types/network.js";
@@ -9,22 +10,18 @@ const SERVICE_NAME = "checkService";
class CheckService {
static SERVICE_NAME = SERVICE_NAME;
private errorService: any;
private monitorsRepository: IMonitorsRepository;
private checksRepository: IChecksRepository;
private logger: any;
constructor({
errorService,
monitorsRepository,
logger,
checksRepository,
}: {
errorService: any;
monitorsRepository: IMonitorsRepository;
logger: any;
checksRepository: IChecksRepository;
}) {
this.errorService = errorService;
this.monitorsRepository = monitorsRepository;
this.logger = logger;
this.checksRepository = checksRepository;
@@ -112,11 +109,10 @@ class CheckService {
getChecksByMonitor = async ({ monitorId, query, teamId }: { monitorId: string; query: any; teamId: string }) => {
if (!monitorId) {
throw this.errorService.createBadRequestError("No monitor ID in request");
throw new AppError({ message: "No monitor ID in request", service: SERVICE_NAME, method: "getChecksByMonitor", status: 400 });
}
if (!teamId) {
throw this.errorService.createBadRequestError("No team ID in request");
throw new AppError({ message: "No team ID in request", service: SERVICE_NAME, method: "getChecksByMonitor", status: 400 });
}
// For verificaiton, throws an error if monitor doesn't belong to team
@@ -136,7 +132,7 @@ class CheckService {
let { sortOrder, dateRange, filter, page, rowsPerPage } = query;
if (!teamId) {
throw this.errorService.createBadRequestError("No team ID in request");
throw new AppError({ message: "No team ID in request", service: SERVICE_NAME, method: "getChecksByTeam", status: 400 });
}
const parsedPage = page ? parseInt(page) : page;
@@ -148,7 +144,7 @@ class CheckService {
getChecksSummaryByTeamId = async ({ teamId }: { teamId: string }) => {
if (!teamId) {
throw this.errorService.createBadRequestError("No team ID in request");
throw new AppError({ message: "No team ID in request", service: SERVICE_NAME, method: "getChecksSummaryByTeamId", status: 400 });
}
const summary = await this.checksRepository.findSummaryByTeamId(teamId);
return summary;
@@ -156,11 +152,11 @@ class CheckService {
deleteChecks = async ({ monitorId, teamId }: { monitorId: string; teamId: string }) => {
if (!monitorId) {
throw this.errorService.createBadRequestError("No monitor ID in request");
throw new AppError({ message: "No monitor ID in request", service: SERVICE_NAME, method: "deleteChecks", status: 400 });
}
if (!teamId) {
throw this.errorService.createBadRequestError("No team ID in request");
throw new AppError({ message: "No team ID in request", service: SERVICE_NAME, method: "deleteChecks", status: 400 });
}
// For verificaiton, throws an error if monitor doesn't belong to team
@@ -171,7 +167,7 @@ class CheckService {
};
deleteChecksByTeamId = async ({ teamId }: { teamId: string }) => {
if (!teamId) {
throw this.errorService.createBadRequestError("No team ID in request");
throw new AppError({ message: "No team ID in request", service: SERVICE_NAME, method: "deleteChecksByTeamId", status: 400 });
}
const deletedCount = await this.checksRepository.deleteByTeamId(teamId);
@@ -18,26 +18,22 @@ class IncidentService {
static SERVICE_NAME = SERVICE_NAME;
private logger: any;
private errorService: any;
private incidentsRepository: IIncidentsRepository;
private monitorsRepository: IMonitorsRepository;
private usersRepository: IUsersRepository;
constructor({
logger,
errorService,
incidentsRepository,
monitorsRepository,
usersRepository,
}: {
logger: any;
errorService: any;
incidentsRepository: IIncidentsRepository;
monitorsRepository: IMonitorsRepository;
usersRepository: IUsersRepository;
}) {
this.logger = logger;
this.errorService = errorService;
this.incidentsRepository = incidentsRepository;
this.monitorsRepository = monitorsRepository;
this.usersRepository = usersRepository;
@@ -139,7 +135,7 @@ class IncidentService {
) => {
try {
if (!teamId) {
throw this.errorService.createBadRequestError("No team ID in request");
throw new AppError({ message: "No team ID in request", service: SERVICE_NAME, method: "getIncidentsByTeam", status: 400 });
}
const startDate = dateRangeLookup[dateRange];
@@ -177,7 +173,7 @@ class IncidentService {
getIncidentSummary = async (teamId: string, limit?: string) => {
try {
if (!teamId) {
throw this.errorService.createBadRequestError(" team ID in request");
throw new AppError({ message: "No team ID in request", service: SERVICE_NAME, method: "getIncidentSummary", status: 400 });
}
const parsedLimit = limit && Number.isFinite(parseInt(limit, 10)) ? parseInt(limit, 10) : 10;
+7 -5
View File
@@ -1,5 +1,6 @@
import type { Invite } from "@/types/index.js";
import type { IInvitesRepository } from "@/repositories/index.js";
import { AppError } from "@/utils/AppError.js";
const SERVICE_NAME = "inviteService";
@@ -8,24 +9,20 @@ class InviteService {
private settingsService: any;
private emailService: any;
private errorService: any;
private invitesRepository: IInvitesRepository;
constructor({
invitesRepository,
settingsService,
emailService,
errorService,
}: {
invitesRepository: IInvitesRepository;
settingsService: any;
emailService: any;
errorService: any;
}) {
this.invitesRepository = invitesRepository;
this.settingsService = settingsService;
this.emailService = emailService;
this.errorService = errorService;
}
get serviceName() {
@@ -48,7 +45,12 @@ class InviteService {
});
const result = await this.emailService.sendEmail(invite.email, "Welcome to Uptime Monitor", html);
if (!result) {
throw this.errorService.createServerError("Failed to send invite e-mail... Please verify your settings.");
throw new AppError({
message: "Failed to send invite e-mail... Please verify your settings.",
service: SERVICE_NAME,
method: "sendInviteEmail",
status: 500,
});
}
};
@@ -1,24 +1,21 @@
import { IMaintenanceWindowsRepository, IMonitorsRepository } from "@/repositories/index.js";
import { ParseBoolean } from "@/utils/utils.js";
import { AppError } from "@/utils/AppError.js";
const SERVICE_NAME = "maintenanceWindowService";
class MaintenanceWindowService {
static SERVICE_NAME = SERVICE_NAME;
private errorService: any;
private monitorsRepository: IMonitorsRepository;
private maintenanceWindowsRepository: IMaintenanceWindowsRepository;
constructor({
errorService,
monitorsRepository,
maintenanceWindowsRepository,
}: {
errorService: any;
monitorsRepository: IMonitorsRepository;
maintenanceWindowsRepository: IMaintenanceWindowsRepository;
}) {
this.errorService = errorService;
this.monitorsRepository = monitorsRepository;
this.maintenanceWindowsRepository = maintenanceWindowsRepository;
}
@@ -34,7 +31,12 @@ class MaintenanceWindowService {
const unauthorizedMonitors = monitors.filter((monitor) => monitor.teamId !== teamId);
if (unauthorizedMonitors.length > 0) {
throw this.errorService.createAuthorizationError();
throw new AppError({
message: "Unauthorized to create maintenance window for one or more monitors",
service: SERVICE_NAME,
method: "createMaintenanceWindow",
status: 403,
});
}
const dbTransactions = monitorIds.map((monitorId: string) => {
+5 -11
View File
@@ -1,4 +1,3 @@
import { createMonitorsBodyValidation } from "@/validation/joi.js";
import { NormalizeData, NormalizeDataUptimeDetails } from "@/utils/dataUtils.js";
import { type Monitor } from "@/types/index.js";
import type {
@@ -12,8 +11,7 @@ import type { IChecksRepository, IMonitorsRepository, IMonitorStatsRepository, I
import fs from "fs";
import { fileURLToPath } from "url";
import path from "path";
import { AppError } from "../infrastructure/errorService.js";
import { AppError } from "@/utils/AppError.js";
import { ISuperSimpleQueue } from "../infrastructure/SuperSimpleQueue/SuperSimpleQueue.js";
const SERVICE_NAME = "MonitorService";
@@ -75,7 +73,6 @@ export class MonitorService implements IMonitorService {
private jobQueue: ISuperSimpleQueue;
private emailService: any;
private logger: any;
private errorService: any;
private games: any;
private monitorsRepository: IMonitorsRepository;
private checksRepository: IChecksRepository;
@@ -86,7 +83,6 @@ export class MonitorService implements IMonitorService {
jobQueue,
emailService,
logger,
errorService,
games,
monitorsRepository,
checksRepository,
@@ -96,7 +92,6 @@ export class MonitorService implements IMonitorService {
jobQueue: ISuperSimpleQueue;
emailService: any;
logger: any;
errorService: any;
games: any;
monitorsRepository: IMonitorsRepository;
checksRepository: IChecksRepository;
@@ -106,7 +101,6 @@ export class MonitorService implements IMonitorService {
this.jobQueue = jobQueue;
this.emailService = emailService;
this.logger = logger;
this.errorService = errorService;
this.games = games;
this.monitorsRepository = monitorsRepository;
this.checksRepository = checksRepository;
@@ -146,7 +140,7 @@ export class MonitorService implements IMonitorService {
createMonitor = async (teamId: string, userId: string, body: Monitor): Promise<void> => {
const monitor = await this.monitorsRepository.create(body, teamId, userId);
if (!monitor) {
throw new AppError("Failed to create monitor", 500);
throw new AppError({ message: "Failed to create monitor", status: 500, service: SERVICE_NAME, method: "createMonitor" });
}
this.jobQueue.addJob(monitor.id, monitor);
@@ -155,7 +149,7 @@ export class MonitorService implements IMonitorService {
createBulkMonitors = async (monitors: Array<Monitor>, userId: string, teamId: string): Promise<Monitor[] | null> => {
const createdMonitors = await this.monitorsRepository.createBulkMonitors(monitors);
if (!monitors || monitors.length === 0) {
throw new AppError("Failed to create monitors", 500);
throw new AppError({ message: "Failed to create monitors", status: 500, service: SERVICE_NAME, method: "createBulkMonitors" });
}
await Promise.all(createdMonitors.map((monitor) => this.jobQueue.addJob(monitor.id, monitor)));
@@ -445,7 +439,7 @@ export class MonitorService implements IMonitorService {
const messageId = await this.emailService.sendEmail(to, subject, html);
if (!messageId) {
throw this.errorService.createServerError("Failed to send test email.");
throw new AppError({ message: "Failed to send test email.", service: SERVICE_NAME, method: "sendTestEmail", status: 500 });
}
return messageId;
@@ -455,7 +449,7 @@ export class MonitorService implements IMonitorService {
const monitors = await this.monitorsRepository.findByTeamId(teamId, {});
if (!monitors || monitors.length === 0) {
throw this.errorService.createNotFoundError("No monitors to export");
throw new AppError({ message: "No monitors found to export.", service: SERVICE_NAME, method: "exportMonitorsToJSON", status: 400 });
}
return monitors;
@@ -48,7 +48,6 @@ class UserService {
settingsService: any;
logger: any;
jwt: any;
errorService: any;
jobQueue: ISuperSimpleQueue;
monitorsRepository: IMonitorsRepository;
usersRepository: IUsersRepository;
@@ -1,101 +0,0 @@
export class AppError extends Error {
constructor(message, status = 500, service = null, method = null, details = null) {
super(message);
this.status = status;
this.service = service;
this.method = method;
this.details = details;
Error.captureStackTrace(this, this.constructor);
}
}
class ValidationError extends AppError {
constructor(message, details = null, service = null, method = null) {
super(message, 422, service, method, details);
}
}
class AuthenticationError extends AppError {
constructor(message, details = null, service = null, method = null) {
super(message, 401, service, method, details);
}
}
class AuthorizationError extends AppError {
constructor(message, details = null, service = null, method = null) {
super(message, 403, service, method, details);
}
}
class NotFoundError extends AppError {
constructor(message, details = null, service = null, method = null) {
super(message, 404, service, method, details);
}
}
class ConflictError extends AppError {
constructor(message, details = null, service = null, method = null) {
super(message, 409, service, method, details);
}
}
class DatabaseError extends AppError {
constructor(message, details = null, service = null, method = null) {
super(message, 500, service, method, details);
}
}
class BadRequestError extends AppError {
constructor(message, details = null, service = null, method = null) {
super(message, 400, service, method, details);
}
}
const SERVICE_NAME = "ErrorService";
class ErrorService {
static SERVICE_NAME = SERVICE_NAME;
constructor() {}
get serviceName() {
return ErrorService.SERVICE_NAME;
}
createError = (message, status = 500, service = null, method = null, details = null) => {
return new AppError(message, status, service, method, details);
};
createValidationError = (message, details = null, service = null, method = null) => {
return new ValidationError(message, details, service, method);
};
createAuthenticationError = (message = "Unauthorized", details = null, service = null, method = null) => {
return new AuthenticationError(message, details, service, method);
};
createAuthorizationError = (message, details = null, service = null, method = null) => {
return new AuthorizationError(message, details, service, method);
};
createNotFoundError = (message, details = null, service = null, method = null) => {
return new NotFoundError(message, details, service, method);
};
createConflictError = (message, details = null, service = null, method = null) => {
return new ConflictError(message, details, service, method);
};
createDatabaseError = (message, details = null, service = null, method = null) => {
return new DatabaseError(message, details, service, method);
};
createServerError = (message, details = null, service = null, method = null) => {
return this.createError(message, 500, service, method, details);
};
createBadRequestError = (message = "BadRequest", details = null, service = null, method = null) => {
return new BadRequestError(message, details, service, method);
};
}
export default ErrorService;
@@ -1,9 +1,6 @@
import sharp from "sharp";
/**
* Generates a 64 * 64 pixel image from a given image
* @param {} file
*/
const GenerateAvatarImage = async (file) => {
const GenerateAvatarImage = async (file: Express.Multer.File) => {
try {
// Resize to target 64 * 64
let resizedImageBuffer = await sharp(file.buffer)
@@ -1,14 +1,14 @@
import joi from "joi";
import { UserRoles } from "@/types/user.js";
import joi, { type CustomHelpers } from "joi";
import { type UserRole, UserRoles } from "@/types/user.js";
//****************************************
// Custom Validators
//****************************************
const roleValidatior = (role) => (value, helpers) => {
const hasRole = role.some((role) => value.includes(role));
const roleValidatior = (role: UserRole[]) => (value: UserRole[], helpers: CustomHelpers) => {
const hasRole = role.some((role: UserRole) => value.includes(role));
if (!hasRole) {
throw new joi.ValidationError(`You do not have the required authorization. Required roles: ${role.join(", ")}`);
return helpers.error("any.invalid", { message: `You do not have the required authorization. Required roles: ${role.join(", ")}` });
}
return value;
};
@@ -45,7 +45,7 @@ const registrationBodyValidation = joi.object({
.custom((value, helpers) => {
const lowercasedValue = value.toLowerCase();
if (value !== lowercasedValue) {
return helpers.message("Email must be in lowercase");
return helpers.message({ custom: "Email must be in lowercase" });
}
return lowercasedValue;
}),