add-nest-auth 1.0.6 → 1.0.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.
- package/README.md +2 -2
- package/dist/cli.js +111 -25
- package/dist/cli.js.map +1 -1
- package/dist/generator/templates/dto/register.dto.ts.hbs +1 -7
- package/dist/generator/templates/jwt/auth.service.ts.hbs +1 -1
- package/dist/generator/templates/shared/README.auth.md.hbs +1 -1
- package/dist/index.js +111 -25
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -359,9 +359,9 @@ If this tool helped you, please consider:
|
|
|
359
359
|
|
|
360
360
|
## 🔗 Links
|
|
361
361
|
|
|
362
|
-
- **GitHub**: https://github.com/
|
|
362
|
+
- **GitHub**: https://github.com/Islamawad132/add-nest-auth
|
|
363
363
|
- **npm**: https://www.npmjs.com/package/add-nest-auth
|
|
364
|
-
- **Issues**: https://github.com/
|
|
364
|
+
- **Issues**: https://github.com/Islamawad132/add-nest-auth/issues
|
|
365
365
|
|
|
366
366
|
---
|
|
367
367
|
|
package/dist/cli.js
CHANGED
|
@@ -127,6 +127,7 @@ var init_file_writer = __esm({
|
|
|
127
127
|
fs3 = __toESM(require("fs-extra"));
|
|
128
128
|
FileWriter = class {
|
|
129
129
|
writtenFiles = [];
|
|
130
|
+
skippedFiles = [];
|
|
130
131
|
backups = /* @__PURE__ */ new Map();
|
|
131
132
|
/**
|
|
132
133
|
* Write a file to disk
|
|
@@ -135,7 +136,8 @@ var init_file_writer = __esm({
|
|
|
135
136
|
const { overwrite = false, backup = true } = options;
|
|
136
137
|
const exists = await fs3.pathExists(filePath);
|
|
137
138
|
if (exists && !overwrite) {
|
|
138
|
-
|
|
139
|
+
this.skippedFiles.push(filePath);
|
|
140
|
+
return;
|
|
139
141
|
}
|
|
140
142
|
if (exists && backup) {
|
|
141
143
|
await this.createBackup(filePath);
|
|
@@ -187,6 +189,12 @@ var init_file_writer = __esm({
|
|
|
187
189
|
getWrittenFiles() {
|
|
188
190
|
return [...this.writtenFiles];
|
|
189
191
|
}
|
|
192
|
+
/**
|
|
193
|
+
* Get list of skipped files (already existed)
|
|
194
|
+
*/
|
|
195
|
+
getSkippedFiles() {
|
|
196
|
+
return [...this.skippedFiles];
|
|
197
|
+
}
|
|
190
198
|
};
|
|
191
199
|
}
|
|
192
200
|
});
|
|
@@ -243,15 +251,18 @@ var init_generator = __esm({
|
|
|
243
251
|
});
|
|
244
252
|
}
|
|
245
253
|
const filesCreated = this.fileWriter.getWrittenFiles();
|
|
254
|
+
const filesSkipped = this.fileWriter.getSkippedFiles();
|
|
246
255
|
await this.fileWriter.cleanupBackups();
|
|
247
256
|
return {
|
|
248
257
|
filesCreated,
|
|
258
|
+
filesSkipped,
|
|
249
259
|
success: true
|
|
250
260
|
};
|
|
251
261
|
} catch (error) {
|
|
252
262
|
await this.fileWriter.rollback();
|
|
253
263
|
return {
|
|
254
264
|
filesCreated: [],
|
|
265
|
+
filesSkipped: [],
|
|
255
266
|
success: false,
|
|
256
267
|
error: error instanceof Error ? error.message : "Unknown error"
|
|
257
268
|
};
|
|
@@ -357,12 +368,12 @@ var init_ast_updater = __esm({
|
|
|
357
368
|
/**
|
|
358
369
|
* Update app.module.ts with auth modules
|
|
359
370
|
*/
|
|
360
|
-
async update() {
|
|
371
|
+
async update(config) {
|
|
361
372
|
await this.createBackup();
|
|
362
373
|
try {
|
|
363
374
|
this.sourceFile = this.project.addSourceFileAtPath(this.appModulePath);
|
|
364
|
-
this.addImports();
|
|
365
|
-
this.addModulesToDecorator();
|
|
375
|
+
this.addImports(config);
|
|
376
|
+
this.addModulesToDecorator(config);
|
|
366
377
|
await this.sourceFile.save();
|
|
367
378
|
} catch (error) {
|
|
368
379
|
await this.restoreBackup();
|
|
@@ -372,11 +383,18 @@ var init_ast_updater = __esm({
|
|
|
372
383
|
/**
|
|
373
384
|
* Add necessary imports
|
|
374
385
|
*/
|
|
375
|
-
addImports() {
|
|
386
|
+
addImports(config) {
|
|
376
387
|
if (!this.sourceFile) {
|
|
377
388
|
throw new Error("Source file not loaded");
|
|
378
389
|
}
|
|
379
390
|
this.addImport("@nestjs/config", ["ConfigModule"]);
|
|
391
|
+
if (config && config.orm === "typeorm") {
|
|
392
|
+
this.addImport("@nestjs/typeorm", ["TypeOrmModule"]);
|
|
393
|
+
this.addImport("./users/entities/user.entity", ["User"]);
|
|
394
|
+
if (config.features.refreshTokens) {
|
|
395
|
+
this.addImport("./users/entities/refresh-token.entity", ["RefreshToken"]);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
380
398
|
this.addImport("./auth/auth.module", ["AuthModule"]);
|
|
381
399
|
this.addImport("./users/users.module", ["UsersModule"]);
|
|
382
400
|
}
|
|
@@ -404,7 +422,7 @@ var init_ast_updater = __esm({
|
|
|
404
422
|
/**
|
|
405
423
|
* Add modules to @Module decorator imports array
|
|
406
424
|
*/
|
|
407
|
-
addModulesToDecorator() {
|
|
425
|
+
addModulesToDecorator(config) {
|
|
408
426
|
if (!this.sourceFile) return;
|
|
409
427
|
const appModuleClass = this.sourceFile.getClass("AppModule");
|
|
410
428
|
if (!appModuleClass) {
|
|
@@ -437,6 +455,11 @@ var init_ast_updater = __esm({
|
|
|
437
455
|
if (!existingModules.has("ConfigModule")) {
|
|
438
456
|
importsArray.addElement("ConfigModule.forRoot({ isGlobal: true })");
|
|
439
457
|
}
|
|
458
|
+
if (config && config.orm === "typeorm" && !existingModules.has("TypeOrmModule")) {
|
|
459
|
+
const entities = config.features.refreshTokens ? "[User, RefreshToken]" : "[User]";
|
|
460
|
+
const typeOrmConfig = this.buildTypeOrmConfig(config.database, entities);
|
|
461
|
+
importsArray.addElement(typeOrmConfig);
|
|
462
|
+
}
|
|
440
463
|
if (!existingModules.has("AuthModule")) {
|
|
441
464
|
importsArray.addElement("AuthModule");
|
|
442
465
|
}
|
|
@@ -444,6 +467,43 @@ var init_ast_updater = __esm({
|
|
|
444
467
|
importsArray.addElement("UsersModule");
|
|
445
468
|
}
|
|
446
469
|
}
|
|
470
|
+
/**
|
|
471
|
+
* Build TypeORM.forRoot() configuration string based on database type
|
|
472
|
+
*/
|
|
473
|
+
buildTypeOrmConfig(database, entities) {
|
|
474
|
+
switch (database) {
|
|
475
|
+
case "sqlite":
|
|
476
|
+
return `TypeOrmModule.forRoot({
|
|
477
|
+
type: 'sqlite',
|
|
478
|
+
database: 'database.sqlite',
|
|
479
|
+
entities: ${entities},
|
|
480
|
+
synchronize: true, // WARNING: disable in production!
|
|
481
|
+
})`;
|
|
482
|
+
case "mysql":
|
|
483
|
+
return `TypeOrmModule.forRoot({
|
|
484
|
+
type: 'mysql',
|
|
485
|
+
host: process.env.DATABASE_HOST || 'localhost',
|
|
486
|
+
port: parseInt(process.env.DATABASE_PORT || '3306'),
|
|
487
|
+
username: process.env.DATABASE_USER || 'root',
|
|
488
|
+
password: process.env.DATABASE_PASSWORD || '',
|
|
489
|
+
database: process.env.DATABASE_NAME || 'auth_db',
|
|
490
|
+
entities: ${entities},
|
|
491
|
+
synchronize: true, // WARNING: disable in production!
|
|
492
|
+
})`;
|
|
493
|
+
case "postgres":
|
|
494
|
+
default:
|
|
495
|
+
return `TypeOrmModule.forRoot({
|
|
496
|
+
type: 'postgres',
|
|
497
|
+
host: process.env.DATABASE_HOST || 'localhost',
|
|
498
|
+
port: parseInt(process.env.DATABASE_PORT || '5432'),
|
|
499
|
+
username: process.env.DATABASE_USER || 'postgres',
|
|
500
|
+
password: process.env.DATABASE_PASSWORD || 'postgres',
|
|
501
|
+
database: process.env.DATABASE_NAME || 'auth_db',
|
|
502
|
+
entities: ${entities},
|
|
503
|
+
synchronize: true, // WARNING: disable in production!
|
|
504
|
+
})`;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
447
507
|
/**
|
|
448
508
|
* Get existing module names from imports array
|
|
449
509
|
*/
|
|
@@ -588,19 +648,19 @@ var init_main_ts_updater = __esm({
|
|
|
588
648
|
}
|
|
589
649
|
const codeToInsert = [
|
|
590
650
|
"",
|
|
591
|
-
"
|
|
592
|
-
"
|
|
593
|
-
"
|
|
594
|
-
"
|
|
595
|
-
"
|
|
596
|
-
"
|
|
597
|
-
"
|
|
598
|
-
"
|
|
651
|
+
"// Enable global validation pipe",
|
|
652
|
+
"app.useGlobalPipes(",
|
|
653
|
+
" new ValidationPipe({",
|
|
654
|
+
" whitelist: true,",
|
|
655
|
+
" forbidNonWhitelisted: true,",
|
|
656
|
+
" transform: true,",
|
|
657
|
+
" }),",
|
|
658
|
+
");",
|
|
599
659
|
"",
|
|
600
|
-
"
|
|
601
|
-
"
|
|
602
|
-
"
|
|
603
|
-
"
|
|
660
|
+
"// Enable global JWT guard (all routes protected by default)",
|
|
661
|
+
"// Use @Public() decorator on routes that should be accessible without auth",
|
|
662
|
+
"const reflector = app.get(Reflector);",
|
|
663
|
+
"app.useGlobalGuards(new JwtAuthGuard(reflector));",
|
|
604
664
|
""
|
|
605
665
|
].join("\n");
|
|
606
666
|
body.insertStatements(listenIndex, codeToInsert);
|
|
@@ -840,6 +900,25 @@ async function detectORM(packageJson) {
|
|
|
840
900
|
}
|
|
841
901
|
return "none";
|
|
842
902
|
}
|
|
903
|
+
function detectDatabase(packageJson, orm) {
|
|
904
|
+
const dependencies = {
|
|
905
|
+
...packageJson.dependencies,
|
|
906
|
+
...packageJson.devDependencies
|
|
907
|
+
};
|
|
908
|
+
if (orm === "typeorm") {
|
|
909
|
+
if (dependencies["pg"]) return "postgres";
|
|
910
|
+
if (dependencies["mysql2"] || dependencies["mysql"]) return "mysql";
|
|
911
|
+
if (dependencies["sqlite3"]) return "sqlite";
|
|
912
|
+
if (dependencies["mongodb"]) return "mongodb";
|
|
913
|
+
}
|
|
914
|
+
if (orm === "prisma") {
|
|
915
|
+
return void 0;
|
|
916
|
+
}
|
|
917
|
+
if (orm === "mongoose") {
|
|
918
|
+
return "mongodb";
|
|
919
|
+
}
|
|
920
|
+
return void 0;
|
|
921
|
+
}
|
|
843
922
|
|
|
844
923
|
// src/analyzer/project-detector.ts
|
|
845
924
|
var ProjectDetector = class {
|
|
@@ -878,6 +957,7 @@ var ProjectDetector = class {
|
|
|
878
957
|
}
|
|
879
958
|
const mainTsPath = path.join(root, sourceRoot, "main.ts");
|
|
880
959
|
const orm = await detectORM(packageJson);
|
|
960
|
+
const database = detectDatabase(packageJson, orm);
|
|
881
961
|
const authModulePath = path.join(root, sourceRoot, "auth");
|
|
882
962
|
if (await fs.pathExists(authModulePath)) {
|
|
883
963
|
errors.push("auth/ directory already exists (use --force to overwrite)");
|
|
@@ -890,6 +970,7 @@ var ProjectDetector = class {
|
|
|
890
970
|
packageJsonPath,
|
|
891
971
|
nestCliConfigPath,
|
|
892
972
|
orm,
|
|
973
|
+
database,
|
|
893
974
|
nestVersion: packageJson.dependencies?.["@nestjs/core"],
|
|
894
975
|
typescriptVersion: packageJson.devDependencies?.["typescript"],
|
|
895
976
|
isValid: errors.length === 0,
|
|
@@ -955,7 +1036,8 @@ function generateSecret(length = 32) {
|
|
|
955
1036
|
}
|
|
956
1037
|
|
|
957
1038
|
// src/cli/prompts.ts
|
|
958
|
-
async function promptConfig(detectedORM) {
|
|
1039
|
+
async function promptConfig(detectedORM, detectedDB) {
|
|
1040
|
+
const dbLabel = detectedDB ? ` with ${detectedDB.charAt(0).toUpperCase() + detectedDB.slice(1)}` : "";
|
|
959
1041
|
const answers = await import_inquirer.default.prompt([
|
|
960
1042
|
{
|
|
961
1043
|
type: "list",
|
|
@@ -1027,7 +1109,7 @@ async function promptConfig(detectedORM) {
|
|
|
1027
1109
|
{
|
|
1028
1110
|
type: "confirm",
|
|
1029
1111
|
name: "useDetectedORM",
|
|
1030
|
-
message: `Detected ${detectedORM.toUpperCase()}${
|
|
1112
|
+
message: `Detected ${detectedORM.toUpperCase()}${dbLabel}. Use it?`,
|
|
1031
1113
|
default: true,
|
|
1032
1114
|
when: () => detectedORM !== "none"
|
|
1033
1115
|
},
|
|
@@ -1053,7 +1135,7 @@ async function promptConfig(detectedORM) {
|
|
|
1053
1135
|
]);
|
|
1054
1136
|
return answers;
|
|
1055
1137
|
}
|
|
1056
|
-
function buildConfig(answers, projectName, sourceRoot, detectedORM) {
|
|
1138
|
+
function buildConfig(answers, projectName, sourceRoot, detectedORM, detectedDB) {
|
|
1057
1139
|
const config = {
|
|
1058
1140
|
projectName,
|
|
1059
1141
|
sourceRoot,
|
|
@@ -1063,7 +1145,7 @@ function buildConfig(answers, projectName, sourceRoot, detectedORM) {
|
|
|
1063
1145
|
roles: answers.roles || []
|
|
1064
1146
|
},
|
|
1065
1147
|
orm: answers.useDetectedORM !== false ? detectedORM : "typeorm",
|
|
1066
|
-
database: answers.database || "postgres",
|
|
1148
|
+
database: answers.database || detectedDB || "postgres",
|
|
1067
1149
|
features: {
|
|
1068
1150
|
refreshTokens: answers.refreshTokens
|
|
1069
1151
|
},
|
|
@@ -1205,12 +1287,13 @@ async function run(cwd = process.cwd()) {
|
|
|
1205
1287
|
orm: projectInfo.orm,
|
|
1206
1288
|
sourceRoot: projectInfo.sourceRoot
|
|
1207
1289
|
});
|
|
1208
|
-
const answers = await promptConfig(projectInfo.orm);
|
|
1290
|
+
const answers = await promptConfig(projectInfo.orm, projectInfo.database);
|
|
1209
1291
|
const config = buildConfig(
|
|
1210
1292
|
answers,
|
|
1211
1293
|
projectInfo.root.split(/[/\\]/).pop() || "project",
|
|
1212
1294
|
projectInfo.sourceRoot,
|
|
1213
|
-
projectInfo.orm
|
|
1295
|
+
projectInfo.orm,
|
|
1296
|
+
projectInfo.database
|
|
1214
1297
|
);
|
|
1215
1298
|
console.log();
|
|
1216
1299
|
console.log("\u2699\uFE0F Generating authentication module...");
|
|
@@ -1225,11 +1308,14 @@ async function run(cwd = process.cwd()) {
|
|
|
1225
1308
|
process.exit(1);
|
|
1226
1309
|
}
|
|
1227
1310
|
genSpinner.succeed(`Generated ${result.filesCreated.length} files`);
|
|
1311
|
+
if (result.filesSkipped.length > 0) {
|
|
1312
|
+
console.log(` \u26A0\uFE0F Skipped ${result.filesSkipped.length} existing file(s)`);
|
|
1313
|
+
}
|
|
1228
1314
|
const astSpinner = createSpinner("Updating app.module.ts...").start();
|
|
1229
1315
|
try {
|
|
1230
1316
|
const { AppModuleUpdater: AppModuleUpdater2 } = await Promise.resolve().then(() => (init_installer(), installer_exports));
|
|
1231
1317
|
const astUpdater = new AppModuleUpdater2(projectInfo.appModulePath);
|
|
1232
|
-
await astUpdater.update();
|
|
1318
|
+
await astUpdater.update(config);
|
|
1233
1319
|
await astUpdater.cleanupBackup();
|
|
1234
1320
|
astSpinner.succeed("Updated app.module.ts");
|
|
1235
1321
|
} catch (error) {
|