@ekodb/ekodb-client 0.4.0 → 0.5.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/dist/client.d.ts CHANGED
@@ -426,6 +426,89 @@ export declare class EkoDBClient {
426
426
  * Create a WebSocket client
427
427
  */
428
428
  websocket(wsURL: string): WebSocketClient;
429
+ /**
430
+ * Generate embeddings for text using ekoDB's native Functions
431
+ *
432
+ * This helper simplifies embedding generation by:
433
+ * 1. Creating a temporary collection with the text
434
+ * 2. Running a Script with FindAll + Embed Functions
435
+ * 3. Extracting and returning the embedding vector
436
+ * 4. Cleaning up temporary resources
437
+ *
438
+ * @param text - The text to generate embeddings for
439
+ * @param model - The embedding model to use (e.g., "text-embedding-3-small")
440
+ * @returns Array of floats representing the embedding vector
441
+ *
442
+ * @example
443
+ * ```typescript
444
+ * const embedding = await client.embed(
445
+ * "Hello world",
446
+ * "text-embedding-3-small"
447
+ * );
448
+ * console.log(`Generated ${embedding.length} dimensions`);
449
+ * ```
450
+ */
451
+ embed(text: string, model: string): Promise<number[]>;
452
+ /**
453
+ * Perform text search without embeddings
454
+ *
455
+ * Simplified text search with full-text matching, fuzzy search, and stemming.
456
+ *
457
+ * @param collection - Collection name to search
458
+ * @param queryText - Search query text
459
+ * @param limit - Maximum number of results to return
460
+ * @returns Array of matching records
461
+ *
462
+ * @example
463
+ * ```typescript
464
+ * const results = await client.textSearch(
465
+ * "documents",
466
+ * "ownership system",
467
+ * 10
468
+ * );
469
+ * ```
470
+ */
471
+ textSearch(collection: string, queryText: string, limit: number): Promise<Record[]>;
472
+ /**
473
+ * Perform hybrid search combining text and vector search
474
+ *
475
+ * Combines semantic similarity (vector search) with keyword matching (text search)
476
+ * for more accurate and relevant results.
477
+ *
478
+ * @param collection - Collection name to search
479
+ * @param queryText - Search query text
480
+ * @param queryVector - Embedding vector for semantic search
481
+ * @param limit - Maximum number of results to return
482
+ * @returns Array of matching records
483
+ *
484
+ * @example
485
+ * ```typescript
486
+ * const embedding = await client.embed(query, "text-embedding-3-small");
487
+ * const results = await client.hybridSearch(
488
+ * "documents",
489
+ * query,
490
+ * embedding,
491
+ * 5
492
+ * );
493
+ * ```
494
+ */
495
+ hybridSearch(collection: string, queryText: string, queryVector: number[], limit: number): Promise<Record[]>;
496
+ /**
497
+ * Find all records in a collection with a limit
498
+ *
499
+ * Simplified method to query all documents in a collection.
500
+ *
501
+ * @param collection - Collection name
502
+ * @param limit - Maximum number of records to return
503
+ * @returns Array of records
504
+ *
505
+ * @example
506
+ * ```typescript
507
+ * const allMessages = await client.findAll("messages", 1000);
508
+ * console.log(`Found ${allMessages.length} messages`);
509
+ * ```
510
+ */
511
+ findAllWithLimit(collection: string, limit: number): Promise<Record[]>;
429
512
  }
