Skip to main content
Glama
EventClient.ts3.24 kB
/** * Client for connecting to real-time server events via SSE. * Provides a consistent interface for subscribing to application events. */ import type { SseEventName, SseEventPayloads } from "../events/types"; import { ServerEventName } from "../events/types"; export interface EventData<T extends SseEventName = SseEventName> { type: T; payload: SseEventPayloads[T]; } export type EventCallback = (event: EventData) => void; /** * Event client that manages SSE connection to the backend. */ export class EventClient { private callbacks: Set<EventCallback> = new Set(); private eventSource?: EventSource; private reconnectTimeout?: ReturnType<typeof setTimeout>; private isConnected = false; /** * Start the SSE connection. */ connect(): void { if (this.eventSource) { console.warn("EventClient already connected"); return; } console.log("📡 Connecting to SSE endpoint..."); this.eventSource = new EventSource("/web/events"); this.eventSource.addEventListener("open", () => { console.log("📡 SSE connection established"); this.isConnected = true; }); this.eventSource.addEventListener("error", (event) => { console.error("❌ SSE connection error:", event); this.isConnected = false; // EventSource will automatically attempt to reconnect }); // Listen for all event types defined in ServerEventName const eventTypes = Object.values(ServerEventName) as SseEventName[]; console.log("🔧 Setting up event listeners", eventTypes); for (const eventType of eventTypes) { this.eventSource.addEventListener(eventType, (event: MessageEvent) => { try { const payload = JSON.parse(event.data); this.notifyCallbacks({ type: eventType, payload, }); } catch (error) { console.error(`Failed to parse SSE event data: ${error}`); } }); } // Add a generic message listener as a fallback to catch any events this.eventSource.addEventListener("message", (event: MessageEvent) => { console.log("📨 Generic message event received:", event.data); }); } /** * Subscribe to events with a callback. * @param callback Function to call when events are received * @returns Unsubscribe function */ subscribe(callback: EventCallback): () => void { this.callbacks.add(callback); return () => { this.callbacks.delete(callback); }; } /** * Disconnect and clean up resources. */ disconnect(): void { if (this.reconnectTimeout) { clearTimeout(this.reconnectTimeout); this.reconnectTimeout = undefined; } if (this.eventSource) { this.eventSource.close(); this.eventSource = undefined; } this.isConnected = false; } /** * Notify all callbacks of an event. */ private notifyCallbacks(event: EventData): void { for (const callback of this.callbacks) { try { callback(event); } catch (error) { console.error("Error in event callback:", error); } } } /** * Check if the client is currently connected. */ isActive(): boolean { return this.isConnected; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/arabold/docs-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server