@cilow/sdk 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +109 -492
- package/dist/abstain.d.ts +43 -0
- package/dist/abstain.d.ts.map +1 -0
- package/dist/abstain.js +42 -0
- package/dist/abstain.js.map +1 -0
- package/dist/adapters/anthropic.d.ts +57 -0
- package/dist/adapters/anthropic.d.ts.map +1 -0
- package/dist/adapters/anthropic.js +57 -0
- package/dist/adapters/anthropic.js.map +1 -0
- package/dist/adapters/index.d.ts +16 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +16 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/langchain.d.ts +62 -0
- package/dist/adapters/langchain.d.ts.map +1 -0
- package/dist/adapters/langchain.js +68 -0
- package/dist/adapters/langchain.js.map +1 -0
- package/dist/adapters/memory.d.ts +105 -0
- package/dist/adapters/memory.d.ts.map +1 -0
- package/dist/adapters/memory.js +105 -0
- package/dist/adapters/memory.js.map +1 -0
- package/dist/adapters/openai.d.ts +56 -0
- package/dist/adapters/openai.d.ts.map +1 -0
- package/dist/adapters/openai.js +64 -0
- package/dist/adapters/openai.js.map +1 -0
- package/dist/adapters/remaining.d.ts +52 -0
- package/dist/adapters/remaining.d.ts.map +1 -0
- package/dist/adapters/remaining.js +67 -0
- package/dist/adapters/remaining.js.map +1 -0
- package/dist/client.d.ts +512 -173
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +648 -504
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts +25 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +28 -0
- package/dist/errors.js.map +1 -0
- package/dist/hash.d.ts +13 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +92 -0
- package/dist/hash.js.map +1 -0
- package/dist/index.d.ts +18 -109
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -876
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +809 -486
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +18 -17
- package/dist/types.js.map +1 -1
- package/package.json +30 -103
- package/dist/client.d.mts +0 -224
- package/dist/client.mjs +0 -505
- package/dist/client.mjs.map +0 -1
- package/dist/index.d.mts +0 -111
- package/dist/index.mjs +0 -863
- package/dist/index.mjs.map +0 -1
- package/dist/providers/langchain.js +0 -821
- package/dist/providers/langchain.js.map +0 -1
- package/dist/providers/langchain.mjs +0 -816
- package/dist/providers/langchain.mjs.map +0 -1
- package/dist/providers/openai.js +0 -737
- package/dist/providers/openai.js.map +0 -1
- package/dist/providers/openai.mjs +0 -732
- package/dist/providers/openai.mjs.map +0 -1
- package/dist/providers/vercel.js +0 -866
- package/dist/providers/vercel.js.map +0 -1
- package/dist/providers/vercel.mjs +0 -860
- package/dist/providers/vercel.mjs.map +0 -1
- package/dist/react/hooks.d.mts +0 -327
- package/dist/react/hooks.d.ts +0 -327
- package/dist/react/hooks.js +0 -1183
- package/dist/react/hooks.js.map +0 -1
- package/dist/react/hooks.mjs +0 -1172
- package/dist/react/hooks.mjs.map +0 -1
- package/dist/types.d.mts +0 -494
- package/dist/types.mjs +0 -14
- package/dist/types.mjs.map +0 -1
- package/dist/websocket.d.mts +0 -160
- package/dist/websocket.d.ts +0 -160
- package/dist/websocket.js +0 -342
- package/dist/websocket.js.map +0 -1
- package/dist/websocket.mjs +0 -339
- package/dist/websocket.mjs.map +0 -1
package/dist/websocket.mjs
DELETED
|
@@ -1,339 +0,0 @@
|
|
|
1
|
-
// src/websocket.ts
|
|
2
|
-
var CilowWebSocket = class {
|
|
3
|
-
constructor(config) {
|
|
4
|
-
this.ws = null;
|
|
5
|
-
this.state = "disconnected";
|
|
6
|
-
this.reconnectCount = 0;
|
|
7
|
-
this.heartbeatTimer = null;
|
|
8
|
-
this.reconnectTimer = null;
|
|
9
|
-
this.messageQueue = [];
|
|
10
|
-
this.subscriptions = [];
|
|
11
|
-
this.listeners = /* @__PURE__ */ new Map();
|
|
12
|
-
this.allListeners = /* @__PURE__ */ new Set();
|
|
13
|
-
const httpUrl = config.apiUrl.replace(/\/$/, "");
|
|
14
|
-
this.wsUrl = config.wsUrl ?? httpUrl.replace(/^http/, "ws") + "/ws";
|
|
15
|
-
this.apiKey = config.apiKey;
|
|
16
|
-
this.reconnectAttempts = config.reconnectAttempts ?? 5;
|
|
17
|
-
this.reconnectDelay = config.reconnectDelay ?? 1e3;
|
|
18
|
-
this.heartbeatInterval = config.heartbeatInterval ?? 3e4;
|
|
19
|
-
this.messageQueueSize = config.messageQueueSize ?? 100;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Get current connection state
|
|
23
|
-
*/
|
|
24
|
-
get connectionState() {
|
|
25
|
-
return this.state;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Check if connected
|
|
29
|
-
*/
|
|
30
|
-
get isConnected() {
|
|
31
|
-
return this.state === "connected";
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Connect to the WebSocket server
|
|
35
|
-
*/
|
|
36
|
-
async connect() {
|
|
37
|
-
if (this.state === "connected" || this.state === "connecting") {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
this.state = "connecting";
|
|
41
|
-
this.emitStatusEvent("connecting");
|
|
42
|
-
return new Promise((resolve, reject) => {
|
|
43
|
-
try {
|
|
44
|
-
const url = new URL(this.wsUrl);
|
|
45
|
-
url.searchParams.set("token", this.apiKey);
|
|
46
|
-
this.ws = new WebSocket(url.toString());
|
|
47
|
-
this.ws.onopen = () => {
|
|
48
|
-
this.state = "connected";
|
|
49
|
-
this.reconnectCount = 0;
|
|
50
|
-
this.emitStatusEvent("connected");
|
|
51
|
-
this.startHeartbeat();
|
|
52
|
-
this.flushMessageQueue();
|
|
53
|
-
this.resubscribe();
|
|
54
|
-
resolve();
|
|
55
|
-
};
|
|
56
|
-
this.ws.onclose = (event) => {
|
|
57
|
-
this.handleClose(event);
|
|
58
|
-
};
|
|
59
|
-
this.ws.onerror = (error) => {
|
|
60
|
-
if (this.state === "connecting") {
|
|
61
|
-
reject(new Error("WebSocket connection failed"));
|
|
62
|
-
}
|
|
63
|
-
this.handleError(error);
|
|
64
|
-
};
|
|
65
|
-
this.ws.onmessage = (event) => {
|
|
66
|
-
this.handleMessage(event);
|
|
67
|
-
};
|
|
68
|
-
} catch (error) {
|
|
69
|
-
this.state = "disconnected";
|
|
70
|
-
reject(error);
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Disconnect from the WebSocket server
|
|
76
|
-
*/
|
|
77
|
-
disconnect() {
|
|
78
|
-
this.stopHeartbeat();
|
|
79
|
-
this.clearReconnectTimer();
|
|
80
|
-
if (this.ws) {
|
|
81
|
-
this.ws.onclose = null;
|
|
82
|
-
this.ws.close(1e3, "Client disconnect");
|
|
83
|
-
this.ws = null;
|
|
84
|
-
}
|
|
85
|
-
this.state = "disconnected";
|
|
86
|
-
this.emitStatusEvent("disconnected", "Client initiated disconnect");
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Subscribe to events with optional filter
|
|
90
|
-
*/
|
|
91
|
-
subscribe(filter) {
|
|
92
|
-
if (filter) {
|
|
93
|
-
this.subscriptions.push(filter);
|
|
94
|
-
}
|
|
95
|
-
if (this.isConnected) {
|
|
96
|
-
this.sendSubscription(filter);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Unsubscribe from events
|
|
101
|
-
*/
|
|
102
|
-
unsubscribe(filter) {
|
|
103
|
-
if (filter) {
|
|
104
|
-
this.subscriptions = this.subscriptions.filter(
|
|
105
|
-
(s) => s.userId !== filter.userId || s.sessionId !== filter.sessionId || JSON.stringify(s.tags) !== JSON.stringify(filter.tags)
|
|
106
|
-
);
|
|
107
|
-
} else {
|
|
108
|
-
this.subscriptions = [];
|
|
109
|
-
}
|
|
110
|
-
if (this.isConnected) {
|
|
111
|
-
this.send({
|
|
112
|
-
type: "unsubscribe",
|
|
113
|
-
filter
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Add event listener for specific event type
|
|
119
|
-
*/
|
|
120
|
-
on(eventType, listener) {
|
|
121
|
-
if (!this.listeners.has(eventType)) {
|
|
122
|
-
this.listeners.set(eventType, /* @__PURE__ */ new Set());
|
|
123
|
-
}
|
|
124
|
-
this.listeners.get(eventType).add(listener);
|
|
125
|
-
return () => {
|
|
126
|
-
this.listeners.get(eventType)?.delete(listener);
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Add listener for all events
|
|
131
|
-
*/
|
|
132
|
-
onAny(listener) {
|
|
133
|
-
this.allListeners.add(listener);
|
|
134
|
-
return () => {
|
|
135
|
-
this.allListeners.delete(listener);
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* Remove event listener
|
|
140
|
-
*/
|
|
141
|
-
off(eventType, listener) {
|
|
142
|
-
this.listeners.get(eventType)?.delete(listener);
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* Remove all listeners for an event type
|
|
146
|
-
*/
|
|
147
|
-
offAll(eventType) {
|
|
148
|
-
if (eventType) {
|
|
149
|
-
this.listeners.delete(eventType);
|
|
150
|
-
} else {
|
|
151
|
-
this.listeners.clear();
|
|
152
|
-
this.allListeners.clear();
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Listen for memory created events
|
|
157
|
-
*/
|
|
158
|
-
onMemoryCreated(listener) {
|
|
159
|
-
return this.on("memory.created", listener);
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Listen for memory updated events
|
|
163
|
-
*/
|
|
164
|
-
onMemoryUpdated(listener) {
|
|
165
|
-
return this.on("memory.updated", listener);
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* Listen for memory deleted events
|
|
169
|
-
*/
|
|
170
|
-
onMemoryDeleted(listener) {
|
|
171
|
-
return this.on("memory.deleted", listener);
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Listen for memory tier changed events
|
|
175
|
-
*/
|
|
176
|
-
onMemoryTierChanged(listener) {
|
|
177
|
-
return this.on("memory.tier_changed", listener);
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Listen for graph node created events
|
|
181
|
-
*/
|
|
182
|
-
onGraphNodeCreated(listener) {
|
|
183
|
-
return this.on("graph.node_created", listener);
|
|
184
|
-
}
|
|
185
|
-
/**
|
|
186
|
-
* Listen for graph edge created events
|
|
187
|
-
*/
|
|
188
|
-
onGraphEdgeCreated(listener) {
|
|
189
|
-
return this.on("graph.edge_created", listener);
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Listen for connection status changes
|
|
193
|
-
*/
|
|
194
|
-
onConnectionStatus(listener) {
|
|
195
|
-
return this.on("connection.status", listener);
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Wait for specific event (one-time)
|
|
199
|
-
*/
|
|
200
|
-
once(eventType, timeout) {
|
|
201
|
-
return new Promise((resolve, reject) => {
|
|
202
|
-
const timeoutId = timeout ? setTimeout(() => {
|
|
203
|
-
unsubscribe();
|
|
204
|
-
reject(new Error(`Timeout waiting for event: ${eventType}`));
|
|
205
|
-
}, timeout) : null;
|
|
206
|
-
const unsubscribe = this.on(eventType, (event) => {
|
|
207
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
208
|
-
unsubscribe();
|
|
209
|
-
resolve(event);
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
// ===========================================================================
|
|
214
|
-
// Private Methods
|
|
215
|
-
// ===========================================================================
|
|
216
|
-
send(message) {
|
|
217
|
-
const data = JSON.stringify(message);
|
|
218
|
-
if (this.isConnected && this.ws) {
|
|
219
|
-
this.ws.send(data);
|
|
220
|
-
} else {
|
|
221
|
-
if (this.messageQueue.length >= this.messageQueueSize) {
|
|
222
|
-
this.messageQueue.shift();
|
|
223
|
-
}
|
|
224
|
-
this.messageQueue.push(data);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
sendSubscription(filter) {
|
|
228
|
-
this.send({
|
|
229
|
-
type: "subscribe",
|
|
230
|
-
filter: filter ?? {}
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
resubscribe() {
|
|
234
|
-
for (const filter of this.subscriptions) {
|
|
235
|
-
this.sendSubscription(filter);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
flushMessageQueue() {
|
|
239
|
-
while (this.messageQueue.length > 0 && this.isConnected && this.ws) {
|
|
240
|
-
const message = this.messageQueue.shift();
|
|
241
|
-
if (message) {
|
|
242
|
-
this.ws.send(message);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
handleMessage(event) {
|
|
247
|
-
try {
|
|
248
|
-
const data = JSON.parse(event.data);
|
|
249
|
-
this.emit(data);
|
|
250
|
-
} catch (error) {
|
|
251
|
-
console.error("Failed to parse WebSocket message:", error);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
handleClose(event) {
|
|
255
|
-
this.stopHeartbeat();
|
|
256
|
-
if (event.code === 1e3) {
|
|
257
|
-
this.state = "disconnected";
|
|
258
|
-
this.emitStatusEvent("disconnected", "Connection closed normally");
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
if (this.reconnectCount < this.reconnectAttempts) {
|
|
262
|
-
this.state = "reconnecting";
|
|
263
|
-
this.emitStatusEvent("reconnecting", `Reconnecting (attempt ${this.reconnectCount + 1}/${this.reconnectAttempts})`);
|
|
264
|
-
this.scheduleReconnect();
|
|
265
|
-
} else {
|
|
266
|
-
this.state = "disconnected";
|
|
267
|
-
this.emitStatusEvent("disconnected", "Max reconnection attempts reached");
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
handleError(_error) {
|
|
271
|
-
console.error("WebSocket error occurred");
|
|
272
|
-
}
|
|
273
|
-
scheduleReconnect() {
|
|
274
|
-
this.clearReconnectTimer();
|
|
275
|
-
const delay = this.reconnectDelay * Math.pow(2, this.reconnectCount);
|
|
276
|
-
this.reconnectCount++;
|
|
277
|
-
this.reconnectTimer = setTimeout(async () => {
|
|
278
|
-
try {
|
|
279
|
-
await this.connect();
|
|
280
|
-
} catch {
|
|
281
|
-
}
|
|
282
|
-
}, delay);
|
|
283
|
-
}
|
|
284
|
-
clearReconnectTimer() {
|
|
285
|
-
if (this.reconnectTimer) {
|
|
286
|
-
clearTimeout(this.reconnectTimer);
|
|
287
|
-
this.reconnectTimer = null;
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
startHeartbeat() {
|
|
291
|
-
this.stopHeartbeat();
|
|
292
|
-
this.heartbeatTimer = setInterval(() => {
|
|
293
|
-
if (this.isConnected) {
|
|
294
|
-
this.send({ type: "ping" });
|
|
295
|
-
}
|
|
296
|
-
}, this.heartbeatInterval);
|
|
297
|
-
}
|
|
298
|
-
stopHeartbeat() {
|
|
299
|
-
if (this.heartbeatTimer) {
|
|
300
|
-
clearInterval(this.heartbeatTimer);
|
|
301
|
-
this.heartbeatTimer = null;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
emit(event) {
|
|
305
|
-
const typeListeners = this.listeners.get(event.type);
|
|
306
|
-
if (typeListeners) {
|
|
307
|
-
for (const listener of typeListeners) {
|
|
308
|
-
try {
|
|
309
|
-
listener(event);
|
|
310
|
-
} catch (error) {
|
|
311
|
-
console.error("Error in event listener:", error);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
for (const listener of this.allListeners) {
|
|
316
|
-
try {
|
|
317
|
-
listener(event);
|
|
318
|
-
} catch (error) {
|
|
319
|
-
console.error("Error in event listener:", error);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
emitStatusEvent(status, reason) {
|
|
324
|
-
const event = {
|
|
325
|
-
type: "connection.status",
|
|
326
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
327
|
-
status: status === "connecting" ? "reconnecting" : status,
|
|
328
|
-
reason
|
|
329
|
-
};
|
|
330
|
-
this.emit(event);
|
|
331
|
-
}
|
|
332
|
-
};
|
|
333
|
-
function createWebSocket(config) {
|
|
334
|
-
return new CilowWebSocket(config);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
export { CilowWebSocket, createWebSocket };
|
|
338
|
-
//# sourceMappingURL=websocket.mjs.map
|
|
339
|
-
//# sourceMappingURL=websocket.mjs.map
|
package/dist/websocket.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/websocket.ts"],"names":[],"mappings":"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","file":"websocket.mjs","sourcesContent":["/**\n * Cilow WebSocket Client\n *\n * Real-time connection for memory updates, graph changes, and event streaming.\n */\n\nimport type {\n CilowConfig,\n WebSocketConfig,\n CilowEvent,\n MemoryCreatedEvent,\n MemoryUpdatedEvent,\n MemoryDeletedEvent,\n MemoryTierChangedEvent,\n GraphNodeCreatedEvent,\n GraphEdgeCreatedEvent,\n ConnectionStatusEvent,\n} from './types';\n\n/**\n * WebSocket connection states\n */\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting';\n\n/**\n * Event listener type\n */\nexport type EventListener<T extends CilowEvent = CilowEvent> = (event: T) => void;\n\n/**\n * Subscription filter options\n */\nexport interface SubscriptionFilter {\n /** Filter by user ID */\n userId?: string;\n /** Filter by session ID */\n sessionId?: string;\n /** Filter by tags */\n tags?: string[];\n /** Filter by event types */\n eventTypes?: string[];\n}\n\n/**\n * CilowWebSocket - Real-time WebSocket client for Cilow\n *\n * @example\n * ```typescript\n * const ws = new CilowWebSocket({\n * apiUrl: 'https://api.cilow.ai',\n * apiKey: 'your-key'\n * });\n *\n * // Subscribe to memory events\n * ws.on('memory.created', (event) => {\n * console.log('New memory:', event.memory);\n * });\n *\n * // Connect\n * await ws.connect();\n *\n * // Subscribe to specific user's events\n * ws.subscribe({ userId: 'user-123' });\n * ```\n */\nexport class CilowWebSocket {\n private ws: WebSocket | null = null;\n private readonly wsUrl: string;\n private readonly apiKey: string;\n private readonly reconnectAttempts: number;\n private readonly reconnectDelay: number;\n private readonly heartbeatInterval: number;\n private readonly messageQueueSize: number;\n\n private state: ConnectionState = 'disconnected';\n private reconnectCount = 0;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private messageQueue: string[] = [];\n private subscriptions: SubscriptionFilter[] = [];\n\n private listeners: Map<string, Set<EventListener>> = new Map();\n private allListeners: Set<EventListener> = new Set();\n\n constructor(config: CilowConfig & WebSocketConfig) {\n // Convert HTTP URL to WebSocket URL\n const httpUrl = config.apiUrl.replace(/\\/$/, '');\n this.wsUrl = config.wsUrl ?? httpUrl.replace(/^http/, 'ws') + '/ws';\n this.apiKey = config.apiKey;\n\n this.reconnectAttempts = config.reconnectAttempts ?? 5;\n this.reconnectDelay = config.reconnectDelay ?? 1000;\n this.heartbeatInterval = config.heartbeatInterval ?? 30000;\n this.messageQueueSize = config.messageQueueSize ?? 100;\n }\n\n /**\n * Get current connection state\n */\n get connectionState(): ConnectionState {\n return this.state;\n }\n\n /**\n * Check if connected\n */\n get isConnected(): boolean {\n return this.state === 'connected';\n }\n\n /**\n * Connect to the WebSocket server\n */\n async connect(): Promise<void> {\n if (this.state === 'connected' || this.state === 'connecting') {\n return;\n }\n\n this.state = 'connecting';\n this.emitStatusEvent('connecting');\n\n return new Promise((resolve, reject) => {\n try {\n // Add authentication to URL\n const url = new URL(this.wsUrl);\n url.searchParams.set('token', this.apiKey);\n\n this.ws = new WebSocket(url.toString());\n\n this.ws.onopen = () => {\n this.state = 'connected';\n this.reconnectCount = 0;\n this.emitStatusEvent('connected');\n this.startHeartbeat();\n this.flushMessageQueue();\n this.resubscribe();\n resolve();\n };\n\n this.ws.onclose = (event) => {\n this.handleClose(event);\n };\n\n this.ws.onerror = (error) => {\n if (this.state === 'connecting') {\n reject(new Error('WebSocket connection failed'));\n }\n this.handleError(error);\n };\n\n this.ws.onmessage = (event) => {\n this.handleMessage(event);\n };\n } catch (error) {\n this.state = 'disconnected';\n reject(error);\n }\n });\n }\n\n /**\n * Disconnect from the WebSocket server\n */\n disconnect(): void {\n this.stopHeartbeat();\n this.clearReconnectTimer();\n\n if (this.ws) {\n this.ws.onclose = null; // Prevent reconnection\n this.ws.close(1000, 'Client disconnect');\n this.ws = null;\n }\n\n this.state = 'disconnected';\n this.emitStatusEvent('disconnected', 'Client initiated disconnect');\n }\n\n /**\n * Subscribe to events with optional filter\n */\n subscribe(filter?: SubscriptionFilter): void {\n if (filter) {\n this.subscriptions.push(filter);\n }\n\n if (this.isConnected) {\n this.sendSubscription(filter);\n }\n }\n\n /**\n * Unsubscribe from events\n */\n unsubscribe(filter?: SubscriptionFilter): void {\n if (filter) {\n this.subscriptions = this.subscriptions.filter(\n (s) =>\n s.userId !== filter.userId ||\n s.sessionId !== filter.sessionId ||\n JSON.stringify(s.tags) !== JSON.stringify(filter.tags)\n );\n } else {\n this.subscriptions = [];\n }\n\n if (this.isConnected) {\n this.send({\n type: 'unsubscribe',\n filter,\n });\n }\n }\n\n /**\n * Add event listener for specific event type\n */\n on<T extends CilowEvent>(eventType: T['type'], listener: EventListener<T>): () => void {\n if (!this.listeners.has(eventType)) {\n this.listeners.set(eventType, new Set());\n }\n this.listeners.get(eventType)!.add(listener as EventListener);\n\n // Return unsubscribe function\n return () => {\n this.listeners.get(eventType)?.delete(listener as EventListener);\n };\n }\n\n /**\n * Add listener for all events\n */\n onAny(listener: EventListener): () => void {\n this.allListeners.add(listener);\n return () => {\n this.allListeners.delete(listener);\n };\n }\n\n /**\n * Remove event listener\n */\n off<T extends CilowEvent>(eventType: T['type'], listener: EventListener<T>): void {\n this.listeners.get(eventType)?.delete(listener as EventListener);\n }\n\n /**\n * Remove all listeners for an event type\n */\n offAll(eventType?: string): void {\n if (eventType) {\n this.listeners.delete(eventType);\n } else {\n this.listeners.clear();\n this.allListeners.clear();\n }\n }\n\n /**\n * Listen for memory created events\n */\n onMemoryCreated(listener: EventListener<MemoryCreatedEvent>): () => void {\n return this.on('memory.created', listener);\n }\n\n /**\n * Listen for memory updated events\n */\n onMemoryUpdated(listener: EventListener<MemoryUpdatedEvent>): () => void {\n return this.on('memory.updated', listener);\n }\n\n /**\n * Listen for memory deleted events\n */\n onMemoryDeleted(listener: EventListener<MemoryDeletedEvent>): () => void {\n return this.on('memory.deleted', listener);\n }\n\n /**\n * Listen for memory tier changed events\n */\n onMemoryTierChanged(listener: EventListener<MemoryTierChangedEvent>): () => void {\n return this.on('memory.tier_changed', listener);\n }\n\n /**\n * Listen for graph node created events\n */\n onGraphNodeCreated(listener: EventListener<GraphNodeCreatedEvent>): () => void {\n return this.on('graph.node_created', listener);\n }\n\n /**\n * Listen for graph edge created events\n */\n onGraphEdgeCreated(listener: EventListener<GraphEdgeCreatedEvent>): () => void {\n return this.on('graph.edge_created', listener);\n }\n\n /**\n * Listen for connection status changes\n */\n onConnectionStatus(listener: EventListener<ConnectionStatusEvent>): () => void {\n return this.on('connection.status', listener);\n }\n\n /**\n * Wait for specific event (one-time)\n */\n once<T extends CilowEvent>(eventType: T['type'], timeout?: number): Promise<T> {\n return new Promise((resolve, reject) => {\n const timeoutId = timeout\n ? setTimeout(() => {\n unsubscribe();\n reject(new Error(`Timeout waiting for event: ${eventType}`));\n }, timeout)\n : null;\n\n const unsubscribe = this.on(eventType, (event) => {\n if (timeoutId) clearTimeout(timeoutId);\n unsubscribe();\n resolve(event as T);\n });\n });\n }\n\n // ===========================================================================\n // Private Methods\n // ===========================================================================\n\n private send(message: Record<string, unknown>): void {\n const data = JSON.stringify(message);\n\n if (this.isConnected && this.ws) {\n this.ws.send(data);\n } else {\n // Queue message for later\n if (this.messageQueue.length >= this.messageQueueSize) {\n this.messageQueue.shift(); // Remove oldest\n }\n this.messageQueue.push(data);\n }\n }\n\n private sendSubscription(filter?: SubscriptionFilter): void {\n this.send({\n type: 'subscribe',\n filter: filter ?? {},\n });\n }\n\n private resubscribe(): void {\n for (const filter of this.subscriptions) {\n this.sendSubscription(filter);\n }\n }\n\n private flushMessageQueue(): void {\n while (this.messageQueue.length > 0 && this.isConnected && this.ws) {\n const message = this.messageQueue.shift();\n if (message) {\n this.ws.send(message);\n }\n }\n }\n\n private handleMessage(event: MessageEvent): void {\n try {\n const data = JSON.parse(event.data) as CilowEvent;\n this.emit(data);\n } catch (error) {\n console.error('Failed to parse WebSocket message:', error);\n }\n }\n\n private handleClose(event: CloseEvent): void {\n this.stopHeartbeat();\n\n if (event.code === 1000) {\n // Normal close\n this.state = 'disconnected';\n this.emitStatusEvent('disconnected', 'Connection closed normally');\n return;\n }\n\n // Attempt reconnection\n if (this.reconnectCount < this.reconnectAttempts) {\n this.state = 'reconnecting';\n this.emitStatusEvent('reconnecting', `Reconnecting (attempt ${this.reconnectCount + 1}/${this.reconnectAttempts})`);\n this.scheduleReconnect();\n } else {\n this.state = 'disconnected';\n this.emitStatusEvent('disconnected', 'Max reconnection attempts reached');\n }\n }\n\n private handleError(_error: Event): void {\n // Errors are typically followed by close events\n // Just log for debugging\n console.error('WebSocket error occurred');\n }\n\n private scheduleReconnect(): void {\n this.clearReconnectTimer();\n\n const delay = this.reconnectDelay * Math.pow(2, this.reconnectCount);\n this.reconnectCount++;\n\n this.reconnectTimer = setTimeout(async () => {\n try {\n await this.connect();\n } catch {\n // Connection failed, will retry in handleClose\n }\n }, delay);\n }\n\n private clearReconnectTimer(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat();\n this.heartbeatTimer = setInterval(() => {\n if (this.isConnected) {\n this.send({ type: 'ping' });\n }\n }, this.heartbeatInterval);\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n private emit(event: CilowEvent): void {\n // Emit to type-specific listeners\n const typeListeners = this.listeners.get(event.type);\n if (typeListeners) {\n for (const listener of typeListeners) {\n try {\n listener(event);\n } catch (error) {\n console.error('Error in event listener:', error);\n }\n }\n }\n\n // Emit to all-event listeners\n for (const listener of this.allListeners) {\n try {\n listener(event);\n } catch (error) {\n console.error('Error in event listener:', error);\n }\n }\n }\n\n private emitStatusEvent(status: 'connected' | 'disconnected' | 'reconnecting' | 'connecting', reason?: string): void {\n const event: ConnectionStatusEvent = {\n type: 'connection.status',\n timestamp: new Date().toISOString(),\n status: status === 'connecting' ? 'reconnecting' : status,\n reason,\n };\n this.emit(event);\n }\n}\n\n/**\n * Create a WebSocket client instance (convenience function)\n */\nexport function createWebSocket(config: CilowConfig & WebSocketConfig): CilowWebSocket {\n return new CilowWebSocket(config);\n}\n"]}
|