import { NextResponse } from "next/server"; import { getPayload } from "payload"; import config from "@payload-config"; import { createLiveKitToken, getLiveKitClientUrl } from "@/lib/meeting/livekit"; import { isMeetingParticipantKicked } from "@/lib/meeting/kicks"; import { verifyMeetingToken } from "@/lib/meeting/token"; import { authorizeMeeting } from "@/lib/meeting/access"; export const dynamic = "force-dynamic"; type Args = { params: Promise<{ slug: string }> }; /** Exchanges the app's short-lived meeting credential for a LiveKit token. */ export async function POST(request: Request, { params }: Args) { const { slug } = await params; const authorization = request.headers.get("authorization") ?? ""; const appToken = authorization.startsWith("Bearer ") ? authorization.slice(7) : ""; const meetingToken = verifyMeetingToken(appToken); if (!meetingToken || meetingToken.eventSlug !== slug) { return NextResponse.json({ error: "Die Meeting-Sitzung ist ungültig." }, { status: 401 }); } if (isMeetingParticipantKicked(slug, meetingToken.participantId, meetingToken.clientId)) { return NextResponse.json({ error: "Du wurdest aus diesem Meeting entfernt." }, { status: 403 }); } try { let expiresAt = meetingToken.exp; const isAdminTestRoom = meetingToken.role === "host" && meetingToken.testRoom === true && slug.startsWith("test-"); if (!isAdminTestRoom) { const payload = await getPayload({ config }); const { docs } = await payload.find({ collection: "events", where: { slug: { equals: slug } }, limit: 1 }); if (!docs[0]?.isOnline) return NextResponse.json({ error: "Dieser Online-Termin wurde nicht gefunden." }, { status: 404 }); const access = await authorizeMeeting(payload, docs[0], meetingToken.role); if (!access || access.accessVersion !== meetingToken.accessVersion) { return NextResponse.json({ error: "Dieser Meeting-Zugang ist nicht mehr gültig. Bitte tritt erneut bei." }, { status: 403 }); } expiresAt = Math.min(expiresAt, access.expiresAt); } const participantToken = await createLiveKitToken({ eventSlug: slug, participantId: meetingToken.participantId, name: meetingToken.name, role: meetingToken.role, clientId: meetingToken.clientId, accessVersion: meetingToken.accessVersion, expiresAt, }); return NextResponse.json({ serverUrl: getLiveKitClientUrl(), participantToken }); } catch (error) { console.error("meeting LiveKit connect failed", error); return NextResponse.json({ error: "Der Video-Server ist gerade nicht erreichbar." }, { status: 503 }); } }