nestcraftx 0.2.5 → 0.3.0

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 (56) hide show
  1. package/AUDIT_ROADMAP.md +798 -0
  2. package/CHANGELOG.fr.md +22 -0
  3. package/CHANGELOG.md +22 -0
  4. package/CLI_USAGE.fr.md +331 -331
  5. package/CLI_USAGE.md +364 -364
  6. package/LICENSE +21 -21
  7. package/PROGRESS.md +258 -0
  8. package/bin/nestcraft.js +84 -64
  9. package/commands/demo.js +337 -330
  10. package/commands/generate.js +94 -0
  11. package/commands/generateConf.js +91 -0
  12. package/commands/help.js +29 -2
  13. package/commands/info.js +48 -48
  14. package/commands/new.js +340 -335
  15. package/commands/start.js +19 -19
  16. package/commands/test.js +7 -7
  17. package/package.json +1 -1
  18. package/utils/app-module.updater.js +96 -0
  19. package/utils/cliParser.js +88 -76
  20. package/utils/colors.js +62 -62
  21. package/utils/configs/configureDocker.js +120 -120
  22. package/utils/configs/setupCleanArchitecture.js +17 -15
  23. package/utils/configs/setupLightArchitecture.js +15 -9
  24. package/utils/file-system.js +75 -0
  25. package/utils/file-utils/saveProjectConfig.js +36 -0
  26. package/utils/fullModeInput.js +607 -607
  27. package/utils/generators/application/dtoGenerator.js +251 -0
  28. package/utils/generators/application/dtoUpdater.js +54 -0
  29. package/utils/generators/cleanModuleGenerator.js +475 -0
  30. package/utils/generators/database/setupDatabase.js +49 -0
  31. package/utils/generators/domain/entityGenerator.js +126 -0
  32. package/utils/generators/domain/entityUpdater.js +78 -0
  33. package/utils/generators/infrastructure/mapperGenerator.js +114 -0
  34. package/utils/generators/infrastructure/mapperUpdater.js +65 -0
  35. package/utils/generators/infrastructure/middlewareGenerator.js +645 -0
  36. package/utils/generators/infrastructure/mongooseSchemaGenerator.js +196 -0
  37. package/utils/generators/infrastructure/repositoryGenerator.js +334 -0
  38. package/utils/generators/lightModuleGenerator.js +131 -0
  39. package/utils/generators/presentation/controllerGenerator.js +142 -0
  40. package/utils/generators/relation/relation.engine.js +64 -0
  41. package/utils/helpers.js +109 -0
  42. package/utils/interactive/askEntityInputs.js +165 -0
  43. package/utils/loggers/logError.js +7 -7
  44. package/utils/loggers/logInfo.js +7 -7
  45. package/utils/loggers/logSuccess.js +7 -7
  46. package/utils/loggers/logWarning.js +7 -7
  47. package/utils/setups/orms/typeOrmSetup.js +630 -630
  48. package/utils/setups/setupAuth.js +33 -20
  49. package/utils/setups/setupDatabase.js +76 -75
  50. package/utils/setups/setupMongoose.js +22 -5
  51. package/utils/setups/setupPrisma.js +748 -630
  52. package/utils/shell.js +112 -32
  53. package/utils/spinner.js +57 -57
  54. package/utils/systemCheck.js +124 -124
  55. package/utils/userInput.js +357 -421
  56. package/utils/utils.js +29 -2164
@@ -6,20 +6,23 @@ const { generateDto } = require("../utils");
6
6
 
