This commit is contained in:
2026-06-11 13:25:26 +03:00
parent b931ee64d4
commit 60b48ca5e8
60 changed files with 12302 additions and 0 deletions
+79
View File
@@ -0,0 +1,79 @@
import { SignJWT, jwtVerify } from 'jose'
import { cookies } from 'next/headers'
import { NextRequest, NextResponse } from 'next/server'
const secretKey = process.env.JWT_SECRET || 'fallback-secret-key-do-not-use-in-prod'
const key = new TextEncoder().encode(secretKey)
export async function encrypt(payload: any) {
return await new SignJWT(payload)
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime('24h')
.sign(key)
}
export async function decrypt(input: string): Promise<any> {
const { payload } = await jwtVerify(input, key, {
algorithms: ['HS256'],
})
return payload
}
export async function login(username: string) {
// Create the session
const expires = new Date(Date.now() + 24 * 60 * 60 * 1000)
const session = await encrypt({ username, expires })
// Save the session in a cookie
const cookieStore = await cookies()
cookieStore.set('session', session, {
expires,
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
path: '/',
})
}
export async function logout() {
const cookieStore = await cookies()
cookieStore.set('session', '', {
expires: new Date(0),
path: '/',
})
}
export async function getSession() {
const cookieStore = await cookies()
const session = cookieStore.get('session')?.value
if (!session) return null
try {
return await decrypt(session)
} catch (error) {
return null
}
}
export async function updateSession(request: NextRequest) {
const session = request.cookies.get('session')?.value
if (!session) return null
try {
const parsed = await decrypt(session)
parsed.expires = new Date(Date.now() + 24 * 60 * 60 * 1000)
const res = NextResponse.next()
res.cookies.set({
name: 'session',
value: await encrypt(parsed),
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
path: '/',
expires: parsed.expires,
})
return res
} catch (error) {
return null
}
}
+9
View File
@@ -0,0 +1,9 @@
import { v2 as cloudinary } from 'cloudinary'
cloudinary.config({
cloud_name: process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
})
export default cloudinary
+19
View File
@@ -0,0 +1,19 @@
import { PrismaClient } from '@prisma/client'
import { Pool } from 'pg'
import { PrismaPg } from '@prisma/adapter-pg'
const prismaClientSingleton = () => {
const pool = new Pool({ connectionString: process.env.DATABASE_URL })
const adapter = new PrismaPg(pool)
return new PrismaClient({ adapter })
}
declare const globalThis: {
prismaGlobal: ReturnType<typeof prismaClientSingleton>;
} & typeof global;
const prisma = globalThis.prismaGlobal ?? prismaClientSingleton()
export default prisma
if (process.env.NODE_ENV !== 'production') globalThis.prismaGlobal = prisma