@cmdoss/memwal-sdk 0.6.2 → 0.8.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/ARCHITECTURE.md +547 -547
- package/BENCHMARKS.md +238 -238
- package/README.md +310 -181
- package/dist/ai-sdk/tools.d.ts +2 -2
- package/dist/ai-sdk/tools.js +2 -2
- package/dist/client/ClientMemoryManager.js +2 -2
- package/dist/client/ClientMemoryManager.js.map +1 -1
- package/dist/client/PersonalDataWallet.d.ts.map +1 -1
- package/dist/client/SimplePDWClient.d.ts +29 -1
- package/dist/client/SimplePDWClient.d.ts.map +1 -1
- package/dist/client/SimplePDWClient.js +45 -13
- package/dist/client/SimplePDWClient.js.map +1 -1
- package/dist/client/namespaces/EmbeddingsNamespace.d.ts +1 -1
- package/dist/client/namespaces/EmbeddingsNamespace.js +1 -1
- package/dist/client/namespaces/MemoryNamespace.d.ts +31 -0
- package/dist/client/namespaces/MemoryNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/MemoryNamespace.js +272 -39
- package/dist/client/namespaces/MemoryNamespace.js.map +1 -1
- package/dist/client/namespaces/consolidated/AINamespace.d.ts +2 -2
- package/dist/client/namespaces/consolidated/AINamespace.js +2 -2
- package/dist/client/namespaces/consolidated/BlockchainNamespace.d.ts +12 -2
- package/dist/client/namespaces/consolidated/BlockchainNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/consolidated/BlockchainNamespace.js +62 -4
- package/dist/client/namespaces/consolidated/BlockchainNamespace.js.map +1 -1
- package/dist/client/namespaces/consolidated/StorageNamespace.d.ts +67 -2
- package/dist/client/namespaces/consolidated/StorageNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/consolidated/StorageNamespace.js +549 -16
- package/dist/client/namespaces/consolidated/StorageNamespace.js.map +1 -1
- package/dist/config/ConfigurationHelper.js +61 -61
- package/dist/config/defaults.js +2 -2
- package/dist/config/defaults.js.map +1 -1
- package/dist/graph/GraphService.js +21 -21
- package/dist/graph/GraphService.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/seal/EncryptionService.d.ts +9 -5
- package/dist/infrastructure/seal/EncryptionService.d.ts.map +1 -1
- package/dist/infrastructure/seal/EncryptionService.js +37 -15
- package/dist/infrastructure/seal/EncryptionService.js.map +1 -1
- package/dist/infrastructure/seal/SealService.d.ts +13 -5
- package/dist/infrastructure/seal/SealService.d.ts.map +1 -1
- package/dist/infrastructure/seal/SealService.js +36 -34
- package/dist/infrastructure/seal/SealService.js.map +1 -1
- package/dist/langchain/createPDWRAG.js +30 -30
- package/dist/retrieval/MemoryDecryptionPipeline.d.ts.map +1 -1
- package/dist/retrieval/MemoryDecryptionPipeline.js +2 -1
- package/dist/retrieval/MemoryDecryptionPipeline.js.map +1 -1
- package/dist/retrieval/MemoryRetrievalService.d.ts +31 -0
- package/dist/retrieval/MemoryRetrievalService.d.ts.map +1 -1
- package/dist/retrieval/MemoryRetrievalService.js +44 -4
- package/dist/retrieval/MemoryRetrievalService.js.map +1 -1
- package/dist/services/CapabilityService.d.ts.map +1 -1
- package/dist/services/CapabilityService.js +30 -14
- package/dist/services/CapabilityService.js.map +1 -1
- package/dist/services/CrossContextPermissionService.d.ts.map +1 -1
- package/dist/services/CrossContextPermissionService.js +9 -7
- package/dist/services/CrossContextPermissionService.js.map +1 -1
- package/dist/services/EmbeddingService.d.ts +28 -1
- package/dist/services/EmbeddingService.d.ts.map +1 -1
- package/dist/services/EmbeddingService.js +54 -0
- package/dist/services/EmbeddingService.js.map +1 -1
- package/dist/services/EncryptionService.d.ts.map +1 -1
- package/dist/services/EncryptionService.js +6 -5
- package/dist/services/EncryptionService.js.map +1 -1
- package/dist/services/GeminiAIService.js +309 -309
- package/dist/services/IndexManager.d.ts +5 -1
- package/dist/services/IndexManager.d.ts.map +1 -1
- package/dist/services/IndexManager.js +17 -40
- package/dist/services/IndexManager.js.map +1 -1
- package/dist/services/QueryService.js +1 -1
- package/dist/services/QueryService.js.map +1 -1
- package/dist/services/StorageService.d.ts +11 -0
- package/dist/services/StorageService.d.ts.map +1 -1
- package/dist/services/StorageService.js +73 -10
- package/dist/services/StorageService.js.map +1 -1
- package/dist/services/TransactionService.d.ts +20 -0
- package/dist/services/TransactionService.d.ts.map +1 -1
- package/dist/services/TransactionService.js +43 -0
- package/dist/services/TransactionService.js.map +1 -1
- package/dist/services/ViewService.js +2 -2
- package/dist/services/ViewService.js.map +1 -1
- package/dist/services/storage/QuiltBatchManager.d.ts +101 -1
- package/dist/services/storage/QuiltBatchManager.d.ts.map +1 -1
- package/dist/services/storage/QuiltBatchManager.js +410 -20
- package/dist/services/storage/QuiltBatchManager.js.map +1 -1
- package/dist/services/storage/index.d.ts +1 -1
- package/dist/services/storage/index.d.ts.map +1 -1
- package/dist/services/storage/index.js.map +1 -1
- package/dist/utils/LRUCache.d.ts +106 -0
- package/dist/utils/LRUCache.d.ts.map +1 -0
- package/dist/utils/LRUCache.js +281 -0
- package/dist/utils/LRUCache.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/memoryIndexOnChain.d.ts +212 -0
- package/dist/utils/memoryIndexOnChain.d.ts.map +1 -0
- package/dist/utils/memoryIndexOnChain.js +312 -0
- package/dist/utils/memoryIndexOnChain.js.map +1 -0
- package/dist/utils/rebuildIndexNode.d.ts +29 -0
- package/dist/utils/rebuildIndexNode.d.ts.map +1 -1
- package/dist/utils/rebuildIndexNode.js +366 -98
- package/dist/utils/rebuildIndexNode.js.map +1 -1
- package/dist/vector/HnswWasmService.d.ts +20 -5
- package/dist/vector/HnswWasmService.d.ts.map +1 -1
- package/dist/vector/HnswWasmService.js +73 -40
- package/dist/vector/HnswWasmService.js.map +1 -1
- package/dist/vector/IHnswService.d.ts +10 -1
- package/dist/vector/IHnswService.d.ts.map +1 -1
- package/dist/vector/IHnswService.js.map +1 -1
- package/dist/vector/NodeHnswService.d.ts +16 -0
- package/dist/vector/NodeHnswService.d.ts.map +1 -1
- package/dist/vector/NodeHnswService.js +84 -5
- package/dist/vector/NodeHnswService.js.map +1 -1
- package/dist/vector/createHnswService.d.ts +1 -1
- package/dist/vector/createHnswService.js +1 -1
- package/dist/vector/index.d.ts +1 -1
- package/dist/vector/index.js +1 -1
- package/package.json +157 -157
- package/src/access/PermissionService.ts +635 -635
- package/src/aggregation/AggregationService.ts +389 -389
- package/src/ai-sdk/PDWVectorStore.ts +715 -715
- package/src/ai-sdk/index.ts +65 -65
- package/src/ai-sdk/tools.ts +460 -460
- package/src/ai-sdk/types.ts +404 -404
- package/src/batch/BatchManager.ts +597 -597
- package/src/batch/BatchingService.ts +429 -429
- package/src/batch/MemoryProcessingCache.ts +492 -492
- package/src/batch/index.ts +30 -30
- package/src/browser.ts +200 -200
- package/src/client/ClientMemoryManager.ts +987 -987
- package/src/client/PersonalDataWallet.ts +345 -345
- package/src/client/SimplePDWClient.ts +1289 -1222
- package/src/client/factory.ts +154 -154
- package/src/client/namespaces/AnalyticsNamespace.ts +377 -377
- package/src/client/namespaces/BatchNamespace.ts +356 -356
- package/src/client/namespaces/CacheNamespace.ts +123 -123
- package/src/client/namespaces/CapabilityNamespace.ts +217 -217
- package/src/client/namespaces/ClassifyNamespace.ts +169 -169
- package/src/client/namespaces/ContextNamespace.ts +297 -297
- package/src/client/namespaces/EmbeddingsNamespace.ts +99 -99
- package/src/client/namespaces/EncryptionNamespace.ts +221 -221
- package/src/client/namespaces/GraphNamespace.ts +468 -468
- package/src/client/namespaces/IndexNamespace.ts +361 -361
- package/src/client/namespaces/MemoryNamespace.ts +1422 -1135
- package/src/client/namespaces/PermissionsNamespace.ts +254 -254
- package/src/client/namespaces/PipelineNamespace.ts +220 -220
- package/src/client/namespaces/SearchNamespace.ts +1049 -1049
- package/src/client/namespaces/StorageNamespace.ts +458 -458
- package/src/client/namespaces/TxNamespace.ts +260 -260
- package/src/client/namespaces/WalletNamespace.ts +243 -243
- package/src/client/namespaces/consolidated/AINamespace.ts +449 -449
- package/src/client/namespaces/consolidated/BlockchainNamespace.ts +607 -546
- package/src/client/namespaces/consolidated/SecurityNamespace.ts +648 -648
- package/src/client/namespaces/consolidated/StorageNamespace.ts +1141 -497
- package/src/client/namespaces/consolidated/index.ts +39 -39
- package/src/client/signers/KeypairSigner.ts +108 -108
- package/src/client/signers/UnifiedSigner.ts +110 -110
- package/src/client/signers/WalletAdapterSigner.ts +159 -159
- package/src/client/signers/index.ts +26 -26
- package/src/config/ConfigurationHelper.ts +412 -412
- package/src/config/defaults.ts +51 -51
- package/src/config/index.ts +8 -8
- package/src/config/validation.ts +70 -70
- package/src/core/index.ts +14 -14
- package/src/core/interfaces/IService.ts +307 -307
- package/src/core/interfaces/index.ts +8 -8
- package/src/core/types/capability.ts +297 -297
- package/src/core/types/index.ts +870 -870
- package/src/core/types/wallet.ts +270 -270
- package/src/core/types.ts +9 -9
- package/src/core/wallet.ts +222 -222
- package/src/embedding/index.ts +19 -19
- package/src/embedding/types.ts +357 -357
- package/src/errors/index.ts +602 -602
- package/src/errors/recovery.ts +461 -461
- package/src/errors/validation.ts +567 -567
- package/src/generated/pdw/capability.ts +319 -319
- package/src/graph/GraphService.ts +887 -887
- package/src/graph/KnowledgeGraphManager.ts +728 -728
- package/src/graph/index.ts +25 -25
- package/src/index.ts +498 -474
- package/src/infrastructure/index.ts +22 -22
- package/src/infrastructure/seal/EncryptionService.ts +628 -603
- package/src/infrastructure/seal/SealService.ts +613 -615
- package/src/infrastructure/seal/index.ts +9 -9
- package/src/infrastructure/sui/BlockchainManager.ts +627 -627
- package/src/infrastructure/sui/SuiService.ts +888 -888
- package/src/infrastructure/sui/index.ts +9 -9
- package/src/infrastructure/walrus/StorageManager.ts +604 -604
- package/src/infrastructure/walrus/WalrusStorageService.ts +612 -612
- package/src/infrastructure/walrus/index.ts +9 -9
- package/src/langchain/PDWEmbeddings.ts +145 -145
- package/src/langchain/PDWVectorStore.ts +456 -456
- package/src/langchain/createPDWRAG.ts +303 -303
- package/src/langchain/index.ts +47 -47
- package/src/permissions/ConsentRepository.browser.ts +249 -249
- package/src/permissions/ConsentRepository.ts +364 -364
- package/src/pipeline/MemoryPipeline.ts +862 -862
- package/src/pipeline/PipelineManager.ts +683 -683
- package/src/pipeline/index.ts +26 -26
- package/src/retrieval/AdvancedSearchService.ts +629 -629
- package/src/retrieval/MemoryAnalyticsService.ts +711 -711
- package/src/retrieval/MemoryDecryptionPipeline.ts +825 -824
- package/src/retrieval/MemoryRetrievalService.ts +904 -830
- package/src/retrieval/index.ts +42 -42
- package/src/services/BatchService.ts +352 -352
- package/src/services/CapabilityService.ts +464 -448
- package/src/services/ClassifierService.ts +465 -465
- package/src/services/CrossContextPermissionService.ts +486 -484
- package/src/services/EmbeddingService.ts +771 -706
- package/src/services/EncryptionService.ts +712 -711
- package/src/services/GeminiAIService.ts +753 -753
- package/src/services/IndexManager.ts +977 -1004
- package/src/services/MemoryIndexService.ts +1003 -1003
- package/src/services/MemoryService.ts +369 -369
- package/src/services/QueryService.ts +890 -890
- package/src/services/StorageService.ts +1182 -1111
- package/src/services/TransactionService.ts +838 -790
- package/src/services/VectorService.ts +462 -462
- package/src/services/ViewService.ts +484 -484
- package/src/services/index.ts +25 -25
- package/src/services/storage/BlobAttributesManager.ts +333 -333
- package/src/services/storage/KnowledgeGraphManager.ts +425 -425
- package/src/services/storage/MemorySearchManager.ts +387 -387
- package/src/services/storage/QuiltBatchManager.ts +1130 -660
- package/src/services/storage/WalrusMetadataManager.ts +268 -268
- package/src/services/storage/WalrusStorageManager.ts +287 -287
- package/src/services/storage/index.ts +57 -52
- package/src/types/index.ts +13 -13
- package/src/utils/LRUCache.ts +378 -0
- package/src/utils/index.ts +76 -68
- package/src/utils/memoryIndexOnChain.ts +507 -0
- package/src/utils/rebuildIndex.ts +290 -290
- package/src/utils/rebuildIndexNode.ts +771 -424
- package/src/vector/BrowserHnswIndexService.ts +758 -758
- package/src/vector/HnswWasmService.ts +731 -679
- package/src/vector/IHnswService.ts +233 -224
- package/src/vector/NodeHnswService.ts +833 -735
- package/src/vector/VectorManager.ts +478 -478
- package/src/vector/createHnswService.ts +135 -135
- package/src/vector/index.ts +56 -56
- package/src/wallet/ContextWalletService.ts +656 -656
- package/src/wallet/MainWalletService.ts +317 -317
|
@@ -1,605 +1,605 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* StorageManager - Unified Storage Operations Manager
|
|
3
|
-
*
|
|
4
|
-
* Orchestrates Walrus storage operations with intelligent batching,
|
|
5
|
-
* encryption management, and seamless integration with memory processing.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { WalrusStorageService, WalrusUploadResult, WalrusRetrievalResult, MemoryMetadata } from './WalrusStorageService';
|
|
9
|
-
import { ProcessedMemory } from '../../embedding/types';
|
|
10
|
-
|
|
11
|
-
export interface StorageManagerConfig {
|
|
12
|
-
walrusConfig?: {
|
|
13
|
-
network?: 'testnet' | 'mainnet';
|
|
14
|
-
enableEncryption?: boolean;
|
|
15
|
-
enableBatching?: boolean;
|
|
16
|
-
batchSize?: number;
|
|
17
|
-
batchDelayMs?: number;
|
|
18
|
-
};
|
|
19
|
-
enableDistributedStorage?: boolean;
|
|
20
|
-
enableCompressionn?: boolean;
|
|
21
|
-
retentionPolicyDays?: number;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface StorageResult {
|
|
25
|
-
success: boolean;
|
|
26
|
-
blobId?: string;
|
|
27
|
-
metadata?: MemoryMetadata;
|
|
28
|
-
error?: string;
|
|
29
|
-
processingTimeMs: number;
|
|
30
|
-
isEncrypted: boolean;
|
|
31
|
-
storageProvider: 'walrus' | 'local' | 'distributed';
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface RetrievalOptions {
|
|
35
|
-
includeMetadata?: boolean;
|
|
36
|
-
decryptionKey?: string;
|
|
37
|
-
preferCache?: boolean;
|
|
38
|
-
timeout?: number;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface StorageBatchOperation {
|
|
42
|
-
memory: ProcessedMemory;
|
|
43
|
-
userId: string;
|
|
44
|
-
priority?: 'low' | 'normal' | 'high';
|
|
45
|
-
encryptionRequired?: boolean;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export interface StorageBatchResult {
|
|
49
|
-
successful: StorageResult[];
|
|
50
|
-
failed: Array<{ memory: ProcessedMemory; error: string }>;
|
|
51
|
-
totalProcessingTime: number;
|
|
52
|
-
averageProcessingTime: number;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export interface StorageStats {
|
|
56
|
-
totalOperations: number;
|
|
57
|
-
successfulUploads: number;
|
|
58
|
-
failedUploads: number;
|
|
59
|
-
totalRetrievals: number;
|
|
60
|
-
storageProviders: {
|
|
61
|
-
walrus: { uploads: number; retrievals: number; success_rate: number };
|
|
62
|
-
local: { uploads: number; retrievals: number; success_rate: number };
|
|
63
|
-
};
|
|
64
|
-
averageUploadTime: number;
|
|
65
|
-
averageRetrievalTime: number;
|
|
66
|
-
totalStorageUsed: number;
|
|
67
|
-
encryptionRate: number;
|
|
68
|
-
compressionSavings: number;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Unified storage manager coordinating multiple storage providers
|
|
73
|
-
*/
|
|
74
|
-
export class StorageManager {
|
|
75
|
-
private walrusService: WalrusStorageService;
|
|
76
|
-
private pendingOperations = new Map<string, Promise<StorageResult>>();
|
|
77
|
-
private batchQueue: StorageBatchOperation[] = [];
|
|
78
|
-
private batchTimer?: NodeJS.Timeout;
|
|
79
|
-
|
|
80
|
-
private readonly config: Required<StorageManagerConfig>;
|
|
81
|
-
private stats: StorageStats = {
|
|
82
|
-
totalOperations: 0,
|
|
83
|
-
successfulUploads: 0,
|
|
84
|
-
failedUploads: 0,
|
|
85
|
-
totalRetrievals: 0,
|
|
86
|
-
storageProviders: {
|
|
87
|
-
walrus: { uploads: 0, retrievals: 0, success_rate: 0 },
|
|
88
|
-
local: { uploads: 0, retrievals: 0, success_rate: 0 }
|
|
89
|
-
},
|
|
90
|
-
averageUploadTime: 0,
|
|
91
|
-
averageRetrievalTime: 0,
|
|
92
|
-
totalStorageUsed: 0,
|
|
93
|
-
encryptionRate: 0,
|
|
94
|
-
compressionSavings: 0
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
constructor(config: StorageManagerConfig = {}) {
|
|
98
|
-
this.config = {
|
|
99
|
-
walrusConfig: {
|
|
100
|
-
network: config.walrusConfig?.network || 'testnet',
|
|
101
|
-
enableEncryption: config.walrusConfig?.enableEncryption !== false,
|
|
102
|
-
enableBatching: config.walrusConfig?.enableBatching !== false,
|
|
103
|
-
batchSize: config.walrusConfig?.batchSize || 10,
|
|
104
|
-
batchDelayMs: config.walrusConfig?.batchDelayMs || 5000
|
|
105
|
-
},
|
|
106
|
-
enableDistributedStorage: config.enableDistributedStorage !== false,
|
|
107
|
-
enableCompressionn: config.enableCompressionn !== false,
|
|
108
|
-
retentionPolicyDays: config.retentionPolicyDays || 365
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
// Initialize Walrus service
|
|
112
|
-
this.walrusService = new WalrusStorageService({
|
|
113
|
-
network: this.config.walrusConfig.network
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// ==================== MEMORY STORAGE OPERATIONS ====================
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Store processed memory with comprehensive options
|
|
121
|
-
*/
|
|
122
|
-
async storeMemory(
|
|
123
|
-
memory: ProcessedMemory,
|
|
124
|
-
userId: string,
|
|
125
|
-
options: {
|
|
126
|
-
priority?: 'low' | 'normal' | 'high';
|
|
127
|
-
enableEncryption?: boolean;
|
|
128
|
-
enableBatching?: boolean;
|
|
129
|
-
customMetadata?: Record<string, string>;
|
|
130
|
-
} = {}
|
|
131
|
-
): Promise<StorageResult> {
|
|
132
|
-
const startTime = Date.now();
|
|
133
|
-
this.stats.totalOperations++;
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
// Check for duplicate operation
|
|
137
|
-
const operationKey = `${memory.id}_${userId}`;
|
|
138
|
-
const existingOperation = this.pendingOperations.get(operationKey);
|
|
139
|
-
if (existingOperation) {
|
|
140
|
-
return await existingOperation;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Create operation promise
|
|
144
|
-
const operationPromise = this.executeStoreOperation(memory, userId, options);
|
|
145
|
-
this.pendingOperations.set(operationKey, operationPromise);
|
|
146
|
-
|
|
147
|
-
try {
|
|
148
|
-
const result = await operationPromise;
|
|
149
|
-
this.updateStorageStats(result);
|
|
150
|
-
return result;
|
|
151
|
-
} finally {
|
|
152
|
-
this.pendingOperations.delete(operationKey);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
} catch (error) {
|
|
156
|
-
this.stats.failedUploads++;
|
|
157
|
-
return {
|
|
158
|
-
success: false,
|
|
159
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
160
|
-
processingTimeMs: Date.now() - startTime,
|
|
161
|
-
isEncrypted: false,
|
|
162
|
-
storageProvider: 'local'
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Store multiple memories in batch
|
|
169
|
-
*/
|
|
170
|
-
async storeMemoryBatch(
|
|
171
|
-
operations: StorageBatchOperation[],
|
|
172
|
-
options: {
|
|
173
|
-
enableProgress?: boolean;
|
|
174
|
-
onProgress?: (completed: number, total: number) => void;
|
|
175
|
-
maxConcurrent?: number;
|
|
176
|
-
} = {}
|
|
177
|
-
): Promise<StorageBatchResult> {
|
|
178
|
-
const startTime = Date.now();
|
|
179
|
-
const maxConcurrent = options.maxConcurrent || 5;
|
|
180
|
-
const successful: StorageResult[] = [];
|
|
181
|
-
const failed: Array<{ memory: ProcessedMemory; error: string }> = [];
|
|
182
|
-
|
|
183
|
-
// Sort by priority (high -> normal -> low)
|
|
184
|
-
const sortedOps = [...operations].sort((a, b) => {
|
|
185
|
-
const priorityOrder = { high: 3, normal: 2, low: 1 };
|
|
186
|
-
const aPriority = priorityOrder[a.priority || 'normal'];
|
|
187
|
-
const bPriority = priorityOrder[b.priority || 'normal'];
|
|
188
|
-
return bPriority - aPriority;
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
// Process in batches to control concurrency
|
|
192
|
-
for (let i = 0; i < sortedOps.length; i += maxConcurrent) {
|
|
193
|
-
const batch = sortedOps.slice(i, i + maxConcurrent);
|
|
194
|
-
|
|
195
|
-
const batchPromises = batch.map(async (op) => {
|
|
196
|
-
try {
|
|
197
|
-
const result = await this.storeMemory(op.memory, op.userId, {
|
|
198
|
-
priority: op.priority,
|
|
199
|
-
enableEncryption: op.encryptionRequired
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
if (result.success) {
|
|
203
|
-
successful.push(result);
|
|
204
|
-
} else {
|
|
205
|
-
failed.push({ memory: op.memory, error: result.error || 'Unknown error' });
|
|
206
|
-
}
|
|
207
|
-
} catch (error) {
|
|
208
|
-
failed.push({ memory: op.memory, error: error instanceof Error ? error.message : 'Unknown error' });
|
|
209
|
-
}
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
await Promise.all(batchPromises);
|
|
213
|
-
|
|
214
|
-
// Progress callback
|
|
215
|
-
if (options.onProgress) {
|
|
216
|
-
options.onProgress(i + batch.length, operations.length);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
const totalTime = Date.now() - startTime;
|
|
221
|
-
const averageTime = operations.length > 0 ? totalTime / operations.length : 0;
|
|
222
|
-
|
|
223
|
-
return {
|
|
224
|
-
successful,
|
|
225
|
-
failed,
|
|
226
|
-
totalProcessingTime: totalTime,
|
|
227
|
-
averageProcessingTime: averageTime
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Add memory to batch queue for deferred processing
|
|
233
|
-
*/
|
|
234
|
-
addToBatchQueue(
|
|
235
|
-
memory: ProcessedMemory,
|
|
236
|
-
userId: string,
|
|
237
|
-
options: {
|
|
238
|
-
priority?: 'low' | 'normal' | 'high';
|
|
239
|
-
encryptionRequired?: boolean;
|
|
240
|
-
} = {}
|
|
241
|
-
): void {
|
|
242
|
-
this.batchQueue.push({
|
|
243
|
-
memory,
|
|
244
|
-
userId,
|
|
245
|
-
priority: options.priority || 'normal',
|
|
246
|
-
encryptionRequired: options.encryptionRequired
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
// Schedule batch processing
|
|
250
|
-
this.scheduleBatchProcessing();
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* Process pending batch queue
|
|
255
|
-
*/
|
|
256
|
-
async processBatchQueue(): Promise<StorageBatchResult> {
|
|
257
|
-
if (this.batchQueue.length === 0) {
|
|
258
|
-
return {
|
|
259
|
-
successful: [],
|
|
260
|
-
failed: [],
|
|
261
|
-
totalProcessingTime: 0,
|
|
262
|
-
averageProcessingTime: 0
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
const operations = [...this.batchQueue];
|
|
267
|
-
this.batchQueue.length = 0; // Clear queue
|
|
268
|
-
|
|
269
|
-
if (this.batchTimer) {
|
|
270
|
-
clearTimeout(this.batchTimer);
|
|
271
|
-
this.batchTimer = undefined;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
return await this.storeMemoryBatch(operations);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// ==================== RETRIEVAL OPERATIONS ====================
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Retrieve memory by blob ID
|
|
281
|
-
*/
|
|
282
|
-
async retrieveMemory(
|
|
283
|
-
blobId: string,
|
|
284
|
-
options: RetrievalOptions = {}
|
|
285
|
-
): Promise<{
|
|
286
|
-
memory: ProcessedMemory | null;
|
|
287
|
-
metadata: MemoryMetadata | null;
|
|
288
|
-
retrievalTimeMs: number;
|
|
289
|
-
isFromCache: boolean;
|
|
290
|
-
}> {
|
|
291
|
-
const startTime = Date.now();
|
|
292
|
-
this.stats.totalRetrievals++;
|
|
293
|
-
|
|
294
|
-
try {
|
|
295
|
-
const result = await this.walrusService.retrieveContent(blobId, options.decryptionKey);
|
|
296
|
-
|
|
297
|
-
// Parse content as memory
|
|
298
|
-
let memory: ProcessedMemory | null = null;
|
|
299
|
-
try {
|
|
300
|
-
const parsed = JSON.parse(result.content as string);
|
|
301
|
-
if (parsed && typeof parsed === 'object' && parsed.id) {
|
|
302
|
-
memory = parsed as ProcessedMemory;
|
|
303
|
-
}
|
|
304
|
-
} catch {
|
|
305
|
-
// Content might not be a memory object
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
this.updateRetrievalStats(Date.now() - startTime);
|
|
309
|
-
|
|
310
|
-
return {
|
|
311
|
-
memory,
|
|
312
|
-
metadata: options.includeMetadata ? result.metadata : null,
|
|
313
|
-
retrievalTimeMs: result.retrievalTimeMs,
|
|
314
|
-
isFromCache: result.isFromCache
|
|
315
|
-
};
|
|
316
|
-
|
|
317
|
-
} catch (error) {
|
|
318
|
-
console.error('Memory retrieval failed:', error);
|
|
319
|
-
return {
|
|
320
|
-
memory: null,
|
|
321
|
-
metadata: null,
|
|
322
|
-
retrievalTimeMs: Date.now() - startTime,
|
|
323
|
-
isFromCache: false
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* Retrieve multiple memories by blob IDs
|
|
330
|
-
*/
|
|
331
|
-
async retrieveMemoryBatch(
|
|
332
|
-
blobIds: string[],
|
|
333
|
-
options: RetrievalOptions & {
|
|
334
|
-
batchSize?: number;
|
|
335
|
-
decryptionKeys?: Record<string, string>;
|
|
336
|
-
} = {}
|
|
337
|
-
): Promise<Array<{
|
|
338
|
-
blobId: string;
|
|
339
|
-
memory: ProcessedMemory | null;
|
|
340
|
-
metadata: MemoryMetadata | null;
|
|
341
|
-
success: boolean;
|
|
342
|
-
error?: string;
|
|
343
|
-
}>> {
|
|
344
|
-
const batchSize = options.batchSize || 10;
|
|
345
|
-
const results: Array<{
|
|
346
|
-
blobId: string;
|
|
347
|
-
memory: ProcessedMemory | null;
|
|
348
|
-
metadata: MemoryMetadata | null;
|
|
349
|
-
success: boolean;
|
|
350
|
-
error?: string;
|
|
351
|
-
}> = [];
|
|
352
|
-
|
|
353
|
-
// Process in batches
|
|
354
|
-
for (let i = 0; i < blobIds.length; i += batchSize) {
|
|
355
|
-
const batch = blobIds.slice(i, i + batchSize);
|
|
356
|
-
|
|
357
|
-
const batchPromises = batch.map(async (blobId) => {
|
|
358
|
-
try {
|
|
359
|
-
const decryptionKey = options.decryptionKeys?.[blobId] || options.decryptionKey;
|
|
360
|
-
const result = await this.retrieveMemory(blobId, { ...options, decryptionKey });
|
|
361
|
-
|
|
362
|
-
return {
|
|
363
|
-
blobId,
|
|
364
|
-
memory: result.memory,
|
|
365
|
-
metadata: result.metadata,
|
|
366
|
-
success: result.memory !== null
|
|
367
|
-
};
|
|
368
|
-
} catch (error) {
|
|
369
|
-
return {
|
|
370
|
-
blobId,
|
|
371
|
-
memory: null,
|
|
372
|
-
metadata: null,
|
|
373
|
-
success: false,
|
|
374
|
-
error: error instanceof Error ? error.message : 'Unknown error'
|
|
375
|
-
};
|
|
376
|
-
}
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
const batchResults = await Promise.all(batchPromises);
|
|
380
|
-
results.push(...batchResults);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
return results;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// ==================== STORAGE MANAGEMENT ====================
|
|
387
|
-
|
|
388
|
-
/**
|
|
389
|
-
* List user's stored memories
|
|
390
|
-
*/
|
|
391
|
-
async listUserMemories(
|
|
392
|
-
userId: string,
|
|
393
|
-
options: {
|
|
394
|
-
category?: string;
|
|
395
|
-
limit?: number;
|
|
396
|
-
offset?: number;
|
|
397
|
-
sortBy?: 'date' | 'size' | 'importance';
|
|
398
|
-
includeMetadata?: boolean;
|
|
399
|
-
} = {}
|
|
400
|
-
) {
|
|
401
|
-
try {
|
|
402
|
-
const blobResult = await this.walrusService.listUserBlobs(userId, {
|
|
403
|
-
category: options.category,
|
|
404
|
-
limit: options.limit,
|
|
405
|
-
offset: options.offset,
|
|
406
|
-
sortBy: options.sortBy
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
const memories = [];
|
|
410
|
-
|
|
411
|
-
for (const blob of blobResult.blobs) {
|
|
412
|
-
try {
|
|
413
|
-
const result = await this.retrieveMemory(blob.blobId, {
|
|
414
|
-
includeMetadata: options.includeMetadata
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
if (result.memory) {
|
|
418
|
-
memories.push({
|
|
419
|
-
memory: result.memory,
|
|
420
|
-
blobId: blob.blobId,
|
|
421
|
-
metadata: result.metadata,
|
|
422
|
-
blobInfo: blob
|
|
423
|
-
});
|
|
424
|
-
}
|
|
425
|
-
} catch (error) {
|
|
426
|
-
console.warn(`Failed to retrieve memory ${blob.blobId}:`, error);
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
return memories;
|
|
431
|
-
|
|
432
|
-
} catch (error) {
|
|
433
|
-
console.error('Failed to list user memories:', error);
|
|
434
|
-
return [];
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
/**
|
|
439
|
-
* Delete stored memory
|
|
440
|
-
*/
|
|
441
|
-
async deleteMemory(blobId: string): Promise<boolean> {
|
|
442
|
-
try {
|
|
443
|
-
return await this.walrusService.deleteBlob(blobId);
|
|
444
|
-
} catch (error) {
|
|
445
|
-
console.error('Failed to delete memory:', error);
|
|
446
|
-
return false;
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
/**
|
|
451
|
-
* Get storage analytics
|
|
452
|
-
*/
|
|
453
|
-
getStorageAnalytics() {
|
|
454
|
-
const walrusStats = this.walrusService.getStats();
|
|
455
|
-
const cacheInfo = this.walrusService.getCacheInfo();
|
|
456
|
-
|
|
457
|
-
return {
|
|
458
|
-
...this.stats,
|
|
459
|
-
walrusService: walrusStats,
|
|
460
|
-
cache: cacheInfo,
|
|
461
|
-
batchQueue: {
|
|
462
|
-
pending: this.batchQueue.length,
|
|
463
|
-
operations: this.pendingOperations.size
|
|
464
|
-
}
|
|
465
|
-
};
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
/**
|
|
469
|
-
* Cleanup old data based on retention policy
|
|
470
|
-
*/
|
|
471
|
-
async cleanupOldData(): Promise<{
|
|
472
|
-
deletedCount: number;
|
|
473
|
-
freedSpaceBytes: number;
|
|
474
|
-
}> {
|
|
475
|
-
// TODO: Implement cleanup based on retention policy
|
|
476
|
-
return {
|
|
477
|
-
deletedCount: 0,
|
|
478
|
-
freedSpaceBytes: 0
|
|
479
|
-
};
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
// ==================== PRIVATE METHODS ====================
|
|
483
|
-
|
|
484
|
-
private async executeStoreOperation(
|
|
485
|
-
memory: ProcessedMemory,
|
|
486
|
-
userId: string,
|
|
487
|
-
options: {
|
|
488
|
-
priority?: 'low' | 'normal' | 'high';
|
|
489
|
-
enableEncryption?: boolean;
|
|
490
|
-
customMetadata?: Record<string, string>;
|
|
491
|
-
}
|
|
492
|
-
): Promise<StorageResult> {
|
|
493
|
-
const startTime = Date.now();
|
|
494
|
-
|
|
495
|
-
try {
|
|
496
|
-
// Prepare memory data
|
|
497
|
-
const memoryData = JSON.stringify(memory);
|
|
498
|
-
|
|
499
|
-
// Prepare metadata
|
|
500
|
-
const customMetadata = {
|
|
501
|
-
owner: userId,
|
|
502
|
-
memoryId: memory.id,
|
|
503
|
-
...options.customMetadata
|
|
504
|
-
};
|
|
505
|
-
|
|
506
|
-
// Upload to Walrus
|
|
507
|
-
const uploadResult = await this.walrusService.uploadContentWithMetadata(
|
|
508
|
-
memoryData,
|
|
509
|
-
userId,
|
|
510
|
-
{
|
|
511
|
-
category: memory.category,
|
|
512
|
-
topic: memory.metadata?.topic,
|
|
513
|
-
importance: memory.metadata?.importance || 5,
|
|
514
|
-
additionalTags: customMetadata,
|
|
515
|
-
enableEncryption: options.enableEncryption
|
|
516
|
-
}
|
|
517
|
-
);
|
|
518
|
-
|
|
519
|
-
this.stats.successfulUploads++;
|
|
520
|
-
this.updateUploadStats(Date.now() - startTime);
|
|
521
|
-
this.stats.totalStorageUsed += uploadResult.metadata.contentSize;
|
|
522
|
-
|
|
523
|
-
if (uploadResult.isEncrypted) {
|
|
524
|
-
this.updateEncryptionRate(true);
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
return {
|
|
528
|
-
success: true,
|
|
529
|
-
blobId: uploadResult.blobId,
|
|
530
|
-
metadata: uploadResult.metadata,
|
|
531
|
-
processingTimeMs: uploadResult.uploadTimeMs,
|
|
532
|
-
isEncrypted: uploadResult.isEncrypted,
|
|
533
|
-
storageProvider: 'walrus'
|
|
534
|
-
};
|
|
535
|
-
|
|
536
|
-
} catch (error) {
|
|
537
|
-
this.stats.failedUploads++;
|
|
538
|
-
throw error;
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
private scheduleBatchProcessing(): void {
|
|
543
|
-
if (this.batchTimer) {
|
|
544
|
-
return; // Already scheduled
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
// Process when batch is full or after delay
|
|
548
|
-
if (this.batchQueue.length >= (this.config.walrusConfig?.batchSize || 10)) {
|
|
549
|
-
this.processBatchQueue();
|
|
550
|
-
} else {
|
|
551
|
-
this.batchTimer = setTimeout(() => {
|
|
552
|
-
this.processBatchQueue();
|
|
553
|
-
}, this.config.walrusConfig.batchDelayMs);
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
private updateStorageStats(result: StorageResult): void {
|
|
558
|
-
if (result.success) {
|
|
559
|
-
if (result.storageProvider === 'walrus') {
|
|
560
|
-
this.stats.storageProviders.walrus.uploads++;
|
|
561
|
-
} else if (result.storageProvider === 'local') {
|
|
562
|
-
this.stats.storageProviders.local.uploads++;
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
// Update success rates
|
|
567
|
-
this.updateProviderSuccessRates();
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
private updateUploadStats(uploadTime: number): void {
|
|
571
|
-
this.stats.averageUploadTime =
|
|
572
|
-
(this.stats.averageUploadTime * (this.stats.successfulUploads - 1) + uploadTime) / this.stats.successfulUploads;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
private updateRetrievalStats(retrievalTime: number): void {
|
|
576
|
-
this.stats.averageRetrievalTime =
|
|
577
|
-
(this.stats.averageRetrievalTime * (this.stats.totalRetrievals - 1) + retrievalTime) / this.stats.totalRetrievals;
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
private updateEncryptionRate(isEncrypted: boolean): void {
|
|
581
|
-
const total = this.stats.successfulUploads;
|
|
582
|
-
if (isEncrypted) {
|
|
583
|
-
this.stats.encryptionRate = (this.stats.encryptionRate * (total - 1) + 1) / total;
|
|
584
|
-
} else {
|
|
585
|
-
this.stats.encryptionRate = (this.stats.encryptionRate * (total - 1)) / total;
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
private updateProviderSuccessRates(): void {
|
|
590
|
-
const walrusTotal = this.stats.storageProviders.walrus.uploads + this.stats.storageProviders.walrus.retrievals;
|
|
591
|
-
const localTotal = this.stats.storageProviders.local.uploads + this.stats.storageProviders.local.retrievals;
|
|
592
|
-
|
|
593
|
-
if (walrusTotal > 0) {
|
|
594
|
-
this.stats.storageProviders.walrus.success_rate =
|
|
595
|
-
this.stats.storageProviders.walrus.uploads / walrusTotal;
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
if (localTotal > 0) {
|
|
599
|
-
this.stats.storageProviders.local.success_rate =
|
|
600
|
-
this.stats.storageProviders.local.uploads / localTotal;
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
|
|
1
|
+
/**
|
|
2
|
+
* StorageManager - Unified Storage Operations Manager
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates Walrus storage operations with intelligent batching,
|
|
5
|
+
* encryption management, and seamless integration with memory processing.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { WalrusStorageService, WalrusUploadResult, WalrusRetrievalResult, MemoryMetadata } from './WalrusStorageService';
|
|
9
|
+
import { ProcessedMemory } from '../../embedding/types';
|
|
10
|
+
|
|
11
|
+
export interface StorageManagerConfig {
|
|
12
|
+
walrusConfig?: {
|
|
13
|
+
network?: 'testnet' | 'mainnet';
|
|
14
|
+
enableEncryption?: boolean;
|
|
15
|
+
enableBatching?: boolean;
|
|
16
|
+
batchSize?: number;
|
|
17
|
+
batchDelayMs?: number;
|
|
18
|
+
};
|
|
19
|
+
enableDistributedStorage?: boolean;
|
|
20
|
+
enableCompressionn?: boolean;
|
|
21
|
+
retentionPolicyDays?: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface StorageResult {
|
|
25
|
+
success: boolean;
|
|
26
|
+
blobId?: string;
|
|
27
|
+
metadata?: MemoryMetadata;
|
|
28
|
+
error?: string;
|
|
29
|
+
processingTimeMs: number;
|
|
30
|
+
isEncrypted: boolean;
|
|
31
|
+
storageProvider: 'walrus' | 'local' | 'distributed';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface RetrievalOptions {
|
|
35
|
+
includeMetadata?: boolean;
|
|
36
|
+
decryptionKey?: string;
|
|
37
|
+
preferCache?: boolean;
|
|
38
|
+
timeout?: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface StorageBatchOperation {
|
|
42
|
+
memory: ProcessedMemory;
|
|
43
|
+
userId: string;
|
|
44
|
+
priority?: 'low' | 'normal' | 'high';
|
|
45
|
+
encryptionRequired?: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface StorageBatchResult {
|
|
49
|
+
successful: StorageResult[];
|
|
50
|
+
failed: Array<{ memory: ProcessedMemory; error: string }>;
|
|
51
|
+
totalProcessingTime: number;
|
|
52
|
+
averageProcessingTime: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface StorageStats {
|
|
56
|
+
totalOperations: number;
|
|
57
|
+
successfulUploads: number;
|
|
58
|
+
failedUploads: number;
|
|
59
|
+
totalRetrievals: number;
|
|
60
|
+
storageProviders: {
|
|
61
|
+
walrus: { uploads: number; retrievals: number; success_rate: number };
|
|
62
|
+
local: { uploads: number; retrievals: number; success_rate: number };
|
|
63
|
+
};
|
|
64
|
+
averageUploadTime: number;
|
|
65
|
+
averageRetrievalTime: number;
|
|
66
|
+
totalStorageUsed: number;
|
|
67
|
+
encryptionRate: number;
|
|
68
|
+
compressionSavings: number;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Unified storage manager coordinating multiple storage providers
|
|
73
|
+
*/
|
|
74
|
+
export class StorageManager {
|
|
75
|
+
private walrusService: WalrusStorageService;
|
|
76
|
+
private pendingOperations = new Map<string, Promise<StorageResult>>();
|
|
77
|
+
private batchQueue: StorageBatchOperation[] = [];
|
|
78
|
+
private batchTimer?: NodeJS.Timeout;
|
|
79
|
+
|
|
80
|
+
private readonly config: Required<StorageManagerConfig>;
|
|
81
|
+
private stats: StorageStats = {
|
|
82
|
+
totalOperations: 0,
|
|
83
|
+
successfulUploads: 0,
|
|
84
|
+
failedUploads: 0,
|
|
85
|
+
totalRetrievals: 0,
|
|
86
|
+
storageProviders: {
|
|
87
|
+
walrus: { uploads: 0, retrievals: 0, success_rate: 0 },
|
|
88
|
+
local: { uploads: 0, retrievals: 0, success_rate: 0 }
|
|
89
|
+
},
|
|
90
|
+
averageUploadTime: 0,
|
|
91
|
+
averageRetrievalTime: 0,
|
|
92
|
+
totalStorageUsed: 0,
|
|
93
|
+
encryptionRate: 0,
|
|
94
|
+
compressionSavings: 0
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
constructor(config: StorageManagerConfig = {}) {
|
|
98
|
+
this.config = {
|
|
99
|
+
walrusConfig: {
|
|
100
|
+
network: config.walrusConfig?.network || 'testnet',
|
|
101
|
+
enableEncryption: config.walrusConfig?.enableEncryption !== false,
|
|
102
|
+
enableBatching: config.walrusConfig?.enableBatching !== false,
|
|
103
|
+
batchSize: config.walrusConfig?.batchSize || 10,
|
|
104
|
+
batchDelayMs: config.walrusConfig?.batchDelayMs || 5000
|
|
105
|
+
},
|
|
106
|
+
enableDistributedStorage: config.enableDistributedStorage !== false,
|
|
107
|
+
enableCompressionn: config.enableCompressionn !== false,
|
|
108
|
+
retentionPolicyDays: config.retentionPolicyDays || 365
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// Initialize Walrus service
|
|
112
|
+
this.walrusService = new WalrusStorageService({
|
|
113
|
+
network: this.config.walrusConfig.network
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ==================== MEMORY STORAGE OPERATIONS ====================
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Store processed memory with comprehensive options
|
|
121
|
+
*/
|
|
122
|
+
async storeMemory(
|
|
123
|
+
memory: ProcessedMemory,
|
|
124
|
+
userId: string,
|
|
125
|
+
options: {
|
|
126
|
+
priority?: 'low' | 'normal' | 'high';
|
|
127
|
+
enableEncryption?: boolean;
|
|
128
|
+
enableBatching?: boolean;
|
|
129
|
+
customMetadata?: Record<string, string>;
|
|
130
|
+
} = {}
|
|
131
|
+
): Promise<StorageResult> {
|
|
132
|
+
const startTime = Date.now();
|
|
133
|
+
this.stats.totalOperations++;
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
// Check for duplicate operation
|
|
137
|
+
const operationKey = `${memory.id}_${userId}`;
|
|
138
|
+
const existingOperation = this.pendingOperations.get(operationKey);
|
|
139
|
+
if (existingOperation) {
|
|
140
|
+
return await existingOperation;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Create operation promise
|
|
144
|
+
const operationPromise = this.executeStoreOperation(memory, userId, options);
|
|
145
|
+
this.pendingOperations.set(operationKey, operationPromise);
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
const result = await operationPromise;
|
|
149
|
+
this.updateStorageStats(result);
|
|
150
|
+
return result;
|
|
151
|
+
} finally {
|
|
152
|
+
this.pendingOperations.delete(operationKey);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
} catch (error) {
|
|
156
|
+
this.stats.failedUploads++;
|
|
157
|
+
return {
|
|
158
|
+
success: false,
|
|
159
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
160
|
+
processingTimeMs: Date.now() - startTime,
|
|
161
|
+
isEncrypted: false,
|
|
162
|
+
storageProvider: 'local'
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Store multiple memories in batch
|
|
169
|
+
*/
|
|
170
|
+
async storeMemoryBatch(
|
|
171
|
+
operations: StorageBatchOperation[],
|
|
172
|
+
options: {
|
|
173
|
+
enableProgress?: boolean;
|
|
174
|
+
onProgress?: (completed: number, total: number) => void;
|
|
175
|
+
maxConcurrent?: number;
|
|
176
|
+
} = {}
|
|
177
|
+
): Promise<StorageBatchResult> {
|
|
178
|
+
const startTime = Date.now();
|
|
179
|
+
const maxConcurrent = options.maxConcurrent || 5;
|
|
180
|
+
const successful: StorageResult[] = [];
|
|
181
|
+
const failed: Array<{ memory: ProcessedMemory; error: string }> = [];
|
|
182
|
+
|
|
183
|
+
// Sort by priority (high -> normal -> low)
|
|
184
|
+
const sortedOps = [...operations].sort((a, b) => {
|
|
185
|
+
const priorityOrder = { high: 3, normal: 2, low: 1 };
|
|
186
|
+
const aPriority = priorityOrder[a.priority || 'normal'];
|
|
187
|
+
const bPriority = priorityOrder[b.priority || 'normal'];
|
|
188
|
+
return bPriority - aPriority;
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Process in batches to control concurrency
|
|
192
|
+
for (let i = 0; i < sortedOps.length; i += maxConcurrent) {
|
|
193
|
+
const batch = sortedOps.slice(i, i + maxConcurrent);
|
|
194
|
+
|
|
195
|
+
const batchPromises = batch.map(async (op) => {
|
|
196
|
+
try {
|
|
197
|
+
const result = await this.storeMemory(op.memory, op.userId, {
|
|
198
|
+
priority: op.priority,
|
|
199
|
+
enableEncryption: op.encryptionRequired
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
if (result.success) {
|
|
203
|
+
successful.push(result);
|
|
204
|
+
} else {
|
|
205
|
+
failed.push({ memory: op.memory, error: result.error || 'Unknown error' });
|
|
206
|
+
}
|
|
207
|
+
} catch (error) {
|
|
208
|
+
failed.push({ memory: op.memory, error: error instanceof Error ? error.message : 'Unknown error' });
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
await Promise.all(batchPromises);
|
|
213
|
+
|
|
214
|
+
// Progress callback
|
|
215
|
+
if (options.onProgress) {
|
|
216
|
+
options.onProgress(i + batch.length, operations.length);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const totalTime = Date.now() - startTime;
|
|
221
|
+
const averageTime = operations.length > 0 ? totalTime / operations.length : 0;
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
successful,
|
|
225
|
+
failed,
|
|
226
|
+
totalProcessingTime: totalTime,
|
|
227
|
+
averageProcessingTime: averageTime
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Add memory to batch queue for deferred processing
|
|
233
|
+
*/
|
|
234
|
+
addToBatchQueue(
|
|
235
|
+
memory: ProcessedMemory,
|
|
236
|
+
userId: string,
|
|
237
|
+
options: {
|
|
238
|
+
priority?: 'low' | 'normal' | 'high';
|
|
239
|
+
encryptionRequired?: boolean;
|
|
240
|
+
} = {}
|
|
241
|
+
): void {
|
|
242
|
+
this.batchQueue.push({
|
|
243
|
+
memory,
|
|
244
|
+
userId,
|
|
245
|
+
priority: options.priority || 'normal',
|
|
246
|
+
encryptionRequired: options.encryptionRequired
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// Schedule batch processing
|
|
250
|
+
this.scheduleBatchProcessing();
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Process pending batch queue
|
|
255
|
+
*/
|
|
256
|
+
async processBatchQueue(): Promise<StorageBatchResult> {
|
|
257
|
+
if (this.batchQueue.length === 0) {
|
|
258
|
+
return {
|
|
259
|
+
successful: [],
|
|
260
|
+
failed: [],
|
|
261
|
+
totalProcessingTime: 0,
|
|
262
|
+
averageProcessingTime: 0
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const operations = [...this.batchQueue];
|
|
267
|
+
this.batchQueue.length = 0; // Clear queue
|
|
268
|
+
|
|
269
|
+
if (this.batchTimer) {
|
|
270
|
+
clearTimeout(this.batchTimer);
|
|
271
|
+
this.batchTimer = undefined;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return await this.storeMemoryBatch(operations);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// ==================== RETRIEVAL OPERATIONS ====================
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Retrieve memory by blob ID
|
|
281
|
+
*/
|
|
282
|
+
async retrieveMemory(
|
|
283
|
+
blobId: string,
|
|
284
|
+
options: RetrievalOptions = {}
|
|
285
|
+
): Promise<{
|
|
286
|
+
memory: ProcessedMemory | null;
|
|
287
|
+
metadata: MemoryMetadata | null;
|
|
288
|
+
retrievalTimeMs: number;
|
|
289
|
+
isFromCache: boolean;
|
|
290
|
+
}> {
|
|
291
|
+
const startTime = Date.now();
|
|
292
|
+
this.stats.totalRetrievals++;
|
|
293
|
+
|
|
294
|
+
try {
|
|
295
|
+
const result = await this.walrusService.retrieveContent(blobId, options.decryptionKey);
|
|
296
|
+
|
|
297
|
+
// Parse content as memory
|
|
298
|
+
let memory: ProcessedMemory | null = null;
|
|
299
|
+
try {
|
|
300
|
+
const parsed = JSON.parse(result.content as string);
|
|
301
|
+
if (parsed && typeof parsed === 'object' && parsed.id) {
|
|
302
|
+
memory = parsed as ProcessedMemory;
|
|
303
|
+
}
|
|
304
|
+
} catch {
|
|
305
|
+
// Content might not be a memory object
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
this.updateRetrievalStats(Date.now() - startTime);
|
|
309
|
+
|
|
310
|
+
return {
|
|
311
|
+
memory,
|
|
312
|
+
metadata: options.includeMetadata ? result.metadata : null,
|
|
313
|
+
retrievalTimeMs: result.retrievalTimeMs,
|
|
314
|
+
isFromCache: result.isFromCache
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
} catch (error) {
|
|
318
|
+
console.error('Memory retrieval failed:', error);
|
|
319
|
+
return {
|
|
320
|
+
memory: null,
|
|
321
|
+
metadata: null,
|
|
322
|
+
retrievalTimeMs: Date.now() - startTime,
|
|
323
|
+
isFromCache: false
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Retrieve multiple memories by blob IDs
|
|
330
|
+
*/
|
|
331
|
+
async retrieveMemoryBatch(
|
|
332
|
+
blobIds: string[],
|
|
333
|
+
options: RetrievalOptions & {
|
|
334
|
+
batchSize?: number;
|
|
335
|
+
decryptionKeys?: Record<string, string>;
|
|
336
|
+
} = {}
|
|
337
|
+
): Promise<Array<{
|
|
338
|
+
blobId: string;
|
|
339
|
+
memory: ProcessedMemory | null;
|
|
340
|
+
metadata: MemoryMetadata | null;
|
|
341
|
+
success: boolean;
|
|
342
|
+
error?: string;
|
|
343
|
+
}>> {
|
|
344
|
+
const batchSize = options.batchSize || 10;
|
|
345
|
+
const results: Array<{
|
|
346
|
+
blobId: string;
|
|
347
|
+
memory: ProcessedMemory | null;
|
|
348
|
+
metadata: MemoryMetadata | null;
|
|
349
|
+
success: boolean;
|
|
350
|
+
error?: string;
|
|
351
|
+
}> = [];
|
|
352
|
+
|
|
353
|
+
// Process in batches
|
|
354
|
+
for (let i = 0; i < blobIds.length; i += batchSize) {
|
|
355
|
+
const batch = blobIds.slice(i, i + batchSize);
|
|
356
|
+
|
|
357
|
+
const batchPromises = batch.map(async (blobId) => {
|
|
358
|
+
try {
|
|
359
|
+
const decryptionKey = options.decryptionKeys?.[blobId] || options.decryptionKey;
|
|
360
|
+
const result = await this.retrieveMemory(blobId, { ...options, decryptionKey });
|
|
361
|
+
|
|
362
|
+
return {
|
|
363
|
+
blobId,
|
|
364
|
+
memory: result.memory,
|
|
365
|
+
metadata: result.metadata,
|
|
366
|
+
success: result.memory !== null
|
|
367
|
+
};
|
|
368
|
+
} catch (error) {
|
|
369
|
+
return {
|
|
370
|
+
blobId,
|
|
371
|
+
memory: null,
|
|
372
|
+
metadata: null,
|
|
373
|
+
success: false,
|
|
374
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
const batchResults = await Promise.all(batchPromises);
|
|
380
|
+
results.push(...batchResults);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return results;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// ==================== STORAGE MANAGEMENT ====================
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* List user's stored memories
|
|
390
|
+
*/
|
|
391
|
+
async listUserMemories(
|
|
392
|
+
userId: string,
|
|
393
|
+
options: {
|
|
394
|
+
category?: string;
|
|
395
|
+
limit?: number;
|
|
396
|
+
offset?: number;
|
|
397
|
+
sortBy?: 'date' | 'size' | 'importance';
|
|
398
|
+
includeMetadata?: boolean;
|
|
399
|
+
} = {}
|
|
400
|
+
) {
|
|
401
|
+
try {
|
|
402
|
+
const blobResult = await this.walrusService.listUserBlobs(userId, {
|
|
403
|
+
category: options.category,
|
|
404
|
+
limit: options.limit,
|
|
405
|
+
offset: options.offset,
|
|
406
|
+
sortBy: options.sortBy
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
const memories = [];
|
|
410
|
+
|
|
411
|
+
for (const blob of blobResult.blobs) {
|
|
412
|
+
try {
|
|
413
|
+
const result = await this.retrieveMemory(blob.blobId, {
|
|
414
|
+
includeMetadata: options.includeMetadata
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
if (result.memory) {
|
|
418
|
+
memories.push({
|
|
419
|
+
memory: result.memory,
|
|
420
|
+
blobId: blob.blobId,
|
|
421
|
+
metadata: result.metadata,
|
|
422
|
+
blobInfo: blob
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
} catch (error) {
|
|
426
|
+
console.warn(`Failed to retrieve memory ${blob.blobId}:`, error);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
return memories;
|
|
431
|
+
|
|
432
|
+
} catch (error) {
|
|
433
|
+
console.error('Failed to list user memories:', error);
|
|
434
|
+
return [];
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Delete stored memory
|
|
440
|
+
*/
|
|
441
|
+
async deleteMemory(blobId: string): Promise<boolean> {
|
|
442
|
+
try {
|
|
443
|
+
return await this.walrusService.deleteBlob(blobId);
|
|
444
|
+
} catch (error) {
|
|
445
|
+
console.error('Failed to delete memory:', error);
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Get storage analytics
|
|
452
|
+
*/
|
|
453
|
+
getStorageAnalytics() {
|
|
454
|
+
const walrusStats = this.walrusService.getStats();
|
|
455
|
+
const cacheInfo = this.walrusService.getCacheInfo();
|
|
456
|
+
|
|
457
|
+
return {
|
|
458
|
+
...this.stats,
|
|
459
|
+
walrusService: walrusStats,
|
|
460
|
+
cache: cacheInfo,
|
|
461
|
+
batchQueue: {
|
|
462
|
+
pending: this.batchQueue.length,
|
|
463
|
+
operations: this.pendingOperations.size
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Cleanup old data based on retention policy
|
|
470
|
+
*/
|
|
471
|
+
async cleanupOldData(): Promise<{
|
|
472
|
+
deletedCount: number;
|
|
473
|
+
freedSpaceBytes: number;
|
|
474
|
+
}> {
|
|
475
|
+
// TODO: Implement cleanup based on retention policy
|
|
476
|
+
return {
|
|
477
|
+
deletedCount: 0,
|
|
478
|
+
freedSpaceBytes: 0
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// ==================== PRIVATE METHODS ====================
|
|
483
|
+
|
|
484
|
+
private async executeStoreOperation(
|
|
485
|
+
memory: ProcessedMemory,
|
|
486
|
+
userId: string,
|
|
487
|
+
options: {
|
|
488
|
+
priority?: 'low' | 'normal' | 'high';
|
|
489
|
+
enableEncryption?: boolean;
|
|
490
|
+
customMetadata?: Record<string, string>;
|
|
491
|
+
}
|
|
492
|
+
): Promise<StorageResult> {
|
|
493
|
+
const startTime = Date.now();
|
|
494
|
+
|
|
495
|
+
try {
|
|
496
|
+
// Prepare memory data
|
|
497
|
+
const memoryData = JSON.stringify(memory);
|
|
498
|
+
|
|
499
|
+
// Prepare metadata
|
|
500
|
+
const customMetadata = {
|
|
501
|
+
owner: userId,
|
|
502
|
+
memoryId: memory.id,
|
|
503
|
+
...options.customMetadata
|
|
504
|
+
};
|
|
505
|
+
|
|
506
|
+
// Upload to Walrus
|
|
507
|
+
const uploadResult = await this.walrusService.uploadContentWithMetadata(
|
|
508
|
+
memoryData,
|
|
509
|
+
userId,
|
|
510
|
+
{
|
|
511
|
+
category: memory.category,
|
|
512
|
+
topic: memory.metadata?.topic,
|
|
513
|
+
importance: memory.metadata?.importance || 5,
|
|
514
|
+
additionalTags: customMetadata,
|
|
515
|
+
enableEncryption: options.enableEncryption
|
|
516
|
+
}
|
|
517
|
+
);
|
|
518
|
+
|
|
519
|
+
this.stats.successfulUploads++;
|
|
520
|
+
this.updateUploadStats(Date.now() - startTime);
|
|
521
|
+
this.stats.totalStorageUsed += uploadResult.metadata.contentSize;
|
|
522
|
+
|
|
523
|
+
if (uploadResult.isEncrypted) {
|
|
524
|
+
this.updateEncryptionRate(true);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
return {
|
|
528
|
+
success: true,
|
|
529
|
+
blobId: uploadResult.blobId,
|
|
530
|
+
metadata: uploadResult.metadata,
|
|
531
|
+
processingTimeMs: uploadResult.uploadTimeMs,
|
|
532
|
+
isEncrypted: uploadResult.isEncrypted,
|
|
533
|
+
storageProvider: 'walrus'
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
} catch (error) {
|
|
537
|
+
this.stats.failedUploads++;
|
|
538
|
+
throw error;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
private scheduleBatchProcessing(): void {
|
|
543
|
+
if (this.batchTimer) {
|
|
544
|
+
return; // Already scheduled
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// Process when batch is full or after delay
|
|
548
|
+
if (this.batchQueue.length >= (this.config.walrusConfig?.batchSize || 10)) {
|
|
549
|
+
this.processBatchQueue();
|
|
550
|
+
} else {
|
|
551
|
+
this.batchTimer = setTimeout(() => {
|
|
552
|
+
this.processBatchQueue();
|
|
553
|
+
}, this.config.walrusConfig.batchDelayMs);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
private updateStorageStats(result: StorageResult): void {
|
|
558
|
+
if (result.success) {
|
|
559
|
+
if (result.storageProvider === 'walrus') {
|
|
560
|
+
this.stats.storageProviders.walrus.uploads++;
|
|
561
|
+
} else if (result.storageProvider === 'local') {
|
|
562
|
+
this.stats.storageProviders.local.uploads++;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// Update success rates
|
|
567
|
+
this.updateProviderSuccessRates();
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
private updateUploadStats(uploadTime: number): void {
|
|
571
|
+
this.stats.averageUploadTime =
|
|
572
|
+
(this.stats.averageUploadTime * (this.stats.successfulUploads - 1) + uploadTime) / this.stats.successfulUploads;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
private updateRetrievalStats(retrievalTime: number): void {
|
|
576
|
+
this.stats.averageRetrievalTime =
|
|
577
|
+
(this.stats.averageRetrievalTime * (this.stats.totalRetrievals - 1) + retrievalTime) / this.stats.totalRetrievals;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
private updateEncryptionRate(isEncrypted: boolean): void {
|
|
581
|
+
const total = this.stats.successfulUploads;
|
|
582
|
+
if (isEncrypted) {
|
|
583
|
+
this.stats.encryptionRate = (this.stats.encryptionRate * (total - 1) + 1) / total;
|
|
584
|
+
} else {
|
|
585
|
+
this.stats.encryptionRate = (this.stats.encryptionRate * (total - 1)) / total;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
private updateProviderSuccessRates(): void {
|
|
590
|
+
const walrusTotal = this.stats.storageProviders.walrus.uploads + this.stats.storageProviders.walrus.retrievals;
|
|
591
|
+
const localTotal = this.stats.storageProviders.local.uploads + this.stats.storageProviders.local.retrievals;
|
|
592
|
+
|
|
593
|
+
if (walrusTotal > 0) {
|
|
594
|
+
this.stats.storageProviders.walrus.success_rate =
|
|
595
|
+
this.stats.storageProviders.walrus.uploads / walrusTotal;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
if (localTotal > 0) {
|
|
599
|
+
this.stats.storageProviders.local.success_rate =
|
|
600
|
+
this.stats.storageProviders.local.uploads / localTotal;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
605
|
export default StorageManager;
|