nestjs-prisma-cli 1.0.8 → 1.0.10

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 (29) hide show
  1. package/README.md +17 -3
  2. package/bin/index.js +45 -32
  3. package/package.json +2 -2
  4. package/template/prisma/schema.prisma +34 -17
  5. package/template/src/app.module.ts +7 -2
  6. package/template/src/common/config/index.ts +4 -0
  7. package/template/src/common/config/multer-config.ts +11 -0
  8. package/template/src/common/config/swagger.config.ts +36 -0
  9. package/template/src/common/decorator/index.ts +4 -0
  10. package/template/src/common/decorator/response-message.decorator.ts +5 -0
  11. package/template/src/common/dto/paginated-response.dto.ts +14 -2
  12. package/template/src/common/dto/pagination.dto.ts +18 -0
  13. package/template/src/common/enums/http-error-type-enum.ts +31 -0
  14. package/template/src/common/enums/index.ts +2 -1
  15. package/template/src/common/enums/message-code.enum.ts +2 -0
  16. package/template/src/common/http-interceptor/http-exception.filter.ts +99 -57
  17. package/template/src/common/http-interceptor/logging.interceptor.ts +55 -10
  18. package/template/src/common/http-interceptor/response.interceptor.ts +68 -28
  19. package/template/src/common/s3/s3.service.ts +9 -24
  20. package/template/src/common/utils/pagination.util.ts +46 -16
  21. package/template/src/main.ts +11 -38
  22. package/template/src/modules/auth/auth.controller.ts +21 -0
  23. package/template/src/modules/auth/auth.service.ts +9 -9
  24. package/template/src/modules/auth/jwt/jwt.guard.ts +1 -1
  25. package/template/src/modules/user/dto/create-user.dto.ts +8 -1
  26. package/template/src/modules/user/user.controller.ts +53 -16
  27. package/template/src/modules/user/user.module.ts +3 -0
  28. package/template/src/modules/user/user.service.ts +132 -98
  29. package/template/src/common/classes/base64.ts +0 -22
package/README.md CHANGED
@@ -14,6 +14,7 @@ A CLI tool to quickly scaffold a **NestJS + Prisma** project with built-in suppo
14
14
  - 📖 Swagger (OpenAPI) setup
15
15
  - 🔑 Authentication boilerplate
16
16
  - ☁️ AWS S3 integration
17
+ - 📜 Logging via Winston (rotating logs and DB persistence)
17
18
 
18
19
  Compatible with **Node.js >=18** and **NestJS v10+**.
19
20
 
@@ -31,19 +32,20 @@ Once the CLI is installed, you can use the following commands:
31
32
  npm install -g nestjs-prisma-cli
32
33
  ```
33
34
 
34
-
35
35
  ### 2️⃣ Check CLI version
36
36
 
37
37
  ```bash
38
38
  nestgen -v
39
39
  ```
40
+
40
41
  # or
42
+
41
43
  ```bash
42
44
  nestgen --version
43
45
  ```
44
46
 
45
-
46
47
  ### 3️⃣ Generate a new project
48
+
47
49
  ```bash
48
50
  nestgen
49
51
  ```
@@ -61,31 +63,43 @@ Step 3: 🎉 Project ready! Next steps:
61
63
  ```
62
64
 
63
65
  ### Navigate into your project
66
+
64
67
  ```bash
65
68
  cd my-app
66
69
  ```
70
+
67
71
  ### Update .env
72
+
68
73
  ```bash
69
74
  DATABASE_URL="your_database_connection_string"
70
75
  ```
76
+
71
77
  ```bash
72
78
  npx prisma generate
73
79
  ```
80
+
74
81
  ### SQL Databases
82
+
75
83
  ### (PostgreSQL, MySQL, SQLite, CockroachDB, SQLServer)
84
+
76
85
  ```bash
77
86
  npx prisma migrate dev --name init
78
87
  ```
88
+
79
89
  ### NoSQL Database
90
+
80
91
  ### (MongoDB)
92
+
81
93
  ```bash
82
94
  npx prisma db push
83
95
  ```
96
+
84
97
  ### Then, follow this
