UNPKG

ragatanga-mcp-sdk

Version:

SDK for integrating with the Ragatanga Management Control Plane (MCP) with Next.js 15, React 19, WebSocket and Arrow IPC support

311 lines (308 loc) 9.75 kB
'use strict'; var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); // src/client/sse.ts var SSEConnectionStatus = /* @__PURE__ */ ((SSEConnectionStatus2) => { SSEConnectionStatus2["DISCONNECTED"] = "disconnected"; SSEConnectionStatus2["CONNECTING"] = "connecting"; SSEConnectionStatus2["CONNECTED"] = "connected"; SSEConnectionStatus2["RECONNECTING"] = "reconnecting"; SSEConnectionStatus2["ERROR"] = "error"; return SSEConnectionStatus2; })(SSEConnectionStatus || {}); var _MCPSSEClient = class _MCPSSEClient { /** * Create a new SSE client */ constructor(options) { this.eventSource = null; this.eventHandlers = /* @__PURE__ */ new Map(); this.reconnectAttempts = 0; this.status = "disconnected" /* DISCONNECTED */; this.lastEventId = null; this.heartbeatTimer = null; this.connectionTimer = null; this.statusHandlers = /* @__PURE__ */ new Set(); this.baseUrl = options.baseUrl || "https://api.mcp.ai"; this.apiKey = options.apiKey; this.token = options.token; this.tenantId = options.tenantId; this.reconnectTimeout = options.reconnectTimeout || 3e3; this.maxReconnectAttempts = options.maxReconnectAttempts || 10; this.eventsEndpoint = options.eventsEndpoint || "/events"; this.sseOptions = options.sseOptions; this.eventTypes = options.eventTypes; this.heartbeatInterval = options.heartbeatInterval || 3e4; this.connectionTimeout = options.connectionTimeout || 1e4; this.autoReconnect = options.autoReconnect !== false; } /** * Get the current connection status */ getStatus() { return this.status; } /** * Register a handler for connection status changes */ onStatusChange(handler) { this.statusHandlers.add(handler); handler(this.status); return () => { this.statusHandlers.delete(handler); }; } /** * Update connection status and notify handlers */ setStatus(status) { if (this.status !== status) { this.status = status; for (const handler of this.statusHandlers) { try { handler(status); } catch (error) { console.error("Error in SSE status handler:", error); } } } } /** * Connect to the SSE endpoint */ connect() { if (this.eventSource) { this.disconnect(); } this.setStatus("connecting" /* CONNECTING */); this.reconnectAttempts = 0; const url = new URL(`${this.baseUrl}${this.eventsEndpoint}`); if (this.apiKey) { url.searchParams.append("apiKey", this.apiKey); } if (this.token) { url.searchParams.append("token", this.token); } if (this.tenantId) { url.searchParams.append("tenantId", this.tenantId); } if (this.eventTypes && this.eventTypes.length > 0) { url.searchParams.append("events", this.eventTypes.join(",")); } if (this.lastEventId) { url.searchParams.append("lastEventId", this.lastEventId); } try { this.connectionTimer = setTimeout(() => { if (this.status === "connecting" /* CONNECTING */) { console.warn("SSE connection timeout"); this.setStatus("error" /* ERROR */); this.disconnect(); if (this.autoReconnect) { this.attemptReconnect(); } } }, this.connectionTimeout); this.eventSource = new EventSource(url.toString(), this.sseOptions); this.eventSource.onopen = this.handleOpen.bind(this); this.eventSource.onerror = this.handleError.bind(this); this.eventSource.onmessage = this.handleMessage.bind(this); if (this.eventTypes) { for (const eventType of this.eventTypes) { this.eventSource.addEventListener(eventType, this.handleEvent.bind(this)); } } for (const eventType of this.eventHandlers.keys()) { this.eventSource.addEventListener(eventType, this.handleEvent.bind(this)); } } catch (error) { console.error("Error connecting to SSE endpoint:", error); this.handleConnectionError(error); } } /** * Disconnect from the SSE endpoint */ disconnect() { if (this.connectionTimer) { clearTimeout(this.connectionTimer); this.connectionTimer = null; } if (this.heartbeatTimer) { clearInterval(this.heartbeatTimer); this.heartbeatTimer = null; } if (this.eventSource) { this.eventSource.close(); this.eventSource = null; if (this.status !== "error" /* ERROR */) { this.setStatus("disconnected" /* DISCONNECTED */); } } } /** * Register an event handler for a specific event type */ on(eventType, callback) { if (!this.eventHandlers.has(eventType)) { this.eventHandlers.set(eventType, /* @__PURE__ */ new Set()); if (this.eventSource && this.eventSource.readyState === EventSource.OPEN) { this.eventSource.addEventListener(eventType, this.handleEvent.bind(this)); } } const handlers = this.eventHandlers.get(eventType); handlers.add(callback); return () => { if (this.eventHandlers.has(eventType)) { const handlers2 = this.eventHandlers.get(eventType); handlers2.delete(callback); if (handlers2.size === 0) { this.eventHandlers.delete(eventType); } } }; } /** * Remove all event handlers for a specific event type */ off(eventType) { this.eventHandlers.delete(eventType); } /** * Attempt to reconnect with exponential backoff */ attemptReconnect() { if (this.reconnectAttempts >= this.maxReconnectAttempts) { console.error(`SSE maximum reconnection attempts (${this.maxReconnectAttempts}) reached`); this.setStatus("error" /* ERROR */); return; } this.reconnectAttempts++; this.setStatus("reconnecting" /* RECONNECTING */); const baseDelay = this.reconnectTimeout; const exponentialDelay = baseDelay * Math.pow(1.5, this.reconnectAttempts - 1); const jitter = 0.2 * exponentialDelay; const delay = exponentialDelay + Math.random() * jitter; console.log(`SSE reconnecting in ${Math.round(delay)}ms (attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts})`); setTimeout(() => { this.connect(); }, delay); } /** * Start heartbeat to detect connection issues */ startHeartbeat() { if (this.heartbeatTimer) { clearInterval(this.heartbeatTimer); } this.heartbeatTimer = setInterval(() => { if (this.eventSource && this.eventSource.readyState === EventSource.OPEN) { this.dispatchEvent("heartbeat", new MessageEvent("heartbeat", { data: JSON.stringify({ timestamp: Date.now() }) })); } else if (this.eventSource && this.eventSource.readyState === EventSource.CLOSED) { console.warn("SSE connection unexpectedly closed during heartbeat check"); this.disconnect(); if (this.autoReconnect) { this.attemptReconnect(); } } }, this.heartbeatInterval); } /** * Handle SSE connection open */ handleOpen(event) { if (this.connectionTimer) { clearTimeout(this.connectionTimer); this.connectionTimer = null; } console.log("SSE connection opened"); this.setStatus("connected" /* CONNECTED */); this.reconnectAttempts = 0; this.startHeartbeat(); this.dispatchEvent("open", new MessageEvent("open")); } /** * Handle SSE connection error */ handleError(event) { console.error("SSE connection error:", event); this.dispatchEvent("error", new MessageEvent("error")); this.setStatus("error" /* ERROR */); if (this.autoReconnect) { this.disconnect(); this.attemptReconnect(); } } /** * Handle connection initialization error */ handleConnectionError(error) { if (this.connectionTimer) { clearTimeout(this.connectionTimer); this.connectionTimer = null; } this.setStatus("error" /* ERROR */); this.dispatchEvent("error", new MessageEvent("error", { data: error instanceof Error ? error.message : String(error) })); if (this.autoReconnect) { this.attemptReconnect(); } } /** * Handle generic message event */ handleMessage(event) { if (event.lastEventId) { this.lastEventId = event.lastEventId; } try { const data = JSON.parse(event.data); if (data.type && typeof data.type === "string") { this.dispatchEvent(data.type, new MessageEvent(data.type, { data: data.payload || data, lastEventId: event.lastEventId })); } } catch (e) { } this.reconnectAttempts = 0; this.dispatchEvent("message", event); } /** * Handle specific event type */ handleEvent(event) { this.dispatchEvent(event.type, event); } /** * Dispatch an event to all registered handlers */ dispatchEvent(eventType, event) { if (this.eventHandlers.has(eventType)) { const handlers = this.eventHandlers.get(eventType); for (const handler of handlers) { try { handler(event); } catch (error) { console.error(`Error in SSE event handler for ${eventType}:`, error); } } } } }; __name(_MCPSSEClient, "MCPSSEClient"); var MCPSSEClient = _MCPSSEClient; function createSSEClient(options) { return new MCPSSEClient(options); } __name(createSSEClient, "createSSEClient"); exports.MCPSSEClient = MCPSSEClient; exports.SSEConnectionStatus = SSEConnectionStatus; exports.createSSEClient = createSSEClient; //# sourceMappingURL=sse.js.map //# sourceMappingURL=sse.js.map