speedrun-cli 2.6.1

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 (159) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/LICENSE +21 -0
  3. package/README.md +620 -0
  4. package/bin/cli.js +224 -0
  5. package/index.js +12 -0
  6. package/package.json +74 -0
  7. package/src/constants.js +65 -0
  8. package/src/generator.js +271 -0
  9. package/src/index.js +13 -0
  10. package/src/moduleGenerator.js +586 -0
  11. package/src/postSetup.js +365 -0
  12. package/src/prompts.js +189 -0
  13. package/src/utils.js +112 -0
  14. package/templates/README.md +81 -0
  15. package/templates/base/eslint.config.mjs +34 -0
  16. package/templates/base/gitignore +78 -0
  17. package/templates/base/nest-cli.json +8 -0
  18. package/templates/base/src/common/constants/cookie.config.ts +20 -0
  19. package/templates/base/src/common/decorators/get-user.decorator.ts +13 -0
  20. package/templates/base/src/common/decorators/public.decorator.ts +4 -0
  21. package/templates/base/src/common/decorators/roles.decorator.ts +4 -0
  22. package/templates/base/src/common/dtos/pagination.dto.ts +29 -0
  23. package/templates/base/src/common/filters/http-exception.filter.ts +108 -0
  24. package/templates/base/src/common/guards/auth.guard.ts +51 -0
  25. package/templates/base/src/common/guards/refresh-token.guard.ts +39 -0
  26. package/templates/base/src/common/guards/roles.guard.ts +45 -0
  27. package/templates/base/src/common/interceptors/response.interceptor.ts +55 -0
  28. package/templates/base/src/common/interfaces/api-response.interface.ts +26 -0
  29. package/templates/base/src/common/middleware/correlation-id.middleware.ts +20 -0
  30. package/templates/base/src/common/validators/password.validator.ts +37 -0
  31. package/templates/base/src/config/config.module.ts +14 -0
  32. package/templates/base/src/config/logger.config.ts +109 -0
  33. package/templates/base/src/main.ts +84 -0
  34. package/templates/base/src/modules/auth/auth.controller.ts +133 -0
  35. package/templates/base/src/modules/auth/dtos/login.dto.ts +11 -0
  36. package/templates/base/src/modules/auth/dtos/signup.dto.ts +8 -0
  37. package/templates/base/src/modules/health/health.controller.ts +20 -0
  38. package/templates/base/src/modules/health/health.module.ts +7 -0
  39. package/templates/base/src/modules/users/dtos/update-profile.dto.ts +12 -0
  40. package/templates/base/src/modules/users/dtos/update-user.dto.ts +13 -0
  41. package/templates/base/src/modules/users/users.controller.ts +65 -0
  42. package/templates/base/test/app.e2e-spec.ts +24 -0
  43. package/templates/base/test/jest-e2e.json +9 -0
  44. package/templates/base/tsconfig.build.json +4 -0
  45. package/templates/base/tsconfig.json +24 -0
  46. package/templates/base-crud/CRUD_README.md +385 -0
  47. package/templates/base-crud/src/common/base/base.controller.ts +321 -0
  48. package/templates/base-crud/src/common/base/base.service.ts +192 -0
  49. package/templates/base-crud/src/common/base/index.ts +20 -0
  50. package/templates/base-crud/src/common/base/swagger/api-response.dto.ts +82 -0
  51. package/templates/base-crud/src/common/base/swagger/paginated.dto.ts +102 -0
  52. package/templates/base-crud/src/modules/products/dto/create-product.dto.ts +44 -0
  53. package/templates/base-crud/src/modules/products/dto/product.dto.ts +38 -0
  54. package/templates/base-crud/src/modules/products/dto/update-product.dto.ts +12 -0
  55. package/templates/base-crud/src/modules/products/products.controller.ts +94 -0
  56. package/templates/base-crud-drizzle/src/modules/products/products.controller.ts +79 -0
  57. package/templates/base-crud-drizzle/src/modules/products/products.module.ts +24 -0
  58. package/templates/base-crud-drizzle/src/modules/products/products.service.ts +140 -0
  59. package/templates/base-crud-drizzle/src/modules/products/schema/products.schema.ts +39 -0
  60. package/templates/base-crud-mongoose/src/modules/products/products.controller.ts +79 -0
  61. package/templates/base-crud-mongoose/src/modules/products/products.module.ts +26 -0
  62. package/templates/base-crud-mongoose/src/modules/products/products.service.ts +133 -0
  63. package/templates/base-crud-mongoose/src/modules/products/schemas/product.schema.ts +67 -0
  64. package/templates/base-crud-prisma/src/modules/products/products.module.ts +12 -0
  65. package/templates/base-crud-prisma/src/modules/products/products.service.ts +100 -0
  66. package/templates/base-crud-typeorm/src/modules/products/entities/product.entity.ts +58 -0
  67. package/templates/base-crud-typeorm/src/modules/products/products.controller.ts +79 -0
  68. package/templates/base-crud-typeorm/src/modules/products/products.module.ts +25 -0
  69. package/templates/base-crud-typeorm/src/modules/products/products.service.ts +102 -0
  70. package/templates/database/mongodb/.env.example +22 -0
  71. package/templates/database/mysql/.env.example +24 -0
  72. package/templates/database/mysql/drizzle.config.ts +13 -0
  73. package/templates/database/mysql/package.json +5 -0
  74. package/templates/database/mysql/prisma/schema.prisma +55 -0
  75. package/templates/database/mysql/src/database/drizzle.ts +13 -0
  76. package/templates/database/mysql/src/database/schema.ts +58 -0
  77. package/templates/database/postgres/.env.example +24 -0
  78. package/templates/database/postgres/drizzle.config.ts +13 -0
  79. package/templates/database/postgres/package.json +8 -0
  80. package/templates/database/postgres/prisma/schema.prisma +55 -0
  81. package/templates/database/sqlite/.env.example +24 -0
  82. package/templates/database/sqlite/drizzle.config.ts +13 -0
  83. package/templates/database/sqlite/package.json +8 -0
  84. package/templates/database/sqlite/prisma/schema.prisma +48 -0
  85. package/templates/database/sqlite/src/database/drizzle.ts +11 -0
  86. package/templates/database/sqlite/src/database/schema.ts +52 -0
  87. package/templates/orm/drizzle/drizzle.config.ts +13 -0
  88. package/templates/orm/drizzle/package.json +90 -0
  89. package/templates/orm/drizzle/src/app.module.ts +73 -0
  90. package/templates/orm/drizzle/src/config/env.validation.ts +55 -0
  91. package/templates/orm/drizzle/src/database/database.module.ts +25 -0
  92. package/templates/orm/drizzle/src/database/drizzle.ts +13 -0
  93. package/templates/orm/drizzle/src/database/schema.ts +60 -0
  94. package/templates/orm/drizzle/src/database/seed.ts +87 -0
  95. package/templates/orm/drizzle/src/modules/auth/auth.module.ts +12 -0
  96. package/templates/orm/drizzle/src/modules/auth/auth.service.ts +298 -0
  97. package/templates/orm/drizzle/src/modules/health/health.controller.ts +34 -0
  98. package/templates/orm/drizzle/src/modules/health/health.module.ts +7 -0
  99. package/templates/orm/drizzle/src/modules/users/users.module.ts +10 -0
  100. package/templates/orm/drizzle/src/modules/users/users.service.ts +152 -0
  101. package/templates/orm/mongoose/.env.example +22 -0
  102. package/templates/orm/mongoose/package.json +86 -0
  103. package/templates/orm/mongoose/src/app.module.ts +73 -0
  104. package/templates/orm/mongoose/src/config/env.validation.ts +55 -0
  105. package/templates/orm/mongoose/src/database/database.module.ts +19 -0
  106. package/templates/orm/mongoose/src/database/seed.ts +107 -0
  107. package/templates/orm/mongoose/src/modules/auth/auth.module.ts +21 -0
  108. package/templates/orm/mongoose/src/modules/auth/auth.service.ts +272 -0
  109. package/templates/orm/mongoose/src/modules/auth/dtos/login.dto.ts +10 -0
  110. package/templates/orm/mongoose/src/modules/auth/dtos/signup.dto.ts +8 -0
  111. package/templates/orm/mongoose/src/modules/health/health.controller.ts +26 -0
  112. package/templates/orm/mongoose/src/modules/health/health.module.ts +7 -0
  113. package/templates/orm/mongoose/src/modules/users/dtos/update-profile.dto.ts +24 -0
  114. package/templates/orm/mongoose/src/modules/users/dtos/update-user.dto.ts +13 -0
  115. package/templates/orm/mongoose/src/modules/users/users.module.ts +19 -0
  116. package/templates/orm/mongoose/src/modules/users/users.service.ts +179 -0
  117. package/templates/orm/mongoose/src/schemas/index.ts +2 -0
  118. package/templates/orm/mongoose/src/schemas/refresh-token.schema.ts +55 -0
  119. package/templates/orm/mongoose/src/schemas/user.schema.ts +53 -0
  120. package/templates/orm/prisma/package.json +102 -0
  121. package/templates/orm/prisma/prisma/schema.prisma +60 -0
  122. package/templates/orm/prisma/prisma/seed.ts +69 -0
  123. package/templates/orm/prisma/src/app.module.ts +55 -0
  124. package/templates/orm/prisma/src/config/env.validation.ts +56 -0
  125. package/templates/orm/prisma/src/modules/auth/auth.module.ts +17 -0
  126. package/templates/orm/prisma/src/modules/auth/auth.service.ts +308 -0
  127. package/templates/orm/prisma/src/modules/health/health.controller.ts +26 -0
  128. package/templates/orm/prisma/src/modules/health/health.module.ts +10 -0
  129. package/templates/orm/prisma/src/modules/users/users.module.ts +11 -0
  130. package/templates/orm/prisma/src/modules/users/users.service.ts +105 -0
  131. package/templates/orm/prisma/src/prisma/prisma.module.ts +9 -0
  132. package/templates/orm/prisma/src/prisma/prisma.service.ts +16 -0
  133. package/templates/orm/typeorm/package.json +100 -0
  134. package/templates/orm/typeorm/src/app.module.ts +55 -0
  135. package/templates/orm/typeorm/src/config/env.validation.ts +58 -0
  136. package/templates/orm/typeorm/src/database/data-source.ts +19 -0
  137. package/templates/orm/typeorm/src/database/database.module.ts +27 -0
  138. package/templates/orm/typeorm/src/database/seed.ts +76 -0
  139. package/templates/orm/typeorm/src/entities/index.ts +2 -0
  140. package/templates/orm/typeorm/src/entities/refresh-token.entity.ts +45 -0
  141. package/templates/orm/typeorm/src/entities/user.entity.ts +51 -0
  142. package/templates/orm/typeorm/src/modules/auth/auth.module.ts +19 -0
  143. package/templates/orm/typeorm/src/modules/auth/auth.service.ts +286 -0
  144. package/templates/orm/typeorm/src/modules/health/health.controller.ts +24 -0
  145. package/templates/orm/typeorm/src/modules/health/health.module.ts +9 -0
  146. package/templates/orm/typeorm/src/modules/users/users.module.ts +13 -0
  147. package/templates/orm/typeorm/src/modules/users/users.service.ts +108 -0
  148. package/templates/swagger/src/common/dtos/pagination.dto.ts +43 -0
  149. package/templates/swagger/src/main.ts +116 -0
  150. package/templates/swagger/src/modules/auth/auth.controller.ts +235 -0
  151. package/templates/swagger/src/modules/auth/dtos/login.dto.ts +20 -0
  152. package/templates/swagger/src/modules/auth/dtos/signup.dto.ts +14 -0
  153. package/templates/swagger/src/modules/users/dtos/update-profile.dto.ts +19 -0
  154. package/templates/swagger/src/modules/users/dtos/update-user.dto.ts +23 -0
  155. package/templates/swagger/src/modules/users/users.controller.ts +214 -0
  156. package/templates/swagger-mongoose/src/modules/auth/dtos/login.dto.ts +20 -0
  157. package/templates/swagger-mongoose/src/modules/auth/dtos/signup.dto.ts +14 -0
  158. package/templates/swagger-mongoose/src/modules/users/dtos/update-profile.dto.ts +40 -0
  159. package/templates/swagger-mongoose/src/modules/users/dtos/update-user.dto.ts +23 -0
