@ekodb/ekodb-client 0.1.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/README.md +329 -0
- package/dist/client.d.ts +404 -0
- package/dist/client.js +553 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +20 -0
- package/dist/join.d.ts +68 -0
- package/dist/join.js +71 -0
- package/dist/query-builder.d.ts +141 -0
- package/dist/query-builder.js +370 -0
- package/dist/schema.d.ts +189 -0
- package/dist/schema.js +186 -0
- package/dist/search.d.ts +172 -0
- package/dist/search.js +183 -0
- package/package.json +27 -0
- package/src/client.ts +757 -0
- package/src/index.ts +29 -0
- package/src/join.ts +102 -0
- package/src/query-builder.ts +419 -0
- package/src/schema.ts +285 -0
- package/src/search.ts +275 -0
- package/tsconfig.json +18 -0
package/dist/client.js
ADDED
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ekoDB TypeScript Client
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.WebSocketClient = exports.EkoDBClient = exports.MergeStrategy = exports.RateLimitError = void 0;
|
|
40
|
+
const query_builder_1 = require("./query-builder");
|
|
41
|
+
const search_1 = require("./search");
|
|
42
|
+
const schema_1 = require("./schema");
|
|
43
|
+
/**
|
|
44
|
+
* Rate limit error
|
|
45
|
+
*/
|
|
46
|
+
class RateLimitError extends Error {
|
|
47
|
+
constructor(retryAfterSecs, message) {
|
|
48
|
+
super(message || `Rate limit exceeded. Retry after ${retryAfterSecs} seconds`);
|
|
49
|
+
this.retryAfterSecs = retryAfterSecs;
|
|
50
|
+
this.name = 'RateLimitError';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.RateLimitError = RateLimitError;
|
|
54
|
+
var MergeStrategy;
|
|
55
|
+
(function (MergeStrategy) {
|
|
56
|
+
MergeStrategy["Chronological"] = "Chronological";
|
|
57
|
+
MergeStrategy["Summarized"] = "Summarized";
|
|
58
|
+
MergeStrategy["LatestOnly"] = "LatestOnly";
|
|
59
|
+
})(MergeStrategy || (exports.MergeStrategy = MergeStrategy = {}));
|
|
60
|
+
class EkoDBClient {
|
|
61
|
+
constructor(config, apiKey) {
|
|
62
|
+
this.token = null;
|
|
63
|
+
this.rateLimitInfo = null;
|
|
64
|
+
// Support both old (baseURL, apiKey) and new (config object) signatures
|
|
65
|
+
if (typeof config === 'string') {
|
|
66
|
+
this.baseURL = config;
|
|
67
|
+
this.apiKey = apiKey;
|
|
68
|
+
this.shouldRetry = true;
|
|
69
|
+
this.maxRetries = 3;
|
|
70
|
+
this.timeout = 30000;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
this.baseURL = config.baseURL;
|
|
74
|
+
this.apiKey = config.apiKey;
|
|
75
|
+
this.shouldRetry = config.shouldRetry ?? true;
|
|
76
|
+
this.maxRetries = config.maxRetries ?? 3;
|
|
77
|
+
this.timeout = config.timeout ?? 30000;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Initialize the client by getting an auth token
|
|
82
|
+
*/
|
|
83
|
+
async init() {
|
|
84
|
+
await this.refreshToken();
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Get the current rate limit information
|
|
88
|
+
*/
|
|
89
|
+
getRateLimitInfo() {
|
|
90
|
+
return this.rateLimitInfo;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Check if approaching rate limit (less than 10% remaining)
|
|
94
|
+
*/
|
|
95
|
+
isNearRateLimit() {
|
|
96
|
+
if (!this.rateLimitInfo)
|
|
97
|
+
return false;
|
|
98
|
+
const threshold = this.rateLimitInfo.limit * 0.1;
|
|
99
|
+
return this.rateLimitInfo.remaining <= threshold;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Refresh the authentication token
|
|
103
|
+
*/
|
|
104
|
+
async refreshToken() {
|
|
105
|
+
const response = await fetch(`${this.baseURL}/api/auth/token`, {
|
|
106
|
+
method: 'POST',
|
|
107
|
+
headers: { 'Content-Type': 'application/json' },
|
|
108
|
+
body: JSON.stringify({ api_key: this.apiKey }),
|
|
109
|
+
});
|
|
110
|
+
if (!response.ok) {
|
|
111
|
+
throw new Error(`Auth failed with status: ${response.status}`);
|
|
112
|
+
}
|
|
113
|
+
const result = await response.json();
|
|
114
|
+
this.token = result.token;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Extract rate limit information from response headers
|
|
118
|
+
*/
|
|
119
|
+
extractRateLimitInfo(response) {
|
|
120
|
+
const limit = response.headers.get('x-ratelimit-limit');
|
|
121
|
+
const remaining = response.headers.get('x-ratelimit-remaining');
|
|
122
|
+
const reset = response.headers.get('x-ratelimit-reset');
|
|
123
|
+
if (limit && remaining && reset) {
|
|
124
|
+
this.rateLimitInfo = {
|
|
125
|
+
limit: parseInt(limit, 10),
|
|
126
|
+
remaining: parseInt(remaining, 10),
|
|
127
|
+
reset: parseInt(reset, 10),
|
|
128
|
+
};
|
|
129
|
+
// Log warning if approaching rate limit
|
|
130
|
+
if (this.isNearRateLimit()) {
|
|
131
|
+
console.warn(`Approaching rate limit: ${this.rateLimitInfo.remaining}/${this.rateLimitInfo.limit} remaining`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Sleep for a specified number of seconds
|
|
137
|
+
*/
|
|
138
|
+
sleep(seconds) {
|
|
139
|
+
return new Promise(resolve => setTimeout(resolve, seconds * 1000));
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Make an HTTP request to the ekoDB API with retry logic
|
|
143
|
+
*/
|
|
144
|
+
async makeRequest(method, path, data, attempt = 0) {
|
|
145
|
+
if (!this.token) {
|
|
146
|
+
await this.refreshToken();
|
|
147
|
+
}
|
|
148
|
+
const options = {
|
|
149
|
+
method,
|
|
150
|
+
headers: {
|
|
151
|
+
'Authorization': `Bearer ${this.token}`,
|
|
152
|
+
'Content-Type': 'application/json',
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
if (data) {
|
|
156
|
+
options.body = JSON.stringify(data);
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
const response = await fetch(`${this.baseURL}${path}`, options);
|
|
160
|
+
// Extract rate limit info from successful responses
|
|
161
|
+
if (response.ok) {
|
|
162
|
+
this.extractRateLimitInfo(response);
|
|
163
|
+
return response.json();
|
|
164
|
+
}
|
|
165
|
+
// Handle rate limiting (429)
|
|
166
|
+
if (response.status === 429) {
|
|
167
|
+
const retryAfter = parseInt(response.headers.get('retry-after') || '60', 10);
|
|
168
|
+
if (this.shouldRetry && attempt < this.maxRetries) {
|
|
169
|
+
console.log(`Rate limited. Retrying after ${retryAfter} seconds...`);
|
|
170
|
+
await this.sleep(retryAfter);
|
|
171
|
+
return this.makeRequest(method, path, data, attempt + 1);
|
|
172
|
+
}
|
|
173
|
+
throw new RateLimitError(retryAfter);
|
|
174
|
+
}
|
|
175
|
+
// Handle service unavailable (503)
|
|
176
|
+
if (response.status === 503 && this.shouldRetry && attempt < this.maxRetries) {
|
|
177
|
+
const retryDelay = 10;
|
|
178
|
+
console.log(`Service unavailable. Retrying after ${retryDelay} seconds...`);
|
|
179
|
+
await this.sleep(retryDelay);
|
|
180
|
+
return this.makeRequest(method, path, data, attempt + 1);
|
|
181
|
+
}
|
|
182
|
+
// Handle other errors
|
|
183
|
+
const text = await response.text();
|
|
184
|
+
throw new Error(`Request failed with status ${response.status}: ${text}`);
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
// Handle network errors with retry
|
|
188
|
+
if (error instanceof TypeError && this.shouldRetry && attempt < this.maxRetries) {
|
|
189
|
+
const retryDelay = 3;
|
|
190
|
+
console.log(`Network error. Retrying after ${retryDelay} seconds...`);
|
|
191
|
+
await this.sleep(retryDelay);
|
|
192
|
+
return this.makeRequest(method, path, data, attempt + 1);
|
|
193
|
+
}
|
|
194
|
+
throw error;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Insert a document into a collection
|
|
199
|
+
*/
|
|
200
|
+
async insert(collection, record, ttl) {
|
|
201
|
+
const data = { ...record };
|
|
202
|
+
if (ttl) {
|
|
203
|
+
data.ttl_duration = ttl;
|
|
204
|
+
}
|
|
205
|
+
return this.makeRequest('POST', `/api/insert/${collection}`, data);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Find documents in a collection
|
|
209
|
+
*
|
|
210
|
+
* @param collection - Collection name
|
|
211
|
+
* @param query - Query object or QueryBuilder instance
|
|
212
|
+
* @returns Array of matching records
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```typescript
|
|
216
|
+
* // Using QueryBuilder
|
|
217
|
+
* const results = await client.find("users",
|
|
218
|
+
* new QueryBuilder()
|
|
219
|
+
* .eq("status", "active")
|
|
220
|
+
* .gt("age", 18)
|
|
221
|
+
* .sortDesc("created_at")
|
|
222
|
+
* .limit(10)
|
|
223
|
+
* );
|
|
224
|
+
*
|
|
225
|
+
* // Using plain Query object
|
|
226
|
+
* const results = await client.find("users", { limit: 10 });
|
|
227
|
+
* ```
|
|
228
|
+
*/
|
|
229
|
+
async find(collection, query = {}) {
|
|
230
|
+
const queryObj = query instanceof query_builder_1.QueryBuilder ? query.build() : query;
|
|
231
|
+
return this.makeRequest('POST', `/api/find/${collection}`, queryObj);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Find a document by ID
|
|
235
|
+
*/
|
|
236
|
+
async findByID(collection, id) {
|
|
237
|
+
return this.makeRequest('GET', `/api/find/${collection}/${id}`);
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Update a document
|
|
241
|
+
*/
|
|
242
|
+
async update(collection, id, record) {
|
|
243
|
+
return this.makeRequest('PUT', `/api/update/${collection}/${id}`, record);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Delete a document
|
|
247
|
+
*/
|
|
248
|
+
async delete(collection, id) {
|
|
249
|
+
await this.makeRequest('DELETE', `/api/delete/${collection}/${id}`);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Batch insert multiple documents
|
|
253
|
+
*/
|
|
254
|
+
async batchInsert(collection, records) {
|
|
255
|
+
const inserts = records.map(data => ({ data }));
|
|
256
|
+
const result = await this.makeRequest('POST', `/api/batch/insert/${collection}`, { inserts });
|
|
257
|
+
return result.successful.map(id => ({ id }));
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Batch update multiple documents
|
|
261
|
+
*/
|
|
262
|
+
async batchUpdate(collection, updates) {
|
|
263
|
+
const result = await this.makeRequest('PUT', `/api/batch/update/${collection}`, { updates });
|
|
264
|
+
return result.successful.map(id => ({ id }));
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Batch delete multiple documents
|
|
268
|
+
*/
|
|
269
|
+
async batchDelete(collection, ids) {
|
|
270
|
+
const deletes = ids.map(id => ({ id }));
|
|
271
|
+
const result = await this.makeRequest('DELETE', `/api/batch/delete/${collection}`, { deletes });
|
|
272
|
+
return result.successful.length;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Set a key-value pair
|
|
276
|
+
*/
|
|
277
|
+
async kvSet(key, value) {
|
|
278
|
+
await this.makeRequest('POST', `/api/kv/set/${encodeURIComponent(key)}`, { value });
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Get a value by key
|
|
282
|
+
*/
|
|
283
|
+
async kvGet(key) {
|
|
284
|
+
const result = await this.makeRequest('GET', `/api/kv/get/${encodeURIComponent(key)}`);
|
|
285
|
+
return result.value;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Delete a key
|
|
289
|
+
*/
|
|
290
|
+
async kvDelete(key) {
|
|
291
|
+
await this.makeRequest('DELETE', `/api/kv/delete/${encodeURIComponent(key)}`);
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* List all collections
|
|
295
|
+
*/
|
|
296
|
+
async listCollections() {
|
|
297
|
+
const result = await this.makeRequest('GET', '/api/collections');
|
|
298
|
+
return result.collections;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Delete a collection
|
|
302
|
+
*/
|
|
303
|
+
async deleteCollection(collection) {
|
|
304
|
+
await this.makeRequest('DELETE', `/api/collections/${collection}`);
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Create a collection with schema
|
|
308
|
+
*
|
|
309
|
+
* @param collection - Collection name
|
|
310
|
+
* @param schema - Schema definition or SchemaBuilder instance
|
|
311
|
+
*
|
|
312
|
+
* @example
|
|
313
|
+
* ```typescript
|
|
314
|
+
* const schema = new SchemaBuilder()
|
|
315
|
+
* .addField("name", new FieldTypeSchemaBuilder("string").required())
|
|
316
|
+
* .addField("email", new FieldTypeSchemaBuilder("string").unique())
|
|
317
|
+
* .addField("age", new FieldTypeSchemaBuilder("number").range(0, 150));
|
|
318
|
+
*
|
|
319
|
+
* await client.createCollection("users", schema);
|
|
320
|
+
* ```
|
|
321
|
+
*/
|
|
322
|
+
async createCollection(collection, schema) {
|
|
323
|
+
const schemaObj = schema instanceof schema_1.SchemaBuilder ? schema.build() : schema;
|
|
324
|
+
await this.makeRequest('POST', `/api/collections/${collection}`, schemaObj);
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Get collection metadata and schema
|
|
328
|
+
*
|
|
329
|
+
* @param collection - Collection name
|
|
330
|
+
* @returns Collection metadata including schema and analytics
|
|
331
|
+
*/
|
|
332
|
+
async getCollection(collection) {
|
|
333
|
+
return this.makeRequest('GET', `/api/collections/${collection}`);
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Get collection schema
|
|
337
|
+
*
|
|
338
|
+
* @param collection - Collection name
|
|
339
|
+
* @returns The collection schema
|
|
340
|
+
*/
|
|
341
|
+
async getSchema(collection) {
|
|
342
|
+
const metadata = await this.getCollection(collection);
|
|
343
|
+
return metadata.collection;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Search documents in a collection using full-text, vector, or hybrid search
|
|
347
|
+
*
|
|
348
|
+
* @param collection - Collection name
|
|
349
|
+
* @param searchQuery - Search query object or SearchQueryBuilder instance
|
|
350
|
+
* @returns Search response with results and metadata
|
|
351
|
+
*
|
|
352
|
+
* @example
|
|
353
|
+
* ```typescript
|
|
354
|
+
* // Full-text search
|
|
355
|
+
* const results = await client.search("users",
|
|
356
|
+
* new SearchQueryBuilder("john")
|
|
357
|
+
* .fields(["name", "email"])
|
|
358
|
+
* .fuzzy(true)
|
|
359
|
+
* .limit(10)
|
|
360
|
+
* );
|
|
361
|
+
*
|
|
362
|
+
* // Vector search
|
|
363
|
+
* const results = await client.search("documents",
|
|
364
|
+
* new SearchQueryBuilder("")
|
|
365
|
+
* .vector([0.1, 0.2, 0.3, ...])
|
|
366
|
+
* .vectorK(5)
|
|
367
|
+
* );
|
|
368
|
+
*
|
|
369
|
+
* // Hybrid search
|
|
370
|
+
* const results = await client.search("products",
|
|
371
|
+
* new SearchQueryBuilder("laptop")
|
|
372
|
+
* .vector([0.1, 0.2, ...])
|
|
373
|
+
* .textWeight(0.7)
|
|
374
|
+
* .vectorWeight(0.3)
|
|
375
|
+
* );
|
|
376
|
+
* ```
|
|
377
|
+
*/
|
|
378
|
+
async search(collection, searchQuery) {
|
|
379
|
+
const queryObj = searchQuery instanceof search_1.SearchQueryBuilder ? searchQuery.build() : searchQuery;
|
|
380
|
+
return this.makeRequest('POST', `/api/search/${collection}`, queryObj);
|
|
381
|
+
}
|
|
382
|
+
// ========== Chat Methods ==========
|
|
383
|
+
/**
|
|
384
|
+
* Create a new chat session
|
|
385
|
+
*/
|
|
386
|
+
async createChatSession(request) {
|
|
387
|
+
return this.makeRequest('POST', '/api/chat', request);
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Send a message in an existing chat session
|
|
391
|
+
*/
|
|
392
|
+
async chatMessage(sessionId, request) {
|
|
393
|
+
return this.makeRequest('POST', `/api/chat/${sessionId}/messages`, request);
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Get a chat session by ID
|
|
397
|
+
*/
|
|
398
|
+
async getChatSession(sessionId) {
|
|
399
|
+
return this.makeRequest('GET', `/api/chat/${sessionId}`);
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* List all chat sessions
|
|
403
|
+
*/
|
|
404
|
+
async listChatSessions(query) {
|
|
405
|
+
const params = new URLSearchParams();
|
|
406
|
+
if (query?.limit)
|
|
407
|
+
params.append('limit', query.limit.toString());
|
|
408
|
+
if (query?.skip)
|
|
409
|
+
params.append('skip', query.skip.toString());
|
|
410
|
+
if (query?.sort)
|
|
411
|
+
params.append('sort', query.sort);
|
|
412
|
+
const queryString = params.toString();
|
|
413
|
+
const path = queryString ? `/api/chat?${queryString}` : '/api/chat';
|
|
414
|
+
return this.makeRequest('GET', path);
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Get messages from a chat session
|
|
418
|
+
*/
|
|
419
|
+
async getChatSessionMessages(sessionId, query) {
|
|
420
|
+
const params = new URLSearchParams();
|
|
421
|
+
if (query?.limit)
|
|
422
|
+
params.append('limit', query.limit.toString());
|
|
423
|
+
if (query?.skip)
|
|
424
|
+
params.append('skip', query.skip.toString());
|
|
425
|
+
if (query?.sort)
|
|
426
|
+
params.append('sort', query.sort);
|
|
427
|
+
const queryString = params.toString();
|
|
428
|
+
const path = queryString ? `/api/chat/${sessionId}/messages?${queryString}` : `/api/chat/${sessionId}/messages`;
|
|
429
|
+
return this.makeRequest('GET', path);
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Update a chat session
|
|
433
|
+
*/
|
|
434
|
+
async updateChatSession(sessionId, request) {
|
|
435
|
+
return this.makeRequest('PUT', `/api/chat/${sessionId}`, request);
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Branch a chat session
|
|
439
|
+
*/
|
|
440
|
+
async branchChatSession(request) {
|
|
441
|
+
return this.makeRequest('POST', '/api/chat/branch', request);
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Delete a chat session
|
|
445
|
+
*/
|
|
446
|
+
async deleteChatSession(sessionId) {
|
|
447
|
+
await this.makeRequest('DELETE', `/api/chat/${sessionId}`);
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Regenerate an AI response message
|
|
451
|
+
*/
|
|
452
|
+
async regenerateMessage(sessionId, messageId) {
|
|
453
|
+
return this.makeRequest('POST', `/api/chat/${sessionId}/messages/${messageId}/regenerate`);
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Update a specific message
|
|
457
|
+
*/
|
|
458
|
+
async updateChatMessage(sessionId, messageId, content) {
|
|
459
|
+
await this.makeRequest('PUT', `/api/chat/${sessionId}/messages/${messageId}`, { content });
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Delete a specific message
|
|
463
|
+
*/
|
|
464
|
+
async deleteChatMessage(sessionId, messageId) {
|
|
465
|
+
await this.makeRequest('DELETE', `/api/chat/${sessionId}/messages/${messageId}`);
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Toggle the "forgotten" status of a message
|
|
469
|
+
*/
|
|
470
|
+
async toggleForgottenMessage(sessionId, messageId, forgotten) {
|
|
471
|
+
await this.makeRequest('PATCH', `/api/chat/${sessionId}/messages/${messageId}/forgotten`, { forgotten });
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Merge multiple chat sessions into one
|
|
475
|
+
*/
|
|
476
|
+
async mergeChatSessions(request) {
|
|
477
|
+
return this.makeRequest('POST', '/api/chat/merge', request);
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Create a WebSocket client
|
|
481
|
+
*/
|
|
482
|
+
websocket(wsURL) {
|
|
483
|
+
return new WebSocketClient(wsURL, this.token);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
exports.EkoDBClient = EkoDBClient;
|
|
487
|
+
/**
|
|
488
|
+
* WebSocket client for real-time queries
|
|
489
|
+
*/
|
|
490
|
+
class WebSocketClient {
|
|
491
|
+
constructor(wsURL, token) {
|
|
492
|
+
this.ws = null;
|
|
493
|
+
this.wsURL = wsURL;
|
|
494
|
+
this.token = token;
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Connect to WebSocket
|
|
498
|
+
*/
|
|
499
|
+
async connect() {
|
|
500
|
+
if (this.ws)
|
|
501
|
+
return;
|
|
502
|
+
// Dynamic import for Node.js WebSocket
|
|
503
|
+
const WebSocket = (await Promise.resolve().then(() => __importStar(require('ws')))).default;
|
|
504
|
+
let url = this.wsURL;
|
|
505
|
+
if (!url.endsWith('/api/ws')) {
|
|
506
|
+
url += '/api/ws';
|
|
507
|
+
}
|
|
508
|
+
this.ws = new WebSocket(url, {
|
|
509
|
+
headers: {
|
|
510
|
+
'Authorization': `Bearer ${this.token}`,
|
|
511
|
+
},
|
|
512
|
+
});
|
|
513
|
+
return new Promise((resolve, reject) => {
|
|
514
|
+
this.ws.on('open', () => resolve());
|
|
515
|
+
this.ws.on('error', (err) => reject(err));
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Find all records in a collection via WebSocket
|
|
520
|
+
*/
|
|
521
|
+
async findAll(collection) {
|
|
522
|
+
await this.connect();
|
|
523
|
+
const messageId = Date.now().toString();
|
|
524
|
+
const request = {
|
|
525
|
+
type: 'FindAll',
|
|
526
|
+
messageId,
|
|
527
|
+
payload: { collection },
|
|
528
|
+
};
|
|
529
|
+
return new Promise((resolve, reject) => {
|
|
530
|
+
this.ws.send(JSON.stringify(request));
|
|
531
|
+
this.ws.once('message', (data) => {
|
|
532
|
+
const response = JSON.parse(data.toString());
|
|
533
|
+
if (response.type === 'Error') {
|
|
534
|
+
reject(new Error(response.message));
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
resolve(response.payload?.data || []);
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
this.ws.once('error', reject);
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Close the WebSocket connection
|
|
545
|
+
*/
|
|
546
|
+
close() {
|
|
547
|
+
if (this.ws) {
|
|
548
|
+
this.ws.close();
|
|
549
|
+
this.ws = null;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
exports.WebSocketClient = WebSocketClient;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { EkoDBClient, WebSocketClient, MergeStrategy, RateLimitError } from './client';
|
|
2
|
+
export { QueryBuilder, SortOrder } from './query-builder';
|
|
3
|
+
export { SearchQueryBuilder } from './search';
|
|
4
|
+
export { SchemaBuilder, FieldTypeSchemaBuilder, VectorIndexAlgorithm, DistanceMetric } from './schema';
|
|
5
|
+
export { JoinBuilder } from './join';
|
|
6
|
+
export type { SearchQuery, SearchResult, SearchResponse } from './search';
|
|
7
|
+
export type { Schema, FieldTypeSchema, IndexConfig, CollectionMetadata } from './schema';
|
|
8
|
+
export type { JoinConfig } from './join';
|
|
9
|
+
export type { Record, Query, BatchOperationResult, ClientConfig, RateLimitInfo, CollectionConfig, ChatRequest, CreateChatSessionRequest, ChatMessageRequest, TokenUsage, ChatResponse, ChatSession, ChatSessionResponse, ListSessionsQuery, ListSessionsResponse, GetMessagesQuery, GetMessagesResponse, UpdateSessionRequest, MergeSessionsRequest } from './client';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.JoinBuilder = exports.DistanceMetric = exports.VectorIndexAlgorithm = exports.FieldTypeSchemaBuilder = exports.SchemaBuilder = exports.SearchQueryBuilder = exports.SortOrder = exports.QueryBuilder = exports.RateLimitError = exports.MergeStrategy = exports.WebSocketClient = exports.EkoDBClient = void 0;
|
|
4
|
+
var client_1 = require("./client");
|
|
5
|
+
Object.defineProperty(exports, "EkoDBClient", { enumerable: true, get: function () { return client_1.EkoDBClient; } });
|
|
6
|
+
Object.defineProperty(exports, "WebSocketClient", { enumerable: true, get: function () { return client_1.WebSocketClient; } });
|
|
7
|
+
Object.defineProperty(exports, "MergeStrategy", { enumerable: true, get: function () { return client_1.MergeStrategy; } });
|
|
8
|
+
Object.defineProperty(exports, "RateLimitError", { enumerable: true, get: function () { return client_1.RateLimitError; } });
|
|
9
|
+
var query_builder_1 = require("./query-builder");
|
|
10
|
+
Object.defineProperty(exports, "QueryBuilder", { enumerable: true, get: function () { return query_builder_1.QueryBuilder; } });
|
|
11
|
+
Object.defineProperty(exports, "SortOrder", { enumerable: true, get: function () { return query_builder_1.SortOrder; } });
|
|
12
|
+
var search_1 = require("./search");
|
|
13
|
+
Object.defineProperty(exports, "SearchQueryBuilder", { enumerable: true, get: function () { return search_1.SearchQueryBuilder; } });
|
|
14
|
+
var schema_1 = require("./schema");
|
|
15
|
+
Object.defineProperty(exports, "SchemaBuilder", { enumerable: true, get: function () { return schema_1.SchemaBuilder; } });
|
|
16
|
+
Object.defineProperty(exports, "FieldTypeSchemaBuilder", { enumerable: true, get: function () { return schema_1.FieldTypeSchemaBuilder; } });
|
|
17
|
+
Object.defineProperty(exports, "VectorIndexAlgorithm", { enumerable: true, get: function () { return schema_1.VectorIndexAlgorithm; } });
|
|
18
|
+
Object.defineProperty(exports, "DistanceMetric", { enumerable: true, get: function () { return schema_1.DistanceMetric; } });
|
|
19
|
+
var join_1 = require("./join");
|
|
20
|
+
Object.defineProperty(exports, "JoinBuilder", { enumerable: true, get: function () { return join_1.JoinBuilder; } });
|
package/dist/join.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Join support for multi-collection queries
|
|
3
|
+
*
|
|
4
|
+
* This module provides support for joining data across multiple collections,
|
|
5
|
+
* similar to SQL joins but with document-oriented semantics.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Configuration for joining collections
|
|
9
|
+
*/
|
|
10
|
+
export interface JoinConfig {
|
|
11
|
+
/** Target collections to join with */
|
|
12
|
+
collections: string[];
|
|
13
|
+
/** Field in the current collection */
|
|
14
|
+
local_field: string;
|
|
15
|
+
/** Field in the target collection(s) */
|
|
16
|
+
foreign_field: string;
|
|
17
|
+
/** Name of the field to store joined data */
|
|
18
|
+
as_field: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Builder for constructing join configurations
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* // Single collection join
|
|
26
|
+
* const join = JoinBuilder.single("users", "user_id", "id", "user");
|
|
27
|
+
*
|
|
28
|
+
* // Multi-collection join
|
|
29
|
+
* const join = JoinBuilder.multi(
|
|
30
|
+
* ["users", "profiles", "settings"],
|
|
31
|
+
* "user_id",
|
|
32
|
+
* "id",
|
|
33
|
+
* "user_info"
|
|
34
|
+
* );
|
|
35
|
+
*
|
|
36
|
+
* // Use in query
|
|
37
|
+
* const query = new QueryBuilder()
|
|
38
|
+
* .eq("status", "active")
|
|
39
|
+
* .join(join)
|
|
40
|
+
* .build();
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare class JoinBuilder {
|
|
44
|
+
private config;
|
|
45
|
+
private constructor();
|
|
46
|
+
/**
|
|
47
|
+
* Create a join with a single collection
|
|
48
|
+
*
|
|
49
|
+
* @param collection - Target collection name
|
|
50
|
+
* @param localField - Field in the current collection
|
|
51
|
+
* @param foreignField - Field in the target collection
|
|
52
|
+
* @param asField - Name of the field to store joined data
|
|
53
|
+
*/
|
|
54
|
+
static single(collection: string, localField: string, foreignField: string, asField: string): JoinConfig;
|
|
55
|
+
/**
|
|
56
|
+
* Create a join with multiple collections
|
|
57
|
+
*
|
|
58
|
+
* @param collections - Array of target collection names
|
|
59
|
+
* @param localField - Field in the current collection
|
|
60
|
+
* @param foreignField - Field in the target collections
|
|
61
|
+
* @param asField - Name of the field to store joined data
|
|
62
|
+
*/
|
|
63
|
+
static multi(collections: string[], localField: string, foreignField: string, asField: string): JoinConfig;
|
|
64
|
+
/**
|
|
65
|
+
* Build the final JoinConfig
|
|
66
|
+
*/
|
|
67
|
+
build(): JoinConfig;
|
|
68
|
+
}
|