/** * POST /api/magic/devices/[deviceId]/request-release * * Startet 24h Cooldown für Magic-Device-Binding. * Nach 24h wird Token automatisch via Cron invalidiert. * * Idempotent: wenn bereits gesetzt → return existing. */ export default defineEventHandler(async (event) => { const user = await requireUser(event); const deviceId = getRouterParam(event, "deviceId"); if (!deviceId) { throw createError({ statusCode: 400, message: "deviceId required", }); } const db = usePrisma(); // Ownership-Check + Magic-Binding-Check const device = await db.userDevice.findUnique({ where: { userId_deviceId: { userId: user.id, deviceId } }, select: { id: true, magicEnrolledAt: true, magicRevokedAt: true, releaseRequestedAt: true, }, }); if (!device || !device.magicEnrolledAt || device.magicRevokedAt) { throw createError({ statusCode: 404, message: "Magic-Binding nicht gefunden oder bereits revoked", }); } // Idempotent: wenn bereits gesetzt → return existing if (device.releaseRequestedAt) { const releaseAvailableAt = new Date( device.releaseRequestedAt.getTime() + 24 * 60 * 60 * 1000, ); return { success: true, data: { releaseRequestedAt: device.releaseRequestedAt.toISOString(), releaseAvailableAt: releaseAvailableAt.toISOString(), }, }; } // Setze releaseRequestedAt const now = new Date(); await db.userDevice.update({ where: { id: device.id }, data: { releaseRequestedAt: now }, }); const releaseAvailableAt = new Date(now.getTime() + 24 * 60 * 60 * 1000); return { success: true, data: { releaseRequestedAt: now.toISOString(), releaseAvailableAt: releaseAvailableAt.toISOString(), }, }; });