@nest-arch/tui 0.1.48 → 0.2.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 (30) hide show
  1. package/dist/cli.js +1 -1
  2. package/dist/constants-BbJ71cex.js +1 -0
  3. package/dist/index.js +61 -61
  4. package/dist/templates/base/.gitignore.hbs +3 -0
  5. package/dist/templates/base/README.md.hbs +119 -6
  6. package/dist/templates/base/pnpm-workspace.yaml.hbs +3 -0
  7. package/dist/templates/base/src/app.controller.ts.hbs +10 -0
  8. package/dist/templates/base/src/app.module.ts.hbs +33 -4
  9. package/dist/templates/base/src/app.router.spec.ts.hbs +58 -0
  10. package/dist/templates/base/src/app.router.ts.hbs +26 -0
  11. package/dist/templates/base/src/database/adapters/interfaces/db-adapter.interface.ts.hbs +3 -3
  12. package/dist/templates/base/src/libs/middlewares/auth.trpc.middleware.ts.hbs +42 -0
  13. package/dist/templates/base/src/libs/trpc/context.ts.hbs +13 -0
  14. package/dist/templates/base/src/libs/trpc/error.handler.ts.hbs +10 -0
  15. package/dist/templates/base/src/libs/trpc/inner.context.ts.hbs +7 -0
  16. package/dist/templates/base/src/libs/trpc/protected.ts.hbs +12 -0
  17. package/dist/templates/base/src/libs/trpc/scripts/fix-trpc-generated.mjs.hbs +21 -0
  18. package/dist/templates/base/src/libs/trpc/scripts/watch-trpc.mjs.hbs +91 -0
  19. package/dist/templates/base/src/main.ts.hbs +74 -1
  20. package/dist/templates/extras/swagger/create-docs.ts.hbs +232 -0
  21. package/dist/templates/monorepo/apps/api-gateway/src/app.controller.ts.hbs +10 -0
  22. package/dist/templates/monorepo/apps/api-gateway/src/app.module.ts.hbs +26 -1
  23. package/dist/templates/monorepo/apps/api-gateway/src/main.ts.hbs +73 -0
  24. package/dist/templates/monorepo/root/pnpm-workspace.yaml.hbs +3 -0
  25. package/dist/templates/single-project/architecture/nest-api/pnpm-workspace.yaml.hbs +3 -0
  26. package/dist/templates/single-project/architecture/nest-api/src/main.ts.hbs +73 -0
  27. package/dist/templates/single-project/architecture/nest-gateway/src/main.ts.hbs +73 -0
  28. package/dist/templates/single-project/architecture/nest-microservice/src/main.ts.hbs +74 -0
  29. package/package.json +3 -3
  30. package/dist/constants-D_Ow0fiZ.js +0 -1
@@ -6,6 +6,9 @@
6
6
  # Prisma generated
7
7
  **/prisma/generated
8
8
 
9
+ # Trpc generated
10
+ **/trpc/@generated
11
+
9
12
  # Logs
10
13
  logs
11
14
  *.log