@@ -0,0 +1,13 @@
1
+ import type { Config } from 'drizzle-kit';
2
+ import * as dotenv from 'dotenv';
3
+
4
+ dotenv.config();
5
+
6
+ export default {
7
+ schema: './src/database/schema.ts',
8
+ out: './drizzle',
9
+ dialect: 'postgresql',
10
+ dbCredentials: {
11
+ url: process.env.DATABASE_URL!,
12
+ },
13
+ } satisfies Config;
@@ -0,0 +1,90 @@
1
+ {
2
+ "name": "nestjs-auth-drizzle",
3
+ "version": "0.0.1",
4
+ "description": "NestJS Authentication API with Drizzle ORM",
5
+ "author": "",
6
+ "private": true,
7
+ "license": "MIT",
8
+ "scripts": {
9
+ "build": "nest build",
10
+ "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
11
+ "start": "nest start",
12
+ "start:dev": "nest start --watch",
13
+ "start:debug": "nest start --debug --watch",
14
+ "start:prod": "node dist/main",
15
+ "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
16
+ "test": "jest",
17
+ "test:watch": "jest --watch",
18
+ "test:cov": "jest --coverage",
19
+ "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
20
+ "test:e2e": "jest --config ./test/jest-e2e.json",
21
+ "db:generate": "drizzle-kit generate",
22
+ "db:migrate": "drizzle-kit migrate",
23
+ "db:push": "drizzle-kit push",
24
+ "db:studio": "drizzle-kit studio",
25
+ "db:seed": "ts-node src/database/seed.ts"
26
+ },
27
+ "dependencies": {
28
+ "@nestjs/common": "^11.0.0",
29
+ "@nestjs/config": "^4.0.0",
30
+ "@nestjs/core": "^11.0.0",
31
+ "@nestjs/jwt": "^11.0.0",
32
+ "@nestjs/platform-express": "^11.0.0",
33
+ "@nestjs/throttler": "^6.4.0",
34
+ "bcrypt": "^6.0.0",
35
+ "class-transformer": "^0.5.1",
36
+ "class-validator": "^0.14.2",
37
+ "cookie-parser": "^1.4.7",
38
+ "drizzle-orm": "^0.38.0",
39
+ "helmet": "^8.1.0",
40
+ "zod": "^4.1.12",
41
+ "nestjs-pino": "^4.2.0",
42
+ "pino-http": "^10.4.0",
43
+ "pino-pretty": "^13.0.0",
44
+ "reflect-metadata": "^0.2.2",
45
+ "rxjs": "^7.8.1"
46
+ },
47
+ "devDependencies": {
48
+ "@nestjs/cli": "^11.0.0",
49
+ "@nestjs/schematics": "^11.0.0",
50
+ "@nestjs/testing": "^11.0.0",
51
+ "@types/bcrypt": "^6.0.0",
52
+ "@types/cookie-parser": "^1.4.10",
53
+ "@types/express": "^5.0.0",
54
+ "@types/jest": "^30.0.0",
55
+ "@types/node": "^22.10.0",
56
+ "@types/supertest": "^6.0.2",
57
+ "dotenv": "^16.4.7",
58
+ "drizzle-kit": "^0.30.0",
59
+ "eslint": "^9.16.0",
60
+ "eslint-config-prettier": "^10.0.0",
61
+ "eslint-plugin-prettier": "^5.2.2",
62
+ "jest": "^30.0.0",
63
+ "prettier": "^3.4.2",
64
+ "source-map-support": "^0.5.21",
65
+ "supertest": "^7.0.0",
66
+ "ts-jest": "^29.2.5",
67
+ "ts-loader": "^9.5.1",
68
+ "ts-node": "^10.9.2",
69
+ "tsconfig-paths": "^4.2.0",
70
+ "typescript": "^5.7.2",
71
+ "typescript-eslint": "^8.18.0"
72
+ },
73
+ "jest": {
74
+ "moduleFileExtensions": [
75
+ "js",
76
+ "json",
77
+ "ts"
78
+ ],
79
+ "rootDir": "src",
80
+ "testRegex": ".*\\.spec\\.ts$",
81
+ "transform": {
82
+ "^.+\\.(t|j)s$": "ts-jest"
83
+ },
84
+ "collectCoverageFrom": [
85
+ "**/*.(t|j)s"
86
+ ],
87
+ "coverageDirectory": "../coverage",
88
+ "testEnvironment": "node"
89
+ }
90
+ }
@@ -0,0 +1,73 @@
1
+ import { Module } from '@nestjs/common';
2
+ import { ConfigModule } from '@nestjs/config';
3
+ import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core';
4
+ import { ThrottlerModule, ThrottlerGuard } from '@nestjs/throttler';
5
+ import { LoggerModule } from 'nestjs-pino';
6
+
7
+ import { loggerConfig } from './config/logger.config';
8
+ import { validate } from './config/env.validation';
9
+ import { DatabaseModule } from './database/database.module';
10
+ import { AuthModule } from './modules/auth/auth.module';
11
+ import { UsersModule } from './modules/users/users.module';
12
+ import { HealthModule } from './modules/health/health.module';
13
+ import { AuthGuard } from './common/guards/auth.guard';
14
+ import { RolesGuard } from './common/guards/roles.guard';
15
+ import { HttpExceptionFilter } from './common/filters/http-exception.filter';
16
+ import { ResponseInterceptor } from './common/interceptors/response.interceptor';
17
+
18
+ @Module({
19
+ imports: [
20
+ // Configuration
21
+ ConfigModule.forRoot({
22
+ isGlobal: true,
23
+ validate,
24
+ }),
25
+
26
+ // Logging
27
+ LoggerModule.forRoot(loggerConfig),
28
+
29
+ // Rate limiting
30
+ ThrottlerModule.forRoot([
31
+ {
32
+ ttl: 60000, // 1 minute
33
+ limit: 100, // 100 requests per minute
34
+ },
35
+ ]),
36
+
37
+ // Database (PostgreSQL via Drizzle)
38
+ DatabaseModule,
39
+
40
+ // Feature modules
41
+ AuthModule,
42
+ UsersModule,
43
+ HealthModule,
44
+ ],
45
+ providers: [
46
+ // Global exception filter
47
+ {
48
+ provide: APP_FILTER,
49
+ useClass: HttpExceptionFilter,
50
+ },
51
+ // Global response interceptor
52
+ {
53
+ provide: APP_INTERCEPTOR,
54
+ useClass: ResponseInterceptor,
55
+ },
56
+ // Global rate limiter
57
+ {
58
+ provide: APP_GUARD,
59
+ useClass: ThrottlerGuard,
60
+ },
61
+ // Global auth guard
62
+ {
63
+ provide: APP_GUARD,
64
+ useClass: AuthGuard,
65
+ },
66
+ // Global roles guard
67
+ {
68
+ provide: APP_GUARD,
69
+ useClass: RolesGuard,
70
+ },
71
+ ],
72
+ })
73
+ export class AppModule {}
@@ -0,0 +1,55 @@
1
+ import { z } from 'zod';
2
+
3
+ export const envSchema = z.object({
4
+ NODE_ENV: z
5
+ .enum(['development', 'production', 'test'])
6
+ .default('development'),
7
+ PORT: z.coerce.number().default(8080),
8
+
9
+ // Database
10
+ DATABASE_URL: z.string().min(1, 'DATABASE_URL is required'),
11
+
12
+ // JWT Secrets
13
+ JWT_ACCESS_SECRET: z
14
+ .string()
15
+ .min(32, 'JWT_ACCESS_SECRET must be at least 32 characters'),
16
+ JWT_REFRESH_SECRET: z
17
+ .string()
18
+ .min(32, 'JWT_REFRESH_SECRET must be at least 32 characters'),
19
+ JWT_ACCESS_EXPIRY: z
20
+ .string()
21
+ .regex(/^\d+[smhd]$/, 'JWT_ACCESS_EXPIRY must be in format: 60m, 1h, etc.')
22
+ .default('15m'),
23
+ JWT_REFRESH_EXPIRY: z
24
+ .string()
25
+ .regex(/^\d+[smhd]$/, 'JWT_REFRESH_EXPIRY must be in format: 7d, 30d, etc.')
26
+ .default('7d'),
27
+
28
+ // CORS
29
+ CORS_ORIGIN: z
30
+ .string()
31
+ .refine((val) => {
32
+ const origins = val.split(',').map((o) => o.trim());
33
+ const urlRegex = /^https?:\/\/.+/;
34
+ return origins.every((origin) => urlRegex.test(origin) || origin === '*');
35
+ }, 'CORS_ORIGIN must be valid URL(s) or "*"')
36
+ .default('http://localhost:3000'),
37
+
38
+ // Logging
39
+ LOG_LEVEL: z
40
+ .enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace'])
41
+ .default('info'),
42
+ });
43
+
44
+ export type Env = z.infer<typeof envSchema>;
45
+
46
+ export function validate(config: Record<string, unknown>) {
47
+ const result = envSchema.safeParse(config);
48
+ if (!result.success) {
49
+ const errors = result.error.issues
50
+ .map((e) => `${e.path.join('.')}: ${e.message}`)
51
+ .join('\n');
52
+ throw new Error(`Environment validation failed:\n${errors}`);
53
+ }
54
+ return result.data;
55
+ }
@@ -0,0 +1,25 @@
1
+ import { Module, Global } from '@nestjs/common';
2
+ import { ConfigService } from '@nestjs/config';
3
+ import { drizzle } from 'drizzle-orm/node-postgres';
4
+ import { Pool } from 'pg';
5
+ import * as schema from './schema';
6
+
7
+ export const DRIZZLE = Symbol('DRIZZLE');
8
+
9
+ @Global()
10
+ @Module({
11
+ providers: [
12
+ {
13
+ provide: DRIZZLE,
14
+ inject: [ConfigService],
15
+ useFactory: (configService: ConfigService) => {
16
+ const pool = new Pool({
17
+ connectionString: configService.get<string>('DATABASE_URL'),
18
+ });
19
+ return drizzle(pool, { schema });
20
+ },
21
+ },
22
+ ],
23
+ exports: [DRIZZLE],
24
+ })
25
+ export class DatabaseModule {}
@@ -0,0 +1,13 @@
1
+ import { drizzle } from 'drizzle-orm/node-postgres';
2
+ import { Pool } from 'pg';
3
+ import * as schema from './schema';
4
+
5
+ // Create PostgreSQL connection pool
6
+ const pool = new Pool({
7
+ connectionString: process.env.DATABASE_URL,
8
+ });
9
+
10
+ // Create drizzle instance with schema
11
+ export const db = drizzle(pool, { schema });
12
+
13
+ export type DrizzleDB = typeof db;
@@ -0,0 +1,60 @@
1
+ import {
2
+ pgTable,
3
+ varchar,
4
+ text,
5
+ timestamp,
6
+ boolean,
7
+ pgEnum,
8
+ uuid,
9
+ } from 'drizzle-orm/pg-core';
10
+ import { relations } from 'drizzle-orm';
11
+
12
+ // UserRole enum
13
+ export const userRoleEnum = pgEnum('user_role', ['USER', 'ADMIN']);
14
+
15
+ // Users table
16
+ export const users = pgTable('users', {
17
+ id: uuid('id').defaultRandom().primaryKey(),
18
+ fullName: varchar('full_name', { length: 255 }).notNull(),
19
+ email: varchar('email', { length: 255 }).notNull().unique(),
20
+ passwordHash: text('password_hash').notNull(),
21
+ role: userRoleEnum('role').default('USER').notNull(),
22
+ isActive: boolean('is_active').default(true).notNull(),
23
+ createdAt: timestamp('created_at').defaultNow().notNull(),
24
+ updatedAt: timestamp('updated_at').defaultNow().notNull(),
25
+ });
26
+
27
+ // Refresh tokens table
28
+ export const refreshTokens = pgTable('refresh_tokens', {
29
+ id: uuid('id').defaultRandom().primaryKey(),
30
+ token: text('token').notNull(),
31
+ userId: uuid('user_id')
32
+ .notNull()
33
+ .references(() => users.id, { onDelete: 'cascade' }),
34
+ userAgent: varchar('user_agent', { length: 500 }).notNull(),
35
+ ipAddress: varchar('ip_address', { length: 45 }).notNull(),
36
+ expiresAt: timestamp('expires_at').notNull(),
37
+ isRevoked: boolean('is_revoked').default(false).notNull(),
38
+ createdAt: timestamp('created_at').defaultNow().notNull(),
39
+ updatedAt: timestamp('updated_at').defaultNow().notNull(),
40
+ });
41
+
42
+ // Relations
43
+ export const usersRelations = relations(users, ({ many }) => ({
44
+ refreshTokens: many(refreshTokens),
45
+ }));
46
+
47
+ export const refreshTokensRelations = relations(refreshTokens, ({ one }) => ({
48
+ user: one(users, {
49
+ fields: [refreshTokens.userId],
50
+ references: [users.id],
51
+ }),
52
+ }));
53
+
54
+ // Types
55
+ export type User = typeof users.$inferSelect;
56
+ export type NewUser = typeof users.$inferInsert;
57
+ export type RefreshToken = typeof refreshTokens.$inferSelect;
58
+ export type NewRefreshToken = typeof refreshTokens.$inferInsert;
59
+
60
+ export type UserRole = 'USER' | 'ADMIN';
@@ -0,0 +1,87 @@
1
+ import { drizzle } from 'drizzle-orm/node-postgres';
2
+ import { Pool } from 'pg';
3
+ import * as bcrypt from 'bcrypt';
4
+ import * as dotenv from 'dotenv';
5
+ import { eq } from 'drizzle-orm';
6
+ import { users } from './schema';
7
+
8
+ dotenv.config();
9
+
10
+ const SALT_ROUNDS = 12;
11
+
12
+ async function seed() {
13
+ const databaseUrl = process.env.DATABASE_URL;
14
+
15
+ if (!databaseUrl) {
16
+ console.error('āŒ DATABASE_URL is not defined in environment variables');
17
+ process.exit(1);
18
+ }
19
+
20
+ console.log('🌱 Starting database seed...\n');
21
+
22
+ const pool = new Pool({ connectionString: databaseUrl });
23
+ const db = drizzle(pool);
24
+
25
+ try {
26
+ // Check if admin already exists
27
+ const [existingAdmin] = await db
28
+ .select()
29
+ .from(users)
30
+ .where(eq(users.email, 'admin@example.com'))
31
+ .limit(1);
32
+
33
+ if (existingAdmin) {
34
+ console.log('āš ļø Admin user already exists, skipping...');
35
+ } else {
36
+ // Create admin user
37
+ const adminPasswordHash = await bcrypt.hash('Admin@123', SALT_ROUNDS);
38
+
39
+ await db.insert(users).values({
40
+ fullName: 'Admin User',
41
+ email: 'admin@example.com',
42
+ passwordHash: adminPasswordHash,
43
+ role: 'ADMIN',
44
+ isActive: true,
45
+ });
46
+
47
+ console.log('āœ“ Created admin user');
48
+ console.log(' Email: admin@example.com');
49
+ console.log(' Password: Admin@123');
50
+ }
51
+
52
+ // Check if regular user already exists
53
+ const [existingUser] = await db
54
+ .select()
55
+ .from(users)
56
+ .where(eq(users.email, 'user@example.com'))
57
+ .limit(1);
58
+
59
+ if (existingUser) {
60
+ console.log('āš ļø Regular user already exists, skipping...');
61
+ } else {
62
+ // Create regular user
63
+ const userPasswordHash = await bcrypt.hash('User@123', SALT_ROUNDS);
64
+
65
+ await db.insert(users).values({
66
+ fullName: 'Regular User',
67
+ email: 'user@example.com',
68
+ passwordHash: userPasswordHash,
69
+ role: 'USER',
70
+ isActive: true,
71
+ });
72
+
73
+ console.log('āœ“ Created regular user');
74
+ console.log(' Email: user@example.com');
75
+ console.log(' Password: User@123');
76
+ }
77
+
78
+ console.log('\nāœ… Database seed completed successfully!\n');
79
+ } catch (error) {
80
+ console.error('āŒ Seed failed:', error);
81
+ process.exit(1);
82
+ } finally {
83
+ await pool.end();
84
+ }
85
+ }
86
+
87
+ seed();
@@ -0,0 +1,12 @@
1
+ import { Module } from '@nestjs/common';
2
+ import { JwtModule } from '@nestjs/jwt';
3
+ import { AuthController } from './auth.controller';
4
+ import { AuthService } from './auth.service';
5
+
6
+ @Module({
7
+ imports: [JwtModule.register({})],
8
+ controllers: [AuthController],
9
+ providers: [AuthService],
10
+ exports: [AuthService, JwtModule],
11
+ })
12
+ export class AuthModule {}