import { revalidatePath } from "next/cache"; import { and, desc, eq, isNull } from "drizzle-orm"; import { auth } from "@/auth"; import { db } from "@/lib/db/client"; import { cliTokens, users } from "@/lib/db/schema"; import { mintCliToken, revokeCliToken, CLI_TOKEN_TTL_SECONDS, } from "@/lib/auth/cli-token"; import { Container, PageHeader } from "@/app/_components/ui/container"; import { Card, CardBody, CardHeader } from "@/app/_components/ui/card"; import { Badge } from "@/app/_components/ui/badge"; import { EmptyState } from "@/app/_components/ui/empty-state"; import TokensManager from "./tokens-manager"; export const dynamic = "force-dynamic"; async function createTokenAction(_prev: { token: string | null; error: string | null }, formData: FormData): Promise<{ token: string | null; error: string | null }> { "use server"; try { const session = await auth(); if (!session?.user?.id) return { token: null, error: "not authenticated" }; const name = String(formData.get("name") ?? "").trim() || `Token ${new Date().toISOString().slice(0, 10)}`; const userRow = await db .select({ oidcIss: users.oidcIss, oidcSub: users.oidcSub, email: users.email, name: users.name, }) .from(users) .where(eq(users.id, session.user.id)) .limit(1); const u = userRow[0]; if (!u) return { token: null, error: "user row not found" }; const minted = await mintCliToken( { userId: session.user.id, oidcIss: u.oidcIss, oidcSub: u.oidcSub, email: u.email, name: u.name, }, { tokenName: name }, ); revalidatePath("/settings/tokens"); return { token: minted.token, error: null }; } catch (e) { return { token: null, error: e instanceof Error ? e.message : "unknown error" }; } } async function revokeTokenAction(formData: FormData) { "use server"; const session = await auth(); if (!session?.user?.id) throw new Error("not authenticated"); const tokenId = String(formData.get("tokenId") ?? ""); await revokeCliToken(session.user.id, tokenId); revalidatePath("/settings/tokens"); } export default async function TokensPage() { const session = await auth(); const userId = session!.user.id; const tokens = await db .select({ id: cliTokens.id, name: cliTokens.name, jti: cliTokens.jti, createdAt: cliTokens.createdAt, lastUsedAt: cliTokens.lastUsedAt, expiresAt: cliTokens.expiresAt, revokedAt: cliTokens.revokedAt, }) .from(cliTokens) .where(eq(cliTokens.userId, userId)) .orderBy(desc(cliTokens.createdAt)); const active = tokens.filter((t) => !t.revokedAt && t.expiresAt > new Date()); const inactive = tokens.filter((t) => t.revokedAt || t.expiresAt <= new Date()); const ttlDays = Math.floor(CLI_TOKEN_TTL_SECONDS / 86400); return ( Generate a new token

Active tokens

{active.length === 0 ? ( ) : ( {active.map((t, i) => (
0 ? "border-t border-border" : ""}`} >
{t.name}
Created {new Date(t.createdAt).toLocaleDateString()} ·{" "} {t.lastUsedAt ? `last used ${new Date(t.lastUsedAt).toLocaleString()}` : "never used"} {" · "}expires {new Date(t.expiresAt).toLocaleDateString()}
))}
)} {inactive.length > 0 ? ( <>

Revoked / expired

{inactive.map((t, i) => (
0 ? "border-t border-border" : ""}`} >
{t.name}
{t.revokedAt ? `Revoked ${new Date(t.revokedAt).toLocaleString()}` : `Expired ${new Date(t.expiresAt).toLocaleString()}`}
{t.revokedAt ? "revoked" : "expired"}
))}
) : null}
); }