diff --git a/app/actions/generate-key.js b/app/actions/generate-key.js index 08d6376..27f2ebd 100644 --- a/app/actions/generate-key.js +++ b/app/actions/generate-key.js @@ -9,8 +9,7 @@ import { mintAndPersist, numEnv } from "@/lib/keys/mint-key"; /** * @typedef {Object} GenerateKeyResult * @property {"created"|"exists"|"error"} status - * @property {string} [rawKey] present only when status === "created" (shown once) - * @property {string|null} [keyHint] last-4 hint for masked display + * @property {string|null} [rawKey] full key, present for "created" and "exists" (retrievable) * @property {string} [message] human-friendly info/error */ @@ -35,10 +34,10 @@ export async function generateKey() { return { status: "error", message: "Sign in with GitHub first." }; } - // Idempotency fast-path: existing active key → masked hint, never mint again. + // Idempotency fast-path: existing active key → return it, never mint again. const existing = await repo.findByGithubUserId(identity.githubUserId); if (existing && existing.status === "active") { - return { status: "exists", keyHint: existing.key_hint, message: "You already have a key." }; + return { status: "exists", rawKey: existing.openrouter_key, message: "You already have a key." }; } // Feature gate: live minting stays OFF until the OpenRouter ToS gate clears. @@ -87,7 +86,7 @@ export async function generateKey() { async function resolveConflict(identity) { const row = await repo.findByGithubUserId(identity.githubUserId); if (row?.status === "active") { - return { result: { status: "exists", keyHint: row.key_hint, message: "You already have a key." } }; + return { result: { status: "exists", rawKey: row.openrouter_key, message: "You already have a key." } }; } // Pending row. If stale, an earlier mint was interrupted — reclaim and retry. if (row && isStale(row.created_at, STALE_PENDING_MS)) { diff --git a/app/dashboard/page.js b/app/dashboard/page.js index 6c08083..ee2bcf0 100644 --- a/app/dashboard/page.js +++ b/app/dashboard/page.js @@ -25,10 +25,10 @@ export default async function DashboardPage() { ); } - let existingHint = null; + let existingKey = null; try { const row = await repo.findByGithubUserId(identity.githubUserId); - if (row && row.status === "active") existingHint = row.key_hint; + if (row && row.status === "active") existingKey = row.openrouter_key; } catch { // DB not reachable (e.g. local without POSTGRES_URL) — show the panel; the // server action gates minting and reports a friendly error. @@ -41,7 +41,7 @@ export default async function DashboardPage() {

Your key

Signed in as @{identity.githubUsername}.

- +
); } diff --git a/components/admin/admin-keys-table.js b/components/admin/admin-keys-table.js index 86654c9..4bdec8b 100644 --- a/components/admin/admin-keys-table.js +++ b/components/admin/admin-keys-table.js @@ -1,9 +1,9 @@ -import { maskFromHint } from "@/lib/keys/key-format"; import { AdminKeyRowActions } from "./admin-key-row-actions"; /** - * Renders only safe columns: username, masked key hint, status, created date. - * The `openrouter_key_hash` is NEVER rendered or serialized to the client. + * Admin table: username, full key, status, created date. The full raw key is + * shown here intentionally (admin-only, gated route). The delete handle + * (`openrouter_key_hash`) is never rendered. * * @param {{ rows: import('@/lib/keys/api-keys-repository').ApiKeyRow[] }} props */ @@ -33,7 +33,7 @@ export function AdminKeysTable({ rows }) { @{row.github_username} - {maskFromHint(row.key_hint)} + {row.openrouter_key ?? "—"} {row.status} diff --git a/components/generate-key-panel.js b/components/generate-key-panel.js index 7675b67..5f02c3b 100644 --- a/components/generate-key-panel.js +++ b/components/generate-key-panel.js @@ -3,19 +3,18 @@ import { useState } from "react"; import { generateKey } from "@/app/actions/generate-key"; -import { maskFromHint } from "@/lib/keys/key-format"; import { KeyDisplay } from "./key-display"; /** - * Generate / existing-key panel. Calls the server action; renders the one-time - * key on success, the masked hint if a key already exists. + * Generate / existing-key panel. Calls the server action; renders the full key + * (retrievable) whether it was just created or already existed. * - * @param {{ existingHint: string|null, model: string, repoUrl: string }} props + * @param {{ existingKey: string|null, model: string, repoUrl: string }} props */ -export function GenerateKeyPanel({ existingHint, model, repoUrl }) { +export function GenerateKeyPanel({ existingKey, model, repoUrl }) { const [state, setState] = useState( - existingHint - ? { status: "exists", keyHint: existingHint } + existingKey + ? { status: "exists", rawKey: existingKey } : { status: "idle" }, ); const [loading, setLoading] = useState(false); @@ -27,24 +26,11 @@ export function GenerateKeyPanel({ existingHint, model, repoUrl }) { setLoading(false); } - if (state.status === "created") { + // Both freshly created and previously existing keys render the full value. + if (state.status === "created" || state.status === "exists") { return ; } - if (state.status === "exists") { - return ( -
-

- Your key (masked): {maskFromHint(state.keyHint)} -

-

- The full key is shown only once at creation. Lost it? That's okay — - it's free; a regenerate flow may come later. -

-
- ); - } - return (