@soulcraft/brainy 0.52.0 → 0.54.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 CHANGED
@@ -69,6 +69,160 @@ const results = await brainy.search("AI language models", 5, {
69
69
 
70
70
  **That's it. You just built a knowledge graph with semantic search and faceted filtering in 8 lines.**
71
71
 
72
+ ## ⚙️ Configuration Options
73
+
74
+ Brainy works great with **zero configuration**, but you can customize it for your specific needs:
75
+
76
+ ### 🚀 Quick Start (Recommended)
77
+ ```javascript
78
+ const brainy = new BrainyData() // Auto-detects everything
79
+ await brainy.init() // Zero config needed
80
+ ```
81
+
82
+ ### 🎯 Specialized Configurations
83
+
84
+ #### Writer Service with Deduplication
85
+ Perfect for high-throughput data ingestion with smart caching:
86
+ ```javascript
87
+ const brainy = new BrainyData({
88
+ writeOnly: true, // Skip search index loading
89
+ allowDirectReads: true // Enable ID-based lookups for deduplication
90
+ })
91
+ // ✅ Can: add(), get(), has(), exists(), getMetadata(), getBatch()
92
+ // ❌ Cannot: search(), similar(), query() (saves memory & startup time)
93
+ ```
94
+
95
+ #### Pure Writer Service
96
+ For maximum performance data ingestion only:
97
+ ```javascript
98
+ const brainy = new BrainyData({
99
+ writeOnly: true, // No search capabilities
100
+ allowDirectReads: false // No read operations at all
101
+ })
102
+ // ✅ Can: add(), addBatch(), relate()
103
+ // ❌ Cannot: Any read operations (fastest startup)
104
+ ```
105
+
106
+ #### Read-Only Service
107
+ For search-only applications with immutable data:
108
+ ```javascript
109
+ const brainy = new BrainyData({
110
+ readOnly: true, // Block all write operations
111
+ frozen: true // Block statistics updates and optimizations
112
+ })
113
+ // ✅ Can: All search operations
114
+ // ❌ Cannot: add(), update(), delete()
115
+ ```
116
+
117
+ #### Custom Storage & Performance
118
+ ```javascript
119
+ const brainy = new BrainyData({
120
+ // Storage options
121
+ storage: {
122
+ type: 's3', // 's3', 'memory', 'filesystem'
123
+ requestPersistentStorage: true, // Browser: request persistent storage
124
+ s3Storage: {
125
+ bucketName: 'my-vectors',
126
+ region: 'us-east-1'
127
+ }
128
+ },
129
+
130
+ // Performance tuning
131
+ hnsw: {
132
+ maxConnections: 16, // Higher = better search quality
133
+ efConstruction: 200, // Higher = better index quality
134
+ useOptimized: true // Enable disk-based storage
135
+ },
136
+
137
+ // Embedding customization
138
+ embeddingFunction: myCustomEmbedder,
139
+ distanceFunction: 'euclidean' // 'cosine', 'euclidean', 'manhattan'
140
+ })
141
+ ```
142
+
143
+ #### Distributed Services
144
+ ```javascript
145
+ // Microservice A (Writer)
146
+ const writerService = new BrainyData({
147
+ writeOnly: true,
148
+ allowDirectReads: true, // For deduplication
149
+ defaultService: 'data-ingestion'
150
+ })
151
+
152
+ // Microservice B (Reader)
153
+ const readerService = new BrainyData({
154
+ readOnly: true,
155
+ defaultService: 'search-api'
156
+ })
157
+
158
+ // Full-featured service
159
+ const hybridService = new BrainyData({
160
+ writeOnly: false, // Can read and write
161
+ defaultService: 'full-stack-app'
162
+ })
163
+ ```
164
+
165
+ ### 🔧 All Configuration Options
166
+
167
+ <details>
168
+ <summary>Click to see complete configuration reference</summary>
169
+
170
+ ```javascript
171
+ const brainy = new BrainyData({
172
+ // === Operation Modes ===
173
+ writeOnly?: boolean // Disable search operations, enable fast ingestion
174
+ allowDirectReads?: boolean // Enable ID lookups in writeOnly mode
175
+ readOnly?: boolean // Disable write operations
176
+ frozen?: boolean // Disable all optimizations and statistics
177
+ lazyLoadInReadOnlyMode?: boolean // Load index on-demand
178
+
179
+ // === Storage Configuration ===
180
+ storage?: {
181
+ type?: 'auto' | 'memory' | 'filesystem' | 's3' | 'opfs'
182
+ requestPersistentStorage?: boolean // Browser persistent storage
183
+
184
+ // Cloud storage options
185
+ s3Storage?: {
186
+ bucketName: string
187
+ region?: string
188
+ accessKeyId?: string
189
+ secretAccessKey?: string
190
+ },
191
+
192
+ r2Storage?: { /* Cloudflare R2 options */ },
193
+ gcsStorage?: { /* Google Cloud Storage options */ }
194
+ },
195
+
196
+ // === Performance Tuning ===
197
+ hnsw?: {
198
+ maxConnections?: number // Default: 16
199
+ efConstruction?: number // Default: 200
200
+ efSearch?: number // Default: 50
201
+ useOptimized?: boolean // Default: true
202
+ useDiskBasedIndex?: boolean // Default: auto-detected
203
+ },
204
+
205
+ // === Embedding & Distance ===
206
+ embeddingFunction?: EmbeddingFunction
207
+ distanceFunction?: 'cosine' | 'euclidean' | 'manhattan'
208
+
209
+ // === Service Identity ===
210
+ defaultService?: string // Default service name for operations
211
+
212
+ // === Advanced Options ===
213
+ logging?: {
214
+ verbose?: boolean // Enable detailed logging
215
+ },
216
+
217
+ timeouts?: {
218
+ embedding?: number // Embedding timeout (ms)
219
+ search?: number // Search timeout (ms)
220
+ }
221
+ })
222
+ ```
223
+
224
+ </details>
225
+
72
226
  ## 🔥 MAJOR UPDATES: What's New in v0.51, v0.49 & v0.48
73
227
 
74
228
  ### 🎯 **v0.51: Revolutionary Developer Experience**
@@ -105,6 +105,13 @@ export interface BrainyDataConfig {
105
105
  * This is useful for data ingestion scenarios where only write operations are needed
106
106
  */
107
107
  writeOnly?: boolean;
108
+ /**
109
+ * Allow direct storage reads in write-only mode
110
+ * When true and writeOnly is also true, enables direct ID-based lookups (get, has, exists, getMetadata, getBatch, getVerb)
111
+ * that don't require search indexes. Search operations (search, similar, query, findRelated) remain disabled.
112
+ * This is useful for writer services that need deduplication without loading expensive search indexes.
113
+ */
114
+ allowDirectReads?: boolean;
108
115
  /**
109
116
  * Remote server configuration for search operations
110
117
  */
@@ -354,6 +361,7 @@ export declare class BrainyData<T = any> implements BrainyDataInterface<T> {
354
361
  private frozen;
355
362
  private lazyLoadInReadOnlyMode;
356
363
  private writeOnly;
364
+ private allowDirectReads;
357
365
  private storageConfig;
358
366
  private config;
359
367
  private useOptimizedIndex;
@@ -410,6 +418,7 @@ export declare class BrainyData<T = any> implements BrainyDataInterface<T> {
410
418
  /**
411
419
  * Check if the database is in write-only mode and throw an error if it is
412
420
  * @param allowExistenceChecks If true, allows existence checks (get operations) in write-only mode
421
+ * @param isDirectStorageOperation If true, allows the operation when allowDirectReads is enabled
413
422
  * @throws Error if the database is in write-only mode and operation is not allowed
414
423
  */
415
424
  private checkWriteOnly;
@@ -699,6 +708,34 @@ export declare class BrainyData<T = any> implements BrainyDataInterface<T> {
699
708
  * Get a vector by ID
700
709
  */
701
710
  get(id: string): Promise<VectorDocument<T> | null>;
711
+ /**
712
+ * Check if a document with the given ID exists
713
+ * This is a direct storage operation that works in write-only mode when allowDirectReads is enabled
714
+ * @param id The ID to check for existence
715
+ * @returns Promise<boolean> True if the document exists, false otherwise
716
+ */
717
+ has(id: string): Promise<boolean>;
718
+ /**
719
+ * Check if a document with the given ID exists (alias for has)
720
+ * This is a direct storage operation that works in write-only mode when allowDirectReads is enabled
721
+ * @param id The ID to check for existence
722
+ * @returns Promise<boolean> True if the document exists, false otherwise
723
+ */
724
+ exists(id: string): Promise<boolean>;
725
+ /**
726
+ * Get metadata for a document by ID
727
+ * This is a direct storage operation that works in write-only mode when allowDirectReads is enabled
728
+ * @param id The ID of the document
729
+ * @returns Promise<T | null> The metadata object or null if not found
730
+ */
731
+ getMetadata(id: string): Promise<T | null>;
732
+ /**
733
+ * Get multiple documents by their IDs
734
+ * This is a direct storage operation that works in write-only mode when allowDirectReads is enabled
735
+ * @param ids Array of IDs to retrieve
736
+ * @returns Promise<Array<VectorDocument<T> | null>> Array of documents (null for missing IDs)
737
+ */
738
+ getBatch(ids: string[]): Promise<Array<VectorDocument<T> | null>>;
702
739
  /**
703
740
  * Get all nouns in the database
704
741
  * @returns Array of vector documents
@@ -789,6 +826,7 @@ export declare class BrainyData<T = any> implements BrainyDataInterface<T> {
789
826
  }): Promise<string>;
790
827
  /**
791
828
  * Get a verb by ID
829
+ * This is a direct storage operation that works in write-only mode when allowDirectReads is enabled
792
830
  */
793
831
  getVerb(id: string): Promise<GraphVerb | null>;
794
832
  /**
@@ -122,6 +122,8 @@ export class BrainyData {
122
122
  this.lazyLoadInReadOnlyMode = config.lazyLoadInReadOnlyMode || false;
123
123
  // Set write-only flag
124
124
  this.writeOnly = config.writeOnly || false;
125
+ // Set allowDirectReads flag
126
+ this.allowDirectReads = config.allowDirectReads || false;
125
127
  // Validate that readOnly and writeOnly are not both true
126
128
  if (this.readOnly && this.writeOnly) {
127
129
  throw new Error('Database cannot be both read-only and write-only');
@@ -227,11 +229,15 @@ export class BrainyData {
227
229
  /**
228
230
  * Check if the database is in write-only mode and throw an error if it is
229
231
  * @param allowExistenceChecks If true, allows existence checks (get operations) in write-only mode
232
+ * @param isDirectStorageOperation If true, allows the operation when allowDirectReads is enabled
230
233
  * @throws Error if the database is in write-only mode and operation is not allowed
231
234
  */
232
- checkWriteOnly(allowExistenceChecks = false) {
233
- if (this.writeOnly && !allowExistenceChecks) {
234
- throw new Error('Cannot perform search operation: database is in write-only mode. Use get() for existence checks.');
235
+ checkWriteOnly(allowExistenceChecks = false, isDirectStorageOperation = false) {
236
+ if (this.writeOnly && !allowExistenceChecks && !(isDirectStorageOperation && this.allowDirectReads)) {
237
+ throw new Error('Cannot perform search operation: database is in write-only mode. ' +
238
+ (this.allowDirectReads
239
+ ? 'Direct storage operations (get, has, exists, getMetadata, getBatch, getVerb) are allowed.'
240
+ : 'Use get() for existence checks or enable allowDirectReads for direct storage operations.'));
235
241
  }
236
242
  }
237
243
  /**
@@ -2026,6 +2032,96 @@ export class BrainyData {
2026
2032
  throw new Error(`Failed to get vector ${id}: ${error}`);
2027
2033
  }
2028
2034
  }
2035
+ /**
2036
+ * Check if a document with the given ID exists
2037
+ * This is a direct storage operation that works in write-only mode when allowDirectReads is enabled
2038
+ * @param id The ID to check for existence
2039
+ * @returns Promise<boolean> True if the document exists, false otherwise
2040
+ */
2041
+ async has(id) {
2042
+ if (id === null || id === undefined) {
2043
+ throw new Error('ID cannot be null or undefined');
2044
+ }
2045
+ await this.ensureInitialized();
2046
+ // This is a direct storage operation - check if allowed in write-only mode
2047
+ if (this.writeOnly && !this.allowDirectReads) {
2048
+ throw new Error('Cannot perform has() operation: database is in write-only mode. Enable allowDirectReads for direct storage operations.');
2049
+ }
2050
+ try {
2051
+ // Always query storage directly for existence check
2052
+ const noun = await this.storage.getNoun(id);
2053
+ return noun !== null;
2054
+ }
2055
+ catch (error) {
2056
+ // If storage lookup fails, the item doesn't exist
2057
+ return false;
2058
+ }
2059
+ }
2060
+ /**
2061
+ * Check if a document with the given ID exists (alias for has)
2062
+ * This is a direct storage operation that works in write-only mode when allowDirectReads is enabled
2063
+ * @param id The ID to check for existence
2064
+ * @returns Promise<boolean> True if the document exists, false otherwise
2065
+ */
2066
+ async exists(id) {
2067
+ return this.has(id);
2068
+ }
2069
+ /**
2070
+ * Get metadata for a document by ID
2071
+ * This is a direct storage operation that works in write-only mode when allowDirectReads is enabled
2072
+ * @param id The ID of the document
2073
+ * @returns Promise<T | null> The metadata object or null if not found
2074
+ */
2075
+ async getMetadata(id) {
2076
+ if (id === null || id === undefined) {
2077
+ throw new Error('ID cannot be null or undefined');
2078
+ }
2079
+ await this.ensureInitialized();
2080
+ // This is a direct storage operation - check if allowed in write-only mode
2081
+ if (this.writeOnly && !this.allowDirectReads) {
2082
+ throw new Error('Cannot perform getMetadata() operation: database is in write-only mode. Enable allowDirectReads for direct storage operations.');
2083
+ }
2084
+ try {
2085
+ const metadata = await this.storage.getMetadata(id);
2086
+ return metadata;
2087
+ }
2088
+ catch (error) {
2089
+ console.error(`Failed to get metadata for ${id}:`, error);
2090
+ return null;
2091
+ }
2092
+ }
2093
+ /**
2094
+ * Get multiple documents by their IDs
2095
+ * This is a direct storage operation that works in write-only mode when allowDirectReads is enabled
2096
+ * @param ids Array of IDs to retrieve
2097
+ * @returns Promise<Array<VectorDocument<T> | null>> Array of documents (null for missing IDs)
2098
+ */
2099
+ async getBatch(ids) {
2100
+ if (!Array.isArray(ids)) {
2101
+ throw new Error('IDs must be provided as an array');
2102
+ }
2103
+ await this.ensureInitialized();
2104
+ // This is a direct storage operation - check if allowed in write-only mode
2105
+ if (this.writeOnly && !this.allowDirectReads) {
2106
+ throw new Error('Cannot perform getBatch() operation: database is in write-only mode. Enable allowDirectReads for direct storage operations.');
2107
+ }
2108
+ const results = [];
2109
+ for (const id of ids) {
2110
+ if (id === null || id === undefined) {
2111
+ results.push(null);
2112
+ continue;
2113
+ }
2114
+ try {
2115
+ const result = await this.get(id);
2116
+ results.push(result);
2117
+ }
2118
+ catch (error) {
2119
+ console.error(`Failed to get document ${id} in batch:`, error);
2120
+ results.push(null);
2121
+ }
2122
+ }
2123
+ return results;
2124
+ }
2029
2125
  /**
2030
2126
  * Get all nouns in the database
2031
2127
  * @returns Array of vector documents
@@ -2690,9 +2786,14 @@ export class BrainyData {
2690
2786
  }
2691
2787
  /**
2692
2788
  * Get a verb by ID
2789
+ * This is a direct storage operation that works in write-only mode when allowDirectReads is enabled
2693
2790
  */
2694
2791
  async getVerb(id) {
2695
2792
  await this.ensureInitialized();
2793
+ // This is a direct storage operation - check if allowed in write-only mode
2794
+ if (this.writeOnly && !this.allowDirectReads) {
2795
+ throw new Error('Cannot perform getVerb() operation: database is in write-only mode. Enable allowDirectReads for direct storage operations.');
2796
+ }
2696
2797
  try {
2697
2798
  // Get the lightweight verb from storage
2698
2799
  const hnswVerb = await this.storage.getVerb(id);