@nest-arch/tui 0.2.7 → 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 (71) hide show
  1. package/README.md +20 -42
  2. package/dist/cli.js +1 -1
  3. package/dist/constants-C3xmDWeK.js +1 -0
  4. package/dist/index.js +295 -82
  5. package/dist/templates/base/.env.example.hbs +4 -2
  6. package/dist/templates/base/.env.hbs +4 -2
  7. package/dist/templates/base/.gitignore.hbs +2 -1
  8. package/dist/templates/base/.yarnrc.yml.hbs +0 -5
  9. package/dist/templates/base/README.md.hbs +33 -5
  10. package/dist/templates/base/nest-cli.json.hbs +2 -1
  11. package/dist/templates/base/pnpm-workspace.yaml.hbs +9 -0
  12. package/dist/templates/base/prisma.config.ts.hbs +32 -6
  13. package/dist/templates/base/src/app.controller.spec.ts.hbs +3 -11
  14. package/dist/templates/base/src/app.controller.ts.hbs +2 -2
  15. package/dist/templates/base/src/app.module.ts.hbs +19 -1
  16. package/dist/templates/base/src/app.router.ts.hbs +2 -2
  17. package/dist/templates/base/src/database/adapters/interfaces/db-adapter.interface.ts.hbs +7 -0
  18. package/dist/templates/base/src/database/adapters/mongo/prisma-mongo.adapter.ts.hbs +25 -1
  19. package/dist/templates/base/src/database/adapters/mongo/raw-mongo.adapter.ts.hbs +17 -12
  20. package/dist/templates/base/src/database/adapters/sql/drizzle-sql.adapter.ts.hbs +9 -0
  21. package/dist/templates/base/src/database/adapters/sql/prisma-sql.adapter.ts.hbs +7 -4
  22. package/dist/templates/base/src/database/adapters/sql/raw-sql.adapter.ts.hbs +37 -0
  23. package/dist/templates/base/src/database/adapters/sql/typeorm-sql.adapter.ts.hbs +8 -3
  24. package/dist/templates/base/src/database/db.module.ts.hbs +32 -35
  25. package/dist/templates/base/src/database/db.service.ts.hbs +40 -6
  26. package/dist/templates/base/src/database/entities/todo.entity.ts.hbs +12 -7
  27. package/dist/templates/base/src/database/index.ts.hbs +1 -0
  28. package/dist/templates/base/src/database/orm/drizzle/schema.ts.hbs +47 -5
  29. package/dist/templates/base/src/database/orm/typeorm/data-source.ts.hbs +12 -4
  30. package/dist/templates/base/src/libs/trpc/error.handler.ts.hbs +1 -1
  31. package/dist/templates/base/src/main.ts.hbs +21 -6
  32. package/dist/templates/base/test/app.e2e-spec.ts.hbs +208 -6
  33. package/dist/templates/base/test/bootstrap.e2e-spec.ts.hbs +74 -0
  34. package/dist/templates/base/tsconfig.build.json.hbs +2 -0
  35. package/dist/templates/base/tsconfig.json.hbs +1 -1
  36. package/dist/templates/base/vitest.config.e2e.ts.hbs +4 -3
  37. package/dist/templates/base/vitest.config.ts.hbs +4 -3
  38. package/dist/templates/base/yarn.lock.hbs +1 -0
  39. package/dist/templates/extras/docker/Dockerfile.hbs +4 -1
  40. package/dist/templates/extras/swagger/create-docs.ts.hbs +47 -119
  41. package/dist/templates/feature/graphql/src/graphql/graphql.module.ts.hbs +8 -1
  42. package/dist/templates/feature/graphql/src/graphql/models/todo.model.ts.hbs +4 -0
  43. package/dist/templates/feature/graphql/src/graphql/orm/drizzle/drizzle-graphql.module.ts.hbs +4 -3
  44. package/dist/templates/feature/graphql/src/graphql/resolvers/todo.resolver.ts.hbs +69 -24
  45. package/dist/templates/feature/rest/todo-example/src/api/todo/todo.controller.ts.hbs +3 -1
  46. package/dist/templates/feature/rest/todo-example/src/api/todo/todo.module.ts.hbs +1 -3
  47. package/dist/templates/feature/rest/todo-example/src/api/todo/todo.service.ts.hbs +98 -32
  48. package/dist/templates/monorepo/apps/api-gateway/package.json.hbs +0 -1
  49. package/dist/templates/monorepo/apps/api-gateway/src/app.controller.spec.ts.hbs +1 -1
  50. package/dist/templates/monorepo/apps/api-gateway/test/app.e2e-spec.ts.hbs +20 -1
  51. package/dist/templates/monorepo/apps/api-gateway/tsconfig.build.json.hbs +2 -1
  52. package/dist/templates/monorepo/apps/api-gateway/vitest.config.e2e.ts.hbs +3 -2
  53. package/dist/templates/monorepo/apps/api-gateway/vitest.config.ts.hbs +3 -2
  54. package/dist/templates/monorepo/feature/graphql/src/graphql/resolvers/todo.resolver.ts.hbs +24 -21
  55. package/dist/templates/monorepo/packages/env/src/api-gateway.ts.hbs +9 -3
  56. package/dist/templates/monorepo/root/.gitignore.hbs +1 -0
  57. package/dist/templates/monorepo/root/pnpm-workspace.yaml.hbs +9 -0
  58. package/dist/templates/monorepo/root/tsconfig.json.hbs +1 -1
  59. package/dist/templates/monorepo/root/turbo.json.hbs +2 -0
  60. package/dist/templates/single-project/architecture/nest-api/.env.hbs +3 -1
  61. package/dist/templates/single-project/architecture/nest-api/package.json.hbs +0 -1
  62. package/dist/templates/single-project/architecture/nest-api/src/main.ts.hbs +20 -5
  63. package/dist/templates/single-project/architecture/nest-microservice/.env.hbs +18 -0
  64. package/dist/templates/single-project/architecture/nest-microservice/proto/app.proto.hbs +13 -0
  65. package/dist/templates/single-project/architecture/nest-microservice/src/app.controller.ts.hbs +14 -1
  66. package/dist/templates/single-project/architecture/nest-microservice/src/app.service.ts.hbs +4 -0
  67. package/dist/templates/single-project/architecture/nest-microservice/src/main.ts.hbs +13 -2
  68. package/dist/templates/single-project/architecture/nest-microservice/test/microservice.e2e-spec.ts.hbs +64 -0
  69. package/dist/templates/single-project/shared/config/env.ts.hbs +27 -3
  70. package/package.json +7 -4
  71. package/dist/constants-Cgtoxhmd.js +0 -1
