"use server"; import { revalidatePath } from "next/cache"; import { getServerSession } from "@/lib/auth/guards"; import { prisma } from "@/lib/db"; import { subjectHasFeature } from "@/lib/billing/subscription"; import { generateRawKey, hashKey, keyPreview } from "@/lib/apikeys"; export async function createApiKeyAction( name: string ): Promise<{ ok: boolean; error?: string; key?: string }> { const session = await getServerSession(); if (!session) return { ok: false, error: "You must be signed in." }; const allowed = await subjectHasFeature( session.user.id, "api_access", session.session.activeOrganizationId ); if (!allowed) return { ok: false, error: "API access requires the Pro plan or higher." }; const trimmed = name.trim() || "Untitled key"; const raw = generateRawKey(); await prisma.apiKey.create({ data: { userId: session.user.id, name: trimmed, hashedKey: hashKey(raw), prefix: keyPreview(raw), }, }); revalidatePath("/api-keys"); // Return the raw key once — it is never stored in plaintext. return { ok: true, key: raw }; } export async function revokeApiKeyAction(id: string): Promise<{ ok: boolean; error?: string }> { const session = await getServerSession(); if (!session) return { ok: false, error: "You must be signed in." }; const key = await prisma.apiKey.findUnique({ where: { id }, select: { userId: true } }); if (!key || key.userId !== session.user.id) return { ok: false, error: "Not allowed." }; await prisma.apiKey.update({ where: { id }, data: { revokedAt: new Date() } }); revalidatePath("/api-keys"); return { ok: true }; }