@soulcraft/brainy 3.25.2 → 3.27.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/CHANGELOG.md CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [3.27.0](https://github.com/soulcraftlabs/brainy/compare/v3.26.0...v3.27.0) (2025-10-08)
6
+
7
+ - test: skip incomplete clusterByDomain tests pending implementation (19aa4af)
8
+ - feat: add native Google Cloud Storage adapter with ADC support (e2aa8e3)
9
+
10
+
11
+ ## [3.26.0](https://github.com/soulcraftlabs/brainy/compare/v3.25.2...v3.26.0) (2025-10-08)
12
+
13
+
14
+ ### ⚠ BREAKING CHANGES
15
+
16
+ * Requires data migration for existing S3/GCS/R2/OpFS deployments.
17
+ See .strategy/UNIFIED-UUID-SHARDING.md for migration guidance.
18
+
19
+ ### 🐛 Bug Fixes
20
+
21
+ * implement unified UUID-based sharding for metadata across all storage adapters ([2f33571](https://github.com/soulcraftlabs/brainy/commit/2f3357132d06c70cd74532d22cbfbf6abb92903a))
22
+
5
23
  ### [3.25.2](https://github.com/soulcraftlabs/brainy/compare/v3.25.1...v3.25.2) (2025-10-08)
6
24
 
7
25
 
@@ -510,7 +510,11 @@ export class FileSystemStorage extends BaseStorage {
510
510
  */
511
511
  async saveNounMetadata_internal(id, metadata) {
512
512
  await this.ensureInitialized();
513
- const filePath = path.join(this.nounMetadataDir, `${id}.json`);
513
+ // Use UUID-based sharding for metadata (consistent with noun vectors)
514
+ const filePath = this.getShardedPath(this.nounMetadataDir, id);
515
+ // Ensure shard directory exists
516
+ const shardDir = path.dirname(filePath);
517
+ await fs.promises.mkdir(shardDir, { recursive: true });
514
518
  await fs.promises.writeFile(filePath, JSON.stringify(metadata, null, 2));
515
519
  }
516
520
  /**
@@ -518,7 +522,8 @@ export class FileSystemStorage extends BaseStorage {
518
522
  */
519
523
  async getNounMetadata(id) {
520
524
  await this.ensureInitialized();
521
- const filePath = path.join(this.nounMetadataDir, `${id}.json`);
525
+ // Use UUID-based sharding for metadata (consistent with noun vectors)
526
+ const filePath = this.getShardedPath(this.nounMetadataDir, id);
522
527
  try {
523
528
  const data = await fs.promises.readFile(filePath, 'utf-8');
524
529
  return JSON.parse(data);
@@ -0,0 +1,334 @@
1
+ /**
2
+ * Google Cloud Storage Adapter (Native)
3
+ * Uses the native @google-cloud/storage library for optimal performance and authentication
4
+ *
5
+ * Supports multiple authentication methods:
6
+ * 1. Application Default Credentials (ADC) - Automatic in Cloud Run/GCE
7
+ * 2. Service Account Key File
8
+ * 3. Service Account Credentials Object
9
+ * 4. HMAC Keys (fallback for backward compatibility)
10
+ */
11
+ import { GraphVerb, HNSWNoun, HNSWVerb, StatisticsData } from '../../coreTypes.js';
12
+ import { BaseStorage } from '../baseStorage.js';
13
+ type HNSWNode = HNSWNoun;
14
+ type Edge = HNSWVerb;
15
+ /**
16
+ * Native Google Cloud Storage adapter for server environments
17
+ * Uses the @google-cloud/storage library with Application Default Credentials
18
+ *
19
+ * Authentication priority:
20
+ * 1. Application Default Credentials (if no credentials provided)
21
+ * 2. Service Account Key File (if keyFilename provided)
22
+ * 3. Service Account Credentials Object (if credentials provided)
23
+ * 4. HMAC Keys (if accessKeyId/secretAccessKey provided)
24
+ */
25
+ export declare class GcsStorage extends BaseStorage {
26
+ private storage;
27
+ private bucket;
28
+ private bucketName;
29
+ private keyFilename?;
30
+ private credentials?;
31
+ private accessKeyId?;
32
+ private secretAccessKey?;
33
+ private nounPrefix;
34
+ private verbPrefix;
35
+ private metadataPrefix;
36
+ private verbMetadataPrefix;
37
+ private systemPrefix;
38
+ protected statisticsCache: StatisticsData | null;
39
+ private pendingOperations;
40
+ private maxConcurrentOperations;
41
+ private baseBatchSize;
42
+ private currentBatchSize;
43
+ private lastMemoryCheck;
44
+ private memoryCheckInterval;
45
+ private consecutiveErrors;
46
+ private lastErrorReset;
47
+ private backpressure;
48
+ private nounWriteBuffer;
49
+ private verbWriteBuffer;
50
+ private requestCoalescer;
51
+ private highVolumeMode;
52
+ private lastVolumeCheck;
53
+ private volumeCheckInterval;
54
+ private forceHighVolumeMode;
55
+ private nounCacheManager;
56
+ private verbCacheManager;
57
+ private logger;
58
+ /**
59
+ * Initialize the storage adapter
60
+ * @param options Configuration options for Google Cloud Storage
61
+ */
62
+ constructor(options: {
63
+ bucketName: string;
64
+ keyFilename?: string;
65
+ credentials?: object;
66
+ accessKeyId?: string;
67
+ secretAccessKey?: string;
68
+ cacheConfig?: {
69
+ hotCacheMaxSize?: number;
70
+ hotCacheEvictionThreshold?: number;
71
+ warmCacheTTL?: number;
72
+ };
73
+ readOnly?: boolean;
74
+ });
75
+ /**
76
+ * Initialize the storage adapter
77
+ */
78
+ init(): Promise<void>;
79
+ /**
80
+ * Get the GCS object key for a noun using UUID-based sharding
81
+ *
82
+ * Uses first 2 hex characters of UUID for consistent sharding.
83
+ * Path format: entities/nouns/vectors/{shardId}/{uuid}.json
84
+ *
85
+ * @example
86
+ * getNounKey('ab123456-1234-5678-9abc-def012345678')
87
+ * // returns 'entities/nouns/vectors/ab/ab123456-1234-5678-9abc-def012345678.json'
88
+ */
89
+ private getNounKey;
90
+ /**
91
+ * Get the GCS object key for a verb using UUID-based sharding
92
+ *
93
+ * Uses first 2 hex characters of UUID for consistent sharding.
94
+ * Path format: entities/verbs/vectors/{shardId}/{uuid}.json
95
+ *
96
+ * @example
97
+ * getVerbKey('cd987654-4321-8765-cba9-fed543210987')
98
+ * // returns 'entities/verbs/vectors/cd/cd987654-4321-8765-cba9-fed543210987.json'
99
+ */
100
+ private getVerbKey;
101
+ /**
102
+ * Override base class method to detect GCS-specific throttling errors
103
+ */
104
+ protected isThrottlingError(error: any): boolean;
105
+ /**
106
+ * Apply backpressure before starting an operation
107
+ * @returns Request ID for tracking
108
+ */
109
+ private applyBackpressure;
110
+ /**
111
+ * Release backpressure after completing an operation
112
+ * @param success Whether the operation succeeded
113
+ * @param requestId Request ID from applyBackpressure()
114
+ */
115
+ private releaseBackpressure;
116
+ /**
117
+ * Check if high-volume mode should be enabled
118
+ */
119
+ private checkVolumeMode;
120
+ /**
121
+ * Flush noun buffer to GCS
122
+ */
123
+ private flushNounBuffer;
124
+ /**
125
+ * Flush verb buffer to GCS
126
+ */
127
+ private flushVerbBuffer;
128
+ /**
129
+ * Save a noun to storage (internal implementation)
130
+ */
131
+ protected saveNoun_internal(noun: HNSWNoun): Promise<void>;
132
+ /**
133
+ * Save a node to storage
134
+ */
135
+ protected saveNode(node: HNSWNode): Promise<void>;
136
+ /**
137
+ * Save a node directly to GCS (bypass buffer)
138
+ */
139
+ private saveNodeDirect;
140
+ /**
141
+ * Get a noun from storage (internal implementation)
142
+ */
143
+ protected getNoun_internal(id: string): Promise<HNSWNoun | null>;
144
+ /**
145
+ * Get a node from storage
146
+ */
147
+ protected getNode(id: string): Promise<HNSWNode | null>;
148
+ /**
149
+ * Delete a noun from storage (internal implementation)
150
+ */
151
+ protected deleteNoun_internal(id: string): Promise<void>;
152
+ /**
153
+ * Save noun metadata to storage (internal implementation)
154
+ */
155
+ protected saveNounMetadata_internal(id: string, metadata: any): Promise<void>;
156
+ /**
157
+ * Save metadata to storage (public API - delegates to saveNounMetadata_internal)
158
+ */
159
+ saveMetadata(id: string, metadata: any): Promise<void>;
160
+ /**
161
+ * Get metadata from storage (public API - delegates to getNounMetadata)
162
+ */
163
+ getMetadata(id: string): Promise<any | null>;
164
+ /**
165
+ * Get noun metadata from storage
166
+ */
167
+ getNounMetadata(id: string): Promise<any | null>;
168
+ /**
169
+ * Save verb metadata to storage (internal implementation)
170
+ */
171
+ protected saveVerbMetadata_internal(id: string, metadata: any): Promise<void>;
172
+ /**
173
+ * Get verb metadata from storage
174
+ */
175
+ getVerbMetadata(id: string): Promise<any | null>;
176
+ /**
177
+ * Save a verb to storage (internal implementation)
178
+ */
179
+ protected saveVerb_internal(verb: HNSWVerb): Promise<void>;
180
+ /**
181
+ * Save an edge to storage
182
+ */
183
+ protected saveEdge(edge: Edge): Promise<void>;
184
+ /**
185
+ * Save an edge directly to GCS (bypass buffer)
186
+ */
187
+ private saveEdgeDirect;
188
+ /**
189
+ * Get a verb from storage (internal implementation)
190
+ */
191
+ protected getVerb_internal(id: string): Promise<HNSWVerb | null>;
192
+ /**
193
+ * Get an edge from storage
194
+ */
195
+ protected getEdge(id: string): Promise<Edge | null>;
196
+ /**
197
+ * Delete a verb from storage (internal implementation)
198
+ */
199
+ protected deleteVerb_internal(id: string): Promise<void>;
200
+ /**
201
+ * Get nouns with pagination
202
+ * Iterates through all UUID-based shards (00-ff) for consistent pagination
203
+ */
204
+ getNounsWithPagination(options?: {
205
+ limit?: number;
206
+ cursor?: string;
207
+ filter?: {
208
+ nounType?: string | string[];
209
+ service?: string | string[];
210
+ metadata?: Record<string, any>;
211
+ };
212
+ }): Promise<{
213
+ items: HNSWNoun[];
214
+ totalCount?: number;
215
+ hasMore: boolean;
216
+ nextCursor?: string;
217
+ }>;
218
+ /**
219
+ * Get nodes with pagination (internal implementation)
220
+ * Iterates through UUID-based shards for consistent pagination
221
+ */
222
+ private getNodesWithPagination;
223
+ /**
224
+ * Get nouns by noun type (internal implementation)
225
+ */
226
+ protected getNounsByNounType_internal(nounType: string): Promise<HNSWNoun[]>;
227
+ /**
228
+ * Get verbs by source ID (internal implementation)
229
+ */
230
+ protected getVerbsBySource_internal(sourceId: string): Promise<GraphVerb[]>;
231
+ /**
232
+ * Get verbs by target ID (internal implementation)
233
+ */
234
+ protected getVerbsByTarget_internal(targetId: string): Promise<GraphVerb[]>;
235
+ /**
236
+ * Get verbs by type (internal implementation)
237
+ */
238
+ protected getVerbsByType_internal(type: string): Promise<GraphVerb[]>;
239
+ /**
240
+ * Get verbs with pagination
241
+ */
242
+ getVerbsWithPagination(options?: {
243
+ limit?: number;
244
+ cursor?: string;
245
+ filter?: {
246
+ verbType?: string | string[];
247
+ sourceId?: string | string[];
248
+ targetId?: string | string[];
249
+ service?: string | string[];
250
+ metadata?: Record<string, any>;
251
+ };
252
+ }): Promise<{
253
+ items: GraphVerb[];
254
+ totalCount?: number;
255
+ hasMore: boolean;
256
+ nextCursor?: string;
257
+ }>;
258
+ /**
259
+ * Get nouns with filtering and pagination (public API)
260
+ */
261
+ getNouns(options?: {
262
+ pagination?: {
263
+ offset?: number;
264
+ limit?: number;
265
+ cursor?: string;
266
+ };
267
+ filter?: {
268
+ nounType?: string | string[];
269
+ service?: string | string[];
270
+ metadata?: Record<string, any>;
271
+ };
272
+ }): Promise<{
273
+ items: any[];
274
+ totalCount?: number;
275
+ hasMore: boolean;
276
+ nextCursor?: string;
277
+ }>;
278
+ /**
279
+ * Get verbs with filtering and pagination (public API)
280
+ */
281
+ getVerbs(options?: {
282
+ pagination?: {
283
+ offset?: number;
284
+ limit?: number;
285
+ cursor?: string;
286
+ };
287
+ filter?: {
288
+ verbType?: string | string[];
289
+ sourceId?: string | string[];
290
+ targetId?: string | string[];
291
+ service?: string | string[];
292
+ metadata?: Record<string, any>;
293
+ };
294
+ }): Promise<{
295
+ items: GraphVerb[];
296
+ totalCount?: number;
297
+ hasMore: boolean;
298
+ nextCursor?: string;
299
+ }>;
300
+ /**
301
+ * Clear all data from storage
302
+ */
303
+ clear(): Promise<void>;
304
+ /**
305
+ * Get storage status
306
+ */
307
+ getStorageStatus(): Promise<{
308
+ type: string;
309
+ used: number;
310
+ quota: number | null;
311
+ details?: Record<string, any>;
312
+ }>;
313
+ /**
314
+ * Save statistics data to storage
315
+ */
316
+ protected saveStatisticsData(statistics: StatisticsData): Promise<void>;
317
+ /**
318
+ * Get statistics data from storage
319
+ */
320
+ protected getStatisticsData(): Promise<StatisticsData | null>;
321
+ /**
322
+ * Initialize counts from storage
323
+ */
324
+ protected initializeCounts(): Promise<void>;
325
+ /**
326
+ * Initialize counts from storage scan (expensive - only for first-time init)
327
+ */
328
+ private initializeCountsFromScan;
329
+ /**
330
+ * Persist counts to storage
331
+ */
332
+ protected persistCounts(): Promise<void>;
333
+ }
334
+ export {};