Merge pull request #3418 from bluewave-labs/fix/middleware-typing

fix: middleware typing
This commit is contained in:
Alexander Holliday authored and GitHub committed 2026-03-13 11:41:50 -07:00
commit d80e232a10
7 files changed
+44 -28

No files matched your search

+1
View File
@@ -37,6 +37,7 @@ export default [
},
},
rules: {
"@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], // Ignore unused variables that start with '_'
"@typescript-eslint/no-explicit-any": "warn", // Warn on 'any' types
"mocha/max-top-level-suites": "warn", // Warn if there are too many top-level suites instead of failing
},
+1 -1
View File
@@ -1,5 +1,5 @@
import { Schema, model, type Types } from "mongoose";
import type { MaintenanceWindow, DurationUnit } from "@/types/maintenanceWindow.js";
import type { MaintenanceWindow } from "@/types/maintenanceWindow.js";
type MaintenanceWindowDocumentBase = Omit<MaintenanceWindow, "id" | "monitorId" | "teamId" | "start" | "end" | "createdAt" | "updatedAt"> & {
monitorId: Types.ObjectId;
+9 -6
View File
@@ -1,15 +1,18 @@
import type { NextFunction, Request, Response } from "express";
import { logger } from "@/utils/logger.js";
import { AppError } from "@/utils/AppError.js";
const handleErrors = (error: any, req: Request, res: Response, next: NextFunction) => {
const status = error.status || 500;
const message = error.message || "Server error";
const service = error.service || "unknownService";
const handleErrors = (error: unknown, req: Request, res: Response, _next: NextFunction) => {
const status = error instanceof AppError ? error.status || 500 : 500;
const message = error instanceof AppError ? error.message : "Server error";
const service = error instanceof AppError ? error.service : "unknownService";
const method = error instanceof AppError ? error.method : "unknownMethod";
logger.error({
message: message,
service: service,
method: error.method,
stack: error.stack,
method: method,
stack: error instanceof AppError ? error.stack : undefined,
details: error instanceof AppError ? error.details : undefined,
});
res.status(status).json({
status,
+12 -5
View File
@@ -1,7 +1,9 @@
import type { Request, Response, NextFunction } from "express";
import DOMPurify from "isomorphic-dompurify";
export const sanitizeInput = (input: any, options = {}) => {
export function sanitizeInput(input: string, options?: object): string;
export function sanitizeInput(input: unknown, options?: object): unknown;
export function sanitizeInput(input: unknown, options = {}): unknown {
if (typeof input !== "string") {
return input;
}
@@ -15,9 +17,9 @@ export const sanitizeInput = (input: any, options = {}) => {
};
return DOMPurify.sanitize(input, defaultConfig);
};
}
export const sanitizeObject = (obj: Record<string, any>, options = {}): Record<string, any> => {
export const sanitizeObject = (obj: unknown, options = {}): unknown => {
if (typeof obj !== "object" || obj === null) {
return obj;
}
@@ -26,7 +28,7 @@ export const sanitizeObject = (obj: Record<string, any>, options = {}): Record<s
return obj.map((item) => sanitizeObject(item, options));
}
const sanitized: Record<string, any> = {};
const sanitized: Record<string, unknown> = {};
for (const [key, value] of Object.entries(obj)) {
if (typeof value === "string") {
sanitized[key] = sanitizeInput(value, options);
@@ -52,7 +54,12 @@ export const sanitizeBody = (options = {}): ((req: Request, res: Response, next:
export const sanitizeQuery = (options = {}): ((req: Request, res: Response, next: NextFunction) => void) => {
return (req: Request, res: Response, next: NextFunction) => {
if (req.query && typeof req.query === "object") {
req.query = sanitizeObject(req.query, options);
for (const key of Object.keys(req.query)) {
const value = req.query[key];
if (typeof value === "string") {
req.query[key] = sanitizeInput(value, options);
}
}
}
next();
};
+11 -5
View File
@@ -3,10 +3,15 @@ import { NextFunction, Request, Response } from "express";
import jwt from "jsonwebtoken";
import { AppError } from "@/utils/AppError.js";
import { Settings } from "@/types/settings.js";
import type { User } from "@/types/user.js";
const SERVICE_NAME = "verifyJWT";
const TOKEN_PREFIX = "Bearer ";
const isUser = (payload: unknown): payload is User => {
return typeof payload === "object" && payload !== null && "id" in payload && "teamId" in payload && "role" in payload;
};
export const createVerifyJWT = (settingsService: { getSettings: () => Settings }) => {
return (req: Request, res: Response, next: NextFunction) => {
const token = req.headers["authorization"];
@@ -31,21 +36,22 @@ export const createVerifyJWT = (settingsService: { getSettings: () => Settings }
next(error);
return;
}
jwt.verify(parsedToken, jwtSecret, (err: any, decoded: any) => {
jwt.verify(parsedToken, jwtSecret, (err: jwt.VerifyErrors | null, decoded: jwt.JwtPayload | string | undefined) => {
if (err) {
const error = new AppError({
message: "Failed to authenticate token",
details: err,
message: err instanceof Error ? err.message : "Failed to authenticate token",
status: 401,
service: SERVICE_NAME,
details: err instanceof Error ? { error: err } : undefined,
method: "verifyJWT",
});
next(error);
return;
} else {
// Token is valid, carry on
} else if (isUser(decoded)) {
req.user = decoded;
next();
} else {
next(new AppError({ message: "Invalid token payload", status: 401, service: SERVICE_NAME, method: "verifyJWT" }));
}
});
};
@@ -360,8 +360,7 @@ export class StatusService implements IStatusService {
};
} catch (error: unknown) {
throw new AppError({
message: `Failed to update monitor status: ${error instanceof Error ? error.message : "Unknown error"}`,
details: `Error updating status for monitor with id ${check.metadata.monitorId}`,
message: `Failed to update monitor with id ${check.metadata.monitorId} with status: ${error instanceof Error ? error.message : "Unknown error"}`,
service: SERVICE_NAME,
method: "updateMonitorStatus",
});
+9 -9
View File
@@ -1,18 +1,18 @@
export interface AppErrorConfig {
message: string;
message?: string;
status?: number;
service?: string | null;
method?: string | null;
details?: unknown;
service?: string;
method?: string;
details?: Record<string, unknown> | undefined;
}
export class AppError extends Error {
private status: number;
private service: string | null;
private method: string | null;
private details: unknown;
readonly status: number;
readonly service: string;
readonly method: string;
readonly details: Record<string, unknown> | undefined;
constructor({ message, status = 500, service = null, method = null, details = null }: AppErrorConfig) {
constructor({ message, status = 500, service = "unknownService", method = "unknownMethod", details = undefined }: AppErrorConfig) {
super(message);
this.status = status;
this.service = service;