@vibe-kit/grok-cli
Version:
An open-source AI agent that brings the power of Grok directly into your terminal.
136 lines • 5.21 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SseTransport = void 0;
const transport_interface_1 = require("./transport-interface");
class SseTransport extends transport_interface_1.McpTransport {
constructor(options) {
super(options);
this.eventSource = null;
this.pendingRequests = new Map();
this.url = options.url;
}
async connect() {
return new Promise((resolve, reject) => {
try {
// Import EventSource at runtime
let EventSource;
try {
// The eventsource package exports the constructor directly
EventSource = require('eventsource');
}
catch (error) {
return reject(new Error('EventSource package not found. Install "eventsource" package for Node.js support.'));
}
const headers = {
'Accept': 'text/event-stream',
'Cache-Control': 'no-cache',
...this.options.headers
};
this.eventSource = new EventSource(this.url, {
headers
});
let connected = false;
const timeout = setTimeout(() => {
if (!connected) {
this.eventSource?.close();
reject(new Error('Connection timeout'));
}
}, this.options.timeout || 30000);
this.eventSource.onopen = () => {
clearTimeout(timeout);
connected = true;
this.connected = true;
this.emit('connect');
resolve();
};
this.eventSource.onmessage = (event) => {
try {
const message = JSON.parse(event.data);
this.handleMessage(message);
}
catch (error) {
console.warn('Failed to parse SSE message:', event.data, error);
}
};
this.eventSource.onerror = (error) => {
clearTimeout(timeout);
this.connected = false;
this.emit('error', error);
if (!connected) {
reject(new Error('Failed to connect to SSE endpoint'));
}
};
}
catch (error) {
reject(error);
}
});
}
handleMessage(message) {
if (message.id !== undefined) {
// Response
const pending = this.pendingRequests.get(message.id);
if (pending) {
this.pendingRequests.delete(message.id);
if (message.error) {
pending.reject(new Error(`${message.error.message} (${message.error.code})`));
}
else {
pending.resolve(message.result);
}
}
}
else {
// Notification
this.emit('message', message);
}
}
async send(message) {
if (!this.connected || !this.eventSource) {
throw new Error('SSE transport not connected');
}
// For SSE, we typically send requests via HTTP POST to a companion endpoint
// The SSE stream is for receiving responses/notifications
const postUrl = this.url.replace('/sse', '/request');
try {
const response = await fetch(postUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...this.options.headers
},
body: JSON.stringify(message)
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
// If this is a request (has ID), wait for response via SSE
if (message.id !== undefined) {
return new Promise((resolve, reject) => {
this.pendingRequests.set(message.id, { resolve, reject });
// Timeout handling
setTimeout(() => {
if (this.pendingRequests.has(message.id)) {
this.pendingRequests.delete(message.id);
reject(new Error(`Request timeout for method: ${message.method}`));
}
}, this.options.timeout || 30000);
});
}
}
catch (error) {
throw new Error(`Failed to send SSE request: ${error}`);
}
}
async disconnect() {
if (this.eventSource) {
this.eventSource.close();
this.eventSource = null;
}
this.connected = false;
this.pendingRequests.clear();
this.emit('disconnect');
}
}
exports.SseTransport = SseTransport;
//# sourceMappingURL=sse-transport.js.map