"use client" import { useState } from "react" import { useRouter } from "next/navigation" import { toast } from "sonner" import { Check, Copy, KeyRound, Loader2, Plus, Trash2, TriangleAlert } from "lucide-react" import { createApiKey, revokeApiKey } from "@/app/actions/api-keys" export type ApiKeyRow = { id: string name: string key_prefix: string created_at: string last_used_at: string | null revoked_at: string | null } const inputClass = "w-full rounded-lg border border-white/10 bg-white/5 px-4 py-2.5 text-sm text-white placeholder-white/30 outline-none ring-indigo-500 transition focus:border-indigo-500/50 focus:ring-1" function formatDate(value: string | null): string { if (!value) return "Never" const d = new Date(value) return Number.isNaN(d.getTime()) ? "—" : d.toLocaleDateString(undefined, { year: "numeric", month: "short", day: "numeric" }) } export function ApiKeyManager({ initialKeys }: { initialKeys: ApiKeyRow[] }) { const router = useRouter() const [name, setName] = useState("") const [creating, setCreating] = useState(false) const [busyId, setBusyId] = useState(null) const [newKey, setNewKey] = useState<{ plaintext: string; prefix: string } | null>(null) const [copied, setCopied] = useState(false) async function handleCreate(e: React.FormEvent) { e.preventDefault() const trimmed = name.trim() if (!trimmed) return setCreating(true) try { const result = await createApiKey(trimmed) setNewKey(result) setName("") setCopied(false) toast.success("API key created") router.refresh() } catch (err) { toast.error(err instanceof Error ? err.message : "Failed to create API key") } finally { setCreating(false) } } async function handleCopy() { if (!newKey) return try { await navigator.clipboard.writeText(newKey.plaintext) setCopied(true) toast.success("Copied to clipboard") setTimeout(() => setCopied(false), 2000) } catch { toast.error("Copy failed — select and copy the key manually") } } async function handleRevoke(key: ApiKeyRow) { setBusyId(key.id) try { await revokeApiKey(key.id) toast.success(`Revoked "${key.name}"`) router.refresh() } catch (err) { toast.error(err instanceof Error ? err.message : "Failed to revoke key") } finally { setBusyId(null) } } return (
{/* One-time plaintext reveal */} {newKey && (

Copy your new API key now

This is the only time it will be shown. Store it somewhere safe — you will not see it again.

{newKey.plaintext}
)} {/* Create form */}

Create an API key

Use API keys to authenticate requests to the public REST API.

setName(e.target.value)} placeholder="e.g. Production integration" className={inputClass + " sm:flex-1"} />
{/* Keys list */}

Your API keys ({initialKeys.length})

{initialKeys.length === 0 ? (
No API keys yet. Create one above to start using the REST API.
) : (
    {initialKeys.map((key) => { const busy = busyId === key.id const revoked = !!key.revoked_at return (
  • {key.name}

    {revoked && ( Revoked )}
    {key.key_prefix} Created {formatDate(key.created_at)} Last used {formatDate(key.last_used_at)}
    {!revoked && ( )}
  • ) })}
)}
) }