UNPKG

claude-flow

Version:

Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration

204 lines (177 loc) 4.6 kB
/** * Registry API Client * Secure integration with Claude Flow Cloud Functions * * Security: * - HTTPS only * - No credentials stored in code * - Rate limiting respected * - Input validation */ const REGISTRY_API_URL = 'https://us-central1-claude-flow.cloudfunctions.net/publish-registry'; export interface RatingResponse { success: boolean; itemId: string; average: number; count: number; error?: string; } export interface BulkRatingsResponse { [itemId: string]: { average: number; count: number; }; } export interface AnalyticsResponse { downloads: Record<string, number>; exports: number; imports: number; publishes: number; } /** * Validate item ID to prevent injection */ function validateItemId(itemId: string): boolean { // Only allow alphanumeric, @, /, -, _ return /^[@a-zA-Z0-9\/_-]+$/.test(itemId) && itemId.length < 100; } /** * Validate rating value */ function validateRating(rating: number): boolean { return Number.isInteger(rating) && rating >= 1 && rating <= 5; } /** * Rate a plugin or model */ export async function rateItem( itemId: string, rating: number, itemType: 'plugin' | 'model' = 'plugin', userId?: string ): Promise<RatingResponse> { if (!validateItemId(itemId)) { throw new Error('Invalid item ID'); } if (!validateRating(rating)) { throw new Error('Rating must be integer 1-5'); } const response = await fetch(`${REGISTRY_API_URL}?action=rate`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ itemId, rating, itemType, ...(userId && { userId }), }), signal: AbortSignal.timeout(10000), }); if (!response.ok) { const error = await response.text(); throw new Error(`Rating failed: ${error}`); } return response.json() as Promise<RatingResponse>; } /** * Get ratings for a single item */ export async function getRating( itemId: string, itemType: 'plugin' | 'model' = 'plugin' ): Promise<RatingResponse> { if (!validateItemId(itemId)) { throw new Error('Invalid item ID'); } const params = new URLSearchParams({ action: 'get-ratings', itemId, itemType, }); const response = await fetch(`${REGISTRY_API_URL}?${params}`, { signal: AbortSignal.timeout(10000), }); if (!response.ok) { throw new Error('Failed to get ratings'); } return response.json() as Promise<RatingResponse>; } /** * Get ratings for multiple items (batch) */ export async function getBulkRatings( itemIds: string[], itemType: 'plugin' | 'model' = 'plugin' ): Promise<BulkRatingsResponse> { // Validate all IDs for (const id of itemIds) { if (!validateItemId(id)) { throw new Error(`Invalid item ID: ${id}`); } } // Limit batch size const limitedIds = itemIds.slice(0, 50); const response = await fetch(`${REGISTRY_API_URL}?action=bulk-ratings`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ itemIds: limitedIds, itemType, }), signal: AbortSignal.timeout(15000), }); if (!response.ok) { throw new Error('Failed to get bulk ratings'); } return response.json() as Promise<BulkRatingsResponse>; } /** * Get analytics data */ export async function getAnalytics(): Promise<AnalyticsResponse> { const response = await fetch(`${REGISTRY_API_URL}?action=analytics`, { signal: AbortSignal.timeout(10000), }); if (!response.ok) { throw new Error('Failed to get analytics'); } return response.json() as Promise<AnalyticsResponse>; } /** * Track a download event */ export async function trackDownload(pluginId: string): Promise<void> { if (!validateItemId(pluginId)) { return; // Silently fail for invalid IDs } try { await fetch(`${REGISTRY_API_URL}?action=track-download`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ pluginId }), signal: AbortSignal.timeout(5000), }); } catch { // Non-critical, don't throw } } /** * Check API health */ export async function checkHealth(): Promise<{ healthy: boolean; latestCid?: string; error?: string; }> { try { const response = await fetch(`${REGISTRY_API_URL}?action=status`, { signal: AbortSignal.timeout(5000), }); return response.json() as Promise<{ healthy: boolean; latestCid?: string; error?: string }>; } catch (error) { return { healthy: false, error: error instanceof Error ? error.message : 'Unknown error', }; } }