@nest-arch/tui 0.4.6 → 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 +145 -133
- package/dist/templates/addons/husky/pre-commit.hbs +1 -1
- package/dist/templates/base/.env.example.hbs +7 -2
- package/dist/templates/base/.env.hbs +7 -2
- package/dist/templates/base/README.md.hbs +11 -2
- package/dist/templates/base/pnpm-workspace.yaml.hbs +9 -4
- package/dist/templates/base/prisma.config.ts.hbs +5 -0
- package/dist/templates/base/src/app.module.ts.hbs +5 -22
- 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 +15 -1
- package/dist/templates/base/src/database/db.service.ts.hbs +6 -3
- 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 +2 -2
- package/dist/templates/base/test/app.e2e-spec.ts.hbs +368 -196
- 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 +2 -2
- package/dist/templates/monorepo/root/README.md.hbs +8 -13
- package/dist/templates/single-project/architecture/nest-api/.env.hbs +6 -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 +2 -2
- package/dist/templates/single-project/architecture/nest-gateway/src/main.ts.hbs +2 -2
- 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 +2 -2
- package/dist/templates/single-project/architecture/nest-microservice/test/microservice.e2e-spec.ts.hbs +35 -0
- package/package.json +5 -5
- package/dist/constants-DVhgS48N.js +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
set -e
|
|
3
3
|
|
|
4
|
-
{{#if isPnpm}}pnpm test{{else if isYarn}}yarn test{{else if isBun}}bun run test{{else}}npm test{{/if}}
|
|
4
|
+
{{#if isPnpm}}pnpm test --passWithNoTests{{else if isYarn}}yarn test --passWithNoTests{{else if isBun}}bun run test --passWithNoTests{{else}}npm test -- --passWithNoTests{{/if}}
|
|
5
5
|
|
|
6
6
|
{{#if hasFormatter}}
|
|
7
7
|
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACMR)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Server
|
|
2
2
|
PORT=3000
|
|
3
3
|
NODE_ENV=development
|
|
4
|
-
CORS_ORIGIN=http://localhost:
|
|
4
|
+
CORS_ORIGIN=http://localhost:3000
|
|
5
5
|
# Comma-separated trusted reverse proxy IP addresses or CIDRs
|
|
6
6
|
TRUSTED_PROXY_IPS={{#each trustedProxyIps}}{{#unless @first}},{{/unless}}{{this}}{{/each}}
|
|
7
7
|
|
|
@@ -35,7 +35,12 @@ MONGODB_URL=mongodb://localhost:27017/{{projectNameKebab}}_db
|
|
|
35
35
|
GRAPHQL_PLAYGROUND=true
|
|
36
36
|
|
|
37
37
|
{{/if}}
|
|
38
|
-
{{#if (eq auth "passport")}}
|
|
38
|
+
{{#if (and (eq auth "passport") (not hasDatabase))}}
|
|
39
|
+
# External identity provider (RS256 JWKS)
|
|
40
|
+
OIDC_JWKS_URI=https://identity.example.com/.well-known/jwks.json
|
|
41
|
+
OIDC_ISSUER=https://identity.example.com/
|
|
42
|
+
OIDC_AUDIENCE=generated-resource-server
|
|
43
|
+
{{else if (eq auth "passport")}}
|
|
39
44
|
# JWT
|
|
40
45
|
JWT_ACCESS_SECRET=change-me-to-a-random-secret-at-least-32-characters-long
|
|
41
46
|
{{#if hasDatabase}}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
CORS_ORIGIN=http://localhost:
|
|
1
|
+
CORS_ORIGIN=http://localhost:3000
|
|
2
2
|
PORT=3000
|
|
3
3
|
TRUSTED_PROXY_IPS={{#each trustedProxyIps}}{{#unless @first}},{{/unless}}{{this}}{{/each}}
|
|
4
4
|
{{#if hasGraphql}}
|
|
@@ -26,7 +26,12 @@ SQLSERVER_TRUST_SERVER_CERTIFICATE=true
|
|
|
26
26
|
{{#if hasMongodb}}
|
|
27
27
|
MONGODB_URL=mongodb://localhost:27017/{{projectNameKebab}}_db
|
|
28
28
|
{{/if}}
|
|
29
|
-
{{#if (eq auth "passport")}}
|
|
29
|
+
{{#if (and (eq auth "passport") (not hasDatabase))}}
|
|
30
|
+
# External identity provider (RS256 JWKS)
|
|
31
|
+
OIDC_JWKS_URI=https://identity.example.com/.well-known/jwks.json
|
|
32
|
+
OIDC_ISSUER=https://identity.example.com/
|
|
33
|
+
OIDC_AUDIENCE=generated-resource-server
|
|
34
|
+
{{else if (eq auth "passport")}}
|
|
30
35
|
JWT_ACCESS_SECRET=change-me-to-a-random-secret-at-least-32-characters-long
|
|
31
36
|
{{#if hasDatabase}}
|
|
32
37
|
JWT_REFRESH_SECRET=change-me-to-a-different-random-secret-at-least-32-characters
|
|
@@ -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
|
|
|
@@ -98,9 +102,14 @@ This project uses **Better Auth** with database-backed sessions. Set `BETTER_AUT
|
|
|
98
102
|
|
|
99
103
|
Run `auth:generate` with your package manager. The script uses the installed CLI version.
|
|
100
104
|
{{#if usePrisma}}
|
|
101
|
-
|
|
105
|
+
{{#if hasMongodb}}
|
|
106
|
+
`auth:generate` normalizes MongoDB IDs and writes auth models to `src/database/orm/prisma/auth.prisma`, using `auth-schema.prisma` as intermediate CLI output. Then run `prisma:push` and `prisma:generate`, as shown in Setup.
|
|
107
|
+
{{else}}
|
|
108
|
+
`auth:generate` updates auth models in `src/database/orm/prisma/schema.prisma`. For local development, run `prisma:push` and then `prisma:generate`, as shown in Setup. For a workflow with migration history, use `prisma:migrate --name auth` instead of pushing the schema and then regenerate the client. For deployments, apply the committed migrations with `prisma:migrate:deploy`.
|
|
109
|
+
{{/if}}
|
|
110
|
+
Inspect the schema diff after changing plugins.
|
|
102
111
|
{{else if useDrizzle}}
|
|
103
|
-
|
|
112
|
+
For local development, run `db:push`, as shown in Setup. For a workflow with migration history, use `db:generate` and `db:migrate` instead. Auth owns `src/database/orm/drizzle/auth-schema.ts`; application tables remain in `schema.ts`. Commit generated migration files. SQLite requires no Docker service.
|
|
104
113
|
{{else}}
|
|
105
114
|
Then run `auth:migrate` and `build`.
|
|
106
115
|
{{/if}}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
allowBuilds:
|
|
2
|
-
{{#if useDrizzle}}
|
|
2
|
+
{{#if (or useDrizzle useTypescript7)}}
|
|
3
3
|
esbuild: true
|
|
4
4
|
{{/if}}
|
|
5
5
|
protobufjs: true
|
|
6
6
|
"@nestjs/core": true
|
|
7
|
-
{{#if useTypescript7}}
|
|
8
|
-
esbuild: true
|
|
9
|
-
{{/if}}
|
|
10
7
|
{{#if swagger}}
|
|
11
8
|
"@scarf/scarf": true
|
|
12
9
|
{{/if}}
|
|
@@ -20,7 +17,9 @@ allowBuilds:
|
|
|
20
17
|
"@prisma/client": true
|
|
21
18
|
{{/if}}
|
|
22
19
|
{{#if isPrisma8}}
|
|
20
|
+
{{#unless (or useDrizzle useTypescript7)}}
|
|
23
21
|
esbuild: true
|
|
22
|
+
{{/unless}}
|
|
24
23
|
msgpackr-extract: true
|
|
25
24
|
workerd: true
|
|
26
25
|
{{/if}}
|
|
@@ -31,3 +30,9 @@ allowBuilds:
|
|
|
31
30
|
{{#if hasSqlite}}
|
|
32
31
|
better-sqlite3: true
|
|
33
32
|
{{/if}}
|
|
33
|
+
{{#if hasTrpc}}
|
|
34
|
+
peerDependencyRules:
|
|
35
|
+
allowedVersions:
|
|
36
|
+
"nestjs-trpc>@nestjs/common": "^12.0.0"
|
|
37
|
+
"nestjs-trpc>@nestjs/core": "^12.0.0"
|
|
38
|
+
{{/if}}
|
|
@@ -27,6 +27,11 @@ import { defineConfig } from "prisma/config";
|
|
|
27
27
|
|
|
28
28
|
export default defineConfig({
|
|
29
29
|
schema: "src/database/orm/prisma{{#unless isBetterAuth}}/schema.prisma{{/unless}}",
|
|
30
|
+
{{#unless isMonorepo}}
|
|
31
|
+
migrations: {
|
|
32
|
+
path: "src/database/orm/prisma/migrations",
|
|
33
|
+
},
|
|
34
|
+
{{/unless}}
|
|
30
35
|
datasource: {
|
|
31
36
|
{{#if hasPostgres}}url: env.POSTGRES_URL,{{/if}}
|
|
32
37
|
{{#if hasMysql}}url: env.MYSQL_URL,{{/if}}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import { Module
|
|
2
|
-
{{#if (and hasGraphql hasRateLimiting)}}
|
|
3
|
-
import { GqlExecutionContext } from "@nestjs/graphql";
|
|
4
|
-
{{/if}}
|
|
1
|
+
import { Module } from "@nestjs/common";
|
|
5
2
|
{{#if (and isPassportAuth hasDatabase)}}
|
|
6
3
|
import { PassportModule } from "@nestjs/passport";
|
|
7
4
|
{{/if}}
|
|
@@ -50,30 +47,16 @@ import { HealthModule } from "./health/health.module.js";
|
|
|
50
47
|
{{/if}}
|
|
51
48
|
{{#if hasRateLimiting}}
|
|
52
49
|
import { APP_GUARD } from "@nestjs/core";
|
|
53
|
-
import { ThrottlerGuard, ThrottlerModule } from "@nestjs/throttler";
|
|
50
|
+
import { {{#unless hasGraphql}}ThrottlerGuard, {{/unless}}ThrottlerModule } from "@nestjs/throttler";
|
|
51
|
+
{{/if}}
|
|
52
|
+
{{#if (and hasGraphql hasRateLimiting)}}
|
|
53
|
+
import { GraphqlThrottlerGuard } from "./libs/middlewares/graphql-throttler.guard.js";
|
|
54
54
|
{{/if}}
|
|
55
55
|
{{#if (and isPassportAuth hasDatabase hasGraphql (not hasRateLimiting))}}
|
|
56
56
|
import { APP_GUARD } from "@nestjs/core";
|
|
57
57
|
{{/if}}
|
|
58
58
|
import { AppService } from "./app.service.js";
|
|
59
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
|
-
|
|
77
60
|
@Module({
|
|
78
61
|
{{#if hasRest}}
|
|
79
62
|
controllers: [
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { Injectable, Inject
|
|
2
|
-
import
|
|
1
|
+
import { Injectable, Inject } from "@nestjs/common";
|
|
2
|
+
import type { OnModuleDestroy, OnModuleInit } from "@nestjs/common";
|
|
3
|
+
import { MongoClient } from "mongodb";
|
|
4
|
+
import type { Collection, Db, Document } from "mongodb";
|
|
3
5
|
import type { IMongoAdapter } from "../interfaces/db-adapter.interface.js";
|
|
4
6
|
|
|
5
7
|
@Injectable()
|
|
@@ -66,6 +66,10 @@ import mysql from 'mysql2/promise';
|
|
|
66
66
|
import { drizzle } from 'drizzle-orm/better-sqlite3';
|
|
67
67
|
import Database from 'better-sqlite3';
|
|
68
68
|
{{/if}}
|
|
69
|
+
{{#if hasSqlserver}}
|
|
70
|
+
import { drizzle } from 'drizzle-orm/node-mssql';
|
|
71
|
+
import sql from 'mssql';
|
|
72
|
+
{{/if}}
|
|
69
73
|
{{/if}}
|
|
70
74
|
|
|
71
75
|
{{#if useTypeorm}}
|
|
@@ -184,13 +188,23 @@ export class DbModule {
|
|
|
184
188
|
{{#if useDrizzle}}
|
|
185
189
|
providers.push({
|
|
186
190
|
provide: 'DRIZZLE_CLIENT',
|
|
187
|
-
useFactory: () => {
|
|
191
|
+
useFactory: {{#if hasSqlserver}}async {{/if}}() => {
|
|
188
192
|
{{#if hasPostgres}}
|
|
189
193
|
const client = new Pool({ connectionString: options.postgresUrl });
|
|
190
194
|
return drizzle({ client, schema });
|
|
191
195
|
{{else if hasMysql}}
|
|
192
196
|
const client = mysql.createPool({ uri: options.mysqlUrl });
|
|
193
197
|
return drizzle(client, { schema, mode: "default" });
|
|
198
|
+
{{else if hasSqlserver}}
|
|
199
|
+
const client = await new sql.ConnectionPool({
|
|
200
|
+
server: options.sqlserver?.server ?? 'localhost',
|
|
201
|
+
port: options.sqlserver?.port ?? 1433,
|
|
202
|
+
database: options.sqlserver?.database ?? 'app_db',
|
|
203
|
+
user: options.sqlserver?.user ?? 'sa',
|
|
204
|
+
password: options.sqlserver?.password ?? 'DevOnly_Strong_Password_2026!X9',
|
|
205
|
+
options: options.sqlserver?.options ?? { encrypt: true, trustServerCertificate: true },
|
|
206
|
+
}).connect();
|
|
207
|
+
return drizzle({ client, schema });
|
|
194
208
|
{{else}}
|
|
195
209
|
const client = new Database(options.sqlitePath || ':memory:');
|
|
196
210
|
return drizzle({ client, schema });
|
|
@@ -49,6 +49,9 @@ import type { MySql2Database } from 'drizzle-orm/mysql2';
|
|
|
49
49
|
{{#if hasSqlite}}
|
|
50
50
|
import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';
|
|
51
51
|
{{/if}}
|
|
52
|
+
{{#if hasSqlserver}}
|
|
53
|
+
import type { NodeMsSqlDatabase } from 'drizzle-orm/node-mssql';
|
|
54
|
+
{{/if}}
|
|
52
55
|
{{#if isMonorepo}}
|
|
53
56
|
import type * as schema from './database/orm/drizzle/schema.js';
|
|
54
57
|
{{else}}
|
|
@@ -64,7 +67,7 @@ type SqlClient = PrismaClient;
|
|
|
64
67
|
{{else if useTypeorm}}
|
|
65
68
|
type SqlClient = DataSource;
|
|
66
69
|
{{else if useDrizzle}}
|
|
67
|
-
type DrizzleClient = {{#if hasPostgres}}NodePgDatabase{{/if}}{{#if hasMysql}}MySql2Database{{/if}}{{#if hasSqlite}}BetterSQLite3Database{{/if}}<typeof schema
|
|
70
|
+
type DrizzleClient = {{#if hasPostgres}}NodePgDatabase{{/if}}{{#if hasMysql}}MySql2Database{{/if}}{{#if hasSqlite}}BetterSQLite3Database{{/if}}{{#if hasSqlserver}}NodeMsSqlDatabase<typeof schema>{{/if}}{{#unless hasSqlserver}}<typeof schema>{{/unless}};
|
|
68
71
|
type SqlClient = DrizzleClient;
|
|
69
72
|
{{else if hasPostgres}}
|
|
70
73
|
type SqlClient = import('pg').Pool;
|
|
@@ -125,14 +128,14 @@ export class DbService {
|
|
|
125
128
|
{{/if}}
|
|
126
129
|
{{/if}}
|
|
127
130
|
{{#if useDrizzle}}
|
|
128
|
-
{{#if (or hasPostgres hasMysql hasSqlite)}}
|
|
131
|
+
{{#if (or hasPostgres hasMysql hasSqlite hasSqlserver)}}
|
|
129
132
|
get drizzle(): DrizzleClient {
|
|
130
133
|
return this.sql.getClient();
|
|
131
134
|
}
|
|
132
135
|
{{/if}}
|
|
133
136
|
{{/if}}
|
|
134
137
|
{{#if useTypeorm}}
|
|
135
|
-
{{#if (or hasPostgres hasMysql hasSqlite)}}
|
|
138
|
+
{{#if (or hasPostgres hasMysql hasSqlite hasSqlserver)}}
|
|
136
139
|
get typeorm(): DataSource {
|
|
137
140
|
return this.sql.getClient();
|
|
138
141
|
}
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
|
|
13
13
|
@Entity("todos")
|
|
14
14
|
export class Todo {
|
|
15
|
-
@PrimaryGeneratedColumn("uuid")
|
|
15
|
+
@PrimaryGeneratedColumn("{{#if hasSqlserver}}increment{{else}}uuid{{/if}}")
|
|
16
16
|
id: string;
|
|
17
17
|
|
|
18
18
|
@Column({ type: "varchar", length: 255, nullable: true })
|
|
@@ -21,7 +21,7 @@ export class Todo {
|
|
|
21
21
|
@Column({ type: "varchar", length: 255 })
|
|
22
22
|
title: string;
|
|
23
23
|
|
|
24
|
-
@Column({ default: false, name: "is_completed", type: "boolean" })
|
|
24
|
+
@Column({ default: false, name: "is_completed", type: "{{#if hasSqlserver}}bit{{else}}boolean{{/if}}" })
|
|
25
25
|
completed: boolean;
|
|
26
26
|
|
|
27
27
|
{{#if hasAuth}}
|
|
@@ -9,6 +9,7 @@ export type { PrismaClient } from '@prisma/client';
|
|
|
9
9
|
export type { Todo } from '@prisma/client';
|
|
10
10
|
{{/if}}
|
|
11
11
|
{{else}}
|
|
12
|
+
{{#unless isPrisma8}}
|
|
12
13
|
{{#if isMonorepo}}
|
|
13
14
|
export type { PrismaClient } from './database/orm/prisma/generated/client.js';
|
|
14
15
|
{{#if hasTodoExample}}
|
|
@@ -20,6 +21,7 @@ export type { PrismaClient } from './orm/prisma/generated/client.js';
|
|
|
20
21
|
export type { Todo } from './orm/prisma/generated/client.js';
|
|
21
22
|
{{/if}}
|
|
22
23
|
{{/if}}
|
|
24
|
+
{{/unless}}
|
|
23
25
|
{{/if}}
|
|
24
26
|
{{/if}}
|
|
25
27
|
export * from './adapters/interfaces/db-adapter.interface.js';
|
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
// oxlint-disable typescript/no-explicit-any
|
|
2
|
+
{{#if hasPostgres}}
|
|
3
|
+
import { {{#if hasTodoExample}}boolean, {{/if}}pgTable{{#if (or (not isPassportAuth) hasTodoExample)}}, serial{{/if}}, text{{#if (or isPassportAuth (eq auth "better-auth:stateless"))}}, timestamp{{/if}} } from 'drizzle-orm/pg-core';
|
|
4
|
+
{{/if}}
|
|
5
|
+
{{#if hasMysql}}
|
|
6
|
+
import { {{#if hasTodoExample}}boolean, {{/if}}mysqlTable{{#if (or (not isPassportAuth) hasTodoExample)}}, int{{/if}}, text{{#if (or isPassportAuth (eq auth "better-auth:stateless"))}}, timestamp, varchar{{/if}} } from 'drizzle-orm/mysql-core';
|
|
7
|
+
{{/if}}
|
|
8
|
+
{{#if hasSqlite}}
|
|
9
|
+
import { sqliteTable{{#if (or (not isPassportAuth) hasTodoExample)}}, integer{{/if}}, text } from 'drizzle-orm/sqlite-core';
|
|
10
|
+
{{/if}}
|
|
11
|
+
{{#if hasSqlserver}}
|
|
12
|
+
import { bit, int, mssqlTable, nvarchar } from 'drizzle-orm/mssql-core';
|
|
13
|
+
{{/if}}
|
|
2
14
|
{{#if (eq auth "better-auth")}}
|
|
3
15
|
// oxlint-disable-next-line oxc/no-barrel-file
|
|
4
16
|
export * from "./auth-schema.js";
|
|
5
17
|
{{/if}}
|
|
6
18
|
{{#if hasPostgres}}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
{{#unless (eq auth "better-auth")}}
|
|
19
|
+
{{#if (or isPassportAuth (eq auth "better-auth:stateless"))}}
|
|
10
20
|
export const users = pgTable('users', {
|
|
11
21
|
email: text('email').unique(),
|
|
12
22
|
{{#if isPassportAuth}}
|
|
@@ -23,7 +33,7 @@ export const users = pgTable('users', {
|
|
|
23
33
|
role: text('role').default('USER'),
|
|
24
34
|
{{/if}}
|
|
25
35
|
});
|
|
26
|
-
{{/
|
|
36
|
+
{{/if}}
|
|
27
37
|
{{#if hasTodoExample}}
|
|
28
38
|
export const todos = pgTable('todos', {
|
|
29
39
|
{{#if hasAuth}}
|
|
@@ -37,9 +47,7 @@ export const todos = pgTable('todos', {
|
|
|
37
47
|
{{/if}}
|
|
38
48
|
{{/if}}
|
|
39
49
|
{{#if hasMysql}}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
{{#unless (eq auth "better-auth")}}
|
|
50
|
+
{{#if (or isPassportAuth (eq auth "better-auth:stateless"))}}
|
|
43
51
|
export const users = mysqlTable('users', {
|
|
44
52
|
email: varchar('email', { length: 320 }).unique(),
|
|
45
53
|
{{#if isPassportAuth}}
|
|
@@ -56,7 +64,7 @@ export const users = mysqlTable('users', {
|
|
|
56
64
|
role: text('role').default('USER'),
|
|
57
65
|
{{/if}}
|
|
58
66
|
});
|
|
59
|
-
{{/
|
|
67
|
+
{{/if}}
|
|
60
68
|
{{#if hasTodoExample}}
|
|
61
69
|
export const todos = mysqlTable('todos', {
|
|
62
70
|
{{#if hasAuth}}
|
|
@@ -70,9 +78,7 @@ export const todos = mysqlTable('todos', {
|
|
|
70
78
|
{{/if}}
|
|
71
79
|
{{/if}}
|
|
72
80
|
{{#if hasSqlite}}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
{{#unless (eq auth "better-auth")}}
|
|
81
|
+
{{#if (or isPassportAuth (eq auth "better-auth:stateless"))}}
|
|
76
82
|
export const users = sqliteTable('users', {
|
|
77
83
|
email: text('email').unique(),
|
|
78
84
|
{{#if isPassportAuth}}
|
|
@@ -88,7 +94,7 @@ export const users = sqliteTable('users', {
|
|
|
88
94
|
role: text('role').default('USER'),
|
|
89
95
|
{{/if}}
|
|
90
96
|
});
|
|
91
|
-
{{/
|
|
97
|
+
{{/if}}
|
|
92
98
|
{{#if hasTodoExample}}
|
|
93
99
|
export const todos = sqliteTable('todos', {
|
|
94
100
|
{{#if hasAuth}}
|
|
@@ -101,3 +107,33 @@ export const todos = sqliteTable('todos', {
|
|
|
101
107
|
});
|
|
102
108
|
{{/if}}
|
|
103
109
|
{{/if}}
|
|
110
|
+
{{#if hasSqlserver}}
|
|
111
|
+
{{#if (or isPassportAuth (eq auth "better-auth:stateless"))}}
|
|
112
|
+
export const users = mssqlTable('users', {
|
|
113
|
+
email: nvarchar('email', { length: 320 }).unique(),
|
|
114
|
+
{{#if isPassportAuth}}
|
|
115
|
+
id: nvarchar('id', { length: 255 }).primaryKey(),
|
|
116
|
+
{{else}}
|
|
117
|
+
id: int('id').identity().primaryKey(),
|
|
118
|
+
{{/if}}
|
|
119
|
+
name: nvarchar('name', { length: 255 }),
|
|
120
|
+
{{#if isPassportAuth}}
|
|
121
|
+
password: nvarchar('password', { length: 255 }).notNull(),
|
|
122
|
+
firstname: nvarchar('firstname', { length: 255 }),
|
|
123
|
+
lastname: nvarchar('lastname', { length: 255 }),
|
|
124
|
+
role: nvarchar('role', { length: 32 }).default('USER'),
|
|
125
|
+
{{/if}}
|
|
126
|
+
});
|
|
127
|
+
{{/if}}
|
|
128
|
+
{{#if hasTodoExample}}
|
|
129
|
+
export const todos = mssqlTable('todos', {
|
|
130
|
+
{{#if hasAuth}}
|
|
131
|
+
authorId: nvarchar('author_id', { length: 255 }),
|
|
132
|
+
{{/if}}
|
|
133
|
+
completed: bit('completed').notNull().default(false),
|
|
134
|
+
description: nvarchar('description', { length: 'max' }),
|
|
135
|
+
id: int('id').identity().primaryKey(),
|
|
136
|
+
title: nvarchar('title', { length: 255 }).notNull(),
|
|
137
|
+
});
|
|
138
|
+
{{/if}}
|
|
139
|
+
{{/if}}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// oxlint-disable typescript/no-non-null-assertion
|
|
2
2
|
import "reflect-metadata";
|
|
3
|
+
import "dotenv/config";
|
|
3
4
|
{{#if isMonorepo}}
|
|
4
5
|
import { env } from "@repo/env/api-gateway";
|
|
5
6
|
{{else}}
|
|
@@ -16,27 +17,42 @@ import { UserEntity } from "../../../modules/users/entities/user.entity.js";
|
|
|
16
17
|
import { AppEntity } from "../../entities/app.entity.js";
|
|
17
18
|
{{/if}}
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
{{#unless hasSqlite}}
|
|
20
|
+
{{#unless (or hasSqlite hasSqlserver)}}
|
|
21
|
+
const databaseUrl = env.{{#if hasPostgres}}POSTGRES_URL{{/if}}{{#if hasMysql}}MYSQL_URL{{/if}};
|
|
23
22
|
const parsedUrl = new URL(databaseUrl);
|
|
24
23
|
{{/unless}}
|
|
25
24
|
|
|
26
25
|
|
|
27
26
|
export const AppDataSource = new DataSource({
|
|
28
27
|
{{#if hasSqlite}}
|
|
29
|
-
database:
|
|
28
|
+
database: env.SQLITE_PATH,
|
|
29
|
+
{{/if}}
|
|
30
|
+
{{#if hasSqlserver}}
|
|
31
|
+
database: env.SQLSERVER_DATABASE,
|
|
30
32
|
{{/if}}
|
|
31
33
|
// Register entities explicitly for consistent metadata in Node and test runners.
|
|
32
34
|
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}}],
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
{{#if hasSqlserver}}
|
|
36
|
+
host: env.SQLSERVER_HOST,
|
|
37
|
+
{{/if}}
|
|
38
|
+
migrations: [
|
|
39
|
+
"dist/database/orm/typeorm/migrations/*.js",
|
|
40
|
+
"src/database/orm/typeorm/migrations/*.js",
|
|
41
|
+
],
|
|
42
|
+
{{#if hasSqlserver}}
|
|
43
|
+
options: { encrypt: env.SQLSERVER_ENCRYPT, trustServerCertificate: env.SQLSERVER_TRUST_SERVER_CERTIFICATE },
|
|
44
|
+
password: env.SQLSERVER_PASSWORD,
|
|
45
|
+
port: env.SQLSERVER_PORT,
|
|
46
|
+
{{/if}}
|
|
47
|
+
synchronize: false,
|
|
48
|
+
type: "{{#if hasPostgres}}postgres{{/if}}{{#if hasMysql}}mysql{{/if}}{{#if hasSqlite}}better-sqlite3{{/if}}{{#if hasSqlserver}}mssql{{/if}}",
|
|
49
|
+
{{#if hasSqlserver}}
|
|
50
|
+
username: env.SQLSERVER_USER,
|
|
51
|
+
{{/if}}
|
|
52
|
+
{{#unless (or hasSqlite hasSqlserver)}}
|
|
37
53
|
url: databaseUrl,
|
|
38
54
|
{{/unless}}
|
|
39
|
-
{{#unless hasSqlite}}
|
|
55
|
+
{{#unless (or hasSqlite hasSqlserver)}}
|
|
40
56
|
...(parsedUrl.username ? { username: decodeURIComponent(parsedUrl.username) } : {}),
|
|
41
57
|
...(parsedUrl.password ? { password: decodeURIComponent(parsedUrl.password) } : {}),
|
|
42
58
|
{{/unless}}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Injectable, type ExecutionContext } from "@nestjs/common";
|
|
2
|
+
import { GqlExecutionContext } from "@nestjs/graphql";
|
|
3
|
+
import { ThrottlerGuard } from "@nestjs/throttler";
|
|
4
|
+
|
|
5
|
+
@Injectable()
|
|
6
|
+
export class GraphqlThrottlerGuard extends ThrottlerGuard {
|
|
7
|
+
protected getRequestResponse(context: ExecutionContext) {
|
|
8
|
+
if (context.getType<string>() !== "graphql") {
|
|
9
|
+
return super.getRequestResponse(context);
|
|
10
|
+
}
|
|
11
|
+
const gqlContext = GqlExecutionContext.create(context).getContext();
|
|
12
|
+
return { req: gqlContext.req, res: { header: () => true } };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
protected getTracker(request: Record<string, unknown>): Promise<string> {
|
|
16
|
+
const socket = request.socket as { remoteAddress?: string } | undefined;
|
|
17
|
+
const ip = request.ip;
|
|
18
|
+
return Promise.resolve(
|
|
19
|
+
typeof ip === "string" ? ip : (socket?.remoteAddress ?? "unknown")
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ContextOptions } from "nestjs-trpc";
|
|
2
|
-
{{#if (eq auth "better-auth")}}
|
|
2
|
+
{{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}
|
|
3
3
|
import type { UserSession } from "../../auth/auth.js";
|
|
4
4
|
{{else if (eq auth "passport")}}
|
|
5
5
|
import type { AuthService } from "../../auth/auth.service.js";
|
|
6
6
|
{{/if}}
|
|
7
7
|
|
|
8
8
|
export type InnerContext = {
|
|
9
|
-
session?: {{#if (eq auth "better-auth")}}UserSession{{else if (eq auth "passport")}}{ user: NonNullable<Awaited<ReturnType<AuthService[{{#if (and usePrisma (not hasMongodb))}}"validate"{{else}}"validateUser"{{/if}}]>>> }{{else}}unknown{{/if}};
|
|
9
|
+
session?: {{#if (or (eq auth "better-auth") (eq auth "better-auth:stateless"))}}UserSession{{else if (eq auth "passport")}}{ user: NonNullable<Awaited<ReturnType<AuthService[{{#if (and usePrisma (not hasMongodb))}}"validate"{{else}}"validateUser"{{/if}}]>>> }{{else}}unknown{{/if}};
|
|
10
10
|
} & ContextOptions;
|
|
@@ -70,8 +70,8 @@ async function bootstrap() {
|
|
|
70
70
|
{{/if}}
|
|
71
71
|
{{#if (includes apis "trpc")}}
|
|
72
72
|
trpc: {
|
|
73
|
-
routerFilePath: "./src/libs/trpc/@generated/server.ts",
|
|
74
73
|
pathPrefix: "/trpc",
|
|
74
|
+
routerFilePath: "./{{trpcGeneratePath}}/server.ts",
|
|
75
75
|
},
|
|
76
76
|
{{/if}}
|
|
77
77
|
zod: {
|
|
@@ -98,8 +98,8 @@ async function bootstrap() {
|
|
|
98
98
|
{{/if}}
|
|
99
99
|
{{#if (includes apis "trpc")}}
|
|
100
100
|
trpc: {
|
|
101
|
-
routerFilePath: "./src/trpc/router.ts",
|
|
102
101
|
pathPrefix: "/trpc",
|
|
102
|
+
routerFilePath: "./{{trpcGeneratePath}}/server.ts",
|
|
103
103
|
},
|
|
104
104
|
{{/if}}
|
|
105
105
|
zod: {
|