@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,3 +1,43 @@
|
|
|
1
|
+
{{#if (eq auth "passport")}}
|
|
2
|
+
import { Injectable } from "@nestjs/common";
|
|
3
|
+
import { JwtService } from "@nestjs/jwt";
|
|
4
|
+
import { TRPCError } from "@trpc/server";
|
|
5
|
+
import { MiddlewareOptions, MiddlewareResponse, TRPCMiddleware } from "nestjs-trpc";
|
|
6
|
+
import type { ContextOptions } from "nestjs-trpc";
|
|
7
|
+
|
|
8
|
+
import { env } from "../../config/env.js";
|
|
9
|
+
import { AuthService } from "../../auth/auth.service.js";
|
|
10
|
+
|
|
11
|
+
@Injectable()
|
|
12
|
+
export class AuthTRPCMiddleware implements TRPCMiddleware {
|
|
13
|
+
constructor(private readonly auth: AuthService, private readonly jwt: JwtService) {}
|
|
14
|
+
|
|
15
|
+
async use(opts: MiddlewareOptions<ContextOptions>): Promise<MiddlewareResponse> {
|
|
16
|
+
const header = opts.ctx.req.headers.authorization;
|
|
17
|
+
const token = header?.startsWith("Bearer ") ? header.slice("Bearer ".length) : undefined;
|
|
18
|
+
if (!token) throw new TRPCError({ code: "UNAUTHORIZED", message: "Missing bearer token." });
|
|
19
|
+
try {
|
|
20
|
+
const payload = await this.jwt.verifyAsync<Record<string, unknown>>(token, {
|
|
21
|
+
algorithms: ["HS256"], audience: env.JWT_AUDIENCE, issuer: env.JWT_ISSUER,
|
|
22
|
+
});
|
|
23
|
+
{{#if (and usePrisma (not hasMongodb))}}
|
|
24
|
+
const user = await this.auth.validate(payload);
|
|
25
|
+
{{else}}
|
|
26
|
+
const user = await this.auth.validateUser(payload.userId as string);
|
|
27
|
+
{{/if}}
|
|
28
|
+
if (!user) throw new TRPCError({ code: "UNAUTHORIZED", message: "Invalid bearer token." });
|
|
29
|
+
return opts.next({
|
|
30
|
+
ctx: {
|
|
31
|
+
...opts.ctx,
|
|
32
|
+
session: { user },
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
} catch {
|
|
36
|
+
throw new TRPCError({ code: "UNAUTHORIZED", message: "Invalid bearer token." });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
{{else}}
|
|
1
41
|
import { Injectable } from "@nestjs/common";
|
|
2
42
|
import { AuthService } from "@thallesp/nestjs-better-auth";
|
|
3
43
|
import { TRPCError } from "@trpc/server";
|
|
@@ -8,9 +48,15 @@ import {
|
|
|
8
48
|
} from "nestjs-trpc";
|
|
9
49
|
import type { ContextOptions } from "nestjs-trpc";
|
|
10
50
|
|
|
51
|
+
{{#if (eq auth "better-auth:stateless")}}
|
|
52
|
+
import { auth } from "../../auth/auth.js";
|
|
53
|
+
|
|
54
|
+
type AppAuth = typeof auth;
|
|
55
|
+
{{else}}
|
|
11
56
|
import { createAuth } from "../../auth/auth.js";
|
|
12
57
|
|
|
13
58
|
type AppAuth = ReturnType<typeof createAuth>;
|
|
59
|
+
{{/if}}
|
|
14
60
|
|
|
15
61
|
@Injectable()
|
|
16
62
|
export class AuthTRPCMiddleware implements TRPCMiddleware {
|
|
@@ -40,3 +86,4 @@ export class AuthTRPCMiddleware implements TRPCMiddleware {
|
|
|
40
86
|
});
|
|
41
87
|
}
|
|
42
88
|
}
|
|
89
|
+
{{/if}}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{{#if hasRateLimiting}}
|
|
2
|
+
import { Inject, Injectable } from "@nestjs/common";
|
|
3
|
+
import { ThrottlerStorage, type ThrottlerStorage as ThrottlerStorageService } from "@nestjs/throttler";
|
|
4
|
+
import { TRPCError } from "@trpc/server";
|
|
5
|
+
import {
|
|
6
|
+
MiddlewareOptions,
|
|
7
|
+
MiddlewareResponse,
|
|
8
|
+
TRPCMiddleware,
|
|
9
|
+
} from "nestjs-trpc";
|
|
10
|
+
import type { ContextOptions } from "nestjs-trpc";
|
|
11
|
+
|
|
12
|
+
@Injectable()
|
|
13
|
+
export class RateLimitTRPCMiddleware implements TRPCMiddleware {
|
|
14
|
+
constructor(
|
|
15
|
+
@Inject(ThrottlerStorage)
|
|
16
|
+
private readonly storage: ThrottlerStorageService
|
|
17
|
+
) {}
|
|
18
|
+
|
|
19
|
+
async use(
|
|
20
|
+
opts: MiddlewareOptions<ContextOptions>
|
|
21
|
+
): Promise<MiddlewareResponse> {
|
|
22
|
+
const request = opts.ctx.req as {
|
|
23
|
+
ip?: string;
|
|
24
|
+
socket?: { remoteAddress?: string };
|
|
25
|
+
};
|
|
26
|
+
const clientIp = request.ip ?? request.socket?.remoteAddress ?? "unknown";
|
|
27
|
+
const result = await this.storage.increment(
|
|
28
|
+
`trpc:${clientIp}`,
|
|
29
|
+
60_000,
|
|
30
|
+
60,
|
|
31
|
+
60_000,
|
|
32
|
+
"trpc"
|
|
33
|
+
);
|
|
34
|
+
if (result.isBlocked) {
|
|
35
|
+
throw new TRPCError({
|
|
36
|
+
code: "TOO_MANY_REQUESTS",
|
|
37
|
+
message: "Too many requests",
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return opts.next();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
{{/if}}
|
|
@@ -3,7 +3,7 @@ import { OnErrorOptions, TRPCErrorHandler } from "nestjs-trpc";
|
|
|
3
3
|
|
|
4
4
|
@Injectable()
|
|
5
5
|
export class AppErrorHandler implements TRPCErrorHandler {
|
|
6
|
-
private logger = new Logger("TRPC Router");
|
|
6
|
+
private readonly logger = new Logger("TRPC Router");
|
|
7
7
|
onError(opts: OnErrorOptions): void {
|
|
8
8
|
this.logger.error(`[${opts.type}] ${opts.path}: ${opts.error.message}`);
|
|
9
9
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { ContextOptions } from "nestjs-trpc";
|
|
2
|
-
|
|
3
|
-
import {
|
|
2
|
+
{{#if (eq auth "better-auth")}}
|
|
3
|
+
import type { UserSession } from "../../auth/auth.js";
|
|
4
|
+
{{else if (eq auth "passport")}}
|
|
5
|
+
import type { AuthService } from "../../auth/auth.service.js";
|
|
6
|
+
{{/if}}
|
|
4
7
|
|
|
5
8
|
export type InnerContext = {
|
|
6
|
-
session: Awaited<ReturnType<
|
|
9
|
+
session?: {{#if (eq auth "better-auth")}}UserSession{{else if (eq auth "passport")}}{ user: NonNullable<Awaited<ReturnType<AuthService[{{#if (and usePrisma (not hasMongodb))}}"validate"{{else}}"validateUser"{{/if}}]>>> }{{else}}unknown{{/if}};
|
|
7
10
|
} & ContextOptions;
|
|
@@ -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") hasBetterAuthWithoutRest))}}
|
|
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}}{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless") hasBetterAuthWithoutRest)}}, { bodyParser: false }{{/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
|
const docsPath = "/docs";
|
|
@@ -41,7 +65,7 @@ async function bootstrap() {
|
|
|
41
65
|
integrations: {
|
|
42
66
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless") hasBetterAuthWithoutRest)}}
|
|
43
67
|
betterAuth: {
|
|
44
|
-
auth,
|
|
68
|
+
auth: app.get(AuthService).instance,
|
|
45
69
|
pathPrefix: "/api/auth",
|
|
46
70
|
},
|
|
47
71
|
{{/if}}
|
|
@@ -69,7 +93,7 @@ async function bootstrap() {
|
|
|
69
93
|
integrations: {
|
|
70
94
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless") hasBetterAuthWithoutRest)}}
|
|
71
95
|
betterAuth: {
|
|
72
|
-
auth,
|
|
96
|
+
auth: app.get(AuthService).instance,
|
|
73
97
|
pathPrefix: "/api/auth",
|
|
74
98
|
},
|
|
75
99
|
{{/if}}
|
|
@@ -86,15 +110,15 @@ async function bootstrap() {
|
|
|
86
110
|
});
|
|
87
111
|
SwaggerModule.setup(docsPath, app, document);
|
|
88
112
|
{{/if}}
|
|
89
|
-
Logger.log(`Swagger documentation available at http://localhost:${env.PORT
|
|
113
|
+
Logger.log(`Swagger documentation available at http://localhost:${env.PORT}${docsPath}`, "SwaggerDocs");
|
|
90
114
|
{{/if}}
|
|
91
|
-
await app.listen(env.PORT
|
|
115
|
+
await app.listen(env.PORT);
|
|
92
116
|
{{#if hasRest}}
|
|
93
|
-
Logger.log(`Started backend server on http://localhost:${env.PORT
|
|
117
|
+
Logger.log(`Started backend server on http://localhost:${env.PORT}/api`, "Main");
|
|
94
118
|
{{else if hasTrpc}}
|
|
95
|
-
Logger.log(`Started trpc server on http://localhost:${env.PORT
|
|
119
|
+
Logger.log(`Started trpc server on http://localhost:${env.PORT}/trpc`, "Main");
|
|
96
120
|
{{else}}
|
|
97
|
-
Logger.log(`Started server on http://localhost:${env.PORT
|
|
121
|
+
Logger.log(`Started server on http://localhost:${env.PORT}`, "Main");
|
|
98
122
|
{{/if}}
|
|
99
123
|
}
|
|
100
|
-
await bootstrap();
|
|
124
|
+
await bootstrap();
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
|
|
2
|
+
|
|
3
|
+
@Entity("users")
|
|
4
|
+
export class UserEntity {
|
|
5
|
+
@PrimaryGeneratedColumn("uuid")
|
|
6
|
+
id: string;
|
|
7
|
+
|
|
8
|
+
@Column({ type: "varchar", unique: true })
|
|
9
|
+
email: string;
|
|
10
|
+
|
|
11
|
+
@Column({ type: "varchar", nullable: true })
|
|
12
|
+
firstname: string | null;
|
|
13
|
+
|
|
14
|
+
@Column({ type: "varchar", nullable: true })
|
|
15
|
+
lastname: string | null;
|
|
16
|
+
|
|
17
|
+
@Column({ type: "varchar" })
|
|
18
|
+
password: string;
|
|
19
|
+
|
|
20
|
+
@Column({ type: "varchar", default: "USER" })
|
|
21
|
+
role: string;
|
|
22
|
+
}
|