UNPKG

recoder-shared

Version:

Shared types, utilities, and configurations for Recoder

515 lines (441 loc) 12.9 kB
/** * Recoder.xyz Unified SDK * Cross-platform SDK for all Recoder platforms */ import { EventEmitter } from 'events'; import { AuthClient } from './auth-client'; import { WebSocketClient } from './websocket-client'; import { SyncClient } from './sync-client'; import { AIClient } from './ai-client'; import axios, { AxiosInstance } from 'axios'; export interface RecoderSDKConfig { baseURL?: string; webSocketURL?: string; platform: 'cli' | 'web' | 'mobile' | 'extension' | 'desktop'; deviceName?: string; enableWebSocket?: boolean; enableAutoSync?: boolean; apiKey?: string; debug?: boolean; } export interface AIProvider { name: string; status: 'healthy' | 'degraded' | 'offline' | 'error'; responseTime?: number; errorRate?: number; uptime?: number; } export interface AIProviderRecommendation { taskType: string; recommended: { provider: string; name: string; reason: string; status: string; }; fallbacks: Array<{ provider: string; name: string; status: string; }>; } export interface AnalyticsData { eventType: 'api_call' | 'code_generation' | 'authentication' | 'sync' | 'ai_request'; provider?: string; tokens?: number; cost?: number; duration?: number; success?: boolean; metadata?: any; } export class RecoderSDK extends EventEmitter { private config: Required<RecoderSDKConfig>; private api: AxiosInstance; public auth: AuthClient; public websocket?: WebSocketClient; public sync?: SyncClient; public ai: AIClient; constructor(config: RecoderSDKConfig) { super(); this.config = { baseURL: config.baseURL || 'http://localhost:3001', webSocketURL: config.webSocketURL || 'http://localhost:3001', platform: config.platform, deviceName: config.deviceName || `${config.platform}-${Date.now()}`, enableWebSocket: config.enableWebSocket ?? true, enableAutoSync: config.enableAutoSync ?? true, apiKey: config.apiKey || '', debug: config.debug || false }; // Initialize API client this.api = axios.create({ baseURL: `${this.config.baseURL}/api`, timeout: 10000, headers: { 'User-Agent': `Recoder-${config.platform}/${this.getVersion()}` } }); // Initialize auth client this.auth = new AuthClient(this.config.baseURL); // Initialize AI client this.ai = new AIClient(this.auth, { platform: this.config.platform, baseURL: this.config.baseURL, routingStrategy: 'balanced' }); // Setup API interceptors this.setupAPIInterceptors(); // Initialize other clients this.initializeClients(); // Setup event forwarding this.setupEventForwarding(); if (this.config.debug) { console.log('Recoder SDK initialized for platform:', this.config.platform); } } private setupAPIInterceptors(): void { this.api.interceptors.request.use((config) => { const tokens = this.auth.getTokens(); if (tokens?.accessToken) { config.headers.Authorization = `Bearer ${tokens.accessToken}`; } return config; }); this.api.interceptors.response.use( (response) => response, (error) => { if (this.config.debug) { console.error('API Error:', error.response?.data || error.message); } return Promise.reject(error); } ); } private initializeClients(): void { // Initialize WebSocket client if (this.config.enableWebSocket) { this.websocket = new WebSocketClient({ url: this.config.webSocketURL, authClient: this.auth, platform: this.config.platform }); } // Initialize sync client this.sync = new SyncClient({ authClient: this.auth, webSocketClient: this.websocket, baseURL: this.config.baseURL, enableRealTimeSync: this.config.enableWebSocket }); } private setupEventForwarding(): void { // Forward auth events this.auth.on('authenticated', (data) => { this.emit('authenticated', data); this.onAuthenticated(); }); this.auth.on('logout', () => { this.emit('logout'); this.onLogout(); }); // Forward WebSocket events if (this.websocket) { this.websocket.on('connected', () => { this.emit('websocketConnected'); }); this.websocket.on('disconnected', () => { this.emit('websocketDisconnected'); }); this.websocket.on('notificationReceived', (notification) => { this.emit('notification', notification); }); this.websocket.on('syncUpdated', (data) => { this.emit('syncUpdate', data); }); } // Forward sync events if (this.sync) { this.sync.on('syncCompleted', (data) => { this.emit('syncCompleted', data); }); this.sync.on('syncError', (data) => { this.emit('syncError', data); }); } // Forward AI events this.ai.on('requestStarted', (data) => { this.emit('aiRequestStarted', data); }); this.ai.on('responseReceived', (data) => { this.emit('aiResponseReceived', data); }); this.ai.on('requestFailed', (data) => { this.emit('aiRequestFailed', data); }); this.ai.on('providerError', (data) => { this.emit('aiProviderError', data); }); } private async onAuthenticated(): Promise<void> { try { // Register device await this.auth.registerDevice({ name: this.config.deviceName, deviceType: this.config.platform, platform: this.getPlatformDetails() }); // Connect WebSocket if (this.websocket) { await this.websocket.connect(); } // Start auto sync if (this.sync && this.config.enableAutoSync) { await this.sync.startAutoSync(); } this.emit('ready'); if (this.config.debug) { console.log('Recoder SDK ready for platform:', this.config.platform); } } catch (error) { console.error('SDK initialization after auth failed:', error); this.emit('initError', error); } } private onLogout(): void { // Disconnect WebSocket if (this.websocket) { this.websocket.disconnect(); } // Stop auto sync if (this.sync) { this.sync.stopAutoSync(); } } // Public API Methods async initialize(): Promise<void> { if (this.auth.isAuthenticated()) { await this.onAuthenticated(); } } async connect(): Promise<void> { if (this.websocket && !this.websocket.connected) { await this.websocket.connect(); } } disconnect(): void { if (this.websocket) { this.websocket.disconnect(); } } // AI Provider Methods async getAIProviderStatus(): Promise<AIProvider[]> { try { const response = await this.api.get('/ai-providers/status'); return response.data.data; } catch (error: any) { throw this.handleError(error); } } async healthCheckAIProviders(): Promise<{ providers: any; overall: any }> { try { const response = await this.api.post('/ai-providers/health-check'); return response.data.data; } catch (error: any) { throw this.handleError(error); } } async getAIProviderRecommendation( taskType: 'coding' | 'blockchain' | 'security' | 'analysis' | 'chat' | 'generation', priority: 'speed' | 'cost' | 'quality' = 'quality' ): Promise<AIProviderRecommendation> { try { const response = await this.api.post('/ai-providers/recommend', { taskType, priority }); return response.data.data; } catch (error: any) { throw this.handleError(error); } } async getAIProviderCosts(timeframe: 'hour' | 'day' | 'week' | 'month' = 'day'): Promise<any> { try { const response = await this.api.get('/ai-providers/costs', { params: { timeframe } }); return response.data.data; } catch (error: any) { throw this.handleError(error); } } // Analytics Methods async trackAnalytics(data: AnalyticsData): Promise<void> { try { await this.api.post('/analytics/track', { ...data, platform: this.config.platform }); } catch (error: any) { if (this.config.debug) { console.error('Analytics tracking failed:', error); } // Don't throw - analytics failures shouldn't break the app } } async getAnalyticsDashboard( timeframe: 'hour' | 'day' | 'week' | 'month' = 'day' ): Promise<any> { try { const response = await this.api.get('/analytics/dashboard', { params: { timeframe, platform: this.config.platform } }); return response.data.data; } catch (error: any) { throw this.handleError(error); } } async getPerformanceMetrics(): Promise<any> { try { const response = await this.api.get('/analytics/performance'); return response.data.data; } catch (error: any) { throw this.handleError(error); } } async getRealTimeAnalytics(): Promise<any> { try { const response = await this.api.get('/analytics/realtime'); return response.data.data; } catch (error: any) { throw this.handleError(error); } } // Notification Methods async sendNotification( type: 'info' | 'success' | 'warning' | 'error' | 'system', title: string, message: string, data?: any ): Promise<void> { try { await this.api.post('/notifications/send', { type, title, message, data }); } catch (error: any) { throw this.handleError(error); } } async broadcastNotification( channel: string, event: string, type: 'info' | 'success' | 'warning' | 'error' | 'system', title: string, message: string, data?: any ): Promise<void> { try { await this.api.post('/notifications/broadcast', { channel, event, type, title, message, data }); } catch (error: any) { throw this.handleError(error); } } // Utility Methods isReady(): boolean { return this.auth.isAuthenticated() && (!this.config.enableWebSocket || this.websocket?.connected || false); } getStatus(): any { return { authenticated: this.auth.isAuthenticated(), websocketConnected: this.websocket?.connected || false, autoSyncEnabled: this.sync?.autoSyncEnabled || false, platform: this.config.platform, user: this.auth.getUser(), device: this.auth.getDeviceInfo(), ai: this.ai.getStatus() }; } // Platform Integration Helpers async switchToPlatform(targetPlatform: string, context?: any): Promise<void> { if (this.websocket) { await this.websocket.notifyPlatformSwitch( this.config.platform, targetPlatform, context ); } } async startCollaboration(projectId: string): Promise<void> { if (this.websocket) { await this.websocket.joinCollaboration(projectId); } } async stopCollaboration(projectId: string): Promise<void> { if (this.websocket) { await this.websocket.leaveCollaboration(projectId); } } // Private helpers private getVersion(): string { return '2.0.0'; // SDK version } private getPlatformDetails(): string { if (typeof window !== 'undefined' && window && typeof navigator !== 'undefined' && navigator) { return navigator.userAgent; } else if (typeof process !== 'undefined' && process) { return `${process.platform} ${process.arch}`; } return 'unknown'; } private handleError(error: any): Error { const message = error.response?.data?.error?.message || error.message || 'SDK operation failed'; return new Error(message); } } // Convenience factory functions for different platforms export function createWebSDK(config: Partial<RecoderSDKConfig> = {}): RecoderSDK { return new RecoderSDK({ platform: 'web', deviceName: 'Web Browser', ...config }); } export function createCLISDK(config: Partial<RecoderSDKConfig> = {}): RecoderSDK { return new RecoderSDK({ platform: 'cli', deviceName: `CLI - ${require('os').hostname()}`, ...config }); } export function createMobileSDK(config: Partial<RecoderSDKConfig> = {}): RecoderSDK { return new RecoderSDK({ platform: 'mobile', deviceName: 'Mobile Device', ...config }); } export function createDesktopSDK(config: Partial<RecoderSDKConfig> = {}): RecoderSDK { return new RecoderSDK({ platform: 'desktop', deviceName: 'Desktop App', ...config }); } export function createExtensionSDK(config: Partial<RecoderSDKConfig> = {}): RecoderSDK { return new RecoderSDK({ platform: 'extension', deviceName: 'VS Code Extension', ...config }); } export default RecoderSDK;