@ekodb/ekodb-client 0.1.0 → 0.1.7
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 +7 -1
- package/dist/client.d.ts +3 -3
- package/dist/client.js +74 -66
- package/dist/index.d.ts +9 -9
- package/dist/schema.js +2 -1
- package/package.json +1 -1
- package/src/client.ts +241 -115
- package/src/index.ts +28 -13
- package/src/join.ts +21 -11
- package/src/query-builder.ts +1 -1
- package/src/schema.ts +12 -8
- package/src/search.ts +5 -5
package/src/client.ts
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* ekoDB TypeScript Client
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { QueryBuilder, Query as QueryBuilderQuery } from
|
|
6
|
-
import { SearchQuery, SearchQueryBuilder, SearchResponse } from
|
|
7
|
-
import { Schema, SchemaBuilder, CollectionMetadata } from
|
|
5
|
+
import { QueryBuilder, Query as QueryBuilderQuery } from "./query-builder";
|
|
6
|
+
import { SearchQuery, SearchQueryBuilder, SearchResponse } from "./search";
|
|
7
|
+
import { Schema, SchemaBuilder, CollectionMetadata } from "./schema";
|
|
8
8
|
|
|
9
9
|
export interface Record {
|
|
10
10
|
[key: string]: any;
|
|
@@ -42,9 +42,14 @@ export interface ClientConfig {
|
|
|
42
42
|
* Rate limit error
|
|
43
43
|
*/
|
|
44
44
|
export class RateLimitError extends Error {
|
|
45
|
-
constructor(
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
constructor(
|
|
46
|
+
public retryAfterSecs: number,
|
|
47
|
+
message?: string,
|
|
48
|
+
) {
|
|
49
|
+
super(
|
|
50
|
+
message || `Rate limit exceeded. Retry after ${retryAfterSecs} seconds`,
|
|
51
|
+
);
|
|
52
|
+
this.name = "RateLimitError";
|
|
48
53
|
}
|
|
49
54
|
}
|
|
50
55
|
|
|
@@ -161,9 +166,9 @@ export interface UpdateSessionRequest {
|
|
|
161
166
|
}
|
|
162
167
|
|
|
163
168
|
export enum MergeStrategy {
|
|
164
|
-
Chronological =
|
|
165
|
-
Summarized =
|
|
166
|
-
LatestOnly =
|
|
169
|
+
Chronological = "Chronological",
|
|
170
|
+
Summarized = "Summarized",
|
|
171
|
+
LatestOnly = "LatestOnly",
|
|
167
172
|
}
|
|
168
173
|
|
|
169
174
|
export interface MergeSessionsRequest {
|
|
@@ -183,7 +188,7 @@ export class EkoDBClient {
|
|
|
183
188
|
|
|
184
189
|
constructor(config: string | ClientConfig, apiKey?: string) {
|
|
185
190
|
// Support both old (baseURL, apiKey) and new (config object) signatures
|
|
186
|
-
if (typeof config ===
|
|
191
|
+
if (typeof config === "string") {
|
|
187
192
|
this.baseURL = config;
|
|
188
193
|
this.apiKey = apiKey!;
|
|
189
194
|
this.shouldRetry = true;
|
|
@@ -226,8 +231,8 @@ export class EkoDBClient {
|
|
|
226
231
|
*/
|
|
227
232
|
private async refreshToken(): Promise<void> {
|
|
228
233
|
const response = await fetch(`${this.baseURL}/api/auth/token`, {
|
|
229
|
-
method:
|
|
230
|
-
headers: {
|
|
234
|
+
method: "POST",
|
|
235
|
+
headers: { "Content-Type": "application/json" },
|
|
231
236
|
body: JSON.stringify({ api_key: this.apiKey }),
|
|
232
237
|
});
|
|
233
238
|
|
|
@@ -235,7 +240,7 @@ export class EkoDBClient {
|
|
|
235
240
|
throw new Error(`Auth failed with status: ${response.status}`);
|
|
236
241
|
}
|
|
237
242
|
|
|
238
|
-
const result = await response.json() as { token: string };
|
|
243
|
+
const result = (await response.json()) as { token: string };
|
|
239
244
|
this.token = result.token;
|
|
240
245
|
}
|
|
241
246
|
|
|
@@ -243,9 +248,9 @@ export class EkoDBClient {
|
|
|
243
248
|
* Extract rate limit information from response headers
|
|
244
249
|
*/
|
|
245
250
|
private extractRateLimitInfo(response: Response): void {
|
|
246
|
-
const limit = response.headers.get(
|
|
247
|
-
const remaining = response.headers.get(
|
|
248
|
-
const reset = response.headers.get(
|
|
251
|
+
const limit = response.headers.get("x-ratelimit-limit");
|
|
252
|
+
const remaining = response.headers.get("x-ratelimit-remaining");
|
|
253
|
+
const reset = response.headers.get("x-ratelimit-reset");
|
|
249
254
|
|
|
250
255
|
if (limit && remaining && reset) {
|
|
251
256
|
this.rateLimitInfo = {
|
|
@@ -257,7 +262,7 @@ export class EkoDBClient {
|
|
|
257
262
|
// Log warning if approaching rate limit
|
|
258
263
|
if (this.isNearRateLimit()) {
|
|
259
264
|
console.warn(
|
|
260
|
-
`Approaching rate limit: ${this.rateLimitInfo.remaining}/${this.rateLimitInfo.limit} remaining
|
|
265
|
+
`Approaching rate limit: ${this.rateLimitInfo.remaining}/${this.rateLimitInfo.limit} remaining`,
|
|
261
266
|
);
|
|
262
267
|
}
|
|
263
268
|
}
|
|
@@ -267,7 +272,7 @@ export class EkoDBClient {
|
|
|
267
272
|
* Sleep for a specified number of seconds
|
|
268
273
|
*/
|
|
269
274
|
private sleep(seconds: number): Promise<void> {
|
|
270
|
-
return new Promise(resolve => setTimeout(resolve, seconds * 1000));
|
|
275
|
+
return new Promise((resolve) => setTimeout(resolve, seconds * 1000));
|
|
271
276
|
}
|
|
272
277
|
|
|
273
278
|
/**
|
|
@@ -277,7 +282,7 @@ export class EkoDBClient {
|
|
|
277
282
|
method: string,
|
|
278
283
|
path: string,
|
|
279
284
|
data?: any,
|
|
280
|
-
attempt: number = 0
|
|
285
|
+
attempt: number = 0,
|
|
281
286
|
): Promise<T> {
|
|
282
287
|
if (!this.token) {
|
|
283
288
|
await this.refreshToken();
|
|
@@ -286,8 +291,8 @@ export class EkoDBClient {
|
|
|
286
291
|
const options: RequestInit = {
|
|
287
292
|
method,
|
|
288
293
|
headers: {
|
|
289
|
-
|
|
290
|
-
|
|
294
|
+
Authorization: `Bearer ${this.token}`,
|
|
295
|
+
"Content-Type": "application/json",
|
|
291
296
|
},
|
|
292
297
|
};
|
|
293
298
|
|
|
@@ -306,21 +311,30 @@ export class EkoDBClient {
|
|
|
306
311
|
|
|
307
312
|
// Handle rate limiting (429)
|
|
308
313
|
if (response.status === 429) {
|
|
309
|
-
const retryAfter = parseInt(
|
|
310
|
-
|
|
314
|
+
const retryAfter = parseInt(
|
|
315
|
+
response.headers.get("retry-after") || "60",
|
|
316
|
+
10,
|
|
317
|
+
);
|
|
318
|
+
|
|
311
319
|
if (this.shouldRetry && attempt < this.maxRetries) {
|
|
312
320
|
console.log(`Rate limited. Retrying after ${retryAfter} seconds...`);
|
|
313
321
|
await this.sleep(retryAfter);
|
|
314
322
|
return this.makeRequest<T>(method, path, data, attempt + 1);
|
|
315
323
|
}
|
|
316
|
-
|
|
324
|
+
|
|
317
325
|
throw new RateLimitError(retryAfter);
|
|
318
326
|
}
|
|
319
327
|
|
|
320
328
|
// Handle service unavailable (503)
|
|
321
|
-
if (
|
|
329
|
+
if (
|
|
330
|
+
response.status === 503 &&
|
|
331
|
+
this.shouldRetry &&
|
|
332
|
+
attempt < this.maxRetries
|
|
333
|
+
) {
|
|
322
334
|
const retryDelay = 10;
|
|
323
|
-
console.log(
|
|
335
|
+
console.log(
|
|
336
|
+
`Service unavailable. Retrying after ${retryDelay} seconds...`,
|
|
337
|
+
);
|
|
324
338
|
await this.sleep(retryDelay);
|
|
325
339
|
return this.makeRequest<T>(method, path, data, attempt + 1);
|
|
326
340
|
}
|
|
@@ -330,13 +344,17 @@ export class EkoDBClient {
|
|
|
330
344
|
throw new Error(`Request failed with status ${response.status}: ${text}`);
|
|
331
345
|
} catch (error) {
|
|
332
346
|
// Handle network errors with retry
|
|
333
|
-
if (
|
|
347
|
+
if (
|
|
348
|
+
error instanceof TypeError &&
|
|
349
|
+
this.shouldRetry &&
|
|
350
|
+
attempt < this.maxRetries
|
|
351
|
+
) {
|
|
334
352
|
const retryDelay = 3;
|
|
335
353
|
console.log(`Network error. Retrying after ${retryDelay} seconds...`);
|
|
336
354
|
await this.sleep(retryDelay);
|
|
337
355
|
return this.makeRequest<T>(method, path, data, attempt + 1);
|
|
338
356
|
}
|
|
339
|
-
|
|
357
|
+
|
|
340
358
|
throw error;
|
|
341
359
|
}
|
|
342
360
|
}
|
|
@@ -344,73 +362,92 @@ export class EkoDBClient {
|
|
|
344
362
|
/**
|
|
345
363
|
* Insert a document into a collection
|
|
346
364
|
*/
|
|
347
|
-
async insert(
|
|
365
|
+
async insert(
|
|
366
|
+
collection: string,
|
|
367
|
+
record: Record,
|
|
368
|
+
ttl?: string,
|
|
369
|
+
): Promise<Record> {
|
|
348
370
|
const data = { ...record };
|
|
349
371
|
if (ttl) {
|
|
350
372
|
data.ttl_duration = ttl;
|
|
351
373
|
}
|
|
352
|
-
return this.makeRequest<Record>(
|
|
374
|
+
return this.makeRequest<Record>("POST", `/api/insert/${collection}`, data);
|
|
353
375
|
}
|
|
354
376
|
|
|
355
377
|
/**
|
|
356
378
|
* Find documents in a collection
|
|
357
|
-
*
|
|
379
|
+
*
|
|
358
380
|
* @param collection - Collection name
|
|
359
381
|
* @param query - Query object or QueryBuilder instance
|
|
360
382
|
* @returns Array of matching records
|
|
361
|
-
*
|
|
383
|
+
*
|
|
362
384
|
* @example
|
|
363
385
|
* ```typescript
|
|
364
386
|
* // Using QueryBuilder
|
|
365
|
-
* const results = await client.find("users",
|
|
387
|
+
* const results = await client.find("users",
|
|
366
388
|
* new QueryBuilder()
|
|
367
389
|
* .eq("status", "active")
|
|
368
390
|
* .gt("age", 18)
|
|
369
391
|
* .sortDesc("created_at")
|
|
370
392
|
* .limit(10)
|
|
371
393
|
* );
|
|
372
|
-
*
|
|
394
|
+
*
|
|
373
395
|
* // Using plain Query object
|
|
374
396
|
* const results = await client.find("users", { limit: 10 });
|
|
375
397
|
* ```
|
|
376
398
|
*/
|
|
377
|
-
async find(
|
|
399
|
+
async find(
|
|
400
|
+
collection: string,
|
|
401
|
+
query: Query | QueryBuilder = {},
|
|
402
|
+
): Promise<Record[]> {
|
|
378
403
|
const queryObj = query instanceof QueryBuilder ? query.build() : query;
|
|
379
|
-
return this.makeRequest<Record[]>(
|
|
404
|
+
return this.makeRequest<Record[]>(
|
|
405
|
+
"POST",
|
|
406
|
+
`/api/find/${collection}`,
|
|
407
|
+
queryObj,
|
|
408
|
+
);
|
|
380
409
|
}
|
|
381
410
|
|
|
382
411
|
/**
|
|
383
412
|
* Find a document by ID
|
|
384
413
|
*/
|
|
385
414
|
async findByID(collection: string, id: string): Promise<Record> {
|
|
386
|
-
return this.makeRequest<Record>(
|
|
415
|
+
return this.makeRequest<Record>("GET", `/api/find/${collection}/${id}`);
|
|
387
416
|
}
|
|
388
417
|
|
|
389
418
|
/**
|
|
390
419
|
* Update a document
|
|
391
420
|
*/
|
|
392
|
-
async update(
|
|
393
|
-
|
|
421
|
+
async update(
|
|
422
|
+
collection: string,
|
|
423
|
+
id: string,
|
|
424
|
+
record: Record,
|
|
425
|
+
): Promise<Record> {
|
|
426
|
+
return this.makeRequest<Record>(
|
|
427
|
+
"PUT",
|
|
428
|
+
`/api/update/${collection}/${id}`,
|
|
429
|
+
record,
|
|
430
|
+
);
|
|
394
431
|
}
|
|
395
432
|
|
|
396
433
|
/**
|
|
397
434
|
* Delete a document
|
|
398
435
|
*/
|
|
399
436
|
async delete(collection: string, id: string): Promise<void> {
|
|
400
|
-
await this.makeRequest<void>(
|
|
437
|
+
await this.makeRequest<void>("DELETE", `/api/delete/${collection}/${id}`);
|
|
401
438
|
}
|
|
402
439
|
|
|
403
440
|
/**
|
|
404
441
|
* Batch insert multiple documents
|
|
405
442
|
*/
|
|
406
443
|
async batchInsert(collection: string, records: Record[]): Promise<Record[]> {
|
|
407
|
-
const inserts = records.map(data => ({ data }));
|
|
444
|
+
const inserts = records.map((data) => ({ data }));
|
|
408
445
|
const result = await this.makeRequest<BatchOperationResult>(
|
|
409
|
-
|
|
446
|
+
"POST",
|
|
410
447
|
`/api/batch/insert/${collection}`,
|
|
411
|
-
{ inserts }
|
|
448
|
+
{ inserts },
|
|
412
449
|
);
|
|
413
|
-
return result.successful.map(id => ({ id }));
|
|
450
|
+
return result.successful.map((id) => ({ id }));
|
|
414
451
|
}
|
|
415
452
|
|
|
416
453
|
/**
|
|
@@ -418,25 +455,25 @@ export class EkoDBClient {
|
|
|
418
455
|
*/
|
|
419
456
|
async batchUpdate(
|
|
420
457
|
collection: string,
|
|
421
|
-
updates: Array<{ id: string; data: Record }
|
|
458
|
+
updates: Array<{ id: string; data: Record }>,
|
|
422
459
|
): Promise<Record[]> {
|
|
423
460
|
const result = await this.makeRequest<BatchOperationResult>(
|
|
424
|
-
|
|
461
|
+
"PUT",
|
|
425
462
|
`/api/batch/update/${collection}`,
|
|
426
|
-
{ updates }
|
|
463
|
+
{ updates },
|
|
427
464
|
);
|
|
428
|
-
return result.successful.map(id => ({ id }));
|
|
465
|
+
return result.successful.map((id) => ({ id }));
|
|
429
466
|
}
|
|
430
467
|
|
|
431
468
|
/**
|
|
432
469
|
* Batch delete multiple documents
|
|
433
470
|
*/
|
|
434
471
|
async batchDelete(collection: string, ids: string[]): Promise<number> {
|
|
435
|
-
const deletes = ids.map(id => ({ id }));
|
|
472
|
+
const deletes = ids.map((id) => ({ id }));
|
|
436
473
|
const result = await this.makeRequest<BatchOperationResult>(
|
|
437
|
-
|
|
474
|
+
"DELETE",
|
|
438
475
|
`/api/batch/delete/${collection}`,
|
|
439
|
-
{ deletes }
|
|
476
|
+
{ deletes },
|
|
440
477
|
);
|
|
441
478
|
return result.successful.length;
|
|
442
479
|
}
|
|
@@ -445,7 +482,11 @@ export class EkoDBClient {
|
|
|
445
482
|
* Set a key-value pair
|
|
446
483
|
*/
|
|
447
484
|
async kvSet(key: string, value: any): Promise<void> {
|
|
448
|
-
await this.makeRequest<void>(
|
|
485
|
+
await this.makeRequest<void>(
|
|
486
|
+
"POST",
|
|
487
|
+
`/api/kv/set/${encodeURIComponent(key)}`,
|
|
488
|
+
{ value },
|
|
489
|
+
);
|
|
449
490
|
}
|
|
450
491
|
|
|
451
492
|
/**
|
|
@@ -453,8 +494,8 @@ export class EkoDBClient {
|
|
|
453
494
|
*/
|
|
454
495
|
async kvGet(key: string): Promise<any> {
|
|
455
496
|
const result = await this.makeRequest<{ value: any }>(
|
|
456
|
-
|
|
457
|
-
`/api/kv/get/${encodeURIComponent(key)}
|
|
497
|
+
"GET",
|
|
498
|
+
`/api/kv/get/${encodeURIComponent(key)}`,
|
|
458
499
|
);
|
|
459
500
|
return result.value;
|
|
460
501
|
}
|
|
@@ -463,14 +504,20 @@ export class EkoDBClient {
|
|
|
463
504
|
* Delete a key
|
|
464
505
|
*/
|
|
465
506
|
async kvDelete(key: string): Promise<void> {
|
|
466
|
-
await this.makeRequest<void>(
|
|
507
|
+
await this.makeRequest<void>(
|
|
508
|
+
"DELETE",
|
|
509
|
+
`/api/kv/delete/${encodeURIComponent(key)}`,
|
|
510
|
+
);
|
|
467
511
|
}
|
|
468
512
|
|
|
469
513
|
/**
|
|
470
514
|
* List all collections
|
|
471
515
|
*/
|
|
472
516
|
async listCollections(): Promise<string[]> {
|
|
473
|
-
const result = await this.makeRequest<{ collections: string[] }>(
|
|
517
|
+
const result = await this.makeRequest<{ collections: string[] }>(
|
|
518
|
+
"GET",
|
|
519
|
+
"/api/collections",
|
|
520
|
+
);
|
|
474
521
|
return result.collections;
|
|
475
522
|
}
|
|
476
523
|
|
|
@@ -478,43 +525,53 @@ export class EkoDBClient {
|
|
|
478
525
|
* Delete a collection
|
|
479
526
|
*/
|
|
480
527
|
async deleteCollection(collection: string): Promise<void> {
|
|
481
|
-
await this.makeRequest<void>(
|
|
528
|
+
await this.makeRequest<void>("DELETE", `/api/collections/${collection}`);
|
|
482
529
|
}
|
|
483
530
|
|
|
484
531
|
/**
|
|
485
532
|
* Create a collection with schema
|
|
486
|
-
*
|
|
533
|
+
*
|
|
487
534
|
* @param collection - Collection name
|
|
488
535
|
* @param schema - Schema definition or SchemaBuilder instance
|
|
489
|
-
*
|
|
536
|
+
*
|
|
490
537
|
* @example
|
|
491
538
|
* ```typescript
|
|
492
539
|
* const schema = new SchemaBuilder()
|
|
493
540
|
* .addField("name", new FieldTypeSchemaBuilder("string").required())
|
|
494
541
|
* .addField("email", new FieldTypeSchemaBuilder("string").unique())
|
|
495
542
|
* .addField("age", new FieldTypeSchemaBuilder("number").range(0, 150));
|
|
496
|
-
*
|
|
543
|
+
*
|
|
497
544
|
* await client.createCollection("users", schema);
|
|
498
545
|
* ```
|
|
499
546
|
*/
|
|
500
|
-
async createCollection(
|
|
547
|
+
async createCollection(
|
|
548
|
+
collection: string,
|
|
549
|
+
schema: Schema | SchemaBuilder,
|
|
550
|
+
): Promise<void> {
|
|
501
551
|
const schemaObj = schema instanceof SchemaBuilder ? schema.build() : schema;
|
|
502
|
-
await this.makeRequest<void>(
|
|
552
|
+
await this.makeRequest<void>(
|
|
553
|
+
"POST",
|
|
554
|
+
`/api/collections/${collection}`,
|
|
555
|
+
schemaObj,
|
|
556
|
+
);
|
|
503
557
|
}
|
|
504
558
|
|
|
505
559
|
/**
|
|
506
560
|
* Get collection metadata and schema
|
|
507
|
-
*
|
|
561
|
+
*
|
|
508
562
|
* @param collection - Collection name
|
|
509
563
|
* @returns Collection metadata including schema and analytics
|
|
510
564
|
*/
|
|
511
565
|
async getCollection(collection: string): Promise<CollectionMetadata> {
|
|
512
|
-
return this.makeRequest<CollectionMetadata>(
|
|
566
|
+
return this.makeRequest<CollectionMetadata>(
|
|
567
|
+
"GET",
|
|
568
|
+
`/api/collections/${collection}`,
|
|
569
|
+
);
|
|
513
570
|
}
|
|
514
571
|
|
|
515
572
|
/**
|
|
516
573
|
* Get collection schema
|
|
517
|
-
*
|
|
574
|
+
*
|
|
518
575
|
* @param collection - Collection name
|
|
519
576
|
* @returns The collection schema
|
|
520
577
|
*/
|
|
@@ -525,11 +582,11 @@ export class EkoDBClient {
|
|
|
525
582
|
|
|
526
583
|
/**
|
|
527
584
|
* Search documents in a collection using full-text, vector, or hybrid search
|
|
528
|
-
*
|
|
585
|
+
*
|
|
529
586
|
* @param collection - Collection name
|
|
530
587
|
* @param searchQuery - Search query object or SearchQueryBuilder instance
|
|
531
588
|
* @returns Search response with results and metadata
|
|
532
|
-
*
|
|
589
|
+
*
|
|
533
590
|
* @example
|
|
534
591
|
* ```typescript
|
|
535
592
|
* // Full-text search
|
|
@@ -539,14 +596,14 @@ export class EkoDBClient {
|
|
|
539
596
|
* .fuzzy(true)
|
|
540
597
|
* .limit(10)
|
|
541
598
|
* );
|
|
542
|
-
*
|
|
599
|
+
*
|
|
543
600
|
* // Vector search
|
|
544
601
|
* const results = await client.search("documents",
|
|
545
602
|
* new SearchQueryBuilder("")
|
|
546
603
|
* .vector([0.1, 0.2, 0.3, ...])
|
|
547
604
|
* .vectorK(5)
|
|
548
605
|
* );
|
|
549
|
-
*
|
|
606
|
+
*
|
|
550
607
|
* // Hybrid search
|
|
551
608
|
* const results = await client.search("products",
|
|
552
609
|
* new SearchQueryBuilder("laptop")
|
|
@@ -556,9 +613,19 @@ export class EkoDBClient {
|
|
|
556
613
|
* );
|
|
557
614
|
* ```
|
|
558
615
|
*/
|
|
559
|
-
async search(
|
|
560
|
-
|
|
561
|
-
|
|
616
|
+
async search(
|
|
617
|
+
collection: string,
|
|
618
|
+
searchQuery: SearchQuery | SearchQueryBuilder,
|
|
619
|
+
): Promise<SearchResponse> {
|
|
620
|
+
const queryObj =
|
|
621
|
+
searchQuery instanceof SearchQueryBuilder
|
|
622
|
+
? searchQuery.build()
|
|
623
|
+
: searchQuery;
|
|
624
|
+
return this.makeRequest<SearchResponse>(
|
|
625
|
+
"POST",
|
|
626
|
+
`/api/search/${collection}`,
|
|
627
|
+
queryObj,
|
|
628
|
+
);
|
|
562
629
|
}
|
|
563
630
|
|
|
564
631
|
// ========== Chat Methods ==========
|
|
@@ -566,106 +633,165 @@ export class EkoDBClient {
|
|
|
566
633
|
/**
|
|
567
634
|
* Create a new chat session
|
|
568
635
|
*/
|
|
569
|
-
async createChatSession(
|
|
570
|
-
|
|
636
|
+
async createChatSession(
|
|
637
|
+
request: CreateChatSessionRequest,
|
|
638
|
+
): Promise<ChatResponse> {
|
|
639
|
+
return this.makeRequest<ChatResponse>("POST", "/api/chat", request);
|
|
571
640
|
}
|
|
572
641
|
|
|
573
642
|
/**
|
|
574
643
|
* Send a message in an existing chat session
|
|
575
644
|
*/
|
|
576
|
-
async chatMessage(
|
|
577
|
-
|
|
645
|
+
async chatMessage(
|
|
646
|
+
sessionId: string,
|
|
647
|
+
request: ChatMessageRequest,
|
|
648
|
+
): Promise<ChatResponse> {
|
|
649
|
+
return this.makeRequest<ChatResponse>(
|
|
650
|
+
"POST",
|
|
651
|
+
`/api/chat/${sessionId}/messages`,
|
|
652
|
+
request,
|
|
653
|
+
);
|
|
578
654
|
}
|
|
579
655
|
|
|
580
656
|
/**
|
|
581
657
|
* Get a chat session by ID
|
|
582
658
|
*/
|
|
583
659
|
async getChatSession(sessionId: string): Promise<ChatSessionResponse> {
|
|
584
|
-
return this.makeRequest<ChatSessionResponse>(
|
|
660
|
+
return this.makeRequest<ChatSessionResponse>(
|
|
661
|
+
"GET",
|
|
662
|
+
`/api/chat/${sessionId}`,
|
|
663
|
+
);
|
|
585
664
|
}
|
|
586
665
|
|
|
587
666
|
/**
|
|
588
667
|
* List all chat sessions
|
|
589
668
|
*/
|
|
590
|
-
async listChatSessions(
|
|
669
|
+
async listChatSessions(
|
|
670
|
+
query?: ListSessionsQuery,
|
|
671
|
+
): Promise<ListSessionsResponse> {
|
|
591
672
|
const params = new URLSearchParams();
|
|
592
|
-
if (query?.limit) params.append(
|
|
593
|
-
if (query?.skip) params.append(
|
|
594
|
-
if (query?.sort) params.append(
|
|
595
|
-
|
|
673
|
+
if (query?.limit) params.append("limit", query.limit.toString());
|
|
674
|
+
if (query?.skip) params.append("skip", query.skip.toString());
|
|
675
|
+
if (query?.sort) params.append("sort", query.sort);
|
|
676
|
+
|
|
596
677
|
const queryString = params.toString();
|
|
597
|
-
const path = queryString ? `/api/chat?${queryString}` :
|
|
598
|
-
return this.makeRequest<ListSessionsResponse>(
|
|
678
|
+
const path = queryString ? `/api/chat?${queryString}` : "/api/chat";
|
|
679
|
+
return this.makeRequest<ListSessionsResponse>("GET", path);
|
|
599
680
|
}
|
|
600
681
|
|
|
601
682
|
/**
|
|
602
683
|
* Get messages from a chat session
|
|
603
684
|
*/
|
|
604
|
-
async getChatSessionMessages(
|
|
685
|
+
async getChatSessionMessages(
|
|
686
|
+
sessionId: string,
|
|
687
|
+
query?: GetMessagesQuery,
|
|
688
|
+
): Promise<GetMessagesResponse> {
|
|
605
689
|
const params = new URLSearchParams();
|
|
606
|
-
if (query?.limit) params.append(
|
|
607
|
-
if (query?.skip) params.append(
|
|
608
|
-
if (query?.sort) params.append(
|
|
609
|
-
|
|
690
|
+
if (query?.limit) params.append("limit", query.limit.toString());
|
|
691
|
+
if (query?.skip) params.append("skip", query.skip.toString());
|
|
692
|
+
if (query?.sort) params.append("sort", query.sort);
|
|
693
|
+
|
|
610
694
|
const queryString = params.toString();
|
|
611
|
-
const path = queryString
|
|
612
|
-
|
|
695
|
+
const path = queryString
|
|
696
|
+
? `/api/chat/${sessionId}/messages?${queryString}`
|
|
697
|
+
: `/api/chat/${sessionId}/messages`;
|
|
698
|
+
return this.makeRequest<GetMessagesResponse>("GET", path);
|
|
613
699
|
}
|
|
614
700
|
|
|
615
701
|
/**
|
|
616
702
|
* Update a chat session
|
|
617
703
|
*/
|
|
618
|
-
async updateChatSession(
|
|
619
|
-
|
|
704
|
+
async updateChatSession(
|
|
705
|
+
sessionId: string,
|
|
706
|
+
request: UpdateSessionRequest,
|
|
707
|
+
): Promise<ChatSessionResponse> {
|
|
708
|
+
return this.makeRequest<ChatSessionResponse>(
|
|
709
|
+
"PUT",
|
|
710
|
+
`/api/chat/${sessionId}`,
|
|
711
|
+
request,
|
|
712
|
+
);
|
|
620
713
|
}
|
|
621
714
|
|
|
622
715
|
/**
|
|
623
716
|
* Branch a chat session
|
|
624
717
|
*/
|
|
625
|
-
async branchChatSession(
|
|
626
|
-
|
|
718
|
+
async branchChatSession(
|
|
719
|
+
request: CreateChatSessionRequest,
|
|
720
|
+
): Promise<ChatResponse> {
|
|
721
|
+
return this.makeRequest<ChatResponse>("POST", "/api/chat/branch", request);
|
|
627
722
|
}
|
|
628
723
|
|
|
629
724
|
/**
|
|
630
725
|
* Delete a chat session
|
|
631
726
|
*/
|
|
632
727
|
async deleteChatSession(sessionId: string): Promise<void> {
|
|
633
|
-
await this.makeRequest<void>(
|
|
728
|
+
await this.makeRequest<void>("DELETE", `/api/chat/${sessionId}`);
|
|
634
729
|
}
|
|
635
730
|
|
|
636
731
|
/**
|
|
637
732
|
* Regenerate an AI response message
|
|
638
733
|
*/
|
|
639
|
-
async regenerateMessage(
|
|
640
|
-
|
|
734
|
+
async regenerateMessage(
|
|
735
|
+
sessionId: string,
|
|
736
|
+
messageId: string,
|
|
737
|
+
): Promise<ChatResponse> {
|
|
738
|
+
return this.makeRequest<ChatResponse>(
|
|
739
|
+
"POST",
|
|
740
|
+
`/api/chat/${sessionId}/messages/${messageId}/regenerate`,
|
|
741
|
+
);
|
|
641
742
|
}
|
|
642
743
|
|
|
643
744
|
/**
|
|
644
745
|
* Update a specific message
|
|
645
746
|
*/
|
|
646
|
-
async updateChatMessage(
|
|
647
|
-
|
|
747
|
+
async updateChatMessage(
|
|
748
|
+
sessionId: string,
|
|
749
|
+
messageId: string,
|
|
750
|
+
content: string,
|
|
751
|
+
): Promise<void> {
|
|
752
|
+
await this.makeRequest<void>(
|
|
753
|
+
"PUT",
|
|
754
|
+
`/api/chat/${sessionId}/messages/${messageId}`,
|
|
755
|
+
{ content },
|
|
756
|
+
);
|
|
648
757
|
}
|
|
649
758
|
|
|
650
759
|
/**
|
|
651
760
|
* Delete a specific message
|
|
652
761
|
*/
|
|
653
762
|
async deleteChatMessage(sessionId: string, messageId: string): Promise<void> {
|
|
654
|
-
await this.makeRequest<void>(
|
|
763
|
+
await this.makeRequest<void>(
|
|
764
|
+
"DELETE",
|
|
765
|
+
`/api/chat/${sessionId}/messages/${messageId}`,
|
|
766
|
+
);
|
|
655
767
|
}
|
|
656
768
|
|
|
657
769
|
/**
|
|
658
770
|
* Toggle the "forgotten" status of a message
|
|
659
771
|
*/
|
|
660
|
-
async toggleForgottenMessage(
|
|
661
|
-
|
|
772
|
+
async toggleForgottenMessage(
|
|
773
|
+
sessionId: string,
|
|
774
|
+
messageId: string,
|
|
775
|
+
forgotten: boolean,
|
|
776
|
+
): Promise<void> {
|
|
777
|
+
await this.makeRequest<void>(
|
|
778
|
+
"PATCH",
|
|
779
|
+
`/api/chat/${sessionId}/messages/${messageId}/forgotten`,
|
|
780
|
+
{ forgotten },
|
|
781
|
+
);
|
|
662
782
|
}
|
|
663
783
|
|
|
664
784
|
/**
|
|
665
785
|
* Merge multiple chat sessions into one
|
|
666
786
|
*/
|
|
667
|
-
async mergeChatSessions(
|
|
668
|
-
|
|
787
|
+
async mergeChatSessions(
|
|
788
|
+
request: MergeSessionsRequest,
|
|
789
|
+
): Promise<ChatSessionResponse> {
|
|
790
|
+
return this.makeRequest<ChatSessionResponse>(
|
|
791
|
+
"POST",
|
|
792
|
+
"/api/chat/merge",
|
|
793
|
+
request,
|
|
794
|
+
);
|
|
669
795
|
}
|
|
670
796
|
|
|
671
797
|
/**
|
|
@@ -696,22 +822,22 @@ export class WebSocketClient {
|
|
|
696
822
|
if (this.ws) return;
|
|
697
823
|
|
|
698
824
|
// Dynamic import for Node.js WebSocket
|
|
699
|
-
const WebSocket = (await import(
|
|
825
|
+
const WebSocket = (await import("ws")).default;
|
|
700
826
|
|
|
701
827
|
let url = this.wsURL;
|
|
702
|
-
if (!url.endsWith(
|
|
703
|
-
url +=
|
|
828
|
+
if (!url.endsWith("/api/ws")) {
|
|
829
|
+
url += "/api/ws";
|
|
704
830
|
}
|
|
705
831
|
|
|
706
832
|
this.ws = new WebSocket(url, {
|
|
707
833
|
headers: {
|
|
708
|
-
|
|
834
|
+
Authorization: `Bearer ${this.token}`,
|
|
709
835
|
},
|
|
710
836
|
});
|
|
711
837
|
|
|
712
838
|
return new Promise((resolve, reject) => {
|
|
713
|
-
this.ws.on(
|
|
714
|
-
this.ws.on(
|
|
839
|
+
this.ws.on("open", () => resolve());
|
|
840
|
+
this.ws.on("error", (err: Error) => reject(err));
|
|
715
841
|
});
|
|
716
842
|
}
|
|
717
843
|
|
|
@@ -723,7 +849,7 @@ export class WebSocketClient {
|
|
|
723
849
|
|
|
724
850
|
const messageId = Date.now().toString();
|
|
725
851
|
const request = {
|
|
726
|
-
type:
|
|
852
|
+
type: "FindAll",
|
|
727
853
|
messageId,
|
|
728
854
|
payload: { collection },
|
|
729
855
|
};
|
|
@@ -731,17 +857,17 @@ export class WebSocketClient {
|
|
|
731
857
|
return new Promise((resolve, reject) => {
|
|
732
858
|
this.ws.send(JSON.stringify(request));
|
|
733
859
|
|
|
734
|
-
this.ws.once(
|
|
860
|
+
this.ws.once("message", (data: Buffer) => {
|
|
735
861
|
const response = JSON.parse(data.toString());
|
|
736
862
|
|
|
737
|
-
if (response.type ===
|
|
863
|
+
if (response.type === "Error") {
|
|
738
864
|
reject(new Error(response.message));
|
|
739
865
|
} else {
|
|
740
866
|
resolve(response.payload?.data || []);
|
|
741
867
|
}
|
|
742
868
|
});
|
|
743
869
|
|
|
744
|
-
this.ws.once(
|
|
870
|
+
this.ws.once("error", reject);
|
|
745
871
|
});
|
|
746
872
|
}
|
|
747
873
|
|