@nest-arch/tui 0.4.5 → 0.5.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.
- package/dist/cli.js +1 -1
- package/dist/constants-DX5wiqrq.js +1 -0
- package/dist/index.js +158 -145
- package/dist/templates/addons/husky/noop-hook.hbs +2 -0
- package/dist/templates/addons/husky/pre-commit.hbs +1 -1
- package/dist/templates/base/.env.example.hbs +16 -2
- package/dist/templates/base/.env.hbs +16 -2
- package/dist/templates/base/README.md.hbs +23 -2
- package/dist/templates/base/pnpm-workspace.yaml.hbs +9 -4
- package/dist/templates/base/prisma.config.ts.hbs +6 -0
- package/dist/templates/base/src/app.module.ts.hbs +6 -22
- package/dist/templates/base/src/database/adapters/interfaces/db-adapter.interface.ts.hbs +1 -1
- package/dist/templates/base/src/database/adapters/mongo/raw-mongo.adapter.ts.hbs +4 -2
- package/dist/templates/base/src/database/db.module.ts.hbs +30 -3
- package/dist/templates/base/src/database/db.service.ts.hbs +11 -8
- package/dist/templates/base/src/database/entities/todo.entity.ts.hbs +2 -2
- package/dist/templates/base/src/database/index.ts.hbs +2 -0
- package/dist/templates/base/src/database/orm/drizzle/schema.ts.hbs +48 -12
- package/dist/templates/base/src/database/orm/typeorm/data-source.ts.hbs +26 -10
- package/dist/templates/base/src/libs/middlewares/graphql-throttler.guard.ts.hbs +22 -0
- package/dist/templates/base/src/libs/trpc/inner.context.ts.hbs +2 -2
- package/dist/templates/base/src/main.ts.hbs +7 -6
- package/dist/templates/base/test/app.e2e-spec.ts.hbs +374 -198
- package/dist/templates/base/test/bootstrap.e2e-spec.ts.hbs +2 -2
- package/dist/templates/extras/docker/Dockerfile.hbs +8 -1
- package/dist/templates/extras/health/src/health/health.controller.ts.hbs +7 -1
- package/dist/templates/extras/swagger/create-docs.ts.hbs +6 -1
- package/dist/templates/feature/graphql/src/graphql/models/todo.model.ts.hbs +1 -1
- package/dist/templates/feature/graphql/src/graphql/resolvers/todo.resolver.ts.hbs +1 -1
- package/dist/templates/feature/rest/todo-example/src/api/todo/todo.controller.ts.hbs +80 -7
- package/dist/templates/feature/rest/todo-example/src/api/todo/todo.service.ts.hbs +181 -25
- package/dist/templates/monorepo/apps/api-gateway/src/main.ts.hbs +10 -9
- package/dist/templates/monorepo/root/README.md.hbs +8 -13
- package/dist/templates/single-project/architecture/nest-api/.env.hbs +15 -2
- package/dist/templates/single-project/architecture/nest-api/pnpm-workspace.yaml.hbs +6 -0
- package/dist/templates/single-project/architecture/nest-api/src/main.ts.hbs +10 -9
- package/dist/templates/single-project/architecture/nest-gateway/src/main.ts.hbs +10 -9
- package/dist/templates/single-project/architecture/nest-microservice/.env.hbs +6 -0
- package/dist/templates/single-project/architecture/nest-microservice/src/app.controller.ts.hbs +2 -2
- package/dist/templates/single-project/architecture/nest-microservice/src/app.module.ts.hbs +28 -1
- package/dist/templates/single-project/architecture/nest-microservice/src/http-throttler.guard.ts.hbs +13 -0
- package/dist/templates/single-project/architecture/nest-microservice/src/main.ts.hbs +10 -9
- package/dist/templates/single-project/architecture/nest-microservice/test/microservice.e2e-spec.ts.hbs +35 -0
- package/dist/templates/single-project/shared/config/env.ts.hbs +9 -0
- package/package.json +5 -5
- package/dist/constants-BbC7KTI7.js +0 -1
|
@@ -41,9 +41,7 @@ async function bootstrap() {
|
|
|
41
41
|
docsPath,
|
|
42
42
|
apiReference({
|
|
43
43
|
content: await createDocs(app, {
|
|
44
|
-
title: "{{projectNamePascalCase}} API",
|
|
45
44
|
description: "{{description}}",
|
|
46
|
-
version: "1.0.0",
|
|
47
45
|
integrations: {
|
|
48
46
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
|
|
49
47
|
betterAuth: {
|
|
@@ -53,7 +51,7 @@ async function bootstrap() {
|
|
|
53
51
|
{{/if}}
|
|
54
52
|
{{#if (includes apis "trpc")}}
|
|
55
53
|
trpc: {
|
|
56
|
-
routerFilePath: "./
|
|
54
|
+
routerFilePath: "./{{trpcGeneratePath}}/server.ts",
|
|
57
55
|
pathPrefix: "/trpc",
|
|
58
56
|
},
|
|
59
57
|
{{/if}}
|
|
@@ -61,16 +59,17 @@ async function bootstrap() {
|
|
|
61
59
|
withFastify: {{#if (eq httpProvider "fastify")}}true{{else}}false{{/if}},
|
|
62
60
|
},
|
|
63
61
|
},
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
title: "{{projectNamePascalCase}} API",
|
|
63
|
+
version: "1.0.0",
|
|
64
|
+
}),
|
|
65
|
+
{{#if (eq httpProvider "fastify")}}withFastify: true,{{/if}}
|
|
66
|
+
pageTitle: "{{projectNamePascalCase}} API Docs",
|
|
66
67
|
theme: "default",
|
|
67
68
|
}),
|
|
68
69
|
);
|
|
69
70
|
{{else}}
|
|
70
71
|
const document = await createDocs(app, {
|
|
71
|
-
title: "{{projectNamePascalCase}} API",
|
|
72
72
|
description: "{{description}}",
|
|
73
|
-
version: "1.0.0",
|
|
74
73
|
integrations: {
|
|
75
74
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
|
|
76
75
|
betterAuth: {
|
|
@@ -80,7 +79,7 @@ async function bootstrap() {
|
|
|
80
79
|
{{/if}}
|
|
81
80
|
{{#if (includes apis "trpc")}}
|
|
82
81
|
trpc: {
|
|
83
|
-
routerFilePath: "./
|
|
82
|
+
routerFilePath: "./{{trpcGeneratePath}}/server.ts",
|
|
84
83
|
pathPrefix: "/trpc",
|
|
85
84
|
},
|
|
86
85
|
{{/if}}
|
|
@@ -88,13 +87,15 @@ async function bootstrap() {
|
|
|
88
87
|
withFastify: {{#if (eq httpProvider "fastify")}}true{{else}}false{{/if}},
|
|
89
88
|
},
|
|
90
89
|
},
|
|
90
|
+
title: "{{projectNamePascalCase}} API",
|
|
91
|
+
version: "1.0.0",
|
|
91
92
|
});
|
|
92
93
|
SwaggerModule.setup(docsPath, app, document);
|
|
93
94
|
{{/if}}
|
|
94
95
|
Logger.log(`Swagger documentation available at http://localhost:${env.PORT ?? 3000}${docsPath}`, "SwaggerDocs");
|
|
95
96
|
}
|
|
96
97
|
{{/if}}
|
|
97
|
-
await app.listen(env.PORT ?? 3000);
|
|
98
|
+
await app.listen(env.PORT ?? 3000, "0.0.0.0");
|
|
98
99
|
{{#if hasRest}}
|
|
99
100
|
Logger.log(`Started backend server on http://localhost:${env.PORT ?? 3000}/api`, "Main");
|
|
100
101
|
{{else if hasTrpc}}
|
|
@@ -4,10 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
## Setup
|
|
6
6
|
|
|
7
|
+
{{#if setupInstructions}}
|
|
8
|
+
{{{setupInstructions}}}
|
|
9
|
+
{{else}}
|
|
7
10
|
```bash
|
|
8
11
|
# Install dependencies
|
|
9
12
|
{{#if isPnpm}}pnpm install{{else if isYarn}}yarn install{{else if isBun}}bun install{{else}}npm install{{/if}}
|
|
10
13
|
```
|
|
14
|
+
{{/if}}
|
|
11
15
|
|
|
12
16
|
## Running the App
|
|
13
17
|
|
|
@@ -35,20 +39,11 @@
|
|
|
35
39
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
|
|
36
40
|
## Auth Setup
|
|
37
41
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
{{#if useDrizzle}}Then run Drizzle migrations:
|
|
45
|
-
|
|
46
|
-
```bash
|
|
47
|
-
{{#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}}
|
|
48
|
-
```
|
|
49
|
-
|
|
42
|
+
{{#if (eq auth "better-auth:stateless")}}
|
|
43
|
+
Configure the Better Auth secret, URL and external OIDC provider settings. Register the callback URL with your provider. Stateless auth requires no authentication schema generation or database migration.
|
|
44
|
+
{{else}}
|
|
45
|
+
Follow the ordered steps in Setup. Run the generated `auth:generate` script in `apps/api-gateway` before applying the database schema and regenerating Prisma Client in `packages/db`. The script uses the installed CLI version and preserves application-owned models.
|
|
50
46
|
{{/if}}
|
|
51
|
-
See https://better-auth.com/docs/adapters/prisma for more details.
|
|
52
47
|
|
|
53
48
|
### Usage
|
|
54
49
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
CORS_ORIGIN=http://localhost:
|
|
1
|
+
CORS_ORIGIN=http://localhost:3000
|
|
2
2
|
PORT=3000
|
|
3
3
|
{{#if hasGraphql}}
|
|
4
4
|
GRAPHQL_PLAYGROUND=true
|
|
@@ -13,10 +13,23 @@ MYSQL_URL=mysql://root:mysql@localhost:3306/{{projectNameKebab}}_db
|
|
|
13
13
|
{{#if hasSqlite}}
|
|
14
14
|
SQLITE_PATH=file:./src/database/dev.db
|
|
15
15
|
{{/if}}
|
|
16
|
+
{{#if hasSqlserver}}
|
|
17
|
+
SQLSERVER_HOST=localhost
|
|
18
|
+
SQLSERVER_PORT=1433
|
|
19
|
+
SQLSERVER_DATABASE={{projectNameKebab}}_db
|
|
20
|
+
SQLSERVER_USER=sa
|
|
21
|
+
SQLSERVER_PASSWORD=DevOnly_Strong_Password_2026!X9
|
|
22
|
+
SQLSERVER_ENCRYPT=true
|
|
23
|
+
SQLSERVER_TRUST_SERVER_CERTIFICATE=true
|
|
24
|
+
{{/if}}
|
|
16
25
|
{{#if hasMongodb}}
|
|
17
26
|
MONGODB_URL=mongodb://localhost:27017/{{projectNameKebab}}_db
|
|
18
27
|
{{/if}}
|
|
19
|
-
{{#if (eq auth "passport")}}
|
|
28
|
+
{{#if (and (eq auth "passport") (not hasDatabase))}}
|
|
29
|
+
OIDC_JWKS_URI=https://identity.example.com/.well-known/jwks.json
|
|
30
|
+
OIDC_ISSUER=https://identity.example.com/
|
|
31
|
+
OIDC_AUDIENCE=generated-resource-server
|
|
32
|
+
{{else if (eq auth "passport")}}
|
|
20
33
|
JWT_ACCESS_SECRET=change-me-to-a-random-secret-at-least-32-characters-long
|
|
21
34
|
{{#if hasDatabase}}
|
|
22
35
|
JWT_REFRESH_SECRET=change-me-to-a-different-random-secret-at-least-32-characters
|
|
@@ -12,5 +12,11 @@ allowBuilds:
|
|
|
12
12
|
{{#if hasSqlite}}
|
|
13
13
|
better-sqlite3: true
|
|
14
14
|
{{/if}}
|
|
15
|
+
{{#if hasTrpc}}
|
|
16
|
+
peerDependencyRules:
|
|
17
|
+
allowedVersions:
|
|
18
|
+
"nestjs-trpc>@nestjs/common": "^12.0.0"
|
|
19
|
+
"nestjs-trpc>@nestjs/core": "^12.0.0"
|
|
20
|
+
{{/if}}
|
|
15
21
|
catalog:
|
|
16
22
|
dotenv: ^17.2.2
|
|
@@ -61,9 +61,7 @@ async function bootstrap() {
|
|
|
61
61
|
docsPath,
|
|
62
62
|
apiReference({
|
|
63
63
|
content: await createDocs(app, {
|
|
64
|
-
title: "{{projectNamePascalCase}} API",
|
|
65
64
|
description: "{{description}}",
|
|
66
|
-
version: "1.0.0",
|
|
67
65
|
integrations: {
|
|
68
66
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
|
|
69
67
|
betterAuth: {
|
|
@@ -73,24 +71,25 @@ async function bootstrap() {
|
|
|
73
71
|
{{/if}}
|
|
74
72
|
{{#if (includes apis "trpc")}}
|
|
75
73
|
trpc: {
|
|
76
|
-
routerFilePath: "./src/trpc/router.ts",
|
|
77
74
|
pathPrefix: "/trpc",
|
|
75
|
+
routerFilePath: "./{{trpcGeneratePath}}/server.ts",
|
|
78
76
|
},
|
|
79
77
|
{{/if}}
|
|
80
78
|
zod: {
|
|
81
79
|
withFastify: {{#if (eq httpProvider "fastify")}}true{{else}}false{{/if}},
|
|
82
80
|
},
|
|
83
81
|
},
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
title: "{{projectNamePascalCase}} API",
|
|
83
|
+
version: "1.0.0",
|
|
84
|
+
}),
|
|
85
|
+
{{#if (eq httpProvider "fastify")}}withFastify: true,{{/if}}
|
|
86
|
+
pageTitle: "{{projectNamePascalCase}} API Docs",
|
|
86
87
|
theme: "default",
|
|
87
88
|
}),
|
|
88
89
|
);
|
|
89
90
|
{{else}}
|
|
90
91
|
const document = await createDocs(app, {
|
|
91
|
-
title: "{{projectNamePascalCase}} API",
|
|
92
92
|
description: "{{description}}",
|
|
93
|
-
version: "1.0.0",
|
|
94
93
|
integrations: {
|
|
95
94
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
|
|
96
95
|
betterAuth: {
|
|
@@ -100,14 +99,16 @@ async function bootstrap() {
|
|
|
100
99
|
{{/if}}
|
|
101
100
|
{{#if (includes apis "trpc")}}
|
|
102
101
|
trpc: {
|
|
103
|
-
routerFilePath: "./src/trpc/router.ts",
|
|
104
102
|
pathPrefix: "/trpc",
|
|
103
|
+
routerFilePath: "./{{trpcGeneratePath}}/server.ts",
|
|
105
104
|
},
|
|
106
105
|
{{/if}}
|
|
107
106
|
zod: {
|
|
108
107
|
withFastify: {{#if (eq httpProvider "fastify")}}true{{else}}false{{/if}},
|
|
109
108
|
},
|
|
110
109
|
},
|
|
110
|
+
title: "{{projectNamePascalCase}} API",
|
|
111
|
+
version: "1.0.0",
|
|
111
112
|
});
|
|
112
113
|
SwaggerModule.setup(docsPath, app, document);
|
|
113
114
|
{{/if}}
|
|
@@ -115,7 +116,7 @@ async function bootstrap() {
|
|
|
115
116
|
}
|
|
116
117
|
{{/if}}
|
|
117
118
|
|
|
118
|
-
await app.listen(env.PORT);
|
|
119
|
+
await app.listen(env.PORT, "0.0.0.0");
|
|
119
120
|
{{#if hasRest}}
|
|
120
121
|
Logger.log(`Started backend server on http://localhost:${env.PORT}/api`, "Main");
|
|
121
122
|
{{else if hasTrpc}}
|
|
@@ -33,9 +33,7 @@ async function bootstrap() {
|
|
|
33
33
|
docsPath,
|
|
34
34
|
apiReference({
|
|
35
35
|
content: await createDocs(app, {
|
|
36
|
-
title: "{{projectNamePascalCase}} API",
|
|
37
36
|
description: "{{description}}",
|
|
38
|
-
version: "1.0.0",
|
|
39
37
|
integrations: {
|
|
40
38
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
|
|
41
39
|
betterAuth: {
|
|
@@ -45,7 +43,7 @@ async function bootstrap() {
|
|
|
45
43
|
{{/if}}
|
|
46
44
|
{{#if (includes apis "trpc")}}
|
|
47
45
|
trpc: {
|
|
48
|
-
routerFilePath: "./
|
|
46
|
+
routerFilePath: "./{{trpcGeneratePath}}/server.ts",
|
|
49
47
|
pathPrefix: "/trpc",
|
|
50
48
|
},
|
|
51
49
|
{{/if}}
|
|
@@ -53,16 +51,17 @@ async function bootstrap() {
|
|
|
53
51
|
withFastify: {{#if (eq httpProvider "fastify")}}true{{else}}false{{/if}},
|
|
54
52
|
},
|
|
55
53
|
},
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
title: "{{projectNamePascalCase}} API",
|
|
55
|
+
version: "1.0.0",
|
|
56
|
+
}),
|
|
57
|
+
{{#if (eq httpProvider "fastify")}}withFastify: true,{{/if}}
|
|
58
|
+
pageTitle: "{{projectNamePascalCase}} API Docs",
|
|
58
59
|
theme: "default",
|
|
59
60
|
}),
|
|
60
61
|
);
|
|
61
62
|
{{else}}
|
|
62
63
|
const document = await createDocs(app, {
|
|
63
|
-
title: "{{projectNamePascalCase}} API",
|
|
64
64
|
description: "{{description}}",
|
|
65
|
-
version: "1.0.0",
|
|
66
65
|
integrations: {
|
|
67
66
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
|
|
68
67
|
betterAuth: {
|
|
@@ -72,7 +71,7 @@ async function bootstrap() {
|
|
|
72
71
|
{{/if}}
|
|
73
72
|
{{#if (includes apis "trpc")}}
|
|
74
73
|
trpc: {
|
|
75
|
-
routerFilePath: "./
|
|
74
|
+
routerFilePath: "./{{trpcGeneratePath}}/server.ts",
|
|
76
75
|
pathPrefix: "/trpc",
|
|
77
76
|
},
|
|
78
77
|
{{/if}}
|
|
@@ -80,6 +79,8 @@ async function bootstrap() {
|
|
|
80
79
|
withFastify: {{#if (eq httpProvider "fastify")}}true{{else}}false{{/if}},
|
|
81
80
|
},
|
|
82
81
|
},
|
|
82
|
+
title: "{{projectNamePascalCase}} API",
|
|
83
|
+
version: "1.0.0",
|
|
83
84
|
});
|
|
84
85
|
SwaggerModule.setup(docsPath, app, document);
|
|
85
86
|
{{/if}}
|
|
@@ -87,7 +88,7 @@ async function bootstrap() {
|
|
|
87
88
|
}
|
|
88
89
|
{{/if}}
|
|
89
90
|
|
|
90
|
-
await app.listen(env.PORT ?? 3000);
|
|
91
|
+
await app.listen(env.PORT ?? 3000, "0.0.0.0");
|
|
91
92
|
{{#if hasRest}}
|
|
92
93
|
Logger.log(`Started backend server on http://localhost:${env.PORT ?? 3000}/api`, "Main");
|
|
93
94
|
{{else if hasTrpc}}
|
|
@@ -2,21 +2,27 @@ PORT=3000
|
|
|
2
2
|
MICROSERVICE_PORT=3001
|
|
3
3
|
CORS_ORIGIN=http://localhost:3001
|
|
4
4
|
{{#if (includes microservices "redis")}}
|
|
5
|
+
REDIS_PORT=6379
|
|
5
6
|
REDIS_URL=redis://127.0.0.1:6379
|
|
6
7
|
{{/if}}
|
|
7
8
|
{{#if (includes microservices "mqtt")}}
|
|
9
|
+
MQTT_PORT=1883
|
|
8
10
|
MQTT_URL=mqtt://127.0.0.1:1883
|
|
9
11
|
{{/if}}
|
|
10
12
|
{{#if (includes microservices "nats")}}
|
|
13
|
+
NATS_PORT=4222
|
|
11
14
|
NATS_URL=nats://127.0.0.1:4222
|
|
12
15
|
{{/if}}
|
|
13
16
|
{{#if (includes microservices "rabbitmq")}}
|
|
17
|
+
RABBITMQ_PORT=5672
|
|
14
18
|
RABBITMQ_URL=amqp://127.0.0.1:5672
|
|
15
19
|
{{/if}}
|
|
16
20
|
{{#if (includes microservices "kafka")}}
|
|
21
|
+
KAFKA_PORT=9092
|
|
17
22
|
KAFKA_BROKER=127.0.0.1:9092
|
|
18
23
|
{{/if}}
|
|
19
24
|
{{#if (includes microservices "grpc")}}
|
|
25
|
+
GRPC_PORT=5000
|
|
20
26
|
GRPC_URL=0.0.0.0:5000
|
|
21
27
|
{{/if}}
|
|
22
28
|
{{#if hasGraphql}}
|
package/dist/templates/single-project/architecture/nest-microservice/src/app.controller.ts.hbs
CHANGED
|
@@ -9,11 +9,11 @@ import { EventPattern, MessagePattern } from "@nestjs/microservices";
|
|
|
9
9
|
import { AppService } from "./app.service.js";
|
|
10
10
|
|
|
11
11
|
{{#unless (includes microservices "grpc")}}
|
|
12
|
-
|
|
12
|
+
interface AuditEvent {
|
|
13
13
|
id: string;
|
|
14
14
|
payload: Record<string, unknown>;
|
|
15
15
|
source: string;
|
|
16
|
-
}
|
|
16
|
+
}
|
|
17
17
|
|
|
18
18
|
const isAuditEvent = (value: unknown): value is AuditEvent => {
|
|
19
19
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { Module } from "@nestjs/common";
|
|
2
|
+
{{#if hasRateLimiting}}
|
|
3
|
+
import { APP_GUARD } from "@nestjs/core";
|
|
4
|
+
import { ThrottlerModule } from "@nestjs/throttler";
|
|
5
|
+
{{/if}}
|
|
2
6
|
{{#if (or hasDatabase hasOrm)}}
|
|
3
7
|
import { DbModule } from "./database/db.module.js";
|
|
4
8
|
import { env } from "./config/env.js";
|
|
@@ -9,6 +13,15 @@ import { AuthModule } from "./auth/auth.module.js";
|
|
|
9
13
|
|
|
10
14
|
import { AppController } from "./app.controller.js";
|
|
11
15
|
import { AppService } from "./app.service.js";
|
|
16
|
+
{{#if hasRateLimiting}}
|
|
17
|
+
import { HttpThrottlerGuard } from "./http-throttler.guard.js";
|
|
18
|
+
{{/if}}
|
|
19
|
+
{{#if (and hasRest hasTodoExample)}}
|
|
20
|
+
import { TodoModule } from "./api/todo/todo.module.js";
|
|
21
|
+
{{/if}}
|
|
22
|
+
{{#if hasHealthCheck}}
|
|
23
|
+
import { HealthModule } from "./health/health.module.js";
|
|
24
|
+
{{/if}}
|
|
12
25
|
|
|
13
26
|
@Module({
|
|
14
27
|
controllers: [AppController],
|
|
@@ -24,7 +37,21 @@ import { AppService } from "./app.service.js";
|
|
|
24
37
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
|
|
25
38
|
AuthModule,
|
|
26
39
|
{{/if}}
|
|
40
|
+
{{#if hasRateLimiting}}
|
|
41
|
+
ThrottlerModule.forRoot([{ limit: 60, ttl: 60_000 }]),
|
|
42
|
+
{{/if}}
|
|
43
|
+
{{#if (and hasRest hasTodoExample)}}
|
|
44
|
+
TodoModule,
|
|
45
|
+
{{/if}}
|
|
46
|
+
{{#if hasHealthCheck}}
|
|
47
|
+
HealthModule,
|
|
48
|
+
{{/if}}
|
|
49
|
+
],
|
|
50
|
+
providers: [
|
|
51
|
+
AppService,
|
|
52
|
+
{{#if hasRateLimiting}}
|
|
53
|
+
{ provide: APP_GUARD, useClass: HttpThrottlerGuard },
|
|
54
|
+
{{/if}}
|
|
27
55
|
],
|
|
28
|
-
providers: [AppService],
|
|
29
56
|
})
|
|
30
57
|
export class AppModule {}
|
package/dist/templates/single-project/architecture/nest-microservice/src/http-throttler.guard.ts.hbs
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Injectable } from "@nestjs/common";
|
|
2
|
+
import type { ExecutionContext } from "@nestjs/common";
|
|
3
|
+
import { ThrottlerGuard } from "@nestjs/throttler";
|
|
4
|
+
|
|
5
|
+
@Injectable()
|
|
6
|
+
export class HttpThrottlerGuard extends ThrottlerGuard {
|
|
7
|
+
canActivate(context: ExecutionContext): Promise<boolean> {
|
|
8
|
+
if (context.getType() !== "http") {
|
|
9
|
+
return Promise.resolve(true);
|
|
10
|
+
}
|
|
11
|
+
return super.canActivate(context);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -68,9 +68,7 @@ async function bootstrap() {
|
|
|
68
68
|
docsPath,
|
|
69
69
|
apiReference({
|
|
70
70
|
content: await createDocs(app, {
|
|
71
|
-
title: "{{projectNamePascalCase}} API",
|
|
72
71
|
description: "{{description}}",
|
|
73
|
-
version: "1.0.0",
|
|
74
72
|
integrations: {
|
|
75
73
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
|
|
76
74
|
betterAuth: {
|
|
@@ -80,7 +78,7 @@ async function bootstrap() {
|
|
|
80
78
|
{{/if}}
|
|
81
79
|
{{#if (includes apis "trpc")}}
|
|
82
80
|
trpc: {
|
|
83
|
-
routerFilePath: "./
|
|
81
|
+
routerFilePath: "./{{trpcGeneratePath}}/server.ts",
|
|
84
82
|
pathPrefix: "/trpc",
|
|
85
83
|
},
|
|
86
84
|
{{/if}}
|
|
@@ -88,16 +86,17 @@ async function bootstrap() {
|
|
|
88
86
|
withFastify: {{#if (eq httpProvider "fastify")}}true{{else}}false{{/if}},
|
|
89
87
|
},
|
|
90
88
|
},
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
title: "{{projectNamePascalCase}} API",
|
|
90
|
+
version: "1.0.0",
|
|
91
|
+
}),
|
|
92
|
+
{{#if (eq httpProvider "fastify")}}withFastify: true,{{/if}}
|
|
93
|
+
pageTitle: "{{projectNamePascalCase}} API Docs",
|
|
93
94
|
theme: "default",
|
|
94
95
|
}),
|
|
95
96
|
);
|
|
96
97
|
{{else}}
|
|
97
98
|
const document = await createDocs(app, {
|
|
98
|
-
title: "{{projectNamePascalCase}} API",
|
|
99
99
|
description: "{{description}}",
|
|
100
|
-
version: "1.0.0",
|
|
101
100
|
integrations: {
|
|
102
101
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
|
|
103
102
|
betterAuth: {
|
|
@@ -107,7 +106,7 @@ async function bootstrap() {
|
|
|
107
106
|
{{/if}}
|
|
108
107
|
{{#if (includes apis "trpc")}}
|
|
109
108
|
trpc: {
|
|
110
|
-
routerFilePath: "./
|
|
109
|
+
routerFilePath: "./{{trpcGeneratePath}}/server.ts",
|
|
111
110
|
pathPrefix: "/trpc",
|
|
112
111
|
},
|
|
113
112
|
{{/if}}
|
|
@@ -115,6 +114,8 @@ async function bootstrap() {
|
|
|
115
114
|
withFastify: {{#if (eq httpProvider "fastify")}}true{{else}}false{{/if}},
|
|
116
115
|
},
|
|
117
116
|
},
|
|
117
|
+
title: "{{projectNamePascalCase}} API",
|
|
118
|
+
version: "1.0.0",
|
|
118
119
|
});
|
|
119
120
|
SwaggerModule.setup(docsPath, app, document);
|
|
120
121
|
{{/if}}
|
|
@@ -123,7 +124,7 @@ async function bootstrap() {
|
|
|
123
124
|
{{/if}}
|
|
124
125
|
|
|
125
126
|
await app.startAllMicroservices();
|
|
126
|
-
await app.listen(env.PORT ?? 3000);
|
|
127
|
+
await app.listen(env.PORT ?? 3000, "0.0.0.0");
|
|
127
128
|
{{#if hasRest}}
|
|
128
129
|
Logger.log(`Started backend server on http://localhost:${env.PORT ?? 3000}/api`, "Main");
|
|
129
130
|
{{else if hasTrpc}}
|
|
@@ -6,6 +6,9 @@ import { Test } from "@nestjs/testing";
|
|
|
6
6
|
import { setTimeout as delay } from "node:timers/promises";
|
|
7
7
|
import request from "supertest";
|
|
8
8
|
{{/unless}}
|
|
9
|
+
{{#if (and (includes microservices "grpc") (or hasTodoExample hasHealthCheck hasRateLimiting))}}
|
|
10
|
+
import request from "supertest";
|
|
11
|
+
{{/if}}
|
|
9
12
|
import { firstValueFrom } from "rxjs";
|
|
10
13
|
{{#if (includes microservices "grpc")}}
|
|
11
14
|
import type { Observable } from "rxjs";
|
|
@@ -96,6 +99,38 @@ it("sends ping through the selected message transport", async () => {
|
|
|
96
99
|
{{/if}}
|
|
97
100
|
}, 60_000);
|
|
98
101
|
|
|
102
|
+
{{#if (or hasTodoExample hasHealthCheck hasRateLimiting)}}
|
|
103
|
+
it("serves the selected HTTP extras alongside the message transport", async () => {
|
|
104
|
+
const server = app.getHttpServer();
|
|
105
|
+
{{#if hasTodoExample}}
|
|
106
|
+
const created = await request(server)
|
|
107
|
+
.post("/api/todos")
|
|
108
|
+
.send({ completed: false, title: "Microservice todo" })
|
|
109
|
+
.expect(201);
|
|
110
|
+
const todo = created.body as { id: string };
|
|
111
|
+
const listed = await request(server).get("/api/todos").expect(200);
|
|
112
|
+
expect(listed.body).toEqual(
|
|
113
|
+
expect.arrayContaining([expect.objectContaining({ id: todo.id })])
|
|
114
|
+
);
|
|
115
|
+
await request(server)
|
|
116
|
+
.put(`/api/todos/${todo.id}`)
|
|
117
|
+
.send({ completed: true })
|
|
118
|
+
.expect(200);
|
|
119
|
+
await request(server).delete(`/api/todos/${todo.id}`).expect(200);
|
|
120
|
+
{{/if}}
|
|
121
|
+
{{#if hasHealthCheck}}
|
|
122
|
+
const health = await request(server).get("/api/health").expect(200);
|
|
123
|
+
expect(health.body.info.app.status).toBe("up");
|
|
124
|
+
{{/if}}
|
|
125
|
+
{{#if hasRateLimiting}}
|
|
126
|
+
const responses = await Promise.all(
|
|
127
|
+
Array.from({ length: 80 }, () => request(server).get("/api"))
|
|
128
|
+
);
|
|
129
|
+
expect(responses.some((response) => response.status === 429)).toBe(true);
|
|
130
|
+
{{/if}}
|
|
131
|
+
}, 60_000);
|
|
132
|
+
{{/if}}
|
|
133
|
+
|
|
99
134
|
afterAll(async () => {
|
|
100
135
|
await app?.close();
|
|
101
136
|
client.close();
|
|
@@ -64,6 +64,15 @@ export const env = createEnv({
|
|
|
64
64
|
{{#if hasSqlite}}
|
|
65
65
|
SQLITE_PATH: z.string().default("sqlite.db"),
|
|
66
66
|
{{/if}}
|
|
67
|
+
{{#if hasSqlserver}}
|
|
68
|
+
SQLSERVER_HOST: z.string().default("localhost"),
|
|
69
|
+
SQLSERVER_PORT: z.string().transform(Number).default(1433),
|
|
70
|
+
SQLSERVER_DATABASE: z.string().default("{{projectNameKebab}}_db"),
|
|
71
|
+
SQLSERVER_USER: z.string(),
|
|
72
|
+
SQLSERVER_PASSWORD: z.string(),
|
|
73
|
+
SQLSERVER_ENCRYPT: z.string().transform((value) => value !== "false").default(true),
|
|
74
|
+
SQLSERVER_TRUST_SERVER_CERTIFICATE: z.string().transform((value) => value === "true").default(false),
|
|
75
|
+
{{/if}}
|
|
67
76
|
{{#if hasMongodb}}
|
|
68
77
|
MONGODB_URL: z.url(),
|
|
69
78
|
{{/if}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nest-arch/tui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Interactive terminal UI for generating NestJS projects",
|
|
6
6
|
"keywords": [
|
|
@@ -45,15 +45,15 @@
|
|
|
45
45
|
"zod": "^4.1.13"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
+
"@nest-arch/core": "0.4.3",
|
|
49
|
+
"@nest-arch/env": "0.0.0",
|
|
50
|
+
"@nest-arch/shared": "0.0.0",
|
|
48
51
|
"@types/react": "^18.3.12",
|
|
49
52
|
"@types/semver": "^7.8.0",
|
|
50
53
|
"ink-testing-library": "^4.0.0",
|
|
51
54
|
"pkgroll": "^2.5.2",
|
|
52
55
|
"tsx": "^4.19.2",
|
|
53
|
-
"vitest": "^4.1.7"
|
|
54
|
-
"@nest-arch/core": "0.4.3",
|
|
55
|
-
"@nest-arch/env": "0.0.0",
|
|
56
|
-
"@nest-arch/shared": "0.0.0"
|
|
56
|
+
"vitest": "^4.1.7"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"typescript": "^5"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var o="0.4.5",O={version:o};const s="Nest Arch",A=`v${O.version}`,n="Build production-ready NestJS projects.",t="#e54545",c="#A0A0A0",R="#6B6B6B",C="#E5E5E5",E="#61AFEF",_="#3A3A3A",e="#7FD99A",r="#E8C468",L="#e96142ff";export{s as APP_NAME,n as APP_TAGLINE,A as APP_VERSION,E as COLOR_ACCENT,c as COLOR_DIM,R as COLOR_DIMMER,_ as COLOR_DIVIDER,C as COLOR_FG,t as COLOR_RED,e as COLOR_SUCCESS,r as COLOR_WARM,L as COLOR_WARM_SECONDARY};
|