430
513
  /**
431
514
  * WebSocket client for real-time queries
package/dist/client.js CHANGED
@@ -228,6 +228,13 @@ class EkoDBClient {
228
228
  }
229
229
  throw new RateLimitError(retryAfter);
230
230
  }
231
+ // Handle unauthorized (401) - try refreshing token
232
+ if (response.status === 401 && attempt === 0) {
233
+ console.log("Authentication failed, refreshing token...");
234
+ await this.refreshToken();
235
+ // Retry with new token
236
+ return this.makeRequest(method, path, data, attempt + 1, forceJson);
237
+ }
231
238
  // Handle service unavailable (503)
232
239
  if (response.status === 503 &&
233
240
  this.shouldRetry &&
@@ -595,6 +602,156 @@ class EkoDBClient {
595
602
  websocket(wsURL) {
596
603
  return new WebSocketClient(wsURL, this.token);
597
604
  }
605
+ // ========== RAG Helper Methods ==========
606
+ /**
607
+ * Generate embeddings for text using ekoDB's native Functions
608
+ *
609
+ * This helper simplifies embedding generation by:
610
+ * 1. Creating a temporary collection with the text
611
+ * 2. Running a Script with FindAll + Embed Functions
612
+ * 3. Extracting and returning the embedding vector
613
+ * 4. Cleaning up temporary resources
614
+ *
615
+ * @param text - The text to generate embeddings for
616
+ * @param model - The embedding model to use (e.g., "text-embedding-3-small")
617
+ * @returns Array of floats representing the embedding vector
618
+ *
619
+ * @example
620
+ * ```typescript
621
+ * const embedding = await client.embed(
622
+ * "Hello world",
623
+ * "text-embedding-3-small"
624
+ * );
625
+ * console.log(`Generated ${embedding.length} dimensions`);
626
+ * ```
627
+ */
628
+ async embed(text, model) {
629
+ const tempCollection = `embed_temp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
630
+ try {
631
+ // Insert temporary record with the text
632
+ await this.insert(tempCollection, { text }, undefined);
633
+ // Create Script with FindAll + Embed Functions
634
+ const tempLabel = `embed_script_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
635
+ const script = {
636
+ label: tempLabel,
637
+ name: "Generate Embedding",
638
+ description: "Temporary script for embedding generation",
639
+ version: "1.0",
640
+ parameters: {},
641
+ functions: [
642
+ {
643
+ type: "FindAll",
644
+ collection: tempCollection,
645
+ },
646
+ {
647
+ type: "Embed",
648
+ input_field: "text",
649
+ output_field: "embedding",
650
+ model: model,
651
+ },
652
+ ],
653
+ tags: [],
654
+ };
655
+ // Save and execute the script
656
+ const scriptId = await this.saveScript(script);
657
+ const result = await this.callScript(scriptId, undefined);
658
+ // Clean up
659
+ await this.deleteScript(scriptId).catch(() => { });
660
+ await this.deleteCollection(tempCollection).catch(() => { });
661
+ // Extract embedding from result
662
+ if (result.records && result.records.length > 0) {
663
+ const record = result.records[0];
664
+ if (record.embedding && Array.isArray(record.embedding)) {
665
+ return record.embedding;
666
+ }
667
+ }
668
+ throw new Error("Failed to extract embedding from result");
669
+ }
670
+ catch (error) {
671
+ // Ensure cleanup even on error
672
+ await this.deleteCollection(tempCollection).catch(() => { });
673
+ throw error;
674
+ }
675
+ }
676
+ /**
677
+ * Perform text search without embeddings
678
+ *
679
+ * Simplified text search with full-text matching, fuzzy search, and stemming.
680
+ *
681
+ * @param collection - Collection name to search
682
+ * @param queryText - Search query text
683
+ * @param limit - Maximum number of results to return
684
+ * @returns Array of matching records
685
+ *
686
+ * @example
687
+ * ```typescript
688
+ * const results = await client.textSearch(
689
+ * "documents",
690
+ * "ownership system",
691
+ * 10
692
+ * );
693
+ * ```
694
+ */
695
+ async textSearch(collection, queryText, limit) {
696
+ const searchQuery = {
697
+ query: queryText,
698
+ limit,
699
+ };
700
+ const response = await this.search(collection, searchQuery);
701
+ return response.results.map((r) => r.record);
702
+ }
703
+ /**
704
+ * Perform hybrid search combining text and vector search
705
+ *
706
+ * Combines semantic similarity (vector search) with keyword matching (text search)
707
+ * for more accurate and relevant results.
708
+ *
709
+ * @param collection - Collection name to search
710
+ * @param queryText - Search query text
711
+ * @param queryVector - Embedding vector for semantic search
712
+ * @param limit - Maximum number of results to return
713
+ * @returns Array of matching records
714
+ *
715
+ * @example
716
+ * ```typescript
717
+ * const embedding = await client.embed(query, "text-embedding-3-small");
718
+ * const results = await client.hybridSearch(
719
+ * "documents",
720
+ * query,
721
+ * embedding,
722
+ * 5
723
+ * );
724
+ * ```
725
+ */
726
+ async hybridSearch(collection, queryText, queryVector, limit) {
727
+ const searchQuery = {
728
+ query: queryText,
729
+ vector: queryVector,
730
+ limit,
731
+ };
732
+ const response = await this.search(collection, searchQuery);
733
+ return response.results.map((r) => r.record);
734
+ }
735
+ /**
736
+ * Find all records in a collection with a limit
737
+ *
738
+ * Simplified method to query all documents in a collection.
739
+ *
740
+ * @param collection - Collection name
741
+ * @param limit - Maximum number of records to return
742
+ * @returns Array of records
743
+ *
744
+ * @example
745
+ * ```typescript
746
+ * const allMessages = await client.findAll("messages", 1000);
747
+ * console.log(`Found ${allMessages.length} messages`);
748
+ * ```
749
+ */
750
+ async findAllWithLimit(collection, limit) {
751
+ const query = new query_builder_1.QueryBuilder().limit(limit).build();
752
+ const results = await this.find(collection, query);
753
+ return results;
754
+ }
598
755
  }
