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 CHANGED
@@ -359,9 +359,9 @@ If this tool helped you, please consider:
359
359
 
360
360
  ## 🔗 Links
361
361
 
362
- - **GitHub**: https://github.com/yourusername/add-nest-auth
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/yourusername/add-nest-auth/issues
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
- throw new Error(`File already exists: ${filePath}`);
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
- " // Enable global validation pipe",
592
- " app.useGlobalPipes(",
593
- " new ValidationPipe({",
594
- " whitelist: true,",
595
- " forbidNonWhitelisted: true,",
596
- " transform: true,",
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
- " // Enable global JWT guard (all routes protected by default)",
601
- " // Use @Public() decorator on routes that should be accessible without auth",
602
- " const reflector = app.get(Reflector);",
603
- " app.useGlobalGuards(new JwtAuthGuard(reflector));",
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()}${detectedORM === "typeorm" ? " with PostgreSQL" : ""}. Use it?`,
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) {