@cilow/sdk 0.2.0 → 0.2.1
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/README.md +412 -199
- package/dist/client.d.mts +224 -0
- package/dist/client.d.ts +224 -0
- package/dist/client.js +509 -0
- package/dist/client.js.map +1 -0
- package/dist/client.mjs +505 -0
- package/dist/client.mjs.map +1 -0
- package/dist/index.d.mts +94 -390
- package/dist/index.d.ts +94 -390
- package/dist/index.js +745 -350
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +732 -318
- package/dist/index.mjs.map +1 -0
- package/dist/providers/langchain.js +821 -0
- package/dist/providers/langchain.js.map +1 -0
- package/dist/providers/langchain.mjs +816 -0
- package/dist/providers/langchain.mjs.map +1 -0
- package/dist/providers/openai.js +737 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/openai.mjs +732 -0
- package/dist/providers/openai.mjs.map +1 -0
- package/dist/providers/vercel.js +866 -0
- package/dist/providers/vercel.js.map +1 -0
- package/dist/providers/vercel.mjs +860 -0
- package/dist/providers/vercel.mjs.map +1 -0
- package/dist/react/hooks.d.mts +327 -0
- package/dist/react/hooks.d.ts +327 -0
- package/dist/react/hooks.js +1183 -0
- package/dist/react/hooks.js.map +1 -0
- package/dist/react/hooks.mjs +1172 -0
- package/dist/react/hooks.mjs.map +1 -0
- package/dist/types.d.mts +494 -0
- package/dist/types.d.ts +494 -0
- package/dist/types.js +18 -0
- package/dist/types.js.map +1 -0
- package/dist/types.mjs +14 -0
- package/dist/types.mjs.map +1 -0
- package/dist/websocket.d.mts +160 -0
- package/dist/websocket.d.ts +160 -0
- package/dist/websocket.js +342 -0
- package/dist/websocket.js.map +1 -0
- package/dist/websocket.mjs +339 -0
- package/dist/websocket.mjs.map +1 -0
- package/package.json +90 -31
- package/LICENSE +0 -21
package/dist/index.mjs
CHANGED
|
@@ -1,449 +1,863 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
// src/client.ts
|
|
2
|
+
async function fetchWithRetry(url, options, config) {
|
|
3
|
+
const controller = new AbortController();
|
|
4
|
+
const timeoutId = setTimeout(() => controller.abort(), config.timeout);
|
|
5
|
+
let lastError = null;
|
|
6
|
+
for (let attempt = 0; attempt <= config.retries; attempt++) {
|
|
7
|
+
try {
|
|
8
|
+
const response = await fetch(url, {
|
|
9
|
+
...options,
|
|
10
|
+
signal: controller.signal
|
|
11
|
+
});
|
|
12
|
+
clearTimeout(timeoutId);
|
|
13
|
+
if (!response.ok) {
|
|
14
|
+
const errorBody = await response.text();
|
|
15
|
+
let apiError;
|
|
16
|
+
try {
|
|
17
|
+
apiError = JSON.parse(errorBody);
|
|
18
|
+
} catch {
|
|
19
|
+
apiError = {
|
|
20
|
+
code: `HTTP_${response.status}`,
|
|
21
|
+
message: errorBody || response.statusText
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
throw new CilowApiError(apiError.message, apiError.code, response.status, apiError.details);
|
|
25
|
+
}
|
|
26
|
+
return response;
|
|
27
|
+
} catch (error) {
|
|
28
|
+
lastError = error;
|
|
29
|
+
if (error instanceof CilowApiError) {
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
if (config.debug) {
|
|
33
|
+
console.warn(`Cilow API request failed (attempt ${attempt + 1}/${config.retries + 1}):`, error);
|
|
34
|
+
}
|
|
35
|
+
if (attempt < config.retries) {
|
|
36
|
+
await new Promise((resolve) => setTimeout(resolve, Math.pow(2, attempt) * 100));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
clearTimeout(timeoutId);
|
|
41
|
+
throw lastError || new Error("Request failed");
|
|
42
|
+
}
|
|
43
|
+
var CilowApiError = class extends Error {
|
|
44
|
+
constructor(message, code, statusCode, details) {
|
|
4
45
|
super(message);
|
|
5
|
-
this.
|
|
46
|
+
this.code = code;
|
|
6
47
|
this.statusCode = statusCode;
|
|
7
48
|
this.details = details;
|
|
8
|
-
|
|
49
|
+
this.name = "CilowApiError";
|
|
9
50
|
}
|
|
10
51
|
};
|
|
11
|
-
var ConnectionError = class _ConnectionError extends CilowError {
|
|
12
|
-
constructor(message, details) {
|
|
13
|
-
super(message, void 0, details);
|
|
14
|
-
this.name = "ConnectionError";
|
|
15
|
-
Object.setPrototypeOf(this, _ConnectionError.prototype);
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
var AuthenticationError = class _AuthenticationError extends CilowError {
|
|
19
|
-
constructor(message = "Invalid API key or unauthorized", details) {
|
|
20
|
-
super(message, 401, details);
|
|
21
|
-
this.name = "AuthenticationError";
|
|
22
|
-
Object.setPrototypeOf(this, _AuthenticationError.prototype);
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
var NotFoundError = class _NotFoundError extends CilowError {
|
|
26
|
-
constructor(message = "Resource not found", details) {
|
|
27
|
-
super(message, 404, details);
|
|
28
|
-
this.name = "NotFoundError";
|
|
29
|
-
Object.setPrototypeOf(this, _NotFoundError.prototype);
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
var ValidationError = class _ValidationError extends CilowError {
|
|
33
|
-
constructor(message = "Validation error", details) {
|
|
34
|
-
super(message, 422, details);
|
|
35
|
-
this.name = "ValidationError";
|
|
36
|
-
Object.setPrototypeOf(this, _ValidationError.prototype);
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
var RateLimitError = class _RateLimitError extends CilowError {
|
|
40
|
-
constructor(message = "Rate limit exceeded", retryAfter, details) {
|
|
41
|
-
super(message, 429, details);
|
|
42
|
-
this.name = "RateLimitError";
|
|
43
|
-
this.retryAfter = retryAfter;
|
|
44
|
-
Object.setPrototypeOf(this, _RateLimitError.prototype);
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
// src/client.ts
|
|
49
|
-
function toCamelCase(obj) {
|
|
50
|
-
if (Array.isArray(obj)) {
|
|
51
|
-
return obj.map((item) => toCamelCase(item));
|
|
52
|
-
}
|
|
53
|
-
if (obj !== null && typeof obj === "object") {
|
|
54
|
-
return Object.entries(obj).reduce((acc, [key, value]) => {
|
|
55
|
-
const camelKey = key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
56
|
-
acc[camelKey] = toCamelCase(value);
|
|
57
|
-
return acc;
|
|
58
|
-
}, {});
|
|
59
|
-
}
|
|
60
|
-
return obj;
|
|
61
|
-
}
|
|
62
|
-
function toSnakeCase(obj) {
|
|
63
|
-
if (Array.isArray(obj)) {
|
|
64
|
-
return obj.map((item) => toSnakeCase(item));
|
|
65
|
-
}
|
|
66
|
-
if (obj !== null && typeof obj === "object") {
|
|
67
|
-
return Object.entries(obj).reduce((acc, [key, value]) => {
|
|
68
|
-
const snakeKey = key.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
69
|
-
acc[snakeKey] = toSnakeCase(value);
|
|
70
|
-
return acc;
|
|
71
|
-
}, {});
|
|
72
|
-
}
|
|
73
|
-
return obj;
|
|
74
|
-
}
|
|
75
52
|
var CilowClient = class {
|
|
76
|
-
constructor(config
|
|
77
|
-
this.baseUrl =
|
|
53
|
+
constructor(config) {
|
|
54
|
+
this.baseUrl = config.apiUrl.replace(/\/$/, "");
|
|
78
55
|
this.apiKey = config.apiKey;
|
|
79
|
-
this.accessToken = config.accessToken;
|
|
80
56
|
this.timeout = config.timeout ?? 3e4;
|
|
57
|
+
this.retries = config.retries ?? 3;
|
|
58
|
+
this.debug = config.debug ?? false;
|
|
59
|
+
const authHeaders = this.apiKey.startsWith("cilow_") ? { "X-API-Key": this.apiKey } : { Authorization: `Bearer ${this.apiKey}` };
|
|
60
|
+
this.headers = {
|
|
61
|
+
"Content-Type": "application/json",
|
|
62
|
+
...authHeaders,
|
|
63
|
+
...config.headers
|
|
64
|
+
};
|
|
81
65
|
}
|
|
82
66
|
/**
|
|
83
|
-
*
|
|
84
|
-
*/
|
|
85
|
-
setAccessToken(token) {
|
|
86
|
-
this.accessToken = token;
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Make API request with error handling
|
|
67
|
+
* Make an API request
|
|
90
68
|
*/
|
|
91
|
-
async request(method,
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
69
|
+
async request(method, path, body, queryParams) {
|
|
70
|
+
let url = `${this.baseUrl}${path}`;
|
|
71
|
+
if (queryParams) {
|
|
72
|
+
const params = new URLSearchParams();
|
|
73
|
+
for (const [key, value] of Object.entries(queryParams)) {
|
|
74
|
+
if (value !== void 0) {
|
|
75
|
+
params.append(key, String(value));
|
|
76
|
+
}
|
|
99
77
|
}
|
|
100
|
-
|
|
101
|
-
|
|
78
|
+
const queryString = params.toString();
|
|
79
|
+
if (queryString) {
|
|
80
|
+
url += `?${queryString}`;
|
|
102
81
|
}
|
|
103
82
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
83
|
+
if (this.debug) {
|
|
84
|
+
console.log(`Cilow API: ${method} ${url}`);
|
|
85
|
+
}
|
|
86
|
+
const response = await fetchWithRetry(
|
|
87
|
+
url,
|
|
88
|
+
{
|
|
108
89
|
method,
|
|
109
|
-
headers,
|
|
110
|
-
body:
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
case 401:
|
|
118
|
-
throw new AuthenticationError("Invalid API key or unauthorized");
|
|
119
|
-
case 404:
|
|
120
|
-
throw new NotFoundError(`Resource not found: ${endpoint}`);
|
|
121
|
-
case 422:
|
|
122
|
-
throw new ValidationError(`Validation error: ${errorText}`);
|
|
123
|
-
case 429:
|
|
124
|
-
const retryAfter = response.headers.get("Retry-After");
|
|
125
|
-
throw new RateLimitError(
|
|
126
|
-
"Rate limit exceeded",
|
|
127
|
-
retryAfter ? parseInt(retryAfter, 10) : void 0
|
|
128
|
-
);
|
|
129
|
-
default:
|
|
130
|
-
throw new CilowError(`API error ${response.status}: ${errorText}`, response.status);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
const json = await response.json();
|
|
134
|
-
return toCamelCase(json);
|
|
135
|
-
} catch (error) {
|
|
136
|
-
clearTimeout(timeoutId);
|
|
137
|
-
if (error instanceof CilowError) {
|
|
138
|
-
throw error;
|
|
139
|
-
}
|
|
140
|
-
if (error instanceof Error) {
|
|
141
|
-
if (error.name === "AbortError") {
|
|
142
|
-
throw new ConnectionError("Request timeout");
|
|
143
|
-
}
|
|
144
|
-
throw new ConnectionError(`Failed to connect to Cilow API: ${error.message}`);
|
|
145
|
-
}
|
|
146
|
-
throw new ConnectionError("Unknown error occurred");
|
|
90
|
+
headers: this.headers,
|
|
91
|
+
body: body ? JSON.stringify(body) : void 0
|
|
92
|
+
},
|
|
93
|
+
{ timeout: this.timeout, retries: this.retries, debug: this.debug }
|
|
94
|
+
);
|
|
95
|
+
const text = await response.text();
|
|
96
|
+
if (!text) {
|
|
97
|
+
return void 0;
|
|
147
98
|
}
|
|
99
|
+
return JSON.parse(text);
|
|
148
100
|
}
|
|
149
101
|
// ===========================================================================
|
|
150
|
-
//
|
|
102
|
+
// Simple API (remember, recall, forget)
|
|
151
103
|
// ===========================================================================
|
|
152
104
|
/**
|
|
153
|
-
*
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
105
|
+
* Store a memory (simple API)
|
|
106
|
+
*
|
|
107
|
+
* @param content - The content to remember
|
|
108
|
+
* @param options - Optional configuration
|
|
109
|
+
* @returns The created memory ID
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```typescript
|
|
113
|
+
* await cilow.remember("User prefers dark mode", {
|
|
114
|
+
* tags: ["preference"],
|
|
115
|
+
* userId: "user-123"
|
|
116
|
+
* });
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
async remember(content, options) {
|
|
120
|
+
const response = await this.request("POST", "/api/v1/memory/add", {
|
|
121
|
+
content,
|
|
122
|
+
tags: options?.tags ?? [],
|
|
123
|
+
user_id: options?.userId,
|
|
124
|
+
session_id: options?.sessionId,
|
|
125
|
+
metadata: options?.metadata,
|
|
126
|
+
type: options?.tier
|
|
127
|
+
});
|
|
128
|
+
return response.memory_id || response.id || "";
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Search memories (simple API)
|
|
132
|
+
*
|
|
133
|
+
* @param query - Search query text
|
|
134
|
+
* @param options - Search options
|
|
135
|
+
* @returns Array of search results
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```typescript
|
|
139
|
+
* const memories = await cilow.recall("user preferences", {
|
|
140
|
+
* limit: 10,
|
|
141
|
+
* tags: ["preference"]
|
|
142
|
+
* });
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
async recall(query, options) {
|
|
146
|
+
const response = await this.request("POST", "/api/v1/memory/search", {
|
|
147
|
+
query,
|
|
148
|
+
limit: options?.limit ?? 10,
|
|
149
|
+
min_score: options?.minRelevance ?? 0.3,
|
|
150
|
+
tags: options?.tags,
|
|
151
|
+
user_id: options?.userId
|
|
152
|
+
});
|
|
153
|
+
return (response.results ?? []).map((r) => ({
|
|
154
|
+
memory: {
|
|
155
|
+
id: r.memory_id,
|
|
156
|
+
content: r.content,
|
|
157
|
+
tags: r.tags ?? [],
|
|
158
|
+
tier: "hot",
|
|
159
|
+
status: "active",
|
|
160
|
+
accessCount: 0,
|
|
161
|
+
tokenCount: Math.ceil(r.content.length / 4),
|
|
162
|
+
metadata: {},
|
|
163
|
+
createdAt: r.created_at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
164
|
+
updatedAt: r.created_at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
165
|
+
lastAccessedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
166
|
+
},
|
|
167
|
+
score: r.similarity,
|
|
168
|
+
highlights: []
|
|
169
|
+
}));
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Delete memories (simple API)
|
|
173
|
+
*
|
|
174
|
+
* @param filter - Filter criteria for deletion
|
|
175
|
+
* @returns Number of memories deleted
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```typescript
|
|
179
|
+
* // Delete by tags
|
|
180
|
+
* await cilow.forget({ tags: ["temporary"] });
|
|
181
|
+
*
|
|
182
|
+
* // Delete by user
|
|
183
|
+
* await cilow.forget({ userId: "user-123" });
|
|
184
|
+
*
|
|
185
|
+
* // Delete specific memory
|
|
186
|
+
* await cilow.forget({ memoryId: "mem-abc" });
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
async forget(filter) {
|
|
190
|
+
if (filter.memoryId) {
|
|
191
|
+
await this.deleteMemory(filter.memoryId);
|
|
192
|
+
return 1;
|
|
193
|
+
}
|
|
194
|
+
const response = await this.request("DELETE", "/api/v1/memories/bulk", {
|
|
195
|
+
filter_tags: filter.tags,
|
|
196
|
+
user_id: filter.userId,
|
|
197
|
+
session_id: filter.sessionId,
|
|
198
|
+
older_than: filter.olderThan
|
|
199
|
+
});
|
|
200
|
+
return response.deleted ?? 0;
|
|
159
201
|
}
|
|
160
202
|
// ===========================================================================
|
|
161
|
-
// Memory Operations
|
|
203
|
+
// Memory CRUD Operations
|
|
162
204
|
// ===========================================================================
|
|
163
205
|
/**
|
|
164
|
-
*
|
|
206
|
+
* Create a new memory
|
|
165
207
|
*/
|
|
166
|
-
async
|
|
167
|
-
|
|
168
|
-
|
|
208
|
+
async createMemory(content, options) {
|
|
209
|
+
return this.request("POST", "/api/v1/memories", {
|
|
210
|
+
content,
|
|
211
|
+
tags: options?.tags ?? [],
|
|
212
|
+
user_id: options?.userId,
|
|
213
|
+
session_id: options?.sessionId,
|
|
214
|
+
metadata: options?.metadata,
|
|
215
|
+
tier: options?.tier
|
|
216
|
+
});
|
|
169
217
|
}
|
|
170
218
|
/**
|
|
171
219
|
* Get a memory by ID
|
|
172
220
|
*/
|
|
173
|
-
async getMemory(memoryId
|
|
174
|
-
|
|
175
|
-
return this.request("GET", endpoint);
|
|
221
|
+
async getMemory(memoryId) {
|
|
222
|
+
return this.request("GET", `/api/v1/memories/${memoryId}`);
|
|
176
223
|
}
|
|
177
224
|
/**
|
|
178
|
-
* Update
|
|
225
|
+
* Update a memory
|
|
179
226
|
*/
|
|
180
|
-
async updateMemory(memoryId,
|
|
181
|
-
return this.request("
|
|
227
|
+
async updateMemory(memoryId, updates) {
|
|
228
|
+
return this.request("PATCH", `/api/v1/memories/${memoryId}`, {
|
|
229
|
+
content: updates.content,
|
|
230
|
+
tags: updates.tags,
|
|
231
|
+
metadata: updates.metadata,
|
|
232
|
+
tier: updates.tier
|
|
233
|
+
});
|
|
182
234
|
}
|
|
183
235
|
/**
|
|
184
236
|
* Delete a memory
|
|
185
237
|
*/
|
|
186
238
|
async deleteMemory(memoryId) {
|
|
187
|
-
await this.request("DELETE", `/
|
|
188
|
-
return true;
|
|
239
|
+
await this.request("DELETE", `/api/v1/memories/${memoryId}`);
|
|
189
240
|
}
|
|
190
241
|
/**
|
|
191
|
-
*
|
|
242
|
+
* List memories with pagination
|
|
192
243
|
*/
|
|
193
|
-
async
|
|
244
|
+
async listMemories(options) {
|
|
194
245
|
const response = await this.request(
|
|
195
|
-
"
|
|
196
|
-
"/memory/
|
|
197
|
-
|
|
246
|
+
"GET",
|
|
247
|
+
"/api/v1/memory/list",
|
|
248
|
+
void 0,
|
|
249
|
+
{
|
|
250
|
+
limit: options?.limit ?? 20,
|
|
251
|
+
offset: options?.offset ?? 0,
|
|
252
|
+
user_id: options?.userId,
|
|
253
|
+
session_id: options?.sessionId,
|
|
254
|
+
tags: options?.tags?.join(","),
|
|
255
|
+
type: options?.tier
|
|
256
|
+
}
|
|
198
257
|
);
|
|
199
|
-
|
|
258
|
+
const items = (response.memories ?? []).map((m) => ({
|
|
259
|
+
id: m.memory_id || m.id || "",
|
|
260
|
+
content: m.content,
|
|
261
|
+
tags: m.tags ?? [],
|
|
262
|
+
createdAt: m.created_at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
263
|
+
tier: m.type || "hot"
|
|
264
|
+
}));
|
|
265
|
+
const limit = options?.limit ?? 20;
|
|
266
|
+
const offset = options?.offset ?? 0;
|
|
267
|
+
const total = response.total ?? items.length;
|
|
268
|
+
return {
|
|
269
|
+
items,
|
|
270
|
+
total,
|
|
271
|
+
limit,
|
|
272
|
+
offset,
|
|
273
|
+
hasMore: offset + items.length < total
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
// ===========================================================================
|
|
277
|
+
// Search Operations
|
|
278
|
+
// ===========================================================================
|
|
279
|
+
/**
|
|
280
|
+
* Search memories with full options
|
|
281
|
+
*/
|
|
282
|
+
async searchMemories(query) {
|
|
283
|
+
const response = await this.request("POST", "/api/v1/memories/search", {
|
|
284
|
+
text: query.text,
|
|
285
|
+
limit: query.limit ?? 10,
|
|
286
|
+
min_relevance: query.minRelevance ?? 0.3,
|
|
287
|
+
filter_tags: query.tags,
|
|
288
|
+
user_id: query.userId,
|
|
289
|
+
session_id: query.sessionId,
|
|
290
|
+
tier: query.tier,
|
|
291
|
+
created_after: query.createdAfter,
|
|
292
|
+
created_before: query.createdBefore,
|
|
293
|
+
include_archived: query.includeArchived,
|
|
294
|
+
mode: query.mode ?? "hybrid"
|
|
295
|
+
});
|
|
296
|
+
return response.results ?? [];
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Advanced search with reranking and boosts
|
|
300
|
+
*/
|
|
301
|
+
async advancedSearch(query) {
|
|
302
|
+
const response = await this.request("POST", "/api/v1/memories/search/advanced", {
|
|
303
|
+
text: query.text,
|
|
304
|
+
limit: query.limit ?? 10,
|
|
305
|
+
min_relevance: query.minRelevance ?? 0.3,
|
|
306
|
+
filter_tags: query.tags,
|
|
307
|
+
required_tags: query.requiredTags,
|
|
308
|
+
excluded_tags: query.excludedTags,
|
|
309
|
+
user_id: query.userId,
|
|
310
|
+
session_id: query.sessionId,
|
|
311
|
+
recency_boost: query.recencyBoost,
|
|
312
|
+
frequency_boost: query.frequencyBoost,
|
|
313
|
+
metadata_filters: query.metadataFilters,
|
|
314
|
+
reranker: query.reranker
|
|
315
|
+
});
|
|
316
|
+
return response.results ?? [];
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Get context for AI applications
|
|
320
|
+
*/
|
|
321
|
+
async getContext(query, options) {
|
|
322
|
+
const maxTokens = options?.maxTokens ?? 4e3;
|
|
323
|
+
const tokensPerChar = 0.25;
|
|
324
|
+
const results = await this.searchMemories({
|
|
325
|
+
text: query,
|
|
326
|
+
limit: 30,
|
|
327
|
+
minRelevance: 0.3,
|
|
328
|
+
userId: options?.userId,
|
|
329
|
+
tags: options?.tags
|
|
330
|
+
});
|
|
331
|
+
let context = "";
|
|
332
|
+
let estimatedTokens = 0;
|
|
333
|
+
const memoryIds = [];
|
|
334
|
+
const scores = [];
|
|
335
|
+
for (const result of results) {
|
|
336
|
+
const memoryText = `[Relevance: ${(result.score * 100).toFixed(0)}%]
|
|
337
|
+
${result.memory.content}
|
|
338
|
+
|
|
339
|
+
`;
|
|
340
|
+
const memoryTokens = Math.ceil(memoryText.length * tokensPerChar);
|
|
341
|
+
if (estimatedTokens + memoryTokens > maxTokens) break;
|
|
342
|
+
context += memoryText;
|
|
343
|
+
estimatedTokens += memoryTokens;
|
|
344
|
+
memoryIds.push(result.memory.id);
|
|
345
|
+
scores.push(result.score);
|
|
346
|
+
}
|
|
347
|
+
return {
|
|
348
|
+
context: context.trim(),
|
|
349
|
+
memoriesUsed: memoryIds.length,
|
|
350
|
+
estimatedTokens,
|
|
351
|
+
memoryIds,
|
|
352
|
+
scores
|
|
353
|
+
};
|
|
200
354
|
}
|
|
355
|
+
// ===========================================================================
|
|
356
|
+
// Conversation Operations
|
|
357
|
+
// ===========================================================================
|
|
201
358
|
/**
|
|
202
|
-
*
|
|
359
|
+
* Store a conversation turn
|
|
203
360
|
*/
|
|
204
|
-
async
|
|
205
|
-
|
|
361
|
+
async storeConversation(turn) {
|
|
362
|
+
const content = `User: ${turn.userMessage}
|
|
363
|
+
|
|
364
|
+
Assistant: ${turn.assistantResponse}`;
|
|
365
|
+
const tags = ["conversation"];
|
|
366
|
+
if (turn.sessionId) {
|
|
367
|
+
tags.push(`session:${turn.sessionId}`);
|
|
368
|
+
}
|
|
369
|
+
return this.remember(content, {
|
|
370
|
+
tags,
|
|
371
|
+
userId: turn.userId,
|
|
372
|
+
sessionId: turn.sessionId,
|
|
373
|
+
metadata: {
|
|
374
|
+
type: "conversation",
|
|
375
|
+
...turn.metadata
|
|
376
|
+
}
|
|
377
|
+
});
|
|
206
378
|
}
|
|
207
379
|
/**
|
|
208
|
-
*
|
|
380
|
+
* Get conversation history for a session
|
|
209
381
|
*/
|
|
210
|
-
async
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
return Array.isArray(response) ? response : response.memories ?? [];
|
|
382
|
+
async getConversationHistory(sessionId, options) {
|
|
383
|
+
const response = await this.listMemories({
|
|
384
|
+
sessionId,
|
|
385
|
+
tags: ["conversation"],
|
|
386
|
+
limit: options?.limit ?? 50,
|
|
387
|
+
offset: options?.offset ?? 0
|
|
388
|
+
});
|
|
389
|
+
return response.items;
|
|
219
390
|
}
|
|
220
391
|
// ===========================================================================
|
|
221
|
-
//
|
|
392
|
+
// Graph Operations
|
|
222
393
|
// ===========================================================================
|
|
223
394
|
/**
|
|
224
|
-
*
|
|
395
|
+
* Get a graph node
|
|
225
396
|
*/
|
|
226
|
-
async
|
|
227
|
-
|
|
228
|
-
"POST",
|
|
229
|
-
"/vectors",
|
|
230
|
-
options
|
|
231
|
-
);
|
|
232
|
-
return response.vectorId ?? response.id ?? "";
|
|
397
|
+
async getGraphNode(nodeId) {
|
|
398
|
+
return this.request("GET", `/api/v1/graph/nodes/${nodeId}`);
|
|
233
399
|
}
|
|
234
400
|
/**
|
|
235
|
-
*
|
|
401
|
+
* Create a graph node
|
|
236
402
|
*/
|
|
237
|
-
async
|
|
238
|
-
|
|
239
|
-
|
|
403
|
+
async createGraphNode(type, name, properties) {
|
|
404
|
+
return this.request("POST", "/api/v1/graph/nodes", {
|
|
405
|
+
type,
|
|
406
|
+
name,
|
|
407
|
+
properties: properties ?? {}
|
|
408
|
+
});
|
|
240
409
|
}
|
|
241
410
|
/**
|
|
242
|
-
*
|
|
411
|
+
* Create a graph edge
|
|
243
412
|
*/
|
|
244
|
-
async
|
|
245
|
-
return this.request("
|
|
413
|
+
async createGraphEdge(sourceId, targetId, type, properties) {
|
|
414
|
+
return this.request("POST", "/api/v1/graph/edges", {
|
|
415
|
+
source_id: sourceId,
|
|
416
|
+
target_id: targetId,
|
|
417
|
+
type,
|
|
418
|
+
properties: properties ?? {}
|
|
419
|
+
});
|
|
246
420
|
}
|
|
247
421
|
/**
|
|
248
|
-
*
|
|
422
|
+
* Traverse the graph from a starting node
|
|
249
423
|
*/
|
|
250
|
-
async
|
|
251
|
-
|
|
252
|
-
|
|
424
|
+
async traverseGraph(options) {
|
|
425
|
+
return this.request("POST", "/api/v1/graph/traverse", {
|
|
426
|
+
start_node_id: options.startNodeId,
|
|
427
|
+
max_depth: options.maxDepth ?? 3,
|
|
428
|
+
relationship_types: options.relationshipTypes,
|
|
429
|
+
limit: options.limit ?? 100,
|
|
430
|
+
direction: options.direction ?? "both"
|
|
431
|
+
});
|
|
253
432
|
}
|
|
254
|
-
// ===========================================================================
|
|
255
|
-
// Graph Operations
|
|
256
|
-
// ===========================================================================
|
|
257
433
|
/**
|
|
258
|
-
*
|
|
434
|
+
* Get related nodes for a memory
|
|
259
435
|
*/
|
|
260
|
-
async
|
|
436
|
+
async getRelatedNodes(memoryId) {
|
|
261
437
|
const response = await this.request(
|
|
262
|
-
"
|
|
263
|
-
|
|
264
|
-
{ query, limit }
|
|
438
|
+
"GET",
|
|
439
|
+
`/api/v1/memories/${memoryId}/related-nodes`
|
|
265
440
|
);
|
|
266
|
-
return
|
|
441
|
+
return response.nodes ?? [];
|
|
267
442
|
}
|
|
443
|
+
// ===========================================================================
|
|
444
|
+
// Statistics & Admin
|
|
445
|
+
// ===========================================================================
|
|
268
446
|
/**
|
|
269
|
-
*
|
|
447
|
+
* Get memory statistics
|
|
270
448
|
*/
|
|
271
|
-
async
|
|
272
|
-
|
|
273
|
-
"POST",
|
|
274
|
-
"/graph/nodes",
|
|
275
|
-
options
|
|
276
|
-
);
|
|
277
|
-
return response.nodeId ?? response.id ?? "";
|
|
449
|
+
async getStats() {
|
|
450
|
+
return this.request("GET", "/api/v1/stats");
|
|
278
451
|
}
|
|
279
452
|
/**
|
|
280
|
-
* Get
|
|
453
|
+
* Get all tags with counts
|
|
281
454
|
*/
|
|
282
|
-
async
|
|
283
|
-
|
|
455
|
+
async getTags() {
|
|
456
|
+
const response = await this.request("GET", "/api/v1/tags");
|
|
457
|
+
return response.tags ?? [];
|
|
284
458
|
}
|
|
285
459
|
/**
|
|
286
|
-
*
|
|
460
|
+
* Get user statistics
|
|
287
461
|
*/
|
|
288
|
-
async
|
|
289
|
-
|
|
290
|
-
return true;
|
|
462
|
+
async getUserStats(userId) {
|
|
463
|
+
return this.request("GET", `/api/v1/users/${userId}/stats`);
|
|
291
464
|
}
|
|
292
465
|
/**
|
|
293
|
-
*
|
|
466
|
+
* Health check
|
|
294
467
|
*/
|
|
295
|
-
async
|
|
296
|
-
return this.request("GET", "/
|
|
468
|
+
async healthCheck() {
|
|
469
|
+
return this.request("GET", "/health");
|
|
297
470
|
}
|
|
298
471
|
// ===========================================================================
|
|
299
|
-
//
|
|
472
|
+
// Batch Operations
|
|
300
473
|
// ===========================================================================
|
|
301
474
|
/**
|
|
302
|
-
*
|
|
475
|
+
* Batch create memories
|
|
476
|
+
*/
|
|
477
|
+
async batchCreate(items) {
|
|
478
|
+
const response = await this.request("POST", "/api/v1/memories/batch", {
|
|
479
|
+
memories: items.map((item) => ({
|
|
480
|
+
content: item.content,
|
|
481
|
+
tags: item.options?.tags ?? [],
|
|
482
|
+
user_id: item.options?.userId,
|
|
483
|
+
session_id: item.options?.sessionId,
|
|
484
|
+
metadata: item.options?.metadata
|
|
485
|
+
}))
|
|
486
|
+
});
|
|
487
|
+
return response.ids ?? [];
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Batch delete memories
|
|
303
491
|
*/
|
|
304
|
-
async
|
|
305
|
-
const response = await this.request("
|
|
306
|
-
|
|
307
|
-
type: options.agentType ?? "react",
|
|
308
|
-
config: options.config
|
|
492
|
+
async batchDelete(memoryIds) {
|
|
493
|
+
const response = await this.request("DELETE", "/api/v1/memories/batch", {
|
|
494
|
+
ids: memoryIds
|
|
309
495
|
});
|
|
310
|
-
return response.
|
|
496
|
+
return response.deleted ?? 0;
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
function createClient(config) {
|
|
500
|
+
return new CilowClient(config);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// src/types.ts
|
|
504
|
+
function isMemoryEvent(event) {
|
|
505
|
+
return event.type.startsWith("memory.");
|
|
506
|
+
}
|
|
507
|
+
function isGraphEvent(event) {
|
|
508
|
+
return event.type.startsWith("graph.");
|
|
509
|
+
}
|
|
510
|
+
function isApiError(obj) {
|
|
511
|
+
return typeof obj === "object" && obj !== null && "code" in obj && "message" in obj;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// src/websocket.ts
|
|
515
|
+
var CilowWebSocket = class {
|
|
516
|
+
constructor(config) {
|
|
517
|
+
this.ws = null;
|
|
518
|
+
this.state = "disconnected";
|
|
519
|
+
this.reconnectCount = 0;
|
|
520
|
+
this.heartbeatTimer = null;
|
|
521
|
+
this.reconnectTimer = null;
|
|
522
|
+
this.messageQueue = [];
|
|
523
|
+
this.subscriptions = [];
|
|
524
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
525
|
+
this.allListeners = /* @__PURE__ */ new Set();
|
|
526
|
+
const httpUrl = config.apiUrl.replace(/\/$/, "");
|
|
527
|
+
this.wsUrl = config.wsUrl ?? httpUrl.replace(/^http/, "ws") + "/ws";
|
|
528
|
+
this.apiKey = config.apiKey;
|
|
529
|
+
this.reconnectAttempts = config.reconnectAttempts ?? 5;
|
|
530
|
+
this.reconnectDelay = config.reconnectDelay ?? 1e3;
|
|
531
|
+
this.heartbeatInterval = config.heartbeatInterval ?? 3e4;
|
|
532
|
+
this.messageQueueSize = config.messageQueueSize ?? 100;
|
|
311
533
|
}
|
|
312
534
|
/**
|
|
313
|
-
* Get
|
|
535
|
+
* Get current connection state
|
|
314
536
|
*/
|
|
315
|
-
|
|
316
|
-
return this.
|
|
537
|
+
get connectionState() {
|
|
538
|
+
return this.state;
|
|
317
539
|
}
|
|
318
540
|
/**
|
|
319
|
-
*
|
|
541
|
+
* Check if connected
|
|
320
542
|
*/
|
|
321
|
-
|
|
322
|
-
return this.
|
|
543
|
+
get isConnected() {
|
|
544
|
+
return this.state === "connected";
|
|
323
545
|
}
|
|
324
|
-
// ===========================================================================
|
|
325
|
-
// Fact Extraction
|
|
326
|
-
// ===========================================================================
|
|
327
546
|
/**
|
|
328
|
-
*
|
|
547
|
+
* Connect to the WebSocket server
|
|
329
548
|
*/
|
|
330
|
-
async
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
549
|
+
async connect() {
|
|
550
|
+
if (this.state === "connected" || this.state === "connecting") {
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
this.state = "connecting";
|
|
554
|
+
this.emitStatusEvent("connecting");
|
|
555
|
+
return new Promise((resolve, reject) => {
|
|
556
|
+
try {
|
|
557
|
+
const url = new URL(this.wsUrl);
|
|
558
|
+
url.searchParams.set("token", this.apiKey);
|
|
559
|
+
this.ws = new WebSocket(url.toString());
|
|
560
|
+
this.ws.onopen = () => {
|
|
561
|
+
this.state = "connected";
|
|
562
|
+
this.reconnectCount = 0;
|
|
563
|
+
this.emitStatusEvent("connected");
|
|
564
|
+
this.startHeartbeat();
|
|
565
|
+
this.flushMessageQueue();
|
|
566
|
+
this.resubscribe();
|
|
567
|
+
resolve();
|
|
568
|
+
};
|
|
569
|
+
this.ws.onclose = (event) => {
|
|
570
|
+
this.handleClose(event);
|
|
571
|
+
};
|
|
572
|
+
this.ws.onerror = (error) => {
|
|
573
|
+
if (this.state === "connecting") {
|
|
574
|
+
reject(new Error("WebSocket connection failed"));
|
|
575
|
+
}
|
|
576
|
+
this.handleError(error);
|
|
577
|
+
};
|
|
578
|
+
this.ws.onmessage = (event) => {
|
|
579
|
+
this.handleMessage(event);
|
|
580
|
+
};
|
|
581
|
+
} catch (error) {
|
|
582
|
+
this.state = "disconnected";
|
|
583
|
+
reject(error);
|
|
584
|
+
}
|
|
334
585
|
});
|
|
335
|
-
return response.facts ?? [];
|
|
336
586
|
}
|
|
337
|
-
// ===========================================================================
|
|
338
|
-
// Authentication Operations
|
|
339
|
-
// ===========================================================================
|
|
340
587
|
/**
|
|
341
|
-
*
|
|
588
|
+
* Disconnect from the WebSocket server
|
|
342
589
|
*/
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
590
|
+
disconnect() {
|
|
591
|
+
this.stopHeartbeat();
|
|
592
|
+
this.clearReconnectTimer();
|
|
593
|
+
if (this.ws) {
|
|
594
|
+
this.ws.onclose = null;
|
|
595
|
+
this.ws.close(1e3, "Client disconnect");
|
|
596
|
+
this.ws = null;
|
|
597
|
+
}
|
|
598
|
+
this.state = "disconnected";
|
|
599
|
+
this.emitStatusEvent("disconnected", "Client initiated disconnect");
|
|
352
600
|
}
|
|
353
601
|
/**
|
|
354
|
-
*
|
|
602
|
+
* Subscribe to events with optional filter
|
|
355
603
|
*/
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
this.accessToken = response.accessToken;
|
|
364
|
-
return response;
|
|
604
|
+
subscribe(filter) {
|
|
605
|
+
if (filter) {
|
|
606
|
+
this.subscriptions.push(filter);
|
|
607
|
+
}
|
|
608
|
+
if (this.isConnected) {
|
|
609
|
+
this.sendSubscription(filter);
|
|
610
|
+
}
|
|
365
611
|
}
|
|
366
612
|
/**
|
|
367
|
-
*
|
|
613
|
+
* Unsubscribe from events
|
|
368
614
|
*/
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
615
|
+
unsubscribe(filter) {
|
|
616
|
+
if (filter) {
|
|
617
|
+
this.subscriptions = this.subscriptions.filter(
|
|
618
|
+
(s) => s.userId !== filter.userId || s.sessionId !== filter.sessionId || JSON.stringify(s.tags) !== JSON.stringify(filter.tags)
|
|
619
|
+
);
|
|
620
|
+
} else {
|
|
621
|
+
this.subscriptions = [];
|
|
622
|
+
}
|
|
623
|
+
if (this.isConnected) {
|
|
624
|
+
this.send({
|
|
625
|
+
type: "unsubscribe",
|
|
626
|
+
filter
|
|
627
|
+
});
|
|
628
|
+
}
|
|
373
629
|
}
|
|
374
630
|
/**
|
|
375
|
-
*
|
|
631
|
+
* Add event listener for specific event type
|
|
376
632
|
*/
|
|
377
|
-
|
|
378
|
-
|
|
633
|
+
on(eventType, listener) {
|
|
634
|
+
if (!this.listeners.has(eventType)) {
|
|
635
|
+
this.listeners.set(eventType, /* @__PURE__ */ new Set());
|
|
636
|
+
}
|
|
637
|
+
this.listeners.get(eventType).add(listener);
|
|
638
|
+
return () => {
|
|
639
|
+
this.listeners.get(eventType)?.delete(listener);
|
|
640
|
+
};
|
|
379
641
|
}
|
|
380
642
|
/**
|
|
381
|
-
*
|
|
643
|
+
* Add listener for all events
|
|
382
644
|
*/
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
645
|
+
onAny(listener) {
|
|
646
|
+
this.allListeners.add(listener);
|
|
647
|
+
return () => {
|
|
648
|
+
this.allListeners.delete(listener);
|
|
649
|
+
};
|
|
387
650
|
}
|
|
388
651
|
/**
|
|
389
|
-
*
|
|
652
|
+
* Remove event listener
|
|
390
653
|
*/
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
return {
|
|
394
|
-
keyId: response.keyId ?? response.id ?? "",
|
|
395
|
-
name: response.name,
|
|
396
|
-
key: response.apiKey ?? response.key,
|
|
397
|
-
permissions: response.permissions ?? [],
|
|
398
|
-
expiresAt: response.expiresAt,
|
|
399
|
-
isActive: true
|
|
400
|
-
};
|
|
654
|
+
off(eventType, listener) {
|
|
655
|
+
this.listeners.get(eventType)?.delete(listener);
|
|
401
656
|
}
|
|
402
657
|
/**
|
|
403
|
-
*
|
|
658
|
+
* Remove all listeners for an event type
|
|
404
659
|
*/
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
660
|
+
offAll(eventType) {
|
|
661
|
+
if (eventType) {
|
|
662
|
+
this.listeners.delete(eventType);
|
|
663
|
+
} else {
|
|
664
|
+
this.listeners.clear();
|
|
665
|
+
this.allListeners.clear();
|
|
666
|
+
}
|
|
408
667
|
}
|
|
409
668
|
/**
|
|
410
|
-
*
|
|
669
|
+
* Listen for memory created events
|
|
411
670
|
*/
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
return true;
|
|
671
|
+
onMemoryCreated(listener) {
|
|
672
|
+
return this.on("memory.created", listener);
|
|
415
673
|
}
|
|
416
674
|
/**
|
|
417
|
-
*
|
|
675
|
+
* Listen for memory updated events
|
|
418
676
|
*/
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
677
|
+
onMemoryUpdated(listener) {
|
|
678
|
+
return this.on("memory.updated", listener);
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* Listen for memory deleted events
|
|
682
|
+
*/
|
|
683
|
+
onMemoryDeleted(listener) {
|
|
684
|
+
return this.on("memory.deleted", listener);
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Listen for memory tier changed events
|
|
688
|
+
*/
|
|
689
|
+
onMemoryTierChanged(listener) {
|
|
690
|
+
return this.on("memory.tier_changed", listener);
|
|
425
691
|
}
|
|
426
692
|
/**
|
|
427
|
-
*
|
|
693
|
+
* Listen for graph node created events
|
|
428
694
|
*/
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
return true;
|
|
695
|
+
onGraphNodeCreated(listener) {
|
|
696
|
+
return this.on("graph.node_created", listener);
|
|
432
697
|
}
|
|
433
698
|
/**
|
|
434
|
-
*
|
|
699
|
+
* Listen for graph edge created events
|
|
435
700
|
*/
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
701
|
+
onGraphEdgeCreated(listener) {
|
|
702
|
+
return this.on("graph.edge_created", listener);
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Listen for connection status changes
|
|
706
|
+
*/
|
|
707
|
+
onConnectionStatus(listener) {
|
|
708
|
+
return this.on("connection.status", listener);
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Wait for specific event (one-time)
|
|
712
|
+
*/
|
|
713
|
+
once(eventType, timeout) {
|
|
714
|
+
return new Promise((resolve, reject) => {
|
|
715
|
+
const timeoutId = timeout ? setTimeout(() => {
|
|
716
|
+
unsubscribe();
|
|
717
|
+
reject(new Error(`Timeout waiting for event: ${eventType}`));
|
|
718
|
+
}, timeout) : null;
|
|
719
|
+
const unsubscribe = this.on(eventType, (event) => {
|
|
720
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
721
|
+
unsubscribe();
|
|
722
|
+
resolve(event);
|
|
723
|
+
});
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
// ===========================================================================
|
|
727
|
+
// Private Methods
|
|
728
|
+
// ===========================================================================
|
|
729
|
+
send(message) {
|
|
730
|
+
const data = JSON.stringify(message);
|
|
731
|
+
if (this.isConnected && this.ws) {
|
|
732
|
+
this.ws.send(data);
|
|
733
|
+
} else {
|
|
734
|
+
if (this.messageQueue.length >= this.messageQueueSize) {
|
|
735
|
+
this.messageQueue.shift();
|
|
736
|
+
}
|
|
737
|
+
this.messageQueue.push(data);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
sendSubscription(filter) {
|
|
741
|
+
this.send({
|
|
742
|
+
type: "subscribe",
|
|
743
|
+
filter: filter ?? {}
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
resubscribe() {
|
|
747
|
+
for (const filter of this.subscriptions) {
|
|
748
|
+
this.sendSubscription(filter);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
flushMessageQueue() {
|
|
752
|
+
while (this.messageQueue.length > 0 && this.isConnected && this.ws) {
|
|
753
|
+
const message = this.messageQueue.shift();
|
|
754
|
+
if (message) {
|
|
755
|
+
this.ws.send(message);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
handleMessage(event) {
|
|
760
|
+
try {
|
|
761
|
+
const data = JSON.parse(event.data);
|
|
762
|
+
this.emit(data);
|
|
763
|
+
} catch (error) {
|
|
764
|
+
console.error("Failed to parse WebSocket message:", error);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
handleClose(event) {
|
|
768
|
+
this.stopHeartbeat();
|
|
769
|
+
if (event.code === 1e3) {
|
|
770
|
+
this.state = "disconnected";
|
|
771
|
+
this.emitStatusEvent("disconnected", "Connection closed normally");
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
if (this.reconnectCount < this.reconnectAttempts) {
|
|
775
|
+
this.state = "reconnecting";
|
|
776
|
+
this.emitStatusEvent("reconnecting", `Reconnecting (attempt ${this.reconnectCount + 1}/${this.reconnectAttempts})`);
|
|
777
|
+
this.scheduleReconnect();
|
|
778
|
+
} else {
|
|
779
|
+
this.state = "disconnected";
|
|
780
|
+
this.emitStatusEvent("disconnected", "Max reconnection attempts reached");
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
handleError(_error) {
|
|
784
|
+
console.error("WebSocket error occurred");
|
|
785
|
+
}
|
|
786
|
+
scheduleReconnect() {
|
|
787
|
+
this.clearReconnectTimer();
|
|
788
|
+
const delay = this.reconnectDelay * Math.pow(2, this.reconnectCount);
|
|
789
|
+
this.reconnectCount++;
|
|
790
|
+
this.reconnectTimer = setTimeout(async () => {
|
|
791
|
+
try {
|
|
792
|
+
await this.connect();
|
|
793
|
+
} catch {
|
|
794
|
+
}
|
|
795
|
+
}, delay);
|
|
796
|
+
}
|
|
797
|
+
clearReconnectTimer() {
|
|
798
|
+
if (this.reconnectTimer) {
|
|
799
|
+
clearTimeout(this.reconnectTimer);
|
|
800
|
+
this.reconnectTimer = null;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
startHeartbeat() {
|
|
804
|
+
this.stopHeartbeat();
|
|
805
|
+
this.heartbeatTimer = setInterval(() => {
|
|
806
|
+
if (this.isConnected) {
|
|
807
|
+
this.send({ type: "ping" });
|
|
808
|
+
}
|
|
809
|
+
}, this.heartbeatInterval);
|
|
810
|
+
}
|
|
811
|
+
stopHeartbeat() {
|
|
812
|
+
if (this.heartbeatTimer) {
|
|
813
|
+
clearInterval(this.heartbeatTimer);
|
|
814
|
+
this.heartbeatTimer = null;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
emit(event) {
|
|
818
|
+
const typeListeners = this.listeners.get(event.type);
|
|
819
|
+
if (typeListeners) {
|
|
820
|
+
for (const listener of typeListeners) {
|
|
821
|
+
try {
|
|
822
|
+
listener(event);
|
|
823
|
+
} catch (error) {
|
|
824
|
+
console.error("Error in event listener:", error);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
for (const listener of this.allListeners) {
|
|
829
|
+
try {
|
|
830
|
+
listener(event);
|
|
831
|
+
} catch (error) {
|
|
832
|
+
console.error("Error in event listener:", error);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
emitStatusEvent(status, reason) {
|
|
837
|
+
const event = {
|
|
838
|
+
type: "connection.status",
|
|
839
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
840
|
+
status: status === "connecting" ? "reconnecting" : status,
|
|
841
|
+
reason
|
|
842
|
+
};
|
|
843
|
+
this.emit(event);
|
|
439
844
|
}
|
|
440
845
|
};
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
846
|
+
function createWebSocket(config) {
|
|
847
|
+
return new CilowWebSocket(config);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// src/index.ts
|
|
851
|
+
var Cilow = class extends CilowClient {
|
|
852
|
+
constructor(config) {
|
|
853
|
+
super(config);
|
|
854
|
+
}
|
|
449
855
|
};
|
|
856
|
+
function createCilow(config) {
|
|
857
|
+
return new Cilow(config);
|
|
858
|
+
}
|
|
859
|
+
var src_default = Cilow;
|
|
860
|
+
|
|
861
|
+
export { Cilow, CilowApiError, CilowClient, CilowWebSocket, createCilow, createClient, createWebSocket, src_default as default, isApiError, isGraphEvent, isMemoryEvent };
|
|
862
|
+
//# sourceMappingURL=index.mjs.map
|
|
863
|
+
//# sourceMappingURL=index.mjs.map
|