@gyxer-studio/generator 0.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.
Files changed (50) hide show
  1. package/README.md +63 -0
  2. package/dist/generators/app.generator.d.ts +19 -0
  3. package/dist/generators/app.generator.d.ts.map +1 -0
  4. package/dist/generators/app.generator.js +237 -0
  5. package/dist/generators/app.generator.js.map +1 -0
  6. package/dist/generators/controller.generator.d.ts +10 -0
  7. package/dist/generators/controller.generator.d.ts.map +1 -0
  8. package/dist/generators/controller.generator.js +88 -0
  9. package/dist/generators/controller.generator.js.map +1 -0
  10. package/dist/generators/docker.generator.d.ts +15 -0
  11. package/dist/generators/docker.generator.d.ts.map +1 -0
  12. package/dist/generators/docker.generator.js +82 -0
  13. package/dist/generators/docker.generator.js.map +1 -0
  14. package/dist/generators/dto.generator.d.ts +23 -0
  15. package/dist/generators/dto.generator.d.ts.map +1 -0
  16. package/dist/generators/dto.generator.js +271 -0
  17. package/dist/generators/dto.generator.js.map +1 -0
  18. package/dist/generators/module.generator.d.ts +6 -0
  19. package/dist/generators/module.generator.d.ts.map +1 -0
  20. package/dist/generators/module.generator.js +20 -0
  21. package/dist/generators/module.generator.js.map +1 -0
  22. package/dist/generators/prisma.generator.d.ts +6 -0
  23. package/dist/generators/prisma.generator.d.ts.map +1 -0
  24. package/dist/generators/prisma.generator.js +243 -0
  25. package/dist/generators/prisma.generator.js.map +1 -0
  26. package/dist/generators/service.generator.d.ts +6 -0
  27. package/dist/generators/service.generator.d.ts.map +1 -0
  28. package/dist/generators/service.generator.js +97 -0
  29. package/dist/generators/service.generator.js.map +1 -0
  30. package/dist/index.d.ts +14 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +16 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/modules/auth-jwt.generator.d.ts +20 -0
  35. package/dist/modules/auth-jwt.generator.d.ts.map +1 -0
  36. package/dist/modules/auth-jwt.generator.js +431 -0
  37. package/dist/modules/auth-jwt.generator.js.map +1 -0
  38. package/dist/project-generator.d.ts +16 -0
  39. package/dist/project-generator.d.ts.map +1 -0
  40. package/dist/project-generator.js +199 -0
  41. package/dist/project-generator.js.map +1 -0
  42. package/dist/security/report.d.ts +24 -0
  43. package/dist/security/report.d.ts.map +1 -0
  44. package/dist/security/report.js +108 -0
  45. package/dist/security/report.js.map +1 -0
  46. package/dist/utils.d.ts +16 -0
  47. package/dist/utils.d.ts.map +1 -0
  48. package/dist/utils.js +44 -0
  49. package/dist/utils.js.map +1 -0
  50. package/package.json +58 -0