@@ -36,22 +36,54 @@ npm run start{{/if}}
36
36
  {{#if isPnpm}}pnpm test:cov{{else if isYarn}}yarn test:cov{{else if isBun}}bun run test:cov{{else}}npm run test:cov{{/if}}
37
37
  ```
38
38
 
39
- {{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
40
- ## Auth Setup
39
+ {{#if usePrisma}}
40
+ ## Database Setup
41
41
 
42
- This project uses **Better Auth**. Generate the database schema by running:
42
+ This project uses **Prisma** as the ORM. Available commands:
43
43
 
44
44
  ```bash
45
- {{#if isPnpm}}pnpm dlx auth@latest generate --config src/auth/auth.ts --output src/database/orm/prisma/schema.prisma -y{{else if isYarn}}yarn dlx auth@latest generate --config src/auth/auth.ts --output src/database/orm/prisma/schema.prisma -y{{else if isBun}}bun x auth@latest generate --config src/auth/auth.ts --output src/database/orm/prisma/schema.prisma -y{{else}}npx auth@latest generate --config src/auth/auth.ts --output src/database/orm/prisma/schema.prisma -y{{/if}}
45
+ {{#if isPnpm}}pnpm prisma:generate{{else if isYarn}}yarn prisma:generate{{else if isBun}}bun run prisma:generate{{else}}npm run prisma:generate{{/if}}
46
+ {{#if isPnpm}}pnpm prisma:push{{else if isYarn}}yarn prisma:push{{else if isBun}}bun run prisma:push{{else}}npm run prisma:push{{/if}}
47
+ {{#if isPnpm}}pnpm prisma:studio{{else if isYarn}}yarn prisma:studio{{else if isBun}}bun run prisma:studio{{else}}npm run prisma:studio{{/if}}
48
+ {{#if isPnpm}}pnpm prisma:migrate{{else if isYarn}}yarn prisma:migrate{{else if isBun}}bun run prisma:migrate{{else}}npm run prisma:migrate{{/if}}
49
+ {{#if isPnpm}}pnpm prisma:migrate:deploy{{else if isYarn}}yarn prisma:migrate:deploy{{else if isBun}}bun run prisma:migrate:deploy{{else}}npm run prisma:migrate:deploy{{/if}}
46
50
  ```
51
+ {{/if}}
52
+
53
+ {{#if useDrizzle}}
54
+ ## Database Setup
47
55
 
48
- {{#if useDrizzle}}Then run Drizzle migrations:
56
+ This project uses **Drizzle** as the ORM. Available commands:
49
57
 
50
58
  ```bash
51
- {{#if isPnpm}}pnpm drizzle-kit generate && pnpm drizzle-kit migrate{{else if isYarn}}yarn drizzle-kit generate && yarn drizzle-kit migrate{{else}}npx drizzle-kit generate && npx drizzle-kit migrate{{/if}}
59
+ {{#if isPnpm}}pnpm db:generate{{else if isYarn}}yarn db:generate{{else if isBun}}bun run db:generate{{else}}npm run db:generate{{/if}}
60
+ {{#if isPnpm}}pnpm db:migrate{{else if isYarn}}yarn db:migrate{{else if isBun}}bun run db:migrate{{else}}npm run db:migrate{{/if}}
61
+ {{#if isPnpm}}pnpm db:studio{{else if isYarn}}yarn db:studio{{else if isBun}}bun run db:studio{{else}}npm run db:studio{{/if}}
62
+ {{#if isPnpm}}pnpm db:push{{else if isYarn}}yarn db:push{{else if isBun}}bun run db:push{{else}}npm run db:push{{/if}}
52
63
  ```
64
+ {{/if}}
65
+
66
+ {{#if useTypeorm}}
67
+ ## Database Setup
53
68
 
69
+ This project uses **TypeORM** as the ORM. Available commands:
70
+
71
+ ```bash
72
+ {{#if isPnpm}}pnpm typeorm:run{{else if isYarn}}yarn typeorm:run{{else if isBun}}bun run typeorm:run{{else}}npm run typeorm:run{{/if}}
73
+ {{#if isPnpm}}pnpm typeorm:revert{{else if isYarn}}yarn typeorm:revert{{else if isBun}}bun run typeorm:revert{{else}}npm run typeorm:revert{{/if}}
74
+ {{#if isPnpm}}pnpm typeorm:generate{{else if isYarn}}yarn typeorm:generate{{else if isBun}}bun run typeorm:generate{{else}}npm run typeorm:generate{{/if}}
75
+ {{#if isPnpm}}pnpm typeorm:create{{else if isYarn}}yarn typeorm:create{{else if isBun}}bun run typeorm:create{{else}}npm run typeorm:create{{/if}}
76
+ ```
54
77
  {{/if}}
78
+
79
+ {{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
80
+ ## Auth Setup
81
+
82
+ This project uses **Better Auth**. Generate the database schema by running:
83
+
84
+ ```bash
85
+ {{#if isPnpm}}pnpm dlx auth@latest generate --config src/auth/auth.ts --output src/database/orm/prisma/schema.prisma -y{{else if isYarn}}yarn dlx auth@latest generate --config src/auth/auth.ts --output src/database/orm/prisma/schema.prisma -y{{else if isBun}}bun x auth@latest generate --config src/auth/auth.ts --output src/database/orm/prisma/schema.prisma -y{{else}}npx auth@latest generate --config src/auth/auth.ts --output src/database/orm/prisma/schema.prisma -y{{/if}}
86
+ ```
55
87
  See https://better-auth.com/docs/adapters/prisma for more details.
56
88
 
57
89
  ### Usage
@@ -72,3 +104,84 @@ export class AppController {
72
104
  }
73
105
  ```
74
106
  {{/if}}
107
+ {{#if hasTrpc}}
108
+ ## tRPC Setup
109
+
110
+ This project uses **nestjs-trpc** with decorator-based routing.
111
+
112
+ ### Generating tRPC Types
113
+
114
+ After creating or modifying routers, generate the tRPC types:
115
+
116
+ ```bash
117
+ {{#if isPnpm}}pnpm trpc:generate{{else if isYarn}}yarn trpc:generate{{else if isBun}}bun run trpc:generate{{else}}npm run trpc:generate{{/if}}
118
+ ```
119
+
120
+ For watch mode (auto-regenerates on changes):
121
+
122
+ ```bash
123
+ {{#if isPnpm}}pnpm trpc:watch{{else if isYarn}}yarn trpc:watch{{else if isBun}}bun run trpc:watch{{else}}npm run trpc:watch{{/if}}
124
+ ```
125
+
126
+ {{#if hasTrpcAndAuth}}
127
+ ### Router Example (with Auth)
128
+
129
+ Routers are defined using the `@Router` decorator from `nestjs-trpc`. **Router names must start with a lowercase letter.**
130
+
131
+ ```typescript
132
+ import { Router, Query, UseMiddlewares, Ctx } from "nestjs-trpc";
133
+ import z from "zod";
134
+
135
+ import { AppService } from "./app.service.js";
136
+ import type { UserSession } from "./auth/auth.js";
137
+ import { AuthTRPCMiddleware } from "./libs/middlewares/auth.trpc.middleware.js";
138
+ import type { InnerContext } from "./libs/trpc/inner.context.js";
139
+
140
+ @Router({ alias: "appRouter" })
141
+ export class AppRouterClass {
142
+ constructor(private readonly appService: AppService) {}
143
+
144
+ @Query()
145
+ @UseMiddlewares(AuthTRPCMiddleware)
146
+ testAuth(@Ctx() ctx: InnerContext): UserSession {
147
+ return ctx.session!;
148
+ }
149
+
150
+ @Query({ output: z.string() })
151
+ getHello(): string {
152
+ return this.appService.getHello();
153
+ }
154
+ }
155
+ ```
156
+ {{else}}
157
+ ### Router Example
158
+
159
+ Routers are defined using the `@Router` decorator from `nestjs-trpc`. **Router names must start with a lowercase letter.**
160
+
161
+ ```typescript
162
+ import { Router, Query } from "nestjs-trpc";
163
+ import z from "zod";
164
+
165
+ @Router({ alias: "appRouter" })
166
+ export class AppRouterClass {
167
+ constructor(private readonly appService: AppService) {}
168
+
169
+ @Query({ output: z.string() })
170
+ getHello(): string {
171
+ return this.appService.getHello();
172
+ }
173
+ }
174
+ ```
175
+ {{/if}}
176
+
177
+ Import the router in your module:
178
+
179
+ ```typescript
180
+ import { AppRouterClass as AppRouter } from "./app.router.js";
181
+
182
+ @Module({
183
+ providers: [AppRouter],
184
+ })
185
+ export class AppModule {}
186
+ ```
187
+ {{/if}}
@@ -1,5 +1,8 @@
1
1
  allowBuilds:
2
2
  "@nestjs/core": true
3
+ {{#if swagger}}
4
+ "@scarf/scarf": true
5
+ {{/if}}
3
6
  {{#if usePrisma}}
4
7
  prisma: true
5
8
  "@prisma/engines": true
@@ -1,9 +1,15 @@
1
1
  import { Controller, Get } from "@nestjs/common";
2
+ {{#if swagger}}
3
+ import { ApiOperation, ApiResponse, ApiTags } from "@nestjs/swagger";
4
+ {{/if}}
2
5
  {{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
3
6
  import { AllowAnonymous } from "@thallesp/nestjs-better-auth";
4
7
  {{/if}}
5
8
  import { AppService } from "./app.service.js";
6
9
 
10
+ {{#if swagger}}
11
+ @ApiTags("App")
12
+ {{/if}}
7
13
  @Controller()
8
14
  export class AppController {
9
15
  constructor(private readonly appService: AppService) {}
@@ -11,6 +17,10 @@ export class AppController {
11
17
  {{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
12
18
  @AllowAnonymous()
13
19
  {{/if}}
20
+ {{#if swagger}}
21
+ @ApiOperation({ summary: "/api" })
22
+ @ApiResponse({ status: 200, description: "Returns a hello world message" })
23
+ {{/if}}
14
24
  @Get()
15
25
  getHello(): string {
16
26
  return this.appService.getHello();
@@ -1,17 +1,30 @@
1
1
  import { Module } from "@nestjs/common";
2
2
  {{#if (or hasDatabase hasOrm)}}
3
3
  import { env } from "./config/env.js";
4
- {{/if}}
5
4
  import { DbModule } from "./database/db.module.js";
6
- {{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
5
+ {{/if}}
6
+ {{#if shouldImportAuthModule}}
7
7
  import { AuthModule } from "./auth/auth.module.js";
8
8
  {{/if}}
9
+ {{#if hasTrpc}}
10
+ import { TRPCModule } from "nestjs-trpc";
11
+ import { AppRouterClass as AppRouter } from "./app.router.js";
12
+ import { AppContext } from "./libs/trpc/context.js";
13
+ import { AppErrorHandler } from "./libs/trpc/error.handler.js";
14
+ {{#if hasTrpcAndAuth}}
15
+ import { AuthTRPCMiddleware } from "./libs/middlewares/auth.trpc.middleware.js";
16
+ {{/if}}
17
+ {{/if}}
9
18
 
19
+ {{#if hasRest}}
10
20
  import { AppController } from "./app.controller.js";
21
+ {{/if}}
11
22
  import { AppService } from "./app.service.js";
12
23
 
13
24
  @Module({
25
+ {{#if hasRest}}
14
26
  controllers: [AppController],
27
+ {{/if}}
15
28
  imports: [
16
29
  {{#if (or hasDatabase hasOrm)}}
17
30
  DbModule.forRoot({
@@ -21,10 +34,26 @@ import { AppService } from "./app.service.js";
21
34
  {{#if hasMongodb}}mongodbUrl: env.MONGODB_URL,{{/if}}
22
35
  }),
23
36
  {{/if}}
24
- {{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
37
+ {{#if shouldImportAuthModule}}
25
38
  AuthModule,
26
39
  {{/if}}
40
+ {{#if hasTrpc}}
41
+ TRPCModule.forRoot({
42
+ context: AppContext,
43
+ onError: AppErrorHandler,
44
+ }),
45
+ {{/if}}
46
+ ],
47
+ providers: [
48
+ AppService,
49
+ {{#if hasTrpc}}
50
+ {{#if hasTrpcAndAuth}}
51
+ AuthTRPCMiddleware,
52
+ {{/if}}
53
+ AppContext,
54
+ AppErrorHandler,
55
+ AppRouter,
56
+ {{/if}}
27
57
  ],
28
- providers: [AppService],
29
58
  })
30
59
  export class AppModule {}
@@ -0,0 +1,58 @@
1
+ import { Test, TestingModule } from "@nestjs/testing";
2
+ import { beforeEach, describe, expect, it, vi } from "vitest";
3
+
4
+ import { AppRouterClass } from "./app.router.js";
5
+ import { AppService } from "./app.service.js";
6
+ {{#if hasTrpcAndAuth}}
7
+ import { AuthTRPCMiddleware } from "./libs/middlewares/auth.trpc.middleware.js";
8
+ import type { InnerContext } from "./libs/trpc/inner.context.js";
9
+ {{/if}}
10
+
11
+ describe(AppRouterClass, () => {
12
+ let router: AppRouterClass;
13
+
14
+ const mockAppService = {
15
+ getHello: vi.fn<() => string>().mockReturnValue("Hello World!"),
16
+ };
17
+
18
+ beforeEach(async () => {
19
+ const module: TestingModule = await Test.createTestingModule({
20
+ providers: [
21
+ AppRouterClass,
22
+ { provide: AppService, useValue: mockAppService },
23
+ {{#if hasTrpcAndAuth}}
24
+ { provide: AuthTRPCMiddleware, useValue: {} },
25
+ {{/if}}
26
+ ],
27
+ }).compile();
28
+
29
+ router = module.get<AppRouterClass>(AppRouterClass);
30
+ });
31
+
32
+ it("should be defined", () => {
33
+ expect(router).toBeDefined();
34
+ });
35
+
36
+ describe("getHello", () => {
37
+ it("should return the hello message from AppService", () => {
38
+ const result = router.getHello();
39
+ expect(result).toBe("Hello World!");
40
+ expect(mockAppService.getHello).toHaveBeenCalledWith();
41
+ });
42
+ });
43
+
44
+ {{#if hasTrpcAndAuth}}
45
+ describe("testAuth", () => {
46
+ it("should return the session from context", () => {
47
+ const mockCtx = {
48
+ session: {
49
+ session: { expiresAt: new Date() },
50
+ user: { email: "test@example.com", id: "1", name: "Test User" },
51
+ },
52
+ } as InnerContext;
53
+ const result = router.testAuth(mockCtx);
54
+ expect(result).toStrictEqual(mockCtx.session);
55
+ });
56
+ });
57
+ {{/if}}
58
+ });
@@ -0,0 +1,26 @@
1
+ import { Router, Query, UseMiddlewares, Ctx } from "nestjs-trpc";
2
+ import z from "zod";
3
+ {{#if hasTrpcAndAuth}}
4
+ import type { UserSession } from "./auth/auth.js";
5
+ import { AuthTRPCMiddleware } from "./libs/middlewares/auth.trpc.middleware.js";
6
+ import type { InnerContext } from "./libs/trpc/inner.context.js";
7
+ {{/if}}
8
+ import { AppService } from "./app.service.js";
9
+
10
+ @Router({ alias: "appRouter" })
11
+ export class AppRouterClass {
12
+ constructor(private readonly appService: AppService) {}
13
+
14
+ {{#if hasTrpcAndAuth}}
15
+ @Query()
16
+ @UseMiddlewares(AuthTRPCMiddleware)
17
+ testAuth(@Ctx() ctx: InnerContext): UserSession {
18
+ return ctx.session!;
19
+ }
20
+
21
+ {{/if}}
22
+ @Query({ output: z.string() })
23
+ getHello(): string {
24
+ return this.appService.getHello();
25
+ }
26
+ }
@@ -1,8 +1,8 @@
1
1
  {{#if (or hasPostgres hasMysql hasSqlite)}}
2
2
  export interface ISqlAdapter<TClient = unknown> {
3
- query<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>;
4
- execute(sql: string, params?: unknown[]): Promise<unknown>;
5
- getClient(): TClient;
3
+ query: <T = unknown>(sql: string, params?: unknown[]) => Promise<T[]>;
4
+ execute: (sql: string, params?: unknown[]) => Promise<unknown>;
5
+ getClient: () => TClient;
6
6
  }
7
7
  {{/if}}
8
8
 
@@ -0,0 +1,42 @@
1
+ import { Injectable } from "@nestjs/common";
2
+ import { AuthService } from "@thallesp/nestjs-better-auth";
3
+ import { TRPCError } from "@trpc/server";
4
+ import {
5
+ MiddlewareOptions,
6
+ MiddlewareResponse,
7
+ TRPCMiddleware,
8
+ } from "nestjs-trpc";
9
+ import type { ContextOptions } from "nestjs-trpc";
10
+
11
+ import { createAuth } from "../../auth/auth.js";
12
+
13
+ type AppAuth = ReturnType<typeof createAuth>;
14
+
15
+ @Injectable()
16
+ export class AuthTRPCMiddleware implements TRPCMiddleware {
17
+ constructor(private readonly authService: AuthService<AppAuth>) {}
18
+
19
+ async use(
20
+ opts: MiddlewareOptions<ContextOptions>
21
+ ): Promise<MiddlewareResponse> {
22
+ const { ctx, next } = opts;
23
+
24
+ const session = await this.authService.api.getSession({
25
+ headers: ctx.req.headers,
26
+ });
27
+
28
+ if (session === null) {
29
+ throw new TRPCError({
30
+ code: "UNAUTHORIZED",
31
+ message: "No session found.",
32
+ });
33
+ }
34
+
35
+ return next({
36
+ ctx: {
37
+ ...ctx,
38
+ session,
39
+ },
40
+ });
41
+ }
42
+ }
@@ -0,0 +1,13 @@
1
+ // oxlint-disable require-await
2
+ import { Injectable } from "@nestjs/common";
3
+ import { ContextOptions, TRPCContext } from "nestjs-trpc";
4
+
5
+ @Injectable()
6
+ export class AppContext implements TRPCContext {
7
+ async create(opts: ContextOptions): Promise<Record<string, unknown>> {
8
+ return {
9
+ req: opts.req,
10
+ res: opts.res,
11
+ };
12
+ }
13
+ }
@@ -0,0 +1,10 @@
1
+ import { Injectable, Logger } from "@nestjs/common";
2
+ import { OnErrorOptions, TRPCErrorHandler } from "nestjs-trpc";
3
+
4
+ @Injectable()
5
+ export class AppErrorHandler implements TRPCErrorHandler {
6
+ private logger = new Logger("TRPC Router");
7
+ onError(opts: OnErrorOptions): void {
8
+ this.logger.error(`[${opts.type}] ${opts.path}: ${opts.error.message}`);
9
+ }
10
+ }
@@ -0,0 +1,7 @@
1
+ import { ContextOptions } from "nestjs-trpc";
2
+
3
+ import { auth } from "../../auth/auth.js";
4
+
5
+ export type InnerContext = {
6
+ session: Awaited<ReturnType<typeof auth.api.getSession>>;
7
+ } & ContextOptions;
@@ -0,0 +1,12 @@
1
+ // oxlint-disable typescript/no-explicit-any
2
+ import { TRPCError } from "@trpc/server";
3
+
4
+ export function requireAuth(ctx: any) {
5
+ if (!ctx.session?.user) {
6
+ throw new TRPCError({
7
+ code: "UNAUTHORIZED",
8
+ });
9
+ }
10
+
11
+ return ctx.session.user;
12
+ }
@@ -0,0 +1,21 @@
1
+ // This script is needed because nestjs-trpc doesn't have support for NestJS 12 yet.
2
+ // Awaiting PR approval to support the new ESM support.
3
+ import { readFileSync, writeFileSync } from "node:fs";
4
+ import path from "node:path";
5
+
6
+ const generatedFile = path.join(
7
+ import.meta.dirname,
8
+ "..",
9
+ "@generated",
10
+ "server.ts"
11
+ );
12
+
13
+ let content = readFileSync(generatedFile, "utf-8");
14
+
15
+ content = content.replaceAll(
16
+ /(?<ext>\.router)(?<quote>")/gu,
17
+ "$<ext>.js$<quote>"
18
+ );
19
+
20
+ writeFileSync(generatedFile, content, "utf-8");
21
+ console.log("Fixed trpc generated file:", generatedFile);
@@ -0,0 +1,91 @@
1
+ // This script is needed because nestjs-trpc doesn't have support for NestJS 12 yet.
2
+ // Awaiting PR approval to support the new ESM support.
3
+ import { spawn } from "node:child_process";
4
+ import { watchFile, readFileSync, writeFileSync } from "node:fs";
5
+ import path from "node:path";
6
+
7
+ const generatedFile = path.join(
8
+ import.meta.dirname,
9
+ "..",
10
+ "@generated",
11
+ "server.ts"
12
+ );
13
+ const REGEX_REPLACE = /(?<ext>\.router)(?<quote>")/gu;
14
+
15
+ function fixGeneratedFile() {
16
+ try {
17
+ let content = readFileSync(generatedFile, "utf-8");
18
+ const original = content;
19
+ content = content.replaceAll(REGEX_REPLACE, "$<ext>.js$<quote>");
20
+ if (content !== original) {
21
+ writeFileSync(generatedFile, content, "utf-8");
22
+ console.log("Fixed trpc generated file:", generatedFile);
23
+ }
24
+ } catch {
25
+ // file might not exist yet
26
+ }
27
+ }
28
+
29
+ // Run generate + fix upfront
30
+ const projectRoot = path.join(import.meta.dirname, "..", "..", "..", "..");
31
+ const SHELL = process.platform === "win32" ? "powershell.exe" : true;
32
+ {{#if isMonorepo}}
33
+ const genCmd =
34
+ "pnpm exec nestjs-trpc generate -e src/app.module.ts -o ../../packages/api/src/trpc/@generated";
35
+ {{else}}
36
+ const genCmd =
37
+ "pnpm exec nestjs-trpc generate -e src/app.module.ts -o src/libs/trpc/@generated";
38
+ {{/if}}
39
+
40
+ const spawnOpts = {
41
+ cwd: projectRoot,
42
+ shell: SHELL,
43
+ stdio: "inherit",
44
+ };
45
+
46
+ const gen = spawn(genCmd, [], spawnOpts);
47
+
48
+ gen.on("close", (code) => {
49
+ if (code !== 0) {
50
+ process.exit(code);
51
+ }
52
+ fixGeneratedFile();
53
+
54
+ // Watch generated file for changes and re-apply fix
55
+ watchFile(generatedFile, { interval: 500 }, () => {
56
+ fixGeneratedFile();
57
+ });
58
+
59
+ // Start watch mode
60
+ {{#if isMonorepo}}
61
+ const watch = spawn(
62
+ "pnpm",
63
+ [
64
+ "exec",
65
+ "nestjs-trpc",
66
+ "watch",
67
+ "-e",
68
+ "src/app.module.ts",
69
+ "-o",
70
+ " ../../packages/api/src/trpc/@generated",
71
+ ],
72
+ spawnOpts
73
+ );
74
+ {{else}}
75
+ const watch = spawn(
76
+ "pnpm",
77
+ [
78
+ "exec",
79
+ "nestjs-trpc",
80
+ "watch",
81
+ "-e",
82
+ "src/app.module.ts",
83
+ "-o",
84
+ "src/libs/trpc/@generated",
85
+ ],
86
+ spawnOpts
87
+ );
88
+ {{/if}}
89
+
90
+ watch.on("close", (exitCode) => process.exit(exitCode ?? 0));
91
+ });
@@ -2,16 +2,89 @@ import { NestFactory } from "@nestjs/core";
2
2
  {{#if (eq httpProvider "fastify")}}
3
3
  import { FastifyAdapter, NestFastifyApplication } from "@nestjs/platform-fastify";
4
4
  {{/if}}
5
+ import { Logger } from "@nestjs/common";
5
6
 
6
7
  import { AppModule } from "./app.module.js";
7
8
  import { env } from "./config/env.js";
9
+ {{#if swagger}}
10
+ import { createDocs } from "./docs/create-docs.js";
11
+ {{/if}}
12
+ {{#if (and swagger useSwaggerScalar)}}
13
+ import { apiReference } from "@scalar/nestjs-api-reference";
14
+ {{/if}}
15
+ {{#if (and swagger (eq useSwaggerScalar false))}}
16
+ import { SwaggerModule } from "@nestjs/swagger";
17
+ {{/if}}
18
+ {{#if (and swagger (or (eq auth "better-auth") (eq auth "better-auth:stateless") hasBetterAuthWithoutRest))}}
19
+ import { auth } from "./auth/auth.js";
20
+ {{/if}}
8
21
 
9
22
  async function bootstrap() {
10
- const app = await NestFactory.create{{#if (eq httpProvider "fastify")}}<NestFastifyApplication>(AppModule, new FastifyAdapter(){{else}}(AppModule{{/if}}{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}, { bodyParser: false }{{/if}});
23
+ const app = await NestFactory.create{{#if (eq httpProvider "fastify")}}<NestFastifyApplication>(AppModule, new FastifyAdapter(){{else}}(AppModule{{/if}}{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless") hasBetterAuthWithoutRest)}}, { bodyParser: false }{{/if}});
11
24
  app.enableCors({
12
25
  origin: env.CORS_ORIGIN,
13
26
  });
14
27
  app.setGlobalPrefix("api");
28
+ {{#if swagger}}
29
+ const docsPath = "/docs";
30
+ {{#if useSwaggerScalar}}
31
+ app.use(
32
+ docsPath,
33
+ apiReference({
34
+ content: await createDocs(app, {
35
+ description: "{{description}}",
36
+ title: "{{projectNamePascalCase}} API",
37
+ integrations: {
38
+ {{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless") hasBetterAuthWithoutRest)}}
39
+ betterAuth: {
40
+ auth,
41
+ pathPrefix: "/api/auth",
42
+ },
43
+ {{/if}}
44
+ {{#if (includes apis "trpc")}}
45
+ trpc: {
46
+ routerFilePath: "./src/libs/trpc/@generated/server.ts",
47
+ pathPrefix: "/trpc",
48
+ },
49
+ {{/if}}
50
+ zod: {
51
+ withFastify: {{#if (eq httpProvider "fastify")}}true{{else}}false{{/if}},
52
+ },
53
+ },
54
+ version: "1.0.0",
55
+ }),
56
+ pageTitle: "{{projectNamePascalCase}} API Docs",
57
+ theme: "default",
58
+ }),
59
+ );
60
+ {{else}}
61
+ const document = await createDocs(app, {
62
+ title: "{{projectNamePascalCase}} API",
63
+ description: "{{description}}",
64
+ version: "1.0.0",
65
+ integrations: {
66
+ {{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless") hasBetterAuthWithoutRest)}}
67
+ betterAuth: {
68
+ auth,
69
+ pathPrefix: "/api/auth",
70
+ },
71
+ {{/if}}
72
+ {{#if (includes apis "trpc")}}
73
+ trpc: {
74
+ routerFilePath: "./src/trpc/router.ts",
75
+ pathPrefix: "/trpc",
76
+ },
77
+ {{/if}}
78
+ zod: {
79
+ withFastify: {{#if (eq httpProvider "fastify")}}true{{else}}false{{/if}},
80
+ },
81
+ },
82
+ });
83
+ SwaggerModule.setup(docsPath, app, document);
84
+ {{/if}}
85
+ Logger.log(`Swagger documentation available at http://localhost:${env.PORT ?? 3000}${docsPath}`, "SwaggerDocs");
86
+ {{/if}}
15
87
  await app.listen(env.PORT ?? 3000);
88
+ Logger.log(`Started backend server on http://localhost:${env.PORT ?? 3000}/api`, "Main");
16
89
  }
17
90
  await bootstrap();