init
This commit is contained in:
Executable
+43
@@ -0,0 +1,43 @@
|
||||
import KeyvRedis from '@keyv/redis';
|
||||
import Keyv from 'keyv';
|
||||
import type { CacheModuleAsyncOptions } from '@nestjs/cache-manager';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { Logger } from '@nestjs/common'; // 1. Import Logger
|
||||
|
||||
export function cacheConfig(): CacheModuleAsyncOptions {
|
||||
// 2. Create a logger instance
|
||||
const logger = new Logger('CacheConfig');
|
||||
|
||||
return {
|
||||
isGlobal: true,
|
||||
inject: [ConfigService],
|
||||
useFactory: (configService: ConfigService) => {
|
||||
const ttl = configService.get<number>('CACHE_TTL', 120);
|
||||
const namespace = configService.get<string>('CACHE_NAMESPACE', 'app-cache');
|
||||
const redisUri = configService.getOrThrow<string>('REDIS_URI');
|
||||
|
||||
// 3. Create the KeyvRedis store first
|
||||
const keyvRedisStore = new KeyvRedis(redisUri);
|
||||
|
||||
// 4. Attach event listeners
|
||||
keyvRedisStore.client.on('connect', () => {
|
||||
logger.log('✅ Redis connected successfully.');
|
||||
});
|
||||
keyvRedisStore.client.on('error', (error) => {
|
||||
logger.error('❌ Redis connection error:', error);
|
||||
});
|
||||
|
||||
// 5. Pass the store to Keyv
|
||||
const store = new Keyv({
|
||||
store: keyvRedisStore, // Use the instance
|
||||
namespace,
|
||||
ttl: ttl * 1000,
|
||||
});
|
||||
|
||||
return {
|
||||
store,
|
||||
ttl,
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
import type { HttpModuleAsyncOptions } from '@nestjs/axios';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
export function httpConfig(): HttpModuleAsyncOptions {
|
||||
return {
|
||||
inject: [ConfigService],
|
||||
global: true,
|
||||
useFactory: (configService: ConfigService) => {
|
||||
return {
|
||||
timeout: configService.getOrThrow<number>('AXIOS_TIMEOUT'),
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
global: true,
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
import { defineConfig, PostgreSqlDriver } from '@mikro-orm/postgresql';
|
||||
import * as dotenv from 'dotenv';
|
||||
|
||||
// 1. Load environment variables from your .env file
|
||||
dotenv.config();
|
||||
|
||||
// 2. Read variables directly from process.env
|
||||
const DB_PASS = process.env.DB_PASS;
|
||||
const DB_USER = process.env.DB_USER;
|
||||
const DB_HOST = process.env.DB_HOST;
|
||||
const DB_PORT = process.env.DB_PORT ? +process.env.DB_PORT : 5432;
|
||||
const DB_NAME = process.env.DB_NAME;
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
|
||||
// 3. Add checks to ensure variables are loaded
|
||||
if (!DB_PASS || !DB_USER || !DB_HOST || !DB_PORT || !DB_NAME) {
|
||||
throw new Error('One or more database environment variables are not set.');
|
||||
}
|
||||
|
||||
const encodedPassword = encodeURIComponent(DB_PASS);
|
||||
|
||||
// 4. Export the result of defineConfig as the default
|
||||
export default defineConfig({
|
||||
entities: ['dist/**/*.entity.js'],
|
||||
entitiesTs: ['src/**/*.entity.ts'],
|
||||
driver: PostgreSqlDriver,
|
||||
dbName: DB_NAME,
|
||||
debug: !isProduction,
|
||||
clientUrl: `postgres://${DB_USER}:${encodedPassword}@${DB_HOST}:${DB_PORT}`,
|
||||
ensureDatabase: isProduction
|
||||
? false
|
||||
: {
|
||||
forceCheck: true,
|
||||
create: true,
|
||||
schema: 'update',
|
||||
},
|
||||
forceUtcTimezone: true,
|
||||
pool: {
|
||||
min: isProduction ? 5 : 2,
|
||||
max: isProduction ? 20 : 10,
|
||||
idleTimeoutMillis: 30000,
|
||||
acquireTimeoutMillis: 30000,
|
||||
reapIntervalMillis: 1000,
|
||||
createTimeoutMillis: 15000,
|
||||
destroyTimeoutMillis: 5000,
|
||||
},
|
||||
// 5. Use console for CLI logging, not the injected Nest logger
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
logger: isProduction ? console.log.bind(console) : console.debug.bind(console),
|
||||
schemaGenerator: {
|
||||
disableForeignKeys: false,
|
||||
},
|
||||
migrations: {
|
||||
path: './database/migrations',
|
||||
pathTs: './database/migrations',
|
||||
tableName: 'migrations',
|
||||
transactional: true,
|
||||
allOrNothing: true,
|
||||
dropTables: false,
|
||||
safe: true,
|
||||
emit: 'ts',
|
||||
},
|
||||
connect: true,
|
||||
allowGlobalContext: true,
|
||||
driverOptions: {
|
||||
connection: {
|
||||
keepAlive: true,
|
||||
keepAliveInitialDelayMillis: 10000,
|
||||
statement_timeout: 60000,
|
||||
query_timeout: 60000,
|
||||
idle_in_transaction_session_timeout: 60000,
|
||||
connectionTimeoutMillis: 10000,
|
||||
application_name: DB_NAME,
|
||||
},
|
||||
connectionRetries: 5,
|
||||
connectionRetryDelay: 3000,
|
||||
validateConnection: (connection: any) => {
|
||||
try {
|
||||
return !!(connection && !connection.closed);
|
||||
} catch (e: unknown) {
|
||||
// Use console.error directly
|
||||
console.error(`Connection validation failed: ${(e as Error).message}`);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
poolErrorHandler: (err: Error) => {
|
||||
// Use console.error directly
|
||||
console.error(`PostgreSQL pool error: ${err.message}`);
|
||||
if (err.message.includes('ECONNRESET') || err.message.includes('Connection terminated unexpectedly')) {
|
||||
console.warn('Connection reset detected, will attempt to reconnect');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,109 @@
|
||||
import type { MikroOrmModuleAsyncOptions } from '@mikro-orm/nestjs';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { PostgreSqlDriver } from '@mikro-orm/postgresql';
|
||||
// import { defineConfig } from '@mikro-orm/postgresql';
|
||||
|
||||
import type { Logger } from '@nestjs/common';
|
||||
import { MIKRO_ORM_QUERY_LOGGER } from '../common/constants';
|
||||
import { mikroOrmQueryLoggerProvider } from '../common/providers/mikro-orm-logger.provider';
|
||||
|
||||
const dataBaseConfig: MikroOrmModuleAsyncOptions = {
|
||||
// entities: ['dist/**/*.entity.js'],
|
||||
// entitiesTs: ['src/**/*.entity.ts'],
|
||||
// dbName: 'your_db_name',
|
||||
// type: 'postgresql',
|
||||
// user: 'your_user',
|
||||
// password: 'your_password',
|
||||
// host: 'localhost',
|
||||
// port: 5432,
|
||||
// debug: true,
|
||||
|
||||
inject: [ConfigService, MIKRO_ORM_QUERY_LOGGER],
|
||||
providers: [mikroOrmQueryLoggerProvider],
|
||||
useFactory: (configService: ConfigService, logger: Logger) => {
|
||||
const DB_PASS = configService.getOrThrow<string>('DB_PASS');
|
||||
const DB_USER = configService.getOrThrow<string>('DB_USER');
|
||||
const DB_HOST = configService.getOrThrow<string>('DB_HOST');
|
||||
const DB_PORT = configService.getOrThrow<number>('DB_PORT');
|
||||
const DB_NAME = configService.getOrThrow<string>('DB_NAME');
|
||||
const encodedPassword = encodeURIComponent(DB_PASS);
|
||||
const isProduction = configService.getOrThrow<string>('NODE_ENV') === 'production';
|
||||
|
||||
return ({
|
||||
// entities: ['dist/**/*.entity.js'],
|
||||
entitiesTs: ['src/**/*.entity.ts'],
|
||||
driver: PostgreSqlDriver,
|
||||
autoLoadEntities: true,
|
||||
dbName: DB_NAME,
|
||||
debug: !isProduction,
|
||||
clientUrl: `postgres://${DB_USER}:${encodedPassword}@${DB_HOST}:${DB_PORT}`,
|
||||
ensureDatabase: isProduction
|
||||
? false
|
||||
: {
|
||||
forceCheck: true,
|
||||
create: true,
|
||||
schema: 'update',
|
||||
},
|
||||
forceUtcTimezone: true,
|
||||
pool: {
|
||||
min: isProduction ? 5 : 2,
|
||||
max: isProduction ? 20 : 10,
|
||||
idleTimeoutMillis: 30000,
|
||||
acquireTimeoutMillis: 30000,
|
||||
reapIntervalMillis: 1000,
|
||||
createTimeoutMillis: 15000,
|
||||
destroyTimeoutMillis: 5000,
|
||||
},
|
||||
logger: isProduction ? message => logger.log(message) : message => logger.debug(message),
|
||||
schemaGenerator: {
|
||||
// createForeignKey: !isProduction,
|
||||
disableForeignKeys: false,
|
||||
// createIndex: true,
|
||||
},
|
||||
migrations: {
|
||||
path: './database/migrations',
|
||||
pathTs: './database/migrations',
|
||||
tableName: 'migrations',
|
||||
transactional: true,
|
||||
allOrNothing: true,
|
||||
dropTables: false,
|
||||
safe: true,
|
||||
emit: 'ts',
|
||||
},
|
||||
connect: true,
|
||||
allowGlobalContext: true,
|
||||
driverOptions: {
|
||||
connection: {
|
||||
keepAlive: true,
|
||||
keepAliveInitialDelayMillis: 10000,
|
||||
statement_timeout: 60000,
|
||||
query_timeout: 60000,
|
||||
idle_in_transaction_session_timeout: 60000,
|
||||
connectionTimeoutMillis: 10000,
|
||||
application_name: configService.getOrThrow<string>('DB_NAME'),
|
||||
},
|
||||
connectionRetries: 5,
|
||||
connectionRetryDelay: 3000,
|
||||
validateConnection: (connection: any) => {
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
return !!(connection && !connection.closed);
|
||||
} catch (e: unknown) {
|
||||
logger.error(`Connection validation failed: ${(e as Error).message}`);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
poolErrorHandler: (err: Error) => {
|
||||
logger.error(`PostgreSQL pool error: ${err.message}`);
|
||||
if (err.message.includes('ECONNRESET') || err.message.includes('Connection terminated unexpectedly')) {
|
||||
logger.warn('Connection reset detected, will attempt to reconnect');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default dataBaseConfig;
|
||||
@@ -0,0 +1,22 @@
|
||||
import type { INestApplication } from '@nestjs/common';
|
||||
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
||||
|
||||
export function getSwaggerConfig(app: INestApplication) {
|
||||
const config = new DocumentBuilder()
|
||||
.setTitle('Tahavol API')
|
||||
.setDescription('API documentation for Tahavol backend')
|
||||
.setVersion('1.0')
|
||||
.addBearerAuth() // optional: for JWT endpoints
|
||||
.build();
|
||||
|
||||
const document = SwaggerModule.createDocument(app, config);
|
||||
|
||||
SwaggerModule.setup('docs', app, document, {
|
||||
swaggerOptions: {
|
||||
persistAuthorization: true,
|
||||
displayRequestDuration: true,
|
||||
filter: true,
|
||||
showExtensions: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user