mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-29 22:23:01 +00:00
* feat: add mnemonic recovery flow and encryption key management - Introduced a new Mnemonic page for users to generate or import their recovery phrase. - Updated routing to redirect users to the Mnemonic page after onboarding. - Enhanced state management to store and retrieve AES encryption keys derived from the mnemonic. - Added utility functions for generating and validating BIP39 mnemonic phrases. - Updated selectors and reducers to handle encryption key state in the auth slice. - Included new dependencies for cryptographic operations. * feat: integrate Web3 wallet functionality and enhance state management - Added WalletInfoSection component to display connected wallet address, network, and balance. - Updated auth slice to manage primary wallet address derived from mnemonic. - Enhanced SkillManager to pass wallet address as load parameters for wallet skill. - Introduced utility function to derive EVM wallet address from mnemonic. - Updated dependencies for cryptographic operations related to wallet functionality. * fix: improve error handling and network selection in WalletInfoSection - Enhanced the parsing of network data to ensure robustness against undefined values. - Updated network selection logic to prioritize valid entries and provide a fallback. - Improved error logging for better debugging of wallet information loading issues. - Adjusted balance retrieval to handle cases where chain_id may be missing. * feat: add socket event contract for Tauri integration - Documented the socket event contract for communication between the backend and frontend in Tauri mode. - Introduced constants for `REQUEST_ENCRYPTION_KEY` and `ENCRYPTION_KEY_EVENT` to facilitate encryption key management. - Updated `setupTauriSocketListeners` to handle the encryption key request and response flow. * Refactor wallet information fetching and connection status handling - Updated `WalletInfoSection` to improve loading state management and error handling during wallet info retrieval. - Introduced a retry mechanism for fetching wallet information with a maximum of 5 attempts. - Enhanced connection status logic in `SkillsGrid` to treat missing authentication status as connected. - Added a new method in `SkillManager` to set the wallet address and notify the wallet skill accordingly. * feat: add integration token fetching and decryption functionality - Introduced `fetchIntegrationTokens` API call to retrieve encrypted OAuth tokens for integrations. - Implemented decryption logic for integration tokens using a provided key. - Enhanced deep link handling to support fetching and storing integration tokens upon successful OAuth login. - Added utility functions for hex and base64 conversions to facilitate token decryption. - Updated `authApi.ts` and `desktopDeepLinkListener.ts` to integrate new functionality. * refactor: move integration token encryption/decryption logic to a new utility file - Extracted encryption and decryption functions for integration tokens into `integrationTokensCrypto.ts`. - Removed redundant functions from `desktopDeepLinkListener.ts` to streamline the code. - Updated deep link handling to store only the encrypted tokens instead of decrypted ones. - Improved type definitions for integration tokens and their payloads. * feat: enhance Gmail skill integration and state management - Updated `SkillManager` to accept an optional access token for Gmail during OAuth completion. - Introduced `gmailSlice` to manage Gmail user profile and emails in the Redux store. - Implemented synchronization of Gmail skill state with the Redux store to keep user data updated. - Refactored `SkillProvider` to handle Gmail state changes and fetch initial state from the backend. - Adjusted deep link handling to pass decrypted access tokens for Gmail integration. - Modified API endpoint for onboarding completion to remove the Telegram prefix. * feat: implement Gmail metadata synchronization to backend - Added a new utility function `syncGmailMetadataToBackend` to emit Gmail profile and email summaries to the backend via the `integration:metadata-sync` socket event. - Updated `SkillProvider` to call the new synchronization function, ensuring Gmail skill state is sent to the backend when updated. * refactor: update Tauri socket event handling and improve Mnemonic component typing - Revised the Tauri socket event contract to clarify that encryption key handling is managed via the API instead of the socket. - Removed outdated socket event constants related to encryption key requests from `tauriSocket.ts`. - Enhanced type definitions in the `Mnemonic` component by specifying the event type for keyboard events. * fix: update Gmail provider constant and adjust metadata synchronization logic - Changed the constant for the Google provider from 'google' to 'gmail' for clarity. - Commented out the email metadata synchronization logic in `syncGmailMetadataToBackend` to prevent potential issues with undefined email states. * feat: implement Gmail metadata synchronization service - Added a new file `metadataSync.ts` to handle the synchronization of Gmail profile and email summaries to the backend via the `integration:metadata-sync` socket event. - Updated import paths in `SkillProvider` to reflect the new location of the Gmail metadata synchronization function. - Enhanced type definitions for Gmail profile and email summaries to ensure proper data structure during synchronization. * refactor: clean up code formatting and improve readability across multiple components - Standardized import statements and formatting in various files, including `WalletInfoSection`, `AgentChatPanel`, and `SkillsPanel`. - Enhanced readability by adjusting line breaks and spacing in JSX elements and function definitions. - Improved consistency in the use of arrow functions and destructuring across components. - Updated type definitions and ensured proper alignment of code for better maintainability. * feat: enhance error handling in WalletInfoSection and improve user feedback - Added error reporting functionality in `WalletInfoSection` to capture and enqueue errors when wallet info fails to load. - Updated `Mnemonic` component to handle user state more robustly, ensuring encryption key is only set if the user is loaded. - Refactored `TauriCommandsPanel` to improve string comparisons for loading states by converting to lowercase. - Adjusted deep link handling in `desktopDeepLinkListener` to use trimmed hex values for encryption key conversion. * fix: improve balance parsing and error handling in WalletInfoSection - Updated balance parsing logic in `WalletInfoSection` to ensure that non-finite values default to zero. - Enhanced error handling in `desktopDeepLinkListener` by adding error reporting for invalid encryption keys and conversion failures, improving user feedback and debugging capabilities. * Merge remote-tracking branch 'upstream/develop' into feat/final-flow-check * chore: update submodule URL for skills repository to use HTTPS * chore: update skills submodule to latest commit and enhance SkillsGrid component - Updated the skills submodule to the latest commit for improved functionality. - Refactored `SkillsGrid` to better handle skill setup logic, ensuring accurate representation of skills with setup requirements. - Cleaned up code formatting and improved readability in various components, including `SkillActionButton` and `desktopDeepLinkListener`. * feat: implement Notion metadata synchronization and user profile management - Added a new service `metadataSync.ts` to handle synchronization of Notion user metadata to the backend via the `integration:metadata-sync` socket event. - Introduced a new Redux slice `notionSlice.ts` for managing the Notion user profile state. - Updated `SkillProvider` to fetch and sync Notion user profile upon connection, ensuring seamless integration with the backend. - Enhanced the store configuration to include the new Notion reducer. * refactor: remove unnecessary console warnings in SkillProvider - Eliminated console warnings related to Notion user retrieval errors and auto-loading skills, streamlining the logging process for better clarity and reducing noise in the console output. - Improved code readability by cleaning up commented-out warning messages that were no longer needed.
7.2 KiB
7.2 KiB
Services Layer
The application uses singleton services for external communication. This prevents connection leaks and provides consistent API access.
Service Architecture
Services Layer
├─ apiClient (HTTP REST)
│ ├─ reads auth.token from Redux
│ └─ makes requests to BACKEND_URL
├─ socketService (Socket.io)
│ ├─ manages real-time connection
│ └─ emits/listens for MCP messages
└─ mtprotoService (Telegram)
├─ manages TelegramClient
└─ stores session in Redux
API Client (services/apiClient.ts)
HTTP REST client for backend communication.
Features
- Fetch-based implementation
- Auto-injects JWT from Redux store
- Typed request/response handling
- Error handling with typed errors
Usage
import apiClient from '../services/apiClient';
// GET request
const user = await apiClient.get<User>('/users/me');
// POST request
const result = await apiClient.post<LoginResponse>('/auth/login', { email, password });
// With custom headers
const data = await apiClient.get<Data>('/endpoint', { headers: { 'X-Custom': 'value' } });
Configuration
Reads VITE_BACKEND_URL from environment or uses default:
const BACKEND_URL = import.meta.env.VITE_BACKEND_URL || 'https://api.example.com';
API Endpoints (services/api/)
Auth API (services/api/authApi.ts)
Authentication-related endpoints.
import { authApi } from '../services/api/authApi';
// Login
const { token, user } = await authApi.login(credentials);
// Token exchange (for deep link flow)
const { sessionToken, user } = await authApi.exchangeToken(loginToken);
// Logout
await authApi.logout();
User API (services/api/userApi.ts)
User profile endpoints.
import { userApi } from '../services/api/userApi';
// Get current user
const user = await userApi.getCurrentUser();
// Update profile
const updated = await userApi.updateProfile({ firstName, lastName });
// Get settings
const settings = await userApi.getSettings();
Socket Service (services/socketService.ts)
Socket.io client singleton for real-time communication.
Features
- Singleton pattern - single connection per app
- Auth token passed in socket
authobject - Transports: polling first, then WebSocket upgrade
- Auto-reconnection handling
API
import socketService from '../services/socketService';
// Connect with auth token
socketService.connect(token);
// Disconnect
socketService.disconnect();
// Emit event
socketService.emit('event-name', data);
// Listen for events
socketService.on('event-name', data => {
// Handle event
});
// Remove listener
socketService.off('event-name', handler);
// One-time listener
socketService.once('event-name', data => {
// Handle once
});
// Get socket instance
const socket = socketService.getSocket();
// Check connection status
const isConnected = socketService.isConnected();
Connection Flow
// In SocketProvider.tsx
useEffect(() => {
if (token) {
socketService.connect(token);
socketService.on('connect', () => {
dispatch(setSocketStatus({ userId, status: 'connected' }));
dispatch(setSocketId({ userId, socketId: socket.id }));
// Initialize MCP server
initMCPServer(socketService.getSocket());
});
socketService.on('disconnect', () => {
dispatch(setSocketStatus({ userId, status: 'disconnected' }));
});
}
return () => {
socketService.disconnect();
};
}, [token]);
Configuration
const socket = io(BACKEND_URL, {
auth: { token },
transports: ['polling', 'websocket'],
reconnection: true,
reconnectionAttempts: 5,
reconnectionDelay: 1000,
});
Socket event contract (Tauri)
In Tauri mode, the Rust socket forwards server events to the frontend via the server:event Tauri event. The frontend listens and can emit back via emitViaRustSocket (see utils/tauriSocket.ts). Encryption key is handled via the API, not the socket.
MTProto Service (services/mtprotoService.ts)
Telegram MTProto client singleton.
Features
- Singleton pattern - one client per user
- Session persistence via Redux (not localStorage)
- Auto-retry for FLOOD_WAIT up to 60s
- Supports QR login and phone auth
Initialization
import mtprotoService from '../services/mtprotoService';
// Get or create instance for user
const client = await mtprotoService.getInstance().initialize(userId);
// Set session string (from Redux)
await client.setSession(sessionString);
// Connect to Telegram
await client.connect();
Session Management
// Session is stored in Redux, not localStorage
// In TelegramProvider:
const sessionString = useAppSelector(state => state.telegram.byUser[userId]?.sessionString);
// When session updates
useEffect(() => {
if (client && sessionString) {
client.setSession(sessionString);
}
}, [sessionString]);
// Save session after auth
const newSession = await client.getSession();
dispatch(setSessionString({ userId, sessionString: newSession }));
API Operations
// Get current user
const me = await client.getMe();
// Get dialogs (chats)
const dialogs = await client.getDialogs({ limit: 20 });
// Send message
await client.sendMessage(peer, { message: 'Hello!' });
// Get history
const messages = await client.getMessages(peer, { limit: 50 });
Error Handling
try {
await client.connect();
} catch (error) {
if (error.message.includes('FLOOD_WAIT')) {
const seconds = parseInt(error.message.match(/\d+/)?.[0] || '60');
if (seconds <= 60) {
// Auto-retry after wait
await new Promise(r => setTimeout(r, seconds * 1000));
await client.connect();
}
}
throw error;
}
Service Integration with Providers
SocketProvider
// providers/SocketProvider.tsx
export function SocketProvider({ children }) {
const token = useAppSelector((state) => state.auth.token);
useEffect(() => {
if (token) {
socketService.connect(token);
// On connect, initialize MCP
}
return () => socketService.disconnect();
}, [token]);
return <SocketContext.Provider value={...}>{children}</SocketContext.Provider>;
}
TelegramProvider
// providers/TelegramProvider.tsx
export function TelegramProvider({ children }) {
const dispatch = useAppDispatch();
const userId = useAppSelector((state) => state.user.profile?.id);
useEffect(() => {
if (userId) {
// Parallel init + connect for faster startup
Promise.all([
dispatch(initializeTelegram(userId)),
dispatch(connectTelegram(userId))
]);
}
}, [userId]);
return <TelegramContext.Provider value={...}>{children}</TelegramContext.Provider>;
}
Best Practices
- Use singletons - Never create multiple service instances
- Store sessions in Redux - Not localStorage
- Clean up on unmount - Disconnect in useEffect cleanup
- Handle errors gracefully - Retry for transient failures
- Pass auth via proper channels - Socket auth object, not query string
Previous: State Management | Next: MCP System