add-nest-auth 1.0.8 → 1.1.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/dist/cli.js +560 -473
- package/dist/cli.js.map +1 -1
- package/dist/generator/templates/jwt/auth.controller.ts.hbs +25 -3
- package/dist/generator/templates/jwt/auth.module.ts.hbs +9 -0
- package/dist/generator/templates/jwt/auth.service.ts.hbs +54 -4
- package/dist/generator/templates/jwt/jwt.strategy.ts.hbs +2 -1
- package/dist/generator/templates/shared/env.hbs +32 -0
- package/dist/generator/templates/shared/env.template.hbs +4 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.js +56 -19
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -36,6 +36,457 @@ var init_cjs_shims = __esm({
|
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
+
// src/analyzer/orm-detector.ts
|
|
40
|
+
async function detectORM(packageJson) {
|
|
41
|
+
const dependencies = {
|
|
42
|
+
...packageJson.dependencies,
|
|
43
|
+
...packageJson.devDependencies
|
|
44
|
+
};
|
|
45
|
+
if (dependencies["@nestjs/typeorm"] || dependencies["typeorm"]) {
|
|
46
|
+
return "typeorm";
|
|
47
|
+
}
|
|
48
|
+
if (dependencies["@prisma/client"] || dependencies["prisma"]) {
|
|
49
|
+
return "prisma";
|
|
50
|
+
}
|
|
51
|
+
if (dependencies["@nestjs/mongoose"] || dependencies["mongoose"]) {
|
|
52
|
+
return "mongoose";
|
|
53
|
+
}
|
|
54
|
+
return "none";
|
|
55
|
+
}
|
|
56
|
+
function detectDatabase(packageJson, orm) {
|
|
57
|
+
const dependencies = {
|
|
58
|
+
...packageJson.dependencies,
|
|
59
|
+
...packageJson.devDependencies
|
|
60
|
+
};
|
|
61
|
+
if (orm === "typeorm") {
|
|
62
|
+
if (dependencies["pg"]) return "postgres";
|
|
63
|
+
if (dependencies["mysql2"] || dependencies["mysql"]) return "mysql";
|
|
64
|
+
if (dependencies["sqlite3"]) return "sqlite";
|
|
65
|
+
if (dependencies["mongodb"]) return "mongodb";
|
|
66
|
+
}
|
|
67
|
+
if (orm === "prisma") {
|
|
68
|
+
return void 0;
|
|
69
|
+
}
|
|
70
|
+
if (orm === "mongoose") {
|
|
71
|
+
return "mongodb";
|
|
72
|
+
}
|
|
73
|
+
return void 0;
|
|
74
|
+
}
|
|
75
|
+
var init_orm_detector = __esm({
|
|
76
|
+
"src/analyzer/orm-detector.ts"() {
|
|
77
|
+
"use strict";
|
|
78
|
+
init_cjs_shims();
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// src/analyzer/project-detector.ts
|
|
83
|
+
async function detectProject(cwd = process.cwd()) {
|
|
84
|
+
const detector = new ProjectDetector(cwd);
|
|
85
|
+
return detector.detectProject();
|
|
86
|
+
}
|
|
87
|
+
var path, fs, ProjectDetector;
|
|
88
|
+
var init_project_detector = __esm({
|
|
89
|
+
"src/analyzer/project-detector.ts"() {
|
|
90
|
+
"use strict";
|
|
91
|
+
init_cjs_shims();
|
|
92
|
+
path = __toESM(require("path"));
|
|
93
|
+
fs = __toESM(require("fs-extra"));
|
|
94
|
+
init_orm_detector();
|
|
95
|
+
ProjectDetector = class {
|
|
96
|
+
constructor(cwd) {
|
|
97
|
+
this.cwd = cwd;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Detect and validate a NestJS project
|
|
101
|
+
*/
|
|
102
|
+
async detectProject() {
|
|
103
|
+
const errors = [];
|
|
104
|
+
const root = this.cwd;
|
|
105
|
+
const packageJsonPath = path.join(root, "package.json");
|
|
106
|
+
if (!await fs.pathExists(packageJsonPath)) {
|
|
107
|
+
errors.push("package.json not found");
|
|
108
|
+
return this.createInvalidProject(root, errors);
|
|
109
|
+
}
|
|
110
|
+
const packageJson = await this.readPackageJson(packageJsonPath);
|
|
111
|
+
if (!packageJson) {
|
|
112
|
+
errors.push("Failed to read package.json");
|
|
113
|
+
return this.createInvalidProject(root, errors);
|
|
114
|
+
}
|
|
115
|
+
const hasNestCore = packageJson.dependencies?.["@nestjs/core"];
|
|
116
|
+
const hasNestCommon = packageJson.dependencies?.["@nestjs/common"];
|
|
117
|
+
if (!hasNestCore || !hasNestCommon) {
|
|
118
|
+
errors.push("Not a NestJS project (missing @nestjs/core or @nestjs/common)");
|
|
119
|
+
return this.createInvalidProject(root, errors);
|
|
120
|
+
}
|
|
121
|
+
const nestCliConfigPath = path.join(root, "nest-cli.json");
|
|
122
|
+
const nestCliConfig = await this.readNestCliConfig(nestCliConfigPath);
|
|
123
|
+
const sourceRoot = nestCliConfig?.sourceRoot || "src";
|
|
124
|
+
const appModulePath = path.join(root, sourceRoot, "app.module.ts");
|
|
125
|
+
if (!await fs.pathExists(appModulePath)) {
|
|
126
|
+
errors.push(`app.module.ts not found at ${sourceRoot}/app.module.ts`);
|
|
127
|
+
return this.createInvalidProject(root, errors);
|
|
128
|
+
}
|
|
129
|
+
const mainTsPath = path.join(root, sourceRoot, "main.ts");
|
|
130
|
+
const orm = await detectORM(packageJson);
|
|
131
|
+
const database = detectDatabase(packageJson, orm);
|
|
132
|
+
const authModulePath = path.join(root, sourceRoot, "auth");
|
|
133
|
+
const authExists = await fs.pathExists(authModulePath);
|
|
134
|
+
return {
|
|
135
|
+
authExists,
|
|
136
|
+
root,
|
|
137
|
+
sourceRoot,
|
|
138
|
+
appModulePath,
|
|
139
|
+
mainTsPath,
|
|
140
|
+
packageJsonPath,
|
|
141
|
+
nestCliConfigPath,
|
|
142
|
+
orm,
|
|
143
|
+
database,
|
|
144
|
+
nestVersion: packageJson.dependencies?.["@nestjs/core"],
|
|
145
|
+
typescriptVersion: packageJson.devDependencies?.["typescript"],
|
|
146
|
+
isValid: errors.length === 0,
|
|
147
|
+
errors
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Read and parse package.json
|
|
152
|
+
*/
|
|
153
|
+
async readPackageJson(packageJsonPath) {
|
|
154
|
+
try {
|
|
155
|
+
const content = await fs.readFile(packageJsonPath, "utf-8");
|
|
156
|
+
return JSON.parse(content);
|
|
157
|
+
} catch (error) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Read and parse nest-cli.json
|
|
163
|
+
*/
|
|
164
|
+
async readNestCliConfig(nestCliConfigPath) {
|
|
165
|
+
try {
|
|
166
|
+
if (!await fs.pathExists(nestCliConfigPath)) {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
const content = await fs.readFile(nestCliConfigPath, "utf-8");
|
|
170
|
+
return JSON.parse(content);
|
|
171
|
+
} catch (error) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Create invalid project info object
|
|
177
|
+
*/
|
|
178
|
+
createInvalidProject(root, errors) {
|
|
179
|
+
return {
|
|
180
|
+
root,
|
|
181
|
+
sourceRoot: "src",
|
|
182
|
+
appModulePath: path.join(root, "src", "app.module.ts"),
|
|
183
|
+
mainTsPath: path.join(root, "src", "main.ts"),
|
|
184
|
+
packageJsonPath: path.join(root, "package.json"),
|
|
185
|
+
nestCliConfigPath: path.join(root, "nest-cli.json"),
|
|
186
|
+
orm: "none",
|
|
187
|
+
isValid: false,
|
|
188
|
+
errors
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// src/analyzer/index.ts
|
|
196
|
+
var init_analyzer = __esm({
|
|
197
|
+
"src/analyzer/index.ts"() {
|
|
198
|
+
"use strict";
|
|
199
|
+
init_cjs_shims();
|
|
200
|
+
init_project_detector();
|
|
201
|
+
init_orm_detector();
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// src/config/utils.ts
|
|
206
|
+
function generateSecret(length = 32) {
|
|
207
|
+
return (0, import_crypto.randomBytes)(length).toString("base64");
|
|
208
|
+
}
|
|
209
|
+
var import_crypto;
|
|
210
|
+
var init_utils = __esm({
|
|
211
|
+
"src/config/utils.ts"() {
|
|
212
|
+
"use strict";
|
|
213
|
+
init_cjs_shims();
|
|
214
|
+
import_crypto = require("crypto");
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// src/cli/prompts.ts
|
|
219
|
+
async function promptConfig(detectedORM, detectedDB) {
|
|
220
|
+
const dbLabel = detectedDB ? ` with ${detectedDB.charAt(0).toUpperCase() + detectedDB.slice(1)}` : "";
|
|
221
|
+
const answers = await import_inquirer.default.prompt([
|
|
222
|
+
{
|
|
223
|
+
type: "list",
|
|
224
|
+
name: "strategy",
|
|
225
|
+
message: "Choose authentication strategy:",
|
|
226
|
+
choices: [
|
|
227
|
+
{ name: "JWT Authentication (Recommended)", value: "jwt" },
|
|
228
|
+
{ name: "OAuth 2.0 (Google, GitHub) [Coming soon]", value: "oauth", disabled: true },
|
|
229
|
+
{ name: "Session-based (Traditional) [Coming soon]", value: "session", disabled: true }
|
|
230
|
+
],
|
|
231
|
+
default: "jwt"
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
type: "confirm",
|
|
235
|
+
name: "enableRBAC",
|
|
236
|
+
message: "Enable Role-Based Access Control (RBAC)?",
|
|
237
|
+
default: true
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
type: "checkbox",
|
|
241
|
+
name: "roles",
|
|
242
|
+
message: "Select default roles:",
|
|
243
|
+
choices: [
|
|
244
|
+
{ name: "Admin", value: "Admin", checked: true },
|
|
245
|
+
{ name: "User", value: "User", checked: true },
|
|
246
|
+
{ name: "Moderator", value: "Moderator", checked: false },
|
|
247
|
+
{ name: "Guest", value: "Guest", checked: false }
|
|
248
|
+
],
|
|
249
|
+
when: (answers2) => answers2.enableRBAC,
|
|
250
|
+
validate: (input) => {
|
|
251
|
+
if (input.length === 0) {
|
|
252
|
+
return "Please select at least one role";
|
|
253
|
+
}
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
type: "confirm",
|
|
259
|
+
name: "refreshTokens",
|
|
260
|
+
message: "Enable Refresh Token rotation?",
|
|
261
|
+
default: true
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
type: "list",
|
|
265
|
+
name: "accessExpiration",
|
|
266
|
+
message: "JWT Access Token expiration:",
|
|
267
|
+
choices: [
|
|
268
|
+
{ name: "15 minutes", value: "15m" },
|
|
269
|
+
{ name: "30 minutes", value: "30m" },
|
|
270
|
+
{ name: "1 hour (Recommended)", value: "1h" },
|
|
271
|
+
{ name: "4 hours", value: "4h" },
|
|
272
|
+
{ name: "1 day", value: "1d" }
|
|
273
|
+
],
|
|
274
|
+
default: "1h"
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
type: "list",
|
|
278
|
+
name: "refreshExpiration",
|
|
279
|
+
message: "JWT Refresh Token expiration:",
|
|
280
|
+
choices: [
|
|
281
|
+
{ name: "7 days (Recommended)", value: "7d" },
|
|
282
|
+
{ name: "30 days", value: "30d" },
|
|
283
|
+
{ name: "90 days", value: "90d" },
|
|
284
|
+
{ name: "1 year", value: "1y" }
|
|
285
|
+
],
|
|
286
|
+
default: "7d",
|
|
287
|
+
when: (answers2) => answers2.refreshTokens
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
type: "confirm",
|
|
291
|
+
name: "enableRateLimiting",
|
|
292
|
+
message: "Enable rate limiting on auth endpoints? (recommended)",
|
|
293
|
+
default: true
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
type: "confirm",
|
|
297
|
+
name: "useDetectedORM",
|
|
298
|
+
message: `Detected ${detectedORM.toUpperCase()}${dbLabel}. Use it?`,
|
|
299
|
+
default: true,
|
|
300
|
+
when: () => detectedORM !== "none"
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
type: "list",
|
|
304
|
+
name: "database",
|
|
305
|
+
message: "Select database:",
|
|
306
|
+
choices: [
|
|
307
|
+
{ name: "PostgreSQL (Recommended)", value: "postgres" },
|
|
308
|
+
{ name: "MySQL", value: "mysql" },
|
|
309
|
+
{ name: "SQLite (for testing)", value: "sqlite" },
|
|
310
|
+
{ name: "MongoDB", value: "mongodb" }
|
|
311
|
+
],
|
|
312
|
+
default: "postgres",
|
|
313
|
+
when: (answers2) => detectedORM === "none" || !answers2.useDetectedORM
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
type: "confirm",
|
|
317
|
+
name: "autoInstall",
|
|
318
|
+
message: "Auto-install dependencies after generation?",
|
|
319
|
+
default: true
|
|
320
|
+
}
|
|
321
|
+
]);
|
|
322
|
+
return answers;
|
|
323
|
+
}
|
|
324
|
+
function getDefaultAnswers(detectedORM, detectedDB) {
|
|
325
|
+
return {
|
|
326
|
+
strategy: "jwt",
|
|
327
|
+
enableRBAC: true,
|
|
328
|
+
roles: ["Admin", "User"],
|
|
329
|
+
refreshTokens: true,
|
|
330
|
+
accessExpiration: "1h",
|
|
331
|
+
refreshExpiration: "7d",
|
|
332
|
+
enableRateLimiting: true,
|
|
333
|
+
useDetectedORM: true,
|
|
334
|
+
database: detectedDB || "postgres",
|
|
335
|
+
autoInstall: true
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
function buildConfig(answers, projectName, sourceRoot, detectedORM, detectedDB) {
|
|
339
|
+
const config = {
|
|
340
|
+
projectName,
|
|
341
|
+
sourceRoot,
|
|
342
|
+
strategy: answers.strategy,
|
|
343
|
+
rbac: {
|
|
344
|
+
enabled: answers.enableRBAC,
|
|
345
|
+
roles: answers.roles || []
|
|
346
|
+
},
|
|
347
|
+
orm: answers.useDetectedORM !== false ? detectedORM : "typeorm",
|
|
348
|
+
database: answers.database || detectedDB || "postgres",
|
|
349
|
+
features: {
|
|
350
|
+
refreshTokens: answers.refreshTokens,
|
|
351
|
+
rateLimiting: answers.enableRateLimiting
|
|
352
|
+
},
|
|
353
|
+
jwt: {
|
|
354
|
+
secret: generateSecret(),
|
|
355
|
+
accessExpiration: answers.accessExpiration,
|
|
356
|
+
refreshExpiration: answers.refreshExpiration || "7d"
|
|
357
|
+
},
|
|
358
|
+
autoInstall: answers.autoInstall,
|
|
359
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
360
|
+
generatorVersion: "1.1.0"
|
|
361
|
+
};
|
|
362
|
+
return config;
|
|
363
|
+
}
|
|
364
|
+
var import_inquirer;
|
|
365
|
+
var init_prompts = __esm({
|
|
366
|
+
"src/cli/prompts.ts"() {
|
|
367
|
+
"use strict";
|
|
368
|
+
init_cjs_shims();
|
|
369
|
+
import_inquirer = __toESM(require("inquirer"));
|
|
370
|
+
init_utils();
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
// src/cli/ui.ts
|
|
375
|
+
function getVersion() {
|
|
376
|
+
try {
|
|
377
|
+
const packageJsonPath = (0, import_path.join)(__dirname, "../package.json");
|
|
378
|
+
const packageJson = JSON.parse((0, import_fs.readFileSync)(packageJsonPath, "utf-8"));
|
|
379
|
+
return packageJson.version;
|
|
380
|
+
} catch (error) {
|
|
381
|
+
return "1.0.0";
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
function showBanner() {
|
|
385
|
+
console.log(import_chalk.default.cyan(`
|
|
386
|
+
___ _ _ __ __
|
|
387
|
+
/ _ \\ | | | | | \\/ |
|
|
388
|
+
/ /_\\ \\_ _ | |_| |__ | \\ / | ___
|
|
389
|
+
| _ | | | || __| '_ \\ | |\\/| |/ _ \\
|
|
390
|
+
| | | | |_| || |_| | | | | | | | __/
|
|
391
|
+
\\_| |_/\\__,_| \\__|_| |_| \\_| |_/\\___|
|
|
392
|
+
`));
|
|
393
|
+
console.log(import_chalk.default.bold(`\u{1F510} NestJS Authentication Module Generator v${getVersion()}`));
|
|
394
|
+
console.log();
|
|
395
|
+
}
|
|
396
|
+
function showProjectInfo(info) {
|
|
397
|
+
console.log(import_chalk.default.green("\u2713"), `Detected NestJS ${info.nestVersion || "project"}`);
|
|
398
|
+
if (info.orm !== "none") {
|
|
399
|
+
console.log(import_chalk.default.green("\u2713"), `Found ${info.orm.toUpperCase()}`);
|
|
400
|
+
}
|
|
401
|
+
console.log(import_chalk.default.green("\u2713"), `Source directory: ${info.sourceRoot}/`);
|
|
402
|
+
console.log(import_chalk.default.green("\u2713"), "No existing auth module found");
|
|
403
|
+
console.log();
|
|
404
|
+
}
|
|
405
|
+
function showError(message, errors) {
|
|
406
|
+
console.log();
|
|
407
|
+
console.log(import_chalk.default.red("\u274C Error:"), import_chalk.default.bold(message));
|
|
408
|
+
if (errors && errors.length > 0) {
|
|
409
|
+
console.log();
|
|
410
|
+
errors.forEach((error) => {
|
|
411
|
+
console.log(import_chalk.default.red(" \u2022"), error);
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
console.log();
|
|
415
|
+
}
|
|
416
|
+
function showNestJSHelp() {
|
|
417
|
+
console.log(import_chalk.default.yellow("To create a new NestJS project:"));
|
|
418
|
+
console.log();
|
|
419
|
+
console.log(import_chalk.default.cyan(" npm i -g @nestjs/cli"));
|
|
420
|
+
console.log(import_chalk.default.cyan(" nest new my-project"));
|
|
421
|
+
console.log();
|
|
422
|
+
}
|
|
423
|
+
function showSuccess(stats) {
|
|
424
|
+
console.log();
|
|
425
|
+
console.log(import_chalk.default.green.bold("\u{1F389} Success!"), "Authentication module generated.");
|
|
426
|
+
console.log();
|
|
427
|
+
console.log(import_chalk.default.bold("\u{1F4C1} Files created:"));
|
|
428
|
+
console.log(` \u2022 ${stats.filesCreated} new files in src/auth/ and src/users/`);
|
|
429
|
+
console.log(` \u2022 Updated src/app.module.ts`);
|
|
430
|
+
console.log(` \u2022 Updated package.json`);
|
|
431
|
+
console.log();
|
|
432
|
+
console.log(import_chalk.default.bold("\u{1F4E6} Dependencies added:"));
|
|
433
|
+
console.log(` \u2022 @nestjs/jwt, @nestjs/passport, @nestjs/config`);
|
|
434
|
+
console.log(` \u2022 passport, passport-jwt, passport-local`);
|
|
435
|
+
console.log(` \u2022 bcrypt, class-validator, class-transformer`);
|
|
436
|
+
console.log(` \u2022 ${stats.dependenciesAdded} packages total`);
|
|
437
|
+
console.log();
|
|
438
|
+
console.log(import_chalk.default.bold("\u{1F510} JWT Configuration:"));
|
|
439
|
+
console.log(` \u2022 Access token: ${stats.jwt.accessExpiration}`);
|
|
440
|
+
if (stats.jwt.refreshExpiration) {
|
|
441
|
+
console.log(` \u2022 Refresh token: ${stats.jwt.refreshExpiration}`);
|
|
442
|
+
}
|
|
443
|
+
console.log(` \u2022 Secret: Auto-generated (see .env)`);
|
|
444
|
+
console.log();
|
|
445
|
+
console.log(import_chalk.default.bold("\u{1F4CB} Next steps:"));
|
|
446
|
+
console.log(import_chalk.default.cyan(" 1. Review .env file (auto-generated with secure secret)"));
|
|
447
|
+
console.log(import_chalk.default.gray(" # .env.example is also provided as a git-safe reference"));
|
|
448
|
+
console.log();
|
|
449
|
+
console.log(import_chalk.default.cyan(" 2. Create database migration (if using TypeORM)"));
|
|
450
|
+
console.log(import_chalk.default.gray(" npm run migration:generate -- src/migrations/CreateUserTable"));
|
|
451
|
+
console.log(import_chalk.default.gray(" npm run migration:run"));
|
|
452
|
+
console.log();
|
|
453
|
+
console.log(import_chalk.default.cyan(" 3. Start your NestJS app"));
|
|
454
|
+
console.log(import_chalk.default.gray(" npm run start:dev"));
|
|
455
|
+
console.log();
|
|
456
|
+
console.log(import_chalk.default.cyan(" 4. Test authentication endpoints"));
|
|
457
|
+
console.log(import_chalk.default.gray(" POST http://localhost:3000/auth/register"));
|
|
458
|
+
console.log(import_chalk.default.gray(" POST http://localhost:3000/auth/login"));
|
|
459
|
+
console.log(import_chalk.default.gray(" POST http://localhost:3000/auth/refresh"));
|
|
460
|
+
console.log(import_chalk.default.gray(" POST http://localhost:3000/auth/logout (requires JWT)"));
|
|
461
|
+
console.log(import_chalk.default.gray(" POST http://localhost:3000/auth/logout-all (requires JWT)"));
|
|
462
|
+
console.log(import_chalk.default.gray(" GET http://localhost:3000/users/profile (requires JWT)"));
|
|
463
|
+
console.log();
|
|
464
|
+
console.log(import_chalk.default.bold("\u{1F4D6} Full documentation:"), "src/auth/README.md");
|
|
465
|
+
console.log();
|
|
466
|
+
console.log(import_chalk.default.bold("\u{1F4A1} Tips:"));
|
|
467
|
+
console.log(" \u2022 Use @Public() decorator for routes that don't require auth");
|
|
468
|
+
console.log(" \u2022 Use @Roles('Admin') to restrict routes by role");
|
|
469
|
+
console.log(" \u2022 Access current user with @CurrentUser() decorator");
|
|
470
|
+
console.log();
|
|
471
|
+
}
|
|
472
|
+
function createSpinner(text) {
|
|
473
|
+
return (0, import_ora.default)({
|
|
474
|
+
text,
|
|
475
|
+
color: "cyan"
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
var import_chalk, import_ora, import_fs, import_path;
|
|
479
|
+
var init_ui = __esm({
|
|
480
|
+
"src/cli/ui.ts"() {
|
|
481
|
+
"use strict";
|
|
482
|
+
init_cjs_shims();
|
|
483
|
+
import_chalk = __toESM(require("chalk"));
|
|
484
|
+
import_ora = __toESM(require("ora"));
|
|
485
|
+
import_fs = require("fs");
|
|
486
|
+
import_path = require("path");
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
|
|
39
490
|
// src/generator/template-engine.ts
|
|
40
491
|
var import_handlebars, path2, fs2, TemplateEngine;
|
|
41
492
|
var init_template_engine = __esm({
|
|
@@ -321,6 +772,7 @@ var init_generator = __esm({
|
|
|
321
772
|
}
|
|
322
773
|
plan.push(
|
|
323
774
|
{ template: "shared/env.template.hbs", output: ".env.example" },
|
|
775
|
+
{ template: "shared/env.hbs", output: ".env" },
|
|
324
776
|
{ template: "shared/README.auth.md.hbs", output: `${config.sourceRoot}/auth/README.md` },
|
|
325
777
|
{ template: "shared/main.ts.snippet.hbs", output: "main.ts.example" }
|
|
326
778
|
);
|
|
@@ -456,20 +908,27 @@ var init_ast_updater = __esm({
|
|
|
456
908
|
throw new Error("imports is not an array");
|
|
457
909
|
}
|
|
458
910
|
const existingModules = this.getExistingModuleNames(importsArray);
|
|
911
|
+
const existingElements = importsArray.getElements().map((e) => e.getText());
|
|
912
|
+
const allElements = [...existingElements];
|
|
459
913
|
if (!existingModules.has("ConfigModule")) {
|
|
460
|
-
|
|
914
|
+
allElements.push("ConfigModule.forRoot({ isGlobal: true })");
|
|
461
915
|
}
|
|
462
916
|
if (config && config.orm === "typeorm" && !existingModules.has("TypeOrmModule")) {
|
|
463
917
|
const entities = config.features.refreshTokens ? "[User, RefreshToken]" : "[User]";
|
|
464
|
-
|
|
465
|
-
importsArray.addElement(typeOrmConfig);
|
|
918
|
+
allElements.push(this.buildTypeOrmConfig(config.database, entities));
|
|
466
919
|
}
|
|
467
920
|
if (!existingModules.has("AuthModule")) {
|
|
468
|
-
|
|
921
|
+
allElements.push("AuthModule");
|
|
469
922
|
}
|
|
470
923
|
if (!existingModules.has("UsersModule")) {
|
|
471
|
-
|
|
924
|
+
allElements.push("UsersModule");
|
|
472
925
|
}
|
|
926
|
+
const indent = " ";
|
|
927
|
+
const formattedElements = allElements.map((el) => `${indent}${el}`).join(",\n");
|
|
928
|
+
const multiLineArray = `[
|
|
929
|
+
${formattedElements},
|
|
930
|
+
]`;
|
|
931
|
+
importsProperty.setInitializer(multiLineArray);
|
|
473
932
|
}
|
|
474
933
|
/**
|
|
475
934
|
* Build TypeORM.forRoot() configuration string based on database type
|
|
@@ -777,6 +1236,9 @@ var init_package_updater = __esm({
|
|
|
777
1236
|
break;
|
|
778
1237
|
}
|
|
779
1238
|
}
|
|
1239
|
+
if (config.features.rateLimiting) {
|
|
1240
|
+
dependencies["@nestjs/throttler"] = "^6.0.0";
|
|
1241
|
+
}
|
|
780
1242
|
return { dependencies, devDependencies };
|
|
781
1243
|
}
|
|
782
1244
|
/**
|
|
@@ -808,477 +1270,80 @@ var init_package_updater = __esm({
|
|
|
808
1270
|
* Clean up backup
|
|
809
1271
|
*/
|
|
810
1272
|
async cleanupBackup() {
|
|
811
|
-
if (this.backupPath && await fs6.pathExists(this.backupPath)) {
|
|
812
|
-
await fs6.remove(this.backupPath);
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
};
|
|
816
|
-
}
|
|
817
|
-
});
|
|
818
|
-
|
|
819
|
-
// src/installer/dependency-installer.ts
|
|
820
|
-
var import_execa, import_detect_package_manager, DependencyInstaller;
|
|
821
|
-
var init_dependency_installer = __esm({
|
|
822
|
-
"src/installer/dependency-installer.ts"() {
|
|
823
|
-
"use strict";
|
|
824
|
-
init_cjs_shims();
|
|
825
|
-
import_execa = require("execa");
|
|
826
|
-
import_detect_package_manager = require("detect-package-manager");
|
|
827
|
-
DependencyInstaller = class {
|
|
828
|
-
/**
|
|
829
|
-
* Install dependencies using the detected package manager
|
|
830
|
-
*/
|
|
831
|
-
async install(cwd) {
|
|
832
|
-
const packageManager = await this.detectPackageManager(cwd);
|
|
833
|
-
console.log(`\u{1F4E6} Installing dependencies with ${packageManager}...`);
|
|
834
|
-
try {
|
|
835
|
-
await (0, import_execa.execa)(packageManager, ["install"], {
|
|
836
|
-
cwd,
|
|
837
|
-
stdio: "inherit"
|
|
838
|
-
});
|
|
839
|
-
console.log("\u2705 Dependencies installed successfully");
|
|
840
|
-
} catch (error) {
|
|
841
|
-
throw new Error(
|
|
842
|
-
`Failed to install dependencies with ${packageManager}: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
843
|
-
);
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
/**
|
|
847
|
-
* Detect which package manager is being used
|
|
848
|
-
*/
|
|
849
|
-
async detectPackageManager(cwd) {
|
|
850
|
-
try {
|
|
851
|
-
return await (0, import_detect_package_manager.detect)({ cwd });
|
|
852
|
-
} catch (error) {
|
|
853
|
-
return "npm";
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
};
|
|
857
|
-
}
|
|
858
|
-
});
|
|
859
|
-
|
|
860
|
-
// src/installer/index.ts
|
|
861
|
-
var installer_exports = {};
|
|
862
|
-
__export(installer_exports, {
|
|
863
|
-
AppModuleUpdater: () => AppModuleUpdater,
|
|
864
|
-
DependencyInstaller: () => DependencyInstaller,
|
|
865
|
-
MainTsUpdater: () => MainTsUpdater,
|
|
866
|
-
PackageUpdater: () => PackageUpdater
|
|
867
|
-
});
|
|
868
|
-
var init_installer = __esm({
|
|
869
|
-
"src/installer/index.ts"() {
|
|
870
|
-
"use strict";
|
|
871
|
-
init_cjs_shims();
|
|
872
|
-
init_ast_updater();
|
|
873
|
-
init_main_ts_updater();
|
|
874
|
-
init_package_updater();
|
|
875
|
-
init_dependency_installer();
|
|
876
|
-
}
|
|
877
|
-
});
|
|
878
|
-
|
|
879
|
-
// src/cli.ts
|
|
880
|
-
init_cjs_shims();
|
|
881
|
-
|
|
882
|
-
// src/index.ts
|
|
883
|
-
init_cjs_shims();
|
|
884
|
-
|
|
885
|
-
// src/analyzer/index.ts
|
|
886
|
-
init_cjs_shims();
|
|
887
|
-
|
|
888
|
-
// src/analyzer/project-detector.ts
|
|
889
|
-
init_cjs_shims();
|
|
890
|
-
var path = __toESM(require("path"));
|
|
891
|
-
var fs = __toESM(require("fs-extra"));
|
|
892
|
-
|
|
893
|
-
// src/analyzer/orm-detector.ts
|
|
894
|
-
init_cjs_shims();
|
|
895
|
-
async function detectORM(packageJson) {
|
|
896
|
-
const dependencies = {
|
|
897
|
-
...packageJson.dependencies,
|
|
898
|
-
...packageJson.devDependencies
|
|
899
|
-
};
|
|
900
|
-
if (dependencies["@nestjs/typeorm"] || dependencies["typeorm"]) {
|
|
901
|
-
return "typeorm";
|
|
902
|
-
}
|
|
903
|
-
if (dependencies["@prisma/client"] || dependencies["prisma"]) {
|
|
904
|
-
return "prisma";
|
|
905
|
-
}
|
|
906
|
-
if (dependencies["@nestjs/mongoose"] || dependencies["mongoose"]) {
|
|
907
|
-
return "mongoose";
|
|
908
|
-
}
|
|
909
|
-
return "none";
|
|
910
|
-
}
|
|
911
|
-
function detectDatabase(packageJson, orm) {
|
|
912
|
-
const dependencies = {
|
|
913
|
-
...packageJson.dependencies,
|
|
914
|
-
...packageJson.devDependencies
|
|
915
|
-
};
|
|
916
|
-
if (orm === "typeorm") {
|
|
917
|
-
if (dependencies["pg"]) return "postgres";
|
|
918
|
-
if (dependencies["mysql2"] || dependencies["mysql"]) return "mysql";
|
|
919
|
-
if (dependencies["sqlite3"]) return "sqlite";
|
|
920
|
-
if (dependencies["mongodb"]) return "mongodb";
|
|
921
|
-
}
|
|
922
|
-
if (orm === "prisma") {
|
|
923
|
-
return void 0;
|
|
924
|
-
}
|
|
925
|
-
if (orm === "mongoose") {
|
|
926
|
-
return "mongodb";
|
|
927
|
-
}
|
|
928
|
-
return void 0;
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
// src/analyzer/project-detector.ts
|
|
932
|
-
var ProjectDetector = class {
|
|
933
|
-
constructor(cwd) {
|
|
934
|
-
this.cwd = cwd;
|
|
935
|
-
}
|
|
936
|
-
/**
|
|
937
|
-
* Detect and validate a NestJS project
|
|
938
|
-
*/
|
|
939
|
-
async detectProject() {
|
|
940
|
-
const errors = [];
|
|
941
|
-
const root = this.cwd;
|
|
942
|
-
const packageJsonPath = path.join(root, "package.json");
|
|
943
|
-
if (!await fs.pathExists(packageJsonPath)) {
|
|
944
|
-
errors.push("package.json not found");
|
|
945
|
-
return this.createInvalidProject(root, errors);
|
|
946
|
-
}
|
|
947
|
-
const packageJson = await this.readPackageJson(packageJsonPath);
|
|
948
|
-
if (!packageJson) {
|
|
949
|
-
errors.push("Failed to read package.json");
|
|
950
|
-
return this.createInvalidProject(root, errors);
|
|
951
|
-
}
|
|
952
|
-
const hasNestCore = packageJson.dependencies?.["@nestjs/core"];
|
|
953
|
-
const hasNestCommon = packageJson.dependencies?.["@nestjs/common"];
|
|
954
|
-
if (!hasNestCore || !hasNestCommon) {
|
|
955
|
-
errors.push("Not a NestJS project (missing @nestjs/core or @nestjs/common)");
|
|
956
|
-
return this.createInvalidProject(root, errors);
|
|
957
|
-
}
|
|
958
|
-
const nestCliConfigPath = path.join(root, "nest-cli.json");
|
|
959
|
-
const nestCliConfig = await this.readNestCliConfig(nestCliConfigPath);
|
|
960
|
-
const sourceRoot = nestCliConfig?.sourceRoot || "src";
|
|
961
|
-
const appModulePath = path.join(root, sourceRoot, "app.module.ts");
|
|
962
|
-
if (!await fs.pathExists(appModulePath)) {
|
|
963
|
-
errors.push(`app.module.ts not found at ${sourceRoot}/app.module.ts`);
|
|
964
|
-
return this.createInvalidProject(root, errors);
|
|
965
|
-
}
|
|
966
|
-
const mainTsPath = path.join(root, sourceRoot, "main.ts");
|
|
967
|
-
const orm = await detectORM(packageJson);
|
|
968
|
-
const database = detectDatabase(packageJson, orm);
|
|
969
|
-
const authModulePath = path.join(root, sourceRoot, "auth");
|
|
970
|
-
const authExists = await fs.pathExists(authModulePath);
|
|
971
|
-
return {
|
|
972
|
-
authExists,
|
|
973
|
-
root,
|
|
974
|
-
sourceRoot,
|
|
975
|
-
appModulePath,
|
|
976
|
-
mainTsPath,
|
|
977
|
-
packageJsonPath,
|
|
978
|
-
nestCliConfigPath,
|
|
979
|
-
orm,
|
|
980
|
-
database,
|
|
981
|
-
nestVersion: packageJson.dependencies?.["@nestjs/core"],
|
|
982
|
-
typescriptVersion: packageJson.devDependencies?.["typescript"],
|
|
983
|
-
isValid: errors.length === 0,
|
|
984
|
-
errors
|
|
985
|
-
};
|
|
986
|
-
}
|
|
987
|
-
/**
|
|
988
|
-
* Read and parse package.json
|
|
989
|
-
*/
|
|
990
|
-
async readPackageJson(packageJsonPath) {
|
|
991
|
-
try {
|
|
992
|
-
const content = await fs.readFile(packageJsonPath, "utf-8");
|
|
993
|
-
return JSON.parse(content);
|
|
994
|
-
} catch (error) {
|
|
995
|
-
return null;
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
/**
|
|
999
|
-
* Read and parse nest-cli.json
|
|
1000
|
-
*/
|
|
1001
|
-
async readNestCliConfig(nestCliConfigPath) {
|
|
1002
|
-
try {
|
|
1003
|
-
if (!await fs.pathExists(nestCliConfigPath)) {
|
|
1004
|
-
return null;
|
|
1005
|
-
}
|
|
1006
|
-
const content = await fs.readFile(nestCliConfigPath, "utf-8");
|
|
1007
|
-
return JSON.parse(content);
|
|
1008
|
-
} catch (error) {
|
|
1009
|
-
return null;
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
|
-
/**
|
|
1013
|
-
* Create invalid project info object
|
|
1014
|
-
*/
|
|
1015
|
-
createInvalidProject(root, errors) {
|
|
1016
|
-
return {
|
|
1017
|
-
root,
|
|
1018
|
-
sourceRoot: "src",
|
|
1019
|
-
appModulePath: path.join(root, "src", "app.module.ts"),
|
|
1020
|
-
mainTsPath: path.join(root, "src", "main.ts"),
|
|
1021
|
-
packageJsonPath: path.join(root, "package.json"),
|
|
1022
|
-
nestCliConfigPath: path.join(root, "nest-cli.json"),
|
|
1023
|
-
orm: "none",
|
|
1024
|
-
isValid: false,
|
|
1025
|
-
errors
|
|
1026
|
-
};
|
|
1027
|
-
}
|
|
1028
|
-
};
|
|
1029
|
-
async function detectProject(cwd = process.cwd()) {
|
|
1030
|
-
const detector = new ProjectDetector(cwd);
|
|
1031
|
-
return detector.detectProject();
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
|
-
// src/cli/prompts.ts
|
|
1035
|
-
init_cjs_shims();
|
|
1036
|
-
var import_inquirer = __toESM(require("inquirer"));
|
|
1037
|
-
|
|
1038
|
-
// src/config/utils.ts
|
|
1039
|
-
init_cjs_shims();
|
|
1040
|
-
var import_crypto = require("crypto");
|
|
1041
|
-
function generateSecret(length = 32) {
|
|
1042
|
-
return (0, import_crypto.randomBytes)(length).toString("base64");
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
// src/cli/prompts.ts
|
|
1046
|
-
async function promptConfig(detectedORM, detectedDB) {
|
|
1047
|
-
const dbLabel = detectedDB ? ` with ${detectedDB.charAt(0).toUpperCase() + detectedDB.slice(1)}` : "";
|
|
1048
|
-
const answers = await import_inquirer.default.prompt([
|
|
1049
|
-
{
|
|
1050
|
-
type: "list",
|
|
1051
|
-
name: "strategy",
|
|
1052
|
-
message: "Choose authentication strategy:",
|
|
1053
|
-
choices: [
|
|
1054
|
-
{ name: "JWT Authentication (Recommended)", value: "jwt" },
|
|
1055
|
-
{ name: "OAuth 2.0 (Google, GitHub) [v1.1]", value: "oauth", disabled: true },
|
|
1056
|
-
{ name: "Session-based (Traditional) [v1.2]", value: "session", disabled: true }
|
|
1057
|
-
],
|
|
1058
|
-
default: "jwt"
|
|
1059
|
-
},
|
|
1060
|
-
{
|
|
1061
|
-
type: "confirm",
|
|
1062
|
-
name: "enableRBAC",
|
|
1063
|
-
message: "Enable Role-Based Access Control (RBAC)?",
|
|
1064
|
-
default: true
|
|
1065
|
-
},
|
|
1066
|
-
{
|
|
1067
|
-
type: "checkbox",
|
|
1068
|
-
name: "roles",
|
|
1069
|
-
message: "Select default roles:",
|
|
1070
|
-
choices: [
|
|
1071
|
-
{ name: "Admin", value: "Admin", checked: true },
|
|
1072
|
-
{ name: "User", value: "User", checked: true },
|
|
1073
|
-
{ name: "Moderator", value: "Moderator", checked: false },
|
|
1074
|
-
{ name: "Guest", value: "Guest", checked: false }
|
|
1075
|
-
],
|
|
1076
|
-
when: (answers2) => answers2.enableRBAC,
|
|
1077
|
-
validate: (input) => {
|
|
1078
|
-
if (input.length === 0) {
|
|
1079
|
-
return "Please select at least one role";
|
|
1273
|
+
if (this.backupPath && await fs6.pathExists(this.backupPath)) {
|
|
1274
|
+
await fs6.remove(this.backupPath);
|
|
1080
1275
|
}
|
|
1081
|
-
return true;
|
|
1082
1276
|
}
|
|
1083
|
-
}
|
|
1084
|
-
{
|
|
1085
|
-
type: "confirm",
|
|
1086
|
-
name: "refreshTokens",
|
|
1087
|
-
message: "Enable Refresh Token rotation?",
|
|
1088
|
-
default: true
|
|
1089
|
-
},
|
|
1090
|
-
{
|
|
1091
|
-
type: "list",
|
|
1092
|
-
name: "accessExpiration",
|
|
1093
|
-
message: "JWT Access Token expiration:",
|
|
1094
|
-
choices: [
|
|
1095
|
-
{ name: "15 minutes", value: "15m" },
|
|
1096
|
-
{ name: "30 minutes", value: "30m" },
|
|
1097
|
-
{ name: "1 hour (Recommended)", value: "1h" },
|
|
1098
|
-
{ name: "4 hours", value: "4h" },
|
|
1099
|
-
{ name: "1 day", value: "1d" }
|
|
1100
|
-
],
|
|
1101
|
-
default: "1h"
|
|
1102
|
-
},
|
|
1103
|
-
{
|
|
1104
|
-
type: "list",
|
|
1105
|
-
name: "refreshExpiration",
|
|
1106
|
-
message: "JWT Refresh Token expiration:",
|
|
1107
|
-
choices: [
|
|
1108
|
-
{ name: "7 days (Recommended)", value: "7d" },
|
|
1109
|
-
{ name: "30 days", value: "30d" },
|
|
1110
|
-
{ name: "90 days", value: "90d" },
|
|
1111
|
-
{ name: "1 year", value: "1y" }
|
|
1112
|
-
],
|
|
1113
|
-
default: "7d",
|
|
1114
|
-
when: (answers2) => answers2.refreshTokens
|
|
1115
|
-
},
|
|
1116
|
-
{
|
|
1117
|
-
type: "confirm",
|
|
1118
|
-
name: "useDetectedORM",
|
|
1119
|
-
message: `Detected ${detectedORM.toUpperCase()}${dbLabel}. Use it?`,
|
|
1120
|
-
default: true,
|
|
1121
|
-
when: () => detectedORM !== "none"
|
|
1122
|
-
},
|
|
1123
|
-
{
|
|
1124
|
-
type: "list",
|
|
1125
|
-
name: "database",
|
|
1126
|
-
message: "Select database:",
|
|
1127
|
-
choices: [
|
|
1128
|
-
{ name: "PostgreSQL (Recommended)", value: "postgres" },
|
|
1129
|
-
{ name: "MySQL", value: "mysql" },
|
|
1130
|
-
{ name: "SQLite (for testing)", value: "sqlite" },
|
|
1131
|
-
{ name: "MongoDB", value: "mongodb" }
|
|
1132
|
-
],
|
|
1133
|
-
default: "postgres",
|
|
1134
|
-
when: (answers2) => detectedORM === "none" || !answers2.useDetectedORM
|
|
1135
|
-
},
|
|
1136
|
-
{
|
|
1137
|
-
type: "confirm",
|
|
1138
|
-
name: "autoInstall",
|
|
1139
|
-
message: "Auto-install dependencies after generation?",
|
|
1140
|
-
default: true
|
|
1141
|
-
}
|
|
1142
|
-
]);
|
|
1143
|
-
return answers;
|
|
1144
|
-
}
|
|
1145
|
-
function buildConfig(answers, projectName, sourceRoot, detectedORM, detectedDB) {
|
|
1146
|
-
const config = {
|
|
1147
|
-
projectName,
|
|
1148
|
-
sourceRoot,
|
|
1149
|
-
strategy: answers.strategy,
|
|
1150
|
-
rbac: {
|
|
1151
|
-
enabled: answers.enableRBAC,
|
|
1152
|
-
roles: answers.roles || []
|
|
1153
|
-
},
|
|
1154
|
-
orm: answers.useDetectedORM !== false ? detectedORM : "typeorm",
|
|
1155
|
-
database: answers.database || detectedDB || "postgres",
|
|
1156
|
-
features: {
|
|
1157
|
-
refreshTokens: answers.refreshTokens
|
|
1158
|
-
},
|
|
1159
|
-
jwt: {
|
|
1160
|
-
secret: generateSecret(),
|
|
1161
|
-
accessExpiration: answers.accessExpiration,
|
|
1162
|
-
refreshExpiration: answers.refreshExpiration || "7d"
|
|
1163
|
-
},
|
|
1164
|
-
autoInstall: answers.autoInstall,
|
|
1165
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1166
|
-
generatorVersion: "1.0.0"
|
|
1167
|
-
};
|
|
1168
|
-
return config;
|
|
1169
|
-
}
|
|
1170
|
-
|
|
1171
|
-
// src/cli/ui.ts
|
|
1172
|
-
init_cjs_shims();
|
|
1173
|
-
var import_chalk = __toESM(require("chalk"));
|
|
1174
|
-
var import_ora = __toESM(require("ora"));
|
|
1175
|
-
var import_fs = require("fs");
|
|
1176
|
-
var import_path = require("path");
|
|
1177
|
-
function getVersion() {
|
|
1178
|
-
try {
|
|
1179
|
-
const packageJsonPath = (0, import_path.join)(__dirname, "../package.json");
|
|
1180
|
-
const packageJson = JSON.parse((0, import_fs.readFileSync)(packageJsonPath, "utf-8"));
|
|
1181
|
-
return packageJson.version;
|
|
1182
|
-
} catch (error) {
|
|
1183
|
-
return "1.0.0";
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1186
|
-
function showBanner() {
|
|
1187
|
-
console.log(import_chalk.default.cyan(`
|
|
1188
|
-
___ _ _ __ __
|
|
1189
|
-
/ _ \\ | | | | | \\/ |
|
|
1190
|
-
/ /_\\ \\_ _ | |_| |__ | \\ / | ___
|
|
1191
|
-
| _ | | | || __| '_ \\ | |\\/| |/ _ \\
|
|
1192
|
-
| | | | |_| || |_| | | | | | | | __/
|
|
1193
|
-
\\_| |_/\\__,_| \\__|_| |_| \\_| |_/\\___|
|
|
1194
|
-
`));
|
|
1195
|
-
console.log(import_chalk.default.bold(`\u{1F510} NestJS Authentication Module Generator v${getVersion()}`));
|
|
1196
|
-
console.log();
|
|
1197
|
-
}
|
|
1198
|
-
function showProjectInfo(info) {
|
|
1199
|
-
console.log(import_chalk.default.green("\u2713"), `Detected NestJS ${info.nestVersion || "project"}`);
|
|
1200
|
-
if (info.orm !== "none") {
|
|
1201
|
-
console.log(import_chalk.default.green("\u2713"), `Found ${info.orm.toUpperCase()}`);
|
|
1277
|
+
};
|
|
1202
1278
|
}
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1279
|
+
});
|
|
1280
|
+
|
|
1281
|
+
// src/installer/dependency-installer.ts
|
|
1282
|
+
var import_execa, import_detect_package_manager, DependencyInstaller;
|
|
1283
|
+
var init_dependency_installer = __esm({
|
|
1284
|
+
"src/installer/dependency-installer.ts"() {
|
|
1285
|
+
"use strict";
|
|
1286
|
+
init_cjs_shims();
|
|
1287
|
+
import_execa = require("execa");
|
|
1288
|
+
import_detect_package_manager = require("detect-package-manager");
|
|
1289
|
+
DependencyInstaller = class {
|
|
1290
|
+
/**
|
|
1291
|
+
* Install dependencies using the detected package manager
|
|
1292
|
+
*/
|
|
1293
|
+
async install(cwd) {
|
|
1294
|
+
const packageManager = await this.detectPackageManager(cwd);
|
|
1295
|
+
console.log(`\u{1F4E6} Installing dependencies with ${packageManager}...`);
|
|
1296
|
+
try {
|
|
1297
|
+
await (0, import_execa.execa)(packageManager, ["install"], {
|
|
1298
|
+
cwd,
|
|
1299
|
+
stdio: "inherit"
|
|
1300
|
+
});
|
|
1301
|
+
console.log("\u2705 Dependencies installed successfully");
|
|
1302
|
+
} catch (error) {
|
|
1303
|
+
throw new Error(
|
|
1304
|
+
`Failed to install dependencies with ${packageManager}: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
1305
|
+
);
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
/**
|
|
1309
|
+
* Detect which package manager is being used
|
|
1310
|
+
*/
|
|
1311
|
+
async detectPackageManager(cwd) {
|
|
1312
|
+
try {
|
|
1313
|
+
return await (0, import_detect_package_manager.detect)({ cwd });
|
|
1314
|
+
} catch (error) {
|
|
1315
|
+
return "npm";
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
};
|
|
1215
1319
|
}
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
console.log(import_chalk.default.bold("\u{1F4E6} Dependencies added:"));
|
|
1235
|
-
console.log(` \u2022 @nestjs/jwt, @nestjs/passport, @nestjs/config`);
|
|
1236
|
-
console.log(` \u2022 passport, passport-jwt, passport-local`);
|
|
1237
|
-
console.log(` \u2022 bcrypt, class-validator, class-transformer`);
|
|
1238
|
-
console.log(` \u2022 ${stats.dependenciesAdded} packages total`);
|
|
1239
|
-
console.log();
|
|
1240
|
-
console.log(import_chalk.default.bold("\u{1F510} JWT Configuration:"));
|
|
1241
|
-
console.log(` \u2022 Access token: ${stats.jwt.accessExpiration}`);
|
|
1242
|
-
if (stats.jwt.refreshExpiration) {
|
|
1243
|
-
console.log(` \u2022 Refresh token: ${stats.jwt.refreshExpiration}`);
|
|
1320
|
+
});
|
|
1321
|
+
|
|
1322
|
+
// src/installer/index.ts
|
|
1323
|
+
var installer_exports = {};
|
|
1324
|
+
__export(installer_exports, {
|
|
1325
|
+
AppModuleUpdater: () => AppModuleUpdater,
|
|
1326
|
+
DependencyInstaller: () => DependencyInstaller,
|
|
1327
|
+
MainTsUpdater: () => MainTsUpdater,
|
|
1328
|
+
PackageUpdater: () => PackageUpdater
|
|
1329
|
+
});
|
|
1330
|
+
var init_installer = __esm({
|
|
1331
|
+
"src/installer/index.ts"() {
|
|
1332
|
+
"use strict";
|
|
1333
|
+
init_cjs_shims();
|
|
1334
|
+
init_ast_updater();
|
|
1335
|
+
init_main_ts_updater();
|
|
1336
|
+
init_package_updater();
|
|
1337
|
+
init_dependency_installer();
|
|
1244
1338
|
}
|
|
1245
|
-
|
|
1246
|
-
console.log();
|
|
1247
|
-
console.log(import_chalk.default.bold("\u{1F4CB} Next steps:"));
|
|
1248
|
-
console.log(import_chalk.default.cyan(" 1. Copy .env.example to .env"));
|
|
1249
|
-
console.log(import_chalk.default.gray(" cp .env.example .env"));
|
|
1250
|
-
console.log();
|
|
1251
|
-
console.log(import_chalk.default.cyan(" 2. Update JWT_SECRET in .env (or keep auto-generated)"));
|
|
1252
|
-
console.log();
|
|
1253
|
-
console.log(import_chalk.default.cyan(" 3. Create database migration (if using TypeORM)"));
|
|
1254
|
-
console.log(import_chalk.default.gray(" npm run migration:generate -- src/migrations/CreateUserTable"));
|
|
1255
|
-
console.log(import_chalk.default.gray(" npm run migration:run"));
|
|
1256
|
-
console.log();
|
|
1257
|
-
console.log(import_chalk.default.cyan(" 4. Start your NestJS app"));
|
|
1258
|
-
console.log(import_chalk.default.gray(" npm run start:dev"));
|
|
1259
|
-
console.log();
|
|
1260
|
-
console.log(import_chalk.default.cyan(" 5. Test authentication endpoints"));
|
|
1261
|
-
console.log(import_chalk.default.gray(" POST http://localhost:3000/auth/register"));
|
|
1262
|
-
console.log(import_chalk.default.gray(" POST http://localhost:3000/auth/login"));
|
|
1263
|
-
console.log(import_chalk.default.gray(" GET http://localhost:3000/users/profile (requires JWT)"));
|
|
1264
|
-
console.log();
|
|
1265
|
-
console.log(import_chalk.default.bold("\u{1F4D6} Full documentation:"), "src/auth/README.md");
|
|
1266
|
-
console.log();
|
|
1267
|
-
console.log(import_chalk.default.bold("\u{1F4A1} Tips:"));
|
|
1268
|
-
console.log(" \u2022 Use @Public() decorator for routes that don't require auth");
|
|
1269
|
-
console.log(" \u2022 Use @Roles('Admin') to restrict routes by role");
|
|
1270
|
-
console.log(" \u2022 Access current user with @CurrentUser() decorator");
|
|
1271
|
-
console.log();
|
|
1272
|
-
}
|
|
1273
|
-
function createSpinner(text) {
|
|
1274
|
-
return (0, import_ora.default)({
|
|
1275
|
-
text,
|
|
1276
|
-
color: "cyan"
|
|
1277
|
-
});
|
|
1278
|
-
}
|
|
1339
|
+
});
|
|
1279
1340
|
|
|
1280
1341
|
// src/index.ts
|
|
1281
|
-
|
|
1342
|
+
var index_exports = {};
|
|
1343
|
+
__export(index_exports, {
|
|
1344
|
+
run: () => run
|
|
1345
|
+
});
|
|
1346
|
+
async function run(cwd = process.cwd(), options = {}) {
|
|
1282
1347
|
showBanner();
|
|
1283
1348
|
const spinner = createSpinner("Analyzing project...").start();
|
|
1284
1349
|
const projectInfo = await detectProject(cwd);
|
|
@@ -1295,6 +1360,10 @@ async function run(cwd = process.cwd()) {
|
|
|
1295
1360
|
sourceRoot: projectInfo.sourceRoot
|
|
1296
1361
|
});
|
|
1297
1362
|
if (projectInfo.authExists) {
|
|
1363
|
+
if (options.yes) {
|
|
1364
|
+
console.log("\n auth/ directory already exists. Use interactive mode to overwrite.\n");
|
|
1365
|
+
process.exit(0);
|
|
1366
|
+
}
|
|
1298
1367
|
const inquirer2 = (await import("inquirer")).default;
|
|
1299
1368
|
const { overwrite } = await inquirer2.prompt([{
|
|
1300
1369
|
type: "confirm",
|
|
@@ -1307,7 +1376,7 @@ async function run(cwd = process.cwd()) {
|
|
|
1307
1376
|
process.exit(0);
|
|
1308
1377
|
}
|
|
1309
1378
|
}
|
|
1310
|
-
const answers = await promptConfig(projectInfo.orm, projectInfo.database);
|
|
1379
|
+
const answers = options.yes ? getDefaultAnswers(projectInfo.orm, projectInfo.database) : await promptConfig(projectInfo.orm, projectInfo.database);
|
|
1311
1380
|
const config = buildConfig(
|
|
1312
1381
|
answers,
|
|
1313
1382
|
projectInfo.root.split(/[/\\]/).pop() || "project",
|
|
@@ -1397,14 +1466,32 @@ async function run(cwd = process.cwd()) {
|
|
|
1397
1466
|
console.log("\u2B50 Like it? https://github.com/Islamawad132/add-nest-auth");
|
|
1398
1467
|
console.log();
|
|
1399
1468
|
}
|
|
1469
|
+
var init_index = __esm({
|
|
1470
|
+
"src/index.ts"() {
|
|
1471
|
+
"use strict";
|
|
1472
|
+
init_cjs_shims();
|
|
1473
|
+
init_analyzer();
|
|
1474
|
+
init_prompts();
|
|
1475
|
+
init_ui();
|
|
1476
|
+
}
|
|
1477
|
+
});
|
|
1400
1478
|
|
|
1401
1479
|
// src/cli.ts
|
|
1480
|
+
init_cjs_shims();
|
|
1481
|
+
var import_commander = require("commander");
|
|
1402
1482
|
process.on("unhandledRejection", (error) => {
|
|
1403
1483
|
console.error("Unhandled rejection:", error);
|
|
1404
1484
|
process.exit(1);
|
|
1405
1485
|
});
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1486
|
+
var program = new import_commander.Command();
|
|
1487
|
+
program.name("add-nest-auth").description("Add production-ready authentication to any NestJS project").version("1.1.0").option("-y, --yes", "Skip all prompts and use sensible defaults").action(async (options) => {
|
|
1488
|
+
try {
|
|
1489
|
+
const { run: run2 } = await Promise.resolve().then(() => (init_index(), index_exports));
|
|
1490
|
+
await run2(process.cwd(), { yes: options.yes || false });
|
|
1491
|
+
} catch (error) {
|
|
1492
|
+
console.error("Fatal error:", error);
|
|
1493
|
+
process.exit(1);
|
|
1494
|
+
}
|
|
1409
1495
|
});
|
|
1496
|
+
program.parse();
|
|
1410
1497
|
//# sourceMappingURL=cli.js.map
|