nestforge-generator 0.1.1 → 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.
- package/README.md +39 -23
- package/README.pt-BR.md +39 -23
- package/dist/features/database.js +35 -0
- package/dist/features/database.js.map +1 -1
- package/dist/features/language.js +19 -1
- package/dist/features/language.js.map +1 -1
- package/dist/features/no-orm.js +493 -0
- package/dist/features/no-orm.js.map +1 -0
- package/dist/generator.js +27 -7
- package/dist/generator.js.map +1 -1
- package/dist/index.js +24 -13
- package/dist/index.js.map +1 -1
- package/dist/prompts.js +32 -22
- package/dist/prompts.js.map +1 -1
- package/package.json +2 -1
- package/templates/drizzle/README.md +2 -0
- package/templates/drizzle/README.pt-BR.md +2 -0
- package/templates/prisma/.github/workflows/ci.yml +24 -1
- package/templates/prisma/ARCHITECTURE.md +7 -1
- package/templates/prisma/ARCHITECTURE.pt-BR.md +7 -1
- package/templates/prisma/README.md +11 -7
- package/templates/prisma/README.pt-BR.md +11 -7
- package/templates/prisma/ROADMAP.md +5 -1
- package/templates/prisma/ROADMAP.pt-BR.md +5 -1
- package/templates/prisma/TESTING.md +25 -3
- package/templates/prisma/TESTING.pt-BR.md +25 -3
- package/templates/prisma/docker-compose.yml +29 -1
- package/templates/prisma/docs/adding-a-module.md +246 -230
- package/templates/prisma/docs/features-markers.md +11 -1
- package/templates/prisma/prisma/schema.prisma +4 -0
- package/templates/prisma/src/auth/token.service.ts +12 -3
- package/templates/prisma/src/health/indicators/prisma-health.indicator.spec.ts +39 -22
- package/templates/prisma/src/health/indicators/prisma-health.indicator.ts +24 -19
- package/templates/typeorm/README.md +2 -0
- package/templates/typeorm/README.pt-BR.md +2 -0
|
@@ -1,230 +1,246 @@
|
|
|
1
|
-
# Como adicionar um novo módulo
|
|
2
|
-
|
|
3
|
-
Este guia mostra o passo a passo pra adicionar um recurso novo seguindo as convenções do NestForge, usando um módulo `posts` (posts de blog) como exemplo. Adapte os nomes pro seu caso.
|
|
4
|
-
|
|
5
|
-
## 1. Adicione o model no Prisma
|
|
6
|
-
|
|
7
|
-
Em `prisma/schema.prisma`:
|
|
8
|
-
|
|
9
|
-
```prisma
|
|
10
|
-
model Post {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
export
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
@
|
|
183
|
-
@Permissions(Permission.
|
|
184
|
-
|
|
185
|
-
return this.postsService.
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
@
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
1
|
+
# Como adicionar um novo módulo
|
|
2
|
+
|
|
3
|
+
Este guia mostra o passo a passo pra adicionar um recurso novo seguindo as convenções do NestForge, usando um módulo `posts` (posts de blog) como exemplo. Adapte os nomes pro seu caso.
|
|
4
|
+
|
|
5
|
+
## 1. Adicione o model no Prisma
|
|
6
|
+
|
|
7
|
+
Em `prisma/schema.prisma`:
|
|
8
|
+
|
|
9
|
+
```prisma
|
|
10
|
+
model Post {
|
|
11
|
+
// nestforge:feature:database:relational
|
|
12
|
+
id String @id @default(uuid())
|
|
13
|
+
// nestforge:feature:database:relational:end
|
|
14
|
+
// nestforge:feature:database:mongodb
|
|
15
|
+
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
16
|
+
// nestforge:feature:database:mongodb:end
|
|
17
|
+
title String
|
|
18
|
+
content String
|
|
19
|
+
// nestforge:feature:database:relational
|
|
20
|
+
authorId String
|
|
21
|
+
// nestforge:feature:database:relational:end
|
|
22
|
+
// nestforge:feature:database:mongodb
|
|
23
|
+
authorId String @db.ObjectId
|
|
24
|
+
// nestforge:feature:database:mongodb:end
|
|
25
|
+
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
|
|
26
|
+
createdAt DateTime @default(now())
|
|
27
|
+
updatedAt DateTime @updatedAt
|
|
28
|
+
|
|
29
|
+
@@map("posts")
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Não esqueça de adicionar a relação inversa no `model User`:
|
|
34
|
+
|
|
35
|
+
```prisma
|
|
36
|
+
posts Post[]
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Em PostgreSQL, MySQL ou SQLite, gere a migration:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npx prisma migrate dev --name add_posts
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Em MongoDB, envie o schema diretamente:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm run prisma:push
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## 2. Crie a estrutura de pastas
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
src/posts/
|
|
55
|
+
├── dto/
|
|
56
|
+
│ ├── create-post.dto.ts
|
|
57
|
+
│ └── update-post.dto.ts
|
|
58
|
+
├── entities/
|
|
59
|
+
│ └── post.entity.ts
|
|
60
|
+
├── posts.controller.ts
|
|
61
|
+
├── posts.service.ts
|
|
62
|
+
└── posts.module.ts
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## 3. DTOs com Zod
|
|
66
|
+
|
|
67
|
+
`src/posts/dto/create-post.dto.ts`:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { z } from 'zod';
|
|
71
|
+
import { createZodDto } from 'nestjs-zod';
|
|
72
|
+
|
|
73
|
+
export const createPostSchema = z.object({
|
|
74
|
+
title: z.string().min(3).describe('Título do post'),
|
|
75
|
+
content: z.string().min(10).describe('Conteúdo do post'),
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
export class CreatePostDto extends createZodDto(createPostSchema) {}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`src/posts/dto/update-post.dto.ts`:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import { createZodDto } from 'nestjs-zod';
|
|
85
|
+
import { createPostSchema } from './create-post.dto';
|
|
86
|
+
|
|
87
|
+
export const updatePostSchema = createPostSchema.partial();
|
|
88
|
+
|
|
89
|
+
export class UpdatePostDto extends createZodDto(updatePostSchema) {}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 4. Entity (o que a API expõe)
|
|
93
|
+
|
|
94
|
+
`src/posts/entities/post.entity.ts` — mesmo se não houver nada sensível pra esconder agora, criar a entity já deixa o padrão pronto pra quando houver:
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
export class PostEntity {
|
|
98
|
+
id: string;
|
|
99
|
+
title: string;
|
|
100
|
+
content: string;
|
|
101
|
+
authorId: string;
|
|
102
|
+
createdAt: Date;
|
|
103
|
+
updatedAt: Date;
|
|
104
|
+
|
|
105
|
+
constructor(partial: Partial<PostEntity>) {
|
|
106
|
+
Object.assign(this, partial);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## 5. Service (regra de negócio)
|
|
112
|
+
|
|
113
|
+
`src/posts/posts.service.ts`:
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import { Injectable, NotFoundException } from '@nestjs/common';
|
|
117
|
+
import { PrismaService } from '../database/prisma.service';
|
|
118
|
+
import { CreatePostDto } from './dto/create-post.dto';
|
|
119
|
+
import { UpdatePostDto } from './dto/update-post.dto';
|
|
120
|
+
import { PostEntity } from './entities/post.entity';
|
|
121
|
+
|
|
122
|
+
@Injectable()
|
|
123
|
+
export class PostsService {
|
|
124
|
+
constructor(private readonly prisma: PrismaService) {}
|
|
125
|
+
|
|
126
|
+
async create(authorId: string, dto: CreatePostDto) {
|
|
127
|
+
const post = await this.prisma.post.create({ data: { ...dto, authorId } });
|
|
128
|
+
return new PostEntity(post);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async findOne(id: string) {
|
|
132
|
+
const post = await this.prisma.post.findUnique({ where: { id } });
|
|
133
|
+
if (!post) throw new NotFoundException('Post não encontrado');
|
|
134
|
+
return new PostEntity(post);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async update(id: string, dto: UpdatePostDto) {
|
|
138
|
+
await this.findOne(id);
|
|
139
|
+
const post = await this.prisma.post.update({ where: { id }, data: dto });
|
|
140
|
+
return new PostEntity(post);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async remove(id: string) {
|
|
144
|
+
await this.findOne(id);
|
|
145
|
+
await this.prisma.post.delete({ where: { id } });
|
|
146
|
+
return { message: 'Post removido com sucesso' };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## 6. Controller (guards + permissions)
|
|
152
|
+
|
|
153
|
+
Se o recurso precisa de controle de acesso, adicione a permission em `src/common/constants/permissions.ts` e no mapeamento `src/common/constants/role-permissions.ts` antes de usar:
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
// permissions.ts
|
|
157
|
+
export enum Permission {
|
|
158
|
+
// ...existentes
|
|
159
|
+
PostCreate = 'post:create',
|
|
160
|
+
PostDelete = 'post:delete',
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
`src/posts/posts.controller.ts`:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
import { Body, Controller, Delete, Get, Param, Patch, Post } from '@nestjs/common';
|
|
168
|
+
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
|
169
|
+
import { PostsService } from './posts.service';
|
|
170
|
+
import { CreatePostDto } from './dto/create-post.dto';
|
|
171
|
+
import { UpdatePostDto } from './dto/update-post.dto';
|
|
172
|
+
import { Permissions } from '../common/decorators/permissions.decorator';
|
|
173
|
+
import { Permission } from '../common/constants/permissions';
|
|
174
|
+
import { CurrentUser } from '../common/decorators/current-user.decorator';
|
|
175
|
+
|
|
176
|
+
@ApiTags('posts')
|
|
177
|
+
@ApiBearerAuth()
|
|
178
|
+
@Controller('posts')
|
|
179
|
+
export class PostsController {
|
|
180
|
+
constructor(private readonly postsService: PostsService) {}
|
|
181
|
+
|
|
182
|
+
@Post()
|
|
183
|
+
@Permissions(Permission.PostCreate)
|
|
184
|
+
create(@CurrentUser() user: { id: string }, @Body() dto: CreatePostDto) {
|
|
185
|
+
return this.postsService.create(user.id, dto);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
@Get(':id')
|
|
189
|
+
findOne(@Param('id') id: string) {
|
|
190
|
+
return this.postsService.findOne(id);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
@Patch(':id')
|
|
194
|
+
update(@Param('id') id: string, @Body() dto: UpdatePostDto) {
|
|
195
|
+
return this.postsService.update(id, dto);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
@Delete(':id')
|
|
199
|
+
@Permissions(Permission.PostDelete)
|
|
200
|
+
remove(@Param('id') id: string) {
|
|
201
|
+
return this.postsService.remove(id);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## 7. Module
|
|
207
|
+
|
|
208
|
+
`src/posts/posts.module.ts`:
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
import { Module } from '@nestjs/common';
|
|
212
|
+
import { PostsService } from './posts.service';
|
|
213
|
+
import { PostsController } from './posts.controller';
|
|
214
|
+
|
|
215
|
+
@Module({
|
|
216
|
+
controllers: [PostsController],
|
|
217
|
+
providers: [PostsService],
|
|
218
|
+
exports: [PostsService],
|
|
219
|
+
})
|
|
220
|
+
export class PostsModule {}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Registre no `src/app.module.ts` (dentro do array `imports`):
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
import { PostsModule } from './posts/posts.module';
|
|
227
|
+
// ...
|
|
228
|
+
PostsModule,
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## 8. Testes
|
|
232
|
+
|
|
233
|
+
- **Unitário** (`src/posts/posts.service.spec.ts`): mocke o `PrismaService` como em `src/users/users.service.spec.ts` — sem banco real.
|
|
234
|
+
- **E2e** (`test/posts.e2e-spec.ts`): use os helpers de `test/utils/e2e-setup.ts` e `test/utils/clean-database.ts` (adicione `prisma.post.deleteMany()` na limpeza) e siga o padrão de `test/users.e2e-spec.ts`.
|
|
235
|
+
|
|
236
|
+
## Checklist rápido
|
|
237
|
+
|
|
238
|
+
- [ ] Model no `schema.prisma` + migration ou `prisma:push`
|
|
239
|
+
- [ ] DTOs com Zod (`createZodDto`)
|
|
240
|
+
- [ ] Entity (mesmo sem campo sensível ainda)
|
|
241
|
+
- [ ] Service sem lógica no controller
|
|
242
|
+
- [ ] Permissions novas cadastradas em `permissions.ts` e `role-permissions.ts`, se necessário
|
|
243
|
+
- [ ] Module registrado no `AppModule`
|
|
244
|
+
- [ ] Teste unitário do service
|
|
245
|
+
- [ ] Teste e2e do fluxo principal
|
|
246
|
+
- [ ] Atualizar `ROADMAP.md` se o módulo fechar um item do roadmap
|
|
@@ -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
|
|
@@ -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:
|
|
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:
|
|
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 = {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
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
|
+
});
|