import type { FastifyInstance } from 'fastify'; import { v4 as uuid } from 'uuid'; import { db } from '../../db/client.js'; import { users } from '../../db/schema.js'; import { eq, and } from 'drizzle-orm'; import type { JwtPayload, LoginResponse, AuthType } from '../../types/auth.js'; export function signTokens(app: FastifyInstance, userId: string, authType: AuthType, tier: string) { const payload: JwtPayload = { userId, authType, tier }; const accessToken = app.jwt.sign(payload, { expiresIn: '1h' }); const refreshToken = app.jwt.sign(payload, { expiresIn: '30d' }); return { accessToken, refreshToken }; } export function buildLoginResponse( user: typeof users.$inferSelect, accessToken: string, refreshToken: string, ): LoginResponse { return { accessToken, refreshToken, user: { id: user.id, nickname: user.nickname ?? null, avatarUrl: user.avatarUrl ?? null, tier: user.tier ?? 'free', xpTotal: user.xpTotal ?? 0, streakDays: user.streakDays ?? 0, }, }; } export async function findOrCreateGuest(deviceId: string, app: FastifyInstance): Promise { const [existing] = await db .select() .from(users) .where(and(eq(users.authType, 'guest'), eq(users.authId, deviceId))) .limit(1); let user = existing; if (!user) { const newId = uuid(); await db.insert(users).values({ id: newId, authType: 'guest', authId: deviceId, }); const [created] = await db.select().from(users).where(eq(users.id, newId)).limit(1); user = created; } if (!user) throw new Error('Failed to create user'); const tokens = signTokens(app, user.id, 'guest', user.tier ?? 'free'); return buildLoginResponse(user, tokens.accessToken, tokens.refreshToken); } export async function findOrCreateHuawei( openId: string, nickname: string | null, avatarUrl: string | null, app: FastifyInstance, ): Promise { const [existing] = await db .select() .from(users) .where(and(eq(users.authType, 'huawei'), eq(users.authId, openId))) .limit(1); let user = existing; if (!user) { const newId = uuid(); await db.insert(users).values({ id: newId, authType: 'huawei', authId: openId, nickname, avatarUrl, }); const [created] = await db.select().from(users).where(eq(users.id, newId)).limit(1); user = created; } if (!user) throw new Error('Failed to create user'); const tokens = signTokens(app, user.id, 'huawei', user.tier ?? 'free'); return buildLoginResponse(user, tokens.accessToken, tokens.refreshToken); } export async function refreshJwt(app: FastifyInstance, refreshToken: string): Promise<{ accessToken: string }> { const decoded = app.jwt.verify(refreshToken); const payload: JwtPayload = { userId: decoded.userId, authType: decoded.authType, tier: decoded.tier, }; const accessToken = app.jwt.sign(payload, { expiresIn: '1h' }); return { accessToken }; }