@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.
Files changed (64) hide show
  1. package/dist/cli.js +1 -1
  2. package/dist/{constants-C3xmDWeK.js → constants-7dJLZpB2.js} +1 -1
  3. package/dist/index.js +188 -134
  4. package/dist/templates/addons/husky/pre-commit.hbs +11 -26
  5. package/dist/templates/base/.env.example.hbs +9 -0
  6. package/dist/templates/base/.env.hbs +7 -0
  7. package/dist/templates/base/README.md.hbs +16 -0
  8. package/dist/templates/base/pnpm-workspace.yaml.hbs +6 -0
  9. package/dist/templates/base/src/app.module.ts.hbs +68 -1
  10. package/dist/templates/base/src/app.router.ts.hbs +1 -2
  11. package/dist/templates/base/src/database/adapters/mongo/prisma-mongo.adapter.ts.hbs +11 -3
  12. package/dist/templates/base/src/database/adapters/sql/prisma-sql.adapter.ts.hbs +1 -1
  13. package/dist/templates/base/src/database/db.module.ts.hbs +24 -8
  14. package/dist/templates/base/src/database/db.service.ts.hbs +20 -0
  15. package/dist/templates/base/src/database/entities/app.entity.ts.hbs +25 -0
  16. package/dist/templates/base/src/database/index.ts.hbs +19 -0
  17. package/dist/templates/base/src/database/orm/drizzle/schema.ts.hbs +42 -11
  18. package/dist/templates/base/src/database/orm/typeorm/data-source.ts.hbs +12 -1
  19. package/dist/templates/base/src/libs/middlewares/auth.trpc.middleware.ts.hbs +47 -0
  20. package/dist/templates/base/src/libs/middlewares/rate-limit.trpc.middleware.ts.hbs +43 -0
  21. package/dist/templates/base/src/libs/trpc/inner.context.ts.hbs +6 -3
  22. package/dist/templates/base/src/main.ts.hbs +13 -4
  23. package/dist/templates/base/src/modules/users/entities/user.entity.ts.hbs +22 -0
  24. package/dist/templates/base/test/app.e2e-spec.ts.hbs +670 -37
  25. package/dist/templates/base/test/bootstrap.e2e-spec.ts.hbs +11 -1
  26. package/dist/templates/extras/docker/.dockerignore.hbs +8 -1
  27. package/dist/templates/extras/docker/Dockerfile.hbs +8 -10
  28. package/dist/templates/extras/health/src/health/health.controller.ts.hbs +54 -0
  29. package/dist/templates/extras/health/src/health/health.module.ts.hbs +9 -0
  30. package/dist/templates/extras/swagger/create-docs.ts.hbs +9 -3
  31. package/dist/templates/feature/graphql/src/graphql/graphql.module.ts.hbs +6 -17
  32. package/dist/templates/feature/graphql/src/graphql/orm/drizzle/drizzle-graphql.module.ts.hbs +3 -2
  33. package/dist/templates/feature/graphql/src/graphql/resolvers/health.resolver.ts.hbs +14 -0
  34. package/dist/templates/feature/graphql/src/graphql/resolvers/todo.resolver.ts.hbs +165 -53
  35. package/dist/templates/feature/rest/todo-example/src/api/todo/dto/create-todo.dto.ts.hbs +12 -0
  36. package/dist/templates/feature/rest/todo-example/src/api/todo/dto/update-todo.dto.ts.hbs +12 -0
  37. package/dist/templates/feature/rest/todo-example/src/api/todo/todo.controller.ts.hbs +18 -8
  38. package/dist/templates/feature/rest/todo-example/src/api/todo/todo.router.ts.hbs +41 -13
  39. package/dist/templates/feature/rest/todo-example/src/api/todo/todo.service.ts.hbs +68 -10
  40. package/dist/templates/monorepo/apps/api-gateway/package.json.hbs +2 -2
  41. package/dist/templates/monorepo/apps/api-gateway/src/app.controller.spec.ts.hbs +5 -0
  42. package/dist/templates/monorepo/apps/api-gateway/src/app.controller.ts.hbs +6 -0
  43. package/dist/templates/monorepo/apps/api-gateway/src/app.module.ts.hbs +32 -1
  44. package/dist/templates/monorepo/apps/api-gateway/src/app.service.ts.hbs +1 -1
  45. package/dist/templates/monorepo/apps/api-gateway/src/main.ts.hbs +13 -4
  46. package/dist/templates/monorepo/apps/api-gateway/test/app.e2e-spec.ts.hbs +26 -1
  47. package/dist/templates/monorepo/feature/graphql/src/graphql/graphql.module.ts.hbs +6 -10
  48. package/dist/templates/monorepo/feature/graphql/src/graphql/resolvers/health.resolver.ts.hbs +14 -0
  49. package/dist/templates/monorepo/feature/graphql/src/graphql/resolvers/todo.resolver.ts.hbs +147 -47
  50. package/dist/templates/monorepo/packages/env/src/api-gateway.ts.hbs +7 -0
  51. package/dist/templates/monorepo/packages/shared/package.json.hbs +1 -0
  52. package/dist/templates/monorepo/packages/shared/src/auth.ts.hbs +6 -0
  53. package/dist/templates/monorepo/root/pnpm-workspace.yaml.hbs +10 -2
  54. package/dist/templates/single-project/architecture/nest-api/.env.hbs +6 -0
  55. package/dist/templates/single-project/architecture/nest-api/package.json.hbs +1 -1
  56. package/dist/templates/single-project/architecture/nest-api/src/main.ts.hbs +13 -4
  57. package/dist/templates/single-project/architecture/nest-gateway/src/main.ts.hbs +3 -3
  58. package/dist/templates/single-project/architecture/nest-microservice/proto/app.proto.hbs +13 -0
  59. package/dist/templates/single-project/architecture/nest-microservice/src/app.controller.ts.hbs +10 -4
  60. package/dist/templates/single-project/architecture/nest-microservice/src/app.service.ts.hbs +2 -2
  61. package/dist/templates/single-project/architecture/nest-microservice/src/main.ts.hbs +3 -3
  62. package/dist/templates/single-project/architecture/nest-microservice/test/microservice.e2e-spec.ts.hbs +7 -1
  63. package/dist/templates/single-project/shared/config/env.ts.hbs +12 -1
  64. package/package.json +2 -2
