Skip to content

Commit

Permalink
Add .history to .gitignore, update .env.example with Throttler config…
Browse files Browse the repository at this point in the history
…urations, remove main.hmr.ts, update .vscode/settings.json with i18n-ally.localesPaths, update app.module.ts with ClsModule and ThrottlerModule configurations, update unique.validator.ts and exists.validator.ts with TypeScript improvements, update context.provider.ts with ClsServiceManager, and remove rateLimit middleware from main.ts
  • Loading branch information
NarHakobyan committed Jan 5, 2024
1 parent 07091de commit 249298a
Show file tree
Hide file tree
Showing 14 changed files with 2,568 additions and 2,038 deletions.
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,7 @@ NATS_PORT=4222
REDIS_CACHE_ENABLED=true
REDIS_HOST=localhost
REDIS_PORT=6379

#== Throttler
THROTTLER_TTL=1m
THROTTLER_LIMIT=10
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,7 @@ db-data
.temp
.cache
.DS_Store


# Local History
.history
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,8 @@
"postgres"
],
"editor.detectIndentation": false,
"rift.autostart": false
"rift.autostart": false,
"i18n-ally.localesPaths": [
"src/i18n"
]
}
126 changes: 59 additions & 67 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
"license": "MIT",
"scripts": {
"build:prod": "tsc -p tsconfig.build.json",
"postbuild:prod": "copyfiles --up 1 src/**/*.json dist",
"start:hmr": "node dist/main.hmr.ts",
"start:dev": "ts-node src/main.ts",
"start:prod": "node dist/main.js",
"typeorm": "typeorm-ts-node-esm",
Expand All @@ -19,7 +17,6 @@
"schema:drop": "yarn run typeorm schema:drop",
"watch:dev": "ts-node-dev src/main.ts",
"debug:dev": "cross-env TS_NODE_CACHE=false ts-node-dev --inspect --ignore '/^src/.*\\.spec\\.ts$/' src/main.ts",
"webpack": "webpack --config webpack.config.js --progress",
"lint": "eslint . --ext .ts",
"lint:fix": "eslint --fix . --ext .ts",
"test": "NODE_ENV=test jest",
Expand All @@ -34,95 +31,90 @@
"release": "release-it"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.369.0",
"@nestjs/common": "^10.0.5",
"@nestjs/config": "^3.0.0",
"@nestjs/core": "^10.0.5",
"@nestjs/cqrs": "^10.0.1",
"@nestjs/jwt": "^10.1.0",
"@nestjs/microservices": "^10.0.5",
"@nestjs/passport": "^10.0.0",
"@nestjs/platform-express": "^10.0.5",
"@nestjs/swagger": "^7.1.1",
"@nestjs/terminus": "^10.0.1",
"@nestjs/typeorm": "^10.0.0",
"bcrypt": "^5.1.0",
"@aws-sdk/client-s3": "^3.485.0",
"@nestjs/common": "^10.3.0",
"@nestjs/config": "^3.1.1",
"@nestjs/core": "^10.3.0",
"@nestjs/cqrs": "^10.2.6",
"@nestjs/jwt": "^10.2.0",
"@nestjs/microservices": "^10.3.0",
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-express": "^10.3.0",
"@nestjs/swagger": "^7.1.17",
"@nestjs/terminus": "^10.2.0",
"@nestjs/throttler": "^5.1.1",
"@nestjs/typeorm": "^10.0.1",
"bcrypt": "^5.1.1",
"cache-manager-redis-store": "^3.0.1",
"class-transformer": "~0.5.1",
"class-validator": "~0.14.0",
"compression": "^1.7.4",
"express": "^4.18.2",
"express-ctx": "^0.1.1",
"express-rate-limit": "^6.7.1",
"helmet": "^7.0.0",
"jsonwebtoken": "^9.0.1",
"helmet": "^7.1.0",
"jsonwebtoken": "^9.0.2",
"lodash": "^4.17.21",
"mime-types": "^2.1.35",
"morgan": "^1.10.0",
"nestjs-i18n": "^10.2.6",
"nestjs-cls": "^3.6.0",
"nestjs-i18n": "^10.4.0",
"parse-duration": "^1.1.0",
"passport": "^0.6.0",
"passport-jwt": "^4.0.1",
"pg": "^8.11.1",
"reflect-metadata": "^0.1.13",
"pg": "^8.11.3",
"reflect-metadata": "^0.2.1",
"rxjs": "^7.8.1",
"source-map-support": "^0.5.21",
"swagger-ui-express": "^5.0.0",
"tslib": "^2.6.2",
"typeorm": "^0.3.17",
"typeorm-transactional": "~0.4.1",
"uuid": "^9.0.0"
"typeorm": "^0.3.19",
"typeorm-transactional": "~0.5.0",
"uuid": "^9.0.1"
},
"devDependencies": {
"@handfish/hygen": "^6.1.6",
"@nestjs/cli": "^10.1.8",
"@nestjs/testing": "^10.0.5",
"@types/bcrypt": "^5.0.0",
"@types/cache-manager-redis-store": "^2.0.1",
"@types/compression": "^1.7.2",
"@types/express": "^4.17.17",
"@types/jest": "^29.5.0",
"@types/jsonwebtoken": "^9.0.1",
"@types/lodash": "^4.14.191",
"@types/mime-types": "^2.1.1",
"@types/morgan": "^1.9.4",
"@types/node": "^20.4.2",
"@types/passport-jwt": "^3.0.9",
"@types/supertest": "^2.0.12",
"@types/uuid": "^9.0.2",
"@types/webpack-env": "^1.18.1",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"@vuepress/client": "2.0.0-beta.66",
"clean-webpack-plugin": "^4.0.0",
"copyfiles": "^2.4.1",
"@nestjs/cli": "^10.2.1",
"@nestjs/testing": "^10.3.0",
"@types/bcrypt": "^5.0.2",
"@types/cache-manager-redis-store": "^2.0.4",
"@types/compression": "^1.7.5",
"@types/express": "^4.17.21",
"@types/jest": "^29.5.11",
"@types/jsonwebtoken": "^9.0.5",
"@types/lodash": "^4.14.202",
"@types/mime-types": "^2.1.4",
"@types/morgan": "^1.9.9",
"@types/node": "^20.10.6",
"@types/passport-jwt": "^3.0.13",
"@types/supertest": "^2.0.16",
"@types/uuid": "^9.0.7",
"@typescript-eslint/eslint-plugin": "^6.17.0",
"@typescript-eslint/parser": "^6.17.0",
"@vuepress/client": "^2.0.0-rc.0",
"cross-env": "^7.0.3",
"eslint": "^8.47.0",
"eslint-config-prettier": "^9.0.0",
"eslint-import-resolver-typescript": "^3.6.0",
"eslint-plugin-canonical": "^4.9.0",
"eslint-plugin-import": "^2.27.5",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-canonical": "^4.18.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-import-helpers": "^1.3.1",
"eslint-plugin-n": "^16.0.1",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-n": "^16.6.1",
"eslint-plugin-prettier": "^5.1.2",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-simple-import-sort": "^10.0.0",
"eslint-plugin-sonarjs": "^0.20.0",
"eslint-plugin-unicorn": "^48.0.1",
"gh-pages": "^6.0.0",
"eslint-plugin-sonarjs": "^0.23.0",
"eslint-plugin-unicorn": "^50.0.1",
"gh-pages": "^6.1.1",
"husky": "^8.0.3",
"jest": "^29.6.1",
"lint-staged": "~13.2.3",
"prettier": "^3.0.0",
"release-it": "^16.1.0",
"jest": "^29.7.0",
"lint-staged": "~15.2.0",
"prettier": "^3.1.1",
"release-it": "^17.0.1",
"supertest": "^6.3.3",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
"ts-node": "^10.9.2",
"ts-node-dev": "^2.0.0",
"typescript": "^5.1.6",
"vue": "^3.3.4",
"webpack": "^5.88.1",
"webpack-cli": "^5.1.4",
"webpack-node-externals": "^3.0.0"
"typescript": "^5.3.3",
"vue": "^3.4.5"
},
"jest": {
"moduleFileExtensions": [
Expand Down
15 changes: 15 additions & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import path from 'node:path';

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { ThrottlerModule } from '@nestjs/throttler';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ClsModule } from 'nestjs-cls';
import {
AcceptLanguageResolver,
HeaderResolver,
Expand All @@ -26,6 +28,19 @@ import { SharedModule } from './shared/shared.module';
AuthModule,
UserModule,
PostModule,
ClsModule.forRoot({
global: true,
middleware: {
mount: true,
},
}),
ThrottlerModule.forRootAsync({
imports: [SharedModule],
useFactory: (configService: ApiConfigService) => ({
throttlers: [configService.throttlerConfigs],
}),
inject: [ApiConfigService],
}),
ConfigModule.forRoot({
isGlobal: true,
envFilePath: '.env',
Expand Down
8 changes: 0 additions & 8 deletions src/main.hmr.ts

This file was deleted.

10 changes: 0 additions & 10 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import {
type NestExpressApplication,
} from '@nestjs/platform-express';
import compression from 'compression';
import { middleware as expressCtx } from 'express-ctx';
import rateLimit from 'express-rate-limit';
import helmet from 'helmet';
import morgan from 'morgan';
import { initializeTransactionalContext } from 'typeorm-transactional';
Expand All @@ -36,12 +34,6 @@ export async function bootstrap(): Promise<NestExpressApplication> {
app.enable('trust proxy'); // only if you're behind a reverse proxy (Heroku, Bluemix, AWS ELB, Nginx, etc)
app.use(helmet());
// app.setGlobalPrefix('/api'); use api as global prefix if you don't have subdomain
app.use(
rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
}),
);
app.use(compression());
app.use(morgan('combined'));
app.enableVersioning();
Expand Down Expand Up @@ -90,8 +82,6 @@ export async function bootstrap(): Promise<NestExpressApplication> {
setupSwagger(app);
}

app.use(expressCtx);

// Starts listening for shutdown hooks
if (!configService.isDevelopment) {
app.enableShutdownHooks();
Expand Down
12 changes: 8 additions & 4 deletions src/providers/context.provider.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getValue, setValue } from 'express-ctx';
import { ClsServiceManager } from 'nestjs-cls';

import { type LanguageCode } from '../constants';
import { type UserEntity } from '../modules/user/user.entity';
Expand All @@ -10,13 +10,17 @@ export class ContextProvider {

private static readonly languageKey = 'language_key';

private static get<T>(key: string): T | undefined {
return getValue<T>(ContextProvider.getKeyWithNamespace(key));
private static get<T>(key: string) {
const store = ClsServiceManager.getClsService();

return store.get<T>(ContextProvider.getKeyWithNamespace(key));
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
private static set(key: string, value: any): void {
setValue(ContextProvider.getKeyWithNamespace(key), value);
const store = ClsServiceManager.getClsService();

store.set(ContextProvider.getKeyWithNamespace(key), value);
}

private static getKeyWithNamespace(key: string): string {
Expand Down
51 changes: 23 additions & 28 deletions src/shared/services/api-config.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { type ThrottlerOptions } from '@nestjs/throttler';
import { type TypeOrmModuleOptions } from '@nestjs/typeorm';
import { isNil } from 'lodash';
import { default as parse, type Units } from 'parse-duration';

import { UserSubscriber } from '../../entity-subscribers/user-subscriber';
import { SnakeNamingStrategy } from '../../snake-naming.strategy';
Expand Down Expand Up @@ -32,6 +34,17 @@ export class ApiConfigService {
}
}

private getDuration(key: string, format?: Units): number {
const value = this.getString(key);
const duration = parse(value, format);

if (duration === undefined) {
throw new Error(`${key} environment variable is not a valid duration`);
}

return duration;
}

private getBoolean(key: string): boolean {
const value = this.get(key);

Expand All @@ -56,38 +69,20 @@ export class ApiConfigService {
return this.getString('FALLBACK_LANGUAGE');
}

get throttlerConfigs(): ThrottlerOptions {
return {
ttl: this.getDuration('THROTTLER_TTL', 'second'),
limit: this.getNumber('THROTTLER_LIMIT'),
// storage: new ThrottlerStorageRedisService(new Redis(this.redis)),
};
}

get postgresConfig(): TypeOrmModuleOptions {
let entities = [
const entities = [
__dirname + '/../../modules/**/*.entity{.ts,.js}',
__dirname + '/../../modules/**/*.view-entity{.ts,.js}',
];
let migrations = [__dirname + '/../../database/migrations/*{.ts,.js}'];

if (module.hot) {
const entityContext = require.context(
'./../../modules',
true,
/\.entity\.ts$/,
);
entities = entityContext.keys().map((id) => {
const entityModule = entityContext<Record<string, unknown>>(id);
const [entity] = Object.values(entityModule);

return entity as string;
});
const migrationContext = require.context(
'./../../database/migrations',
false,
/\.ts$/,
);

migrations = migrationContext.keys().map((id) => {
const migrationModule = migrationContext<Record<string, unknown>>(id);
const [migration] = Object.values(migrationModule);

return migration as string;
});
}
const migrations = [__dirname + '/../../database/migrations/*{.ts,.js}'];

return {
entities,
Expand Down
Loading

0 comments on commit 249298a

Please sign in to comment.