mirror of
https://github.com/kjanat/livedash-node.git
synced 2026-01-16 16:52:08 +01:00
feat: complete development environment setup and code quality improvements
- Set up pre-commit hooks with husky and lint-staged for automated code quality - Improved TypeScript type safety by replacing 'any' types with proper generics - Fixed markdown linting violations (MD030 spacing) across all documentation - Fixed compound adjective hyphenation in technical documentation - Fixed invalid JSON union syntax in API documentation examples - Automated code formatting and linting on commit - Enhanced error handling with better type constraints - Configured biome and markdownlint for consistent code style - All changes verified with successful production build
This commit is contained in:
@ -17,7 +17,11 @@ export class APIError extends Error {
|
||||
message: string,
|
||||
public readonly statusCode: number = 500,
|
||||
public readonly code: string = "INTERNAL_ERROR",
|
||||
public readonly details?: any,
|
||||
public readonly details?:
|
||||
| Record<string, unknown>
|
||||
| string[]
|
||||
| string
|
||||
| number,
|
||||
public readonly logLevel: "info" | "warn" | "error" = "error"
|
||||
) {
|
||||
super(message);
|
||||
@ -100,7 +104,10 @@ export class ConflictError extends APIError {
|
||||
* Database Error - for database operation failures
|
||||
*/
|
||||
export class DatabaseError extends APIError {
|
||||
constructor(message = "Database operation failed", details?: any) {
|
||||
constructor(
|
||||
message = "Database operation failed",
|
||||
details?: Record<string, unknown> | string
|
||||
) {
|
||||
super(message, 500, "DATABASE_ERROR", details, "error");
|
||||
}
|
||||
}
|
||||
@ -112,7 +119,7 @@ export class ExternalServiceError extends APIError {
|
||||
constructor(
|
||||
service: string,
|
||||
message = "External service error",
|
||||
details?: any
|
||||
details?: Record<string, unknown>
|
||||
) {
|
||||
super(
|
||||
`${service} service error: ${message}`,
|
||||
@ -138,7 +145,11 @@ function shouldExposeError(error: unknown): boolean {
|
||||
/**
|
||||
* Log error with appropriate level
|
||||
*/
|
||||
function logError(error: unknown, requestId: string, context?: any): void {
|
||||
function logError(
|
||||
error: unknown,
|
||||
requestId: string,
|
||||
context?: Record<string, unknown>
|
||||
): void {
|
||||
const logData = {
|
||||
requestId,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
@ -170,7 +181,7 @@ function logError(error: unknown, requestId: string, context?: any): void {
|
||||
export function handleAPIError(
|
||||
error: unknown,
|
||||
requestId?: string,
|
||||
context?: any
|
||||
context?: Record<string, unknown>
|
||||
): NextResponse {
|
||||
const id = requestId || crypto.randomUUID();
|
||||
|
||||
@ -220,7 +231,7 @@ export function handleAPIError(
|
||||
/**
|
||||
* Async error handler for promise chains
|
||||
*/
|
||||
export function asyncErrorHandler<T extends any[], R>(
|
||||
export function asyncErrorHandler<T extends readonly unknown[], R>(
|
||||
fn: (...args: T) => Promise<R>
|
||||
) {
|
||||
return async (...args: T): Promise<R> => {
|
||||
@ -237,7 +248,7 @@ export function asyncErrorHandler<T extends any[], R>(
|
||||
/**
|
||||
* Error boundary for API route handlers
|
||||
*/
|
||||
export function withErrorHandling<T extends any[], R>(
|
||||
export function withErrorHandling<T extends readonly unknown[], R>(
|
||||
handler: (...args: T) => Promise<NextResponse> | NextResponse
|
||||
) {
|
||||
return async (...args: T): Promise<NextResponse> => {
|
||||
|
||||
@ -91,10 +91,10 @@ export interface APIHandlerOptions {
|
||||
/**
|
||||
* API handler function type
|
||||
*/
|
||||
export type APIHandler<T = any> = (
|
||||
export type APIHandler<T = unknown> = (
|
||||
context: APIContext,
|
||||
validatedData?: any,
|
||||
validatedQuery?: any
|
||||
validatedData?: unknown,
|
||||
validatedQuery?: unknown
|
||||
) => Promise<T>;
|
||||
|
||||
/**
|
||||
@ -226,7 +226,7 @@ async function validateInput<T>(
|
||||
if (error instanceof SyntaxError) {
|
||||
throw new ValidationError(["Invalid JSON in request body"]);
|
||||
}
|
||||
throw new ValidationError(error as any);
|
||||
throw new ValidationError(error as z.ZodError);
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,7 +239,7 @@ function validateQuery<T>(request: NextRequest, schema: z.ZodSchema<T>): T {
|
||||
const query = Object.fromEntries(searchParams.entries());
|
||||
return schema.parse(query);
|
||||
} catch (error) {
|
||||
throw new ValidationError(error as any);
|
||||
throw new ValidationError(error as z.ZodError);
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,7 +285,7 @@ function addCORSHeaders(
|
||||
/**
|
||||
* Main API handler factory
|
||||
*/
|
||||
export function createAPIHandler<T = any>(
|
||||
export function createAPIHandler<T = unknown>(
|
||||
handler: APIHandler<T>,
|
||||
options: APIHandlerOptions = {}
|
||||
) {
|
||||
@ -368,7 +368,7 @@ export function createAPIHandler<T = any>(
|
||||
/**
|
||||
* Utility function for GET endpoints
|
||||
*/
|
||||
export function createGETHandler<T = any>(
|
||||
export function createGETHandler<T = unknown>(
|
||||
handler: APIHandler<T>,
|
||||
options: Omit<APIHandlerOptions, "validateInput"> = {}
|
||||
) {
|
||||
@ -381,7 +381,7 @@ export function createGETHandler<T = any>(
|
||||
/**
|
||||
* Utility function for POST endpoints
|
||||
*/
|
||||
export function createPOSTHandler<T = any>(
|
||||
export function createPOSTHandler<T = unknown>(
|
||||
handler: APIHandler<T>,
|
||||
options: APIHandlerOptions = {}
|
||||
) {
|
||||
@ -394,7 +394,7 @@ export function createPOSTHandler<T = any>(
|
||||
/**
|
||||
* Utility function for authenticated endpoints
|
||||
*/
|
||||
export function createAuthenticatedHandler<T = any>(
|
||||
export function createAuthenticatedHandler<T = unknown>(
|
||||
handler: APIHandler<T>,
|
||||
options: APIHandlerOptions = {}
|
||||
) {
|
||||
@ -408,7 +408,7 @@ export function createAuthenticatedHandler<T = any>(
|
||||
/**
|
||||
* Utility function for admin endpoints
|
||||
*/
|
||||
export function createAdminHandler<T = any>(
|
||||
export function createAdminHandler<T = unknown>(
|
||||
handler: APIHandler<T>,
|
||||
options: APIHandlerOptions = {}
|
||||
) {
|
||||
|
||||
@ -58,10 +58,11 @@ export {
|
||||
UserRole,
|
||||
} from "./handler";
|
||||
|
||||
import { createPermissionChecker, type Permission } from "./authorization";
|
||||
// Re-import types for use in functions below
|
||||
import type { APIContext, APIHandler, APIHandlerOptions } from "./handler";
|
||||
import { createAPIHandler } from "./handler";
|
||||
import { Permission, createPermissionChecker } from "./authorization";
|
||||
|
||||
// Response utilities
|
||||
export {
|
||||
type APIResponse,
|
||||
|
||||
@ -19,7 +19,7 @@ export interface APIResponseMeta {
|
||||
version?: string;
|
||||
}
|
||||
|
||||
export interface APIResponse<T = any> {
|
||||
export interface APIResponse<T = unknown> {
|
||||
success: boolean;
|
||||
data?: T;
|
||||
error?: string;
|
||||
|
||||
@ -47,7 +47,7 @@ export interface CacheStats {
|
||||
/**
|
||||
* High-performance memory cache with advanced features
|
||||
*/
|
||||
export class PerformanceCache<K extends {} = string, V = any> {
|
||||
export class PerformanceCache<K extends {} = string, V = unknown> {
|
||||
private cache: LRUCache<K, CacheEntry<V>>;
|
||||
private stats: {
|
||||
hits: number;
|
||||
@ -245,7 +245,7 @@ class CacheManager {
|
||||
/**
|
||||
* Create or get a named cache instance
|
||||
*/
|
||||
getCache<K extends {} = string, V = any>(
|
||||
getCache<K extends {} = string, V = unknown>(
|
||||
name: string,
|
||||
options: CacheOptions = {}
|
||||
): PerformanceCache<K, V> {
|
||||
|
||||
@ -13,7 +13,7 @@ import { TIME } from "../constants";
|
||||
export interface DeduplicationOptions {
|
||||
ttl?: number; // How long to keep results cached
|
||||
maxPending?: number; // Maximum pending requests per key
|
||||
keyGenerator?: (...args: any[]) => string;
|
||||
keyGenerator?: (...args: unknown[]) => string;
|
||||
timeout?: number; // Request timeout
|
||||
}
|
||||
|
||||
@ -94,7 +94,7 @@ export class RequestDeduplicator {
|
||||
/**
|
||||
* Memoize a function with deduplication
|
||||
*/
|
||||
memoize<Args extends any[], Return>(
|
||||
memoize<Args extends readonly unknown[], Return>(
|
||||
fn: (...args: Args) => Promise<Return>,
|
||||
options: DeduplicationOptions = {}
|
||||
) {
|
||||
@ -212,7 +212,7 @@ export class RequestDeduplicator {
|
||||
/**
|
||||
* Generate a key from function arguments
|
||||
*/
|
||||
private generateKey(...args: any[]): string {
|
||||
private generateKey(...args: unknown[]): string {
|
||||
try {
|
||||
return JSON.stringify(args);
|
||||
} catch {
|
||||
@ -351,7 +351,9 @@ class DeduplicationManager {
|
||||
ReturnType<RequestDeduplicator["getStats"]>
|
||||
> = {};
|
||||
|
||||
for (const [name, deduplicator] of Array.from(this.deduplicators.entries())) {
|
||||
for (const [name, deduplicator] of Array.from(
|
||||
this.deduplicators.entries()
|
||||
)) {
|
||||
stats[name] = deduplicator.getStats();
|
||||
}
|
||||
|
||||
@ -427,7 +429,7 @@ export class DeduplicationUtils {
|
||||
/**
|
||||
* Create a deduplicated version of an async function
|
||||
*/
|
||||
static deduplicate<T extends any[], R>(
|
||||
static deduplicate<T extends readonly unknown[], R>(
|
||||
fn: (...args: T) => Promise<R>,
|
||||
deduplicatorName = "default",
|
||||
options: DeduplicationOptions = {}
|
||||
@ -464,7 +466,7 @@ export class DeduplicationUtils {
|
||||
options
|
||||
);
|
||||
|
||||
descriptor.value = function (...args: any[]) {
|
||||
descriptor.value = function (...args: unknown[]) {
|
||||
const key = `${target.constructor.name}.${propertyKey}:${JSON.stringify(args)}`;
|
||||
return deduplicator.execute(
|
||||
key,
|
||||
|
||||
@ -5,10 +5,10 @@
|
||||
* caching, and deduplication into existing services and API endpoints.
|
||||
*/
|
||||
|
||||
import { PerformanceUtils, performanceMonitor } from "./monitor";
|
||||
import { caches, CacheUtils } from "./cache";
|
||||
import { deduplicators, DeduplicationUtils } from "./deduplication";
|
||||
import type { NextRequest, NextResponse } from "next/server";
|
||||
import { CacheUtils, caches } from "./cache";
|
||||
import { DeduplicationUtils, deduplicators } from "./deduplication";
|
||||
import { PerformanceUtils, performanceMonitor } from "./monitor";
|
||||
|
||||
/**
|
||||
* Performance integration options
|
||||
@ -235,8 +235,8 @@ export function enhanceAPIRoute(
|
||||
export function PerformanceEnhanced(
|
||||
options: PerformanceIntegrationOptions = {}
|
||||
) {
|
||||
return function <T extends new (...args: any[]) => {}>(constructor: T) {
|
||||
return class extends constructor {
|
||||
return <T extends new (...args: any[]) => {}>(constructor: T) =>
|
||||
class extends constructor {
|
||||
constructor(...args: any[]) {
|
||||
super(...args);
|
||||
|
||||
@ -259,7 +259,6 @@ export function PerformanceEnhanced(
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -268,11 +267,11 @@ export function PerformanceEnhanced(
|
||||
export function PerformanceOptimized(
|
||||
options: PerformanceIntegrationOptions = {}
|
||||
) {
|
||||
return function (
|
||||
return (
|
||||
target: unknown,
|
||||
propertyKey: string,
|
||||
descriptor: PropertyDescriptor
|
||||
) {
|
||||
) => {
|
||||
const originalMethod = descriptor.value;
|
||||
|
||||
if (typeof originalMethod !== "function") {
|
||||
@ -280,7 +279,7 @@ export function PerformanceOptimized(
|
||||
}
|
||||
|
||||
descriptor.value = enhanceServiceMethod(
|
||||
`${(target as any).constructor.name}.${propertyKey}`,
|
||||
`${(target as { constructor: { name: string } }).constructor.name}.${propertyKey}`,
|
||||
originalMethod,
|
||||
options
|
||||
);
|
||||
@ -293,15 +292,15 @@ export function PerformanceOptimized(
|
||||
* Simple caching decorator
|
||||
*/
|
||||
export function Cached(
|
||||
cacheName: string = "default",
|
||||
cacheName = "default",
|
||||
ttl: number = 5 * 60 * 1000,
|
||||
keyGenerator?: (...args: unknown[]) => string
|
||||
) {
|
||||
return function (
|
||||
return (
|
||||
target: unknown,
|
||||
propertyKey: string,
|
||||
descriptor: PropertyDescriptor
|
||||
) {
|
||||
) => {
|
||||
const originalMethod = descriptor.value;
|
||||
|
||||
if (typeof originalMethod !== "function") {
|
||||
@ -309,14 +308,14 @@ export function Cached(
|
||||
}
|
||||
|
||||
descriptor.value = CacheUtils.cached(
|
||||
`${(target as any).constructor.name}.${propertyKey}`,
|
||||
`${(target as { constructor: { name: string } }).constructor.name}.${propertyKey}`,
|
||||
originalMethod,
|
||||
{
|
||||
ttl,
|
||||
keyGenerator:
|
||||
keyGenerator ||
|
||||
((...args) =>
|
||||
`${(target as any).constructor.name}.${propertyKey}:${JSON.stringify(args)}`),
|
||||
`${(target as { constructor: { name: string } }).constructor.name}.${propertyKey}:${JSON.stringify(args)}`),
|
||||
}
|
||||
);
|
||||
|
||||
@ -328,7 +327,7 @@ export function Cached(
|
||||
* Simple deduplication decorator
|
||||
*/
|
||||
export function Deduplicated(
|
||||
deduplicatorName: string = "default",
|
||||
deduplicatorName = "default",
|
||||
ttl: number = 2 * 60 * 1000
|
||||
) {
|
||||
return DeduplicationUtils.deduplicatedMethod(deduplicatorName, { ttl });
|
||||
@ -349,15 +348,18 @@ function mergeOptions(
|
||||
overrides: PerformanceIntegrationOptions
|
||||
): PerformanceIntegrationOptions {
|
||||
return {
|
||||
cache: defaults.cache && overrides.cache
|
||||
? { ...defaults.cache, ...overrides.cache }
|
||||
: defaults.cache || overrides.cache,
|
||||
deduplication: defaults.deduplication && overrides.deduplication
|
||||
? { ...defaults.deduplication, ...overrides.deduplication }
|
||||
: defaults.deduplication || overrides.deduplication,
|
||||
monitoring: defaults.monitoring && overrides.monitoring
|
||||
? { ...defaults.monitoring, ...overrides.monitoring }
|
||||
: defaults.monitoring || overrides.monitoring,
|
||||
cache:
|
||||
defaults.cache && overrides.cache
|
||||
? { ...defaults.cache, ...overrides.cache }
|
||||
: defaults.cache || overrides.cache,
|
||||
deduplication:
|
||||
defaults.deduplication && overrides.deduplication
|
||||
? { ...defaults.deduplication, ...overrides.deduplication }
|
||||
: defaults.deduplication || overrides.deduplication,
|
||||
monitoring:
|
||||
defaults.monitoring && overrides.monitoring
|
||||
? { ...defaults.monitoring, ...overrides.monitoring }
|
||||
: defaults.monitoring || overrides.monitoring,
|
||||
};
|
||||
}
|
||||
|
||||
@ -367,7 +369,9 @@ function mergeOptions(
|
||||
export function createEnhancedService<T>(
|
||||
ServiceClass: new (...args: unknown[]) => T,
|
||||
options: PerformanceIntegrationOptions = {}
|
||||
): new (...args: unknown[]) => T {
|
||||
): new (
|
||||
...args: unknown[]
|
||||
) => T {
|
||||
return PerformanceEnhanced(options)(ServiceClass as never);
|
||||
}
|
||||
|
||||
@ -436,10 +440,7 @@ export function getPerformanceIntegrationStatus() {
|
||||
* Initialize performance systems
|
||||
*/
|
||||
export function initializePerformanceSystems(
|
||||
options: {
|
||||
monitoring?: boolean;
|
||||
monitoringInterval?: number;
|
||||
} = {}
|
||||
options: { monitoring?: boolean; monitoringInterval?: number } = {}
|
||||
) {
|
||||
if (options.monitoring !== false) {
|
||||
const interval = options.monitoringInterval || 30000;
|
||||
|
||||
@ -777,7 +777,7 @@ export class PerformanceUtils {
|
||||
throw new Error("Measured decorator can only be applied to methods");
|
||||
}
|
||||
|
||||
descriptor.value = async function (...args: any[]) {
|
||||
descriptor.value = async function (...args: unknown[]) {
|
||||
const { result, duration } = await PerformanceUtils.measureAsync(
|
||||
metricName,
|
||||
() => originalMethod.apply(this, args)
|
||||
|
||||
@ -5,14 +5,14 @@
|
||||
* to improve system performance based on real-time metrics.
|
||||
*/
|
||||
|
||||
import {
|
||||
performanceMonitor,
|
||||
type PerformanceMetrics,
|
||||
type Bottleneck,
|
||||
} from "./monitor";
|
||||
import { cacheManager, type CacheStats } from "./cache";
|
||||
import { deduplicationManager } from "./deduplication";
|
||||
import { TIME } from "../constants";
|
||||
import { type CacheStats, cacheManager } from "./cache";
|
||||
import { deduplicationManager } from "./deduplication";
|
||||
import {
|
||||
type Bottleneck,
|
||||
type PerformanceMetrics,
|
||||
performanceMonitor,
|
||||
} from "./monitor";
|
||||
|
||||
/**
|
||||
* Optimization action types
|
||||
@ -40,8 +40,8 @@ export interface OptimizationResult {
|
||||
success: boolean;
|
||||
message: string;
|
||||
metrics?: {
|
||||
before: any;
|
||||
after: any;
|
||||
before: Record<string, unknown>;
|
||||
after: Record<string, unknown>;
|
||||
improvement: number; // Percentage
|
||||
};
|
||||
};
|
||||
@ -408,18 +408,17 @@ export class PerformanceOptimizer {
|
||||
},
|
||||
timestamp: new Date(),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
action: OptimizationAction.TRIGGER_GARBAGE_COLLECTION,
|
||||
target: "system",
|
||||
applied: false,
|
||||
result: {
|
||||
success: false,
|
||||
message: "Garbage collection not available (run with --expose-gc)",
|
||||
},
|
||||
timestamp: new Date(),
|
||||
};
|
||||
}
|
||||
return {
|
||||
action: OptimizationAction.TRIGGER_GARBAGE_COLLECTION,
|
||||
target: "system",
|
||||
applied: false,
|
||||
result: {
|
||||
success: false,
|
||||
message: "Garbage collection not available (run with --expose-gc)",
|
||||
},
|
||||
timestamp: new Date(),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
action: OptimizationAction.TRIGGER_GARBAGE_COLLECTION,
|
||||
|
||||
@ -346,7 +346,7 @@ export class SecurityAuditLogRepository
|
||||
if (!acc[key]) {
|
||||
acc[key] = {
|
||||
userId: event.userId!,
|
||||
email: event.user?.email || 'Unknown',
|
||||
email: event.user?.email || "Unknown",
|
||||
count: 0,
|
||||
};
|
||||
}
|
||||
|
||||
@ -231,10 +231,10 @@ export class UserRepository implements BaseRepository<User> {
|
||||
try {
|
||||
return await prisma.user.update({
|
||||
where: { id },
|
||||
data: {
|
||||
data: {
|
||||
lastLoginAt: new Date(),
|
||||
failedLoginAttempts: 0, // Reset failed attempts on successful login
|
||||
lockedAt: null // Unlock account if it was locked
|
||||
lockedAt: null, // Unlock account if it was locked
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
@ -330,7 +330,9 @@ export class UserRepository implements BaseRepository<User> {
|
||||
).length;
|
||||
const lastActivity = events.length > 0 ? events[0].timestamp : null;
|
||||
const countriesAccessed = Array.from(
|
||||
new Set(events.map((e) => e.country).filter((c): c is string => c !== null))
|
||||
new Set(
|
||||
events.map((e) => e.country).filter((c): c is string => c !== null)
|
||||
)
|
||||
);
|
||||
|
||||
return {
|
||||
@ -406,7 +408,10 @@ export class UserRepository implements BaseRepository<User> {
|
||||
/**
|
||||
* Increment failed login attempts and lock account if threshold exceeded
|
||||
*/
|
||||
async incrementFailedLoginAttempts(email: string, maxAttempts = 5): Promise<User | null> {
|
||||
async incrementFailedLoginAttempts(
|
||||
email: string,
|
||||
maxAttempts = 5
|
||||
): Promise<User | null> {
|
||||
try {
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { email },
|
||||
@ -458,7 +463,11 @@ export class UserRepository implements BaseRepository<User> {
|
||||
/**
|
||||
* Set email verification token
|
||||
*/
|
||||
async setEmailVerificationToken(id: string, token: string, expiryHours = 24): Promise<User | null> {
|
||||
async setEmailVerificationToken(
|
||||
id: string,
|
||||
token: string,
|
||||
expiryHours = 24
|
||||
): Promise<User | null> {
|
||||
try {
|
||||
const expiry = new Date(Date.now() + expiryHours * 60 * 60 * 1000);
|
||||
return await prisma.user.update({
|
||||
@ -519,7 +528,10 @@ export class UserRepository implements BaseRepository<User> {
|
||||
/**
|
||||
* Update user preferences
|
||||
*/
|
||||
async updatePreferences(id: string, preferences: Record<string, unknown>): Promise<User | null> {
|
||||
async updatePreferences(
|
||||
id: string,
|
||||
preferences: Record<string, unknown>
|
||||
): Promise<User | null> {
|
||||
try {
|
||||
return await prisma.user.update({
|
||||
where: { id },
|
||||
|
||||
@ -242,7 +242,10 @@ class SecurityMonitoringService {
|
||||
* Configure monitoring thresholds
|
||||
*/
|
||||
updateConfig(config: DeepPartial<MonitoringConfig>): void {
|
||||
this.config = this.deepMerge(this.config as any, config as any) as unknown as MonitoringConfig;
|
||||
this.config = this.deepMerge(
|
||||
this.config as any,
|
||||
config as any
|
||||
) as unknown as MonitoringConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -260,7 +263,10 @@ class SecurityMonitoringService {
|
||||
typeof source[key] === "object" &&
|
||||
!Array.isArray(source[key])
|
||||
) {
|
||||
result[key] = this.deepMerge(target[key] || {} as any, source[key] as any);
|
||||
result[key] = this.deepMerge(
|
||||
target[key] || ({} as any),
|
||||
source[key] as any
|
||||
);
|
||||
} else {
|
||||
result[key] = source[key];
|
||||
}
|
||||
|
||||
@ -6,19 +6,19 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
PerformanceEnhanced,
|
||||
PerformanceOptimized,
|
||||
Cached,
|
||||
Deduplicated,
|
||||
Monitored,
|
||||
PerformanceEnhanced,
|
||||
PerformanceOptimized,
|
||||
} from "../performance/integration";
|
||||
import { AuditOutcome, AuditSeverity } from "../securityAuditLogger";
|
||||
import { AlertChannel, type MonitoringConfig } from "../securityMonitoring";
|
||||
import type { Alert, SecurityEvent } from "../types/security";
|
||||
import { ThreatLevel } from "../types/security";
|
||||
import { AlertManagementService } from "./AlertManagementService";
|
||||
import { SecurityEventProcessor } from "./SecurityEventProcessor";
|
||||
import { ThreatDetectionService } from "./ThreatDetectionService";
|
||||
import { AlertManagementService } from "./AlertManagementService";
|
||||
import { AlertChannel, type MonitoringConfig } from "../securityMonitoring";
|
||||
import { AuditOutcome, AuditSeverity } from "../securityAuditLogger";
|
||||
import { ThreatLevel } from "../types/security";
|
||||
import type { SecurityEvent, Alert } from "../types/security";
|
||||
|
||||
/**
|
||||
* Configuration for enhanced security service
|
||||
@ -161,26 +161,31 @@ export class EnhancedSecurityService {
|
||||
{ metadata: event.metadata }, // Cast to AuditLogContext
|
||||
event.metadata
|
||||
);
|
||||
|
||||
|
||||
// Return threat level based on detected threats
|
||||
if (result.threats.length === 0) {
|
||||
return ThreatLevel.LOW;
|
||||
}
|
||||
|
||||
|
||||
// Find the highest severity threat
|
||||
const highestSeverity = result.threats.reduce((max, threat) => {
|
||||
const severityOrder = { LOW: 1, MEDIUM: 2, HIGH: 3, CRITICAL: 4 };
|
||||
const current = severityOrder[threat.severity as keyof typeof severityOrder] || 1;
|
||||
const current =
|
||||
severityOrder[threat.severity as keyof typeof severityOrder] || 1;
|
||||
const maxVal = severityOrder[max as keyof typeof severityOrder] || 1;
|
||||
return current > maxVal ? threat.severity : max;
|
||||
}, "LOW" as any);
|
||||
|
||||
|
||||
// Map AlertSeverity to ThreatLevel
|
||||
switch (highestSeverity) {
|
||||
case "CRITICAL": return ThreatLevel.CRITICAL;
|
||||
case "HIGH": return ThreatLevel.HIGH;
|
||||
case "MEDIUM": return ThreatLevel.MEDIUM;
|
||||
default: return ThreatLevel.LOW;
|
||||
case "CRITICAL":
|
||||
return ThreatLevel.CRITICAL;
|
||||
case "HIGH":
|
||||
return ThreatLevel.HIGH;
|
||||
case "MEDIUM":
|
||||
return ThreatLevel.MEDIUM;
|
||||
default:
|
||||
return ThreatLevel.LOW;
|
||||
}
|
||||
}
|
||||
|
||||
@ -349,7 +354,7 @@ export class EnhancedSecurityService {
|
||||
// cache: {
|
||||
// enabled: true,
|
||||
// ttl: 10 * 60 * 1000, // 10 minutes
|
||||
// keyGenerator: (query: any) => `search:${JSON.stringify(query)}`,
|
||||
// keyGenerator: (query: Record<string, unknown>) => `search:${JSON.stringify(query)}`,
|
||||
// },
|
||||
// deduplication: {
|
||||
// enabled: true,
|
||||
@ -394,11 +399,11 @@ export class EnhancedSecurityService {
|
||||
private calculateThreatDistribution(
|
||||
events: SecurityEvent[]
|
||||
): Record<ThreatLevel, number> {
|
||||
return {
|
||||
[ThreatLevel.LOW]: 0,
|
||||
[ThreatLevel.MEDIUM]: 0,
|
||||
[ThreatLevel.HIGH]: 0,
|
||||
[ThreatLevel.CRITICAL]: 0
|
||||
return {
|
||||
[ThreatLevel.LOW]: 0,
|
||||
[ThreatLevel.MEDIUM]: 0,
|
||||
[ThreatLevel.HIGH]: 0,
|
||||
[ThreatLevel.CRITICAL]: 0,
|
||||
};
|
||||
}
|
||||
|
||||
@ -441,7 +446,9 @@ export class EnhancedSecurityService {
|
||||
};
|
||||
}
|
||||
|
||||
private async performSearch(query: any): Promise<SecurityEvent[]> {
|
||||
private async performSearch(
|
||||
query: Record<string, unknown>
|
||||
): Promise<SecurityEvent[]> {
|
||||
// Mock search implementation
|
||||
return [];
|
||||
}
|
||||
|
||||
@ -68,7 +68,7 @@ export class SecurityMetricsService {
|
||||
.slice(0, 5);
|
||||
|
||||
// User risk scores - transform data to match expected format
|
||||
const transformedEvents = events.map(event => ({
|
||||
const transformedEvents = events.map((event) => ({
|
||||
userId: event.userId || undefined,
|
||||
user: event.user ? { email: event.user.email } : undefined,
|
||||
eventType: event.eventType as SecurityEventType,
|
||||
@ -76,7 +76,8 @@ export class SecurityMetricsService {
|
||||
severity: event.severity as AuditSeverity,
|
||||
country: event.country || undefined,
|
||||
}));
|
||||
const userRiskScores = await this.calculateUserRiskScores(transformedEvents);
|
||||
const userRiskScores =
|
||||
await this.calculateUserRiskScores(transformedEvents);
|
||||
|
||||
// Calculate overall security score
|
||||
const securityScore = this.calculateSecurityScore({
|
||||
@ -122,7 +123,9 @@ export class SecurityMetricsService {
|
||||
country?: string;
|
||||
}>
|
||||
): Promise<Array<{ userId: string; email: string; riskScore: number }>> {
|
||||
const userEvents = events.filter((e) => e.userId) as Array<typeof events[0] & { userId: string }>;
|
||||
const userEvents = events.filter((e) => e.userId) as Array<
|
||||
(typeof events)[0] & { userId: string }
|
||||
>;
|
||||
const userScores = new Map<
|
||||
string,
|
||||
{ email: string; score: number; events: typeof userEvents }
|
||||
|
||||
@ -139,7 +139,7 @@ export class ThreatDetectionService {
|
||||
// Check for geographical anomalies
|
||||
if (context.country && context.userId) {
|
||||
// Transform historical events to match expected type
|
||||
const transformedEvents = historicalEvents.map(event => ({
|
||||
const transformedEvents = historicalEvents.map((event) => ({
|
||||
userId: event.userId || undefined,
|
||||
country: event.country || undefined,
|
||||
}));
|
||||
|
||||
@ -9,8 +9,8 @@
|
||||
|
||||
import { initTRPC, TRPCError } from "@trpc/server";
|
||||
import type { FetchCreateContextFnOptions } from "@trpc/server/adapters/fetch";
|
||||
import { getServerSession } from "next-auth/next";
|
||||
import type { NextRequest } from "next/server";
|
||||
import { getServerSession } from "next-auth/next";
|
||||
import superjson from "superjson";
|
||||
import type { z } from "zod";
|
||||
import { authOptions } from "./auth";
|
||||
|
||||
@ -26,4 +26,4 @@ export interface Alert {
|
||||
timestamp: Date;
|
||||
resolved: boolean;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,7 +26,6 @@ export class BoundedBuffer<T extends { timestamp: Date }> {
|
||||
* Add item to buffer with automatic cleanup
|
||||
*/
|
||||
push(item: T): void {
|
||||
|
||||
this.buffer.push(item);
|
||||
|
||||
// Trigger cleanup if threshold reached
|
||||
|
||||
Reference in New Issue
Block a user