@nest-arch/tui 0.2.8 → 0.4.3
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 +20 -42
- package/dist/cli.js +1 -1
- package/dist/constants-B5MuV-iH.js +1 -0
- package/dist/index.js +365 -98
- package/dist/templates/addons/husky/pre-commit.hbs +11 -26
- package/dist/templates/base/.env.example.hbs +13 -2
- package/dist/templates/base/.env.hbs +11 -2
- package/dist/templates/base/.gitignore.hbs +2 -1
- package/dist/templates/base/.yarnrc.yml.hbs +0 -5
- package/dist/templates/base/README.md.hbs +49 -5
- package/dist/templates/base/nest-cli.json.hbs +2 -1
- package/dist/templates/base/pnpm-workspace.yaml.hbs +15 -0
- package/dist/templates/base/prisma.config.ts.hbs +32 -6
- package/dist/templates/base/src/app.controller.spec.ts.hbs +3 -11
- package/dist/templates/base/src/app.controller.ts.hbs +2 -2
- package/dist/templates/base/src/app.module.ts.hbs +76 -5
- package/dist/templates/base/src/app.router.ts.hbs +3 -4
- package/dist/templates/base/src/database/adapters/interfaces/db-adapter.interface.ts.hbs +7 -0
- package/dist/templates/base/src/database/adapters/mongo/prisma-mongo.adapter.ts.hbs +36 -4
- package/dist/templates/base/src/database/adapters/mongo/raw-mongo.adapter.ts.hbs +17 -12
- package/dist/templates/base/src/database/adapters/sql/drizzle-sql.adapter.ts.hbs +9 -0
- package/dist/templates/base/src/database/adapters/sql/prisma-sql.adapter.ts.hbs +8 -5
- package/dist/templates/base/src/database/adapters/sql/raw-sql.adapter.ts.hbs +37 -0
- package/dist/templates/base/src/database/adapters/sql/typeorm-sql.adapter.ts.hbs +8 -3
- package/dist/templates/base/src/database/db.module.ts.hbs +55 -42
- package/dist/templates/base/src/database/db.service.ts.hbs +60 -6
- package/dist/templates/base/src/database/entities/app.entity.ts.hbs +25 -0
- package/dist/templates/base/src/database/entities/todo.entity.ts.hbs +12 -7
- package/dist/templates/base/src/database/index.ts.hbs +20 -0
- package/dist/templates/base/src/database/orm/drizzle/schema.ts.hbs +80 -7
- package/dist/templates/base/src/database/orm/typeorm/data-source.ts.hbs +23 -4
- package/dist/templates/base/src/libs/middlewares/auth.trpc.middleware.ts.hbs +47 -0
- package/dist/templates/base/src/libs/middlewares/rate-limit.trpc.middleware.ts.hbs +43 -0
- package/dist/templates/base/src/libs/trpc/error.handler.ts.hbs +1 -1
- package/dist/templates/base/src/libs/trpc/inner.context.ts.hbs +6 -3
- package/dist/templates/base/src/main.ts.hbs +34 -10
- package/dist/templates/base/src/modules/users/entities/user.entity.ts.hbs +22 -0
- package/dist/templates/base/test/app.e2e-spec.ts.hbs +841 -6
- package/dist/templates/base/test/bootstrap.e2e-spec.ts.hbs +84 -0
- package/dist/templates/base/tsconfig.build.json.hbs +2 -0
- package/dist/templates/base/vitest.config.e2e.ts.hbs +4 -3
- package/dist/templates/base/vitest.config.ts.hbs +4 -3
- package/dist/templates/base/yarn.lock.hbs +1 -0
- package/dist/templates/extras/docker/.dockerignore.hbs +8 -1
- package/dist/templates/extras/docker/Dockerfile.hbs +11 -10
- package/dist/templates/extras/health/src/health/health.controller.ts.hbs +54 -0
- package/dist/templates/extras/health/src/health/health.module.ts.hbs +9 -0
- package/dist/templates/extras/swagger/create-docs.ts.hbs +13 -22
- package/dist/templates/feature/graphql/src/graphql/graphql.module.ts.hbs +6 -10
- package/dist/templates/feature/graphql/src/graphql/models/todo.model.ts.hbs +4 -0
- package/dist/templates/feature/graphql/src/graphql/orm/drizzle/drizzle-graphql.module.ts.hbs +6 -4
- package/dist/templates/feature/graphql/src/graphql/resolvers/health.resolver.ts.hbs +14 -0
- package/dist/templates/feature/graphql/src/graphql/resolvers/todo.resolver.ts.hbs +210 -47
- package/dist/templates/feature/rest/todo-example/src/api/todo/dto/create-todo.dto.ts.hbs +12 -0
- package/dist/templates/feature/rest/todo-example/src/api/todo/dto/update-todo.dto.ts.hbs +12 -0
- package/dist/templates/feature/rest/todo-example/src/api/todo/todo.controller.ts.hbs +21 -9
- package/dist/templates/feature/rest/todo-example/src/api/todo/todo.module.ts.hbs +1 -3
- package/dist/templates/feature/rest/todo-example/src/api/todo/todo.router.ts.hbs +41 -13
- package/dist/templates/feature/rest/todo-example/src/api/todo/todo.service.ts.hbs +157 -33
- package/dist/templates/monorepo/apps/api-gateway/package.json.hbs +2 -3
- package/dist/templates/monorepo/apps/api-gateway/src/app.controller.spec.ts.hbs +6 -1
- package/dist/templates/monorepo/apps/api-gateway/src/app.controller.ts.hbs +6 -0
- package/dist/templates/monorepo/apps/api-gateway/src/app.module.ts.hbs +32 -1
- package/dist/templates/monorepo/apps/api-gateway/src/app.service.ts.hbs +1 -1
- package/dist/templates/monorepo/apps/api-gateway/src/main.ts.hbs +13 -4
- package/dist/templates/monorepo/apps/api-gateway/test/app.e2e-spec.ts.hbs +45 -1
- package/dist/templates/monorepo/apps/api-gateway/tsconfig.build.json.hbs +2 -1
- package/dist/templates/monorepo/apps/api-gateway/vitest.config.e2e.ts.hbs +3 -2
- package/dist/templates/monorepo/apps/api-gateway/vitest.config.ts.hbs +3 -2
- package/dist/templates/monorepo/feature/graphql/src/graphql/graphql.module.ts.hbs +6 -10
- package/dist/templates/monorepo/feature/graphql/src/graphql/resolvers/health.resolver.ts.hbs +14 -0
- package/dist/templates/monorepo/feature/graphql/src/graphql/resolvers/todo.resolver.ts.hbs +151 -42
- package/dist/templates/monorepo/packages/env/src/api-gateway.ts.hbs +16 -3
- package/dist/templates/monorepo/packages/shared/package.json.hbs +1 -0
- package/dist/templates/monorepo/packages/shared/src/auth.ts.hbs +6 -0
- package/dist/templates/monorepo/root/.gitignore.hbs +1 -0
- package/dist/templates/monorepo/root/pnpm-workspace.yaml.hbs +19 -2
- package/dist/templates/monorepo/root/tsconfig.json.hbs +1 -1
- package/dist/templates/monorepo/root/turbo.json.hbs +2 -0
- package/dist/templates/single-project/architecture/nest-api/.env.hbs +9 -1
- package/dist/templates/single-project/architecture/nest-api/package.json.hbs +1 -2
- package/dist/templates/single-project/architecture/nest-api/src/main.ts.hbs +33 -9
- package/dist/templates/single-project/architecture/nest-gateway/src/main.ts.hbs +3 -3
- package/dist/templates/single-project/architecture/nest-microservice/.env.hbs +18 -0
- package/dist/templates/single-project/architecture/nest-microservice/proto/app.proto.hbs +26 -0
- package/dist/templates/single-project/architecture/nest-microservice/src/app.controller.ts.hbs +23 -4
- package/dist/templates/single-project/architecture/nest-microservice/src/app.service.ts.hbs +6 -2
- package/dist/templates/single-project/architecture/nest-microservice/src/main.ts.hbs +16 -5
- package/dist/templates/single-project/architecture/nest-microservice/test/microservice.e2e-spec.ts.hbs +70 -0
- package/dist/templates/single-project/shared/config/env.ts.hbs +38 -3
- package/package.json +5 -2
- package/dist/constants-Cgtoxhmd.js +0 -1
|
@@ -1,28 +1,39 @@
|
|
|
1
|
+
{{#if hasDatabase}}
|
|
1
2
|
{{#if (and hasAuth hasDatabase)}}
|
|
2
|
-
import { UseGuards } from "@nestjs/common";
|
|
3
|
+
import { BadRequestException, NotFoundException, UseGuards } from "@nestjs/common";
|
|
4
|
+
{{else}}
|
|
5
|
+
import { BadRequestException, NotFoundException } from "@nestjs/common";
|
|
3
6
|
{{/if}}
|
|
4
|
-
import { Args, Mutation, Query, Resolver } from "@nestjs/graphql";
|
|
5
7
|
{{#if (and hasAuth hasDatabase)}}
|
|
6
8
|
import { UserEntity } from "../../auth/decorators/index.js";
|
|
7
9
|
import { GqlAuthGuard } from "../../auth/guards/gql-auth.guard.js";
|
|
8
10
|
{{/if}}
|
|
9
|
-
import {
|
|
10
|
-
import { CreateTodoInput } from "../dto/create-todo.input.js";
|
|
11
|
-
import { UpdateTodoInput } from "../dto/update-todo.input.js";
|
|
11
|
+
import { Args, Mutation, Query, Resolver } from "@nestjs/graphql";
|
|
12
12
|
{{#if useTypeorm}}
|
|
13
|
-
import { GraphRelationBuilder } from "typeorm-relations-graphql";
|
|
14
13
|
import { GraphQLResolveInfo } from "graphql";
|
|
14
|
+
import { GraphRelationBuilder } from "typeorm-relations-graphql";
|
|
15
|
+
import { Todo as TodoEntity } from "@repo/db/src/entities/todo.entity.js";
|
|
15
16
|
{{/if}}
|
|
16
17
|
{{#if useDrizzle}}
|
|
18
|
+
import { and, eq } from "drizzle-orm";
|
|
17
19
|
import * as schema from "@repo/db/src/orm/drizzle/schema.js";
|
|
18
20
|
{{/if}}
|
|
19
|
-
{
|
|
21
|
+
import { DbService } from "@repo/db";
|
|
22
|
+
import { CreateTodoInput } from "../dto/create-todo.input.js";
|
|
23
|
+
import { UpdateTodoInput } from "../dto/update-todo.input.js";
|
|
24
|
+
import { Todo } from "../models/todo.model.js";
|
|
25
|
+
{{else}}
|
|
26
|
+
import { Args, Mutation, Query, Resolver } from "@nestjs/graphql";
|
|
27
|
+
import { CreateTodoInput } from "../dto/create-todo.input.js";
|
|
28
|
+
import { UpdateTodoInput } from "../dto/update-todo.input.js";
|
|
20
29
|
import { Todo } from "../models/todo.model.js";
|
|
21
30
|
{{/if}}
|
|
22
31
|
|
|
23
32
|
@Resolver(() => Todo)
|
|
24
33
|
export class TodoResolver {
|
|
34
|
+
{{#if hasDatabase}}
|
|
25
35
|
constructor(private readonly db: DbService) {}
|
|
36
|
+
{{/if}}
|
|
26
37
|
|
|
27
38
|
@Query(() => String)
|
|
28
39
|
hello(): string {
|
|
@@ -30,84 +41,182 @@ export class TodoResolver {
|
|
|
30
41
|
}{{#if hasDatabase}}
|
|
31
42
|
|
|
32
43
|
@Query(() => [Todo])
|
|
33
|
-
|
|
44
|
+
{{#if hasAuth}}
|
|
45
|
+
@UseGuards(GqlAuthGuard)
|
|
46
|
+
{{/if}}
|
|
47
|
+
todos({{#if useTypeorm}}info: GraphQLResolveInfo, {{/if}}{{#if hasAuth}}@UserEntity() user: { id: string }{{/if}}) {
|
|
34
48
|
{{#if useTypeorm}}
|
|
35
|
-
const builder = new GraphRelationBuilder(this.db.
|
|
49
|
+
const builder = new GraphRelationBuilder(this.db.typeorm);
|
|
36
50
|
const relations = builder.buildForQuery(Todo, info, "todos");
|
|
37
|
-
|
|
51
|
+
{{#if hasAuth}}
|
|
52
|
+
return this.db.typeorm.getRepository(TodoEntity).find({ relations, where: { authorId: user.id } });
|
|
53
|
+
{{else}}
|
|
54
|
+
return this.db.typeorm.getRepository(TodoEntity).find({ relations });
|
|
55
|
+
{{/if}}
|
|
56
|
+
{{else if isPrisma8}}
|
|
57
|
+
{{#if hasAuth}}
|
|
58
|
+
return ((this.db.prisma.orm.public as any).Todo).where({ authorId: user.id }).all();
|
|
59
|
+
{{else}}
|
|
60
|
+
return ((this.db.prisma.orm.public as any).Todo).all();
|
|
61
|
+
{{/if}}
|
|
38
62
|
{{else if usePrisma}}
|
|
63
|
+
{{#if hasAuth}}
|
|
64
|
+
return this.db.prisma.todo.findMany({ where: { authorId: user.id } });
|
|
65
|
+
{{else}}
|
|
39
66
|
return this.db.prisma.todo.findMany();
|
|
67
|
+
{{/if}}
|
|
40
68
|
{{else if useDrizzle}}
|
|
41
|
-
|
|
69
|
+
{{#if hasAuth}}
|
|
70
|
+
return this.db.drizzle.select().from(schema.todos).where(eq(schema.todos.authorId, user.id));
|
|
71
|
+
{{else}}
|
|
72
|
+
return this.db.drizzle.select().from(schema.todos);
|
|
73
|
+
{{/if}}
|
|
42
74
|
{{else}}
|
|
43
75
|
return [];
|
|
44
76
|
{{/if}}
|
|
45
77
|
}
|
|
46
78
|
|
|
79
|
+
{{#if hasAuth}}
|
|
47
80
|
@UseGuards(GqlAuthGuard)
|
|
81
|
+
{{/if}}
|
|
48
82
|
@Mutation(() => Todo)
|
|
49
|
-
createTodo(
|
|
83
|
+
async createTodo(
|
|
84
|
+
{{#if hasAuth}}
|
|
50
85
|
@UserEntity() user: { id: string },
|
|
86
|
+
{{/if}}
|
|
51
87
|
@Args("input") input: CreateTodoInput{{#if useTypeorm}}, info: GraphQLResolveInfo{{/if}}
|
|
52
88
|
) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
89
|
+
if (!input.title.trim()) throw new BadRequestException("Title must not be empty");
|
|
90
|
+
{{#if isPrisma8}}
|
|
91
|
+
{{#if hasAuth}}
|
|
92
|
+
return ((this.db.prisma.orm.public as any).Todo).create({ ...input, authorId: user.id });
|
|
93
|
+
{{else}}
|
|
94
|
+
return ((this.db.prisma.orm.public as any).Todo).create(input);
|
|
95
|
+
{{/if}}
|
|
96
|
+
{{else if usePrisma}}
|
|
97
|
+
{{#if hasAuth}}
|
|
98
|
+
const todo = await this.db.prisma.todo.create({ data: { ...input, authorId: user.id } });
|
|
99
|
+
{{else}}
|
|
100
|
+
const todo = await this.db.prisma.todo.create({ data: input });
|
|
101
|
+
{{/if}}
|
|
102
|
+
return todo;
|
|
103
|
+
{{else if useTypeorm}}
|
|
104
|
+
{{#if hasAuth}}
|
|
105
|
+
const entity = this.db.typeorm.getRepository(TodoEntity).create({ ...input, authorId: user.id });
|
|
106
|
+
{{else}}
|
|
107
|
+
const entity = this.db.typeorm.getRepository(TodoEntity).create(input);
|
|
108
|
+
{{/if}}
|
|
109
|
+
const saved = await this.db.typeorm.getRepository(TodoEntity).save(entity);
|
|
110
|
+
const builder = new GraphRelationBuilder(this.db.typeorm);
|
|
57
111
|
const relations = builder.buildForQuery(Todo, info, "createTodo");
|
|
58
|
-
return this.db.getRepository(
|
|
59
|
-
where: { id: saved.id },
|
|
112
|
+
return this.db.typeorm.getRepository(TodoEntity).findOneOrFail({
|
|
60
113
|
relations,
|
|
61
|
-
|
|
62
|
-
{{else if usePrisma}}
|
|
63
|
-
return this.db.prisma.todo.create({
|
|
64
|
-
data: { ...input, authorId: user.id },
|
|
114
|
+
where: { id: saved.id },
|
|
65
115
|
});
|
|
66
116
|
{{else if useDrizzle}}
|
|
67
|
-
|
|
117
|
+
{{#if hasAuth}}
|
|
118
|
+
const [todo] = await this.db.drizzle.insert(schema.todos).values({ ...input, authorId: user.id }).returning();
|
|
119
|
+
{{else}}
|
|
120
|
+
const [todo] = await this.db.drizzle.insert(schema.todos).values(input).returning();
|
|
121
|
+
{{/if}}
|
|
122
|
+
if (!todo) throw new NotFoundException("Todo not found");
|
|
68
123
|
return todo;
|
|
69
124
|
{{else}}
|
|
70
125
|
return { id: "1", ...input };
|
|
71
126
|
{{/if}}
|
|
72
127
|
}
|
|
73
128
|
|
|
129
|
+
{{#if hasAuth}}
|
|
74
130
|
@UseGuards(GqlAuthGuard)
|
|
131
|
+
{{/if}}
|
|
75
132
|
@Mutation(() => Todo)
|
|
76
|
-
updateTodo(
|
|
133
|
+
async updateTodo(
|
|
134
|
+
{{#if hasAuth}}
|
|
135
|
+
@UserEntity() user: { id: string },
|
|
136
|
+
{{/if}}
|
|
137
|
+
@Args("input") input: UpdateTodoInput{{#if useTypeorm}}, info: GraphQLResolveInfo{{/if}}
|
|
138
|
+
) {
|
|
77
139
|
const { id, ...data } = input;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
140
|
+
if (data.title !== undefined && !data.title.trim()) throw new BadRequestException("Title must not be empty");
|
|
141
|
+
{{#if isPrisma8}}
|
|
142
|
+
{{#if hasAuth}}
|
|
143
|
+
return ((this.db.prisma.orm.public as any).Todo).where({ authorId: user.id, id }).update(data);
|
|
144
|
+
{{else}}
|
|
145
|
+
return ((this.db.prisma.orm.public as any).Todo).where({ id }).update(data);
|
|
146
|
+
{{/if}}
|
|
147
|
+
{{else if usePrisma}}
|
|
148
|
+
{{#if hasAuth}}
|
|
149
|
+
const result = await this.db.prisma.todo.update({ data, where: { authorId: user.id, id } });
|
|
150
|
+
{{else}}
|
|
151
|
+
const result = await this.db.prisma.todo.update({ data, where: { id } });
|
|
152
|
+
{{/if}}
|
|
153
|
+
return result;
|
|
154
|
+
{{else if useTypeorm}}
|
|
155
|
+
{{#if hasAuth}}
|
|
156
|
+
const updateResult = await this.db.typeorm.getRepository(TodoEntity).update({ authorId: user.id, id }, data);
|
|
157
|
+
{{else}}
|
|
158
|
+
const updateResult = await this.db.typeorm.getRepository(TodoEntity).update(id, data);
|
|
159
|
+
{{/if}}
|
|
160
|
+
if ((updateResult.affected ?? 0) === 0) throw new NotFoundException("Todo not found");
|
|
161
|
+
const builder = new GraphRelationBuilder(this.db.typeorm);
|
|
81
162
|
const relations = builder.buildForQuery(Todo, info, "updateTodo");
|
|
82
|
-
return this.db.getRepository(
|
|
83
|
-
where: { id },
|
|
163
|
+
return this.db.typeorm.getRepository(TodoEntity).findOneOrFail({
|
|
84
164
|
relations,
|
|
165
|
+
where: { id },
|
|
85
166
|
});
|
|
86
|
-
{{else if usePrisma}}
|
|
87
|
-
return this.db.prisma.todo.update({ where: { id }, data });
|
|
88
167
|
{{else if useDrizzle}}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
168
|
+
{{#if hasAuth}}
|
|
169
|
+
const [todo] = await this.db.drizzle.update(schema.todos).set(data).where(and(eq(schema.todos.authorId, user.id), eq(schema.todos.id, Number(id)))).returning();
|
|
170
|
+
{{else}}
|
|
171
|
+
const [todo] = await this.db.drizzle.update(schema.todos).set(data).where(eq(schema.todos.id, Number(id))).returning();
|
|
172
|
+
{{/if}}
|
|
173
|
+
if (!todo) throw new NotFoundException("Todo not found");
|
|
94
174
|
return todo;
|
|
95
175
|
{{else}}
|
|
96
176
|
return { id, ...data };
|
|
97
177
|
{{/if}}
|
|
98
178
|
}
|
|
99
179
|
|
|
180
|
+
{{#if hasAuth}}
|
|
100
181
|
@UseGuards(GqlAuthGuard)
|
|
182
|
+
{{/if}}
|
|
101
183
|
@Mutation(() => Boolean)
|
|
102
|
-
async deleteTodo(
|
|
103
|
-
{{#if
|
|
104
|
-
|
|
105
|
-
|
|
184
|
+
async deleteTodo(
|
|
185
|
+
{{#if hasAuth}}
|
|
186
|
+
@UserEntity() user: { id: string },
|
|
187
|
+
{{/if}}
|
|
188
|
+
@Args("id") id: string
|
|
189
|
+
): Promise<boolean> {
|
|
190
|
+
{{#if isPrisma8}}
|
|
191
|
+
{{#if hasAuth}}
|
|
192
|
+
await ((this.db.prisma.orm.public as any).Todo).where({ authorId: user.id, id }).delete();
|
|
193
|
+
{{else}}
|
|
194
|
+
await ((this.db.prisma.orm.public as any).Todo).where({ id }).delete();
|
|
195
|
+
{{/if}}
|
|
196
|
+
return true;
|
|
106
197
|
{{else if usePrisma}}
|
|
107
|
-
|
|
198
|
+
{{#if hasAuth}}
|
|
199
|
+
const result = await this.db.prisma.todo.deleteMany({ where: { authorId: user.id, id } });
|
|
200
|
+
{{else}}
|
|
201
|
+
const result = await this.db.prisma.todo.deleteMany({ where: { id } });
|
|
202
|
+
{{/if}}
|
|
203
|
+
if (result.count === 0) throw new NotFoundException("Todo not found");
|
|
204
|
+
return true;
|
|
205
|
+
{{else if useTypeorm}}
|
|
206
|
+
{{#if hasAuth}}
|
|
207
|
+
const result = await this.db.typeorm.getRepository(TodoEntity).delete({ authorId: user.id, id });
|
|
208
|
+
{{else}}
|
|
209
|
+
const result = await this.db.typeorm.getRepository(TodoEntity).delete(id);
|
|
210
|
+
{{/if}}
|
|
211
|
+
if ((result.affected ?? 0) === 0) throw new NotFoundException("Todo not found");
|
|
108
212
|
return true;
|
|
109
213
|
{{else if useDrizzle}}
|
|
110
|
-
|
|
214
|
+
{{#if hasAuth}}
|
|
215
|
+
const deleted = await this.db.drizzle.delete(schema.todos).where(and(eq(schema.todos.authorId, user.id), eq(schema.todos.id, Number(id)))).returning();
|
|
216
|
+
{{else}}
|
|
217
|
+
const deleted = await this.db.drizzle.delete(schema.todos).where(eq(schema.todos.id, Number(id))).returning();
|
|
218
|
+
{{/if}}
|
|
219
|
+
if (deleted.length === 0) throw new NotFoundException("Todo not found");
|
|
111
220
|
return true;
|
|
112
221
|
{{else}}
|
|
113
222
|
return true;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "dotenv/config";
|
|
2
2
|
import { createEnv } from "@t3-oss/env-core";
|
|
3
|
-
import
|
|
3
|
+
import { z } from "zod";
|
|
4
4
|
|
|
5
5
|
export const env = createEnv({
|
|
6
6
|
/**
|
|
@@ -31,8 +31,9 @@ export const env = createEnv({
|
|
|
31
31
|
.default("development"),
|
|
32
32
|
PORT: z
|
|
33
33
|
.string()
|
|
34
|
-
.transform(
|
|
34
|
+
.transform(Number)
|
|
35
35
|
.default(3000),
|
|
36
|
+
TRUSTED_PROXY_IPS: z.string().default("{{#each trustedProxyIps}}{{#unless @first}},{{/unless}}{{this}}{{/each}}"),
|
|
36
37
|
{{#if hasPostgres}}
|
|
37
38
|
POSTGRES_URL: z.url(),
|
|
38
39
|
{{/if}}
|
|
@@ -51,9 +52,21 @@ export const env = createEnv({
|
|
|
51
52
|
.transform((val) => val === "true")
|
|
52
53
|
.default(true),
|
|
53
54
|
{{/if}}
|
|
54
|
-
{{#if (
|
|
55
|
+
{{#if (eq auth "passport")}}
|
|
55
56
|
JWT_ACCESS_SECRET: z.string().min(32),
|
|
57
|
+
{{#if hasDatabase}}
|
|
56
58
|
JWT_REFRESH_SECRET: z.string().min(32),
|
|
57
59
|
{{/if}}
|
|
60
|
+
{{/if}}
|
|
61
|
+
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
|
|
62
|
+
BETTER_AUTH_SECRET: z.string().min(32),
|
|
63
|
+
BETTER_AUTH_URL: z.url(),
|
|
64
|
+
{{#if (eq auth "better-auth:stateless")}}
|
|
65
|
+
OIDC_PROVIDER_ID: z.string().min(1),
|
|
66
|
+
OIDC_CLIENT_ID: z.string().min(1),
|
|
67
|
+
OIDC_CLIENT_SECRET: z.string().min(1),
|
|
68
|
+
OIDC_DISCOVERY_URL: z.url(),
|
|
69
|
+
{{/if}}
|
|
70
|
+
{{/if}}
|
|
58
71
|
},
|
|
59
72
|
});
|
|
@@ -2,8 +2,16 @@ packages:
|
|
|
2
2
|
- apps/*
|
|
3
3
|
- packages/*
|
|
4
4
|
allowBuilds:
|
|
5
|
+
{{#if useDrizzle}}
|
|
6
|
+
esbuild: true
|
|
7
|
+
{{/if}}
|
|
8
|
+
protobufjs: true
|
|
5
9
|
'@nestjs/core': true
|
|
6
10
|
esbuild: true
|
|
11
|
+
{{#if usePrisma}}
|
|
12
|
+
prisma: true
|
|
13
|
+
'@prisma/engines': true
|
|
14
|
+
{{/if}}
|
|
7
15
|
{{#if swagger}}
|
|
8
16
|
'@scarf/scarf': true
|
|
9
17
|
{{/if}}
|
|
@@ -16,8 +24,17 @@ allowBuilds:
|
|
|
16
24
|
{{#if hasSqlite}}
|
|
17
25
|
better-sqlite3: true
|
|
18
26
|
{{/if}}
|
|
27
|
+
{{#if isPrisma8}}
|
|
28
|
+
esbuild: true
|
|
29
|
+
msgpackr-extract: true
|
|
30
|
+
workerd: true
|
|
31
|
+
{{/if}}
|
|
19
32
|
catalog:
|
|
20
|
-
"@
|
|
33
|
+
"@nestjs/common": ^12.0.1
|
|
34
|
+
"@nestjs/core": ^12.0.1
|
|
35
|
+
"@types/node": ^24.0.0
|
|
21
36
|
dotenv: ^17.2.2
|
|
22
|
-
|
|
37
|
+
reflect-metadata: ^0.2.2
|
|
38
|
+
rxjs: ^7.8.1
|
|
39
|
+
typescript: {{#if useTypescript7}}^7.0.0{{else}}^6.0.2{{/if}}
|
|
23
40
|
zod: ^4.4.3
|
|
@@ -16,11 +16,19 @@ SQLITE_PATH=file:./src/database/dev.db
|
|
|
16
16
|
{{#if hasMongodb}}
|
|
17
17
|
MONGODB_URL=mongodb://localhost:27017/{{projectNameKebab}}_db
|
|
18
18
|
{{/if}}
|
|
19
|
-
{{#if (
|
|
19
|
+
{{#if (eq auth "passport")}}
|
|
20
20
|
JWT_ACCESS_SECRET=change-me-to-a-random-secret-at-least-32-characters-long
|
|
21
|
+
{{#if hasDatabase}}
|
|
21
22
|
JWT_REFRESH_SECRET=change-me-to-a-different-random-secret-at-least-32-characters
|
|
22
23
|
{{/if}}
|
|
24
|
+
{{/if}}
|
|
23
25
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
|
|
24
26
|
BETTER_AUTH_SECRET=change-me-to-a-random-secret-at-least-32-characters-long
|
|
25
27
|
BETTER_AUTH_URL=http://localhost:3000
|
|
28
|
+
{{#if (eq auth "better-auth:stateless")}}
|
|
29
|
+
OIDC_PROVIDER_ID=company-oidc
|
|
30
|
+
OIDC_CLIENT_ID=replace-with-provider-client-id
|
|
31
|
+
OIDC_CLIENT_SECRET=replace-with-provider-client-secret
|
|
32
|
+
OIDC_DISCOVERY_URL=https://identity.example.com/.well-known/openid-configuration
|
|
33
|
+
{{/if}}
|
|
26
34
|
{{/if}}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"test:debug": "vitest --inspect-brk --no-file-parallelism",
|
|
21
21
|
"test:e2e": "vitest run --config ./vitest.config.e2e.ts"{{#if hasUltracite}},
|
|
22
22
|
"check": "ultracite check",
|
|
23
|
-
"fix": "ultracite fix"{{/if}}{{#if hasHusky}},
|
|
23
|
+
"fix": "ultracite fix --ignore-pattern migrations/**"{{/if}}{{#if hasHusky}},
|
|
24
24
|
"prepare": "husky"{{/if}}
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
@@ -46,7 +46,6 @@
|
|
|
46
46
|
"source-map-support": "^0.5.21",
|
|
47
47
|
"supertest": "^7.0.0",
|
|
48
48
|
"typescript": "^6.0.2",
|
|
49
|
-
"vite-tsconfig-paths": "^5.1.4",
|
|
50
49
|
"vitest": "^4.1.2"
|
|
51
50
|
}
|
|
52
51
|
}
|
|
@@ -2,10 +2,18 @@ import { NestFactory } from "@nestjs/core";
|
|
|
2
2
|
{{#if (eq httpProvider "fastify")}}
|
|
3
3
|
import { FastifyAdapter, NestFastifyApplication } from "@nestjs/platform-fastify";
|
|
4
4
|
{{/if}}
|
|
5
|
+
{{#if (includes addons "nestjs-zod")}}
|
|
6
|
+
import { Logger } from "@nestjs/common";
|
|
7
|
+
import { ZodValidationPipe } from "nestjs-zod";
|
|
8
|
+
{{else}}
|
|
5
9
|
import { Logger, StandardSchemaValidationPipe } from "@nestjs/common";
|
|
10
|
+
{{/if}}
|
|
6
11
|
|
|
7
12
|
import { AppModule } from "./app.module.js";
|
|
8
13
|
import { env } from "./config/env.js";
|
|
14
|
+
{{#if isPrisma8}}
|
|
15
|
+
import { connectDatabase } from "./prisma/db.js";
|
|
16
|
+
{{/if}}
|
|
9
17
|
{{#if swagger}}
|
|
10
18
|
import { createDocs } from "./docs/create-docs.js";
|
|
11
19
|
{{/if}}
|
|
@@ -16,18 +24,34 @@ import { apiReference } from "@scalar/nestjs-api-reference";
|
|
|
16
24
|
import { SwaggerModule } from "@nestjs/swagger";
|
|
17
25
|
{{/if}}
|
|
18
26
|
{{#if (and swagger (or (eq auth "better-auth") (eq auth "better-auth:stateless")))}}
|
|
19
|
-
import {
|
|
27
|
+
import { AuthService } from "@thallesp/nestjs-better-auth";
|
|
20
28
|
{{/if}}
|
|
21
29
|
|
|
22
30
|
async function bootstrap() {
|
|
23
|
-
const
|
|
31
|
+
const trustedProxyIps = env.TRUSTED_PROXY_IPS
|
|
32
|
+
.split(",")
|
|
33
|
+
.map((ip) => ip.trim())
|
|
34
|
+
.filter(Boolean);
|
|
35
|
+
{{#if isPrisma8}}
|
|
36
|
+
await connectDatabase();
|
|
37
|
+
{{/if}}
|
|
38
|
+
const app = await NestFactory.create{{#if (eq httpProvider "fastify")}}<NestFastifyApplication>(AppModule, new FastifyAdapter({ trustProxy: trustedProxyIps })){{else}}(AppModule){{/if}};
|
|
39
|
+
{{#unless (eq httpProvider "fastify")}}
|
|
40
|
+
if (trustedProxyIps.length > 0) {
|
|
41
|
+
app.getHttpAdapter().getInstance().set("trust proxy", trustedProxyIps);
|
|
42
|
+
}
|
|
43
|
+
{{/unless}}
|
|
24
44
|
app.enableCors({
|
|
25
45
|
origin: env.CORS_ORIGIN,
|
|
26
46
|
});
|
|
27
47
|
{{#if hasRest}}
|
|
28
48
|
app.setGlobalPrefix("api");
|
|
29
49
|
{{/if}}
|
|
50
|
+
{{#if (includes addons "nestjs-zod")}}
|
|
51
|
+
app.useGlobalPipes(new ZodValidationPipe());
|
|
52
|
+
{{else}}
|
|
30
53
|
app.useGlobalPipes(new StandardSchemaValidationPipe());
|
|
54
|
+
{{/if}}
|
|
31
55
|
app.enableShutdownHooks();
|
|
32
56
|
{{#if swagger}}
|
|
33
57
|
if (env.NODE_ENV === "development") {
|
|
@@ -43,7 +67,7 @@ async function bootstrap() {
|
|
|
43
67
|
integrations: {
|
|
44
68
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
|
|
45
69
|
betterAuth: {
|
|
46
|
-
auth,
|
|
70
|
+
auth: app.get(AuthService).instance,
|
|
47
71
|
pathPrefix: "/api/auth",
|
|
48
72
|
},
|
|
49
73
|
{{/if}}
|
|
@@ -70,7 +94,7 @@ async function bootstrap() {
|
|
|
70
94
|
integrations: {
|
|
71
95
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
|
|
72
96
|
betterAuth: {
|
|
73
|
-
auth,
|
|
97
|
+
auth: app.get(AuthService).instance,
|
|
74
98
|
pathPrefix: "/api/auth",
|
|
75
99
|
},
|
|
76
100
|
{{/if}}
|
|
@@ -87,17 +111,17 @@ async function bootstrap() {
|
|
|
87
111
|
});
|
|
88
112
|
SwaggerModule.setup(docsPath, app, document);
|
|
89
113
|
{{/if}}
|
|
90
|
-
Logger.log(`Swagger documentation available at http://localhost:${env.PORT
|
|
114
|
+
Logger.log(`Swagger documentation available at http://localhost:${env.PORT}${docsPath}`, "SwaggerDocs");
|
|
91
115
|
}
|
|
92
116
|
{{/if}}
|
|
93
117
|
|
|
94
|
-
await app.listen(env.PORT
|
|
118
|
+
await app.listen(env.PORT);
|
|
95
119
|
{{#if hasRest}}
|
|
96
|
-
Logger.log(`Started backend server on http://localhost:${env.PORT
|
|
120
|
+
Logger.log(`Started backend server on http://localhost:${env.PORT}/api`, "Main");
|
|
97
121
|
{{else if hasTrpc}}
|
|
98
|
-
Logger.log(`Started trpc server on http://localhost:${env.PORT
|
|
122
|
+
Logger.log(`Started trpc server on http://localhost:${env.PORT}/trpc`, "Main");
|
|
99
123
|
{{else}}
|
|
100
|
-
Logger.log(`Started server on http://localhost:${env.PORT
|
|
124
|
+
Logger.log(`Started server on http://localhost:${env.PORT}`, "Main");
|
|
101
125
|
{{/if}}
|
|
102
126
|
}
|
|
103
127
|
await bootstrap();
|
|
@@ -16,7 +16,7 @@ import { apiReference } from "@scalar/nestjs-api-reference";
|
|
|
16
16
|
import { SwaggerModule } from "@nestjs/swagger";
|
|
17
17
|
{{/if}}
|
|
18
18
|
{{#if (and swagger (or (eq auth "better-auth") (eq auth "better-auth:stateless")))}}
|
|
19
|
-
import {
|
|
19
|
+
import { AuthService } from "@thallesp/nestjs-better-auth";
|
|
20
20
|
{{/if}}
|
|
21
21
|
|
|
22
22
|
async function bootstrap() {
|
|
@@ -39,7 +39,7 @@ async function bootstrap() {
|
|
|
39
39
|
integrations: {
|
|
40
40
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
|
|
41
41
|
betterAuth: {
|
|
42
|
-
auth,
|
|
42
|
+
auth: app.get(AuthService).instance,
|
|
43
43
|
pathPrefix: "/api/auth",
|
|
44
44
|
},
|
|
45
45
|
{{/if}}
|
|
@@ -66,7 +66,7 @@ async function bootstrap() {
|
|
|
66
66
|
integrations: {
|
|
67
67
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
|
|
68
68
|
betterAuth: {
|
|
69
|
-
auth,
|
|
69
|
+
auth: app.get(AuthService).instance,
|
|
70
70
|
pathPrefix: "/api/auth",
|
|
71
71
|
},
|
|
72
72
|
{{/if}}
|
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
PORT=3000
|
|
2
2
|
MICROSERVICE_PORT=3001
|
|
3
3
|
CORS_ORIGIN=http://localhost:3001
|
|
4
|
+
{{#if (includes microservices "redis")}}
|
|
5
|
+
REDIS_URL=redis://127.0.0.1:6379
|
|
6
|
+
{{/if}}
|
|
7
|
+
{{#if (includes microservices "mqtt")}}
|
|
8
|
+
MQTT_URL=mqtt://127.0.0.1:1883
|
|
9
|
+
{{/if}}
|
|
10
|
+
{{#if (includes microservices "nats")}}
|
|
11
|
+
NATS_URL=nats://127.0.0.1:4222
|
|
12
|
+
{{/if}}
|
|
13
|
+
{{#if (includes microservices "rabbitmq")}}
|
|
14
|
+
RABBITMQ_URL=amqp://127.0.0.1:5672
|
|
15
|
+
{{/if}}
|
|
16
|
+
{{#if (includes microservices "kafka")}}
|
|
17
|
+
KAFKA_BROKER=127.0.0.1:9092
|
|
18
|
+
{{/if}}
|
|
19
|
+
{{#if (includes microservices "grpc")}}
|
|
20
|
+
GRPC_URL=0.0.0.0:5000
|
|
21
|
+
{{/if}}
|
|
4
22
|
{{#if hasGraphql}}
|
|
5
23
|
GRAPHQL_PLAYGROUND=true
|
|
6
24
|
{{/if}}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
|
|
3
|
+
package app;
|
|
4
|
+
|
|
5
|
+
service AppService {
|
|
6
|
+
rpc Ping (PingRequest) returns (PingResponse);
|
|
7
|
+
rpc Log (LogRequest) returns (LogResponse);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
message PingRequest {}
|
|
11
|
+
|
|
12
|
+
message PingResponse {
|
|
13
|
+
string message = 1;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
message LogRequest {
|
|
17
|
+
string id = 1;
|
|
18
|
+
string source = 2;
|
|
19
|
+
string payload = 3;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
message LogResponse {
|
|
23
|
+
string id = 1;
|
|
24
|
+
string source = 2;
|
|
25
|
+
string payload = 3;
|
|
26
|
+
}
|
package/dist/templates/single-project/architecture/nest-microservice/src/app.controller.ts.hbs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Controller,
|
|
1
|
+
import { Controller, Get } from "@nestjs/common";
|
|
2
|
+
import { {{#if (includes microservices "grpc")}}GrpcMethod{{else}}MessagePattern{{/if}} } from "@nestjs/microservices";
|
|
2
3
|
|
|
3
4
|
import { AppService } from "./app.service.js";
|
|
4
5
|
|
|
@@ -6,13 +7,31 @@ import { AppService } from "./app.service.js";
|
|
|
6
7
|
export class AppController {
|
|
7
8
|
constructor(private readonly appService: AppService) {}
|
|
8
9
|
|
|
10
|
+
@Get()
|
|
11
|
+
getHello(): string {
|
|
12
|
+
return this.appService.getHello();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
{{#if (includes microservices "grpc")}}
|
|
16
|
+
@GrpcMethod("AppService", "Ping")
|
|
17
|
+
handleGrpcPing(): { message: string } {
|
|
18
|
+
return { message: this.appService.handlePing() };
|
|
19
|
+
}
|
|
20
|
+
@GrpcMethod("AppService", "Log")
|
|
21
|
+
handleGrpcLog(data: { id: string; source: string; payload: string }): { id: string; source: string; payload: string } {
|
|
22
|
+
return data;
|
|
23
|
+
}
|
|
24
|
+
{{else}}
|
|
9
25
|
@MessagePattern("ping")
|
|
10
26
|
handlePing(): string {
|
|
11
27
|
return this.appService.handlePing();
|
|
12
28
|
}
|
|
29
|
+
{{/if}}
|
|
13
30
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
31
|
+
{{#unless (includes microservices "grpc")}}
|
|
32
|
+
@MessagePattern("log")
|
|
33
|
+
handleLog(data: Record<string, unknown>): { received: Record<string, unknown> } {
|
|
34
|
+
return this.appService.handleLog(data);
|
|
17
35
|
}
|
|
36
|
+
{{/unless}}
|
|
18
37
|
}
|
|
@@ -9,11 +9,15 @@ export class AppService {
|
|
|
9
9
|
constructor(private readonly db: DbService) {}
|
|
10
10
|
|
|
11
11
|
{{/if}}
|
|
12
|
+
getHello(): string {
|
|
13
|
+
return "Hello World!";
|
|
14
|
+
}
|
|
15
|
+
|
|
12
16
|
handlePing(): string {
|
|
13
17
|
return "pong";
|
|
14
18
|
}
|
|
15
19
|
|
|
16
|
-
handleLog(data: Record<string, unknown>):
|
|
17
|
-
|
|
20
|
+
handleLog(data: Record<string, unknown>): { received: Record<string, unknown> } {
|
|
21
|
+
return { received: data };
|
|
18
22
|
}
|
|
19
23
|
}
|