UNPKG

@agentdao/core

Version:

Core functionality, skills, and ready-made UI components for AgentDAO - Web3 subscriptions, content generation, social media, help support, live chat, RSS fetching, web search, and agent pricing integration

294 lines (293 loc) 9.76 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.trackMonetization = exports.trackPerformance = exports.trackError = exports.trackApiCall = exports.trackSkillUsage = exports.trackEvent = exports.AnalyticsService = void 0; const apiClient_1 = require("./apiClient"); class AnalyticsService { constructor(config) { this.eventQueue = []; this.processingQueue = false; this.rateLimitMap = new Map(); this.config = { batchSize: 10, flushInterval: 30000, // 30 seconds rateLimit: 10, // 10 events per minute ...config, enabled: config.enabled !== false // Default to true unless explicitly disabled }; // Initialize client with default values (will be overridden if endpoint is provided) this.client = new apiClient_1.AgentBridgeClient('https://developers.agentdao.com', config.apiKey); // Auto-flush events periodically if (this.config.enabled) { setInterval(() => this.flushQueue(), this.config.flushInterval); } } static getInstance(config) { if (!AnalyticsService.instance) { AnalyticsService.instance = new AnalyticsService(config || { enabled: true }); } return AnalyticsService.instance; } /** * Track an important event */ async trackEvent(event) { if (!this.config.enabled) return; // Only track important events to prevent bloat if (!AnalyticsService.IMPORTANT_EVENTS.has(event.event_name)) { return; } // Rate limiting const userKey = event.user_id || event.agent_id || 'anonymous'; if (this.isRateLimited(userKey)) { return; } // Add timestamp if not provided if (!event.timestamp) { event.timestamp = new Date().toISOString(); } // Add to queue for batch processing this.eventQueue.push(event); // Flush immediately if queue is getting large if (this.eventQueue.length >= this.config.batchSize) { this.flushQueue(); } } /** * Track skill usage */ async trackSkillUsage(skillName, agentId, metadata) { await this.trackEvent({ event_type: 'skill_usage', event_name: 'skill_used', skill_name: skillName, agent_id: agentId, metadata: { skill_name: skillName, ...metadata } }); } /** * Track API calls */ async trackApiCall(endpoint, success, duration, metadata) { await this.trackEvent({ event_type: 'api_call', event_name: 'api_request', metadata: { endpoint, success, duration, ...metadata } }); } /** * Track errors */ async trackError(error, context, agentId, metadata) { await this.trackEvent({ event_type: 'error', event_name: 'error_occurred', agent_id: agentId, metadata: { error_message: error.message, error_stack: error.stack, context, ...metadata } }); } /** * Track performance metrics */ async trackPerformance(metric, value, unit, metadata) { await this.trackEvent({ event_type: 'performance', event_name: 'performance_metric', metadata: { metric, value, unit, ...metadata } }); } /** * Track monetization events */ async trackMonetization(event, amount, currency, metadata) { await this.trackEvent({ event_type: 'monetization', event_name: event, metadata: { amount, currency, ...metadata } }); } /** * Check rate limiting */ isRateLimited(userKey) { const now = Date.now(); const userLimit = this.rateLimitMap.get(userKey); if (!userLimit || now > userLimit.resetTime) { this.rateLimitMap.set(userKey, { count: 1, resetTime: now + 60000 // 1 minute }); return false; } if (userLimit.count >= this.config.rateLimit) { return true; } userLimit.count++; return false; } /** * Batch process queued events */ async flushQueue() { if (this.processingQueue || this.eventQueue.length === 0) { return; } this.processingQueue = true; const eventsToProcess = this.eventQueue.splice(0, this.config.batchSize); try { // Send events to AgentDAO platform if (this.config.endpoint) { await this.sendToEndpoint(eventsToProcess); } else { // Use AgentBridge client to send to platform await this.sendViaAgentBridge(eventsToProcess); } } catch (error) { console.warn('Failed to flush analytics queue:', error); // Put events back in queue for retry (but limit retries) if (this.eventQueue.length < 100) { this.eventQueue.unshift(...eventsToProcess); } } finally { this.processingQueue = false; } } /** * Send events to custom endpoint */ async sendToEndpoint(events) { if (!this.config.endpoint) return; const response = await fetch(this.config.endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', ...(this.config.apiKey && { 'Authorization': `Bearer ${this.config.apiKey}` }) }, body: JSON.stringify({ events }) }); if (!response.ok) { throw new Error(`Analytics endpoint failed: ${response.status}`); } } /** * Send events via AgentBridge */ async sendViaAgentBridge(events) { try { // Send events to AgentDAO platform via AgentBridge const response = await fetch(`${this.client['baseUrl']}/api/analytics/batch`, { method: 'POST', headers: { 'Content-Type': 'application/json', ...(this.client['token'] && { 'Authorization': `Bearer ${this.client['token']}` }) }, body: JSON.stringify({ events }) }); if (!response.ok) { throw new Error(`Analytics endpoint failed: ${response.status}`); } } catch (error) { // Fallback to console logging in development if (process.env.NODE_ENV === 'development') { console.log('Analytics events (development):', events); } throw error; } } /** * Get analytics summary */ async getAnalyticsSummary(timeRange = '30d') { try { const response = await fetch(`${this.client['baseUrl']}/api/analytics/summary?timeRange=${timeRange}`, { headers: { ...(this.client['token'] && { 'Authorization': `Bearer ${this.client['token']}` }) } }); if (!response.ok) { throw new Error(`Analytics summary failed: ${response.status}`); } return await response.json(); } catch (error) { console.warn('Failed to get analytics summary:', error); return null; } } /** * Enable/disable analytics */ setEnabled(enabled) { this.config.enabled = enabled; } /** * Update configuration */ updateConfig(newConfig) { this.config = { ...this.config, ...newConfig }; } /** * Get current queue size */ getQueueSize() { return this.eventQueue.length; } /** * Force flush queue */ async forceFlush() { await this.flushQueue(); } } exports.AnalyticsService = AnalyticsService; // Important events that should be tracked AnalyticsService.IMPORTANT_EVENTS = new Set([ 'agent_created', 'agent_deployed', 'skill_used', 'api_call', 'error_occurred', 'user_action', 'performance_metric', 'monetization_event' ]); // Export convenience functions const trackEvent = (event) => AnalyticsService.getInstance().trackEvent(event); exports.trackEvent = trackEvent; const trackSkillUsage = (skillName, agentId, metadata) => AnalyticsService.getInstance().trackSkillUsage(skillName, agentId, metadata); exports.trackSkillUsage = trackSkillUsage; const trackApiCall = (endpoint, success, duration, metadata) => AnalyticsService.getInstance().trackApiCall(endpoint, success, duration, metadata); exports.trackApiCall = trackApiCall; const trackError = (error, context, agentId, metadata) => AnalyticsService.getInstance().trackError(error, context, agentId, metadata); exports.trackError = trackError; const trackPerformance = (metric, value, unit, metadata) => AnalyticsService.getInstance().trackPerformance(metric, value, unit, metadata); exports.trackPerformance = trackPerformance; const trackMonetization = (event, amount, currency, metadata) => AnalyticsService.getInstance().trackMonetization(event, amount, currency, metadata); exports.trackMonetization = trackMonetization;