@urbansolv/create-nestjs-app 1.2.4 → 1.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/templates/nestjs-app/src/common/dto/api-response.dto.ts +2 -2
  2. package/dist/templates/nestjs-app/src/common/filters/http-exception.filter.ts +1 -1
  3. package/dist/templates/nestjs-app/src/common/interceptors/transform.interceptor.ts +2 -2
  4. package/dist/templates/nestjs-app/src/common/prisma/prisma.service.ts +0 -1
  5. package/dist/templates/nestjs-app/src/modules/auth/auth.service.ts +0 -7
  6. package/dist/templates/nestjs-app/src/modules/auth/controllers/v1/auth.controller.ts +4 -0
  7. package/dist/templates/nestjs-app/src/modules/users/controllers/v1/users.controller.ts +2 -2
  8. package/dist/templates/nestjs-app/src/modules/users/users.service.ts +4 -0
  9. package/package.json +2 -1
  10. package/templates/nestjs-app/.editorconfig +12 -0
  11. package/templates/nestjs-app/.env.example +24 -0
  12. package/templates/nestjs-app/.eslintrc.js +25 -0
  13. package/templates/nestjs-app/.prettierrc +8 -0
  14. package/templates/nestjs-app/README.md +133 -0
  15. package/templates/nestjs-app/nest-cli.json +10 -0
  16. package/templates/nestjs-app/package.json +88 -0
  17. package/templates/nestjs-app/prisma/schema.prisma +79 -0
  18. package/templates/nestjs-app/prisma/seed.ts +153 -0
  19. package/templates/nestjs-app/src/app.module.ts +68 -0
  20. package/templates/nestjs-app/src/common/constants/permissions.constant.ts +27 -0
  21. package/templates/nestjs-app/src/common/decorators/api-response.decorator.ts +44 -0
  22. package/templates/nestjs-app/src/common/decorators/get-user.decorator.ts +11 -0
  23. package/templates/nestjs-app/src/common/decorators/permissions.decorator.ts +5 -0
  24. package/templates/nestjs-app/src/common/decorators/public.decorator.ts +4 -0
  25. package/templates/nestjs-app/src/common/dto/api-response.dto.ts +21 -0
  26. package/templates/nestjs-app/src/common/dto/pagination.dto.ts +33 -0
  27. package/templates/nestjs-app/src/common/filters/http-exception.filter.ts +56 -0
  28. package/templates/nestjs-app/src/common/guards/jwt-auth.guard.ts +32 -0
  29. package/templates/nestjs-app/src/common/guards/permissions.guard.ts +53 -0
  30. package/templates/nestjs-app/src/common/interceptors/logging.interceptor.ts +37 -0
  31. package/templates/nestjs-app/src/common/interceptors/transform.interceptor.ts +55 -0
  32. package/templates/nestjs-app/src/common/prisma/prisma.module.ts +9 -0
  33. package/templates/nestjs-app/src/common/prisma/prisma.service.ts +45 -0
  34. package/templates/nestjs-app/src/common/utils/password.util.ts +13 -0
  35. package/templates/nestjs-app/src/config/app.config.ts +10 -0
  36. package/templates/nestjs-app/src/config/database.config.ts +5 -0
  37. package/templates/nestjs-app/src/config/env.validation.ts +30 -0
  38. package/templates/nestjs-app/src/config/jwt.config.ts +8 -0
  39. package/templates/nestjs-app/src/config/swagger.config.ts +6 -0
  40. package/templates/nestjs-app/src/main.ts +93 -0
  41. package/templates/nestjs-app/src/modules/auth/auth.module.ts +28 -0
  42. package/templates/nestjs-app/src/modules/auth/auth.service.ts +173 -0
  43. package/templates/nestjs-app/src/modules/auth/controllers/v1/auth.controller.ts +37 -0
  44. package/templates/nestjs-app/src/modules/auth/core/dto/auth-response.dto.ts +19 -0
  45. package/templates/nestjs-app/src/modules/auth/core/dto/login-response.dto.ts +10 -0
  46. package/templates/nestjs-app/src/modules/auth/core/dto/login.dto.ts +15 -0
  47. package/templates/nestjs-app/src/modules/auth/core/dto/register.dto.ts +30 -0
  48. package/templates/nestjs-app/src/modules/auth/core/interfaces/jwt-payload.interface.ts +7 -0
  49. package/templates/nestjs-app/src/modules/auth/core/strategies/jwt.strategy.ts +54 -0
  50. package/templates/nestjs-app/src/modules/health/health.controller.ts +29 -0
  51. package/templates/nestjs-app/src/modules/health/health.module.ts +7 -0
  52. package/templates/nestjs-app/src/modules/users/controllers/v1/users.controller.ts +118 -0
  53. package/templates/nestjs-app/src/modules/users/core/dto/change-position.dto.ts +9 -0
  54. package/templates/nestjs-app/src/modules/users/core/dto/create-user.dto.ts +35 -0
  55. package/templates/nestjs-app/src/modules/users/core/dto/manage-permissions.dto.ts +13 -0
  56. package/templates/nestjs-app/src/modules/users/core/dto/update-user.dto.ts +30 -0
  57. package/templates/nestjs-app/src/modules/users/core/dto/user-query.dto.ts +22 -0
  58. package/templates/nestjs-app/src/modules/users/core/dto/user-response.dto.ts +32 -0
  59. package/templates/nestjs-app/src/modules/users/core/entities/user.entity.ts +45 -0
  60. package/templates/nestjs-app/src/modules/users/core/helpers/user-transform.helper.ts +31 -0
  61. package/templates/nestjs-app/src/modules/users/users.module.ts +10 -0
  62. package/templates/nestjs-app/src/modules/users/users.service.ts +344 -0
  63. package/templates/nestjs-app/test/app.e2e-spec.ts +40 -0
  64. package/templates/nestjs-app/test/jest-e2e.json +9 -0
  65. package/templates/nestjs-app/tsconfig.json +26 -0