@@ -0,0 +1,97 @@
1
+ import { toCamelCase, toKebabCase } from '../utils.js';
2
+ /**
3
+ * Generate a NestJS service for an entity with full CRUD.
4
+ */
5
+ export function generateService(entity, project) {
6
+ const name = entity.name;
7
+ const camel = toCamelCase(name);
8
+ const className = `${name}Service`;
9
+ const hasAuthJwt = name === 'User' &&
10
+ project.modules?.some((m) => m.name === 'auth-jwt' && m.enabled !== false);
11
+ // User + auth-jwt: create method hashes password
12
+ if (hasAuthJwt) {
13
+ return `import { Injectable, NotFoundException } from '@nestjs/common';
14
+ import * as bcrypt from 'bcrypt';
15
+ import { Prisma } from '@prisma/client';
16
+ import { PrismaService } from '../prisma/prisma.service';
17
+ import { Create${name}Dto } from './dto/create-${toKebabCase(name)}.dto';
18
+ import { Update${name}Dto } from './dto/update-${toKebabCase(name)}.dto';
19
+
20
+ @Injectable()
21
+ export class ${className} {
22
+ constructor(private readonly prisma: PrismaService) {}
23
+
24
+ async create(dto: Create${name}Dto) {
25
+ const { password, ...rest } = dto;
26
+ const passwordHash = await bcrypt.hash(password, 12);
27
+ return this.prisma.${camel}.create({ data: { ...rest, passwordHash } as Prisma.${name}UncheckedCreateInput });
28
+ }
29
+
30
+ async findAll() {
31
+ return this.prisma.${camel}.findMany({
32
+ select: { id: true, email: true, name: true, createdAt: true, updatedAt: true },
33
+ });
34
+ }
35
+
36
+ async findOne(id: number) {
37
+ const ${camel} = await this.prisma.${camel}.findUnique({
38
+ where: { id },
39
+ select: { id: true, email: true, name: true, createdAt: true, updatedAt: true },
40
+ });
41
+ if (!${camel}) {
42
+ throw new NotFoundException(\`${name} with id \${id} not found\`);
43
+ }
44
+ return ${camel};
45
+ }
46
+
47
+ async update(id: number, data: Update${name}Dto) {
48
+ await this.findOne(id);
49
+ return this.prisma.${camel}.update({ where: { id }, data: data as Prisma.${name}UncheckedUpdateInput });
50
+ }
51
+
52
+ async remove(id: number) {
53
+ await this.findOne(id);
54
+ return this.prisma.${camel}.delete({ where: { id } });
55
+ }
56
+ }
57
+ `;
58
+ }
59
+ return `import { Injectable, NotFoundException } from '@nestjs/common';
60
+ import { Prisma } from '@prisma/client';
61
+ import { PrismaService } from '../prisma/prisma.service';
62
+ import { Create${name}Dto } from './dto/create-${toKebabCase(name)}.dto';
63
+ import { Update${name}Dto } from './dto/update-${toKebabCase(name)}.dto';
64
+
65
+ @Injectable()
66
+ export class ${className} {
67
+ constructor(private readonly prisma: PrismaService) {}
68
+
69
+ async create(data: Create${name}Dto) {
70
+ return this.prisma.${camel}.create({ data: data as Prisma.${name}UncheckedCreateInput });
71
+ }
72
+
73
+ async findAll() {
74
+ return this.prisma.${camel}.findMany();
75
+ }
76
+
77
+ async findOne(id: number) {
78
+ const ${camel} = await this.prisma.${camel}.findUnique({ where: { id } });
79
+ if (!${camel}) {
80
+ throw new NotFoundException(\`${name} with id \${id} not found\`);
81
+ }
82
+ return ${camel};
83
+ }
84
+
85
+ async update(id: number, data: Update${name}Dto) {
86
+ await this.findOne(id);
87
+ return this.prisma.${camel}.update({ where: { id }, data: data as Prisma.${name}UncheckedUpdateInput });
88
+ }
89
+
90
+ async remove(id: number) {
91
+ await this.findOne(id);
92
+ return this.prisma.${camel}.delete({ where: { id } });
93
+ }
94
+ }
95
+ `;
96
+ }
97
+ //# sourceMappingURL=service.generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.generator.js","sourceRoot":"","sources":["../../src/generators/service.generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEvD;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,OAAqB;IACnE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IACzB,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,SAAS,GAAG,GAAG,IAAI,SAAS,CAAC;IAEnC,MAAM,UAAU,GACd,IAAI,KAAK,MAAM;QACf,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,IAAI,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC;IAE7E,iDAAiD;IACjD,IAAI,UAAU,EAAE,CAAC;QACf,OAAO;;;;iBAIM,IAAI,4BAA4B,WAAW,CAAC,IAAI,CAAC;iBACjD,IAAI,4BAA4B,WAAW,CAAC,IAAI,CAAC;;;eAGnD,SAAS;;;4BAGI,IAAI;;;yBAGP,KAAK,uDAAuD,IAAI;;;;yBAIhE,KAAK;;;;;;YAMlB,KAAK,wBAAwB,KAAK;;;;WAInC,KAAK;sCACsB,IAAI;;aAE7B,KAAK;;;yCAGuB,IAAI;;yBAEpB,KAAK,iDAAiD,IAAI;;;;;yBAK1D,KAAK;;;CAG7B,CAAC;IACA,CAAC;IAED,OAAO;;;iBAGQ,IAAI,4BAA4B,WAAW,CAAC,IAAI,CAAC;iBACjD,IAAI,4BAA4B,WAAW,CAAC,IAAI,CAAC;;;eAGnD,SAAS;;;6BAGK,IAAI;yBACR,KAAK,kCAAkC,IAAI;;;;yBAI3C,KAAK;;;;YAIlB,KAAK,wBAAwB,KAAK;WACnC,KAAK;sCACsB,IAAI;;aAE7B,KAAK;;;yCAGuB,IAAI;;yBAEpB,KAAK,iDAAiD,IAAI;;;;;yBAK1D,KAAK;;;CAG7B,CAAC;AACF,CAAC"}
@@ -0,0 +1,14 @@
1
+ export { generateProject } from './project-generator.js';
2
+ export type { GenerateOptions, GenerateResult } from './project-generator.js';
3
+ export { generatePrismaSchema } from './generators/prisma.generator.js';
4
+ export { generateCreateDto, generateUpdateDto } from './generators/dto.generator.js';
5
+ export { generateService } from './generators/service.generator.js';
6
+ export { generateController } from './generators/controller.generator.js';
7
+ export { generateModule } from './generators/module.generator.js';
8
+ export { generateMain, generateAppModule, generatePrismaService, generatePrismaModule, generatePrismaExceptionFilter, } from './generators/app.generator.js';
9
+ export { generateDockerfile, generateDockerCompose, generateEnvFile, generateEnvExample, } from './generators/docker.generator.js';
10
+ export { generateAuthJwtFiles } from './modules/auth-jwt.generator.js';
11
+ export { generateSecurityReport, formatSecurityReport } from './security/report.js';
12
+ export type { SecurityCheck, SecurityReport } from './security/report.js';
13
+ export { toKebabCase, toCamelCase, toSnakeCase, pluralize } from './utils.js';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAG9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACrF,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,6BAA6B,GAC9B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,EACf,kBAAkB,GACnB,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAGvE,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACpF,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG1E,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ export { generateProject } from './project-generator.js';
2
+ // Individual generators (for advanced usage)
3
+ export { generatePrismaSchema } from './generators/prisma.generator.js';
4
+ export { generateCreateDto, generateUpdateDto } from './generators/dto.generator.js';
5
+ export { generateService } from './generators/service.generator.js';
6
+ export { generateController } from './generators/controller.generator.js';
7
+ export { generateModule } from './generators/module.generator.js';
8
+ export { generateMain, generateAppModule, generatePrismaService, generatePrismaModule, generatePrismaExceptionFilter, } from './generators/app.generator.js';
9
+ export { generateDockerfile, generateDockerCompose, generateEnvFile, generateEnvExample, } from './generators/docker.generator.js';
10
+ // Modules
11
+ export { generateAuthJwtFiles } from './modules/auth-jwt.generator.js';
12
+ // Security
13
+ export { generateSecurityReport, formatSecurityReport } from './security/report.js';
14
+ // Utils
15
+ export { toKebabCase, toCamelCase, toSnakeCase, pluralize } from './utils.js';
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,6CAA6C;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACrF,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,6BAA6B,GAC9B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,EACf,kBAAkB,GACnB,MAAM,kCAAkC,CAAC;AAE1C,UAAU;AACV,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAEvE,WAAW;AACX,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAGpF,QAAQ;AACR,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { GyxerProject } from '@gyxer-studio/schema';
2
+ /**
3
+ * Generate all files needed for JWT authentication module.
4
+ */
5
+ export declare function generateAuthJwtFiles(project: GyxerProject): Map<string, string>;
6
+ /**
7
+ * Returns the additional Prisma fields that need to be added to the User model
8
+ * when auth-jwt module is enabled.
9
+ */
10
+ export declare function getAuthPrismaFields(): string;
11
+ /**
12
+ * Returns additional env variables needed for auth-jwt.
13
+ */
14
+ export declare function getAuthEnvVars(): string;
15
+ /**
16
+ * Returns additional npm dependencies for auth-jwt.
17
+ */
18
+ export declare function getAuthDependencies(): Record<string, string>;
19
+ export declare function getAuthDevDependencies(): Record<string, string>;
20
+ //# sourceMappingURL=auth-jwt.generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-jwt.generator.d.ts","sourceRoot":"","sources":["../../src/modules/auth-jwt.generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAuB/E;AA0YD;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAMvC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQ5D;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAK/D"}
@@ -0,0 +1,431 @@
1
+ /**
2
+ * Generate all files needed for JWT authentication module.
3
+ */
4
+ export function generateAuthJwtFiles(project) {
5
+ const files = new Map();
6
+ // Auth module
7
+ files.set('src/auth/auth.module.ts', generateAuthModule());
8
+ files.set('src/auth/auth.service.ts', generateAuthService());
9
+ files.set('src/auth/auth.controller.ts', generateAuthController());
10
+ // DTOs
11
+ files.set('src/auth/dto/register.dto.ts', generateRegisterDto());
12
+ files.set('src/auth/dto/login.dto.ts', generateLoginDto());
13
+ files.set('src/auth/dto/auth-response.dto.ts', generateAuthResponseDto());
14
+ files.set('src/auth/dto/refresh-token.dto.ts', generateRefreshTokenDto());
15
+ // JWT strategy & guard
16
+ files.set('src/auth/strategies/jwt.strategy.ts', generateJwtStrategy());
17
+ files.set('src/auth/guards/jwt-auth.guard.ts', generateJwtAuthGuard());
18
+ // Decorators
19
+ files.set('src/auth/decorators/current-user.decorator.ts', generateCurrentUserDecorator());
20
+ files.set('src/auth/decorators/public.decorator.ts', generatePublicDecorator());
21
+ return files;
22
+ }
23
+ // ─── Auth Module ────────────────────────────────────────────
24
+ function generateAuthModule() {
25
+ return `import { Module } from '@nestjs/common';
26
+ import { JwtModule } from '@nestjs/jwt';
27
+ import { PassportModule } from '@nestjs/passport';
28
+ import { AuthService } from './auth.service';
29
+ import { AuthController } from './auth.controller';
30
+ import { JwtStrategy } from './strategies/jwt.strategy';
31
+
32
+ @Module({
33
+ imports: [
34
+ PassportModule.register({ defaultStrategy: 'jwt' }),
35
+ JwtModule.register({
36
+ secret: process.env.JWT_SECRET || 'change-me-in-production',
37
+ signOptions: { expiresIn: process.env.JWT_EXPIRES_IN || '15m' },
38
+ }),
39
+ ],
40
+ controllers: [AuthController],
41
+ providers: [AuthService, JwtStrategy],
42
+ exports: [AuthService],
43
+ })
44
+ export class AuthModule {}
45
+ `;
46
+ }
47
+ // ─── Auth Service ───────────────────────────────────────────
48
+ function generateAuthService() {
49
+ return `import {
50
+ Injectable,
51
+ UnauthorizedException,
52
+ ConflictException,
53
+ } from '@nestjs/common';
54
+ import { JwtService } from '@nestjs/jwt';
55
+ import * as bcrypt from 'bcrypt';
56
+ import { PrismaService } from '../prisma/prisma.service';
57
+
58
+ interface JwtPayload {
59
+ sub: number;
60
+ email: string;
61
+ }
62
+
63
+ @Injectable()
64
+ export class AuthService {
65
+ constructor(
66
+ private readonly prisma: PrismaService,
67
+ private readonly jwtService: JwtService,
68
+ ) {}
69
+
70
+ async register(email: string, password: string, name: string) {
71
+ // Check if user already exists
72
+ const existing = await this.prisma.user.findUnique({ where: { email } });
73
+ if (existing) {
74
+ throw new ConflictException('User with this email already exists');
75
+ }
76
+
77
+ // Hash password
78
+ const passwordHash = await bcrypt.hash(password, 12);
79
+
80
+ // Create user
81
+ const user = await this.prisma.user.create({
82
+ data: { email, name, passwordHash },
83
+ });
84
+
85
+ return this.generateTokens(user.id, user.email);
86
+ }
87
+
88
+ async login(email: string, password: string) {
89
+ const user = await this.prisma.user.findUnique({ where: { email } });
90
+ if (!user) {
91
+ throw new UnauthorizedException('Invalid credentials');
92
+ }
93
+
94
+ const isPasswordValid = await bcrypt.compare(password, user.passwordHash);
95
+ if (!isPasswordValid) {
96
+ throw new UnauthorizedException('Invalid credentials');
97
+ }
98
+
99
+ return this.generateTokens(user.id, user.email);
100
+ }
101
+
102
+ async refreshToken(refreshToken: string) {
103
+ try {
104
+ const payload = this.jwtService.verify<JwtPayload>(refreshToken, {
105
+ secret: process.env.JWT_REFRESH_SECRET || 'change-me-refresh-secret',
106
+ });
107
+
108
+ const user = await this.prisma.user.findUnique({
109
+ where: { id: payload.sub },
110
+ });
111
+
112
+ if (!user) {
113
+ throw new UnauthorizedException('User not found');
114
+ }
115
+
116
+ return this.generateTokens(user.id, user.email);
117
+ } catch {
118
+ throw new UnauthorizedException('Invalid refresh token');
119
+ }
120
+ }
121
+
122
+ async getProfile(userId: number) {
123
+ const user = await this.prisma.user.findUnique({
124
+ where: { id: userId },
125
+ select: {
126
+ id: true,
127
+ email: true,
128
+ name: true,
129
+ createdAt: true,
130
+ updatedAt: true,
131
+ },
132
+ });
133
+
134
+ if (!user) {
135
+ throw new UnauthorizedException('User not found');
136
+ }
137
+
138
+ return user;
139
+ }
140
+
141
+ private generateTokens(userId: number, email: string) {
142
+ const payload: JwtPayload = { sub: userId, email };
143
+
144
+ const accessToken = this.jwtService.sign(payload);
145
+ const refreshToken = this.jwtService.sign(payload, {
146
+ secret: process.env.JWT_REFRESH_SECRET || 'change-me-refresh-secret',
147
+ expiresIn: process.env.JWT_REFRESH_EXPIRES_IN || '7d',
148
+ });
149
+
150
+ return { accessToken, refreshToken };
151
+ }
152
+ }
153
+ `;
154
+ }
155
+ // ─── Auth Controller ────────────────────────────────────────
156
+ function generateAuthController() {
157
+ return `import {
158
+ Controller,
159
+ Post,
160
+ Get,
161
+ Body,
162
+ UseGuards,
163
+ HttpCode,
164
+ HttpStatus,
165
+ } from '@nestjs/common';
166
+ import {
167
+ ApiTags,
168
+ ApiOperation,
169
+ ApiResponse,
170
+ ApiBearerAuth,
171
+ } from '@nestjs/swagger';
172
+ import { AuthService } from './auth.service';
173
+ import { RegisterDto } from './dto/register.dto';
174
+ import { LoginDto } from './dto/login.dto';
175
+ import { RefreshTokenDto } from './dto/refresh-token.dto';
176
+ import { AuthResponseDto } from './dto/auth-response.dto';
177
+ import { JwtAuthGuard } from './guards/jwt-auth.guard';
178
+ import { CurrentUser } from './decorators/current-user.decorator';
179
+ import { Public } from './decorators/public.decorator';
180
+
181
+ @ApiTags('auth')
182
+ @Controller('auth')
183
+ export class AuthController {
184
+ constructor(private readonly authService: AuthService) {}
185
+
186
+ @Public()
187
+ @Post('register')
188
+ @ApiOperation({ summary: 'Register a new user' })
189
+ @ApiResponse({ status: 201, description: 'User registered', type: AuthResponseDto })
190
+ @ApiResponse({ status: 409, description: 'Email already taken' })
191
+ async register(@Body() dto: RegisterDto) {
192
+ return this.authService.register(dto.email, dto.password, dto.name);
193
+ }
194
+
195
+ @Public()
196
+ @Post('login')
197
+ @HttpCode(HttpStatus.OK)
198
+ @ApiOperation({ summary: 'Login with email and password' })
199
+ @ApiResponse({ status: 200, description: 'Login successful', type: AuthResponseDto })
200
+ @ApiResponse({ status: 401, description: 'Invalid credentials' })
201
+ async login(@Body() dto: LoginDto) {
202
+ return this.authService.login(dto.email, dto.password);
203
+ }
204
+
205
+ @Public()
206
+ @Post('refresh')
207
+ @HttpCode(HttpStatus.OK)
208
+ @ApiOperation({ summary: 'Refresh access token' })
209
+ @ApiResponse({ status: 200, description: 'Tokens refreshed', type: AuthResponseDto })
210
+ @ApiResponse({ status: 401, description: 'Invalid refresh token' })
211
+ async refresh(@Body() dto: RefreshTokenDto) {
212
+ return this.authService.refreshToken(dto.refreshToken);
213
+ }
214
+
215
+ @Get('profile')
216
+ @UseGuards(JwtAuthGuard)
217
+ @ApiBearerAuth()
218
+ @ApiOperation({ summary: 'Get current user profile' })
219
+ @ApiResponse({ status: 200, description: 'User profile' })
220
+ @ApiResponse({ status: 401, description: 'Unauthorized' })
221
+ async getProfile(@CurrentUser('sub') userId: number) {
222
+ return this.authService.getProfile(userId);
223
+ }
224
+ }
225
+ `;
226
+ }
227
+ // ─── DTOs ───────────────────────────────────────────────────
228
+ function generateRegisterDto() {
229
+ return `import { ApiProperty } from '@nestjs/swagger';
230
+ import { IsEmail, IsString, IsNotEmpty, MinLength } from 'class-validator';
231
+
232
+ export class RegisterDto {
233
+ @ApiProperty({ example: 'user@example.com' })
234
+ @IsEmail()
235
+ email: string;
236
+
237
+ @ApiProperty({ example: 'strongPassword123' })
238
+ @IsString()
239
+ @MinLength(8)
240
+ password: string;
241
+
242
+ @ApiProperty({ example: 'John Doe' })
243
+ @IsString()
244
+ @IsNotEmpty()
245
+ name: string;
246
+ }
247
+ `;
248
+ }
249
+ function generateLoginDto() {
250
+ return `import { ApiProperty } from '@nestjs/swagger';
251
+ import { IsEmail, IsString, IsNotEmpty } from 'class-validator';
252
+
253
+ export class LoginDto {
254
+ @ApiProperty({ example: 'user@example.com' })
255
+ @IsEmail()
256
+ email: string;
257
+
258
+ @ApiProperty({ example: 'strongPassword123' })
259
+ @IsString()
260
+ @IsNotEmpty()
261
+ password: string;
262
+ }
263
+ `;
264
+ }
265
+ function generateAuthResponseDto() {
266
+ return `import { ApiProperty } from '@nestjs/swagger';
267
+
268
+ export class AuthResponseDto {
269
+ @ApiProperty({ description: 'JWT access token (short-lived)' })
270
+ accessToken: string;
271
+
272
+ @ApiProperty({ description: 'JWT refresh token (long-lived)' })
273
+ refreshToken: string;
274
+ }
275
+ `;
276
+ }
277
+ function generateRefreshTokenDto() {
278
+ return `import { ApiProperty } from '@nestjs/swagger';
279
+ import { IsString, IsNotEmpty } from 'class-validator';
280
+
281
+ export class RefreshTokenDto {
282
+ @ApiProperty({ description: 'Refresh token from login/register response' })
283
+ @IsString()
284
+ @IsNotEmpty()
285
+ refreshToken: string;
286
+ }
287
+ `;
288
+ }
289
+ // ─── JWT Strategy ───────────────────────────────────────────
290
+ function generateJwtStrategy() {
291
+ return `import { Injectable, UnauthorizedException } from '@nestjs/common';
292
+ import { PassportStrategy } from '@nestjs/passport';
293
+ import { ExtractJwt, Strategy } from 'passport-jwt';
294
+ import { PrismaService } from '../../prisma/prisma.service';
295
+
296
+ interface JwtPayload {
297
+ sub: number;
298
+ email: string;
299
+ }
300
+
301
+ @Injectable()
302
+ export class JwtStrategy extends PassportStrategy(Strategy) {
303
+ constructor(private readonly prisma: PrismaService) {
304
+ super({
305
+ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
306
+ ignoreExpiration: false,
307
+ secretOrKey: process.env.JWT_SECRET || 'change-me-in-production',
308
+ });
309
+ }
310
+
311
+ async validate(payload: JwtPayload) {
312
+ const user = await this.prisma.user.findUnique({
313
+ where: { id: payload.sub },
314
+ });
315
+
316
+ if (!user) {
317
+ throw new UnauthorizedException('User not found');
318
+ }
319
+
320
+ return { sub: user.id, email: user.email };
321
+ }
322
+ }
323
+ `;
324
+ }
325
+ // ─── Guards ─────────────────────────────────────────────────
326
+ function generateJwtAuthGuard() {
327
+ return `import { Injectable, ExecutionContext } from '@nestjs/common';
328
+ import { AuthGuard } from '@nestjs/passport';
329
+ import { Reflector } from '@nestjs/core';
330
+ import { IS_PUBLIC_KEY } from '../decorators/public.decorator';
331
+
332
+ @Injectable()
333
+ export class JwtAuthGuard extends AuthGuard('jwt') {
334
+ constructor(private reflector: Reflector) {
335
+ super();
336
+ }
337
+
338
+ canActivate(context: ExecutionContext) {
339
+ const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
340
+ context.getHandler(),
341
+ context.getClass(),
342
+ ]);
343
+
344
+ if (isPublic) {
345
+ return true;
346
+ }
347
+
348
+ return super.canActivate(context);
349
+ }
350
+ }
351
+ `;
352
+ }
353
+ // ─── Decorators ─────────────────────────────────────────────
354
+ function generateCurrentUserDecorator() {
355
+ return `import { createParamDecorator, ExecutionContext } from '@nestjs/common';
356
+
357
+ /**
358
+ * Extract the current authenticated user from the request.
359
+ *
360
+ * Usage:
361
+ * @CurrentUser() user — full user payload { sub, email }
362
+ * @CurrentUser('sub') userId — just the user ID
363
+ * @CurrentUser('email') email — just the email
364
+ */
365
+ export const CurrentUser = createParamDecorator(
366
+ (data: string | undefined, ctx: ExecutionContext) => {
367
+ const request = ctx.switchToHttp().getRequest();
368
+ const user = request.user;
369
+
370
+ if (data) {
371
+ return user?.[data];
372
+ }
373
+
374
+ return user;
375
+ },
376
+ );
377
+ `;
378
+ }
379
+ function generatePublicDecorator() {
380
+ return `import { SetMetadata } from '@nestjs/common';
381
+
382
+ export const IS_PUBLIC_KEY = 'isPublic';
383
+
384
+ /**
385
+ * Mark an endpoint as public (no JWT required).
386
+ *
387
+ * Usage:
388
+ * @Public()
389
+ * @Get('health')
390
+ * healthCheck() { ... }
391
+ */
392
+ export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
393
+ `;
394
+ }
395
+ // ─── Extra Prisma fields for User entity when auth is enabled ──
396
+ /**
397
+ * Returns the additional Prisma fields that need to be added to the User model
398
+ * when auth-jwt module is enabled.
399
+ */
400
+ export function getAuthPrismaFields() {
401
+ return ` passwordHash String @map("password_hash")`;
402
+ }
403
+ /**
404
+ * Returns additional env variables needed for auth-jwt.
405
+ */
406
+ export function getAuthEnvVars() {
407
+ return `JWT_SECRET=change-me-in-production
408
+ JWT_EXPIRES_IN=15m
409
+ JWT_REFRESH_SECRET=change-me-refresh-secret
410
+ JWT_REFRESH_EXPIRES_IN=7d
411
+ `;
412
+ }
413
+ /**
414
+ * Returns additional npm dependencies for auth-jwt.
415
+ */
416
+ export function getAuthDependencies() {
417
+ return {
418
+ '@nestjs/jwt': '^10.2.0',
419
+ '@nestjs/passport': '^10.0.0',
420
+ 'passport': '^0.7.0',
421
+ 'passport-jwt': '^4.0.1',
422
+ 'bcrypt': '^5.1.0',
423
+ };
424
+ }
425
+ export function getAuthDevDependencies() {
426
+ return {
427
+ '@types/passport-jwt': '^4.0.0',
428
+ '@types/bcrypt': '^5.0.0',
429
+ };
430
+ }
431
+ //# sourceMappingURL=auth-jwt.generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-jwt.generator.js","sourceRoot":"","sources":["../../src/modules/auth-jwt.generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { GyxerProject } from '@gyxer-studio/schema';
2
+ import type { SecurityReport } from './security/report.js';
3
+ export interface GenerateOptions {
4
+ outputDir: string;
5
+ silent?: boolean;
6
+ }
7
+ export interface GenerateResult {
8
+ outputDir: string;
9
+ filesCreated: string[];
10
+ securityReport: SecurityReport;
11
+ }
12
+ /**
13
+ * Generate a complete NestJS project from a GyxerProject schema.
14
+ */
15
+ export declare function generateProject(project: GyxerProject, options: GenerateOptions): Promise<GenerateResult>;
16
+ //# sourceMappingURL=project-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-generator.d.ts","sourceRoot":"","sources":["../src/project-generator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAqBzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAQ3D,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,EAAE,cAAc,CAAC;CAChC;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,CAAC,CA4KzB"}