nestforge-generator 0.2.0 → 0.3.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.
@@ -21,6 +21,16 @@ export class UsersController {
21
21
 
22
22
  O nome depois de `nestforge:feature:` tem que ser exatamente o mesmo nas duas linhas (abertura e `:end`), e bater com o nome usado no array `features` da CLI (`docker`, `swagger`, `validation`, `redis`, `rbac`).
23
23
 
24
+ Marcadores de banco são adicionados automaticamente pelo gerador:
25
+
26
+ * `database:postgres`;
27
+ * `database:mysql`;
28
+ * `database:sqlite`;
29
+ * `database:mongodb`;
30
+ * `database:relational`, habilitado em PostgreSQL, MySQL e SQLite.
31
+
32
+ Use `database:relational` quando o mesmo trecho SQL serve para todos os bancos relacionais, como a etapa `prisma migrate deploy`. Use o marcador específico quando provider, URL, health check ou infraestrutura dependem do banco selecionado.
33
+
24
34
  Funciona em qualquer arquivo cuja linguagem use `//` para comentário (`.ts`, `.js`). **Não funciona em JSON** (`package.json`) — pra dependências, ver a seção final deste documento.
25
35
 
26
36
  ## Marcador de arquivo inteiro
@@ -47,4 +57,4 @@ JSON não aceita comentário, então marcador não funciona ali. Em vez disso, o
47
57
  - [ ] Todo trecho de código exclusivo do recurso está marcado (bloco ou arquivo inteiro)
48
58
  - [ ] O nome do marcador bate com o valor usado em `features` na CLI (`packages/cli/src/prompts.ts`)
49
59
  - [ ] Dependências novas do `package.json` estão em `FEATURE_DEPENDENCIES` (`packages/cli/src/features/dependencies.ts`)
50
- - [ ] Testado gerando o projeto com o recurso ligado **e** desligado — o projeto tem que compilar/rodar dos dois jeitos
60
+ - [ ] Testado gerando o projeto com o recurso ligado **e** desligado — o projeto tem que compilar/rodar dos dois jeitos
@@ -97,6 +97,10 @@ model Session {
97
97
  data String
98
98
  // nestforge:feature:database:sqlite:end
99
99
 
100
+ // nestforge:feature:database:mongodb
101
+ data String
102
+ // nestforge:feature:database:mongodb:end
103
+
100
104
  expiresAt DateTime
101
105
 
102
106
  @@map("sessions")
@@ -1,6 +1,7 @@
1
1
  // nestforge:feature-file:auth:token
2
2
  import { Injectable, UnauthorizedException } from '@nestjs/common';
3
3
  import { JwtService } from '@nestjs/jwt';
4
+ import type { JwtSignOptions } from '@nestjs/jwt';
4
5
  import { createHash } from 'crypto';
5
6
  import { PrismaService } from '../database/prisma.service';
6
7
 
@@ -14,14 +15,22 @@ export class TokenService {
14
15
  async issueTokens(userId: string, email: string, role: string) {
15
16
  const payload = { sub: userId, email, role };
16
17
 
18
+ const accessTokenExpiresIn = (
19
+ process.env.JWT_ACCESS_EXPIRES_IN ?? '15m'
20
+ ) as JwtSignOptions['expiresIn'];
21
+
22
+ const refreshTokenExpiresIn = (
23
+ process.env.JWT_REFRESH_EXPIRES_IN ?? '7d'
24
+ ) as JwtSignOptions['expiresIn'];
25
+
17
26
  const accessToken = this.jwtService.sign(payload, {
18
27
  secret: process.env.JWT_ACCESS_SECRET,
19
- expiresIn: process.env.JWT_ACCESS_EXPIRES_IN ?? '15m',
28
+ expiresIn: accessTokenExpiresIn,
20
29
  });
21
30
 
22
31
  const refreshToken = this.jwtService.sign(payload, {
23
32
  secret: process.env.JWT_REFRESH_SECRET,
24
- expiresIn: process.env.JWT_REFRESH_EXPIRES_IN ?? '7d',
33
+ expiresIn: refreshTokenExpiresIn,
25
34
  });
26
35
 
27
36
  const expiresAt = new Date();
@@ -81,4 +90,4 @@ export class TokenService {
81
90
  private hashToken(token: string): string {
82
91
  return createHash('sha256').update(token).digest('hex');
83
92
  }
84
- }
93
+ }
@@ -1,22 +1,39 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
- import { HealthCheckError } from '@nestjs/terminus';
3
- import { PrismaHealthIndicator } from './prisma-health.indicator';
4
- import { PrismaService } from '../../database/prisma.service';
5
-
6
- describe('PrismaHealthIndicator', () => {
7
- it('retorna status up quando a query executa com sucesso', async () => {
8
- const prisma = { $queryRaw: vi.fn().mockResolvedValue([{ '?column?': 1 }]) };
9
- const indicator = new PrismaHealthIndicator(prisma as unknown as PrismaService);
10
-
11
- const result = await indicator.isHealthy('database');
12
-
13
- expect(result).toEqual({ database: { status: 'up' } });
14
- });
15
-
16
- it('lança HealthCheckError quando a query falha', async () => {
17
- const prisma = { $queryRaw: vi.fn().mockRejectedValue(new Error('conexão recusada')) };
18
- const indicator = new PrismaHealthIndicator(prisma as unknown as PrismaService);
19
-
20
- await expect(indicator.isHealthy('database')).rejects.toBeInstanceOf(HealthCheckError);
21
- });
22
- });
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { HealthCheckError } from '@nestjs/terminus';
3
+ import { PrismaHealthIndicator } from './prisma-health.indicator';
4
+ import { PrismaService } from '../../database/prisma.service';
5
+
6
+ describe('PrismaHealthIndicator', () => {
7
+ it('retorna status up quando a query executa com sucesso', async () => {
8
+ const prisma = {
9
+ // nestforge:feature:database:relational
10
+ $queryRaw: vi.fn().mockResolvedValue([{ '?column?': 1 }]),
11
+ // nestforge:feature:database:relational:end
12
+ // nestforge:feature:database:mongodb
13
+ $runCommandRaw: vi.fn().mockResolvedValue({ ok: 1 }),
14
+ // nestforge:feature:database:mongodb:end
15
+ };
16
+ const indicator = new PrismaHealthIndicator(prisma as unknown as PrismaService);
17
+
18
+ const result = await indicator.isHealthy('database');
19
+
20
+ expect(result).toEqual({ database: { status: 'up' } });
21
+ // nestforge:feature:database:mongodb
22
+ expect(prisma.$runCommandRaw).toHaveBeenCalledWith({ ping: 1 });
23
+ // nestforge:feature:database:mongodb:end
24
+ });
25
+
26
+ it('lança HealthCheckError quando a query falha', async () => {
27
+ const prisma = {
28
+ // nestforge:feature:database:relational
29
+ $queryRaw: vi.fn().mockRejectedValue(new Error('conexão recusada')),
30
+ // nestforge:feature:database:relational:end
31
+ // nestforge:feature:database:mongodb
32
+ $runCommandRaw: vi.fn().mockRejectedValue(new Error('conexão recusada')),
33
+ // nestforge:feature:database:mongodb:end
34
+ };
35
+ const indicator = new PrismaHealthIndicator(prisma as unknown as PrismaService);
36
+
37
+ await expect(indicator.isHealthy('database')).rejects.toBeInstanceOf(HealthCheckError);
38
+ });
39
+ });
@@ -1,19 +1,24 @@
1
- import { Injectable } from '@nestjs/common';
2
- import { HealthIndicatorResult, HealthCheckError } from '@nestjs/terminus';
3
- import { PrismaService } from '../../database/prisma.service';
4
-
5
- @Injectable()
6
- export class PrismaHealthIndicator {
7
- constructor(private readonly prisma: PrismaService) { }
8
-
9
- async isHealthy(key: string): Promise<HealthIndicatorResult> {
10
- try {
11
- await this.prisma.$queryRaw`SELECT 1`;
12
- return { [key]: { status: 'up' } };
13
- } catch (error) {
14
- throw new HealthCheckError('Banco de dados indisponível', {
15
- [key]: { status: 'down', message: (error as Error).message },
16
- });
17
- }
18
- }
19
- }
1
+ import { Injectable } from '@nestjs/common';
2
+ import { HealthIndicatorResult, HealthCheckError } from '@nestjs/terminus';
3
+ import { PrismaService } from '../../database/prisma.service';
4
+
5
+ @Injectable()
6
+ export class PrismaHealthIndicator {
7
+ constructor(private readonly prisma: PrismaService) { }
8
+
9
+ async isHealthy(key: string): Promise<HealthIndicatorResult> {
10
+ try {
11
+ // nestforge:feature:database:relational
12
+ await this.prisma.$queryRaw`SELECT 1`;
13
+ // nestforge:feature:database:relational:end
14
+ // nestforge:feature:database:mongodb
15
+ await this.prisma.$runCommandRaw({ ping: 1 });
16
+ // nestforge:feature:database:mongodb:end
17
+ return { [key]: { status: 'up' } };
18
+ } catch (error) {
19
+ throw new HealthCheckError('Banco de dados indisponível', {
20
+ [key]: { status: 'down', message: (error as Error).message },
21
+ });
22
+ }
23
+ }
24
+ }
@@ -25,6 +25,8 @@ NestForge is a NestJS starter designed to accelerate the beginning of serious ba
25
25
  - 🐳 **Docker** — complete environment with a single command
26
26
  - ⚙️ **CI/CD** — GitHub Actions (build, lint, test)
27
27
 
28
+ > **MongoDB compatibility:** MongoDB is not available in this NestForge template. Although TypeORM provides basic MongoDB support, adopting it would require a separate document-oriented architecture for entities, repositories, relations, migrations, session persistence, and tests; it is not a direct database-driver substitution. MongoDB generation is currently available through the Prisma template.
29
+
28
30
  ## 🧱 Stack
29
31
 
30
32
  | Layer | Technology |
@@ -25,6 +25,8 @@ NestForge é um boilerplate de NestJS pensado para acelerar o início de projeto
25
25
  - 🐳 **Docker** — ambiente completo com um comando
26
26
  - ⚙️ **CI/CD** — GitHub Actions (build, lint, test)
27
27
 
28
+ > **Compatibilidade com MongoDB:** o MongoDB não está disponível neste template do NestForge. Embora o TypeORM ofereça suporte básico a MongoDB, adotá-lo exigiria uma arquitetura separada e orientada a documentos para entidades, repositories, relações, migrations, persistência de sessões e testes; não se trata de uma troca direta do driver de banco. Atualmente, a geração com MongoDB está disponível por meio do template Prisma.
29
+
28
30
  ## 🧱 Stack
29
31
 
30
32
  | Camada | Tecnologia |