@nest-arch/tui 0.4.4 → 0.4.6
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-7dJLZpB2.js → constants-DVhgS48N.js} +1 -1
- package/dist/index.js +148 -133
- package/dist/templates/addons/husky/noop-hook.hbs +2 -0
- package/dist/templates/base/.env.example.hbs +9 -0
- package/dist/templates/base/.env.hbs +9 -0
- package/dist/templates/base/README.md.hbs +12 -0
- package/dist/templates/base/prisma.config.ts.hbs +1 -0
- package/dist/templates/base/src/app.module.ts.hbs +1 -0
- package/dist/templates/base/src/database/adapters/interfaces/db-adapter.interface.ts.hbs +4 -4
- package/dist/templates/base/src/database/adapters/mongo/prisma-mongo.adapter.ts.hbs +4 -4
- package/dist/templates/base/src/database/db.module.ts.hbs +15 -2
- package/dist/templates/base/src/database/db.service.ts.hbs +5 -5
- package/dist/templates/base/src/database/index.ts.hbs +12 -3
- package/dist/templates/base/src/main.ts.hbs +5 -4
- package/dist/templates/base/test/app.e2e-spec.ts.hbs +50 -13
- package/dist/templates/base/test/bootstrap.e2e-spec.ts.hbs +2 -2
- package/dist/templates/base/tsconfig.build.json.hbs +1 -0
- package/dist/templates/base/vitest.config.e2e.ts.hbs +1 -1
- package/dist/templates/base/vitest.config.ts.hbs +1 -1
- package/dist/templates/extras/docker/Dockerfile.hbs +1 -1
- package/dist/templates/extras/health/src/health/health.controller.ts.hbs +7 -3
- package/dist/templates/feature/rest/todo-example/src/api/todo/todo.controller.ts.hbs +4 -6
- package/dist/templates/feature/rest/todo-example/src/api/todo/todo.router.ts.hbs +38 -37
- package/dist/templates/monorepo/apps/api-gateway/src/main.ts.hbs +8 -7
- package/dist/templates/monorepo/apps/api-gateway/test/app.e2e-spec.ts.hbs +4 -1
- package/dist/templates/single-project/architecture/nest-api/.env.hbs +9 -0
- package/dist/templates/single-project/architecture/nest-api/src/main.ts.hbs +8 -7
- package/dist/templates/single-project/architecture/nest-gateway/src/main.ts.hbs +8 -7
- package/dist/templates/single-project/architecture/nest-microservice/src/app.controller.ts.hbs +52 -1
- package/dist/templates/single-project/architecture/nest-microservice/src/app.service.ts.hbs +21 -0
- package/dist/templates/single-project/architecture/nest-microservice/src/main.ts.hbs +35 -16
- package/dist/templates/single-project/architecture/nest-microservice/test/microservice.e2e-spec.ts.hbs +51 -19
- package/dist/templates/single-project/shared/config/env.ts.hbs +27 -16
- package/package.json +2 -2
|
@@ -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: {
|
|
@@ -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: {
|
|
@@ -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,7 +4,10 @@ import { Test, TestingModule } from "@nestjs/testing";
|
|
|
4
4
|
import { FastifyAdapter } from "@nestjs/platform-fastify";
|
|
5
5
|
{{/if}}
|
|
6
6
|
import request from "supertest";
|
|
7
|
-
import { afterEach, beforeEach, describe,
|
|
7
|
+
import { afterEach, beforeEach, describe, it } from "vitest";
|
|
8
|
+
{{#if (eq auth "better-auth")}}
|
|
9
|
+
import { expect } from "vitest";
|
|
10
|
+
{{/if}}
|
|
8
11
|
import type { App } from "supertest/types";
|
|
9
12
|
|
|
10
13
|
import { AppModule } from "./../src/app.module.js";
|
|
@@ -13,6 +13,15 @@ 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}}
|
|
@@ -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: {
|
|
@@ -81,16 +79,17 @@ async function bootstrap() {
|
|
|
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: {
|
|
@@ -108,6 +107,8 @@ async function bootstrap() {
|
|
|
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: {
|
|
@@ -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: {
|
|
@@ -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}}
|
package/dist/templates/single-project/architecture/nest-microservice/src/app.controller.ts.hbs
CHANGED
|
@@ -1,10 +1,43 @@
|
|
|
1
|
+
{{#if (includes microservices "grpc")}}
|
|
1
2
|
import { Controller, Get } from "@nestjs/common";
|
|
2
|
-
import {
|
|
3
|
+
import { GrpcMethod } from "@nestjs/microservices";
|
|
4
|
+
{{else}}
|
|
5
|
+
import { Controller, Get, Logger, Param } from "@nestjs/common";
|
|
6
|
+
import { EventPattern, MessagePattern } from "@nestjs/microservices";
|
|
7
|
+
{{/if}}
|
|
3
8
|
|
|
4
9
|
import { AppService } from "./app.service.js";
|
|
5
10
|
|
|
11
|
+
{{#unless (includes microservices "grpc")}}
|
|
12
|
+
type AuditEvent = {
|
|
13
|
+
id: string;
|
|
14
|
+
payload: Record<string, unknown>;
|
|
15
|
+
source: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const isAuditEvent = (value: unknown): value is AuditEvent => {
|
|
19
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
const candidate = value as Record<string, unknown>;
|
|
23
|
+
return (
|
|
24
|
+
typeof candidate.id === "string" &&
|
|
25
|
+
candidate.id.trim().length > 0 &&
|
|
26
|
+
typeof candidate.source === "string" &&
|
|
27
|
+
candidate.source.trim().length > 0 &&
|
|
28
|
+
typeof candidate.payload === "object" &&
|
|
29
|
+
candidate.payload !== null &&
|
|
30
|
+
!Array.isArray(candidate.payload)
|
|
31
|
+
);
|
|
32
|
+
};
|
|
33
|
+
{{/unless}}
|
|
34
|
+
|
|
6
35
|
@Controller()
|
|
7
36
|
export class AppController {
|
|
37
|
+
{{#unless (includes microservices "grpc")}}
|
|
38
|
+
private readonly logger = new Logger(AppController.name);
|
|
39
|
+
{{/unless}}
|
|
40
|
+
|
|
8
41
|
constructor(private readonly appService: AppService) {}
|
|
9
42
|
|
|
10
43
|
@Get()
|
|
@@ -12,6 +45,24 @@ export class AppController {
|
|
|
12
45
|
return this.appService.getHello();
|
|
13
46
|
}
|
|
14
47
|
|
|
48
|
+
{{#unless (includes microservices "grpc")}}
|
|
49
|
+
@Get("events/:id")
|
|
50
|
+
getAuditEvent(
|
|
51
|
+
@Param("id") id: string
|
|
52
|
+
): { id: string; payload: Record<string, unknown>; source: string } | null {
|
|
53
|
+
return this.appService.getAuditEvent(id);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@EventPattern("audit")
|
|
57
|
+
handleAuditEvent(data: unknown): void {
|
|
58
|
+
if (!isAuditEvent(data)) {
|
|
59
|
+
this.logger.warn("Discarded malformed audit event payload");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
this.appService.recordAuditEvent(data);
|
|
63
|
+
}
|
|
64
|
+
{{/unless}}
|
|
65
|
+
|
|
15
66
|
{{#if (includes microservices "grpc")}}
|
|
16
67
|
@GrpcMethod("AppService", "Ping")
|
|
17
68
|
handleGrpcPing(): { message: string } {
|
|
@@ -5,6 +5,27 @@ import { DbService } from "./database/db.service.js";
|
|
|
5
5
|
|
|
6
6
|
@Injectable()
|
|
7
7
|
export class AppService {
|
|
8
|
+
{{#unless (includes microservices "grpc")}}
|
|
9
|
+
private readonly auditEvents = new Map<
|
|
10
|
+
string,
|
|
11
|
+
{ id: string; payload: Record<string, unknown>; source: string }
|
|
12
|
+
>();
|
|
13
|
+
|
|
14
|
+
recordAuditEvent(event: {
|
|
15
|
+
id: string;
|
|
16
|
+
payload: Record<string, unknown>;
|
|
17
|
+
source: string;
|
|
18
|
+
}): void {
|
|
19
|
+
this.auditEvents.set(event.id, event);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getAuditEvent(
|
|
23
|
+
id: string
|
|
24
|
+
): { id: string; payload: Record<string, unknown>; source: string } | null {
|
|
25
|
+
return this.auditEvents.get(id) ?? null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
{{/unless}}
|
|
8
29
|
{{#if (or hasDatabase hasOrm)}}
|
|
9
30
|
constructor(private readonly db: DbService) {}
|
|
10
31
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { NestFactory } from "@nestjs/core";
|
|
2
1
|
{{#if (eq httpProvider "fastify")}}
|
|
3
2
|
import { FastifyAdapter, NestFastifyApplication } from "@nestjs/platform-fastify";
|
|
4
3
|
{{/if}}
|
|
5
4
|
import { Logger } from "@nestjs/common";
|
|
6
|
-
import {
|
|
5
|
+
import { NestFactory } from "@nestjs/core";
|
|
6
|
+
import { Transport } from "@nestjs/microservices";
|
|
7
|
+
import type { MicroserviceOptions } from "@nestjs/microservices";
|
|
7
8
|
|
|
8
9
|
import { AppModule } from "./app.module.js";
|
|
9
10
|
import { env } from "./config/env.js";
|
|
@@ -27,19 +28,36 @@ async function bootstrap() {
|
|
|
27
28
|
app.enableShutdownHooks();
|
|
28
29
|
|
|
29
30
|
app.connectMicroservice<MicroserviceOptions>({
|
|
30
|
-
transport: {{#if (includes microservices "redis")}}Transport.REDIS{{else if (includes microservices "mqtt")}}Transport.MQTT{{else if (includes microservices "nats")}}Transport.NATS{{else if (includes microservices "rabbitmq")}}Transport.RMQ{{else if (includes microservices "kafka")}}Transport.KAFKA{{else if (includes microservices "grpc")}}Transport.GRPC{{else}}Transport.TCP{{/if}},
|
|
31
31
|
options: {
|
|
32
|
-
{{#if (includes microservices "
|
|
33
|
-
{
|
|
34
|
-
{{
|
|
35
|
-
{{#if (includes microservices "
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
{{#if (includes microservices "kafka")}}
|
|
33
|
+
client: { brokers: [env.KAFKA_BROKER ?? "127.0.0.1:9092"] },
|
|
34
|
+
{{/if}}
|
|
35
|
+
{{#if (includes microservices "grpc")}}
|
|
36
|
+
package: "app",
|
|
37
|
+
protoPath: "proto/app.proto",
|
|
38
|
+
url: env.GRPC_URL ?? "0.0.0.0:5000",
|
|
39
|
+
{{/if}}
|
|
40
|
+
{{#if (includes microservices "rabbitmq")}}
|
|
41
|
+
queue: "ping",
|
|
42
|
+
queueOptions: { durable: false },
|
|
43
|
+
urls: [env.RABBITMQ_URL ?? "amqp://127.0.0.1:5672"],
|
|
44
|
+
{{/if}}
|
|
45
|
+
{{#if (includes microservices "redis")}}
|
|
46
|
+
host: new URL(env.REDIS_URL).hostname,
|
|
47
|
+
port: Number(new URL(env.REDIS_URL).port || 6379),
|
|
48
|
+
{{/if}}
|
|
49
|
+
{{#if (includes microservices "nats")}}
|
|
50
|
+
servers: [env.NATS_URL ?? "nats://127.0.0.1:4222"],
|
|
51
|
+
{{/if}}
|
|
52
|
+
{{#if (includes microservices "mqtt")}}
|
|
53
|
+
url: env.MQTT_URL ?? "mqtt://127.0.0.1:1883",
|
|
54
|
+
{{/if}}
|
|
38
55
|
{{#unless (or (includes microservices "redis") (includes microservices "mqtt") (includes microservices "nats") (includes microservices "rabbitmq") (includes microservices "kafka") (includes microservices "grpc"))}}
|
|
39
56
|
host: "0.0.0.0",
|
|
40
57
|
port: env.MICROSERVICE_PORT,
|
|
41
58
|
{{/unless}}
|
|
42
59
|
},
|
|
60
|
+
transport: {{#if (includes microservices "redis")}}Transport.REDIS{{else if (includes microservices "mqtt")}}Transport.MQTT{{else if (includes microservices "nats")}}Transport.NATS{{else if (includes microservices "rabbitmq")}}Transport.RMQ{{else if (includes microservices "kafka")}}Transport.KAFKA{{else if (includes microservices "grpc")}}Transport.GRPC{{else}}Transport.TCP{{/if}},
|
|
43
61
|
});
|
|
44
62
|
|
|
45
63
|
{{#if swagger}}
|
|
@@ -50,9 +68,7 @@ async function bootstrap() {
|
|
|
50
68
|
docsPath,
|
|
51
69
|
apiReference({
|
|
52
70
|
content: await createDocs(app, {
|
|
53
|
-
title: "{{projectNamePascalCase}} API",
|
|
54
71
|
description: "{{description}}",
|
|
55
|
-
version: "1.0.0",
|
|
56
72
|
integrations: {
|
|
57
73
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
|
|
58
74
|
betterAuth: {
|
|
@@ -70,16 +86,17 @@ async function bootstrap() {
|
|
|
70
86
|
withFastify: {{#if (eq httpProvider "fastify")}}true{{else}}false{{/if}},
|
|
71
87
|
},
|
|
72
88
|
},
|
|
73
|
-
|
|
74
|
-
|
|
89
|
+
title: "{{projectNamePascalCase}} API",
|
|
90
|
+
version: "1.0.0",
|
|
91
|
+
}),
|
|
92
|
+
{{#if (eq httpProvider "fastify")}}withFastify: true,{{/if}}
|
|
93
|
+
pageTitle: "{{projectNamePascalCase}} API Docs",
|
|
75
94
|
theme: "default",
|
|
76
95
|
}),
|
|
77
96
|
);
|
|
78
97
|
{{else}}
|
|
79
98
|
const document = await createDocs(app, {
|
|
80
|
-
title: "{{projectNamePascalCase}} API",
|
|
81
99
|
description: "{{description}}",
|
|
82
|
-
version: "1.0.0",
|
|
83
100
|
integrations: {
|
|
84
101
|
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
|
|
85
102
|
betterAuth: {
|
|
@@ -97,6 +114,8 @@ async function bootstrap() {
|
|
|
97
114
|
withFastify: {{#if (eq httpProvider "fastify")}}true{{else}}false{{/if}},
|
|
98
115
|
},
|
|
99
116
|
},
|
|
117
|
+
title: "{{projectNamePascalCase}} API",
|
|
118
|
+
version: "1.0.0",
|
|
100
119
|
});
|
|
101
120
|
SwaggerModule.setup(docsPath, app, document);
|
|
102
121
|
{{/if}}
|
|
@@ -105,7 +124,7 @@ async function bootstrap() {
|
|
|
105
124
|
{{/if}}
|
|
106
125
|
|
|
107
126
|
await app.startAllMicroservices();
|
|
108
|
-
await app.listen(env.PORT ?? 3000);
|
|
127
|
+
await app.listen(env.PORT ?? 3000, "0.0.0.0");
|
|
109
128
|
{{#if hasRest}}
|
|
110
129
|
Logger.log(`Started backend server on http://localhost:${env.PORT ?? 3000}/api`, "Main");
|
|
111
130
|
{{else if hasTrpc}}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
{{#if (includes microservices "grpc")}}type ClientGrpc,{{else if (includes microservices "kafka")}}type ClientKafka,{{else}}type ClientProxy,{{/if}}
|
|
5
|
-
type MicroserviceOptions,
|
|
6
|
-
Transport,
|
|
7
|
-
} from "@nestjs/microservices";
|
|
1
|
+
import type { INestApplication } from "@nestjs/common";
|
|
2
|
+
import { ClientProxyFactory, Transport } from "@nestjs/microservices";
|
|
3
|
+
import type { {{#if (includes microservices "grpc")}}ClientGrpc{{else if (includes microservices "kafka")}}ClientKafka{{else}}ClientProxy{{/if}}, MicroserviceOptions } from "@nestjs/microservices";
|
|
8
4
|
import { Test } from "@nestjs/testing";
|
|
5
|
+
{{#unless (includes microservices "grpc")}}
|
|
9
6
|
import { setTimeout as delay } from "node:timers/promises";
|
|
10
|
-
import
|
|
7
|
+
import request from "supertest";
|
|
8
|
+
{{/unless}}
|
|
9
|
+
import { firstValueFrom } from "rxjs";
|
|
10
|
+
{{#if (includes microservices "grpc")}}
|
|
11
|
+
import type { Observable } from "rxjs";
|
|
12
|
+
{{/if}}
|
|
11
13
|
import { afterAll, expect, it } from "vitest";
|
|
12
14
|
|
|
13
15
|
import { AppModule } from "../src/app.module.js";
|
|
@@ -16,21 +18,40 @@ import { env } from "../src/config/env.js";
|
|
|
16
18
|
const transport = {{#if (includes microservices "redis")}}Transport.REDIS{{else if (includes microservices "mqtt")}}Transport.MQTT{{else if (includes microservices "nats")}}Transport.NATS{{else if (includes microservices "rabbitmq")}}Transport.RMQ{{else if (includes microservices "kafka")}}Transport.KAFKA{{else if (includes microservices "grpc")}}Transport.GRPC{{else}}Transport.TCP{{/if}};
|
|
17
19
|
|
|
18
20
|
const options = {
|
|
19
|
-
{{#if (includes microservices "
|
|
20
|
-
{
|
|
21
|
-
{
|
|
22
|
-
{{
|
|
23
|
-
{{#if (includes microservices "
|
|
24
|
-
|
|
21
|
+
{{#if (includes microservices "kafka")}}
|
|
22
|
+
client: { brokers: [env.KAFKA_BROKER] },
|
|
23
|
+
consumer: { groupId: "ping-consumer" },
|
|
24
|
+
{{/if}}
|
|
25
|
+
{{#if (includes microservices "grpc")}}
|
|
26
|
+
package: "app",
|
|
27
|
+
protoPath: "proto/app.proto",
|
|
28
|
+
url: env.GRPC_URL,
|
|
29
|
+
{{/if}}
|
|
30
|
+
{{#if (includes microservices "rabbitmq")}}
|
|
31
|
+
queue: "ping",
|
|
32
|
+
queueOptions: { durable: false },
|
|
33
|
+
urls: [env.RABBITMQ_URL],
|
|
34
|
+
{{/if}}
|
|
35
|
+
{{#if (includes microservices "redis")}}
|
|
36
|
+
host: new URL(env.REDIS_URL).hostname,
|
|
37
|
+
port: Number(new URL(env.REDIS_URL).port || 6379),
|
|
38
|
+
{{/if}}
|
|
39
|
+
{{#if (includes microservices "nats")}}
|
|
40
|
+
servers: [env.NATS_URL],
|
|
41
|
+
{{/if}}
|
|
42
|
+
{{#if (includes microservices "mqtt")}}
|
|
43
|
+
url: env.MQTT_URL,
|
|
44
|
+
{{/if}}
|
|
25
45
|
};
|
|
26
46
|
|
|
27
47
|
let app: INestApplication;
|
|
28
|
-
|
|
48
|
+
const client{{#if (includes microservices "grpc")}}: ClientGrpc = ClientProxyFactory.create({ options, transport } as MicroserviceOptions) as unknown as ClientGrpc;{{else if (includes microservices "kafka")}}: ClientKafka = ClientProxyFactory.create({ options, transport } as MicroserviceOptions) as ClientKafka;{{else}}: ClientProxy = ClientProxyFactory.create({ options, transport } as MicroserviceOptions);{{/if}}
|
|
29
49
|
|
|
30
50
|
it("sends ping through the selected message transport", async () => {
|
|
31
51
|
const module = await Test.createTestingModule({ imports: [AppModule] }).compile();
|
|
32
52
|
app = module.createNestApplication();
|
|
33
|
-
app.connectMicroservice<MicroserviceOptions>({
|
|
53
|
+
app.connectMicroservice<MicroserviceOptions>({ options, transport } as MicroserviceOptions);
|
|
54
|
+
app.setGlobalPrefix("api");
|
|
34
55
|
await app.startAllMicroservices();
|
|
35
56
|
await app.init();
|
|
36
57
|
{{#if (includes microservices "kafka")}}
|
|
@@ -42,7 +63,7 @@ it("sends ping through the selected message transport", async () => {
|
|
|
42
63
|
try {
|
|
43
64
|
await client.connect();
|
|
44
65
|
} catch {
|
|
45
|
-
await delay(
|
|
66
|
+
await delay(1000);
|
|
46
67
|
await client.connect();
|
|
47
68
|
}
|
|
48
69
|
{{else}}
|
|
@@ -55,12 +76,23 @@ it("sends ping through the selected message transport", async () => {
|
|
|
55
76
|
log: (request: { id: string; source: string; payload: string }) => Observable<{ id: string; source: string; payload: string }>;
|
|
56
77
|
}>("AppService");
|
|
57
78
|
await expect(firstValueFrom(service.ping({}))).resolves.toEqual({ message: "pong" });
|
|
58
|
-
const event = { id: "event-1",
|
|
79
|
+
const event = { id: "event-1", payload: "healthy", source: "scenario" };
|
|
59
80
|
await expect(firstValueFrom(service.log(event))).resolves.toEqual(event);
|
|
60
81
|
{{else}}
|
|
61
82
|
await expect(firstValueFrom(client.send<string, Record<string, never>>("ping", {}))).resolves.toBe("pong");
|
|
62
|
-
const event = { id: "event-1",
|
|
83
|
+
const event = { id: "event-1", payload: { healthy: true }, source: "scenario" };
|
|
63
84
|
await expect(firstValueFrom(client.send("log", event))).resolves.toEqual({ received: event });
|
|
85
|
+
const auditEvent = {
|
|
86
|
+
id: "audit-1",
|
|
87
|
+
payload: { healthy: true },
|
|
88
|
+
source: "scenario",
|
|
89
|
+
};
|
|
90
|
+
await firstValueFrom(client.emit("audit", auditEvent));
|
|
91
|
+
await delay(250);
|
|
92
|
+
const auditResponse = await request(app.getHttpServer())
|
|
93
|
+
.get(`/api/events/${auditEvent.id}`)
|
|
94
|
+
.expect(200);
|
|
95
|
+
expect(auditResponse.body).toEqual(auditEvent);
|
|
64
96
|
{{/if}}
|
|
65
97
|
}, 60_000);
|
|
66
98
|
|
|
@@ -26,16 +26,14 @@ export const env = createEnv({
|
|
|
26
26
|
|
|
27
27
|
server: {
|
|
28
28
|
CORS_ORIGIN: z.string().default("*"),
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
{{#if (includes microservices "redis")}}
|
|
38
|
-
REDIS_URL: z.url().default("redis://127.0.0.1:6379"),
|
|
29
|
+
{{#if (includes microservices "grpc")}}
|
|
30
|
+
GRPC_URL: z.string().default("0.0.0.0:5000"),
|
|
31
|
+
{{/if}}
|
|
32
|
+
{{#if (includes microservices "kafka")}}
|
|
33
|
+
KAFKA_BROKER: z.string().default("127.0.0.1:9092"),
|
|
34
|
+
{{/if}}
|
|
35
|
+
{{#if (or (includes microservices "redis") (includes microservices "mqtt") (includes microservices "nats") (includes microservices "rabbitmq") (includes microservices "kafka") (includes microservices "grpc"))}}
|
|
36
|
+
MICROSERVICE_PORT: z.string().transform(Number).default(3001),
|
|
39
37
|
{{/if}}
|
|
40
38
|
{{#if (includes microservices "mqtt")}}
|
|
41
39
|
MQTT_URL: z.url().default("mqtt://127.0.0.1:1883"),
|
|
@@ -43,16 +41,20 @@ export const env = createEnv({
|
|
|
43
41
|
{{#if (includes microservices "nats")}}
|
|
44
42
|
NATS_URL: z.url().default("nats://127.0.0.1:4222"),
|
|
45
43
|
{{/if}}
|
|
44
|
+
NODE_ENV: z
|
|
45
|
+
.enum(["development", "production", "test"])
|
|
46
|
+
.default("development"),
|
|
47
|
+
PORT: z
|
|
48
|
+
.string()
|
|
49
|
+
.transform(Number)
|
|
50
|
+
.default(3000),
|
|
46
51
|
{{#if (includes microservices "rabbitmq")}}
|
|
47
52
|
RABBITMQ_URL: z.url().default("amqp://127.0.0.1:5672"),
|
|
48
53
|
{{/if}}
|
|
49
|
-
{{#if (includes microservices "
|
|
50
|
-
|
|
51
|
-
{{/if}}
|
|
52
|
-
{{#if (includes microservices "grpc")}}
|
|
53
|
-
GRPC_URL: z.string().default("0.0.0.0:5000"),
|
|
54
|
+
{{#if (includes microservices "redis")}}
|
|
55
|
+
REDIS_URL: z.url().default("redis://127.0.0.1:6379"),
|
|
54
56
|
{{/if}}
|
|
55
|
-
|
|
57
|
+
TRUSTED_PROXY_IPS: z.string().default("{{#each trustedProxyIps}}{{#unless @first}},{{/unless}}{{this}}{{/each}}"),
|
|
56
58
|
{{#if hasPostgres}}
|
|
57
59
|
POSTGRES_URL: z.url(),
|
|
58
60
|
{{/if}}
|
|
@@ -62,6 +64,15 @@ export const env = createEnv({
|
|
|
62
64
|
{{#if hasSqlite}}
|
|
63
65
|
SQLITE_PATH: z.string().default("sqlite.db"),
|
|
64
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}}
|
|
65
76
|
{{#if hasMongodb}}
|
|
66
77
|
MONGODB_URL: z.url(),
|
|
67
78
|
{{/if}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nest-arch/tui",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.6",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Interactive terminal UI for generating NestJS projects",
|
|
6
6
|
"keywords": [
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"pkgroll": "^2.5.2",
|
|
52
52
|
"tsx": "^4.19.2",
|
|
53
53
|
"vitest": "^4.1.7",
|
|
54
|
-
"@nest-arch/core": "0.4.3",
|
|
55
54
|
"@nest-arch/env": "0.0.0",
|
|
55
|
+
"@nest-arch/core": "0.4.3",
|
|
56
56
|
"@nest-arch/shared": "0.0.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|