refactor: improve code quality

This commit is contained in:
2026-05-12 15:42:21 +02:00
parent 8abdfc3b2f
commit 528fff3a5b
42 changed files with 1756 additions and 1255 deletions

View File

@@ -2,10 +2,10 @@ import { defineConfig } from "drizzle-kit";
import { env } from "~/env";
export default defineConfig({
dialect: "postgresql",
out: "./drizzle",
schema: "./src/schema/index.ts",
dbCredentials: {
url: env.DATABASE_URL,
},
dialect: "postgresql",
out: "./drizzle",
schema: "./src/schema/index.ts",
dbCredentials: {
url: env.DATABASE_URL,
},
});

View File

@@ -1,36 +1,37 @@
{
"name": "@lbf-bot/database",
"type": "module",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"default": "./dist/index.js"
"name": "@lbf-bot/database",
"type": "module",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"default": "./dist/index.js"
}
},
"files": [
"dist",
"drizzle"
],
"scripts": {
"build": "rm -rf dist && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
"check": "tsc --noEmit && eslint src/",
"db:generate": "drizzle-kit generate",
"db:push": "drizzle-kit push",
"db:studio": "drizzle-kit studio"
},
"dependencies": {
"@lbf-bot/utils": "workspace:*",
"drizzle-orm": "0.44.7",
"ioredis": "5.8.2",
"pg": "8.16.3",
"zod": "4.1.11"
},
"devDependencies": {
"drizzle-kit": "0.31.7",
"tsc-alias": "1.8.16",
"typescript": "5.9.3"
}
},
"files": [
"dist",
"drizzle"
],
"scripts": {
"build": "rm -rf dist && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
"db:generate": "drizzle-kit generate",
"db:push": "drizzle-kit push",
"db:studio": "drizzle-kit studio"
},
"dependencies": {
"@lbf-bot/utils": "workspace:*",
"drizzle-orm": "0.44.7",
"ioredis": "5.8.2",
"pg": "8.16.3",
"zod": "4.1.11"
},
"devDependencies": {
"drizzle-kit": "0.31.7",
"tsc-alias": "1.8.16",
"typescript": "5.9.3"
}
}

View File

@@ -1,14 +1,14 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"removeComments": false
},
"tsc-alias": {
"resolveFullPaths": true
},
"include": ["src"]
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"removeComments": false
},
"tsc-alias": {
"resolveFullPaths": true
},
"include": ["src"]
}

View File

@@ -1,28 +1,27 @@
{
"compilerOptions": {
"lib": ["ESNext"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"compilerOptions": {
"lib": ["ESNext"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"moduleResolution": "bundler",
"allowImportingTsExtensions": false,
"baseUrl": ".",
"paths": {
"~/*": ["./src/*"],
"~": ["./src/index"]
"moduleResolution": "bundler",
"allowImportingTsExtensions": false,
"paths": {
"~/*": ["./src/*"],
"~": ["./src/index"]
},
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
},
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
},
"include": ["src", "drizzle.config.ts"],
"exclude": ["node_modules", "dist"]
"include": ["src", "drizzle.config.ts"],
"exclude": ["node_modules", "dist"]
}

View File

@@ -1,29 +1,30 @@
{
"name": "@lbf-bot/utils",
"type": "module",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"default": "./dist/index.js"
"name": "@lbf-bot/utils",
"type": "module",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"default": "./dist/index.js"
}
},
"files": [
"dist"
],
"scripts": {
"build": "rm -rf dist && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
"check": "tsc --noEmit && eslint src/"
},
"dependencies": {
"dotenv": "17.2.3",
"zod": "4.1.11"
},
"devDependencies": {
"@types/node": "22.19.1",
"tsc-alias": "1.8.16",
"typescript": "5.9.3"
}
},
"files": [
"dist"
],
"scripts": {
"build": "rm -rf dist && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json"
},
"dependencies": {
"dotenv": "17.2.3",
"zod": "4.1.11"
},
"devDependencies": {
"@types/node": "22.19.1",
"tsc-alias": "1.8.16",
"typescript": "5.9.3"
}
}

View File

