import { CanActivate, ExecutionContext, ForbiddenException, Inject, Injectable, UnauthorizedException, } from '@nestjs/common'; import { fromNodeHeaders } from 'better-auth/node'; import type { Auth } from '@mosaic/auth'; import type { FastifyRequest } from 'fastify'; import { AUTH } from '../auth/auth.tokens.js'; interface UserWithRole { id: string; role?: string; } @Injectable() export class AdminGuard implements CanActivate { constructor(@Inject(AUTH) private readonly auth: Auth) {} async canActivate(context: ExecutionContext): Promise { const request = context.switchToHttp().getRequest(); const headers = fromNodeHeaders(request.raw.headers); const result = await this.auth.api.getSession({ headers }); if (!result) { throw new UnauthorizedException('Invalid or expired session'); } const user = result.user as UserWithRole; if (user.role !== 'admin') { throw new ForbiddenException('Admin access required'); } (request as FastifyRequest & { user: unknown; session: unknown }).user = result.user; (request as FastifyRequest & { user: unknown; session: unknown }).session = result.session; return true; } }