@@ -1,31 +1,16 @@
1
- {{#if isPnpm}}pnpm test{{else if isYarn}}yarn test{{else if isBun}}bun run test{{else}}npm test{{/if}}
2
-
3
- # ultracite
4
1
  #!/bin/sh
5
- # Exit on any error
6
2
  set -e
7
3
 
8
- # Check if there are any staged files
9
- STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACMR)
10
- if [ -z "$STAGED_FILES" ]; then
11
- echo "No staged files to format"
12
- exit 0
13
- fi
14
-
15
- # Run formatter
16
- {{#if isPnpm}}pnpm dlx ultracite fix{{else if isYarn}}yarn dlx ultracite fix{{else if isBun}}bunx ultracite fix{{else}}npx --yes ultracite fix{{/if}}
17
- FORMAT_EXIT_CODE=$?
18
-
19
- # Re-stage files that were already staged
20
- echo "$STAGED_FILES" | while IFS= read -r file; do
21
- if [ -f "$file" ]; then
22
- git add -- "$file"
23
- fi
24
- done
4
+ {{#if isPnpm}}pnpm test{{else if isYarn}}yarn test{{else if isBun}}bun run test{{else}}npm test{{/if}}
25
5
 
26
- if [ $FORMAT_EXIT_CODE -ne 0 ]; then
27
- echo "Ultracite found issues that could not be auto-fixed."
28
- exit $FORMAT_EXIT_CODE
6
+ {{#if hasFormatter}}
7
+ STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACMR)
8
+ if [ -n "$STAGED_FILES" ]; then
9
+ {{#if isPnpm}}pnpm run fix{{else if isYarn}}yarn run fix{{else if isBun}}bun run fix{{else}}npm run fix{{/if}}
10
+ echo "$STAGED_FILES" | while IFS= read -r file; do
11
+ if [ -f "$file" ]; then
12
+ git add -- "$file"
13
+ fi
14
+ done
29
15
  fi
30
-
31
- echo "✨ Files formatted by Ultracite"
16
+ {{/if}}
@@ -2,6 +2,8 @@
2
2
  PORT=3000
3
3
  NODE_ENV=development
4
4
  CORS_ORIGIN=http://localhost:3001
5
+ # Comma-separated trusted reverse proxy IP addresses or CIDRs
6
+ TRUSTED_PROXY_IPS={{#each trustedProxyIps}}{{#unless @first}},{{/unless}}{{this}}{{/each}}
5
7
 
6
8
  {{#if hasDatabase}}
7
9
  # Database
@@ -35,4 +37,11 @@ JWT_REFRESH_SECRET=change-me-to-a-different-random-secret-at-least-32-characters
35
37
  # Better Auth
36
38
  BETTER_AUTH_SECRET=change-me-to-a-random-secret-at-least-32-characters-long
37
39
  BETTER_AUTH_URL=http://localhost:3000
40
+ {{#if (eq auth "better-auth:stateless")}}
41
+ # OIDC provider; register http://localhost:3000/api/auth/callback/$OIDC_PROVIDER_ID as its callback URL
42
+ OIDC_PROVIDER_ID=company-oidc
43
+ OIDC_CLIENT_ID=replace-with-provider-client-id
44
+ OIDC_CLIENT_SECRET=replace-with-provider-client-secret
45
+ OIDC_DISCOVERY_URL=https://identity.example.com/.well-known/openid-configuration
46
+ {{/if}}
38
47
  {{/if}}
@@ -1,5 +1,6 @@
1
1
  CORS_ORIGIN=http://localhost:3001
2
2
  PORT=3000
3
+ TRUSTED_PROXY_IPS={{#each trustedProxyIps}}{{#unless @first}},{{/unless}}{{this}}{{/each}}
3
4
  {{#if hasGraphql}}
4
5
  GRAPHQL_PLAYGROUND=true
5
6
  {{/if}}
@@ -25,4 +26,10 @@ JWT_REFRESH_SECRET=change-me-to-a-different-random-secret-at-least-32-characters
25
26
  {{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
26
27
  BETTER_AUTH_SECRET=change-me-to-a-random-secret-at-least-32-characters-long
27
28
  BETTER_AUTH_URL=http://localhost:3000
29
+ {{#if (eq auth "better-auth:stateless")}}
30
+ OIDC_PROVIDER_ID=company-oidc
31
+ OIDC_CLIENT_ID=replace-with-provider-client-id
32
+ OIDC_CLIENT_SECRET=replace-with-provider-client-secret
33
+ OIDC_DISCOVERY_URL=https://identity.example.com/.well-known/openid-configuration
34
+ {{/if}}
28
35
  {{/if}}
@@ -36,6 +36,12 @@ npm run start{{/if}}
36
36
  {{#if isPnpm}}pnpm test:cov{{else if isYarn}}yarn test:cov{{else if isBun}}bun run test:cov{{else}}npm run test:cov{{/if}}
37
37
  ```
38
38
 
39
+ {{#if hasRateLimiting}}
40
+ ## Reverse Proxy
41
+
42
+ Set `TRUSTED_PROXY_IPS` to the IP addresses or CIDRs of your trusted reverse proxies. Leave it empty when clients connect directly. The application uses this allowlist when reading forwarded client IP headers for rate limiting.
43
+ {{/if}}
44
+
39
45
  {{#if usePrisma}}
40
46
  ## Database Setup
41
47
 
@@ -79,6 +85,11 @@ This project uses **TypeORM** as the ORM. Available commands:
79
85
  {{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
80
86
  ## Auth Setup
81
87
 
88
+ {{#if (eq auth "better-auth:stateless")}}
89
+ This project uses **Better Auth** with encrypted stateless cookie sessions and an external OpenID Connect provider. Set `BETTER_AUTH_SECRET`, `BETTER_AUTH_URL`, `OIDC_PROVIDER_ID`, `OIDC_CLIENT_ID`, `OIDC_CLIENT_SECRET`, and `OIDC_DISCOVERY_URL` in `.env`. Register `${BETTER_AUTH_URL}/api/auth/callback/${OIDC_PROVIDER_ID}` with the provider, then begin the authorization-code flow through Better Auth's social sign-in endpoint. The generated configuration uses discovery, PKCE, and issuer validation.
90
+
91
+ No local registration, password login, database migration, or immediate server-side revocation is included in this profile.
92
+ {{else}}
82
93
  This project uses **Better Auth** with database-backed sessions. Set `BETTER_AUTH_SECRET` and `BETTER_AUTH_URL` in `.env` before running the generated scripts.
83
94
 
84
95
  Run `auth:generate` with your package manager. The script uses the installed CLI version.
@@ -91,6 +102,7 @@ Then run `auth:migrate` and `build`.
91
102
  {{/if}}
92
103
 
93
104
  The runtime auth module receives the database client owned by Nest. CLI schema discovery uses separate configuration. `GET /api/auth-profile` is a protected example for the Prisma and Drizzle profiles.
105
+ {{/if}}
94
106
 
95
107
  ### Usage
96
108
 
@@ -195,6 +207,7 @@ export class AppModule {}
195
207
  {{#if isPassportAuth}}
196
208
  ## Passport authentication
197
209
 
210
+ {{#if hasDatabase}}
198
211
  Set a random `JWT_ACCESS_SECRET` of at least 32 characters. Configure `JWT_ISSUER`, `JWT_AUDIENCE`, and `JWT_KEY_ID` consistently across instances. Apply Prisma migrations before starting.
199
212
 
200
213
  Register with `POST /api/auth/register` and sign in with `POST /api/auth/login`, using `{ "email": "user@example.com", "password": "a-long-unique-password" }`. Send the returned access token in `Authorization: Bearer <token>` to `GET /api/auth/profile`. Access tokens expire after 15 minutes. Passwords are hashed with bcrypt; token payloads contain no password or role supplied by the client.
@@ -202,6 +215,9 @@ Register with `POST /api/auth/register` and sign in with `POST /api/auth/login`,
202
215
  Refresh with `POST /api/auth/refresh` and `{ "refreshToken": "..." }`. Refresh tokens rotate on every use and expire seven days after login. Reusing a consumed token revokes the entire login session, including access tokens. Concurrent refresh requests therefore require client-side serialization. `POST /api/auth/logout` takes the same body and revokes that login session. Tokens are returned in JSON; no cookie transport is generated.
203
216
 
204
217
  Only hashes of refresh tokens are stored. Schedule deletion of expired refresh-token families according to your retention policy. Secret replacement invalidates existing access tokens; overlapping signing keys are not implemented in this baseline.
218
+ {{else}}
219
+ Configure `OIDC_JWKS_URI`, `OIDC_ISSUER`, and `OIDC_AUDIENCE` for your trusted identity provider. Send its RS256 access token in `Authorization: Bearer <token>` to `GET /api/auth/profile`. The API verifies the signature using the provider's cached, rate-limited JWKS keys and checks the issuer, audience, and expiration. This API does not accept passwords or issue local tokens.
220
+ {{/if}}
205
221
  {{/if}}
206
222
  {{#if hasGraphql}}
207
223
  ## GraphQL
@@ -4,6 +4,9 @@ allowBuilds:
4
4
  {{/if}}
5
5
  protobufjs: true
6
6
  "@nestjs/core": true
7
+ {{#if useTypescript7}}
8
+ esbuild: true
9
+ {{/if}}
7
10
  {{#if swagger}}
8
11
  "@scarf/scarf": true
9
12
  {{/if}}
@@ -13,6 +16,9 @@ allowBuilds:
13
16
  {{#if usePrisma}}
14
17
  prisma: true
15
18
  "@prisma/engines": true
19
+ {{#if isPrisma6}}
20
+ "@prisma/client": true
21
+ {{/if}}
16
22
  {{#if isPrisma8}}
17
23
  esbuild: true
18
24
  msgpackr-extract: true
@@ -1,4 +1,7 @@
1
- import { Module } from "@nestjs/common";
1
+ import { Module{{#if (and hasGraphql hasRateLimiting)}}, Injectable, type ExecutionContext{{/if}} } from "@nestjs/common";
2
+ {{#if (and hasGraphql hasRateLimiting)}}
3
+ import { GqlExecutionContext } from "@nestjs/graphql";
4
+ {{/if}}
2
5
  {{#if (and isPassportAuth hasDatabase)}}
3
6
  import { PassportModule } from "@nestjs/passport";
4
7
  {{/if}}
@@ -13,8 +16,10 @@ import { AuthModule } from "./auth/auth.module.js";
13
16
  {{#if hasGraphql}}
14
17
  import { GqlAuthGuard } from "./auth/guards/gql-auth.guard.js";
15
18
  {{/if}}
19
+ {{#if hasRest}}
16
20
  import { RestAuthGuard } from "./auth/guards/rest-auth.guard.js";
17
21
  {{/if}}
22
+ {{/if}}
18
23
  {{#if hasGraphql}}
19
24
  import { GraphqlAppModule } from "./graphql/graphql.module.js";
20
25
  {{/if}}
@@ -26,6 +31,9 @@ import { AppErrorHandler } from "./libs/trpc/error.handler.js";
26
31
  {{#if hasTrpcAndAuth}}
27
32
  import { AuthTRPCMiddleware } from "./libs/middlewares/auth.trpc.middleware.js";
28
33
  {{/if}}
34
+ {{#if (and hasTrpc hasRateLimiting)}}
35
+ import { RateLimitTRPCMiddleware } from "./libs/middlewares/rate-limit.trpc.middleware.js";
36
+ {{/if}}
29
37
  {{/if}}
30
38
 
31
39
  {{#if hasRest}}
@@ -37,8 +45,35 @@ import { TodoModule } from "./api/todo/todo.module.js";
37
45
  {{#if (and hasTrpc hasTodoExample hasRest)}}
38
46
  import { TodoRouter } from "./api/todo/todo.router.js";
39
47
  {{/if}}
48
+ {{#if hasHealthCheck}}
49
+ import { HealthModule } from "./health/health.module.js";
50
+ {{/if}}
51
+ {{#if hasRateLimiting}}
52
+ import { APP_GUARD } from "@nestjs/core";
53
+ import { ThrottlerGuard, ThrottlerModule } from "@nestjs/throttler";
54
+ {{/if}}
55
+ {{#if (and isPassportAuth hasDatabase hasGraphql (not hasRateLimiting))}}
56
+ import { APP_GUARD } from "@nestjs/core";
57
+ {{/if}}
40
58
  import { AppService } from "./app.service.js";
41
59
 
60
+ {{#if (and hasGraphql hasRateLimiting)}}
61
+ @Injectable()
62
+ class GraphqlThrottlerGuard extends ThrottlerGuard {
63
+ protected getRequestResponse(context: ExecutionContext) {
64
+ if (context.getType<string>() !== "graphql") return super.getRequestResponse(context);
65
+ const gqlContext = GqlExecutionContext.create(context).getContext();
66
+ return { req: gqlContext.req, res: { header: () => undefined } };
67
+ }
68
+
69
+ protected getTracker(request: Record<string, unknown>): Promise<string> {
70
+ const socket = request.socket as { remoteAddress?: string } | undefined;
71
+ const ip = request.ip;
72
+ return Promise.resolve(typeof ip === "string" ? ip : socket?.remoteAddress ?? "unknown");
73
+ }
74
+ }
75
+ {{/if}}
76
+
42
77
  @Module({
43
78
  {{#if hasRest}}
44
79
  controllers: [
@@ -67,11 +102,28 @@ import { AppService } from "./app.service.js";
67
102
  TRPCModule.forRoot({
68
103
  context: AppContext,
69
104
  onError: AppErrorHandler,
105
+ {{#if hasRateLimiting}}
106
+ globalMiddlewares: [RateLimitTRPCMiddleware],
107
+ {{/if}}
70
108
  }),
71
109
  {{/if}}
72
110
  {{#if (and hasTodoExample (or hasRest hasTrpc))}}
73
111
  TodoModule,
74
112
  {{/if}}
113
+ {{#if hasHealthCheck}}
114
+ HealthModule,
115
+ {{/if}}
116
+ {{#if hasRateLimiting}}
117
+ ThrottlerModule.forRoot([
118
+ {
119
+ ttl: 60_000,
120
+ limit: 60,
121
+ {{#if hasGraphql}}
122
+ setHeaders: false,
123
+ {{/if}}
124
+ },
125
+ ]),
126
+ {{/if}}
75
127
  ],
76
128
  providers: [
77
129
  AppService,
@@ -79,12 +131,17 @@ import { AppService } from "./app.service.js";
79
131
  {{#if hasGraphql}}
80
132
  GqlAuthGuard,
81
133
  {{/if}}
134
+ {{#if hasRest}}
82
135
  RestAuthGuard,
83
136
  {{/if}}
137
+ {{/if}}
84
138
  {{#if hasTrpc}}
85
139
  {{#if hasTrpcAndAuth}}
86
140
  AuthTRPCMiddleware,
87
141
  {{/if}}
142
+ {{#if hasRateLimiting}}
143
+ RateLimitTRPCMiddleware,
144
+ {{/if}}
88
145
  AppContext,
89
146
  AppErrorHandler,
90
147
  AppRouter,
@@ -92,6 +149,16 @@ import { AppService } from "./app.service.js";
92
149
  TodoRouter,
93
150
  {{/if}}
94
151
  {{/if}}
152
+ {{#if hasRateLimiting}}
153
+ {
154
+ provide: APP_GUARD,
155
+ {{#if hasGraphql}}
156
+ useClass: GraphqlThrottlerGuard,
157
+ {{else}}
158
+ useClass: ThrottlerGuard,
159
+ {{/if}}
160
+ },
161
+ {{/if}}
95
162
  ],
96
163
  })
97
164
  export class AppModule {}
@@ -1,7 +1,6 @@
1
1
  import { Router, Query{{#if hasTrpcAndAuth}}, UseMiddlewares, Ctx{{/if}} } from "nestjs-trpc";
2
2
  import { z } from "zod";
3
3
  {{#if hasTrpcAndAuth}}
4
- import type { UserSession } from "./auth/auth.js";
5
4
  import { AuthTRPCMiddleware } from "./libs/middlewares/auth.trpc.middleware.js";
6
5
  import type { InnerContext } from "./libs/trpc/inner.context.js";
7
6
  {{/if}}
@@ -14,7 +13,7 @@ export class AppRouterClass {
14
13
  {{#if hasTrpcAndAuth}}
15
14
  @Query()
16
15
  @UseMiddlewares(AuthTRPCMiddleware)
17
- testAuth(@Ctx() ctx: InnerContext): UserSession {
16
+ testAuth(@Ctx() ctx: InnerContext): NonNullable<InnerContext["session"]> {
18
17
  return ctx.session!;
19
18
  }
20
19
 
@@ -8,9 +8,17 @@ import { db } from '../../prisma/db.js';
8
8
  {{/if}}
9
9
  {{else}}
10
10
  {{#if isMonorepo}}
11
- import type { PrismaClient } from '../../../database/orm/prisma/generated/client.js';
11
+ {{#if isPrisma6}}
12
+ import type { Prisma, PrismaClient } from '@prisma/client';
12
13
  {{else}}
13
- import type { PrismaClient } from '../../orm/prisma/generated/client.js';
14
+ import type { Prisma, PrismaClient } from '../../database/orm/prisma/generated/client.js';
15
+ {{/if}}
16
+ {{else}}
17
+ {{#if isPrisma6}}
18
+ import type { Prisma, PrismaClient } from '@prisma/client';
19
+ {{else}}
20
+ import type { Prisma, PrismaClient } from '../../orm/prisma/generated/client.js';
21
+ {{/if}}
14
22
  {{/if}}
15
23
  {{/if}}
16
24
 
@@ -38,7 +46,7 @@ export class PrismaMongoAdapter implements IMongoAdapter<any> {
38
46
  return this.prisma[name as keyof PrismaClient] as T;
39
47
  }
40
48
 
41
- async runCommand(command: unknown): Promise<unknown> {
49
+ async runCommand(command: Prisma.InputJsonObject): Promise<unknown> {
42
50
  return this.prisma.$runCommandRaw(command);
43
51
  }
44
52
 
@@ -1,7 +1,7 @@
1
1
  import { Injectable, Inject } from '@nestjs/common';
2
2
  import { ISqlAdapter } from '../interfaces/db-adapter.interface.js';
3
3
  {{#if isMonorepo}}
4
- import type { PrismaClient } from '../../../database/orm/prisma/generated/client.js';
4
+ import type { PrismaClient } from '../../database/orm/prisma/generated/client.js';
5
5
  {{else}}
6
6
  import type { PrismaClient } from '../../orm/prisma/generated/client.js';
7
7
  {{/if}}
@@ -14,11 +14,19 @@ import { DynamicModule, Module, Global, Provider } from '@nestjs/common';
14
14
  import { DbService } from './db.service.js';
15
15
 
16
16
  {{#if usePrisma}}
17
- {{#if isMonorepo}}
18
- import { PrismaClient } from '../database/orm/prisma/generated/client.js';
19
- {{else}}
17
+ {{#if isMonorepo}}
18
+ {{#if isPrisma6}}
19
+ import { PrismaClient } from '@prisma/client';
20
+ {{else}}
21
+ import { PrismaClient } from './database/orm/prisma/generated/client.js';
22
+ {{/if}}
23
+ {{else}}
24
+ {{#if isPrisma6}}
25
+ import { PrismaClient } from '@prisma/client';
26
+ {{else}}
20
27
  import { PrismaClient } from '../database/orm/prisma/generated/client.js';
21
- {{/if}}
28
+ {{/if}}
29
+ {{/if}}
22
30
  {{#if (or hasPostgres hasMysql hasSqlite)}}
23
31
  import { PrismaSqlAdapter } from './adapters/sql/prisma-sql.adapter.js';
24
32
  {{/if}}
@@ -38,7 +46,11 @@ import { PrismaMongoAdapter } from './adapters/mongo/prisma-mongo.adapter.js';
38
46
 
39
47
  {{#if useDrizzle}}
40
48
  import { DrizzleSqlAdapter } from './adapters/sql/drizzle-sql.adapter.js';
49
+ {{#if isMonorepo}}
50
+ import * as schema from './database/orm/drizzle/schema.js';
51
+ {{else}}
41
52
  import * as schema from './orm/drizzle/schema.js';
53
+ {{/if}}
42
54
  {{#if hasPostgres}}
43
55
  import { drizzle } from 'drizzle-orm/node-postgres';
44
56
  import { Pool } from "pg"
@@ -98,7 +110,11 @@ export interface DbModuleOptions {
98
110
  @Global()
99
111
  @Module({})
100
112
  export class DbModule {
113
+ {{#if (or usePrisma useDrizzle useRawSql)}}
101
114
  static forRoot(options: DbModuleOptions): DynamicModule {
115
+ {{else}}
116
+ static forRoot(_options: DbModuleOptions): DynamicModule {
117
+ {{/if}}
102
118
  const initialProviders: Provider[] = [DbService];
103
119
  const providers = initialProviders;
104
120
 
@@ -158,12 +174,14 @@ export class DbModule {
158
174
  useFactory: () => {
159
175
  {{#if hasPostgres}}
160
176
  const client = new Pool({ connectionString: options.postgresUrl });
177
+ return drizzle({ client, schema });
161
178
  {{else if hasMysql}}
162
179
  const client = mysql.createPool({ uri: options.mysqlUrl });
180
+ return drizzle(client, { schema, mode: "default" });
163
181
  {{else}}
164
182
  const client = new Database(options.sqlitePath || ':memory:');
165
- {{/if}}
166
183
  return drizzle({ client, schema });
184
+ {{/if}}
167
185
  },
168
186
  });
169
187
  providers.push({ provide: 'SQL_ADAPTER', useClass: DrizzleSqlAdapter });
@@ -172,9 +190,7 @@ export class DbModule {
172
190
  {{#if useTypeorm}}
173
191
  providers.push({
174
192
  provide: 'TYPEORM_DATA_SOURCE',
175
- useFactory: async () => {
176
- return AppDataSource.initialize();
177
- },
193
+ useFactory: () => AppDataSource.initialize(),
178
194
  });
179
195
  providers.push({
180
196
  provide: 'SQL_ADAPTER',
@@ -25,8 +25,20 @@ import type { ISqlAdapter } from './adapters/interfaces/db-adapter.interface.js'
25
25
  import type { IMongoAdapter } from './adapters/interfaces/db-adapter.interface.js';
26
26
  {{/if}}
27
27
  {{#if usePrisma}}
28
+ {{#if isMonorepo}}
29
+ {{#if isPrisma6}}
30
+ import type { PrismaClient } from '@prisma/client';
31
+ {{else}}
32
+ import type { PrismaClient } from './database/orm/prisma/generated/client.js';
33
+ {{/if}}
34
+ {{else}}
35
+ {{#if isPrisma6}}
36
+ import type { PrismaClient } from '@prisma/client';
37
+ {{else}}
28
38
  import type { PrismaClient } from './orm/prisma/generated/client.js';
29
39
  {{/if}}
40
+ {{/if}}
41
+ {{/if}}
30
42
  {{#if useDrizzle}}
31
43
  {{#if hasPostgres}}
32
44
  import type { NodePgDatabase } from 'drizzle-orm/node-postgres';
@@ -37,8 +49,12 @@ import type { MySql2Database } from 'drizzle-orm/mysql2';
37
49
  {{#if hasSqlite}}
38
50
  import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';
39
51
  {{/if}}
52
+ {{#if isMonorepo}}
53
+ import type * as schema from './database/orm/drizzle/schema.js';
54
+ {{else}}
40
55
  import type * as schema from './orm/drizzle/schema.js';
41
56
  {{/if}}
57
+ {{/if}}
42
58
  {{#if useTypeorm}}
43
59
  import type { DataSource } from 'typeorm';
44
60
  {{/if}}
@@ -102,6 +118,10 @@ export class DbService {
102
118
  get prisma(): PrismaClient {
103
119
  return this.sql.getClient();
104
120
  }
121
+ {{else if hasMongodb}}
122
+ get prisma(): PrismaClient {
123
+ return this.mongo.getClient();
124
+ }
105
125
  {{/if}}
106
126
  {{/if}}
107
127
  {{#if useDrizzle}}
@@ -0,0 +1,25 @@
1
+ import {
2
+ Column,
3
+ CreateDateColumn,
4
+ Entity,
5
+ PrimaryGeneratedColumn,
6
+ UpdateDateColumn,
7
+ } from "typeorm";
8
+
9
+ @Entity("app_data")
10
+ export class AppEntity {
11
+ @PrimaryGeneratedColumn("uuid")
12
+ id: string;
13
+
14
+ @Column({ type: "varchar", length: 255, unique: true })
15
+ key: string;
16
+
17
+ @Column({ type: "text" })
18
+ value: string;
19
+
20
+ @CreateDateColumn({ name: "created_at" })
21
+ createdAt: Date;
22
+
23
+ @UpdateDateColumn({ name: "updated_at" })
24
+ updatedAt: Date;
25
+ }
@@ -2,10 +2,29 @@
2
2
  // biome-ignore-all lint/performance/noBarrelFile: Public entry point shared with the monorepo database package.
3
3
  export * from './db.module.js';
4
4
  export * from './db.service.js';
5
+ {{#if usePrisma}}
6
+ {{#if isPrisma6}}
7
+ export type { PrismaClient, Todo } from '@prisma/client';
8
+ {{else}}
9
+ {{#if isMonorepo}}
10
+ export type { PrismaClient, Todo } from './database/orm/prisma/generated/client.js';
11
+ {{else}}
12
+ export type { PrismaClient, Todo } from './orm/prisma/generated/client.js';
13
+ {{/if}}
14
+ {{/if}}
15
+ {{/if}}
5
16
  export * from './adapters/interfaces/db-adapter.interface.js';
6
17
  {{#if useDrizzle}}
18
+ {{#if isMonorepo}}
19
+ export * from './database/orm/drizzle/schema.js';
20
+ {{else}}
7
21
  export * from './orm/drizzle/schema.js';
8
22
  {{/if}}
23
+ {{/if}}
9
24
  {{#if useTypeorm}}
25
+ {{#if isMonorepo}}
26
+ export * from './database/orm/typeorm/data-source.js';
27
+ {{else}}
10
28
  export * from './orm/typeorm/data-source.js';
11
29
  {{/if}}
30
+ {{/if}}
@@ -1,16 +1,27 @@
1
- {{#if isBetterAuth}}
1
+ // oxlint-disable typescript/no-explicit-any
2
+ {{#if (eq auth "better-auth")}}
3
+ // oxlint-disable-next-line oxc/no-barrel-file
2
4
  export * from "./auth-schema.js";
3
5
  {{/if}}
4
- // oxlint-disable typescript/no-explicit-any
5
6
  {{#if hasPostgres}}
6
- import { boolean, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';
7
+ import { {{#if hasTodoExample}}boolean, {{/if}}pgTable{{#if (or (not isPassportAuth) hasTodoExample)}}, serial{{/if}}, text, timestamp } from 'drizzle-orm/pg-core';
7
8
 
8
- {{#unless isBetterAuth}}
9
+ {{#unless (eq auth "better-auth")}}
9
10
  export const users = pgTable('users', {
10
11
  email: text('email').unique(),
12
+ {{#if isPassportAuth}}
13
+ id: text('id').primaryKey(),
14
+ {{else}}
11
15
  id: serial('id').primaryKey(),
16
+ {{/if}}
12
17
  name: text('name'),
13
18
  createdAt: timestamp('created_at').defaultNow(),
19
+ {{#if isPassportAuth}}
20
+ password: text('password').notNull(),
21
+ firstname: text('firstname'),
22
+ lastname: text('lastname'),
23
+ role: text('role').default('USER'),
24
+ {{/if}}
14
25
  });
15
26
  {{/unless}}
16
27
  {{#if hasTodoExample}}
@@ -26,14 +37,24 @@ export const todos = pgTable('todos', {
26
37
  {{/if}}
27
38
  {{/if}}
28
39
  {{#if hasMysql}}
29
- import { boolean, mysqlTable, serial, text, timestamp } from 'drizzle-orm/mysql-core';
40
+ import { {{#if hasTodoExample}}boolean, {{/if}}mysqlTable{{#if (or (not isPassportAuth) hasTodoExample)}}, int{{/if}}, text, timestamp, varchar } from 'drizzle-orm/mysql-core';
30
41
 
31
- {{#unless isBetterAuth}}
42
+ {{#unless (eq auth "better-auth")}}
32
43
  export const users = mysqlTable('users', {
33
- email: text('email').unique(),
34
- id: serial('id').primaryKey(),
44
+ email: varchar('email', { length: 320 }).unique(),
45
+ {{#if isPassportAuth}}
46
+ id: varchar('id', { length: 255 }).primaryKey(),
47
+ {{else}}
48
+ id: int('id').autoincrement().primaryKey(),
49
+ {{/if}}
35
50
  name: text('name'),
36
51
  createdAt: timestamp('created_at').defaultNow(),
52
+ {{#if isPassportAuth}}
53
+ password: text('password').notNull(),
54
+ firstname: text('firstname'),
55
+ lastname: text('lastname'),
56
+ role: text('role').default('USER'),
57
+ {{/if}}
37
58
  });
38
59
  {{/unless}}
39
60
  {{#if hasTodoExample}}
@@ -43,19 +64,29 @@ export const todos = mysqlTable('todos', {
43
64
  {{/if}}
44
65
  completed: boolean('completed').notNull().default(false),
45
66
  description: text('description'),
46
- id: serial('id').primaryKey(),
67
+ id: int('id').autoincrement().primaryKey(),
47
68
  title: text('title').notNull(),
48
69
  });
49
70
  {{/if}}
50
71
  {{/if}}
51
72
  {{#if hasSqlite}}
52
- import { sqliteTable, integer, text } from 'drizzle-orm/sqlite-core';
73
+ import { sqliteTable{{#if (or (not isPassportAuth) hasTodoExample)}}, integer{{/if}}, text } from 'drizzle-orm/sqlite-core';
53
74
 
54
- {{#unless isBetterAuth}}
75
+ {{#unless (eq auth "better-auth")}}
55
76
  export const users = sqliteTable('users', {
56
77
  email: text('email').unique(),
78
+ {{#if isPassportAuth}}
79
+ id: text('id').primaryKey(),
80
+ {{else}}
57
81
  id: integer('id').primaryKey({ autoIncrement: true }),
82
+ {{/if}}
58
83
  name: text('name'),
84
+ {{#if isPassportAuth}}
85
+ password: text('password').notNull(),
86
+ firstname: text('firstname'),
87
+ lastname: text('lastname'),
88
+ role: text('role').default('USER'),
89
+ {{/if}}
59
90
  });
60
91
  {{/unless}}
61
92
  {{#if hasTodoExample}}
@@ -9,6 +9,12 @@ import { DataSource } from "typeorm";
9
9
  {{#if hasTodoExample}}
10
10
  import { Todo } from "../../entities/todo.entity.js";
11
11
  {{/if}}
12
+ {{#if (and useTypeorm isPassportAuth)}}
13
+ import { UserEntity } from "../../../modules/users/entities/user.entity.js";
14
+ {{/if}}
15
+ {{#if (eq auth "better-auth:stateless")}}
16
+ import { AppEntity } from "../../entities/app.entity.js";
17
+ {{/if}}
12
18
 
13
19
  const databaseUrl =
14
20
  env.{{#if hasPostgres}}POSTGRES_URL{{/if}}{{#if hasMysql}}MYSQL_URL{{/if}}{{#if hasSqlite}}SQLITE_PATH{{/if}};
@@ -19,12 +25,17 @@ const parsedUrl = new URL(databaseUrl);
19
25
 
20
26
 
21
27
  export const AppDataSource = new DataSource({
28
+ {{#if hasSqlite}}
29
+ database: databaseUrl,
30
+ {{/if}}
22
31
  // Register entities explicitly for consistent metadata in Node and test runners.
23
- entities: [{{#if hasTodoExample}}Todo{{/if}}],
32
+ entities: [{{#if hasTodoExample}}Todo{{/if}}{{#if (and hasTodoExample (and useTypeorm isPassportAuth))}}, {{/if}}{{#if (and useTypeorm isPassportAuth)}}UserEntity{{/if}}{{#if (eq auth "better-auth:stateless")}}{{#if (or hasTodoExample (and useTypeorm isPassportAuth))}}, {{/if}}AppEntity{{/if}}],
24
33
  migrations: [{{#if isMonorepo}}"migrations/*.{ts,js}"{{else}}"migrations/*.{ts,js}"{{/if}}],
25
34
  synchronize: env.NODE_ENV === "development",
26
35
  type: "{{#if hasPostgres}}postgres{{/if}}{{#if hasMysql}}mysql{{/if}}{{#if hasSqlite}}better-sqlite3{{/if}}",
36
+ {{#unless hasSqlite}}
27
37
  url: databaseUrl,
38
+ {{/unless}}
28
39
  {{#unless hasSqlite}}
29
40
  ...(parsedUrl.username ? { username: decodeURIComponent(parsedUrl.username) } : {}),
30
41
  ...(parsedUrl.password ? { password: decodeURIComponent(parsedUrl.password) } : {}),