98
+
85
99
  ```bash
86
100
  npx ts-node prisma/seed.ts
87
101
  ```
102
+
88
103
  ```bash
89
104
  npm run start:dev
90
105
  ```
91
-
package/bin/index.js CHANGED
@@ -56,42 +56,42 @@ model User {
56
56
  name String?
57
57
  email String
58
58
  password String
59
+ profileUrl String?
59
60
  isActive Boolean @default(true)
60
61
  createdAt DateTime @default(now())
61
62
  updatedAt DateTime @updatedAt
62
63
  @@map("tbl_user")
63
64
  }
65
+
66
+ model Log {
67
+ id String @id @default(auto()) @map("_id") @db.ObjectId
68
+ method String
69
+ path String
70
+ statusCode Int
71
+ messageCode String?
72
+ message String?
73
+ headers Json
74
+ body Json?
75
+ query Json?
76
+ duration Int
77
+ createdAt DateTime @default(now())
78
+
79
+ @@map("tbl_log")
80
+ }
64
81
  `;
65
82
  }
66
83
 
67
84
  try {
68
85
  let prismaContent = await fs.readFile(templatePrismaPath, "utf-8");
69
- return prismaContent.replace(
70
- /datasource\s+db\s*{[^}]*provider\s*=\s*".*"/,
71
- `datasource db {\n provider = "${selectedProvider}"`
72
- );
73
- } catch {
74
- return `generator client {
75
- provider = "prisma-client-js"
76
- }
77
86
 
78
- datasource db {
79
- provider = "${selectedProvider}"
80
- url = env("DATABASE_URL")
81
- }
87
+ prismaContent = prismaContent.replace(
88
+ /(datasource\s+db\s*{[^}]*provider\s*=\s*")\w+(")/,
89
+ `$1${selectedProvider}$2`
90
+ );
82
91
 
83
- model User {
84
- id Int @id @default(autoincrement())
85
- userId String @unique
86
- name String?
87
- email String
88
- password String
89
- isActive Boolean @default(true)
90
- createdAt DateTime @default(now())
91
- updatedAt DateTime @updatedAt
92
- @@map("tbl_user")
93
- }
94
- `;
92
+ return prismaContent;
93
+ } catch (err) {
94
+ throw new Error(`Failed to read Prisma template: ${err.message}`);
95
95
  }
96
96
  }
97
97
 
@@ -141,12 +141,27 @@ async function main() {
141
141
  "@aws-sdk/s3-request-presigner",
142
142
  "moment",
143
143
  ];
144
- await execa(pkgManager, ["install", ...coreDeps], { cwd: projectPath, stdio: "inherit" });
145
144
 
146
- await execa(pkgManager, ["install", "@prisma/client"], { cwd: projectPath, stdio: "inherit" });
147
- await execa(pkgManager, ["install", "-D", "prisma"], { cwd: projectPath, stdio: "inherit" });
145
+ const devDeps = [
146
+ "prisma",
147
+ "@types/multer",
148
+ ];
149
+
148
150
 
149
- console.log(chalk.green(" Dependencies installed!"));
151
+ await execa(pkgManager, ["install", ...coreDeps], {
152
+ cwd: projectPath,
153
+ stdio: "inherit",
154
+ });
155
+
156
+ await execa(pkgManager, ["install", "@prisma/client"], {
157
+ cwd: projectPath,
158
+ stdio: "inherit",
159
+ });
160
+
161
+ await execa(pkgManager, ["install", "-D", ...devDeps], {
162
+ cwd: projectPath,
163
+ stdio: "inherit",
164
+ });
150
165
 
151
166
  const templatePath = path.resolve(__dirname, "../template");
152
167
  const projectPrismaPath = path.join(projectPath, "prisma/schema.prisma");
@@ -154,7 +169,6 @@ async function main() {
154
169
 
155
170
  if (await fs.pathExists(templatePath)) {
156
171
  await fs.copy(templatePath, projectPath, { overwrite: true });
157
- console.log(chalk.green("✅ Template files copied!"));
158
172
  }
159
173
 
160
174
  const providerMap = {
@@ -199,10 +213,9 @@ PORT=3000
199
213
  await fs.outputFile(path.join(projectPath, ".env"), envContent);
200
214
 
201
215
  console.log(chalk.yellow("🎉 Project ready!"));
202
- console.log(chalk.green("✅ .env created! Please update DATABASE_URL if necessary before running Prisma commands."));
203
- console.log(chalk.cyan(`cd ${projectName}`));
216
+ console.log(chalk.green("✅ Congratulations! Your project has been created successfully."));
217
+ console.log(chalk.cyan(`👉 Next steps: cd ${projectName}`));
204
218
 
205
- console.log(chalk.yellow("🔧 Next steps (run manually):"));
206
219
  console.log(chalk.cyan(`1. Generate Prisma Client:`));
207
220
  console.log(chalk.cyan(` npx prisma generate`));
208
221
  if (selectedProvider === "mongodb") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nestjs-prisma-cli",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "A CLI to generate NestJS + Prisma project boilerplate with Swagger, Auth, and AWS S3 setup",
5
5
  "type": "module",
6
6
  "main": "bin/index.js",
@@ -28,7 +28,7 @@
28
28
  ],
29
29
  "author": "Kyaw Soe",
30
30
  "license": "MIT",
31
- "homepage": "https://github.com/kyawsoe-dev/nestjs-generator-cli/blob/main/README.md",
31
+ "homepage": "https://github.com/kyawsoe-dev/nestjs-generator-cli#readme",
32
32
  "dependencies": {
33
33
  "chalk": "^4.1.2",
34
34
  "execa": "^9.6.0",
@@ -1,20 +1,37 @@
1
1
  generator client {
2
- provider = "prisma-client-js"
3
- }
2
+ provider = "prisma-client-js"
3
+ }
4
4
 
5
- datasource db {
6
- provider = "mysql"
7
- url = env("DATABASE_URL")
8
- }
5
+ datasource db {
6
+ provider = "mysql"
7
+ url = env("DATABASE_URL")
8
+ }
9
9
 
10
- model User {
11
- id Int @id @default(autoincrement())
12
- userId String @unique
13
- name String?
14
- email String
15
- password String
16
- createdAt DateTime @default(now())
17
- updatedAt DateTime @updatedAt
18
- @@map("tbl_user")
19
- }
20
-
10
+ model User {
11
+ id Int @id @default(autoincrement())
12
+ userId String @unique
13
+ name String?
14
+ email String
15
+ password String
16
+ profileUrl String?
17
+ createdAt DateTime @default(now())
18
+ updatedAt DateTime @updatedAt
19
+
20
+ @@map("tbl_user")
21
+ }
22
+
23
+ model Log {
24
+ id Int @id @default(autoincrement())
25
+ method String
26
+ path String
27
+ statusCode Int
28
+ messageCode String?
29
+ message String?
30
+ headers Json
31
+ body Json?
32
+ query Json?
33
+ duration Int
34
+ createdAt DateTime @default(now())
35
+
36
+ @@map("tbl_log")
37
+ }
@@ -1,5 +1,5 @@
1
1
  import { Module } from '@nestjs/common';
2
- import { APP_INTERCEPTOR } from '@nestjs/core';
2
+ import { APP_FILTER, APP_INTERCEPTOR } from '@nestjs/core';
3
3
  import { APP_GUARD } from '@nestjs/core';
4
4
  import { AppController } from './app.controller';
5
5
  import { AppService } from './app.service';
@@ -7,6 +7,7 @@ import { PrismaModule } from './prisma/prisma.module';
7
7
  import {
8
8
  HttpResponseInterceptor,
9
9
  LoggingInterceptor,
10
+ HttpExceptionFilter,
10
11
  } from './common/http-interceptor/index';
11
12
  import { JwtAuthGuard } from './modules/auth/jwt/jwt.guard';
12
13
  import { ConfigModule } from '@nestjs/config';
@@ -20,7 +21,7 @@ import { AuthModule } from './modules/auth/auth.module';
20
21
  }),
21
22
  PrismaModule,
22
23
  UserModule,
23
- AuthModule
24
+ AuthModule,
24
25
  ],
25
26
  controllers: [AppController],
26
27
  providers: [
@@ -28,6 +29,10 @@ import { AuthModule } from './modules/auth/auth.module';
28
29
  provide: APP_INTERCEPTOR,
29
30
  useClass: LoggingInterceptor,
30
31
  },
32
+ {
33
+ provide: APP_FILTER,
34
+ useClass: HttpExceptionFilter,
35
+ },
31
36
  {
32
37
  provide: APP_INTERCEPTOR,
33
38
  useClass: HttpResponseInterceptor,
@@ -0,0 +1,4 @@
1
+ import { MulterConfig } from './multer-config';
2
+ import { SwaggerConfig } from './swagger.config';
3
+
4
+ export { MulterConfig, SwaggerConfig };
@@ -0,0 +1,11 @@
1
+ import { MulterOptions } from '@nestjs/platform-express/multer/interfaces/multer-options.interface';
2
+
3
+ export const MulterConfig: MulterOptions = {
4
+ limits: { fileSize: 10 * 1024 * 1024 },
5
+ fileFilter: (req, file, cb) => {
6
+ if (!file.mimetype.match(/^image\/(jpg|jpeg|png|gif)$/)) {
7
+ return cb(new Error('Only image files are allowed!'), false);
8
+ }
9
+ cb(null, true);
10
+ },
11
+ };
@@ -0,0 +1,36 @@
1
+ import { writeFileSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
4
+ import { INestApplication } from '@nestjs/common';
5
+
6
+ const title = 'API';
7
+ const description = 'API Swagger documentation';
8
+
9
+ export const SwaggerConfig = (app: INestApplication) => {
10
+ const options = new DocumentBuilder()
11
+ .setTitle(title)
12
+ .setDescription(description)
13
+ .setVersion('1.0')
14
+ .addBearerAuth(
15
+ {
16
+ type: 'http',
17
+ scheme: 'bearer',
18
+ bearerFormat: 'JWT',
19
+ },
20
+ 'bearerAuth',
21
+ )
22
+ .addSecurityRequirements('bearerAuth')
23
+ .build();
24
+
25
+ const document = SwaggerModule.createDocument(app, options);
26
+
27
+ const outputPath = join(process.cwd(), 'swagger-openapi-v1.json');
28
+ writeFileSync(outputPath, JSON.stringify(document, null, 2));
29
+ console.log(`Swagger JSON saved to ${outputPath}`);
30
+
31
+ SwaggerModule.setup('api', app, document, {
32
+ swaggerOptions: {
33
+ persistAuthorization: true,
34
+ },
35
+ });
36
+ };
@@ -0,0 +1,4 @@
1
+ import { Public, IS_PUBLIC_KEY } from './public.decorator';
2
+ import { ResponseMessage } from './response-message.decorator';
3
+
4
+ export { Public, IS_PUBLIC_KEY, ResponseMessage };
@@ -0,0 +1,5 @@
1
+
2
+ import { SetMetadata } from '@nestjs/common';
3
+ export const RESPONSE_MESSAGE_METADATA = 'responseMessage';
4
+ export const ResponseMessage = (message: string) =>
5
+ SetMetadata(RESPONSE_MESSAGE_METADATA, message);
@@ -5,10 +5,22 @@ export class PaginatedResponseDto<T> {
5
5
  total: number;
6
6
 
7
7
  @ApiProperty()
8
- page: number;
8
+ limit: number;
9
9
 
10
10
  @ApiProperty()
11
- limit: number;
11
+ currentPage: number;
12
+
13
+ @ApiProperty()
14
+ firstPage: number;
15
+
16
+ @ApiProperty()
17
+ lastPage: number;
18
+
19
+ @ApiProperty()
20
+ nextPage: number | null;
21
+
22
+ @ApiProperty()
23
+ previousPage: number | null;
12
24
 
13
25
  @ApiProperty({ isArray: true })
14
26
  data: T[];
@@ -1,10 +1,12 @@
1
1
  import { ApiPropertyOptional } from '@nestjs/swagger';
2
+ import { Transform } from 'class-transformer';
2
3
  import { Type } from 'class-transformer';
3
4
  import {
4
5
  IsInt,
5
6
  IsOptional,
6
7
  IsString,
7
8
  Min,
9
+ IsIn,
8
10
  IsBooleanString,
9
11
  } from 'class-validator';
10
12
 
@@ -23,6 +25,22 @@ export class PaginationDto {
23
25
  @Min(1)
24
26
  limit?: number = 20;
25
27
 
28
+ @ApiPropertyOptional({ example: 'id', description: 'Field to sort by' })
29
+ @IsOptional()
30
+ @IsString()
31
+ sortBy?: string;
32
+
33
+ @ApiPropertyOptional({
34
+ example: 'desc',
35
+ description: 'Sort order: asc or desc',
36
+ })
37
+ @IsOptional()
38
+ @IsIn(['asc', 'desc'])
39
+ @Transform(({ value }) =>
40
+ typeof value === 'string' ? value.toLowerCase() : value,
41
+ )
42
+ sortOrder?: 'asc' | 'desc';
43
+
26
44
  @ApiPropertyOptional({ example: '', description: 'Search term' })
27
45
  @IsOptional()
28
46
  @IsString()
@@ -0,0 +1,31 @@
1
+ export enum HttpErrorType {
2
+ BAD_REQUEST = 400,
3
+ UNAUTHORIZED = 401,
4
+ PAYMENT_REQUIRED = 402,
5
+ FORBIDDEN = 403,
6
+ NOT_FOUND = 404,
7
+ METHOD_NOT_ALLOWED = 405,
8
+ NOT_ACCEPTABLE = 406,
9
+ PROXY_AUTHENTICATION_REQUIRED = 407,
10
+ REQUEST_TIMEOUT = 408,
11
+ CONFLICT = 409,
12
+ GONE = 410,
13
+ LENGTH_REQUIRED = 411,
14
+ PRECONDITION_FAILED = 412,
15
+ PAYLOAD_TOO_LARGE = 413,
16
+ URI_TOO_LONG = 414,
17
+ UNSUPPORTED_MEDIA_TYPE = 415,
18
+ REQUESTED_RANGE_NOT_SATISFIABLE = 416,
19
+ EXPECTATION_FAILED = 417,
20
+ I_AM_A_TEAPOT = 418,
21
+ MISDIRECTED = 421,
22
+ UNPROCESSABLE_ENTITY = 422,
23
+ FAILED_DEPENDENCY = 424,
24
+ TOO_MANY_REQUESTS = 429,
25
+ INTERNAL_SERVER_ERROR = 500,
26
+ NOT_IMPLEMENTED = 501,
27
+ BAD_GATEWAY = 502,
28
+ SERVICE_UNAVAILABLE = 503,
29
+ GATEWAY_TIMEOUT = 504,
30
+ HTTP_VERSION_NOT_SUPPORTED = 505,
31
+ }
@@ -1,4 +1,5 @@
1
1
  import { DBErrorCode } from './db-error-code.enum';
2
+ import { HttpErrorType } from './http-error-type-enum';
2
3
  import { MESSAGE_CODE } from './message-code.enum';
3
4
 
4
- export { DBErrorCode, MESSAGE_CODE };
5
+ export { DBErrorCode, MESSAGE_CODE, HttpErrorType };
@@ -5,6 +5,7 @@ export enum MESSAGE_CODE {
5
5
  PASSWORD_SUCCESS = 204,
6
6
  DATA_NOT_FOUND = 205,
7
7
  USER_VERIFY = 206,
8
+
8
9
  WRONG_USER_PW = 401,
9
10
  INVALID_USER_ID = 402,
10
11
  MISSED_TOKEN = 403,
@@ -16,5 +17,6 @@ export enum MESSAGE_CODE {
16
17
  ROUTE_NOT_FOUND = 410,
17
18
  REQUEST_FIELD_REQUIRED = 411,
18
19
  DELETE_USER = 412,
20
+
19
21
  SERVER_ERROR = 501,
20
22
  }