@@ -0,0 +1,13 @@
1
+ import { ApiProperty } from '@nestjs/swagger';
2
+ import { IsArray, ArrayNotEmpty, IsString } from 'class-validator';
3
+
4
+ export class ManagePermissionsDto {
5
+ @ApiProperty({
6
+ example: ['VIEW_USER', 'ADD_USER'],
7
+ description: 'Array of permission names to assign or revoke'
8
+ })
9
+ @IsArray()
10
+ @ArrayNotEmpty({ message: 'Permissions array cannot be empty' })
11
+ @IsString({ each: true })
12
+ permissions: string[];
13
+ }
@@ -0,0 +1,30 @@
1
+ import { ApiPropertyOptional } from '@nestjs/swagger';
2
+ import { IsEmail, IsString, MinLength, IsBoolean, IsOptional } from 'class-validator';
3
+
4
+ export class UpdateUserDto {
5
+ @ApiPropertyOptional({ example: 'bhagaskoro@urbansolv.co.id' })
6
+ @IsEmail({}, { message: 'Please provide a valid email address' })
7
+ @IsOptional()
8
+ email?: string;
9
+
10
+ @ApiPropertyOptional({ example: 'newpassword123' })
11
+ @IsString()
12
+ @MinLength(6, { message: 'Password must be at least 6 characters long' })
13
+ @IsOptional()
14
+ password?: string;
15
+
16
+ @ApiPropertyOptional({ example: 'Bhagas' })
17
+ @IsString()
18
+ @IsOptional()
19
+ first_name?: string;
20
+
21
+ @ApiPropertyOptional({ example: 'Koro' })
22
+ @IsString()
23
+ @IsOptional()
24
+ last_name?: string;
25
+
26
+ @ApiPropertyOptional({ example: true })
27
+ @IsBoolean()
28
+ @IsOptional()
29
+ is_active?: boolean;
30
+ }
@@ -0,0 +1,22 @@
1
+ import { ApiPropertyOptional } from '@nestjs/swagger';
2
+ import { IsOptional, IsString, IsBoolean } from 'class-validator';
3
+ import { Type } from 'class-transformer';
4
+ import { PaginationDto } from '@common/dto/pagination.dto';
5
+
6
+ export class UserQueryDto extends PaginationDto {
7
+ @ApiPropertyOptional({ example: 'bhagas' })
8
+ @IsOptional()
9
+ @IsString()
10
+ search?: string;
11
+
12
+ @ApiPropertyOptional({ example: true })
13
+ @IsOptional()
14
+ @Type(() => Boolean)
15
+ @IsBoolean()
16
+ is_active?: boolean;
17
+
18
+ @ApiPropertyOptional({ example: 1 })
19
+ @IsOptional()
20
+ @Type(() => Number)
21
+ position_id?: number;
22
+ }
@@ -0,0 +1,32 @@
1
+ import { ApiProperty } from '@nestjs/swagger';
2
+ import { Exclude } from 'class-transformer';
3
+
4
+ export class UserResponseDto {
5
+ @ApiProperty()
6
+ id: number;
7
+
8
+ @ApiProperty()
9
+ email: string;
10
+
11
+ @ApiProperty({ required: false })
12
+ first_name?: string;
13
+
14
+ @ApiProperty({ required: false })
15
+ last_name?: string;
16
+
17
+ @ApiProperty()
18
+ is_active: boolean;
19
+
20
+ @ApiProperty()
21
+ created_at: Date;
22
+
23
+ @ApiProperty()
24
+ updated_at: Date;
25
+
26
+ @Exclude()
27
+ password: string;
28
+
29
+ constructor(partial: Partial<UserResponseDto>) {
30
+ Object.assign(this, partial);
31
+ }
32
+ }
@@ -0,0 +1,45 @@
1
+ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
2
+ import { User as PrismaUser, Position } from '@prisma/client';
3
+ import { Exclude } from 'class-transformer';
4
+
5
+ export class UserEntity implements Partial<PrismaUser> {
6
+ @ApiProperty()
7
+ id: number;
8
+
9
+ @ApiProperty()
10
+ email: string;
11
+
12
+ @Exclude()
13
+ password: string;
14
+
15
+ @ApiProperty()
16
+ first_name: string;
17
+
18
+ @ApiProperty()
19
+ last_name: string;
20
+
21
+ @ApiProperty()
22
+ is_active: boolean;
23
+
24
+ @ApiProperty()
25
+ position_id: number;
26
+
27
+ @ApiPropertyOptional()
28
+ position?: Partial<Position>;
29
+
30
+ @ApiPropertyOptional()
31
+ permissions?: string[];
32
+
33
+ @ApiProperty()
34
+ created_at: Date;
35
+
36
+ @ApiProperty()
37
+ updated_at: Date;
38
+
39
+ @ApiPropertyOptional()
40
+ deleted_at: Date | null;
41
+
42
+ constructor(partial: Partial<UserEntity>) {
43
+ Object.assign(this, partial);
44
+ }
45
+ }
@@ -0,0 +1,31 @@
1
+ import { User, Position, PositionPermission, Permission } from '@prisma/client';
2
+ import { UserEntity } from '../entities/user.entity';
3
+ type UserWithRelations = User & {
4
+ position?: Position & {
5
+ position_permissions?: (PositionPermission & {
6
+ permission: Permission;
7
+ })[];
8
+ };
9
+ };
10
+
11
+ export class UserTransformHelper {
12
+ static toEntity(user: UserWithRelations): UserEntity {
13
+ const permissions = user.position?.position_permissions?.map(
14
+ (pp) => pp.permission.name,
15
+ ) || [];
16
+
17
+ return new UserEntity({
18
+ ...user,
19
+ permissions,
20
+ position: user.position ? {
21
+ id: user.position.id,
22
+ name: user.position.name,
23
+ description: user.position.description,
24
+ } : undefined,
25
+ });
26
+ }
27
+
28
+ static toEntities(users: UserWithRelations[]): UserEntity[] {
29
+ return users.map((user) => this.toEntity(user));
30
+ }
31
+ }
@@ -0,0 +1,10 @@
1
+ import { Module } from '@nestjs/common';
2
+ import { UsersService } from './users.service';
3
+ import { UsersController } from './controllers/v1/users.controller';
4
+
5
+ @Module({
6
+ controllers: [UsersController],
7
+ providers: [UsersService],
8
+ exports: [UsersService],
9
+ })
10
+ export class UsersModule {}
@@ -0,0 +1,344 @@
1
+ import {
2
+ Injectable,
3
+ NotFoundException,
4
+ ConflictException,
5
+ BadRequestException,
6
+ } from '@nestjs/common';
7
+ import { PrismaService } from '@common/prisma/prisma.service';
8
+ import { PasswordUtil } from '@common/utils/password.util';
9
+ import { CreateUserDto } from './core/dto/create-user.dto';
10
+ import { UpdateUserDto } from './core/dto/update-user.dto';
11
+ import { ChangePositionDto } from './core/dto/change-position.dto';
12
+ import { ManagePermissionsDto } from './core/dto/manage-permissions.dto';
13
+ import { UserQueryDto } from './core/dto/user-query.dto';
14
+ import { UserEntity } from './core/entities/user.entity';
15
+ import { UserTransformHelper } from './core/helpers/user-transform.helper';
16
+ import { PaginatedResponseDto } from '@common/dto/pagination.dto';
17
+
18
+ @Injectable()
19
+ export class UsersService {
20
+ constructor(private prisma: PrismaService) {}
21
+
22
+ async create(createUserDto: CreateUserDto): Promise<UserEntity> {
23
+ const { email, password, position_id, ...userData } = createUserDto;
24
+
25
+ // Check if email already exists
26
+ const existingUser = await this.prisma.user.findUnique({
27
+ where: { email },
28
+ });
29
+
30
+ if (existingUser) {
31
+ throw new ConflictException('Email already exists');
32
+ }
33
+
34
+ // Validate position exists
35
+ const position = await this.prisma.position.findUnique({
36
+ where: { id: position_id },
37
+ });
38
+
39
+ if (!position) {
40
+ throw new BadRequestException('Invalid position ID');
41
+ }
42
+
43
+ // Hash password
44
+ const hashedPassword = await PasswordUtil.hash(password);
45
+
46
+ // Create user
47
+ const user = await this.prisma.user.create({
48
+ data: {
49
+ email,
50
+ password: hashedPassword,
51
+ position_id,
52
+ ...userData,
53
+ },
54
+ include: {
55
+ position: {
56
+ include: {
57
+ position_permissions: {
58
+ include: {
59
+ permission: true,
60
+ },
61
+ },
62
+ },
63
+ },
64
+ },
65
+ });
66
+
67
+ return UserTransformHelper.toEntity(user);
68
+ }
69
+
70
+ async findAll(query: UserQueryDto): Promise<PaginatedResponseDto<UserEntity>> {
71
+ const { page = 1, limit = 10, search, is_active, position_id } = query;
72
+ const skip = (page - 1) * limit;
73
+
74
+ const where: any = {
75
+ deleted_at: null,
76
+ };
77
+
78
+ if (search) {
79
+ where.OR = [
80
+ { first_name: { contains: search, mode: 'insensitive' } },
81
+ { last_name: { contains: search, mode: 'insensitive' } },
82
+ { email: { contains: search, mode: 'insensitive' } },
83
+ ];
84
+ }
85
+
86
+ if (is_active !== undefined) {
87
+ where.is_active = is_active;
88
+ }
89
+
90
+ if (position_id) {
91
+ where.position_id = position_id;
92
+ }
93
+
94
+ const [users, total] = await Promise.all([
95
+ this.prisma.user.findMany({
96
+ where,
97
+ skip,
98
+ take: limit,
99
+ include: {
100
+ position: {
101
+ include: {
102
+ position_permissions: {
103
+ include: {
104
+ permission: true,
105
+ },
106
+ },
107
+ },
108
+ },
109
+ },
110
+ orderBy: {
111
+ created_at: 'desc',
112
+ },
113
+ }),
114
+ this.prisma.user.count({ where }),
115
+ ]);
116
+
117
+ if (total === 0) {
118
+ throw new NotFoundException('No users found');
119
+ }
120
+
121
+ return {
122
+ data: UserTransformHelper.toEntities(users),
123
+ meta: {
124
+ total,
125
+ page,
126
+ limit,
127
+ totalPages: Math.ceil(total / limit),
128
+ },
129
+ };
130
+ }
131
+
132
+ async findOne(id: number): Promise<UserEntity> {
133
+ const user = await this.prisma.user.findFirst({
134
+ where: { id, deleted_at: null },
135
+ include: {
136
+ position: {
137
+ include: {
138
+ position_permissions: {
139
+ include: {
140
+ permission: true,
141
+ },
142
+ },
143
+ },
144
+ },
145
+ },
146
+ });
147
+
148
+ if (!user) {
149
+ throw new NotFoundException(`User with ID ${id} not found`);
150
+ }
151
+
152
+ return UserTransformHelper.toEntity(user);
153
+ }
154
+
155
+ async update(id: number, updateUserDto: UpdateUserDto): Promise<UserEntity> {
156
+ const user = await this.prisma.user.findFirst({
157
+ where: { id, deleted_at: null },
158
+ });
159
+
160
+ if (!user) {
161
+ throw new NotFoundException(`User with ID ${id} not found`);
162
+ }
163
+
164
+ const { email, password, ...updateData } = updateUserDto;
165
+
166
+ // Check email uniqueness if changing email
167
+ if (email && email !== user.email) {
168
+ const existingUser = await this.prisma.user.findUnique({
169
+ where: { email },
170
+ });
171
+
172
+ if (existingUser) {
173
+ throw new ConflictException('Email already exists');
174
+ }
175
+ }
176
+
177
+ // Hash password if provided
178
+ let hashedPassword: string | undefined;
179
+ if (password) {
180
+ hashedPassword = await PasswordUtil.hash(password);
181
+ }
182
+
183
+ const updatedUser = await this.prisma.user.update({
184
+ where: { id },
185
+ data: {
186
+ ...updateData,
187
+ ...(email && { email }),
188
+ ...(hashedPassword && { password: hashedPassword }),
189
+ },
190
+ include: {
191
+ position: {
192
+ include: {
193
+ position_permissions: {
194
+ include: {
195
+ permission: true,
196
+ },
197
+ },
198
+ },
199
+ },
200
+ },
201
+ });
202
+
203
+ return UserTransformHelper.toEntity(updatedUser);
204
+ }
205
+
206
+ async remove(id: number): Promise<void> {
207
+ const user = await this.prisma.user.findFirst({
208
+ where: { id, deleted_at: null },
209
+ });
210
+
211
+ if (!user) {
212
+ throw new NotFoundException(`User with ID ${id} not found`);
213
+ }
214
+
215
+ // Soft delete
216
+ await this.prisma.user.update({
217
+ where: { id },
218
+ data: { deleted_at: new Date() },
219
+ });
220
+ }
221
+
222
+ async changePosition(id: number, changePositionDto: ChangePositionDto): Promise<UserEntity> {
223
+ const user = await this.prisma.user.findFirst({
224
+ where: { id, deleted_at: null },
225
+ });
226
+
227
+ if (!user) {
228
+ throw new NotFoundException(`User with ID ${id} not found`);
229
+ }
230
+
231
+ // Validate position exists
232
+ const position = await this.prisma.position.findUnique({
233
+ where: { id: changePositionDto.position_id },
234
+ });
235
+
236
+ if (!position) {
237
+ throw new BadRequestException('Invalid position ID');
238
+ }
239
+
240
+ const updatedUser = await this.prisma.user.update({
241
+ where: { id },
242
+ data: { position_id: changePositionDto.position_id },
243
+ include: {
244
+ position: {
245
+ include: {
246
+ position_permissions: {
247
+ include: {
248
+ permission: true,
249
+ },
250
+ },
251
+ },
252
+ },
253
+ },
254
+ });
255
+
256
+ return UserTransformHelper.toEntity(updatedUser);
257
+ }
258
+
259
+ async assignPermissions(
260
+ userId: number,
261
+ managePermissionsDto: ManagePermissionsDto,
262
+ ): Promise<UserEntity> {
263
+ const user = await this.prisma.user.findFirst({
264
+ where: { id: userId, deleted_at: null },
265
+ include: { position: true },
266
+ });
267
+
268
+ if (!user) {
269
+ throw new NotFoundException(`User with ID ${userId} not found`);
270
+ }
271
+
272
+ // Validate all permissions exist
273
+ const permissions = await this.prisma.permission.findMany({
274
+ where: { name: { in: managePermissionsDto.permissions } },
275
+ });
276
+
277
+ if (permissions.length !== managePermissionsDto.permissions.length) {
278
+ throw new BadRequestException('One or more permissions are invalid');
279
+ }
280
+
281
+ // Get current permissions for the position
282
+ const currentPermissions = await this.prisma.positionPermission.findMany({
283
+ where: { position_id: user.position_id },
284
+ });
285
+
286
+ const currentPermissionIds = currentPermissions.map((pp) => pp.permission_id);
287
+ const newPermissionIds = permissions.map((p) => p.id);
288
+
289
+ // Find permissions to add
290
+ const permissionsToAdd = newPermissionIds.filter(
291
+ (id) => !currentPermissionIds.includes(id),
292
+ );
293
+
294
+ // Add new permissions
295
+ if (permissionsToAdd.length > 0) {
296
+ await this.prisma.positionPermission.createMany({
297
+ data: permissionsToAdd.map((permission_id) => ({
298
+ position_id: user.position_id,
299
+ permission_id,
300
+ })),
301
+ skipDuplicates: true,
302
+ });
303
+ }
304
+
305
+ // Return updated user
306
+ return this.findOne(userId);
307
+ }
308
+
309
+ async revokePermissions(
310
+ userId: number,
311
+ managePermissionsDto: ManagePermissionsDto,
312
+ ): Promise<UserEntity> {
313
+ const user = await this.prisma.user.findFirst({
314
+ where: { id: userId, deleted_at: null },
315
+ include: { position: true },
316
+ });
317
+
318
+ if (!user) {
319
+ throw new NotFoundException(`User with ID ${userId} not found`);
320
+ }
321
+
322
+ // Validate all permissions exist
323
+ const permissions = await this.prisma.permission.findMany({
324
+ where: { name: { in: managePermissionsDto.permissions } },
325
+ });
326
+
327
+ if (permissions.length !== managePermissionsDto.permissions.length) {
328
+ throw new BadRequestException('One or more permissions are invalid');
329
+ }
330
+
331
+ const permissionIds = permissions.map((p) => p.id);
332
+
333
+ // Remove permissions
334
+ await this.prisma.positionPermission.deleteMany({
335
+ where: {
336
+ position_id: user.position_id,
337
+ permission_id: { in: permissionIds },
338
+ },
339
+ });
340
+
341
+ // Return updated user
342
+ return this.findOne(userId);
343
+ }
344
+ }
@@ -0,0 +1,40 @@
1
+ import { Test, TestingModule } from '@nestjs/testing';
2
+ import { INestApplication } from '@nestjs/common';
3
+ import * as request from 'supertest';
4
+ import { AppModule } from './../src/app.module';
5
+
6
+ describe('AppController (e2e)', () => {
7
+ let app: INestApplication;
8
+
9
+ beforeEach(async () => {
10
+ const moduleFixture: TestingModule = await Test.createTestingModule({
11
+ imports: [AppModule],
12
+ }).compile();
13
+
14
+ app = moduleFixture.createNestApplication();
15
+ await app.init();
16
+ });
17
+
18
+ it('/health (GET)', () => {
19
+ return request(app.getHttpServer())
20
+ .get('/health')
21
+ .expect(200)
22
+ .expect((res) => {
23
+ expect(res.body).toHaveProperty('status', 'ok');
24
+ expect(res.body).toHaveProperty('timestamp');
25
+ });
26
+ });
27
+
28
+ it('/ping (GET)', () => {
29
+ return request(app.getHttpServer())
30
+ .get('/ping')
31
+ .expect(200)
32
+ .expect((res) => {
33
+ expect(res.body).toHaveProperty('message', 'pong');
34
+ });
35
+ });
36
+
37
+ afterAll(async () => {
38
+ await app.close();
39
+ });
40
+ });
@@ -0,0 +1,9 @@
1
+ {
2
+ "moduleFileExtensions": ["js", "json", "ts"],
3
+ "rootDir": ".",
4
+ "testEnvironment": "node",
5
+ "testRegex": ".e2e-spec.ts$",
6
+ "transform": {
7
+ "^.+\\.(t|j)s$": "ts-node/register"
8
+ }
9
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "commonjs",
4
+ "declaration": true,
5
+ "removeComments": true,
6
+ "emitDecoratorMetadata": true,
7
+ "experimentalDecorators": true,
8
+ "allowSyntheticDefaultImports": true,
9
+ "target": "ES2021",
10
+ "sourceMap": true,
11
+ "outDir": "./dist",
12
+ "baseUrl": "./",
13
+ "incremental": true,
14
+ "skipLibCheck": true,
15
+ "strictNullChecks": false,
16
+ "noImplicitAny": false,
17
+ "strictBindCallApply": false,
18
+ "forceConsistentCasingInFileNames": false,
19
+ "noFallthroughCasesInSwitch": false,
20
+ "paths": {
21
+ "@common/*": ["src/common/*"],
22
+ "@config/*": ["src/config/*"],
23
+ "@modules/*": ["src/modules/*"]
24
+ }
25
+ }
26
+ }