@nest-arch/tui 0.4.0 → 0.4.4
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/dist/cli.js +1 -1
- package/dist/{constants-C3xmDWeK.js → constants-7dJLZpB2.js} +1 -1
- package/dist/index.js +188 -134
- package/dist/templates/addons/husky/pre-commit.hbs +11 -26
- package/dist/templates/base/.env.example.hbs +9 -0
- package/dist/templates/base/.env.hbs +7 -0
- package/dist/templates/base/README.md.hbs +16 -0
- package/dist/templates/base/pnpm-workspace.yaml.hbs +6 -0
- package/dist/templates/base/src/app.module.ts.hbs +68 -1
- package/dist/templates/base/src/app.router.ts.hbs +1 -2
- package/dist/templates/base/src/database/adapters/mongo/prisma-mongo.adapter.ts.hbs +11 -3
- package/dist/templates/base/src/database/adapters/sql/prisma-sql.adapter.ts.hbs +1 -1
- package/dist/templates/base/src/database/db.module.ts.hbs +24 -8
- package/dist/templates/base/src/database/db.service.ts.hbs +20 -0
- package/dist/templates/base/src/database/entities/app.entity.ts.hbs +25 -0
- package/dist/templates/base/src/database/index.ts.hbs +19 -0
- package/dist/templates/base/src/database/orm/drizzle/schema.ts.hbs +42 -11
- package/dist/templates/base/src/database/orm/typeorm/data-source.ts.hbs +12 -1
- 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/inner.context.ts.hbs +6 -3
- package/dist/templates/base/src/main.ts.hbs +13 -4
- package/dist/templates/base/src/modules/users/entities/user.entity.ts.hbs +22 -0
- package/dist/templates/base/test/app.e2e-spec.ts.hbs +670 -37
- package/dist/templates/base/test/bootstrap.e2e-spec.ts.hbs +11 -1
- package/dist/templates/extras/docker/.dockerignore.hbs +8 -1
- package/dist/templates/extras/docker/Dockerfile.hbs +8 -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 +9 -3
- package/dist/templates/feature/graphql/src/graphql/graphql.module.ts.hbs +6 -17
- package/dist/templates/feature/graphql/src/graphql/orm/drizzle/drizzle-graphql.module.ts.hbs +3 -2
- 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 +165 -53
- 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 +18 -8
- 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 +68 -10
- package/dist/templates/monorepo/apps/api-gateway/package.json.hbs +2 -2
- package/dist/templates/monorepo/apps/api-gateway/src/app.controller.spec.ts.hbs +5 -0
- 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 +26 -1
- 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 +147 -47
- package/dist/templates/monorepo/packages/env/src/api-gateway.ts.hbs +7 -0
- 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/pnpm-workspace.yaml.hbs +10 -2
- package/dist/templates/single-project/architecture/nest-api/.env.hbs +6 -0
- package/dist/templates/single-project/architecture/nest-api/package.json.hbs +1 -1
- package/dist/templates/single-project/architecture/nest-api/src/main.ts.hbs +13 -4
- package/dist/templates/single-project/architecture/nest-gateway/src/main.ts.hbs +3 -3
- package/dist/templates/single-project/architecture/nest-microservice/proto/app.proto.hbs +13 -0
- package/dist/templates/single-project/architecture/nest-microservice/src/app.controller.ts.hbs +10 -4
- package/dist/templates/single-project/architecture/nest-microservice/src/app.service.ts.hbs +2 -2
- package/dist/templates/single-project/architecture/nest-microservice/src/main.ts.hbs +3 -3
- package/dist/templates/single-project/architecture/nest-microservice/test/microservice.e2e-spec.ts.hbs +7 -1
- package/dist/templates/single-project/shared/config/env.ts.hbs +12 -1
- package/package.json +2 -2
|
@@ -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}}
|
|
@@ -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;
|
|
@@ -24,14 +24,23 @@ import { apiReference } from "@scalar/nestjs-api-reference";
|
|
|
24
24
|
import { SwaggerModule } from "@nestjs/swagger";
|
|
25
25
|
{{/if}}
|
|
26
26
|
{{#if (and swagger (or (eq auth "better-auth") (eq auth "better-auth:stateless") hasBetterAuthWithoutRest))}}
|
|
27
|
-
import {
|
|
27
|
+
import { AuthService } from "@thallesp/nestjs-better-auth";
|
|
28
28
|
{{/if}}
|
|
29
29
|
|
|
30
30
|
async function bootstrap() {
|
|
31
|
+
const trustedProxyIps = env.TRUSTED_PROXY_IPS
|
|
32
|
+
.split(",")
|
|
33
|
+
.map((ip) => ip.trim())
|
|
34
|
+
.filter(Boolean);
|
|
31
35
|
{{#if isPrisma8}}
|
|
32
36
|
await connectDatabase();
|
|
33
37
|
{{/if}}
|
|
34
|
-
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}});
|
|
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}}
|
|
35
44
|
app.enableCors({
|
|
36
45
|
origin: env.CORS_ORIGIN,
|
|
37
46
|
});
|
|
@@ -56,7 +65,7 @@ async function bootstrap() {
|
|
|
56
65
|
integrations: {
|
|
57
66
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless") hasBetterAuthWithoutRest)}}
|
|
58
67
|
betterAuth: {
|
|
59
|
-
auth,
|
|
68
|
+
auth: app.get(AuthService).instance,
|
|
60
69
|
pathPrefix: "/api/auth",
|
|
61
70
|
},
|
|
62
71
|
{{/if}}
|
|
@@ -84,7 +93,7 @@ async function bootstrap() {
|
|
|
84
93
|
integrations: {
|
|
85
94
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless") hasBetterAuthWithoutRest)}}
|
|
86
95
|
betterAuth: {
|
|
87
|
-
auth,
|
|
96
|
+
auth: app.get(AuthService).instance,
|
|
88
97
|
pathPrefix: "/api/auth",
|
|
89
98
|
},
|
|
90
99
|
{{/if}}
|
|
@@ -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
|
+
}
|