@@ -1,3 +1,37 @@
1
+ {{#if (and hasMongodb useRawSql)}}
2
+ import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
3
+ import { ObjectId, type WithId } from "mongodb";
4
+ import { DbService } from "../../database/db.service.js";
5
+ import { CreateTodoDto } from "./dto/create-todo.dto.js";
6
+ import { UpdateTodoDto } from "./dto/update-todo.dto.js";
7
+ interface TodoDocument { title: string; completed: boolean; description?: string; }
8
+ const serialize = ({ _id, ...todo }: WithId<TodoDocument>) => ({ ...todo, id: _id.toHexString() });
9
+ function objectId(id: string): ObjectId {
10
+ if (!/^[a-f0-9]{24}$/iu.test(id)) throw new BadRequestException("Invalid todo identifier");
11
+ return new ObjectId(id);
12
+ }
13
+ @Injectable()
14
+ export class TodoService {
15
+ constructor(private readonly db: DbService) {}
16
+ private get todos() { return this.db.raw.mongo.collection<TodoDocument>("todos"); }
17
+ async findAll() { return (await this.todos.find().sort({ _id: 1 }).limit(100).toArray()).map(serialize); }
18
+ async create(input: CreateTodoDto) {
19
+ const todo = { title: input.title, completed: input.completed ?? false, ...(input.description === undefined ? {} : { description: input.description }) };
20
+ const result = await this.todos.insertOne(todo);
21
+ return { ...todo, id: result.insertedId.toHexString() };
22
+ }
23
+ async update(id: string, input: UpdateTodoDto) {
24
+ const todo = await this.todos.findOneAndUpdate({ _id: objectId(id) }, { $set: input }, { returnDocument: "after" });
25
+ if (!todo) throw new NotFoundException("Todo not found");
26
+ return serialize(todo);
27
+ }
28
+ async delete(id: string) {
29
+ const result = await this.todos.deleteOne({ _id: objectId(id) });
30
+ if (result.deletedCount === 0) throw new NotFoundException("Todo not found");
31
+ return { message: "Todo deleted successfully" };
32
+ }
33
+ }
34
+ {{else}}
1
35
  import { Injectable } from "@nestjs/common";
2
36
  {{#if hasDatabase}}
3
37
  {{#if isMonorepo}}
@@ -7,8 +41,12 @@ import { DbService } from "../../database/db.service.js";
7
41
  {{/if}}
8
42
  {{#if useDrizzle}}
9
43
  import * as schema from "../../database/orm/drizzle/schema.js";
44
+ {{#if hasAuth}}
45
+ import { and, eq } from "drizzle-orm";
46
+ {{else}}
10
47
  import { eq } from "drizzle-orm";
11
48
  {{/if}}
49
+ {{/if}}
12
50
  {{#if useTypeorm}}
13
51
  import { Todo } from "../../database/entities/todo.entity.js";
14
52
  {{/if}}
@@ -33,83 +71,109 @@ export class TodoService {
33
71
  {{#if hasDatabase}}
34
72
  {{#if hasAuth}}
35
73
  findAll(authorId: string) {
36
- {{#if usePrisma}}
74
+ {{#if isPrisma8}}
75
+ return ((this.db.prisma.orm.public as any).Todo).where({ authorId }).all();
76
+ {{else if usePrisma}}
37
77
  return this.db.prisma.todo.findMany({ where: { authorId } });
38
78
  {{else if useTypeorm}}
39
- return this.db.getRepository(Todo).find({ where: { authorId } });
79
+ return this.db.typeorm.getRepository(Todo).find({ where: { authorId } });
40
80
  {{else if useDrizzle}}
41
- return this.db.select().from(schema.todos).where(eq(schema.todos.authorId, authorId));
81
+ return this.db.drizzle.select().from(schema.todos).where(eq(schema.todos.authorId, authorId));
42
82
  {{/if}}
43
83
  }
44
84
 
45
- create(input: CreateTodoDto, authorId: string) {
46
- {{#if usePrisma}}
47
- return this.db.prisma.todo.create({ data: { ...input, authorId } });
85
+ async create(input: CreateTodoDto, authorId: string) {
86
+ {{#if isPrisma8}}
87
+ return ((this.db.prisma.orm.public as any).Todo).create({ ...input, authorId });
88
+ {{else if usePrisma}}
89
+ const todo = await this.db.prisma.todo.create({ data: { ...input, authorId } });
90
+ return todo;
48
91
  {{else if useTypeorm}}
49
- return this.db.getRepository(Todo).save(this.db.getRepository(Todo).create({ ...input, authorId }));
92
+ const todo = await this.db.typeorm.getRepository(Todo).save(this.db.typeorm.getRepository(Todo).create({ ...input, authorId }));
93
+ return todo;
50
94
  {{else if useDrizzle}}
51
- return this.db.insert(schema.todos).values({ ...input, authorId }).returning();
95
+ return this.db.drizzle.insert(schema.todos).values({ ...input, authorId }).returning();
52
96
  {{/if}}
53
97
  }
54
98
 
55
- update(id: string, input: UpdateTodoDto, authorId: string) {
56
- {{#if usePrisma}}
57
- return this.db.prisma.todo.update({ data: input, where: { authorId, id } });
99
+ async update(id: string, input: UpdateTodoDto, authorId: string) {
100
+ {{#if isPrisma8}}
101
+ return ((this.db.prisma.orm.public as any).Todo).where({ authorId, id }).update(input);
102
+ {{else if usePrisma}}
103
+ const result = await this.db.prisma.todo.update({ data: input, where: { authorId, id } });
104
+ return result;
58
105
  {{else if useTypeorm}}
59
- return this.db.getRepository(Todo).update({ authorId, id }, input);
106
+ const result = await this.db.typeorm.getRepository(Todo).update({ authorId, id }, input);
107
+ return result;
60
108
  {{else if useDrizzle}}
61
- return this.db.update(schema.todos).set(input).where(eq(schema.todos.authorId, authorId) && eq(schema.todos.id, id)).returning();
109
+ return this.db.drizzle.update(schema.todos).set(input).where(and(eq(schema.todos.authorId, authorId), eq(schema.todos.id, Number(id)))).returning();
62
110
  {{/if}}
63
111
  }
64
112
 
65
113
  async delete(id: string, authorId: string) {
66
- {{#if usePrisma}}
114
+ {{#if isPrisma8}}
115
+ await ((this.db.prisma.orm.public as any).Todo).where({ authorId, id }).delete();
116
+ {{else if usePrisma}}
67
117
  await this.db.prisma.todo.delete({ where: { authorId, id } });
68
118
  {{else if useTypeorm}}
69
- await this.db.getRepository(Todo).delete({ authorId, id });
119
+ await this.db.typeorm.getRepository(Todo).delete({ authorId, id });
70
120
  {{else if useDrizzle}}
71
- await this.db.delete(schema.todos).where(eq(schema.todos.authorId, authorId) && eq(schema.todos.id, id));
121
+ await this.db.drizzle.delete(schema.todos).where(and(eq(schema.todos.authorId, authorId), eq(schema.todos.id, Number(id))));
72
122
  {{/if}}
73
123
  return { message: "Todo deleted successfully" };
74
124
  }
75
125
  {{else}}
76
126
  findAll() {
77
- {{#if usePrisma}}
127
+ {{#if isPrisma8}}
128
+ return ((this.db.prisma.orm.public as any).Todo).all();
129
+ {{else if usePrisma}}
78
130
  return this.db.prisma.todo.findMany();
79
131
  {{else if useTypeorm}}
80
- return this.db.getRepository(Todo).find();
132
+ return this.db.typeorm.getRepository(Todo).find();
81
133
  {{else if useDrizzle}}
82
- return this.db.select().from(schema.todos);
134
+ return this.db.drizzle.select().from(schema.todos);
83
135
  {{/if}}
84
136
  }
85
137
 
86
- create(input: CreateTodoDto) {
87
- {{#if usePrisma}}
88
- return this.db.prisma.todo.create({ data: input });
138
+ async create(input: CreateTodoDto) {
139
+ {{#if isPrisma8}}
140
+ return ((this.db.prisma.orm.public as any).Todo).create(input);
141
+ {{else if usePrisma}}
142
+ const todo = await this.db.prisma.todo.create({ data: input });
143
+ return todo;
89
144
  {{else if useTypeorm}}
90
- return this.db.getRepository(Todo).save(this.db.getRepository(Todo).create(input));
145
+ const todo = await this.db.typeorm.getRepository(Todo).save(this.db.typeorm.getRepository(Todo).create(input));
146
+ return todo;
91
147
  {{else if useDrizzle}}
92
- return this.db.insert(schema.todos).values(input).returning();
148
+ const [todo] = await this.db.drizzle.insert(schema.todos).values(input).returning();
149
+ return todo;
93
150
  {{/if}}
94
151
  }
95
152
 
96
- update(id: string, input: UpdateTodoDto) {
97
- {{#if usePrisma}}
98
- return this.db.prisma.todo.update({ data: input, where: { id } });
153
+ async update(id: string, input: UpdateTodoDto) {
154
+ {{#if isPrisma8}}
155
+ return ((this.db.prisma.orm.public as any).Todo).where({ id }).update(input);
156
+ {{else if usePrisma}}
157
+ const result = await this.db.prisma.todo.update({ data: input, where: { id } });
158
+ return result;
99
159
  {{else if useTypeorm}}
100
- return this.db.getRepository(Todo).update(id, input);
160
+ const result = await this.db.typeorm.getRepository(Todo).update(id, input);
161
+ return result;
101
162
  {{else if useDrizzle}}
102
- return this.db.update(schema.todos).set(input).where(eq(schema.todos.id, id)).returning();
163
+ const [todo] = await this.db.drizzle.update(schema.todos).set(input).where(eq(schema.todos.id, Number(id))).returning();
164
+ return todo;
103
165
  {{/if}}
104
166
  }
105
167
 
106
168
  async delete(id: string) {
107
- {{#if usePrisma}}
169
+ {{#if isPrisma8}}
170
+ await ((this.db.prisma.orm.public as any).Todo).where({ id }).delete();
171
+ {{else if usePrisma}}
108
172
  await this.db.prisma.todo.delete({ where: { id } });
109
173
  {{else if useTypeorm}}
110
- await this.db.getRepository(Todo).delete(id);
174
+ await this.db.typeorm.getRepository(Todo).delete(id);
111
175
  {{else if useDrizzle}}
112
- await this.db.delete(schema.todos).where(eq(schema.todos.id, id));
176
+ await this.db.drizzle.delete(schema.todos).where(eq(schema.todos.id, Number(id)));
113
177
  {{/if}}
114
178
  return { message: "Todo deleted successfully" };
115
179
  }
@@ -143,3 +207,5 @@ export class TodoService {
143
207
  }
144
208
  {{/if}}
145
209
  }
210
+
211
+ {{/if}}
@@ -45,7 +45,6 @@
45
45
  "source-map-support": "^0.5.21",
46
46
  "supertest": "^7.0.0",
47
47
  "typescript": "catalog:",
48
- "vite-tsconfig-paths": "^5.1.4",
49
48
  {{#if hasUltracite}}"ultracite": "7.8.0",{{/if}}
50
49
  "vitest": "^4.1.2"
51
50
  }
@@ -1,7 +1,7 @@
1
1
  // oxlint-disable vitest/require-mock-type-parameters
2
2
  import type { TestingModule } from "@nestjs/testing";
3
3
  import { Test } from "@nestjs/testing";
4
- import { beforeEach, describe, expect, it, vi } from "vitest";
4
+ import { beforeEach, describe, expect, it{{#if (or hasDatabase hasOrm)}}, vi{{/if}} } from "vitest";
5
5
 
6
6
  import { AppController } from "./app.controller.js";
7
7
  import { AppService } from "./app.service.js";
@@ -1,6 +1,10 @@
1
1
  import { INestApplication } from "@nestjs/common";
2
2
  import { Test, TestingModule } from "@nestjs/testing";
3
+ {{#if (eq httpProvider "fastify")}}
4
+ import { FastifyAdapter } from "@nestjs/platform-fastify";
5
+ {{/if}}
3
6
  import request from "supertest";
7
+ import { afterEach, beforeEach, describe, it } from "vitest";
4
8
  import type { App } from "supertest/types";
5
9
 
6
10
  import { AppModule } from "./../src/app.module.js";
@@ -13,15 +17,30 @@ describe("AppController (e2e)", () => {
13
17
  imports: [AppModule],
14
18
  }).compile();
15
19
 
20
+ {{#if (eq httpProvider "fastify")}}
21
+ app = moduleFixture.createNestApplication(new FastifyAdapter());
22
+ {{else}}
16
23
  app = moduleFixture.createNestApplication();
24
+ {{/if}}
17
25
  await app.init();
26
+ {{#if (eq httpProvider "fastify")}}
27
+ await app.getHttpAdapter().getInstance().ready();
28
+ {{/if}}
18
29
  });
19
30
 
20
31
  it("/ (GET)", () => {
21
32
  return request(app.getHttpServer()).get("/").expect(200).expect("Hello World!");
22
33
  });
23
34
 
35
+ it("returns 404 for an unknown route", async () => {
36
+ await request(app.getHttpServer()).get("/__missing_route__").expect(404);
37
+ });
38
+
39
+ it("rejects unsupported methods", async () => {
40
+ await request(app.getHttpServer()).post("/").send({ unexpected: true }).expect(404);
41
+ });
42
+
24
43
  afterEach(async () => {
25
- await app.close();
44
+ await app?.close();
26
45
  });
27
46
  });
@@ -2,7 +2,8 @@
2
2
  "$schema": "https://json.schemastore.org/tsconfig",
3
3
  "extends": "./tsconfig.json",
4
4
  "compilerOptions": {
5
- "outDir": "./dist"
5
+ "outDir": "./dist",
6
+ "rootDir": "./src"
6
7
  },
7
8
  "include": ["src/**/*"],
8
9
  "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
@@ -1,8 +1,9 @@
1
1
  import { defineConfig } from "vitest/config";
2
- import tsconfigPaths from "vite-tsconfig-paths";
3
2
 
4
3
  export default defineConfig({
5
- plugins: [tsconfigPaths()],
4
+ resolve: {
5
+ tsconfigPaths: true,
6
+ },
6
7
  test: {
7
8
  globals: true,
8
9
  root: "./",
@@ -1,8 +1,9 @@
1
1
  import { defineConfig } from "vitest/config";
2
- import tsconfigPaths from "vite-tsconfig-paths";
3
2
 
4
3
  export default defineConfig({
5
- plugins: [tsconfigPaths()],
4
+ resolve: {
5
+ tsconfigPaths: true,
6
+ },
6
7
  test: {
7
8
  globals: true,
8
9
  root: "./",
@@ -2,9 +2,13 @@
2
2
  import { UseGuards } from "@nestjs/common";
3
3
  {{/if}}
4
4
  import { Args, Mutation, Query, Resolver } from "@nestjs/graphql";
5
+ {{#if (and hasAuth hasDatabase)}}
6
+ import { UserEntity } from "../../auth/decorators/index.js";
7
+ import { GqlAuthGuard } from "../../auth/guards/gql-auth.guard.js";
8
+ {{/if}}
9
+ import { DbService } from "@repo/db";
5
10
  import { CreateTodoInput } from "../dto/create-todo.input.js";
6
11
  import { UpdateTodoInput } from "../dto/update-todo.input.js";
7
- import { DbService } from "@repo/db";
8
12
  {{#if useTypeorm}}
9
13
  import { GraphRelationBuilder } from "typeorm-relations-graphql";
10
14
  import { GraphQLResolveInfo } from "graphql";
@@ -14,11 +18,9 @@ import * as schema from "@repo/db/src/orm/drizzle/schema.js";
14
18
  {{/if}}
15
19
  {{#if (and hasAuth hasDatabase)}}
16
20
  import { Todo } from "../models/todo.model.js";
17
- import { UserEntity } from "../../auth/decorators/index.js";
18
- import { GqlAuthGuard } from "../../auth/guards/gql-auth.guard.js";
19
21
  {{/if}}
20
22
 
21
- @Resolver({{#if (and hasAuth hasDatabase)}}{{"("}}() => Todo){{/if}})
23
+ @Resolver(() => Todo)
22
24
  export class TodoResolver {
23
25
  constructor(private readonly db: DbService) {}
24
26
 
@@ -28,11 +30,13 @@ export class TodoResolver {
28
30
  }{{#if hasDatabase}}
29
31
 
30
32
  @Query(() => [Todo])
31
- todos({{#if useTypeorm}}info: GraphQLResolveInfo{{/if}}): Promise<Todo[]> {
33
+ todos({{#if useTypeorm}}info: GraphQLResolveInfo{{/if}}) {
32
34
  {{#if useTypeorm}}
33
35
  const builder = new GraphRelationBuilder(this.db.getDataSource());
34
36
  const relations = builder.buildForQuery(Todo, info, "todos");
35
37
  return this.db.getRepository(Todo).find({ relations });
38
+ {{else if isPrisma8}}
39
+ return ((this.db.prisma.orm.public as any).Todo).all();
36
40
  {{else if usePrisma}}
37
41
  return this.db.prisma.todo.findMany();
38
42
  {{else if useDrizzle}}
@@ -42,14 +46,12 @@ export class TodoResolver {
42
46
  {{/if}}
43
47
  }
44
48
 
45
- @Mutation(() => Todo)
46
- {{#if (and hasAuth hasDatabase)}}
47
49
  @UseGuards(GqlAuthGuard)
48
- {{/if}}
50
+ @Mutation(() => Todo)
49
51
  createTodo(
50
- @Args("input") input: CreateTodoInput{{#if (and hasAuth hasDatabase)}},
51
- @UserEntity() user: { id: string }{{/if}}{{#if useTypeorm}}, info: GraphQLResolveInfo{{/if}}
52
- ): Promise<Todo> {
52
+ @UserEntity() user: { id: string },
53
+ @Args("input") input: CreateTodoInput{{#if useTypeorm}}, info: GraphQLResolveInfo{{/if}}
54
+ ) {
53
55
  {{#if useTypeorm}}
54
56
  const entity = this.db.getRepository(Todo).create(input);
55
57
  const saved = await this.db.getRepository(Todo).save(entity);
@@ -59,9 +61,11 @@ export class TodoResolver {
59
61
  where: { id: saved.id },
60
62
  relations,
61
63
  });
64
+ {{else if isPrisma8}}
65
+ return ((this.db.prisma.orm.public as any).Todo).create({ ...input, authorId: user.id });
62
66
  {{else if usePrisma}}
63
67
  return this.db.prisma.todo.create({
64
- data: { ...input{{#if (and hasAuth hasDatabase)}}, authorId: user.id{{/if}} },
68
+ data: { ...input, authorId: user.id },
65
69
  });
66
70
  {{else if useDrizzle}}
67
71
  const [todo] = await this.db.insert(schema.todos).values(input).returning();
@@ -71,13 +75,9 @@ export class TodoResolver {
71
75
  {{/if}}
72
76
  }
73
77
 
74
- @Mutation(() => Todo)
75
- {{#if (and hasAuth hasDatabase)}}
76
78
  @UseGuards(GqlAuthGuard)
77
- {{/if}}
78
- updateTodo(
79
- @Args("input") input: UpdateTodoInput{{#if useTypeorm}}, info: GraphQLResolveInfo{{/if}}
80
- ): Promise<Todo> {
79
+ @Mutation(() => Todo)
80
+ updateTodo(@Args("input") input: UpdateTodoInput{{#if useTypeorm}}, info: GraphQLResolveInfo{{/if}}) {
81
81
  const { id, ...data } = input;
82
82
  {{#if useTypeorm}}
83
83
  await this.db.getRepository(Todo).update(id, data);
@@ -87,6 +87,8 @@ export class TodoResolver {
87
87
  where: { id },
88
88
  relations,
89
89
  });
90
+ {{else if isPrisma8}}
91
+ return ((this.db.prisma.orm.public as any).Todo).where({ id }).update(data);
90
92
  {{else if usePrisma}}
91
93
  return this.db.prisma.todo.update({ where: { id }, data });
92
94
  {{else if useDrizzle}}
@@ -101,14 +103,15 @@ export class TodoResolver {
101
103
  {{/if}}
102
104
  }
103
105
 
104
- @Mutation(() => Boolean)
105
- {{#if (and hasAuth hasDatabase)}}
106
106
  @UseGuards(GqlAuthGuard)
107
- {{/if}}
107
+ @Mutation(() => Boolean)
108
108
  async deleteTodo(@Args("id") id: string): Promise<boolean> {
109
109
  {{#if useTypeorm}}
110
110
  const result = await this.db.getRepository(Todo).delete(id);
111
111
  return (result.affected ?? 0) > 0;
112
+ {{else if isPrisma8}}
113
+ await ((this.db.prisma.orm.public as any).Todo).where({ id }).delete();
114
+ return true;
112
115
  {{else if usePrisma}}
113
116
  await this.db.prisma.todo.delete({ where: { id } });
114
117
  return true;
@@ -1,6 +1,6 @@
1
1
  import "dotenv/config";
2
2
  import { createEnv } from "@t3-oss/env-core";
3
- import * as z from "zod";
3
+ import { z } from "zod";
4
4
 
5
5
  export const env = createEnv({
6
6
  /**
@@ -31,7 +31,7 @@ export const env = createEnv({
31
31
  .default("development"),
32
32
  PORT: z
33
33
  .string()
34
- .transform((val) => Number.parseInt(val, 10))
34
+ .transform(Number)
35
35
  .default(3000),
36
36
  {{#if hasPostgres}}
37
37
  POSTGRES_URL: z.url(),
@@ -51,9 +51,15 @@ export const env = createEnv({
51
51
  .transform((val) => val === "true")
52
52
  .default(true),
53
53
  {{/if}}
54
- {{#if (and (eq auth "passport") hasDatabase)}}
54
+ {{#if (eq auth "passport")}}
55
55
  JWT_ACCESS_SECRET: z.string().min(32),
56
+ {{#if hasDatabase}}
56
57
  JWT_REFRESH_SECRET: z.string().min(32),
57
58
  {{/if}}
59
+ {{/if}}
60
+ {{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
61
+ BETTER_AUTH_SECRET: z.string().min(32),
62
+ BETTER_AUTH_URL: z.url(),
63
+ {{/if}}
58
64
  },
59
65
  });
@@ -13,6 +13,7 @@ prisma/generated
13
13
 
14
14
  # Environment variables
15
15
  .env
16
+ .env.test
16
17
  .env*.local
17
18
 
18
19
  # IDEs and editors
@@ -2,6 +2,10 @@ 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
7
11
  {{#if swagger}}
@@ -16,6 +20,11 @@ allowBuilds:
16
20
  {{#if hasSqlite}}
17
21
  better-sqlite3: true
18
22
  {{/if}}
23
+ {{#if isPrisma8}}
24
+ esbuild: true
25
+ msgpackr-extract: true
26
+ workerd: true
27
+ {{/if}}
19
28
  catalog:
20
29
  "@types/node": ^22.13.14
21
30
  dotenv: ^17.2.2
@@ -1,3 +1,3 @@
1
1
  {
2
- "extends": "@repo-config/config/tsconfig.base.json"
2
+ "extends": "@repo/config/tsconfig.base.json"
3
3
  }
@@ -10,6 +10,8 @@
10
10
  "lint": {
11
11
  "dependsOn": ["^lint"]
12
12
  },
13
+ "test": { "cache": false },
14
+ "test:e2e": { "cache": false },
13
15
  "check-types": {
14
16
  "dependsOn": ["^check-types"]
15
17
  },
@@ -16,10 +16,12 @@ 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 (and (eq auth "passport") hasDatabase)}}
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
@@ -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}}
@@ -20,6 +28,9 @@ import { auth } from "./auth/auth.js";
20
28
  {{/if}}
21
29
 
22
30
  async function bootstrap() {
31
+ {{#if isPrisma8}}
32
+ await connectDatabase();
33
+ {{/if}}
23
34
  const app = await NestFactory.create{{#if (eq httpProvider "fastify")}}<NestFastifyApplication>(AppModule, new FastifyAdapter()){{else}}(AppModule){{/if}};
24
35
  app.enableCors({
25
36
  origin: env.CORS_ORIGIN,
@@ -27,7 +38,11 @@ async function bootstrap() {
27
38
  {{#if hasRest}}
28
39
  app.setGlobalPrefix("api");
29
40
  {{/if}}
41
+ {{#if (includes addons "nestjs-zod")}}
42
+ app.useGlobalPipes(new ZodValidationPipe());
43
+ {{else}}
30
44
  app.useGlobalPipes(new StandardSchemaValidationPipe());
45
+ {{/if}}
31
46
  app.enableShutdownHooks();
32
47
  {{#if swagger}}
33
48
  if (env.NODE_ENV === "development") {
@@ -87,17 +102,17 @@ async function bootstrap() {
87
102
  });
88
103
  SwaggerModule.setup(docsPath, app, document);
89
104
  {{/if}}
90
- Logger.log(`Swagger documentation available at http://localhost:${env.PORT ?? 3000}${docsPath}`, "SwaggerDocs");
105
+ Logger.log(`Swagger documentation available at http://localhost:${env.PORT}${docsPath}`, "SwaggerDocs");
91
106
  }
92
107
  {{/if}}
93
108
 
94
- await app.listen(env.PORT ?? 3000);
109
+ await app.listen(env.PORT);
95
110
  {{#if hasRest}}
96
- Logger.log(`Started backend server on http://localhost:${env.PORT ?? 3000}/api`, "Main");
111
+ Logger.log(`Started backend server on http://localhost:${env.PORT}/api`, "Main");
97
112
  {{else if hasTrpc}}
98
- Logger.log(`Started trpc server on http://localhost:${env.PORT ?? 3000}/trpc`, "Main");
113
+ Logger.log(`Started trpc server on http://localhost:${env.PORT}/trpc`, "Main");
99
114
  {{else}}
100
- Logger.log(`Started server on http://localhost:${env.PORT ?? 3000}`, "Main");
115
+ Logger.log(`Started server on http://localhost:${env.PORT}`, "Main");
101
116
  {{/if}}
102
117
  }
103
118
  await bootstrap();
@@ -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,13 @@
1
+ syntax = "proto3";
2
+
3
+ package app;
4
+
5
+ service AppService {
6
+ rpc Ping (PingRequest) returns (PingResponse);
7
+ }
8
+
9
+ message PingRequest {}
10
+
11
+ message PingResponse {
12
+ string message = 1;
13
+ }
@@ -1,4 +1,5 @@
1
- import { Controller, EventPattern, MessagePattern } from "@nestjs/common";
1
+ import { Controller, Get } from "@nestjs/common";
2
+ import { EventPattern, {{#if (includes microservices "grpc")}}GrpcMethod{{else}}MessagePattern{{/if}} } from "@nestjs/microservices";
2
3
 
3
4
  import { AppService } from "./app.service.js";
4
5
 
@@ -6,10 +7,22 @@ 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
+ {{else}}
9
21
  @MessagePattern("ping")
10
22
  handlePing(): string {
11
23
  return this.appService.handlePing();
12
24
  }
25
+ {{/if}}
13
26
 
14
27
  @EventPattern("log")
15
28
  handleLog(data: Record<string, unknown>): void {
@@ -9,6 +9,10 @@ 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
  }