nestforge-generator 0.3.0 → 0.4.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 (135) hide show
  1. package/README.md +13 -1
  2. package/README.pt-BR.md +13 -1
  3. package/dist/features/auth-strategy.js +7 -7
  4. package/dist/features/dependencies.js +3 -3
  5. package/dist/features/language.js +1 -1
  6. package/dist/features/language.js.map +1 -1
  7. package/dist/features/markers.js +11 -11
  8. package/dist/features/markers.js.map +1 -1
  9. package/dist/generator.js +7 -1
  10. package/dist/generator.js.map +1 -1
  11. package/dist/project-name.js +50 -0
  12. package/dist/project-name.js.map +1 -0
  13. package/dist/prompts.js +12 -10
  14. package/dist/prompts.js.map +1 -1
  15. package/package.json +1 -1
  16. package/templates/drizzle/drizzle.config.ts +2 -2
  17. package/templates/drizzle/src/auth/auth.controller.ts +35 -35
  18. package/templates/drizzle/src/auth/auth.service.spec.ts +4 -4
  19. package/templates/drizzle/src/auth/auth.service.ts +9 -9
  20. package/templates/drizzle/src/auth/dto/forgot-password.dto.ts +2 -2
  21. package/templates/drizzle/src/auth/dto/login.dto.ts +3 -3
  22. package/templates/drizzle/src/auth/dto/register.dto.ts +4 -4
  23. package/templates/drizzle/src/auth/dto/reset-password.dto.ts +3 -3
  24. package/templates/drizzle/src/auth/guards/github-auth.guard.ts +2 -2
  25. package/templates/drizzle/src/auth/guards/google-auth.guard.ts +2 -2
  26. package/templates/drizzle/src/auth/guards/session-auth.guard.spec.ts +4 -4
  27. package/templates/drizzle/src/auth/guards/session-auth.guard.ts +2 -2
  28. package/templates/drizzle/src/auth/session.service.spec.ts +5 -5
  29. package/templates/drizzle/src/auth/session.service.ts +5 -5
  30. package/templates/drizzle/src/auth/strategies/github.strategy.ts +3 -3
  31. package/templates/drizzle/src/auth/token.service.ts +3 -3
  32. package/templates/drizzle/src/common/filters/http-exception.filter.ts +1 -1
  33. package/templates/drizzle/src/common/guards/permissions.guard.spec.ts +7 -7
  34. package/templates/drizzle/src/common/guards/roles.guard.spec.ts +4 -4
  35. package/templates/drizzle/src/common/middleware/csrf.middleware.spec.ts +5 -5
  36. package/templates/drizzle/src/common/middleware/csrf.middleware.ts +2 -2
  37. package/templates/drizzle/src/common/utils/avatar-storage.util.ts +2 -2
  38. package/templates/drizzle/src/config/env.validation.ts +1 -1
  39. package/templates/drizzle/src/database/seed.ts +4 -4
  40. package/templates/drizzle/src/health/health.controller.ts +2 -2
  41. package/templates/drizzle/src/health/indicators/drizzle-health.indicator.spec.ts +5 -5
  42. package/templates/drizzle/src/health/indicators/drizzle-health.indicator.ts +2 -2
  43. package/templates/drizzle/src/health/indicators/redis-health.indicator.spec.ts +5 -5
  44. package/templates/drizzle/src/health/indicators/redis-health.indicator.ts +3 -3
  45. package/templates/drizzle/src/mail/mail.processor.ts +4 -4
  46. package/templates/drizzle/src/mail/templates/email-templates.ts +7 -7
  47. package/templates/drizzle/src/metrics/metrics.service.ts +3 -3
  48. package/templates/drizzle/src/users/dto/create-user.dto.ts +5 -5
  49. package/templates/drizzle/src/users/dto/find-users-query.dto.ts +3 -3
  50. package/templates/drizzle/src/users/users.controller.ts +21 -21
  51. package/templates/drizzle/src/users/users.service.spec.ts +12 -12
  52. package/templates/drizzle/src/users/users.service.ts +4 -4
  53. package/templates/drizzle/test/auth.e2e-spec.ts +8 -8
  54. package/templates/drizzle/test/session-auth.e2e-spec.ts +9 -9
  55. package/templates/drizzle/test/users.e2e-spec.ts +18 -18
  56. package/templates/prisma/prisma/seed.ts +46 -46
  57. package/templates/prisma/src/auth/auth.controller.ts +35 -35
  58. package/templates/prisma/src/auth/auth.service.spec.ts +3 -3
  59. package/templates/prisma/src/auth/auth.service.ts +11 -11
  60. package/templates/prisma/src/auth/dto/forgot-password.dto.ts +2 -2
  61. package/templates/prisma/src/auth/dto/login.dto.ts +3 -3
  62. package/templates/prisma/src/auth/dto/register.dto.ts +4 -4
  63. package/templates/prisma/src/auth/dto/reset-password.dto.ts +3 -3
  64. package/templates/prisma/src/auth/guards/github-auth.guard.ts +10 -10
  65. package/templates/prisma/src/auth/guards/google-auth.guard.ts +10 -10
  66. package/templates/prisma/src/auth/guards/session-auth.guard.spec.ts +4 -4
  67. package/templates/prisma/src/auth/guards/session-auth.guard.ts +2 -2
  68. package/templates/prisma/src/auth/session.service.spec.ts +5 -5
  69. package/templates/prisma/src/auth/session.service.ts +5 -5
  70. package/templates/prisma/src/auth/strategies/github.strategy.ts +3 -3
  71. package/templates/prisma/src/auth/token.service.ts +2 -2
  72. package/templates/prisma/src/common/filters/http-exception.filter.ts +34 -34
  73. package/templates/prisma/src/common/guards/permissions.guard.spec.ts +7 -7
  74. package/templates/prisma/src/common/guards/roles.guard.spec.ts +4 -4
  75. package/templates/prisma/src/common/middleware/csrf.middleware.spec.ts +5 -5
  76. package/templates/prisma/src/common/middleware/csrf.middleware.ts +2 -2
  77. package/templates/prisma/src/common/utils/avatar-storage.util.ts +32 -32
  78. package/templates/prisma/src/config/env.validation.ts +1 -1
  79. package/templates/prisma/src/health/health.controller.ts +2 -2
  80. package/templates/prisma/src/health/indicators/prisma-health.indicator.spec.ts +4 -4
  81. package/templates/prisma/src/health/indicators/prisma-health.indicator.ts +1 -1
  82. package/templates/prisma/src/health/indicators/redis-health.indicator.spec.ts +5 -5
  83. package/templates/prisma/src/health/indicators/redis-health.indicator.ts +3 -3
  84. package/templates/prisma/src/mail/mail.processor.ts +4 -4
  85. package/templates/prisma/src/mail/templates/email-templates.ts +7 -7
  86. package/templates/prisma/src/metrics/metrics.service.ts +34 -34
  87. package/templates/prisma/src/users/dto/create-user.dto.ts +12 -12
  88. package/templates/prisma/src/users/dto/find-users-query.dto.ts +12 -12
  89. package/templates/prisma/src/users/users.controller.ts +21 -21
  90. package/templates/prisma/src/users/users.service.spec.ts +11 -11
  91. package/templates/prisma/src/users/users.service.ts +4 -4
  92. package/templates/prisma/test/auth.e2e-spec.ts +8 -8
  93. package/templates/prisma/test/session-auth.e2e-spec.ts +9 -9
  94. package/templates/prisma/test/users.e2e-spec.ts +14 -14
  95. package/templates/typeorm/src/auth/auth.controller.ts +35 -35
  96. package/templates/typeorm/src/auth/auth.service.spec.ts +4 -4
  97. package/templates/typeorm/src/auth/auth.service.ts +9 -9
  98. package/templates/typeorm/src/auth/dto/forgot-password.dto.ts +2 -2
  99. package/templates/typeorm/src/auth/dto/login.dto.ts +3 -3
  100. package/templates/typeorm/src/auth/dto/register.dto.ts +4 -4
  101. package/templates/typeorm/src/auth/dto/reset-password.dto.ts +3 -3
  102. package/templates/typeorm/src/auth/guards/github-auth.guard.ts +2 -2
  103. package/templates/typeorm/src/auth/guards/google-auth.guard.ts +2 -2
  104. package/templates/typeorm/src/auth/guards/session-auth.guard.spec.ts +4 -4
  105. package/templates/typeorm/src/auth/guards/session-auth.guard.ts +2 -2
  106. package/templates/typeorm/src/auth/session.service.spec.ts +5 -5
  107. package/templates/typeorm/src/auth/session.service.ts +5 -5
  108. package/templates/typeorm/src/auth/strategies/github.strategy.ts +3 -3
  109. package/templates/typeorm/src/auth/token.service.ts +3 -3
  110. package/templates/typeorm/src/common/filters/http-exception.filter.ts +1 -1
  111. package/templates/typeorm/src/common/guards/permissions.guard.spec.ts +7 -7
  112. package/templates/typeorm/src/common/guards/roles.guard.spec.ts +4 -4
  113. package/templates/typeorm/src/common/middleware/csrf.middleware.spec.ts +5 -5
  114. package/templates/typeorm/src/common/middleware/csrf.middleware.ts +2 -2
  115. package/templates/typeorm/src/common/utils/avatar-storage.util.ts +2 -2
  116. package/templates/typeorm/src/config/env.validation.ts +1 -1
  117. package/templates/typeorm/src/database/data-source.ts +2 -2
  118. package/templates/typeorm/src/database/seed.ts +3 -3
  119. package/templates/typeorm/src/database/typeorm-options.ts +2 -2
  120. package/templates/typeorm/src/health/health.controller.ts +2 -2
  121. package/templates/typeorm/src/health/indicators/redis-health.indicator.spec.ts +5 -5
  122. package/templates/typeorm/src/health/indicators/redis-health.indicator.ts +3 -3
  123. package/templates/typeorm/src/health/indicators/typeorm-health.indicator.spec.ts +4 -4
  124. package/templates/typeorm/src/health/indicators/typeorm-health.indicator.ts +2 -2
  125. package/templates/typeorm/src/mail/mail.processor.ts +4 -4
  126. package/templates/typeorm/src/mail/templates/email-templates.ts +7 -7
  127. package/templates/typeorm/src/metrics/metrics.service.ts +3 -3
  128. package/templates/typeorm/src/users/dto/create-user.dto.ts +5 -5
  129. package/templates/typeorm/src/users/dto/find-users-query.dto.ts +3 -3
  130. package/templates/typeorm/src/users/users.controller.ts +21 -21
  131. package/templates/typeorm/src/users/users.service.spec.ts +12 -12
  132. package/templates/typeorm/src/users/users.service.ts +4 -4
  133. package/templates/typeorm/test/auth.e2e-spec.ts +8 -8
  134. package/templates/typeorm/test/session-auth.e2e-spec.ts +9 -9
  135. package/templates/typeorm/test/users.e2e-spec.ts +18 -18