599
756
  exports.EkoDBClient = EkoDBClient;
600
757
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ekodb/ekodb-client",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Official TypeScript/JavaScript client for ekoDB",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/client.ts CHANGED
@@ -397,6 +397,14 @@ export class EkoDBClient {
397
397
  throw new RateLimitError(retryAfter);
398
398
  }
399
399
 
400
+ // Handle unauthorized (401) - try refreshing token
401
+ if (response.status === 401 && attempt === 0) {
402
+ console.log("Authentication failed, refreshing token...");
403
+ await this.refreshToken();
404
+ // Retry with new token
405
+ return this.makeRequest<T>(method, path, data, attempt + 1, forceJson);
406
+ }
407
+
400
408
  // Handle service unavailable (503)
401
409
  if (
402
410
  response.status === 503 &&
@@ -1020,6 +1028,177 @@ export class EkoDBClient {
1020
1028
  websocket(wsURL: string): WebSocketClient {
1021
1029
  return new WebSocketClient(wsURL, this.token!);
1022
1030
  }
1031
+
1032
+ // ========== RAG Helper Methods ==========
1033
+
1034
+ /**
1035
+ * Generate embeddings for text using ekoDB's native Functions
1036
+ *
1037
+ * This helper simplifies embedding generation by:
1038
+ * 1. Creating a temporary collection with the text
1039
+ * 2. Running a Script with FindAll + Embed Functions
1040
+ * 3. Extracting and returning the embedding vector
1041
+ * 4. Cleaning up temporary resources
1042
+ *
1043
+ * @param text - The text to generate embeddings for
1044
+ * @param model - The embedding model to use (e.g., "text-embedding-3-small")
1045
+ * @returns Array of floats representing the embedding vector
1046
+ *
1047
+ * @example
1048
+ * ```typescript
1049
+ * const embedding = await client.embed(
1050
+ * "Hello world",
1051
+ * "text-embedding-3-small"
1052
+ * );
1053
+ * console.log(`Generated ${embedding.length} dimensions`);
1054
+ * ```
1055
+ */
1056
+ async embed(text: string, model: string): Promise<number[]> {
1057
+ const tempCollection = `embed_temp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
1058
+
1059
+ try {
1060
+ // Insert temporary record with the text
1061
+ await this.insert(tempCollection, { text }, undefined);
1062
+
1063
+ // Create Script with FindAll + Embed Functions
1064
+ const tempLabel = `embed_script_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
1065
+ const script: Script = {
1066
+ label: tempLabel,
1067
+ name: "Generate Embedding",
1068
+ description: "Temporary script for embedding generation",
1069
+ version: "1.0",
1070
+ parameters: {},
1071
+ functions: [
1072
+ {
1073
+ type: "FindAll",
1074
+ collection: tempCollection,
1075
+ },
1076
+ {
1077
+ type: "Embed",
1078
+ input_field: "text",
1079
+ output_field: "embedding",
1080
+ model: model,
1081
+ } as any,
1082
+ ],
1083
+ tags: [],
1084
+ };
1085
+
1086
+ // Save and execute the script
1087
+ const scriptId = await this.saveScript(script);
1088
+ const result = await this.callScript(scriptId, undefined);
1089
+
1090
+ // Clean up
1091
+ await this.deleteScript(scriptId).catch(() => {});
1092
+ await this.deleteCollection(tempCollection).catch(() => {});
1093
+
1094
+ // Extract embedding from result
1095
+ if (result.records && result.records.length > 0) {
1096
+ const record = result.records[0];
1097
+ if (record.embedding && Array.isArray(record.embedding)) {
1098
+ return record.embedding as number[];
1099
+ }
1100
+ }
1101
+
1102
+ throw new Error("Failed to extract embedding from result");
1103
+ } catch (error) {
1104
+ // Ensure cleanup even on error
1105
+ await this.deleteCollection(tempCollection).catch(() => {});
1106
+ throw error;
1107
+ }
1108
+ }
1109
+
1110
+ /**
1111
+ * Perform text search without embeddings
1112
+ *
1113
+ * Simplified text search with full-text matching, fuzzy search, and stemming.
1114
+ *
1115
+ * @param collection - Collection name to search
1116
+ * @param queryText - Search query text
1117
+ * @param limit - Maximum number of results to return
1118
+ * @returns Array of matching records
1119
+ *
1120
+ * @example
1121
+ * ```typescript
1122
+ * const results = await client.textSearch(
1123
+ * "documents",
1124
+ * "ownership system",
1125
+ * 10
1126
+ * );
1127
+ * ```
1128
+ */
1129
+ async textSearch(
1130
+ collection: string,
1131
+ queryText: string,
1132
+ limit: number,
1133
+ ): Promise<Record[]> {
1134
+ const searchQuery: SearchQuery = {
1135
+ query: queryText,
1136
+ limit,
1137
+ };
1138
+
1139
+ const response = await this.search(collection, searchQuery);
1140
+ return response.results.map((r) => r.record);
1141
+ }
1142
+
1143
+ /**
1144
+ * Perform hybrid search combining text and vector search
1145
+ *
1146
+ * Combines semantic similarity (vector search) with keyword matching (text search)
1147
+ * for more accurate and relevant results.
1148
+ *
1149
+ * @param collection - Collection name to search
1150
+ * @param queryText - Search query text
1151
+ * @param queryVector - Embedding vector for semantic search
1152
+ * @param limit - Maximum number of results to return
1153
+ * @returns Array of matching records
1154
+ *
1155
+ * @example
1156
+ * ```typescript
1157
+ * const embedding = await client.embed(query, "text-embedding-3-small");
1158
+ * const results = await client.hybridSearch(
1159
+ * "documents",
1160
+ * query,
1161
+ * embedding,
1162
+ * 5
1163
+ * );
1164
+ * ```
1165
+ */
1166
+ async hybridSearch(
1167
+ collection: string,
1168
+ queryText: string,
1169
+ queryVector: number[],
1170
+ limit: number,
1171
+ ): Promise<Record[]> {
1172
+ const searchQuery: SearchQuery = {
1173
+ query: queryText,
1174
+ vector: queryVector,
1175
+ limit,
1176
+ };
1177
+
1178
+ const response = await this.search(collection, searchQuery);
1179
+ return response.results.map((r) => r.record);
1180
+ }
1181
+
1182
+ /**
1183
+ * Find all records in a collection with a limit
1184
+ *
1185
+ * Simplified method to query all documents in a collection.
1186
+ *
1187
+ * @param collection - Collection name
1188
+ * @param limit - Maximum number of records to return
1189
+ * @returns Array of records
1190
+ *
1191
+ * @example
1192
+ * ```typescript
1193
+ * const allMessages = await client.findAll("messages", 1000);
1194
+ * console.log(`Found ${allMessages.length} messages`);
1195
+ * ```
1196
+ */
1197
+ async findAllWithLimit(collection: string, limit: number): Promise<Record[]> {
1198
+ const query = new QueryBuilder().limit(limit).build();
1199
+ const results = await this.find(collection, query);
1200
+ return results;
1201
+ }
1023
1202
  }
1024
1203
 
1025
1204
  /**