diff --git a/app/UserAPIKey.tsx b/app/UserAPIKey.tsx index 78a677c..78d9c4b 100644 --- a/app/UserAPIKey.tsx +++ b/app/UserAPIKey.tsx @@ -3,51 +3,54 @@ import { useEffect, useState, useRef } from "react"; import { toast } from "sonner"; +const isValidKeyFormat = (key: string) => /^[a-zA-Z0-9]{64,}$/.test(key); + export function UserAPIKey() { - const [userAPIKey, setUserAPIKey] = useState(""); - const [isValidating, setIsValidating] = useState(false); - const debounceTimeoutRef = useRef(null); + const [userAPIKey, setUserAPIKey] = useState(() => { + if (typeof window !== "undefined") { + return localStorage.getItem("togetherApiKey") || ""; + } + return ""; + }); - // Initialize from sessionStorage - useEffect(() => { - const storedKey = sessionStorage.getItem("togetherApiKey"); - if (storedKey) { - setUserAPIKey(storedKey); + const [isValid, setIsValid] = useState(true); + const [isChecking, setIsChecking] = useState(false); + + const validateKey = async (key: string) => { + if (!key) { + setIsValid(true); + return; } - }, []); - const validateAndSaveApiKey = async (apiKey: string) => { - if (!apiKey) { - sessionStorage.removeItem("togetherApiKey"); - return false; + if (!isValidKeyFormat(key)) { + setIsValid(false); + return; } - setIsValidating(true); + setIsChecking(true); + try { - const response = await fetch("/api/validate-key", { - method: "POST", + const res = await fetch("https://api.together.xyz/v1/models", { headers: { - "Content-Type": "application/json", + Authorization: `Bearer ${key}`, }, - body: JSON.stringify({ apiKey }), }); - const result = await response.json(); - - if (result.success) { - sessionStorage.setItem("togetherApiKey", apiKey); - toast.success("API key validated and saved!"); - return true; - } else { - toast.error(result.message || "Invalid API key"); - return false; - } - } catch (error) { - console.error("Error validating API key:", error); - toast.error("Failed to validate API key. Please try again."); - return false; + setIsValid(res.ok); + } catch { + setIsValid(false); } finally { - setIsValidating(false); + setIsChecking(false); + } + }; + + useEffect(() => { + if (userAPIKey) { + localStorage.setItem("togetherApiKey", userAPIKey); + validateKey(userAPIKey); + } else { + localStorage.removeItem("togetherApiKey"); + setIsValid(true); } }; @@ -70,33 +73,50 @@ export function UserAPIKey() { }; return ( -
-
-

[Optional] Add your

- - Together API Key: - -
-
+
+
+
+

[Optional] Add your

+ + Together API Key: + +
setUserAPIKey(e.target.value)} placeholder="API key" - className="h-8 w-full rounded border-[0.5px] border-gray-700 bg-gray-900 px-2 text-sm focus-visible:outline focus-visible:outline-gray-200" + className={`h-8 rounded border-[0.5px] px-2 text-sm focus-visible:outline + ${ + isValid + ? "border-gray-700 bg-gray-900 focus-visible:outline-gray-200" + : "border-red-500 bg-red-900 focus-visible:outline-red-300" + }`} /> - {isValidating && ( -
-
-
- )}
+ + {!isChecking && !isValid && ( +

+ Invalid Together AI key. Please double-check or create one at{" "} + + Together API settings + . +

+ )} + + {isChecking && ( +

Validating key...

+ )}
); }