@@ -60,7 +60,7 @@ export class AuthService {
60
60
 
61
61
  if (existing) {
62
62
  throw new ConflictException(
63
- 'E-mail já cadastrado',
63
+ 'Email already registered',
64
64
  );
65
65
  }
66
66
 
@@ -103,7 +103,7 @@ export class AuthService {
103
103
 
104
104
  if (!user || !user.passwordHash) {
105
105
  throw new UnauthorizedException(
106
- 'Credenciais inválidas',
106
+ 'Invalid credentials',
107
107
  );
108
108
  }
109
109
 
@@ -114,7 +114,7 @@ export class AuthService {
114
114
 
115
115
  if (!passwordMatches) {
116
116
  throw new UnauthorizedException(
117
- 'Credenciais inválidas',
117
+ 'Invalid credentials',
118
118
  );
119
119
  }
120
120
 
@@ -206,7 +206,7 @@ export class AuthService {
206
206
 
207
207
  const genericResponse = {
208
208
  message:
209
- 'Se o e-mail existir, enviaremos instruções de redefinição de senha',
209
+ 'If the email exists, password reset instructions will be sent',
210
210
  };
211
211
 
212
212
  if (!user) {
@@ -264,7 +264,7 @@ export class AuthService {
264
264
  stored.expiresAt < new Date()
265
265
  ) {
266
266
  throw new UnauthorizedException(
267
- 'Token de redefinição inválido ou expirado',
267
+ 'Invalid or expired password reset token',
268
268
  );
269
269
  }
270
270
 
@@ -433,7 +433,7 @@ export class AuthService {
433
433
  // nestforge:feature:database:sqlite:end
434
434
 
435
435
  return {
436
- message: 'Senha redefinida com sucesso',
436
+ message: 'Password reset successfully',
437
437
  };
438
438
  }
439
439
 
@@ -457,7 +457,7 @@ export class AuthService {
457
457
  stored.expiresAt < new Date()
458
458
  ) {
459
459
  throw new UnauthorizedException(
460
- 'Token de verificação inválido ou expirado',
460
+ 'Invalid or expired verification token',
461
461
  );
462
462
  }
463
463
 
@@ -563,7 +563,7 @@ export class AuthService {
563
563
  // nestforge:feature:database:sqlite:end
564
564
 
565
565
  return {
566
- message: 'E-mail verificado com sucesso',
566
+ message: 'Email verified successfully',
567
567
  };
568
568
  }
569
569
 
@@ -628,4 +628,4 @@ export class AuthService {
628
628
  .update(token)
629
629
  .digest('hex');
630
630
  }
631
- }
631
+ }
@@ -3,7 +3,7 @@ import { z } from 'zod';
3
3
  import { createZodDto } from 'nestjs-zod';
4
4
 
5
5
  export const forgotPasswordSchema = z.object({
6
- email: z.string().email().describe('E-mail da conta a ser recuperada'),
6
+ email: z.string().email().describe('Email of the account to recover'),
7
7
  });
8
8
 
9
- export class ForgotPasswordDto extends createZodDto(forgotPasswordSchema) { }
9
+ export class ForgotPasswordDto extends createZodDto(forgotPasswordSchema) { }
@@ -3,8 +3,8 @@ import { z } from 'zod';
3
3
  import { createZodDto } from 'nestjs-zod';
4
4
 
5
5
  export const loginSchema = z.object({
6
- email: z.string().email().describe('E-mail do usuário'),
7
- password: z.string().min(8).describe('Senha'),
6
+ email: z.string().email().describe('User email'),
7
+ password: z.string().min(8).describe('Password'),
8
8
  });
9
9
 
10
- export class LoginDto extends createZodDto(loginSchema) { }
10
+ export class LoginDto extends createZodDto(loginSchema) { }
@@ -3,9 +3,9 @@ import { z } from 'zod';
3
3
  import { createZodDto } from 'nestjs-zod';
4
4
 
5
5
  export const registerSchema = z.object({
6
- name: z.string().min(2).describe('Nome completo do usuário'),
7
- email: z.string().email().describe('E-mail do usuário'),
8
- password: z.string().min(8).describe('Senha (mínimo 8 caracteres)'),
6
+ name: z.string().min(2).describe('User full name'),
7
+ email: z.string().email().describe('User email'),
8
+ password: z.string().min(8).describe('Password (minimum 8 characters)'),
9
9
  });
10
10
 
11
- export class RegisterDto extends createZodDto(registerSchema) { }
11
+ export class RegisterDto extends createZodDto(registerSchema) { }
@@ -3,8 +3,8 @@ import { z } from 'zod';
3
3
  import { createZodDto } from 'nestjs-zod';
4
4
 
5
5
  export const resetPasswordSchema = z.object({
6
- token: z.string().describe('Token recebido por e-mail'),
7
- password: z.string().min(8).describe('Nova senha (mínimo 8 caracteres)'),
6
+ token: z.string().describe('Token received by email'),
7
+ password: z.string().min(8).describe('New password (minimum 8 characters)'),
8
8
  });
9
9
 
10
- export class ResetPasswordDto extends createZodDto(resetPasswordSchema) { }
10
+ export class ResetPasswordDto extends createZodDto(resetPasswordSchema) { }
@@ -4,7 +4,7 @@ import { AuthGuard } from '@nestjs/passport';
4
4
  @Injectable()
5
5
  export class GithubAuthGuard extends AuthGuard('github') {
6
6
  constructor() {
7
- // API stateless (Bearer token) — não usamos sessão do Passport/Express
7
+ // Stateless API (Bearer token) — Passport/Express sessions are not used.
8
8
  super({ session: false });
9
9
  }
10
- }
10
+ }
@@ -4,7 +4,7 @@ import { AuthGuard } from '@nestjs/passport';
4
4
  @Injectable()
5
5
  export class GoogleAuthGuard extends AuthGuard('google') {
6
6
  constructor() {
7
- // API stateless (Bearer token) — não usamos sessão do Passport/Express
7
+ // Stateless API (Bearer token) — Passport/Express sessions are not used.
8
8
  super({ session: false });
9
9
  }
10
- }
10
+ }
@@ -44,14 +44,14 @@ describe('SessionAuthGuard', () => {
44
44
  return { context, request };
45
45
  }
46
46
 
47
- it('permite acesso a rotas públicas sem sessão', () => {
47
+ it('allows access to public routes without a session', () => {
48
48
  reflector.getAllAndOverride.mockReturnValue(true);
49
49
  const { context } = createContext();
50
50
 
51
51
  expect(guard.canActivate(context)).toBe(true);
52
52
  });
53
53
 
54
- it('rejeita acesso quando não existe usuário na sessão', () => {
54
+ it('rejects access when the session has no user', () => {
55
55
  reflector.getAllAndOverride.mockReturnValue(false);
56
56
  const { context } = createContext();
57
57
 
@@ -60,7 +60,7 @@ describe('SessionAuthGuard', () => {
60
60
  );
61
61
  });
62
62
 
63
- it('permite acesso e disponibiliza o usuário autenticado', () => {
63
+ it('allows access and exposes the authenticated user', () => {
64
64
  reflector.getAllAndOverride.mockReturnValue(false);
65
65
 
66
66
  const user = {
@@ -74,4 +74,4 @@ describe('SessionAuthGuard', () => {
74
74
  expect(guard.canActivate(context)).toBe(true);
75
75
  expect(request.user).toEqual(user);
76
76
  });
77
- });
77
+ });
@@ -27,11 +27,11 @@ export class SessionAuthGuard implements CanActivate {
27
27
  const user = request.session?.user;
28
28
 
29
29
  if (!user) {
30
- throw new UnauthorizedException('Sessão inválida ou expirada');
30
+ throw new UnauthorizedException('Invalid or expired session');
31
31
  }
32
32
 
33
33
  request.user = user;
34
34
 
35
35
  return true;
36
36
  }
37
- }
37
+ }
@@ -31,7 +31,7 @@ describe('SessionService', () => {
31
31
  };
32
32
  }
33
33
 
34
- it('regenera, preenche e salva a sessão', async () => {
34
+ it('regenerates, populates, and saves the session', async () => {
35
35
  const { request, session } = createRequest();
36
36
  const user: SessionUser = {
37
37
  id: 'user-1',
@@ -51,7 +51,7 @@ describe('SessionService', () => {
51
51
  });
52
52
  });
53
53
 
54
- it('emite e salva um novo token CSRF', async () => {
54
+ it('issues and saves a new CSRF token', async () => {
55
55
  const { request, session } = createRequest();
56
56
 
57
57
  const result = await sessionService.issueCsrfToken(request);
@@ -61,14 +61,14 @@ describe('SessionService', () => {
61
61
  expect(session.save).toHaveBeenCalledOnce();
62
62
  });
63
63
 
64
- it('destrói a sessão atual', async () => {
64
+ it('destroys the current session', async () => {
65
65
  const { request, session } = createRequest();
66
66
 
67
67
  const result = await sessionService.destroy(request);
68
68
 
69
69
  expect(session.destroy).toHaveBeenCalledOnce();
70
70
  expect(result).toEqual({
71
- message: 'Logout realizado com sucesso',
71
+ message: 'Logout completed successfully',
72
72
  });
73
73
  });
74
- });
74
+ });
@@ -47,7 +47,7 @@ export class SessionService {
47
47
  if (error) {
48
48
  reject(
49
49
  new InternalServerErrorException(
50
- 'Não foi possível encerrar a sessão',
50
+ 'Unable to end the session',
51
51
  ),
52
52
  );
53
53
  return;
@@ -57,7 +57,7 @@ export class SessionService {
57
57
  });
58
58
  });
59
59
 
60
- return { message: 'Logout realizado com sucesso' };
60
+ return { message: 'Logout completed successfully' };
61
61
  }
62
62
 
63
63
  private async regenerate(request: Request): Promise<void> {
@@ -66,7 +66,7 @@ export class SessionService {
66
66
  if (error) {
67
67
  reject(
68
68
  new InternalServerErrorException(
69
- 'Não foi possível iniciar a sessão',
69
+ 'Unable to start the session',
70
70
  ),
71
71
  );
72
72
  return;
@@ -83,7 +83,7 @@ export class SessionService {
83
83
  if (error) {
84
84
  reject(
85
85
  new InternalServerErrorException(
86
- 'Não foi possível salvar a sessão',
86
+ 'Unable to save the session',
87
87
  ),
88
88
  );
89
89
  return;
@@ -93,4 +93,4 @@ export class SessionService {
93
93
  });
94
94
  });
95
95
  }
96
- }
96
+ }
@@ -25,7 +25,7 @@ export class GithubStrategy extends PassportStrategy(Strategy, 'github') {
25
25
  profile: Profile,
26
26
  done: (error: unknown, user?: OAuthProfile) => void,
27
27
  ) {
28
- // o e-mail pode vir vazio se o usuário deixou o e-mail privado no GitHub
28
+ // The email may be missing when the user keeps it private on GitHub.
29
29
  const email =
30
30
  profile.emails?.[0]?.value ?? `${profile.username}@users.noreply.github.com`;
31
31
 
@@ -33,9 +33,9 @@ export class GithubStrategy extends PassportStrategy(Strategy, 'github') {
33
33
  provider: 'github',
34
34
  providerUserId: profile.id,
35
35
  email,
36
- name: profile.displayName || profile.username || 'Usuário GitHub',
36
+ name: profile.displayName || profile.username || 'GitHub User',
37
37
  };
38
38
 
39
39
  done(null, oauthProfile);
40
40
  }
41
- }
41
+ }
@@ -120,7 +120,7 @@ export class TokenService {
120
120
  stored.expiresAt < new Date()
121
121
  ) {
122
122
  throw new UnauthorizedException(
123
- 'Refresh token inválido ou expirado',
123
+ 'Invalid or expired refresh token',
124
124
  );
125
125
  }
126
126
 
@@ -163,7 +163,7 @@ export class TokenService {
163
163
  );
164
164
 
165
165
  return {
166
- message: 'Logout realizado com sucesso',
166
+ message: 'Logout completed successfully',
167
167
  };
168
168
  }
169
169
 
@@ -172,4 +172,4 @@ export class TokenService {
172
172
  .update(token)
173
173
  .digest('hex');
174
174
  }
175
- }
175
+ }
@@ -22,7 +22,7 @@ export class HttpExceptionFilter implements ExceptionFilter {
22
22
  const message =
23
23
  exception instanceof HttpException
24
24
  ? exception.getResponse()
25
- : 'Erro interno do servidor';
25
+ : 'Internal server error';
26
26
 
27
27
  response.status(status).json({
28
28
  statusCode: status,
@@ -15,14 +15,14 @@ function createContext(user?: { role: Role }): ExecutionContext {
15
15
  }
16
16
 
17
17
  describe('PermissionsGuard', () => {
18
- it('libera acesso quando a rota não exige nenhuma permissão', () => {
18
+ it('allows access when the route requires no permission', () => {
19
19
  const reflector = { getAllAndOverride: vi.fn().mockReturnValue(undefined) } as unknown as Reflector;
20
20
  const guard = new PermissionsGuard(reflector);
21
21
 
22
22
  expect(guard.canActivate(createContext({ role: Role.USER }))).toBe(true);
23
23
  });
24
24
 
25
- it('libera acesso quando a role do usuário tem a permissão exigida', () => {
25
+ it('allows access when the user role has the required permission', () => {
26
26
  const reflector = {
27
27
  getAllAndOverride: vi.fn().mockReturnValue([Permission.UserRead]),
28
28
  } as unknown as Reflector;
@@ -31,7 +31,7 @@ describe('PermissionsGuard', () => {
31
31
  expect(guard.canActivate(createContext({ role: Role.USER }))).toBe(true);
32
32
  });
33
33
 
34
- it('bloqueia acesso quando a role do usuário não tem a permissão exigida', () => {
34
+ it('blocks access when the user role lacks the required permission', () => {
35
35
  const reflector = {
36
36
  getAllAndOverride: vi.fn().mockReturnValue([Permission.UserDelete]),
37
37
  } as unknown as Reflector;
@@ -40,15 +40,15 @@ describe('PermissionsGuard', () => {
40
40
  expect(guard.canActivate(createContext({ role: Role.USER }))).toBe(false);
41
41
  });
42
42
 
43
- it('exige todas as permissões quando mais de uma é requisitada', () => {
43
+ it('requires all permissions when more than one is requested', () => {
44
44
  const reflector = {
45
45
  getAllAndOverride: vi.fn().mockReturnValue([Permission.UserRead, Permission.UserUpdate]),
46
46
  } as unknown as Reflector;
47
47
  const guard = new PermissionsGuard(reflector);
48
48
 
49
- // MANAGER tem user:read e user:update
49
+ // MANAGER has user:read and user:update
50
50
  expect(guard.canActivate(createContext({ role: Role.MANAGER }))).toBe(true);
51
- // USER só tem user:read
51
+ // USER only has user:read
52
52
  expect(guard.canActivate(createContext({ role: Role.USER }))).toBe(false);
53
53
  });
54
- });
54
+ });
@@ -14,24 +14,24 @@ function createContext(user?: { role: Role }): ExecutionContext {
14
14
  }
15
15
 
16
16
  describe('RolesGuard', () => {
17
- it('libera acesso quando a rota não exige nenhuma role', () => {
17
+ it('allows access when the route requires no role', () => {
18
18
  const reflector = { getAllAndOverride: vi.fn().mockReturnValue(undefined) } as unknown as Reflector;
19
19
  const guard = new RolesGuard(reflector);
20
20
 
21
21
  expect(guard.canActivate(createContext({ role: Role.USER }))).toBe(true);
22
22
  });
23
23
 
24
- it('libera acesso quando o usuário tem a role exigida', () => {
24
+ it('allows access when the user has the required role', () => {
25
25
  const reflector = { getAllAndOverride: vi.fn().mockReturnValue([Role.ADMIN]) } as unknown as Reflector;
26
26
  const guard = new RolesGuard(reflector);
27
27
 
28
28
  expect(guard.canActivate(createContext({ role: Role.ADMIN }))).toBe(true);
29
29
  });
30
30
 
31
- it('bloqueia acesso quando o usuário não tem a role exigida', () => {
31
+ it('blocks access when the user does not have the required role', () => {
32
32
  const reflector = { getAllAndOverride: vi.fn().mockReturnValue([Role.ADMIN]) } as unknown as Reflector;
33
33
  const guard = new RolesGuard(reflector);
34
34
 
35
35
  expect(guard.canActivate(createContext({ role: Role.USER }))).toBe(false);
36
36
  });
37
- });
37
+ });
@@ -36,7 +36,7 @@ describe('CsrfMiddleware', () => {
36
36
  }
37
37
 
38
38
  it.each(['GET', 'HEAD', 'OPTIONS'])(
39
- 'permite o método seguro %s sem token',
39
+ 'allows the safe %s method without a token',
40
40
  (method) => {
41
41
  const request = createRequest(method);
42
42
 
@@ -50,7 +50,7 @@ describe('CsrfMiddleware', () => {
50
50
  },
51
51
  );
52
52
 
53
- it('rejeita uma requisição sem token CSRF', () => {
53
+ it('rejects a request without a CSRF token', () => {
54
54
  const request = createRequest('POST');
55
55
 
56
56
  expect(() =>
@@ -64,7 +64,7 @@ describe('CsrfMiddleware', () => {
64
64
  expect(next).not.toHaveBeenCalled();
65
65
  });
66
66
 
67
- it('rejeita quando o token do header é diferente da sessão', () => {
67
+ it('rejects when the header token differs from the session token', () => {
68
68
  const request = createRequest(
69
69
  'PATCH',
70
70
  'session-token',
@@ -82,7 +82,7 @@ describe('CsrfMiddleware', () => {
82
82
  expect(next).not.toHaveBeenCalled();
83
83
  });
84
84
 
85
- it('permite quando o token corresponde ao valor da sessão', () => {
85
+ it('allows the request when the token matches the session value', () => {
86
86
  const token = 'a'.repeat(64);
87
87
  const request = createRequest('DELETE', token, token);
88
88
 
@@ -94,4 +94,4 @@ describe('CsrfMiddleware', () => {
94
94
 
95
95
  expect(next).toHaveBeenCalledOnce();
96
96
  });
97
- });
97
+ });
@@ -27,7 +27,7 @@ export class CsrfMiddleware implements NestMiddleware {
27
27
  !this.tokensMatch(sessionToken, headerToken)
28
28
  ) {
29
29
  throw new ForbiddenException(
30
- 'Token CSRF inválido ou ausente',
30
+ 'Invalid or missing CSRF token',
31
31
  );
32
32
  }
33
33
 
@@ -43,4 +43,4 @@ export class CsrfMiddleware implements NestMiddleware {
43
43
  timingSafeEqual(expectedBuffer, receivedBuffer)
44
44
  );
45
45
  }
46
- }
46
+ }
@@ -20,7 +20,7 @@ export function avatarFileFilter(
20
20
  ) {
21
21
  if (!ALLOWED_MIME_TYPES.includes(file.mimetype)) {
22
22
  callback(
23
- new BadRequestException('Formato de imagem não suportado (use PNG, JPEG ou WEBP)'),
23
+ new BadRequestException('Unsupported image format (use PNG, JPEG, or WEBP)'),
24
24
  false,
25
25
  );
26
26
  return;
@@ -29,4 +29,4 @@ export function avatarFileFilter(
29
29
  callback(null, true);
30
30
  }
31
31
 
32
- export const AVATAR_MAX_SIZE_BYTES = 2 * 1024 * 1024; // 2MB
32
+ export const AVATAR_MAX_SIZE_BYTES = 2 * 1024 * 1024; // 2MB
@@ -43,7 +43,7 @@ export function validateEnv(config: Record<string, unknown>): EnvConfig {
43
43
  const issues = parsed.error.issues
44
44
  .map((issue) => `${issue.path.join('.')}: ${issue.message}`)
45
45
  .join('\n');
46
- throw new Error(`Variáveis de ambiente inválidas:\n${issues}`);
46
+ throw new Error(`Invalid environment variables:\n${issues}`);
47
47
  }
48
48
 
49
49
  return parsed.data;
@@ -46,7 +46,7 @@ const SEED_USERS: SeedUser[] = [
46
46
  role: Role.MANAGER,
47
47
  },
48
48
  {
49
- name: 'Usuário',
49
+ name: 'User',
50
50
  email: 'user@nestforge.dev',
51
51
  password: 'user1234',
52
52
  role: Role.USER,
@@ -57,7 +57,7 @@ const databaseUrl = process.env.DATABASE_URL;
57
57
 
58
58
  if (!databaseUrl) {
59
59
  throw new Error(
60
- 'DATABASE_URL não foi definida',
60
+ 'DATABASE_URL is not defined',
61
61
  );
62
62
  }
63
63
 
@@ -144,9 +144,9 @@ async function seed(): Promise<void> {
144
144
 
145
145
  seed().catch((error: unknown) => {
146
146
  console.error(
147
- 'Erro ao executar o seed:',
147
+ 'Error while running the seed:',
148
148
  error,
149
149
  );
150
150
 
151
151
  process.exitCode = 1;
152
- });
152
+ });
@@ -33,7 +33,7 @@ export class HealthController {
33
33
  @Get()
34
34
  @HealthCheck()
35
35
  // nestforge:feature:swagger
36
- @ApiOperation({ summary: 'Verifica a saúde da API (banco, memória, disco e demais dependências configuradas)' })
36
+ @ApiOperation({ summary: 'Checks API health (database, memory, disk, and other configured dependencies)' })
37
37
  // nestforge:feature:swagger:end
38
38
  check() {
39
39
  return this.health.check([
@@ -46,4 +46,4 @@ export class HealthController {
46
46
  () => this.disk.checkStorage('disk', { path: '/', thresholdPercent: 0.9 }),
47
47
  ]);
48
48
  }
49
- }
49
+ }
@@ -9,7 +9,7 @@ import type { DatabaseClient } from '../../database/database.types';
9
9
  import { DrizzleHealthIndicator } from './drizzle-health.indicator';
10
10
 
11
11
  describe('DrizzleHealthIndicator', () => {
12
- it('retorna status up quando a consulta executa com sucesso', async () => {
12
+ it('returns an up status when the database query succeeds', async () => {
13
13
  const get = vi.fn().mockReturnValue({
14
14
  result: 1,
15
15
  });
@@ -41,16 +41,16 @@ describe('DrizzleHealthIndicator', () => {
41
41
  });
42
42
  });
43
43
 
44
- it('lança HealthCheckError quando a consulta falha', async () => {
44
+ it('throws HealthCheckError when the database query fails', async () => {
45
45
  const get = vi.fn(() => {
46
- throw new Error('conexão recusada');
46
+ throw new Error('connection refused');
47
47
  });
48
48
 
49
49
  const databaseClient = {
50
50
  query: vi
51
51
  .fn()
52
52
  .mockRejectedValue(
53
- new Error('conexão recusada'),
53
+ new Error('connection refused'),
54
54
  ),
55
55
  prepare: vi.fn(() => ({
56
56
  get,
@@ -68,4 +68,4 @@ describe('DrizzleHealthIndicator', () => {
68
68
  HealthCheckError,
69
69
  );
70
70
  });
71
- });
71
+ });
@@ -39,7 +39,7 @@ export class DrizzleHealthIndicator {
39
39
  };
40
40
  } catch (error) {
41
41
  throw new HealthCheckError(
42
- 'Banco de dados indisponível',
42
+ 'Database unavailable',
43
43
  {
44
44
  [key]: {
45
45
  status: 'down',
@@ -49,4 +49,4 @@ export class DrizzleHealthIndicator {
49
49
  );
50
50
  }
51
51
  }
52
- }
52
+ }
@@ -14,7 +14,7 @@ vi.mock('ioredis', () => ({
14
14
  })),
15
15
  }));
16
16
 
17
- // precisa ser importado depois do vi.mock, senão pega o ioredis real
17
+ // Must be imported after vi.mock; otherwise it loads the real ioredis package.
18
18
  const { RedisHealthIndicator } = await import('./redis-health.indicator');
19
19
 
20
20
  describe('RedisHealthIndicator', () => {
@@ -24,7 +24,7 @@ describe('RedisHealthIndicator', () => {
24
24
  disconnectMock.mockReset();
25
25
  });
26
26
 
27
- it('retorna status up quando o PING responde PONG', async () => {
27
+ it('returns an up status when PING returns PONG', async () => {
28
28
  connectMock.mockResolvedValue(undefined);
29
29
  pingMock.mockResolvedValue('PONG');
30
30
 
@@ -35,7 +35,7 @@ describe('RedisHealthIndicator', () => {
35
35
  expect(disconnectMock).toHaveBeenCalled();
36
36
  });
37
37
 
38
- it('lança HealthCheckError quando o PING não responde PONG', async () => {
38
+ it('throws HealthCheckError when PING does not return PONG', async () => {
39
39
  connectMock.mockResolvedValue(undefined);
40
40
  pingMock.mockResolvedValue('ALGO_INESPERADO');
41
41
 
@@ -44,11 +44,11 @@ describe('RedisHealthIndicator', () => {
44
44
  await expect(indicator.isHealthy('redis')).rejects.toBeInstanceOf(HealthCheckError);
45
45
  });
46
46
 
47
- it('lança HealthCheckError quando a conexão falha', async () => {
47
+ it('throws HealthCheckError when the connection fails', async () => {
48
48
  connectMock.mockRejectedValue(new Error('ECONNREFUSED'));
49
49
 
50
50
  const indicator = new RedisHealthIndicator();
51
51
 
52
52
  await expect(indicator.isHealthy('redis')).rejects.toBeInstanceOf(HealthCheckError);
53
53
  });
54
- });
54
+ });
@@ -18,16 +18,16 @@ export class RedisHealthIndicator {
18
18
  const response = await client.ping();
19
19
 
20
20
  if (response !== 'PONG') {
21
- throw new Error('Resposta inesperada do Redis');
21
+ throw new Error('Unexpected Redis response');
22
22
  }
23
23
 
24
24
  return { [key]: { status: 'up' } };
25
25
  } catch (error) {
26
- throw new HealthCheckError('Redis indisponível', {
26
+ throw new HealthCheckError('Redis unavailable', {
27
27
  [key]: { status: 'down', message: (error as Error).message },
28
28
  });
29
29
  } finally {
30
30
  client.disconnect();
31
31
  }
32
32
  }
33
- }
33
+ }