From b511cde849dfbc13ef3b7e3dce4f79dc98130d8a Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 22 Jan 2026 21:49:49 +0000 Subject: [PATCH] remove final js --- server/src/config/services.ts | 15 +-- server/src/db/{MongoDB.js => MongoDB.ts} | 24 +++-- server/src/db/utils/seedDb.js | 75 ------------- server/src/service/business/checkService.ts | 20 ++-- .../src/service/business/incidentService.ts | 8 +- server/src/service/business/inviteService.ts | 12 ++- .../business/maintenanceWindowService.ts | 12 ++- server/src/service/business/monitorService.ts | 16 +-- server/src/service/business/userService.ts | 1 - .../service/infrastructure/errorService.js | 101 ------------------ ...{imageProcessing.js => imageProcessing.ts} | 7 +- server/src/validation/{joi.js => joi.ts} | 12 +-- 12 files changed, 53 insertions(+), 250 deletions(-) rename server/src/db/{MongoDB.js => MongoDB.ts} (67%) delete mode 100755 server/src/db/utils/seedDb.js delete mode 100644 server/src/service/infrastructure/errorService.js rename server/src/utils/{imageProcessing.js => imageProcessing.ts} (74%) rename server/src/validation/{joi.js => joi.ts} (97%) diff --git a/server/src/config/services.ts b/server/src/config/services.ts index a6678dbe5..06701491d 100644 --- a/server/src/config/services.ts +++ b/server/src/config/services.ts @@ -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 => { // 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, diff --git a/server/src/db/MongoDB.js b/server/src/db/MongoDB.ts similarity index 67% rename from server/src/db/MongoDB.js rename to server/src/db/MongoDB.ts index 97498f13a..d62f4bbad 100755 --- a/server/src/db/MongoDB.js +++ b/server/src/db/MongoDB.ts @@ -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, }); diff --git a/server/src/db/utils/seedDb.js b/server/src/db/utils/seedDb.js deleted file mode 100755 index cdfe3675c..000000000 --- a/server/src/db/utils/seedDb.js +++ /dev/null @@ -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; diff --git a/server/src/service/business/checkService.ts b/server/src/service/business/checkService.ts index 3a932ed3f..42788eba8 100644 --- a/server/src/service/business/checkService.ts +++ b/server/src/service/business/checkService.ts @@ -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); diff --git a/server/src/service/business/incidentService.ts b/server/src/service/business/incidentService.ts index 37a02e30d..d30492bcb 100644 --- a/server/src/service/business/incidentService.ts +++ b/server/src/service/business/incidentService.ts @@ -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; diff --git a/server/src/service/business/inviteService.ts b/server/src/service/business/inviteService.ts index cdb860fba..eee0f993c 100644 --- a/server/src/service/business/inviteService.ts +++ b/server/src/service/business/inviteService.ts @@ -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, + }); } }; diff --git a/server/src/service/business/maintenanceWindowService.ts b/server/src/service/business/maintenanceWindowService.ts index 561d97480..faf0ee943 100644 --- a/server/src/service/business/maintenanceWindowService.ts +++ b/server/src/service/business/maintenanceWindowService.ts @@ -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) => { diff --git a/server/src/service/business/monitorService.ts b/server/src/service/business/monitorService.ts index 4f97bdf0f..513fc2a82 100644 --- a/server/src/service/business/monitorService.ts +++ b/server/src/service/business/monitorService.ts @@ -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 => { 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, userId: string, teamId: string): Promise => { 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; diff --git a/server/src/service/business/userService.ts b/server/src/service/business/userService.ts index b9883f594..a0273af99 100644 --- a/server/src/service/business/userService.ts +++ b/server/src/service/business/userService.ts @@ -48,7 +48,6 @@ class UserService { settingsService: any; logger: any; jwt: any; - errorService: any; jobQueue: ISuperSimpleQueue; monitorsRepository: IMonitorsRepository; usersRepository: IUsersRepository; diff --git a/server/src/service/infrastructure/errorService.js b/server/src/service/infrastructure/errorService.js deleted file mode 100644 index 680bb3765..000000000 --- a/server/src/service/infrastructure/errorService.js +++ /dev/null @@ -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; diff --git a/server/src/utils/imageProcessing.js b/server/src/utils/imageProcessing.ts similarity index 74% rename from server/src/utils/imageProcessing.js rename to server/src/utils/imageProcessing.ts index 470a5c27e..442f0d6da 100755 --- a/server/src/utils/imageProcessing.js +++ b/server/src/utils/imageProcessing.ts @@ -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) diff --git a/server/src/validation/joi.js b/server/src/validation/joi.ts similarity index 97% rename from server/src/validation/joi.js rename to server/src/validation/joi.ts index 474feebe5..8871c29e2 100755 --- a/server/src/validation/joi.js +++ b/server/src/validation/joi.ts @@ -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; }),