7
7
  async function setupAuth(inputs) {
8
8
  logInfo(
9
- "🚀 Déploiement de l'architecture Auth Ultime (Mappers, DTOs, Multi-ORM)..."
9
+ "🚀 Déploiement de l'architecture Auth Ultime (Mappers, DTOs, Multi-ORM)...",
10
10
  );
11
11
 
12
12
  const { dbConfig, useSwagger, mode = "full" } = inputs;
13
13
  const isFull = mode === "full";
14
14
 
15
15
  // 1. INSTALLATION DES DÉPENDANCES
16
+ const pkgManager = inputs.packageManager || "npm";
17
+ const installCmd = pkgManager === "yarn" || pkgManager === "pnpm" ? `${pkgManager} add` : "npm install";
18
+
16
19
  await runCommand(
17
- `npm install @nestjs/jwt @nestjs/passport passport passport-jwt bcrypt uuid`,
18
- "Erreur install deps auth"
20
+ `${installCmd} @nestjs/jwt @nestjs/passport passport passport-jwt bcrypt uuid`,
21
+ "Erreur install deps auth",
19
22
  );
20
23
  await runCommand(
21
- `npm install -D @types/passport-jwt @types/bcrypt @types/uuid`,
22
- "Erreur install dev-deps auth"
24
+ `${installCmd} -D @types/passport-jwt @types/bcrypt @types/uuid`,
25
+ "Erreur install dev-deps auth",
23
26
  );
24
27
 
25
28
  // 2. DÉFINITION DES CHEMINS (CLEAN ARCHITECTURE)
@@ -75,6 +78,8 @@ export class Session {
75
78
  import { Session } from '${paths.entities}/session.entity';
76
79
  import { CreateSessionPersistenceDto } from '${paths.appDtos}/create-session.dto';
77
80
 
81
+ export const ISessionRepositoryName = 'ISessionRepository';
82
+
78
83
  export interface ISessionRepository {
79
84
  save(dto: CreateSessionPersistenceDto): Promise<Session>;
80
85
  findByToken(token: string): Promise<Session | null>;
@@ -137,9 +142,9 @@ export interface CreateSessionPersistenceDto {
137
142
  // Définition dynamique des types et injections
138
143
  const repoType = isFull ? "ISessionRepository" : "SessionRepository";
139
144
  const repoImport = isFull
140
- ? `import { ISessionRepository } from '${paths.interfaces}/session.repository.interface';`
145
+ ? `import { ISessionRepositoryName, type ISessionRepository } from '${paths.interfaces}/session.repository.interface';`
141
146
  : `import { SessionRepository } from '${paths.persistence}/session.repository';`;
142
- const injectDecorator = isFull ? `@Inject('ISessionRepository') ` : "";
147
+ const injectDecorator = isFull ? `@Inject(ISessionRepositoryName) ` : "";
143
148
 
144
149
  await createFile({
145
150
  path: `${paths.services}/session.service.ts`,
@@ -247,11 +252,12 @@ import { SendOtpDto } from '${paths.appDtos}/sendOtp.dto';
247
252
  import { VerifyOtpDto } from '${paths.appDtos}/verifyOtp.dto';
248
253
  import { ForgotPasswordDto } from '${paths.appDtos}/forgotPassword.dto';
249
254
  import { ResetPasswordDto } from '${paths.appDtos}/resetPassword.dto';
255
+ ${enumImport}
250
256
  ${
251
257
  mode === "light"
252
258
  ? `import { UserRepository } from '${userRepoPath}';
253
259
  import { CreateUserDto } from '${userDtoPath}/user.dto';`
254
- : `import { IUserRepository } from '${userRepoPath}';
260
+ : `import type { IUserRepository } from '${userRepoPath}';
255
261
  import { CreateUserDto } from '${userDtoPath}/user.dto';`
256
262
  }
257
263
 
@@ -329,27 +335,32 @@ export class AuthService {
329
335
  async refreshToken(token: RefreshTokenDto) {
330
336
  const session = await this.sessionService.validate(token.refreshToken);
331
337
  if (!session) throw new UnauthorizedException('Session expired or invalid');
332
- const payload = this.jwtService.decode(token.refreshToken) as any;
338
+ const payload: {
339
+ sub: string;
340
+ email: string;
341
+ sid: string;
342
+ role: Role;
343
+ } = this.jwtService.decode(token.refreshToken) as any;
333
344
  return { accessToken: this.jwtService.sign({ sub: payload.sub, email: payload.email }, { expiresIn: '15m' }) };
334
345
  }
335
346
 
336
347
  // 📲 Send OTP
337
- async sendOtp(dto: SendOtpDto) {
348
+ sendOtp(dto: SendOtpDto) {
338
349
  const otp = Math.floor(100000 + Math.random() * 900000).toString();
339
350
  this.otps.set(dto.email, otp);
340
351
  console.log(\`[OTP] for \${dto.email} is \${otp}\`);
341
352
  return { message: 'OTP sent' };
342
- }
353
+ }
343
354
 
344
- // Verify OTP
345
- async verifyOtp(dto: VerifyOtpDto) {
355
+ // Verify OTP
356
+ verifyOtp(dto: VerifyOtpDto) {
346
357
  const valid = this.otps.get(dto.email);
347
358
  if (valid === dto.otp) {
348
359
  this.otps.delete(dto.email);
349
360
  return { message: 'OTP verified' };
350
361
  }
351
362
  throw new UnauthorizedException('Invalid OTP');
352
- }
363
+ }
353
364
 
354
365
  // 📬 Forgot Password
355
366
  async forgotPassword(dto: ForgotPasswordDto) {
@@ -413,7 +424,7 @@ export class SessionMapper {
413
424
 
414
425
  // On prépare l'entête dynamiquement
415
426
  const interfaceImport = isFull
416
- ? `import { ISessionRepository } from '${paths.interfaces}/session.repository.interface';`
427
+ ? `import type { ISessionRepository } from '${paths.interfaces}/session.repository.interface';`
417
428
  : "";
418
429
  const implementsClause = isFull ? "implements ISessionRepository " : "";
419
430
 
@@ -765,9 +776,6 @@ export class JwtAuthGuard extends AuthGuard('jwt') {
765
776
  const request = context.switchToHttp().getRequest();
766
777
  const user = request.user;
767
778
 
768
- console.log('🔍 Required Roles:', requiredRoles);
769
- console.log('👤 User Role:', user?.role);
770
-
771
779
  // Check if the user has one of the required roles
772
780
  return user && user.role && requiredRoles.includes(user.role);
773
781
  }
@@ -796,6 +804,11 @@ import { Session, SessionSchema } from '${schemaRelativePath}';`;
796
804
  dbProviders = "PrismaModule,";
797
805
  }
798
806
 
807
+ if (inputs.mode == "full") {
808
+ dbImports =
809
+ +"import { ISessionRepositoryName } from '${paths.interfaces}/session.repository.interface';";
810
+ }
811
+
799
812
  await createFile({
800
813
  path: `${paths.root}/auth.module.ts`,
801
814
  contente: `
@@ -832,7 +845,7 @@ import { SessionRepository } from '${paths.persistence}/session.repository';
832
845
  JwtStrategy,
833
846
  ${
834
847
  isFull
835
- ? "{ provide: 'ISessionRepository', useClass: SessionRepository }"
848
+ ? "{ provide: ISessionRepositoryName, useClass: SessionRepository }"
836
849
  : "SessionRepository"
837
850
  }
838
851
 
@@ -953,7 +966,7 @@ export class AuthModule {}`.trim(),
953
966
  });
954
967
 
955
968
  logSuccess(
956
- ` Authentification Enterprise avec support ${dbConfig.orm.toUpperCase()} et Mappers terminée !`
969
+ ` Authentification Enterprise avec support ${dbConfig.orm.toUpperCase()} et Mappers terminée !`,
957
970
  );
958
971
  }
959
972
 
@@ -1,75 +1,76 @@
1
- const { logInfo } = require("../loggers/logInfo");
2
- const { runCommand } = require("../shell");
3
- const { setupTypeORM } = require("./orms/typeOrmSetup");
4
- const { setupMongoose } = require("./setupMongoose");
5
- const { setupPrisma } = require("./setupPrisma");
6
-
7
- async function setupDatabase(inputs) {
8
- logInfo("🚀 Configuring the database...");
9
-
10
- await runCommand(
11
- "npm install dotenv",
12
- "Error installing dotenv automatically, please run it manually now"
13
- );
14
-
15
- switch (inputs.selectedDB) {
16
- case "postgresql":
17
- await setupPostgres(inputs); // PostgreSQL Configuration
18
- break;
19
- case "mysql":
20
- await setupMySQL(inputs); // MySQL Configuration
21
- break;
22
- case "mongodb":
23
- await setupMongoDB(inputs); // MongoDB Configuration
24
- break;
25
- case "sqlite":
26
- await setupSQLite(inputs); // SQLite Configuration
27
- break;
28
- case "firebase":
29
- await setupFirebase(inputs); // Firebase Configuration
30
- break;
31
- case "redis":
32
- await setupRedis(inputs); // Redis Configuration
33
- break;
34
- default:
35
- throw new Error("Unsupported database.");
36
- }
37
- }
38
-
39
- async function setupMongoDB(inputs) {
40
- logInfo("Configuring MongoDB...");
41
- await setupMongoose(inputs);
42
- }
43
-
44
- async function setupSQLite(inputs) {
45
- logInfo("Configuring SQLite..."); // Calls a SQLite-specific script
46
- await setupSQLiteConfig(inputs);
47
- }
48
-
49
- async function setupMySQL(inputs) {
50
- logInfo("Configuring MySQL..."); // Calls a MySQL-specific script
51
- await setupMySQLConfig(inputs);
52
- }
53
-
54
- async function setupFirebase(inputs) {
55
- logInfo("Configuring Firebase..."); // Calls a Firebase-specific script
56
- await setupFirebaseConfig(inputs);
57
- }
58
-
59
- async function setupPostgres(inputs) {
60
- // Checks which ORM was chosen and calls the corresponding function
61
- if (inputs.dbConfig.orm === "prisma") {
62
- await setupPrisma(inputs);
63
- } else if (inputs.dbConfig.orm === "typeorm") {
64
- await setupTypeORM(inputs);
65
- } else {
66
- throw new Error("Unsupported ORM: " + inputs.dbConfig.orm);
67
- }
68
- }
69
-
70
- async function setupRedis(inputs) {
71
- logInfo("Configuring Redis..."); // Calls a Redis-specific script
72
- await setupRedisConfig(inputs);
73
- }
74
-
75
- module.exports = { setupDatabase };
1
+ const { logInfo } = require("../loggers/logInfo");
2
+ const { runCommand } = require("../shell");
3
+ const { setupTypeORM } = require("./orms/typeOrmSetup");
4
+ const { setupMongoose } = require("./setupMongoose");
5
+ const { setupPrisma } = require("./setupPrisma");
6
+
7
+ async function setupDatabase(inputs) {
8
+ logInfo("🚀 Configuring the database...");
9
+
10
+ await runCommand(
11
+ "npm install dotenv",
12
+ "Error installing dotenv automatically, please run it manually now",
13
+ { critical: false },
14
+ );
15
+
16
+ switch (inputs.selectedDB) {
17
+ case "postgresql":
18
+ await setupPostgres(inputs); // PostgreSQL Configuration
19
+ break;
20
+ case "mysql":
21
+ await setupMySQL(inputs); // MySQL Configuration
22
+ break;
23
+ case "mongodb":
24
+ await setupMongoDB(inputs); // MongoDB Configuration
25
+ break;
26
+ case "sqlite":
27
+ await setupSQLite(inputs); // SQLite Configuration
28
+ break;
29
+ case "firebase":
30
+ await setupFirebase(inputs); // Firebase Configuration
31
+ break;
32
+ case "redis":
33
+ await setupRedis(inputs); // Redis Configuration
34
+ break;
35
+ default:
36
+ throw new Error("Unsupported database.");
37
+ }
38
+ }
39
+
40
+ async function setupMongoDB(inputs) {
41
+ logInfo("Configuring MongoDB...");
42
+ await setupMongoose(inputs);
43
+ }
44
+
45
+ async function setupSQLite(inputs) {
46
+ logInfo("Configuring SQLite..."); // Calls a SQLite-specific script
47
+ await setupSQLiteConfig(inputs);
48
+ }
49
+
50
+ async function setupMySQL(inputs) {
51
+ logInfo("Configuring MySQL..."); // Calls a MySQL-specific script
52
+ await setupMySQLConfig(inputs);
53
+ }
54
+
55
+ async function setupFirebase(inputs) {
56
+ logInfo("Configuring Firebase..."); // Calls a Firebase-specific script
57
+ await setupFirebaseConfig(inputs);
58
+ }
59
+
60
+ async function setupPostgres(inputs) {
61
+ // Checks which ORM was chosen and calls the corresponding function
62
+ if (inputs.dbConfig.orm === "prisma") {
63
+ await setupPrisma(inputs);
64
+ } else if (inputs.dbConfig.orm === "typeorm") {
65
+ await setupTypeORM(inputs);
66
+ } else {
67
+ throw new Error("Unsupported ORM: " + inputs.dbConfig.orm);
68
+ }
69
+ }
70
+
71
+ async function setupRedis(inputs) {
72
+ logInfo("Configuring Redis..."); // Calls a Redis-specific script
73
+ await setupRedisConfig(inputs);
74
+ }
75
+
76
+ module.exports = { setupDatabase };
@@ -1,5 +1,6 @@
1
1
  const { runCommand } = require("../shell");
2
2
  const path = require("path");
3
+ const fs = require("fs");
3
4
  const {
4
5
  createFile,
5
6
  updateFile,
@@ -68,11 +69,27 @@ async function setupMongoose(inputs) {
68
69
  );
69
70
 
70
71
  // --- Base Configuration (app.module.ts and .env) --- // Generating the .env file
71
- const envContent = `
72
- MONGO_URI=${inputs.dbConfig.MONGO_URI}
73
- MONGO_DB=${inputs.dbConfig.MONGO_DB}
74
- `.trim();
75
- await createFile({ path: ".env", contente: envContent });
72
+ const envPath = ".env";
73
+ const mongoUriLine = `MONGO_URI=${inputs.dbConfig.MONGO_URI}`;
74
+ const mongoDbLine = `MONGO_DB=${inputs.dbConfig.MONGO_DB}`;
75
+
76
+ if (!fs.existsSync(envPath)) {
77
+ const envContent = `${mongoUriLine}\n${mongoDbLine}\n`;
78
+ await createFile({ path: envPath, contente: envContent });
79
+ } else {
80
+ let content = fs.readFileSync(envPath, "utf8");
81
+ if (content.includes("MONGO_URI=")) {
82
+ content = content.replace(/MONGO_URI=.*/g, mongoUriLine);
83
+ } else {
84
+ content += `\n${mongoUriLine}`;
85
+ }
86
+ if (content.includes("MONGO_DB=")) {
87
+ content = content.replace(/MONGO_DB=.*/g, mongoDbLine);
88
+ } else {
89
+ content += `\n${mongoDbLine}`;
90
+ }
91
+ fs.writeFileSync(envPath, content, "utf8");
92
+ }
76
93
 
77
94
  const appModulePath = path.join("src", "app.module.ts");
78
95
  const mongooseImport = `import { MongooseModule } from '@nestjs/mongoose';`;