@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.
Files changed (35) hide show
  1. package/dist/cli.js +1 -1
  2. package/dist/{constants-7dJLZpB2.js → constants-DVhgS48N.js} +1 -1
  3. package/dist/index.js +148 -133
  4. package/dist/templates/addons/husky/noop-hook.hbs +2 -0
  5. package/dist/templates/base/.env.example.hbs +9 -0
  6. package/dist/templates/base/.env.hbs +9 -0
  7. package/dist/templates/base/README.md.hbs +12 -0
  8. package/dist/templates/base/prisma.config.ts.hbs +1 -0
  9. package/dist/templates/base/src/app.module.ts.hbs +1 -0
  10. package/dist/templates/base/src/database/adapters/interfaces/db-adapter.interface.ts.hbs +4 -4
  11. package/dist/templates/base/src/database/adapters/mongo/prisma-mongo.adapter.ts.hbs +4 -4
  12. package/dist/templates/base/src/database/db.module.ts.hbs +15 -2
  13. package/dist/templates/base/src/database/db.service.ts.hbs +5 -5
  14. package/dist/templates/base/src/database/index.ts.hbs +12 -3
  15. package/dist/templates/base/src/main.ts.hbs +5 -4
  16. package/dist/templates/base/test/app.e2e-spec.ts.hbs +50 -13
  17. package/dist/templates/base/test/bootstrap.e2e-spec.ts.hbs +2 -2
  18. package/dist/templates/base/tsconfig.build.json.hbs +1 -0
  19. package/dist/templates/base/vitest.config.e2e.ts.hbs +1 -1
  20. package/dist/templates/base/vitest.config.ts.hbs +1 -1
  21. package/dist/templates/extras/docker/Dockerfile.hbs +1 -1
  22. package/dist/templates/extras/health/src/health/health.controller.ts.hbs +7 -3
  23. package/dist/templates/feature/rest/todo-example/src/api/todo/todo.controller.ts.hbs +4 -6
  24. package/dist/templates/feature/rest/todo-example/src/api/todo/todo.router.ts.hbs +38 -37
  25. package/dist/templates/monorepo/apps/api-gateway/src/main.ts.hbs +8 -7
  26. package/dist/templates/monorepo/apps/api-gateway/test/app.e2e-spec.ts.hbs +4 -1
  27. package/dist/templates/single-project/architecture/nest-api/.env.hbs +9 -0
  28. package/dist/templates/single-project/architecture/nest-api/src/main.ts.hbs +8 -7
  29. package/dist/templates/single-project/architecture/nest-gateway/src/main.ts.hbs +8 -7
  30. package/dist/templates/single-project/architecture/nest-microservice/src/app.controller.ts.hbs +52 -1
  31. package/dist/templates/single-project/architecture/nest-microservice/src/app.service.ts.hbs +21 -0
  32. package/dist/templates/single-project/architecture/nest-microservice/src/main.ts.hbs +35 -16
  33. package/dist/templates/single-project/architecture/nest-microservice/test/microservice.e2e-spec.ts.hbs +51 -19
  34. package/dist/templates/single-project/shared/config/env.ts.hbs +27 -16
  35. 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
- pageTitle: "{{projectNamePascalCase}} API Docs",
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, expect, it } from "vitest";
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
- pageTitle: "{{projectNamePascalCase}} API Docs",
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
- pageTitle: "{{projectNamePascalCase}} API Docs",
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}}
@@ -1,10 +1,43 @@
1
+ {{#if (includes microservices "grpc")}}
1
2
  import { Controller, Get } from "@nestjs/common";
2
- import { {{#if (includes microservices "grpc")}}GrpcMethod{{else}}MessagePattern{{/if}} } from "@nestjs/microservices";
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 { Transport, type MicroserviceOptions } from "@nestjs/microservices";
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 "redis")}}host: new URL(env.REDIS_URL).hostname, port: Number(new URL(env.REDIS_URL).port || 6379),{{/if}}
33
- {{#if (includes microservices "mqtt")}}url: env.MQTT_URL ?? "mqtt://127.0.0.1:1883",{{/if}}
34
- {{#if (includes microservices "nats")}}servers: [env.NATS_URL ?? "nats://127.0.0.1:4222"],{{/if}}
35
- {{#if (includes microservices "rabbitmq")}}urls: [env.RABBITMQ_URL ?? "amqp://127.0.0.1:5672"], queue: "ping", queueOptions: { durable: false },{{/if}}
36
- {{#if (includes microservices "kafka")}}client: { brokers: [env.KAFKA_BROKER ?? "127.0.0.1:9092"] },{{/if}}
37
- {{#if (includes microservices "grpc")}}url: env.GRPC_URL ?? "0.0.0.0:5000", package: "app", protoPath: "proto/app.proto",{{/if}}
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
- pageTitle: "{{projectNamePascalCase}} API Docs",
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 { type INestApplication } from "@nestjs/common";
2
- import {
3
- ClientProxyFactory,
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 { firstValueFrom, type Observable } from "rxjs";
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 "redis")}}host: new URL(env.REDIS_URL).hostname, port: Number(new URL(env.REDIS_URL).port || 6379),{{/if}}
20
- {{#if (includes microservices "mqtt")}}url: env.MQTT_URL,{{/if}}
21
- {{#if (includes microservices "nats")}}servers: [env.NATS_URL],{{/if}}
22
- {{#if (includes microservices "rabbitmq")}}urls: [env.RABBITMQ_URL], queue: "ping", queueOptions: { durable: false },{{/if}}
23
- {{#if (includes microservices "kafka")}}client: { brokers: [env.KAFKA_BROKER] }, consumer: { groupId: "ping-consumer" },{{/if}}
24
- {{#if (includes microservices "grpc")}}url: env.GRPC_URL, package: "app", protoPath: "proto/app.proto",{{/if}}
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
- let client{{#if (includes microservices "grpc")}}: ClientGrpc = ClientProxyFactory.create({ transport, options } as MicroserviceOptions) as unknown as ClientGrpc;{{else if (includes microservices "kafka")}}: ClientKafka = ClientProxyFactory.create({ transport, options } as MicroserviceOptions) as ClientKafka;{{else}}: ClientProxy = ClientProxyFactory.create({ transport, options } as MicroserviceOptions);{{/if}}
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>({ transport, options } as 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(1_000);
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", source: "scenario", payload: "healthy" };
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", source: "scenario", payload: { healthy: true } };
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
- NODE_ENV: z
30
- .enum(["development", "production", "test"])
31
- .default("development"),
32
- PORT: z
33
- .string()
34
- .transform(Number)
35
- .default(3000),
36
- TRUSTED_PROXY_IPS: z.string().default("{{#each trustedProxyIps}}{{#unless @first}},{{/unless}}{{this}}{{/each}}"),
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 "kafka")}}
50
- KAFKA_BROKER: z.string().default("127.0.0.1:9092"),
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
- MICROSERVICE_PORT: z.string().transform(Number).default(3001),
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.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": {