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.
- package/AUDIT_ROADMAP.md +798 -0
- package/CHANGELOG.fr.md +22 -0
- package/CHANGELOG.md +22 -0
- package/CLI_USAGE.fr.md +331 -331
- package/CLI_USAGE.md +364 -364
- package/LICENSE +21 -21
- package/PROGRESS.md +258 -0
- package/bin/nestcraft.js +84 -64
- package/commands/demo.js +337 -330
- package/commands/generate.js +94 -0
- package/commands/generateConf.js +91 -0
- package/commands/help.js +29 -2
- package/commands/info.js +48 -48
- package/commands/new.js +340 -335
- package/commands/start.js +19 -19
- package/commands/test.js +7 -7
- package/package.json +1 -1
- package/utils/app-module.updater.js +96 -0
- package/utils/cliParser.js +88 -76
- package/utils/colors.js +62 -62
- package/utils/configs/configureDocker.js +120 -120
- package/utils/configs/setupCleanArchitecture.js +17 -15
- package/utils/configs/setupLightArchitecture.js +15 -9
- package/utils/file-system.js +75 -0
- package/utils/file-utils/saveProjectConfig.js +36 -0
- package/utils/fullModeInput.js +607 -607
- package/utils/generators/application/dtoGenerator.js +251 -0
- package/utils/generators/application/dtoUpdater.js +54 -0
- package/utils/generators/cleanModuleGenerator.js +475 -0
- package/utils/generators/database/setupDatabase.js +49 -0
- package/utils/generators/domain/entityGenerator.js +126 -0
- package/utils/generators/domain/entityUpdater.js +78 -0
- package/utils/generators/infrastructure/mapperGenerator.js +114 -0
- package/utils/generators/infrastructure/mapperUpdater.js +65 -0
- package/utils/generators/infrastructure/middlewareGenerator.js +645 -0
- package/utils/generators/infrastructure/mongooseSchemaGenerator.js +196 -0
- package/utils/generators/infrastructure/repositoryGenerator.js +334 -0
- package/utils/generators/lightModuleGenerator.js +131 -0
- package/utils/generators/presentation/controllerGenerator.js +142 -0
- package/utils/generators/relation/relation.engine.js +64 -0
- package/utils/helpers.js +109 -0
- package/utils/interactive/askEntityInputs.js +165 -0
- package/utils/loggers/logError.js +7 -7
- package/utils/loggers/logInfo.js +7 -7
- package/utils/loggers/logSuccess.js +7 -7
- package/utils/loggers/logWarning.js +7 -7
- package/utils/setups/orms/typeOrmSetup.js +630 -630
- package/utils/setups/setupAuth.js +33 -20
- package/utils/setups/setupDatabase.js +76 -75
- package/utils/setups/setupMongoose.js +22 -5
- package/utils/setups/setupPrisma.js +748 -630
- package/utils/shell.js +112 -32
- package/utils/spinner.js +57 -57
- package/utils/systemCheck.js +124 -124
- package/utils/userInput.js +357 -421
- 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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
345
|
-
|
|
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:
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
|
72
|
-
MONGO_URI=${inputs.dbConfig.MONGO_URI}
|
|
73
|
-
MONGO_DB=${inputs.dbConfig.MONGO_DB}
|
|
74
|
-
|
|
75
|
-
|
|
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';`;
|