UNPKG

anon-identity

Version:

Decentralized identity framework with DIDs, Verifiable Credentials, and privacy-preserving selective disclosure

244 lines 8.43 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ActivitySearchService = void 0; class ActivitySearchService { constructor(index, ipfsStorage, config = {}) { this.resultCache = new Map(); this.index = index; this.ipfsStorage = ipfsStorage; this.config = { enableIPFSFallback: true, cacheResults: true, maxCacheSize: 1000, cacheTTL: 5 * 60 * 1000, // 5 minutes ...config }; } /** * Search activities with advanced querying capabilities */ async searchActivities(query) { // Check cache first if (this.config.cacheResults) { const cached = this.getCachedResult(query); if (cached) { return cached.result; } } try { // Primary search through index const indexResult = await this.index.search(query); // If we have IPFS storage and results seem incomplete, try IPFS fallback if (this.config.enableIPFSFallback && this.ipfsStorage && this.shouldTryIPFSFallback(query, indexResult)) { const enhancedResult = await this.enhanceWithIPFS(indexResult, query); // Cache the result if (this.config.cacheResults) { this.cacheResult(query, enhancedResult); } return enhancedResult; } // Cache the result if (this.config.cacheResults) { this.cacheResult(query, indexResult); } return indexResult; } catch (error) { console.error('Search failed:', error); throw new Error(`Activity search failed: ${error}`); } } /** * Get activity summary with aggregated statistics */ async getActivitySummary(agentDID, period, startDate) { return this.index.getActivitySummary(agentDID, period, startDate); } /** * Get recent activities for an agent */ async getRecentActivities(agentDID, limit = 50) { const query = { agentDID, limit, sortBy: 'timestamp', sortOrder: 'desc' }; const result = await this.searchActivities(query); return result.activities; } /** * Get activities by session ID */ async getSessionActivities(sessionId) { const query = { sessionId, sortBy: 'timestamp', sortOrder: 'asc' }; const result = await this.searchActivities(query); return result.activities; } /** * Search activities by text content (searches in activity details) */ async searchByText(searchText, agentDID, limit = 100) { // This is a basic implementation - in production you might want to use // a full-text search engine like Elasticsearch const query = { agentDID, limit: 1000, // Get more results to filter sortBy: 'timestamp', sortOrder: 'desc' }; const result = await this.searchActivities(query); // Filter by text content const filtered = result.activities.filter(activity => { const searchableText = JSON.stringify(activity.details).toLowerCase(); return searchableText.includes(searchText.toLowerCase()); }); return filtered.slice(0, limit); } /** * Get activity trends over time */ async getActivityTrends(agentDID, days = 30) { const endDate = new Date(); const startDate = new Date(); startDate.setDate(startDate.getDate() - days); const query = { agentDID, dateRange: { start: startDate, end: endDate }, sortBy: 'timestamp', sortOrder: 'asc', limit: 10000 // Get all activities in range }; const result = await this.searchActivities(query); // Group by day const trends = new Map(); result.activities.forEach(activity => { const dateKey = activity.timestamp.toISOString().split('T')[0]; if (!trends.has(dateKey)) { trends.set(dateKey, { count: 0, byType: {}, errors: 0 }); } const trend = trends.get(dateKey); trend.count++; trend.byType[activity.type] = (trend.byType[activity.type] || 0) + 1; if (activity.status === 'failed' || activity.status === 'denied') { trend.errors++; } }); // Convert to array with error rates return Array.from(trends.entries()).map(([date, data]) => ({ date, count: data.count, byType: data.byType, errorRate: data.count > 0 ? data.errors / data.count : 0 })); } /** * Get comparative statistics between agents */ async compareAgents(agentDIDs, period = 'week') { const summaries = {}; for (const agentDID of agentDIDs) { try { summaries[agentDID] = await this.getActivitySummary(agentDID, period); } catch (error) { console.warn(`Failed to get summary for agent ${agentDID}:`, error); } } return summaries; } /** * Clear the search cache */ clearCache() { this.resultCache.clear(); } /** * Get cache statistics */ getCacheStats() { // This is a simplified implementation return { size: this.resultCache.size, maxSize: this.config.maxCacheSize || 1000, hitRate: 0 // Would need to track hits/misses }; } // Private helper methods getCachedResult(query) { if (!this.config.cacheResults) { return null; } const queryHash = this.hashQuery(query); const cached = this.resultCache.get(queryHash); if (!cached) { return null; } // Check TTL const now = new Date(); const age = now.getTime() - cached.timestamp.getTime(); if (age > (this.config.cacheTTL || 300000)) { this.resultCache.delete(queryHash); return null; } return cached; } cacheResult(query, result) { if (!this.config.cacheResults) { return; } const queryHash = this.hashQuery(query); // Check cache size limit if (this.resultCache.size >= (this.config.maxCacheSize || 1000)) { // Remove oldest entry const oldestKey = this.resultCache.keys().next().value; if (oldestKey) { this.resultCache.delete(oldestKey); } } this.resultCache.set(queryHash, { result, timestamp: new Date(), queryHash }); } hashQuery(query) { // Simple hash implementation - in production use a proper hash function return Buffer.from(JSON.stringify(query)).toString('base64'); } shouldTryIPFSFallback(query, indexResult) { // Try IPFS fallback if: // 1. We have few results but no limit was specified // 2. We're searching by specific criteria that might not be fully indexed // 3. The query asks for activity details (which aren't stored in index) if (!query.limit && indexResult.total < 10) { return true; } // If searching by date range and got no results, try IPFS if (query.dateRange && indexResult.total === 0) { return true; } return false; } async enhanceWithIPFS(indexResult, query) { // This is a placeholder - in a real implementation, you would: // 1. Get IPFS hashes from manifest // 2. Retrieve additional activities from IPFS // 3. Merge and deduplicate results // 4. Apply query filters to the enhanced dataset console.log('IPFS fallback not yet implemented - returning index results'); return indexResult; } } exports.ActivitySearchService = ActivitySearchService; //# sourceMappingURL=activity-search-service.js.map