mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-16 12:19:40 +02:00
style: auto-format codebase with Prettier
Applied formatting to 1487+ files using pnpm format:write - TypeScript/JavaScript files - Svelte components - Astro pages - JSON configs - Markdown docs 13 files still need manual review (Astro JSX comments)
This commit is contained in:
parent
0241f5554c
commit
d36b321d9d
3952 changed files with 661498 additions and 739751 deletions
|
|
@ -1,10 +1,10 @@
|
|||
import {
|
||||
type ExceptionFilter,
|
||||
Catch,
|
||||
type ArgumentsHost,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Logger,
|
||||
type ExceptionFilter,
|
||||
Catch,
|
||||
type ArgumentsHost,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Logger,
|
||||
} from '@nestjs/common';
|
||||
import type { Request, Response } from 'express';
|
||||
import { AppError } from '../errors/app-error';
|
||||
|
|
@ -15,13 +15,13 @@ import { ErrorCode } from '../types/error-codes';
|
|||
* Standard error response format returned by all backends.
|
||||
*/
|
||||
export interface ErrorResponseBody {
|
||||
statusCode: number;
|
||||
error: string;
|
||||
message: string;
|
||||
retryable: boolean;
|
||||
timestamp: string;
|
||||
path: string;
|
||||
details?: Record<string, unknown>;
|
||||
statusCode: number;
|
||||
error: string;
|
||||
message: string;
|
||||
retryable: boolean;
|
||||
timestamp: string;
|
||||
path: string;
|
||||
details?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -47,213 +47,198 @@ export interface ErrorResponseBody {
|
|||
*/
|
||||
@Catch()
|
||||
export class AppExceptionFilter implements ExceptionFilter {
|
||||
private readonly logger = new Logger(AppExceptionFilter.name);
|
||||
private readonly logger = new Logger(AppExceptionFilter.name);
|
||||
|
||||
catch(exception: unknown, host: ArgumentsHost): void {
|
||||
const ctx = host.switchToHttp();
|
||||
const response = ctx.getResponse<Response>();
|
||||
const request = ctx.getRequest<Request>();
|
||||
catch(exception: unknown, host: ArgumentsHost): void {
|
||||
const ctx = host.switchToHttp();
|
||||
const response = ctx.getResponse<Response>();
|
||||
const request = ctx.getRequest<Request>();
|
||||
|
||||
const errorResponse = this.buildErrorResponse(exception, request);
|
||||
const errorResponse = this.buildErrorResponse(exception, request);
|
||||
|
||||
this.logError(exception, request, errorResponse);
|
||||
this.logError(exception, request, errorResponse);
|
||||
|
||||
response.status(errorResponse.statusCode).json(errorResponse);
|
||||
}
|
||||
response.status(errorResponse.statusCode).json(errorResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the error response body based on the exception type.
|
||||
*/
|
||||
private buildErrorResponse(
|
||||
exception: unknown,
|
||||
request: Request
|
||||
): ErrorResponseBody {
|
||||
// Handle AppError and subclasses
|
||||
if (isAppError(exception)) {
|
||||
return this.buildAppErrorResponse(exception, request);
|
||||
}
|
||||
/**
|
||||
* Build the error response body based on the exception type.
|
||||
*/
|
||||
private buildErrorResponse(exception: unknown, request: Request): ErrorResponseBody {
|
||||
// Handle AppError and subclasses
|
||||
if (isAppError(exception)) {
|
||||
return this.buildAppErrorResponse(exception, request);
|
||||
}
|
||||
|
||||
// Handle NestJS HttpException
|
||||
if (exception instanceof HttpException) {
|
||||
return this.buildHttpExceptionResponse(exception, request);
|
||||
}
|
||||
// Handle NestJS HttpException
|
||||
if (exception instanceof HttpException) {
|
||||
return this.buildHttpExceptionResponse(exception, request);
|
||||
}
|
||||
|
||||
// Handle standard Error
|
||||
if (exception instanceof Error) {
|
||||
return this.buildStandardErrorResponse(exception, request);
|
||||
}
|
||||
// Handle standard Error
|
||||
if (exception instanceof Error) {
|
||||
return this.buildStandardErrorResponse(exception, request);
|
||||
}
|
||||
|
||||
// Handle unknown errors
|
||||
return this.buildUnknownErrorResponse(request);
|
||||
}
|
||||
// Handle unknown errors
|
||||
return this.buildUnknownErrorResponse(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build response for AppError and subclasses.
|
||||
*/
|
||||
private buildAppErrorResponse(
|
||||
exception: AppError,
|
||||
request: Request
|
||||
): ErrorResponseBody {
|
||||
const baseResponse: ErrorResponseBody = {
|
||||
statusCode: exception.httpStatus,
|
||||
error: exception.code,
|
||||
message: exception.message,
|
||||
retryable: exception.retryable,
|
||||
timestamp: exception.timestamp,
|
||||
path: request.url,
|
||||
};
|
||||
/**
|
||||
* Build response for AppError and subclasses.
|
||||
*/
|
||||
private buildAppErrorResponse(exception: AppError, request: Request): ErrorResponseBody {
|
||||
const baseResponse: ErrorResponseBody = {
|
||||
statusCode: exception.httpStatus,
|
||||
error: exception.code,
|
||||
message: exception.message,
|
||||
retryable: exception.retryable,
|
||||
timestamp: exception.timestamp,
|
||||
path: request.url,
|
||||
};
|
||||
|
||||
// Add credit-specific fields for CreditError
|
||||
if (isCreditError(exception)) {
|
||||
baseResponse.details = {
|
||||
requiredCredits: exception.requiredCredits,
|
||||
availableCredits: exception.availableCredits,
|
||||
...exception.context,
|
||||
};
|
||||
}
|
||||
// Add retry-after for RateLimitError
|
||||
else if (isRateLimitError(exception) && exception.retryAfter) {
|
||||
baseResponse.details = {
|
||||
retryAfter: exception.retryAfter,
|
||||
...exception.context,
|
||||
};
|
||||
}
|
||||
// Add other context if present
|
||||
else if (Object.keys(exception.context).length > 0) {
|
||||
baseResponse.details = exception.context;
|
||||
}
|
||||
// Add credit-specific fields for CreditError
|
||||
if (isCreditError(exception)) {
|
||||
baseResponse.details = {
|
||||
requiredCredits: exception.requiredCredits,
|
||||
availableCredits: exception.availableCredits,
|
||||
...exception.context,
|
||||
};
|
||||
}
|
||||
// Add retry-after for RateLimitError
|
||||
else if (isRateLimitError(exception) && exception.retryAfter) {
|
||||
baseResponse.details = {
|
||||
retryAfter: exception.retryAfter,
|
||||
...exception.context,
|
||||
};
|
||||
}
|
||||
// Add other context if present
|
||||
else if (Object.keys(exception.context).length > 0) {
|
||||
baseResponse.details = exception.context;
|
||||
}
|
||||
|
||||
return baseResponse;
|
||||
}
|
||||
return baseResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build response for NestJS HttpException.
|
||||
*/
|
||||
private buildHttpExceptionResponse(
|
||||
exception: HttpException,
|
||||
request: Request
|
||||
): ErrorResponseBody {
|
||||
const status = exception.getStatus();
|
||||
const exceptionResponse = exception.getResponse();
|
||||
/**
|
||||
* Build response for NestJS HttpException.
|
||||
*/
|
||||
private buildHttpExceptionResponse(
|
||||
exception: HttpException,
|
||||
request: Request
|
||||
): ErrorResponseBody {
|
||||
const status = exception.getStatus();
|
||||
const exceptionResponse = exception.getResponse();
|
||||
|
||||
let message: string;
|
||||
let details: Record<string, unknown> | undefined;
|
||||
let message: string;
|
||||
let details: Record<string, unknown> | undefined;
|
||||
|
||||
if (typeof exceptionResponse === 'object') {
|
||||
const responseObj = exceptionResponse as Record<string, unknown>;
|
||||
message =
|
||||
typeof responseObj.message === 'string'
|
||||
? responseObj.message
|
||||
: Array.isArray(responseObj.message)
|
||||
? (responseObj.message as string[]).join(', ')
|
||||
: exception.message;
|
||||
if (typeof exceptionResponse === 'object') {
|
||||
const responseObj = exceptionResponse as Record<string, unknown>;
|
||||
message =
|
||||
typeof responseObj.message === 'string'
|
||||
? responseObj.message
|
||||
: Array.isArray(responseObj.message)
|
||||
? (responseObj.message as string[]).join(', ')
|
||||
: exception.message;
|
||||
|
||||
// Extract any additional details
|
||||
const { message: _, error: __, statusCode: ___, ...rest } = responseObj;
|
||||
if (Object.keys(rest).length > 0) {
|
||||
details = rest;
|
||||
}
|
||||
} else {
|
||||
message = String(exceptionResponse);
|
||||
}
|
||||
// Extract any additional details
|
||||
const { message: _, error: __, statusCode: ___, ...rest } = responseObj;
|
||||
if (Object.keys(rest).length > 0) {
|
||||
details = rest;
|
||||
}
|
||||
} else {
|
||||
message = String(exceptionResponse);
|
||||
}
|
||||
|
||||
return {
|
||||
statusCode: status,
|
||||
error: this.httpStatusToErrorCode(status),
|
||||
message,
|
||||
retryable: status >= 500,
|
||||
timestamp: new Date().toISOString(),
|
||||
path: request.url,
|
||||
...(details && { details }),
|
||||
};
|
||||
}
|
||||
return {
|
||||
statusCode: status,
|
||||
error: this.httpStatusToErrorCode(status),
|
||||
message,
|
||||
retryable: status >= 500,
|
||||
timestamp: new Date().toISOString(),
|
||||
path: request.url,
|
||||
...(details && { details }),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Build response for standard JavaScript Error.
|
||||
*/
|
||||
private buildStandardErrorResponse(
|
||||
exception: Error,
|
||||
request: Request
|
||||
): ErrorResponseBody {
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
/**
|
||||
* Build response for standard JavaScript Error.
|
||||
*/
|
||||
private buildStandardErrorResponse(exception: Error, request: Request): ErrorResponseBody {
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
|
||||
return {
|
||||
statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
error: ErrorCode.INTERNAL_ERROR,
|
||||
message: isProduction
|
||||
? 'An unexpected error occurred'
|
||||
: exception.message,
|
||||
retryable: true,
|
||||
timestamp: new Date().toISOString(),
|
||||
path: request.url,
|
||||
};
|
||||
}
|
||||
return {
|
||||
statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
error: ErrorCode.INTERNAL_ERROR,
|
||||
message: isProduction ? 'An unexpected error occurred' : exception.message,
|
||||
retryable: true,
|
||||
timestamp: new Date().toISOString(),
|
||||
path: request.url,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Build response for unknown error types.
|
||||
*/
|
||||
private buildUnknownErrorResponse(request: Request): ErrorResponseBody {
|
||||
return {
|
||||
statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
error: ErrorCode.UNKNOWN_ERROR,
|
||||
message: 'An unexpected error occurred',
|
||||
retryable: true,
|
||||
timestamp: new Date().toISOString(),
|
||||
path: request.url,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Build response for unknown error types.
|
||||
*/
|
||||
private buildUnknownErrorResponse(request: Request): ErrorResponseBody {
|
||||
return {
|
||||
statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
error: ErrorCode.UNKNOWN_ERROR,
|
||||
message: 'An unexpected error occurred',
|
||||
retryable: true,
|
||||
timestamp: new Date().toISOString(),
|
||||
path: request.url,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Map HTTP status code to ErrorCode.
|
||||
*/
|
||||
private httpStatusToErrorCode(status: number): string {
|
||||
const statusToCode: Record<number, string> = {
|
||||
400: ErrorCode.VALIDATION_FAILED,
|
||||
401: ErrorCode.AUTHENTICATION_REQUIRED,
|
||||
402: ErrorCode.PAYMENT_REQUIRED,
|
||||
403: ErrorCode.PERMISSION_DENIED,
|
||||
404: ErrorCode.RESOURCE_NOT_FOUND,
|
||||
409: ErrorCode.CONFLICT,
|
||||
429: ErrorCode.RATE_LIMIT_EXCEEDED,
|
||||
500: ErrorCode.INTERNAL_ERROR,
|
||||
502: ErrorCode.EXTERNAL_SERVICE_ERROR,
|
||||
503: ErrorCode.SERVICE_UNAVAILABLE,
|
||||
504: ErrorCode.TIMEOUT,
|
||||
};
|
||||
return statusToCode[status] || ErrorCode.UNKNOWN_ERROR;
|
||||
}
|
||||
/**
|
||||
* Map HTTP status code to ErrorCode.
|
||||
*/
|
||||
private httpStatusToErrorCode(status: number): string {
|
||||
const statusToCode: Record<number, string> = {
|
||||
400: ErrorCode.VALIDATION_FAILED,
|
||||
401: ErrorCode.AUTHENTICATION_REQUIRED,
|
||||
402: ErrorCode.PAYMENT_REQUIRED,
|
||||
403: ErrorCode.PERMISSION_DENIED,
|
||||
404: ErrorCode.RESOURCE_NOT_FOUND,
|
||||
409: ErrorCode.CONFLICT,
|
||||
429: ErrorCode.RATE_LIMIT_EXCEEDED,
|
||||
500: ErrorCode.INTERNAL_ERROR,
|
||||
502: ErrorCode.EXTERNAL_SERVICE_ERROR,
|
||||
503: ErrorCode.SERVICE_UNAVAILABLE,
|
||||
504: ErrorCode.TIMEOUT,
|
||||
};
|
||||
return statusToCode[status] || ErrorCode.UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the error with appropriate level based on status code.
|
||||
*/
|
||||
private logError(
|
||||
exception: unknown,
|
||||
request: Request,
|
||||
response: ErrorResponseBody
|
||||
): void {
|
||||
const logData = {
|
||||
method: request.method,
|
||||
url: request.url,
|
||||
statusCode: response.statusCode,
|
||||
error: response.error,
|
||||
message: response.message,
|
||||
userId: (request as Request & { user?: { sub?: string } }).user?.sub,
|
||||
};
|
||||
/**
|
||||
* Log the error with appropriate level based on status code.
|
||||
*/
|
||||
private logError(exception: unknown, request: Request, response: ErrorResponseBody): void {
|
||||
const logData = {
|
||||
method: request.method,
|
||||
url: request.url,
|
||||
statusCode: response.statusCode,
|
||||
error: response.error,
|
||||
message: response.message,
|
||||
userId: (request as Request & { user?: { sub?: string } }).user?.sub,
|
||||
};
|
||||
|
||||
// Log 5xx errors as errors, others as warnings
|
||||
if (response.statusCode >= 500) {
|
||||
this.logger.error(
|
||||
`[${logData.method}] ${logData.url} - ${logData.statusCode}: ${logData.message}`,
|
||||
isAppError(exception)
|
||||
? JSON.stringify(exception.toFullJSON(), null, 2)
|
||||
: exception instanceof Error
|
||||
? exception.stack
|
||||
: undefined
|
||||
);
|
||||
} else {
|
||||
this.logger.warn(
|
||||
`[${logData.method}] ${logData.url} - ${logData.statusCode}: ${logData.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
// Log 5xx errors as errors, others as warnings
|
||||
if (response.statusCode >= 500) {
|
||||
this.logger.error(
|
||||
`[${logData.method}] ${logData.url} - ${logData.statusCode}: ${logData.message}`,
|
||||
isAppError(exception)
|
||||
? JSON.stringify(exception.toFullJSON(), null, 2)
|
||||
: exception instanceof Error
|
||||
? exception.stack
|
||||
: undefined
|
||||
);
|
||||
} else {
|
||||
this.logger.warn(
|
||||
`[${logData.method}] ${logData.url} - ${logData.statusCode}: ${logData.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue