feat(shared): reorder AppError constructor to (message, code, status), add singleton logger, retry and TTL cache utilities
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { drizzle } from "drizzle-orm/node-postgres";
|
||||
import { Pool } from "pg";
|
||||
import { config } from "../config/index.js";
|
||||
import { createChildLogger } from "../logger/index.js";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
|
||||
const logger = createChildLogger("database");
|
||||
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
export class AppError extends Error {
|
||||
constructor(
|
||||
message: string,
|
||||
public code: string,
|
||||
public statusCode: number = 500,
|
||||
) {
|
||||
super(message);
|
||||
this.name = "AppError";
|
||||
}
|
||||
}
|
||||
|
||||
export class ValidationError extends AppError {
|
||||
constructor(
|
||||
message: string,
|
||||
public details?: Record<string, unknown>,
|
||||
) {
|
||||
super(message, "VALIDATION_ERROR", 400);
|
||||
this.name = "ValidationError";
|
||||
}
|
||||
}
|
||||
|
||||
export class NotFoundError extends AppError {
|
||||
constructor(message: string) {
|
||||
super(message, "NOT_FOUND", 404);
|
||||
this.name = "NotFoundError";
|
||||
}
|
||||
}
|
||||
|
||||
export class UnauthorizedError extends AppError {
|
||||
constructor(message: string = "Unauthorized") {
|
||||
super(message, "UNAUTHORIZED", 401);
|
||||
this.name = "UnauthorizedError";
|
||||
}
|
||||
}
|
||||
|
||||
export class ForbiddenError extends AppError {
|
||||
constructor(message: string = "Forbidden") {
|
||||
super(message, "FORBIDDEN", 403);
|
||||
this.name = "ForbiddenError";
|
||||
}
|
||||
}
|
||||
|
||||
export class ConflictError extends AppError {
|
||||
constructor(message: string) {
|
||||
super(message, "CONFLICT", 409);
|
||||
this.name = "ConflictError";
|
||||
}
|
||||
}
|
||||
|
||||
export class DatabaseError extends AppError {
|
||||
constructor(
|
||||
message: string,
|
||||
public originalError?: Error,
|
||||
) {
|
||||
super(message, "DATABASE_ERROR", 500);
|
||||
this.name = "DatabaseError";
|
||||
}
|
||||
}
|
||||
|
||||
export class ConfigError extends AppError {
|
||||
constructor(message: string) {
|
||||
super(message, "CONFIG_ERROR", 500);
|
||||
this.name = "ConfigError";
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import pino from "pino";
|
||||
import { config } from "../config/index.js";
|
||||
|
||||
const isDev = config.NODE_ENV === "development";
|
||||
|
||||
export const logger = pino({
|
||||
level: config.LOG_LEVEL,
|
||||
transport: isDev
|
||||
? {
|
||||
target: "pino-pretty",
|
||||
options: {
|
||||
colorize: true,
|
||||
translateTime: "SYS:standard",
|
||||
ignore: "pid,hostname",
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
|
||||
export function createChildLogger(context: string) {
|
||||
return logger.child({ context });
|
||||
}
|
||||
|
||||
export type Logger = ReturnType<typeof createChildLogger>;
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { NextFunction, Request, Response } from "express";
|
||||
import { AppError, UnauthorizedError } from "../errors/index.js";
|
||||
import { createChildLogger } from "../logger/index.js";
|
||||
import {
|
||||
AppError,
|
||||
UnauthorizedError,
|
||||
ValidationError,
|
||||
} from "@bete/shared/errors";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
|
||||
const logger = createChildLogger("middleware");
|
||||
|
||||
@@ -46,5 +50,13 @@ export function asyncHandler(
|
||||
};
|
||||
}
|
||||
|
||||
// Import ValidationError for type checking
|
||||
import { ValidationError } from "../errors/index.js";
|
||||
/**
|
||||
* Validate that a value is a non-empty string, or throw a descriptive error.
|
||||
* Use for both route params and query string values.
|
||||
*/
|
||||
export function requireParam(value: unknown, kind: string, name: string): string {
|
||||
if (typeof value !== "string" || value.length === 0) {
|
||||
throw new Error(`Missing ${kind}: ${name}`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import Redis from "ioredis";
|
||||
import { config } from "../config/index.js";
|
||||
import { createChildLogger } from "../logger/index.js";
|
||||
import { createChildLogger } from "@bete/shared/logger";
|
||||
|
||||
const logger = createChildLogger("redis.command-channel");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user