@@ -2,16 +2,16 @@ import "dotenv/config";
import { z } from "zod";
export const parseEnv = <T extends z.ZodRawShape>(vars: T) => {
const schema = z.object(vars);
const result = schema.safeParse(process.env);
if (!result.success) {
console.error("ERROR: Environment variable validation failed:");
for (const issue of result.error.issues) {
console.error(`- ${issue.path.join(".")}: ${issue.message}`);
const schema = z.object(vars);
const result = schema.safeParse(process.env);
if (!result.success) {
console.error("ERROR: Environment variable validation failed:");
for (const issue of result.error.issues) {
console.error(`- ${issue.path.join(".")}: ${issue.message}`);
}
process.exit(1);
}
process.exit(1);
}
return result.data;
return result.data;
};

View File

@@ -1,101 +1,96 @@
type LogLevel = "debug" | "info" | "warn" | "error";
interface LoggerOptions {
prefix?: string;
level?: LogLevel;
type LoggerOptions = {
prefix?: string;
level?: LogLevel;
}
const LOG_LEVELS = {
debug: 0,
info: 1,
warn: 2,
error: 3,
debug: 0,
info: 1,
warn: 2,
error: 3,
} as const satisfies Record<LogLevel, number>;
const COLORS = {
debug: "\x1b[36m", // cyan
info: "\x1b[32m", // green
warn: "\x1b[33m", // yellow
error: "\x1b[31m", // red
reset: "\x1b[0m",
gray: "\x1b[90m",
bold: "\x1b[1m",
debug: "\x1b[36m", // cyan
info: "\x1b[32m", // green
warn: "\x1b[33m", // yellow
error: "\x1b[31m", // red
reset: "\x1b[0m",
gray: "\x1b[90m",
bold: "\x1b[1m",
} as const;
class Logger {
private prefix: string;
private minLevel: number;
private prefix: string;
private minLevel: number;
constructor(options: LoggerOptions = {}) {
this.prefix = options.prefix || "";
this.minLevel = LOG_LEVELS[options.level || "info"];
}
constructor(options: LoggerOptions = {}) {
this.prefix = options.prefix || "";
this.minLevel = LOG_LEVELS[options.level || "info"];
}
private formatTimestamp(): string {
const now = new Date();
const hours = String(now.getHours()).padStart(2, "0");
const minutes = String(now.getMinutes()).padStart(2, "0");
const seconds = String(now.getSeconds()).padStart(2, "0");
return `${hours}:${minutes}:${seconds}`;
}
private formatTimestamp(): string {
const now = new Date();
const hours = String(now.getHours()).padStart(2, "0");
const minutes = String(now.getMinutes()).padStart(2, "0");
const seconds = String(now.getSeconds()).padStart(2, "0");
return `${hours}:${minutes}:${seconds}`;
}
private log(level: LogLevel, message: string, ...args: unknown[]): void {
if (LOG_LEVELS[level] < this.minLevel) return;
private log(level: LogLevel, message: string, ...args: unknown[]): void {
if (LOG_LEVELS[level] < this.minLevel) return;
const timestamp = this.formatTimestamp();
const color = COLORS[level];
const levelStr = level.toUpperCase().padEnd(5);
const prefix = this.prefix ? `[${this.prefix}] ` : "";
const timestamp = this.formatTimestamp();
const color = COLORS[level];
const levelStr = level.toUpperCase().padEnd(5);
const prefix = this.prefix ? `[${this.prefix}] ` : "";
const formattedArgs = args.map((arg) => {
if (arg instanceof Error) {
return arg;
}
return arg;
});
const formattedArgs = args.map((arg) => {
if (arg instanceof Error) {
return arg;
}
return arg;
});
console.log(
`${COLORS.gray}${timestamp}${COLORS.reset} ${color}${COLORS.bold}${levelStr}${COLORS.reset} ${prefix}${message}`,
...formattedArgs,
);
}
console.log(`${COLORS.gray}${timestamp}${COLORS.reset} ${color}${COLORS.bold}${levelStr}${COLORS.reset} ${prefix}${message}`, ...formattedArgs);
}
debug(message: string, ...args: unknown[]): void {
this.log("debug", message, ...args);
}
debug(message: string, ...args: unknown[]): void {
this.log("debug", message, ...args);
}
info(message: string, ...args: unknown[]): void {
this.log("info", message, ...args);
}
info(message: string, ...args: unknown[]): void {
this.log("info", message, ...args);
}
warn(message: string, ...args: unknown[]): void {
this.log("warn", message, ...args);
}
warn(message: string, ...args: unknown[]): void {
this.log("warn", message, ...args);
}
error(message: string, ...args: unknown[]): void {
this.log("error", message, ...args);
}
error(message: string, ...args: unknown[]): void {
this.log("error", message, ...args);
}
fatal(message: string, ...args: unknown[]): never {
this.log("error", message, ...args);
process.exit(1);
}
fatal(message: string, ...args: unknown[]): never {
this.log("error", message, ...args);
process.exit(1);
}
child(prefix: string): Logger {
const childPrefix = this.prefix ? `${this.prefix}:${prefix}` : prefix;
return new Logger({ prefix: childPrefix, level: this.getLevel() });
}
child(prefix: string): Logger {
const childPrefix = this.prefix ? `${this.prefix}:${prefix}` : prefix;
return new Logger({ prefix: childPrefix, level: this.getLevel() });
}
private getLevel(): LogLevel {
const entry = Object.entries(LOG_LEVELS).find(
([, value]) => value === this.minLevel,
);
return (entry?.[0] as LogLevel) || "info";
}
private getLevel(): LogLevel {
const entry = Object.entries(LOG_LEVELS).find(([, value]) => value === this.minLevel);
return (entry?.[0] as LogLevel) || "info";
}
}
export const createLogger = (options?: LoggerOptions): Logger => {
return new Logger(options);
return new Logger(options);
};
export const logger = createLogger();

View File

@@ -1,14 +1,14 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"removeComments": false
},
"tsc-alias": {
"resolveFullPaths": true
},
"include": ["src"]
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"removeComments": false
},
"tsc-alias": {
"resolveFullPaths": true
},
"include": ["src"]
}

View File

@@ -1,28 +1,28 @@
{
"compilerOptions": {
"lib": ["ESNext"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"compilerOptions": {
"lib": ["ESNext"],
"types": ["node"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"moduleResolution": "bundler",
"allowImportingTsExtensions": false,
"baseUrl": ".",
"paths": {
"~/*": ["./src/*"],
"~": ["./src/index"]
"moduleResolution": "bundler",
"allowImportingTsExtensions": false,
"paths": {
"~/*": ["./src/*"],
"~": ["./src/index"]
},
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
},
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
"include": ["src"],
"exclude": ["node_modules", "dist"]
}