diff --git a/libs/health/src/controller/health.controller.ts b/libs/health/src/controller/health.controller.ts new file mode 100644 index 0000000..cba9bba --- /dev/null +++ b/libs/health/src/controller/health.controller.ts @@ -0,0 +1,39 @@ +import { Controller, Get, HttpException, HttpStatus, Inject, Logger } from '@nestjs/common'; +import { SkipThrottle } from '@nestjs/throttler'; +import { HealthService } from '../health.service'; +import { GetHealthSwagger, GetPingSwagger } from './health.swagger'; +import { ApiTags } from '@nestjs/swagger'; + +@SkipThrottle() +@Controller() +@ApiTags('System') +export class HealthController { + private logger = new Logger(HealthController.name); + + constructor( + private readonly healthService: HealthService, + @Inject('SERVICE_NAME') private readonly serviceName: string, + ) {} + + @Get('health') + @GetHealthSwagger() + async checkHealth() { + const pingData = await this.healthService.getHealthData(); + + if (pingData.status !== 'up') { + this.logger.error(`${this.serviceName} is unhealthy!`); + throw new HttpException( + `${this.serviceName} service is unhealthy.`, + HttpStatus.SERVICE_UNAVAILABLE, + ); + } + + return 'healthy'; + } + + @Get('ping') + @GetPingSwagger() + async ping() { + return this.healthService.getHealthData(); + } +} diff --git a/libs/health/src/controller/health.swagger.ts b/libs/health/src/controller/health.swagger.ts new file mode 100644 index 0000000..2271969 --- /dev/null +++ b/libs/health/src/controller/health.swagger.ts @@ -0,0 +1,26 @@ +import { applyDecorators } from '@nestjs/common'; +import { ApiOperation, ApiResponse } from '@nestjs/swagger'; +import { HealthResponse } from '../dtos'; + +export const GetHealthSwagger = () => + applyDecorators( + ApiOperation({ + summary: 'Краткий статус (Health Check)', + description: 'Используется внешними системами для проверки доступности сервиса.', + }), + ApiResponse({ status: 200, description: 'Сервис работает нормально', type: String }), + ApiResponse({ status: 503, description: 'Сервис недоступен или критическая ошибка' }), + ); + +export const GetPingSwagger = () => + applyDecorators( + ApiOperation({ + summary: 'Детальный дамп состояния', + description: 'Возвращает аптайм, время старта и метрики памяти.', + }), + ApiResponse({ + status: 200, + description: 'Полная статистика сервиса', + type: HealthResponse.Output, + }), + ); diff --git a/libs/health/src/dtos/health.dto.ts b/libs/health/src/dtos/health.dto.ts new file mode 100644 index 0000000..1877b33 --- /dev/null +++ b/libs/health/src/dtos/health.dto.ts @@ -0,0 +1,25 @@ +import { createZodDto } from 'node_modules/nestjs-zod/dist/dto.cjs'; +import { z } from 'zod/v4'; + +const HealthResponseSchema = z.object({ + service: z.string().describe('Название сервиса'), + status: z.enum(['up', 'down']).describe('Текущий статус'), + info: z.object({ + version: z.string().describe('Версия приложения'), + node: z.string().describe('Версия Node.js'), + pid: z.number().describe('ID процесса'), + }), + time: z.object({ + now: z.string().datetime().describe('Текущее время сервера'), + startedAt: z.string().datetime().describe('Время старта сервера'), + uptime: z.string().describe('Аптайм в формате ч/м/с'), + uptimeSeconds: z.number().describe('Аптайм в секундах'), + }), + metrics: z.object({ + rss: z.string().describe('Resident Set Size (общая память)'), + heapUsed: z.string().describe('Использованная память в куче'), + loadAverage: z.string().describe('Средняя нагрузка на CPU'), + }), +}); + +export class HealthResponse extends createZodDto(HealthResponseSchema) {} diff --git a/libs/health/src/dtos/index.ts b/libs/health/src/dtos/index.ts new file mode 100644 index 0000000..718605a --- /dev/null +++ b/libs/health/src/dtos/index.ts @@ -0,0 +1 @@ +export { HealthResponse } from './health.dto'; diff --git a/libs/health/src/health.module.ts b/libs/health/src/health.module.ts new file mode 100644 index 0000000..c391e72 --- /dev/null +++ b/libs/health/src/health.module.ts @@ -0,0 +1,21 @@ +import { type DynamicModule, Global, Module } from '@nestjs/common'; +import { HealthController } from './controller/health.controller'; +import { HealthService } from './health.service'; + +@Global() +@Module({}) +export class HealthModule { + static register(serviceName: string): DynamicModule { + return { + module: HealthModule, + providers: [ + { + provide: 'SERVICE_NAME', + useValue: serviceName, + }, + HealthService, + ], + controllers: [HealthController], + }; + } +} diff --git a/libs/health/src/health.service.ts b/libs/health/src/health.service.ts new file mode 100644 index 0000000..076a1a6 --- /dev/null +++ b/libs/health/src/health.service.ts @@ -0,0 +1,51 @@ +import { Inject, Injectable } from '@nestjs/common'; +import * as os from 'os'; + +@Injectable() +export class HealthService { + private readonly startTime: Date; + + constructor( + @Inject('SERVICE_NAME') + private readonly serviceName: string, + ) { + this.startTime = new Date(); + } + + async getHealthData() { + const uptimeSeconds = Math.floor(process.uptime()); + const mem = process.memoryUsage(); + + return { + service: this.serviceName, + status: 'up', + info: { + version: '1.0.0', + node: process.version, + pid: process.pid, + }, + time: { + now: new Date().toISOString(), + startedAt: this.startTime.toISOString(), + uptime: this.formatUptime(uptimeSeconds), + uptimeSeconds: uptimeSeconds, + }, + metrics: { + rss: this.toMb(mem.rss), + heapUsed: this.toMb(mem.heapUsed), + loadAverage: os.loadavg()[0].toFixed(2), + }, + }; + } + + private toMb(bytes: number) { + return `${Math.round(bytes / 1024 / 1024)}MB`; + } + + private formatUptime(seconds: number) { + const h = Math.floor(seconds / 3600); + const m = Math.floor((seconds % 3600) / 60); + const s = seconds % 60; + return `${h}h ${m}m ${s}s`; + } +} diff --git a/libs/health/src/index.ts b/libs/health/src/index.ts new file mode 100644 index 0000000..f0f0421 --- /dev/null +++ b/libs/health/src/index.ts @@ -0,0 +1 @@ +export * from './health.module'; diff --git a/libs/health/tsconfig.lib.json b/libs/health/tsconfig.lib.json new file mode 100644 index 0000000..8e4d095 --- /dev/null +++ b/libs/health/tsconfig.lib.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "declaration": true, + "outDir": "../../dist/libs/health" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] +} diff --git a/nest-cli.json b/nest-cli.json index 8daf27c..5881fec 100644 --- a/nest-cli.json +++ b/nest-cli.json @@ -7,6 +7,15 @@ "webpack": true }, "projects": { + "bootstrap": { + "type": "library", + "root": "libs/bootstrap", + "entryFile": "index", + "sourceRoot": "libs/bootstrap/src", + "compilerOptions": { + "tsConfigPath": "libs/bootstrap/tsconfig.lib.json" + } + }, "config": { "type": "library", "root": "libs/config", @@ -25,13 +34,13 @@ "tsConfigPath": "libs/database/tsconfig.lib.json" } }, - "bootstrap": { + "health": { "type": "library", - "root": "libs/bootstrap", + "root": "libs/health", "entryFile": "index", - "sourceRoot": "libs/bootstrap/src", + "sourceRoot": "libs/health/src", "compilerOptions": { - "tsConfigPath": "libs/bootstrap/tsconfig.lib.json" + "tsConfigPath": "libs/health/tsconfig.lib.json" } } } diff --git a/package.json b/package.json index e770cf6..3aee9e1 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@nestjs/platform-fastify": "^11.1.18", "@nestjs/swagger": "^11.2.7", "@nestjs/throttler": "^6.5.0", + "@willsoto/nestjs-prometheus": "^6.1.0", "drizzle-orm": "^0.45.2", "drizzle-zod": "^0.8.3", "fastify": "^5.8.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f1b9c94..91a0420 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,12 +38,15 @@ importers: '@nestjs/throttler': specifier: ^6.5.0 version: 6.5.0(@nestjs/common@11.1.18(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.18(@nestjs/common@11.1.18(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2) + '@willsoto/nestjs-prometheus': + specifier: ^6.1.0 + version: 6.1.0(@nestjs/common@11.1.18(reflect-metadata@0.2.2)(rxjs@7.8.2))(prom-client@15.1.3) drizzle-orm: specifier: ^0.45.2 - version: 0.45.2(@types/pg@8.20.0)(pg@8.20.0) + version: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.20.0) drizzle-zod: specifier: ^0.8.3 - version: 0.8.3(drizzle-orm@0.45.2(@types/pg@8.20.0)(pg@8.20.0))(zod@4.3.6) + version: 0.8.3(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.20.0))(zod@4.3.6) fastify: specifier: ^5.8.4 version: 5.8.4 @@ -140,7 +143,7 @@ importers: version: 1.5.9(@swc/core@1.15.24) vitest: specifier: ^4.1.4 - version: 4.1.4(@types/node@20.19.39)(@vitest/coverage-v8@4.1.4)(vite@8.0.8(@types/node@20.19.39)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@20.19.39)(@vitest/coverage-v8@4.1.4)(vite@8.0.8(@types/node@20.19.39)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) packages: @@ -1147,6 +1150,10 @@ packages: engines: {node: ^14.18.0 || >=16.10.0, npm: '>=5.10.0'} hasBin: true + '@opentelemetry/api@1.9.1': + resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} + engines: {node: '>=8.0.0'} + '@oxc-project/types@0.124.0': resolution: {integrity: sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==} @@ -1579,6 +1586,12 @@ packages: '@webassemblyjs/wast-printer@1.14.1': resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + '@willsoto/nestjs-prometheus@6.1.0': + resolution: {integrity: sha512-lrCEnJBBSzUIYWGR+PsZw1YXs1B9jzxFEuNAa3RzTxuFAFdI+sW7Fp52il/U/dX2MWoHc32x06OS0nm56QwyzQ==} + peerDependencies: + '@nestjs/common': ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 + prom-client: ^15.0.0 + '@xtuc/ieee754@1.2.0': resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} @@ -1723,6 +1736,9 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + bintrees@1.0.2: + resolution: {integrity: sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==} + bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -3066,6 +3082,10 @@ packages: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} + prom-client@15.1.3: + resolution: {integrity: sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g==} + engines: {node: ^16 || ^18 || >=20} + pump@3.0.4: resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} @@ -3364,6 +3384,9 @@ packages: resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==} engines: {node: '>=6'} + tdigest@0.1.2: + resolution: {integrity: sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==} + terser-webpack-plugin@5.4.0: resolution: {integrity: sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==} engines: {node: '>= 10.13.0'} @@ -4578,6 +4601,8 @@ snapshots: dependencies: consola: 3.4.2 + '@opentelemetry/api@1.9.1': {} + '@oxc-project/types@0.124.0': {} '@paralleldrive/cuid2@2.3.1': @@ -4886,7 +4911,7 @@ snapshots: obug: 2.1.1 std-env: 4.0.0 tinyrainbow: 3.1.0 - vitest: 4.1.4(@types/node@20.19.39)(@vitest/coverage-v8@4.1.4)(vite@8.0.8(@types/node@20.19.39)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + vitest: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@20.19.39)(@vitest/coverage-v8@4.1.4)(vite@8.0.8(@types/node@20.19.39)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) '@vitest/expect@4.1.4': dependencies: @@ -5005,6 +5030,11 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@xtuc/long': 4.2.2 + '@willsoto/nestjs-prometheus@6.1.0(@nestjs/common@11.1.18(reflect-metadata@0.2.2)(rxjs@7.8.2))(prom-client@15.1.3)': + dependencies: + '@nestjs/common': 11.1.18(reflect-metadata@0.2.2)(rxjs@7.8.2) + prom-client: 15.1.3 + '@xtuc/ieee754@1.2.0': {} '@xtuc/long@4.2.2': {} @@ -5115,6 +5145,8 @@ snapshots: baseline-browser-mapping@2.10.17: {} + bintrees@1.0.2: {} + bl@4.1.0: dependencies: buffer: 5.7.1 @@ -5362,14 +5394,15 @@ snapshots: esbuild: 0.25.12 tsx: 4.21.0 - drizzle-orm@0.45.2(@types/pg@8.20.0)(pg@8.20.0): + drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.20.0): optionalDependencies: + '@opentelemetry/api': 1.9.1 '@types/pg': 8.20.0 pg: 8.20.0 - drizzle-zod@0.8.3(drizzle-orm@0.45.2(@types/pg@8.20.0)(pg@8.20.0))(zod@4.3.6): + drizzle-zod@0.8.3(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.20.0))(zod@4.3.6): dependencies: - drizzle-orm: 0.45.2(@types/pg@8.20.0)(pg@8.20.0) + drizzle-orm: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.20.0) zod: 4.3.6 dunder-proto@1.0.1: @@ -6388,6 +6421,11 @@ snapshots: process@0.11.10: {} + prom-client@15.1.3: + dependencies: + '@opentelemetry/api': 1.9.1 + tdigest: 0.1.2 + pump@3.0.4: dependencies: end-of-stream: 1.4.5 @@ -6699,6 +6737,10 @@ snapshots: tapable@2.3.2: {} + tdigest@0.1.2: + dependencies: + bintrees: 1.0.2 + terser-webpack-plugin@5.4.0(@swc/core@1.15.24)(esbuild@0.27.7)(webpack@5.106.0(@swc/core@1.15.24)(esbuild@0.27.7)): dependencies: '@jridgewell/trace-mapping': 0.3.31 @@ -6873,7 +6915,7 @@ snapshots: tsx: 4.21.0 yaml: 2.8.3 - vitest@4.1.4(@types/node@20.19.39)(@vitest/coverage-v8@4.1.4)(vite@8.0.8(@types/node@20.19.39)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): + vitest@4.1.4(@opentelemetry/api@1.9.1)(@types/node@20.19.39)(@vitest/coverage-v8@4.1.4)(vite@8.0.8(@types/node@20.19.39)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@vitest/expect': 4.1.4 '@vitest/mocker': 4.1.4(vite@8.0.8(@types/node@20.19.39)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) @@ -6896,6 +6938,7 @@ snapshots: vite: 8.0.8(@types/node@20.19.39)(esbuild@0.27.7)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: + '@opentelemetry/api': 1.9.1 '@types/node': 20.19.39 '@vitest/coverage-v8': 4.1.4(vitest@4.1.4) transitivePeerDependencies: diff --git a/src/app.controller.ts b/src/app.controller.ts deleted file mode 100644 index a325e8b..0000000 --- a/src/app.controller.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Controller, Get } from '@nestjs/common'; -import { AppService } from './app.service'; - -@Controller() -export class AppController { - constructor(private readonly appService: AppService) {} - - @Get() - getHello(): string { - return this.appService.getHello(); - } -} diff --git a/src/app.service.ts b/src/app.service.ts deleted file mode 100644 index 61b7a5b..0000000 --- a/src/app.service.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -@Injectable() -export class AppService { - getHello(): string { - return 'Hello World!'; - } -} diff --git a/src/main.ts b/src/main.ts index aa7c5a0..de5c124 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,5 @@ import { bootstrapApp } from '@libs/bootstrap'; -import { AppModule } from './app.module'; +import { AppModule } from './modules/app/app.module'; bootstrapApp({ serviceName: 'Tracker Monolit', diff --git a/src/app.controller.spec.ts b/src/modules/app/app.controller.spec.ts similarity index 87% rename from src/app.controller.spec.ts rename to src/modules/app/app.controller.spec.ts index 2552ec5..169b786 100644 --- a/src/app.controller.spec.ts +++ b/src/modules/app/app.controller.spec.ts @@ -1,6 +1,5 @@ import { Test, TestingModule } from '@nestjs/testing'; import { AppController } from './app.controller'; -import { AppService } from './app.service'; describe('AppController', () => { let appController: AppController; @@ -8,7 +7,6 @@ describe('AppController', () => { beforeEach(async () => { const app: TestingModule = await Test.createTestingModule({ controllers: [AppController], - providers: [AppService], }).compile(); appController = app.get(AppController); diff --git a/src/modules/app/app.controller.ts b/src/modules/app/app.controller.ts new file mode 100644 index 0000000..eb0cb39 --- /dev/null +++ b/src/modules/app/app.controller.ts @@ -0,0 +1,11 @@ +import { Controller, Get } from '@nestjs/common'; + +@Controller() +export class AppController { + constructor() {} + + @Get() + getHello(): string { + return 'Hello World!'; + } +} diff --git a/src/app.module.ts b/src/modules/app/app.module.ts similarity index 71% rename from src/app.module.ts rename to src/modules/app/app.module.ts index 0f9f1cf..c55df26 100644 --- a/src/app.module.ts +++ b/src/modules/app/app.module.ts @@ -1,16 +1,25 @@ import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; -import { AppService } from './app.service'; import { ConfigModule } from '@libs/config'; import { DatabaseModule } from '@libs/database'; import { ConfigService } from '@nestjs/config'; -import * as schema from './shared/entities'; +import * as schema from '../../shared/entities'; import { APP_FILTER, APP_PIPE } from '@nestjs/core'; import { ZodValidationPipe, ZodValidationException } from 'nestjs-zod'; +import { PrometheusModule } from '@willsoto/nestjs-prometheus'; +import { HealthModule } from '@libs/health'; @Module({ imports: [ ConfigModule, + PrometheusModule.registerAsync({ + useFactory: () => ({ + path: 'dump', + defaultMetrics: { + enabled: true, + }, + }), + }), DatabaseModule.registerAsync({ global: true, inject: [ConfigService], @@ -22,10 +31,10 @@ import { ZodValidationPipe, ZodValidationException } from 'nestjs-zod'; }; }, }), + HealthModule.register('gateway'), ], controllers: [AppController], providers: [ - AppService, { provide: APP_PIPE, useClass: ZodValidationPipe, diff --git a/test/app.e2e-spec.ts b/test/app.e2e-spec.ts index 95c5212..0f04656 100644 --- a/test/app.e2e-spec.ts +++ b/test/app.e2e-spec.ts @@ -1,7 +1,7 @@ import { Test, TestingModule } from '@nestjs/testing'; import { INestApplication } from '@nestjs/common'; import { agent } from 'supertest'; -import { AppModule } from './../src/app.module'; +import { AppModule } from '../src/modules/app/app.module'; describe('AppController (e2e)', () => { let app: INestApplication; diff --git a/tsconfig.json b/tsconfig.json index 503f4c1..759daf0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,38 +1,63 @@ { - "compilerOptions": { - "module": "commonjs", - "declaration": false, - "removeComments": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "allowSyntheticDefaultImports": true, - "target": "ES2021", - "sourceMap": true, - "outDir": "./dist", - "incremental": true, - "skipLibCheck": true, - "strictNullChecks": false, - "noImplicitAny": false, - "strictBindCallApply": false, - "forceConsistentCasingInFileNames": false, - "noFallthroughCasesInSwitch": false, - "types": ["node", "vitest/globals"], - "paths": { - "@libs/config": ["./libs/config/src"], - "@libs/config/*": ["./libs/config/src/*"], - "@libs/database": ["./libs/database/src"], - "@libs/database/*": ["./libs/database/src/*"], - "@libs/bootstrap": ["./libs/bootstrap/src"], - "@libs/bootstrap/*": ["./libs/bootstrap/src/*"] - } - }, - "include": [ - "src/**/*", - "libs/**/*", - "test/**/*", - "drizzle.config.ts", - "vitest.config.ts", - "vitest.config.e2e.ts" + "compilerOptions": { + "module": "commonjs", + "declaration": false, + "removeComments": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, + "target": "ES2021", + "sourceMap": true, + "outDir": "./dist", + "incremental": true, + "skipLibCheck": true, + "strictNullChecks": false, + "noImplicitAny": false, + "strictBindCallApply": false, + "forceConsistentCasingInFileNames": false, + "noFallthroughCasesInSwitch": false, + "types": [ + "node", + "vitest/globals" ], - "exclude": ["dist", "node_modules"] -} + "paths": { + "@libs/bootstrap": [ + "./libs/bootstrap/src" + ], + "@libs/bootstrap/*": [ + "./libs/bootstrap/src/*" + ], + "@libs/config": [ + "./libs/config/src" + ], + "@libs/config/*": [ + "./libs/config/src/*" + ], + "@libs/database": [ + "./libs/database/src" + ], + "@libs/database/*": [ + "./libs/database/src/*" + ], + "@libs/health": [ + "libs/health/src" + ], + "@libs/health/*": [ + "libs/health/src/*" + ] + }, + "baseUrl": "./" + }, + "include": [ + "src/**/*", + "libs/**/*", + "test/**/*", + "drizzle.config.ts", + "vitest.config.ts", + "vitest.config.e2e.ts" + ], + "exclude": [ + "dist", + "node_modules" + ] +} \ No newline at end of file