UNPKG

byokay-kit

Version:

Byokay Kit lets users bring their own AI API keys and store them securely in their browser. This eliminates the need for your app to manage sensitive credentials or maintain AI API backend infrastructure.

128 lines (127 loc) 5.06 kB
// src/hooks/useMultiApiKeys.ts import { useState, useEffect, useCallback } from "react"; import { ByokayKey } from "../core/ByokayKeyManager"; // Ensure filename matches class ByokayKey import { validateApiKey } from "../core/apiValidationService"; const manager = new ByokayKey(); export const providerNames = { openai: "OpenAI", claude: "Anthropic Claude", gemini: "Google Gemini", grok: "xAI Grok", deepseek: "DeepSeek", }; export function useMultiApiKeys(initialProviders) { const [keys, setKeys] = useState({}); const [saved, setSaved] = useState({}); const [validating, setValidating] = useState({}); const [validated, setValidated] = useState({}); const [validationMessages, setValidationMessages] = useState({}); const [isUnverifiedDueToCors, setIsUnverifiedDueToCors] = useState({}); // Crucial state const [isLoading, setIsLoading] = useState(true); useEffect(() => { const storedKeys = {}; const initialValidated = {}; setIsLoading(true); initialProviders.forEach((provider) => { const stored = manager.getKey(provider); if (stored) { storedKeys[provider] = stored; initialValidated[provider] = true; } }); setKeys(storedKeys); setValidated(initialValidated); setValidationMessages({}); setIsUnverifiedDueToCors({}); setIsLoading(false); }, [initialProviders]); const handleKeyChange = useCallback((provider, value) => { setKeys((prev) => ({ ...prev, [provider]: value })); setValidated((prev) => ({ ...prev, [provider]: false })); setSaved((prev) => ({ ...prev, [provider]: false })); setValidationMessages((prev) => ({ ...prev, [provider]: null })); setIsUnverifiedDueToCors((prev) => ({ ...prev, [provider]: false })); }, []); const handleSave = useCallback((provider, key) => { if (!key || !key.trim()) return; manager.setKey(provider, key); setKeys((prev) => ({ ...prev, [provider]: key })); setSaved((prev) => ({ ...prev, [provider]: true })); setTimeout(() => { setSaved((prev) => ({ ...prev, [provider]: false })); }, 1500); }, []); const handleClear = useCallback((provider) => { manager.removeKey(provider); setKeys((prev) => { const newKeys = { ...prev }; delete newKeys[provider]; return newKeys; }); setValidated((prev) => ({ ...prev, [provider]: false })); setSaved((prev) => ({ ...prev, [provider]: false })); setValidationMessages((prev) => ({ ...prev, [provider]: null })); setIsUnverifiedDueToCors((prev) => ({ ...prev, [provider]: false })); }, []); const handleClearAll = useCallback(() => { initialProviders.forEach((provider) => manager.removeKey(provider)); setKeys({}); setValidated({}); setSaved({}); setValidationMessages({}); setIsUnverifiedDueToCors({}); }, [initialProviders]); const handleValidate = useCallback(async (provider, key) => { if (!key || !key.trim()) { setValidationMessages((prev) => ({ ...prev, [provider]: "API key cannot be empty.", })); setValidating((prev) => ({ ...prev, [provider]: false })); return; } setValidating((prev) => ({ ...prev, [provider]: true })); setValidated((prev) => ({ ...prev, [provider]: false })); setValidationMessages((prev) => ({ ...prev, [provider]: null })); setIsUnverifiedDueToCors((prev) => ({ ...prev, [provider]: false })); const result = await validateApiKey(provider, key); if (result.isValid) { handleSave(provider, key); setValidated((prev) => ({ ...prev, [provider]: true })); } else if (result.isCorsError) { handleSave(provider, key); // Save the key // validated remains false setIsUnverifiedDueToCors((prev) => ({ ...prev, [provider]: true })); // Set CORS flag setValidationMessages((prev) => ({ ...prev, [provider]: result.message, })); } else { setValidated((prev) => ({ ...prev, [provider]: false })); setValidationMessages((prev) => ({ ...prev, [provider]: result.message || "Invalid API key.", })); } setValidating((prev) => ({ ...prev, [provider]: false })); }, [handleSave]); const hasAnyKey = initialProviders.some((provider) => Boolean(manager.getKey(provider))); return { keys, saved, validating, validated, validationMessages, isUnverifiedDueToCors, isLoading, handleKeyChange, handleClear, handleClearAll, handleValidate, hasAnyKey, providerNames, }; }