otp code, packages update
Gitea Actions / Deploy (push) Successful in 1m34s

This commit is contained in:
vadim committed 2026-10-19 17:23:50 +03:00
1 parent c5691da2b8
commit de1b3754df
6 files changed
+949 -1165

No files matched your search

+909 -1130
View File
File diff suppressed because it is too large. Load diff
+17 -19
View File
@@ -24,49 +24,47 @@
"dependencies": { "dependencies": {
"@apollo/server": "^5.5.1", "@apollo/server": "^5.5.1",
"@as-integrations/express5": "^1.1.2", "@as-integrations/express5": "^1.1.2",
"@aws-sdk/client-s3": "^3.1145.0", "@aws-sdk/client-s3": "^3.1152.0",
"@better-auth/prisma-adapter": "^1.7.2", "@better-auth/prisma-adapter": "^1.7.11",
"@nestjs/apollo": "^14.0.0", "@nestjs/apollo": "^14.0.0",
"@nestjs/common": "^12.0.1", "@nestjs/common": "^12.2.0",
"@nestjs/config": "^12.0.0", "@nestjs/config": "^12.0.1",
"@nestjs/core": "^12.0.1", "@nestjs/core": "^12.2.0",
"@nestjs/event-emitter": "^12.0.1", "@nestjs/event-emitter": "^12.0.1",
"@nestjs/graphql": "^14.0.0", "@nestjs/graphql": "^14.0.0",
"@nestjs/platform-express": "^12.0.1", "@nestjs/platform-express": "^12.2.0",
"@nestjs/schedule": "^12.0.2", "@nestjs/schedule": "^12.0.2",
"@nestjs/typeorm": "^12.0.1",
"@prisma/adapter-pg": "^7.10.0", "@prisma/adapter-pg": "^7.10.0",
"@prisma/client": "^7.10.0", "@prisma/client": "^7.10.0",
"@thallesp/nestjs-better-auth": "^2.7.0", "@thallesp/nestjs-better-auth": "^2.8.0",
"better-auth": "^1.7.2", "better-auth": "^1.7.11",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.15.1", "class-validator": "^0.15.1",
"file-type": "^22.1.1", "file-type": "^22.2.0",
"firebase-admin": "^14.5.0", "firebase-admin": "^14.5.0",
"graphql": "^16.14.2", "graphql": "^16.14.2",
"nodemailer": "^10.0.0", "nodemailer": "^10.1.7",
"pg": "^8.23.0", "pg": "^8.23.0",
"reflect-metadata": "^0.2.2", "reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1", "rxjs": "^7.8.1",
"typeorm": "^1.1.1", "valibot": "^1.5.0"
"valibot": "^1.4.2"
}, },
"devDependencies": { "devDependencies": {
"@nestjs/cli": "^12.0.0", "@nestjs/cli": "^12.0.0",
"@nestjs/mau": "^0.2.6", "@nestjs/mau": "^0.2.8",
"@nestjs/schematics": "^12.0.0", "@nestjs/schematics": "^12.0.0",
"@nestjs/testing": "^12.0.1", "@nestjs/testing": "^12.2.0",
"@types/express": "^5.0.0", "@types/express": "^5.0.0",
"@types/multer": "^2.3.0", "@types/multer": "^2.3.0",
"@types/node": "^24.0.0", "@types/node": "^24.0.0",
"@types/pg": "^8.23.1", "@types/pg": "^8.23.1",
"@types/supertest": "^7.0.0", "@types/supertest": "^7.2.1",
"@vitest/coverage-v8": "^4.1.2", "@vitest/coverage-v8": "^4.1.2",
"oxlint": "^1.58.0", "oxlint": "^1.88.0",
"prettier": "^3.4.2", "prettier": "^3.9.10",
"prisma": "^7.10.0", "prisma": "^7.10.0",
"source-map-support": "^0.5.21", "source-map-support": "^0.5.21",
"supertest": "^7.0.0", "supertest": "^7.3.1",
"typescript": "^6.0.2", "typescript": "^6.0.2",
"vite-tsconfig-paths": "^5.1.4", "vite-tsconfig-paths": "^5.1.4",
"vitest": "^4.1.2" "vitest": "^4.1.2"
-8
View File
@@ -26,21 +26,13 @@ import { join } from 'node:path';
isGlobal: true, isGlobal: true,
cache: true, cache: true,
}), }),
// Внутрипроцессная шина доменных событий. Notification-модуль слушает
// события через неё, не завязываясь на модули, которые их порождают.
EventEmitterModule.forRoot(), EventEmitterModule.forRoot(),
// Периодические задачи (@Cron), например сборка файлов-сирот в FileModule
ScheduleModule.forRoot(), ScheduleModule.forRoot(),
GraphQLModule.forRoot<ApolloDriverConfig>({ GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver, driver: ApolloDriver,
autoSchemaFile: join(process.cwd(), 'src/schema.gql'), autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
sortSchema: true, sortSchema: true,
}), }),
// TypeOrmModule.forRootAsync({
// imports: [ConfigModule],
// inject: [ConfigService],
// useFactory: pgConfig,
// }),
AuthModule.forRoot({ AuthModule.forRoot({
auth: auth, auth: auth,
bodyParser: { bodyParser: {
+1 -2
View File
@@ -1,7 +1,6 @@
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
export function pgConfig(config: ConfigService): TypeOrmModuleOptions { export function pgConfig(config: ConfigService): unknown {
return { return {
type: 'postgres', type: 'postgres',
url: config.getOrThrow<string>('DATABASE_URL'), url: config.getOrThrow<string>('DATABASE_URL'),
+22 -1
View File
@@ -2,12 +2,33 @@ import { betterAuth } from 'better-auth';
import { prismaAdapter } from '@better-auth/prisma-adapter'; import { prismaAdapter } from '@better-auth/prisma-adapter';
import prisma from './prisma.js'; import prisma from './prisma.js';
import EmailSender from './email-sender.js'; import EmailSender from './email-sender.js';
import { emailOTP } from 'better-auth/plugins';
export const auth = betterAuth({ export const auth = betterAuth({
appName: process.env.APP_NAME ?? 'app', appName: process.env.APP_NAME ?? 'app',
basePath: '/api/auth', basePath: '/api/auth',
plugins: [ plugins: [
// authTransformResponse() // authTransformResponse()
emailOTP({
async sendVerificationOTP({ email, otp, type }) {
if (type === 'sign-in') {
// Send the OTP for sign in
console.log({ email, otp, type });
void EmailSender.getTransporter().sendMail({
to: email,
subject: `Your OTP code is: ${otp}`,
text: `Your OTP code is: ${otp}`,
});
} else if (type === 'email-verification') {
// Send the OTP for email verification
console.log({ email, otp, type });
} else {
// Send the OTP for password reset
console.log({ email, otp, type });
}
},
}),
], ],
database: prismaAdapter(prisma, { database: prismaAdapter(prisma, {
provider: 'postgresql', provider: 'postgresql',
@@ -24,7 +45,7 @@ export const auth = betterAuth({
emailAndPassword: { emailAndPassword: {
enabled: true, enabled: true,
autoSignIn: false, autoSignIn: false,
requireEmailVerification: false, requireEmailVerification: true,
onExistingUserSignUp: async ({ user }, request) => { onExistingUserSignUp: async ({ user }, request) => {
console.log('onExistingUserSignUp', { user }); console.log('onExistingUserSignUp', { user });
-5
View File
@@ -16,12 +16,7 @@ async function bootstrap() {
logger: new CustomLogger(), logger: new CustomLogger(),
}); });
// app.useGlobalPipes(new StandardSchemaValidationPipe());
app.setGlobalPrefix('api'); app.setGlobalPrefix('api');
// Глобальный body-parser отключён (better-auth сам парсит своё тело),
// поэтому для GraphQL включаем JSON-парсинг точечно на его пути.
app.use('/graphql', json()); app.use('/graphql', json());
app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true })); app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));
app.useGlobalInterceptors(new TransformResponseInterceptor()); app.useGlobalInterceptors(new TransformResponseInterceptor());