@soulcraft/brainy 3.30.0 → 3.30.2
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 +52 -0
- package/README.md +1 -0
- package/dist/storage/adapters/fileSystemStorage.d.ts +15 -19
- package/dist/storage/adapters/fileSystemStorage.js +60 -80
- package/dist/storage/adapters/gcsStorage.d.ts +16 -16
- package/dist/storage/adapters/gcsStorage.js +48 -70
- package/dist/storage/adapters/memoryStorage.d.ts +19 -22
- package/dist/storage/adapters/memoryStorage.js +47 -56
- package/dist/storage/adapters/opfsStorage.d.ts +15 -19
- package/dist/storage/adapters/opfsStorage.js +105 -96
- package/dist/storage/adapters/s3CompatibleStorage.d.ts +12 -16
- package/dist/storage/adapters/s3CompatibleStorage.js +77 -205
- package/dist/storage/baseStorage.d.ts +55 -14
- package/dist/storage/baseStorage.js +125 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,58 @@
|
|
|
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.30.2](https://github.com/soulcraftlabs/brainy/compare/v3.30.1...v3.30.2) (2025-10-09)
|
|
6
|
+
|
|
7
|
+
- chore: update dependencies to latest safe versions (053f292)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### [3.30.1](https://github.com/soulcraftlabs/brainy/compare/v3.30.0...v3.30.1) (2025-10-09)
|
|
11
|
+
|
|
12
|
+
- fix: move metadata routing to base class, fix GCS/S3 system key crashes (1966c39)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### [3.30.1] - Critical Storage Architecture Fix (2025-10-09)
|
|
16
|
+
|
|
17
|
+
#### 🐛 Critical Bug Fixes
|
|
18
|
+
|
|
19
|
+
**Fixed: GCS/S3 Storage Crash on System Metadata Keys**
|
|
20
|
+
- GCS and S3 native adapters were crashing with "Invalid UUID format" errors when saving metadata index keys
|
|
21
|
+
- Root cause: Storage adapters incorrectly assumed ALL metadata keys are UUIDs
|
|
22
|
+
- System keys like `__metadata_field_index__status` and `statistics_` are NOT UUIDs and should not be sharded
|
|
23
|
+
|
|
24
|
+
**Architecture Improvement: Base Class Enforcement Pattern**
|
|
25
|
+
- Moved sharding/routing logic from individual adapters to BaseStorage class
|
|
26
|
+
- All adapters now implement 4 primitive operations instead of metadata-specific methods:
|
|
27
|
+
- `writeObjectToPath(path, data)` - Write any object to storage
|
|
28
|
+
- `readObjectFromPath(path)` - Read any object from storage
|
|
29
|
+
- `deleteObjectFromPath(path)` - Delete object from storage
|
|
30
|
+
- `listObjectsUnderPath(prefix)` - List objects under path prefix
|
|
31
|
+
- BaseStorage.analyzeKey() now routes ALL metadata operations through primitive layer
|
|
32
|
+
- System keys automatically routed to `_system/` directory (no sharding)
|
|
33
|
+
- Entity UUIDs automatically sharded to `entities/{type}/metadata/{shard}/` directories
|
|
34
|
+
|
|
35
|
+
**Benefits:**
|
|
36
|
+
- Impossible for future adapters to make the same mistake
|
|
37
|
+
- Cleaner separation of concerns (routing vs. storage primitives)
|
|
38
|
+
- Zero breaking changes for users
|
|
39
|
+
- No data migration required
|
|
40
|
+
- Full backward compatibility maintained
|
|
41
|
+
|
|
42
|
+
**Updated Adapters:**
|
|
43
|
+
- GcsStorage: Implements primitive operations using GCS bucket.file() API
|
|
44
|
+
- S3CompatibleStorage: Implements primitive operations using AWS SDK
|
|
45
|
+
- OPFSStorage: Implements primitive operations using browser FileSystem API
|
|
46
|
+
- FileSystemStorage: Implements primitive operations using Node.js fs.promises
|
|
47
|
+
- MemoryStorage: Implements primitive operations using Map data structures
|
|
48
|
+
|
|
49
|
+
**Documentation:**
|
|
50
|
+
- Added comprehensive storage architecture documentation: `docs/architecture/data-storage-architecture.md`
|
|
51
|
+
- Linked from README for easy discovery
|
|
52
|
+
|
|
53
|
+
**Impact:** CRITICAL FIX - GCS/S3 native storage now fully functional for metadata indexing
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
5
57
|
### [3.30.0](https://github.com/soulcraftlabs/brainy/compare/v3.29.1...v3.30.0) (2025-10-09)
|
|
6
58
|
|
|
7
59
|
- feat: remove legacy ImportManager, standardize getStats() API (58daf09)
|
package/README.md
CHANGED
|
@@ -888,6 +888,7 @@ We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
|
888
888
|
- [Getting Started Guide](docs/guides/getting-started.md)
|
|
889
889
|
- [API Reference](docs/api/README.md)
|
|
890
890
|
- [Architecture Overview](docs/architecture/overview.md)
|
|
891
|
+
- [Data Storage Architecture](docs/architecture/data-storage-architecture.md) - Deep dive into storage, indexing, and sharding
|
|
891
892
|
- [Natural Language Guide](docs/guides/natural-language.md)
|
|
892
893
|
- [Triple Intelligence](docs/architecture/triple-intelligence.md)
|
|
893
894
|
- [Noun-Verb Taxonomy](docs/architecture/noun-verb-taxonomy.md)
|
|
@@ -96,34 +96,30 @@ export declare class FileSystemStorage extends BaseStorage {
|
|
|
96
96
|
*/
|
|
97
97
|
protected deleteEdge(id: string): Promise<void>;
|
|
98
98
|
/**
|
|
99
|
-
*
|
|
99
|
+
* Primitive operation: Write object to path
|
|
100
|
+
* All metadata operations use this internally via base class routing
|
|
100
101
|
*/
|
|
101
|
-
|
|
102
|
+
protected writeObjectToPath(pathStr: string, data: any): Promise<void>;
|
|
102
103
|
/**
|
|
103
|
-
*
|
|
104
|
+
* Primitive operation: Read object from path
|
|
105
|
+
* All metadata operations use this internally via base class routing
|
|
104
106
|
*/
|
|
105
|
-
|
|
107
|
+
protected readObjectFromPath(pathStr: string): Promise<any | null>;
|
|
106
108
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*/
|
|
110
|
-
getMetadataBatch(ids: string[]): Promise<Map<string, any>>;
|
|
111
|
-
/**
|
|
112
|
-
* Save noun metadata to storage
|
|
109
|
+
* Primitive operation: Delete object from path
|
|
110
|
+
* All metadata operations use this internally via base class routing
|
|
113
111
|
*/
|
|
114
|
-
protected
|
|
112
|
+
protected deleteObjectFromPath(pathStr: string): Promise<void>;
|
|
115
113
|
/**
|
|
116
|
-
*
|
|
114
|
+
* Primitive operation: List objects under path prefix
|
|
115
|
+
* All metadata operations use this internally via base class routing
|
|
117
116
|
*/
|
|
118
|
-
|
|
117
|
+
protected listObjectsUnderPath(prefix: string): Promise<string[]>;
|
|
119
118
|
/**
|
|
120
|
-
*
|
|
121
|
-
|
|
122
|
-
protected saveVerbMetadata_internal(id: string, metadata: any): Promise<void>;
|
|
123
|
-
/**
|
|
124
|
-
* Get verb metadata from storage
|
|
119
|
+
* Get multiple metadata objects in batches (CRITICAL: Prevents socket exhaustion)
|
|
120
|
+
* FileSystem implementation uses controlled concurrency to prevent too many file reads
|
|
125
121
|
*/
|
|
126
|
-
|
|
122
|
+
getMetadataBatch(ids: string[]): Promise<Map<string, any>>;
|
|
127
123
|
/**
|
|
128
124
|
* Get nouns with pagination support
|
|
129
125
|
* @param options Pagination options
|
|
@@ -449,30 +449,79 @@ export class FileSystemStorage extends BaseStorage {
|
|
|
449
449
|
}
|
|
450
450
|
}
|
|
451
451
|
/**
|
|
452
|
-
*
|
|
452
|
+
* Primitive operation: Write object to path
|
|
453
|
+
* All metadata operations use this internally via base class routing
|
|
453
454
|
*/
|
|
454
|
-
async
|
|
455
|
+
async writeObjectToPath(pathStr, data) {
|
|
455
456
|
await this.ensureInitialized();
|
|
456
|
-
const
|
|
457
|
-
await
|
|
457
|
+
const fullPath = path.join(this.rootDir, pathStr);
|
|
458
|
+
await this.ensureDirectoryExists(path.dirname(fullPath));
|
|
459
|
+
await fs.promises.writeFile(fullPath, JSON.stringify(data, null, 2));
|
|
458
460
|
}
|
|
459
461
|
/**
|
|
460
|
-
*
|
|
462
|
+
* Primitive operation: Read object from path
|
|
463
|
+
* All metadata operations use this internally via base class routing
|
|
461
464
|
*/
|
|
462
|
-
async
|
|
465
|
+
async readObjectFromPath(pathStr) {
|
|
463
466
|
await this.ensureInitialized();
|
|
464
|
-
const
|
|
467
|
+
const fullPath = path.join(this.rootDir, pathStr);
|
|
465
468
|
try {
|
|
466
|
-
const data = await fs.promises.readFile(
|
|
469
|
+
const data = await fs.promises.readFile(fullPath, 'utf-8');
|
|
467
470
|
return JSON.parse(data);
|
|
468
471
|
}
|
|
469
472
|
catch (error) {
|
|
470
|
-
if (error.code
|
|
471
|
-
|
|
473
|
+
if (error.code === 'ENOENT') {
|
|
474
|
+
return null;
|
|
472
475
|
}
|
|
476
|
+
console.error(`Error reading object from ${pathStr}:`, error);
|
|
473
477
|
return null;
|
|
474
478
|
}
|
|
475
479
|
}
|
|
480
|
+
/**
|
|
481
|
+
* Primitive operation: Delete object from path
|
|
482
|
+
* All metadata operations use this internally via base class routing
|
|
483
|
+
*/
|
|
484
|
+
async deleteObjectFromPath(pathStr) {
|
|
485
|
+
await this.ensureInitialized();
|
|
486
|
+
const fullPath = path.join(this.rootDir, pathStr);
|
|
487
|
+
try {
|
|
488
|
+
await fs.promises.unlink(fullPath);
|
|
489
|
+
}
|
|
490
|
+
catch (error) {
|
|
491
|
+
if (error.code !== 'ENOENT') {
|
|
492
|
+
console.error(`Error deleting object from ${pathStr}:`, error);
|
|
493
|
+
throw error;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Primitive operation: List objects under path prefix
|
|
499
|
+
* All metadata operations use this internally via base class routing
|
|
500
|
+
*/
|
|
501
|
+
async listObjectsUnderPath(prefix) {
|
|
502
|
+
await this.ensureInitialized();
|
|
503
|
+
const fullPath = path.join(this.rootDir, prefix);
|
|
504
|
+
const paths = [];
|
|
505
|
+
try {
|
|
506
|
+
const entries = await fs.promises.readdir(fullPath, { withFileTypes: true });
|
|
507
|
+
for (const entry of entries) {
|
|
508
|
+
if (entry.isFile() && entry.name.endsWith('.json')) {
|
|
509
|
+
paths.push(path.join(prefix, entry.name));
|
|
510
|
+
}
|
|
511
|
+
else if (entry.isDirectory()) {
|
|
512
|
+
const subdirPaths = await this.listObjectsUnderPath(path.join(prefix, entry.name));
|
|
513
|
+
paths.push(...subdirPaths);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
return paths.sort();
|
|
517
|
+
}
|
|
518
|
+
catch (error) {
|
|
519
|
+
if (error.code === 'ENOENT') {
|
|
520
|
+
return [];
|
|
521
|
+
}
|
|
522
|
+
throw error;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
476
525
|
/**
|
|
477
526
|
* Get multiple metadata objects in batches (CRITICAL: Prevents socket exhaustion)
|
|
478
527
|
* FileSystem implementation uses controlled concurrency to prevent too many file reads
|
|
@@ -486,7 +535,7 @@ export class FileSystemStorage extends BaseStorage {
|
|
|
486
535
|
const batch = ids.slice(i, i + batchSize);
|
|
487
536
|
const batchPromises = batch.map(async (id) => {
|
|
488
537
|
try {
|
|
489
|
-
const metadata = await this.
|
|
538
|
+
const metadata = await this.getMetadata(id);
|
|
490
539
|
return { id, metadata };
|
|
491
540
|
}
|
|
492
541
|
catch (error) {
|
|
@@ -505,75 +554,6 @@ export class FileSystemStorage extends BaseStorage {
|
|
|
505
554
|
}
|
|
506
555
|
return results;
|
|
507
556
|
}
|
|
508
|
-
/**
|
|
509
|
-
* Save noun metadata to storage
|
|
510
|
-
*/
|
|
511
|
-
async saveNounMetadata_internal(id, metadata) {
|
|
512
|
-
await this.ensureInitialized();
|
|
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 });
|
|
518
|
-
await fs.promises.writeFile(filePath, JSON.stringify(metadata, null, 2));
|
|
519
|
-
}
|
|
520
|
-
/**
|
|
521
|
-
* Get noun metadata from storage
|
|
522
|
-
*/
|
|
523
|
-
async getNounMetadata(id) {
|
|
524
|
-
await this.ensureInitialized();
|
|
525
|
-
// Use UUID-based sharding for metadata (consistent with noun vectors)
|
|
526
|
-
const filePath = this.getShardedPath(this.nounMetadataDir, id);
|
|
527
|
-
try {
|
|
528
|
-
const data = await fs.promises.readFile(filePath, 'utf-8');
|
|
529
|
-
return JSON.parse(data);
|
|
530
|
-
}
|
|
531
|
-
catch (error) {
|
|
532
|
-
if (error.code !== 'ENOENT') {
|
|
533
|
-
console.error(`Error reading noun metadata ${id}:`, error);
|
|
534
|
-
}
|
|
535
|
-
return null;
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
/**
|
|
539
|
-
* Save verb metadata to storage
|
|
540
|
-
*/
|
|
541
|
-
async saveVerbMetadata_internal(id, metadata) {
|
|
542
|
-
await this.ensureInitialized();
|
|
543
|
-
console.log(`[DEBUG] Saving verb metadata for ${id} to: ${this.verbMetadataDir}`);
|
|
544
|
-
const filePath = path.join(this.verbMetadataDir, `${id}.json`);
|
|
545
|
-
console.log(`[DEBUG] Full file path: ${filePath}`);
|
|
546
|
-
try {
|
|
547
|
-
await this.ensureDirectoryExists(path.dirname(filePath));
|
|
548
|
-
console.log(`[DEBUG] Directory ensured: ${path.dirname(filePath)}`);
|
|
549
|
-
await fs.promises.writeFile(filePath, JSON.stringify(metadata, null, 2));
|
|
550
|
-
console.log(`[DEBUG] File written successfully: ${filePath}`);
|
|
551
|
-
// Verify the file was actually written
|
|
552
|
-
const exists = await fs.promises.access(filePath).then(() => true).catch(() => false);
|
|
553
|
-
console.log(`[DEBUG] File exists after write: ${exists}`);
|
|
554
|
-
}
|
|
555
|
-
catch (error) {
|
|
556
|
-
console.error(`[DEBUG] Error saving verb metadata:`, error);
|
|
557
|
-
throw error;
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
/**
|
|
561
|
-
* Get verb metadata from storage
|
|
562
|
-
*/
|
|
563
|
-
async getVerbMetadata(id) {
|
|
564
|
-
await this.ensureInitialized();
|
|
565
|
-
const filePath = path.join(this.verbMetadataDir, `${id}.json`);
|
|
566
|
-
try {
|
|
567
|
-
const data = await fs.promises.readFile(filePath, 'utf-8');
|
|
568
|
-
return JSON.parse(data);
|
|
569
|
-
}
|
|
570
|
-
catch (error) {
|
|
571
|
-
if (error.code !== 'ENOENT') {
|
|
572
|
-
console.error(`Error reading verb metadata ${id}:`, error);
|
|
573
|
-
}
|
|
574
|
-
return null;
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
557
|
/**
|
|
578
558
|
* Get nouns with pagination support
|
|
579
559
|
* @param options Pagination options
|
|
@@ -150,29 +150,29 @@ export declare class GcsStorage extends BaseStorage {
|
|
|
150
150
|
*/
|
|
151
151
|
protected deleteNoun_internal(id: string): Promise<void>;
|
|
152
152
|
/**
|
|
153
|
-
*
|
|
153
|
+
* Write an object to a specific path in GCS
|
|
154
|
+
* Primitive operation required by base class
|
|
155
|
+
* @protected
|
|
154
156
|
*/
|
|
155
|
-
protected
|
|
157
|
+
protected writeObjectToPath(path: string, data: any): Promise<void>;
|
|
156
158
|
/**
|
|
157
|
-
*
|
|
159
|
+
* Read an object from a specific path in GCS
|
|
160
|
+
* Primitive operation required by base class
|
|
161
|
+
* @protected
|
|
158
162
|
*/
|
|
159
|
-
|
|
163
|
+
protected readObjectFromPath(path: string): Promise<any | null>;
|
|
160
164
|
/**
|
|
161
|
-
*
|
|
165
|
+
* Delete an object from a specific path in GCS
|
|
166
|
+
* Primitive operation required by base class
|
|
167
|
+
* @protected
|
|
162
168
|
*/
|
|
163
|
-
|
|
169
|
+
protected deleteObjectFromPath(path: string): Promise<void>;
|
|
164
170
|
/**
|
|
165
|
-
*
|
|
171
|
+
* List all objects under a specific prefix in GCS
|
|
172
|
+
* Primitive operation required by base class
|
|
173
|
+
* @protected
|
|
166
174
|
*/
|
|
167
|
-
|
|
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>;
|
|
175
|
+
protected listObjectsUnderPath(prefix: string): Promise<string[]>;
|
|
176
176
|
/**
|
|
177
177
|
* Save a verb to storage (internal implementation)
|
|
178
178
|
*/
|
|
@@ -438,113 +438,91 @@ export class GcsStorage extends BaseStorage {
|
|
|
438
438
|
}
|
|
439
439
|
}
|
|
440
440
|
/**
|
|
441
|
-
*
|
|
441
|
+
* Write an object to a specific path in GCS
|
|
442
|
+
* Primitive operation required by base class
|
|
443
|
+
* @protected
|
|
442
444
|
*/
|
|
443
|
-
async
|
|
445
|
+
async writeObjectToPath(path, data) {
|
|
444
446
|
await this.ensureInitialized();
|
|
445
447
|
try {
|
|
446
|
-
|
|
447
|
-
const
|
|
448
|
-
|
|
449
|
-
this.logger.trace(`Saving noun metadata for ${id} to key: ${key}`);
|
|
450
|
-
// Save to GCS
|
|
451
|
-
const file = this.bucket.file(key);
|
|
452
|
-
await file.save(JSON.stringify(metadata, null, 2), {
|
|
448
|
+
this.logger.trace(`Writing object to path: ${path}`);
|
|
449
|
+
const file = this.bucket.file(path);
|
|
450
|
+
await file.save(JSON.stringify(data, null, 2), {
|
|
453
451
|
contentType: 'application/json',
|
|
454
452
|
resumable: false
|
|
455
453
|
});
|
|
456
|
-
this.logger.
|
|
454
|
+
this.logger.trace(`Object written successfully to ${path}`);
|
|
457
455
|
}
|
|
458
456
|
catch (error) {
|
|
459
|
-
this.logger.error(`Failed to
|
|
460
|
-
throw new Error(`Failed to
|
|
457
|
+
this.logger.error(`Failed to write object to ${path}:`, error);
|
|
458
|
+
throw new Error(`Failed to write object to ${path}: ${error}`);
|
|
461
459
|
}
|
|
462
460
|
}
|
|
463
461
|
/**
|
|
464
|
-
*
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
return this.saveNounMetadata_internal(id, metadata);
|
|
468
|
-
}
|
|
469
|
-
/**
|
|
470
|
-
* Get metadata from storage (public API - delegates to getNounMetadata)
|
|
471
|
-
*/
|
|
472
|
-
async getMetadata(id) {
|
|
473
|
-
return this.getNounMetadata(id);
|
|
474
|
-
}
|
|
475
|
-
/**
|
|
476
|
-
* Get noun metadata from storage
|
|
462
|
+
* Read an object from a specific path in GCS
|
|
463
|
+
* Primitive operation required by base class
|
|
464
|
+
* @protected
|
|
477
465
|
*/
|
|
478
|
-
async
|
|
466
|
+
async readObjectFromPath(path) {
|
|
479
467
|
await this.ensureInitialized();
|
|
480
468
|
try {
|
|
481
|
-
|
|
482
|
-
const
|
|
483
|
-
const key = `${this.metadataPrefix}${shardId}/${id}.json`;
|
|
484
|
-
this.logger.trace(`Getting noun metadata for ${id} from key: ${key}`);
|
|
485
|
-
// Download from GCS
|
|
486
|
-
const file = this.bucket.file(key);
|
|
469
|
+
this.logger.trace(`Reading object from path: ${path}`);
|
|
470
|
+
const file = this.bucket.file(path);
|
|
487
471
|
const [contents] = await file.download();
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
return metadata;
|
|
472
|
+
const data = JSON.parse(contents.toString());
|
|
473
|
+
this.logger.trace(`Object read successfully from ${path}`);
|
|
474
|
+
return data;
|
|
492
475
|
}
|
|
493
476
|
catch (error) {
|
|
494
477
|
// Check if this is a "not found" error
|
|
495
478
|
if (error.code === 404) {
|
|
496
|
-
this.logger.trace(`
|
|
479
|
+
this.logger.trace(`Object not found at ${path}`);
|
|
497
480
|
return null;
|
|
498
481
|
}
|
|
499
|
-
|
|
500
|
-
throw BrainyError.fromError(error, `
|
|
482
|
+
this.logger.error(`Failed to read object from ${path}:`, error);
|
|
483
|
+
throw BrainyError.fromError(error, `readObjectFromPath(${path})`);
|
|
501
484
|
}
|
|
502
485
|
}
|
|
503
486
|
/**
|
|
504
|
-
*
|
|
487
|
+
* Delete an object from a specific path in GCS
|
|
488
|
+
* Primitive operation required by base class
|
|
489
|
+
* @protected
|
|
505
490
|
*/
|
|
506
|
-
async
|
|
491
|
+
async deleteObjectFromPath(path) {
|
|
507
492
|
await this.ensureInitialized();
|
|
508
493
|
try {
|
|
509
|
-
|
|
510
|
-
this.
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
await file.save(JSON.stringify(metadata, null, 2), {
|
|
514
|
-
contentType: 'application/json',
|
|
515
|
-
resumable: false
|
|
516
|
-
});
|
|
517
|
-
this.logger.debug(`Verb metadata for ${id} saved successfully`);
|
|
494
|
+
this.logger.trace(`Deleting object at path: ${path}`);
|
|
495
|
+
const file = this.bucket.file(path);
|
|
496
|
+
await file.delete();
|
|
497
|
+
this.logger.trace(`Object deleted successfully from ${path}`);
|
|
518
498
|
}
|
|
519
499
|
catch (error) {
|
|
520
|
-
|
|
521
|
-
|
|
500
|
+
// If already deleted (404), treat as success
|
|
501
|
+
if (error.code === 404) {
|
|
502
|
+
this.logger.trace(`Object at ${path} not found (already deleted)`);
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
this.logger.error(`Failed to delete object from ${path}:`, error);
|
|
506
|
+
throw new Error(`Failed to delete object from ${path}: ${error}`);
|
|
522
507
|
}
|
|
523
508
|
}
|
|
524
509
|
/**
|
|
525
|
-
*
|
|
510
|
+
* List all objects under a specific prefix in GCS
|
|
511
|
+
* Primitive operation required by base class
|
|
512
|
+
* @protected
|
|
526
513
|
*/
|
|
527
|
-
async
|
|
514
|
+
async listObjectsUnderPath(prefix) {
|
|
528
515
|
await this.ensureInitialized();
|
|
529
516
|
try {
|
|
530
|
-
|
|
531
|
-
this.
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
// Parse JSON
|
|
536
|
-
const metadata = JSON.parse(contents.toString());
|
|
537
|
-
this.logger.trace(`Successfully retrieved verb metadata for ${id}`);
|
|
538
|
-
return metadata;
|
|
517
|
+
this.logger.trace(`Listing objects under prefix: ${prefix}`);
|
|
518
|
+
const [files] = await this.bucket.getFiles({ prefix });
|
|
519
|
+
const paths = files.map((file) => file.name).filter((name) => name && name.length > 0);
|
|
520
|
+
this.logger.trace(`Found ${paths.length} objects under ${prefix}`);
|
|
521
|
+
return paths;
|
|
539
522
|
}
|
|
540
523
|
catch (error) {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
this.logger.trace(`Verb metadata not found for ${id}`);
|
|
544
|
-
return null;
|
|
545
|
-
}
|
|
546
|
-
// For other types of errors, convert to BrainyError
|
|
547
|
-
throw BrainyError.fromError(error, `getVerbMetadata(${id})`);
|
|
524
|
+
this.logger.error(`Failed to list objects under ${prefix}:`, error);
|
|
525
|
+
throw new Error(`Failed to list objects under ${prefix}: ${error}`);
|
|
548
526
|
}
|
|
549
527
|
}
|
|
550
528
|
/**
|
|
@@ -12,10 +12,11 @@ import { PaginatedResult } from '../../types/paginationTypes.js';
|
|
|
12
12
|
export declare class MemoryStorage extends BaseStorage {
|
|
13
13
|
private nouns;
|
|
14
14
|
private verbs;
|
|
15
|
-
private metadata;
|
|
16
|
-
private nounMetadata;
|
|
17
|
-
private verbMetadata;
|
|
18
15
|
private statistics;
|
|
16
|
+
private objectStore;
|
|
17
|
+
private get metadata();
|
|
18
|
+
private get nounMetadata();
|
|
19
|
+
private get verbMetadata();
|
|
19
20
|
constructor();
|
|
20
21
|
/**
|
|
21
22
|
* Initialize the storage adapter
|
|
@@ -118,34 +119,30 @@ export declare class MemoryStorage extends BaseStorage {
|
|
|
118
119
|
*/
|
|
119
120
|
protected deleteVerb_internal(id: string): Promise<void>;
|
|
120
121
|
/**
|
|
121
|
-
*
|
|
122
|
+
* Primitive operation: Write object to path
|
|
123
|
+
* All metadata operations use this internally via base class routing
|
|
122
124
|
*/
|
|
123
|
-
|
|
125
|
+
protected writeObjectToPath(path: string, data: any): Promise<void>;
|
|
124
126
|
/**
|
|
125
|
-
*
|
|
127
|
+
* Primitive operation: Read object from path
|
|
128
|
+
* All metadata operations use this internally via base class routing
|
|
126
129
|
*/
|
|
127
|
-
|
|
130
|
+
protected readObjectFromPath(path: string): Promise<any | null>;
|
|
128
131
|
/**
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*/
|
|
132
|
-
getMetadataBatch(ids: string[]): Promise<Map<string, any>>;
|
|
133
|
-
/**
|
|
134
|
-
* Save noun metadata to storage (internal implementation)
|
|
132
|
+
* Primitive operation: Delete object from path
|
|
133
|
+
* All metadata operations use this internally via base class routing
|
|
135
134
|
*/
|
|
136
|
-
protected
|
|
135
|
+
protected deleteObjectFromPath(path: string): Promise<void>;
|
|
137
136
|
/**
|
|
138
|
-
*
|
|
137
|
+
* Primitive operation: List objects under path prefix
|
|
138
|
+
* All metadata operations use this internally via base class routing
|
|
139
139
|
*/
|
|
140
|
-
|
|
140
|
+
protected listObjectsUnderPath(prefix: string): Promise<string[]>;
|
|
141
141
|
/**
|
|
142
|
-
*
|
|
143
|
-
|
|
144
|
-
protected saveVerbMetadata_internal(id: string, metadata: any): Promise<void>;
|
|
145
|
-
/**
|
|
146
|
-
* Get verb metadata from storage
|
|
142
|
+
* Get multiple metadata objects in batches (CRITICAL: Prevents socket exhaustion)
|
|
143
|
+
* Memory storage implementation is simple since all data is already in memory
|
|
147
144
|
*/
|
|
148
|
-
|
|
145
|
+
getMetadataBatch(ids: string[]): Promise<Map<string, any>>;
|
|
149
146
|
/**
|
|
150
147
|
* Clear all data from storage
|
|
151
148
|
*/
|