UNPKG

@jeanmemory/react

Version:

React SDK for Jean Memory - Build personalized AI chatbots in 5 lines of code

152 lines (151 loc) 5.37 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.JeanProvider = JeanProvider; exports.useJean = useJean; const jsx_runtime_1 = require("react/jsx-runtime"); /** * Jean Memory React SDK v2.0 - Provider Component * Secure OAuth 2.1 PKCE with JWT-in-header authentication */ const react_1 = require("react"); const config_1 = require("./config"); const oauth_1 = require("./oauth"); const JeanContext = (0, react_1.createContext)(null); function JeanProvider({ apiKey, children }) { const [user, setUserState] = (0, react_1.useState)(null); const [messages, setMessages] = (0, react_1.useState)([]); const [isLoading, setIsLoading] = (0, react_1.useState)(false); const [error, setError] = (0, react_1.useState)(null); // Initialize authentication state from stored session (0, react_1.useEffect)(() => { const storedUser = (0, oauth_1.getUserSession)(); if (storedUser && (0, oauth_1.isAuthenticated)()) { setUserState(storedUser); } }, []); const setUser = (newUser) => { setUserState(newUser); setError(null); }; const sendMessage = async (message, options) => { if (!user) { throw new Error('User must be authenticated to send messages'); } setIsLoading(true); setError(null); try { // SECURE: JWT token in Authorization header, API key in X-API-Key header const response = await fetch(`${config_1.JEAN_API_BASE}/api/jean-chat`, { method: 'POST', headers: { 'Authorization': `Bearer ${user.access_token}`, // User identity (JWT) 'X-API-Key': apiKey, // App authentication 'Content-Type': 'application/json' }, body: JSON.stringify({ message, format: options?.format || 'enhanced' }) }); if (!response.ok) { const errorData = await response.text(); throw new Error(`Request failed: ${response.status} - ${errorData}`); } const data = await response.json(); // Add messages to conversation const userMessage = { id: `user-${Date.now()}`, role: 'user', content: message, timestamp: new Date() }; const assistantMessage = { id: `assistant-${Date.now()}`, role: 'assistant', content: data.content || data.context || 'No response received', timestamp: new Date() }; setMessages(prev => [...prev, userMessage, assistantMessage]); return assistantMessage.content; } catch (err) { const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred'; setError(errorMessage); throw err; } finally { setIsLoading(false); } }; const addMemory = async (content) => { if (!user) { throw new Error('User must be authenticated to add memories'); } const response = await fetch(`${config_1.JEAN_API_BASE}/mcp/tools/call`, { method: 'POST', headers: { 'Authorization': `Bearer ${user.access_token}`, 'X-API-Key': apiKey, 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'add_memory', arguments: { content } }) }); if (!response.ok) { throw new Error(`Failed to add memory: ${response.status}`); } return response.json(); }; const searchMemory = async (query) => { if (!user) { throw new Error('User must be authenticated to search memories'); } const response = await fetch(`${config_1.JEAN_API_BASE}/mcp/tools/call`, { method: 'POST', headers: { 'Authorization': `Bearer ${user.access_token}`, 'X-API-Key': apiKey, 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'search_memory', arguments: { query } }) }); if (!response.ok) { throw new Error(`Failed to search memory: ${response.status}`); } return response.json(); }; const clearConversation = () => { setMessages([]); setError(null); }; const contextValue = { // Authentication state isAuthenticated: !!user && (0, oauth_1.isAuthenticated)(), isLoading, user, error, // Messaging messages, sendMessage, clearConversation, // Memory management addMemory, searchMemory, // Internal setUser, apiKey }; return ((0, jsx_runtime_1.jsx)(JeanContext.Provider, { value: contextValue, children: children })); } function useJean() { const context = (0, react_1.useContext)(JeanContext); if (!context) { throw new Error('useJean must be used within a JeanProvider'); } return context; }