@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,333 +1,333 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* BlobAttributesManager - Sui Dynamic Field Operations for Blob Objects
|
|
3
|
-
*
|
|
4
|
-
* Handles mutable on-chain metadata via Sui dynamic fields.
|
|
5
|
-
* Extracted from StorageService for better separation of concerns.
|
|
6
|
-
*
|
|
7
|
-
* Features:
|
|
8
|
-
* - Set/get/update/remove dynamic fields
|
|
9
|
-
* - On-chain indexing and querying
|
|
10
|
-
* - Mutable metadata (unlike Walrus blob content)
|
|
11
|
-
* - Query by attribute filters
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import type { SuiClient } from '@mysten/sui/client';
|
|
15
|
-
import { Transaction } from '@mysten/sui/transactions';
|
|
16
|
-
import type { UnifiedSigner } from '../../client/signers/UnifiedSigner';
|
|
17
|
-
|
|
18
|
-
export interface BlobQueryResult {
|
|
19
|
-
blobObjectId: string;
|
|
20
|
-
blobId: string;
|
|
21
|
-
attributes: Record<string, string>;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* BlobAttributesManager - Manages Sui dynamic fields on Blob objects
|
|
26
|
-
*
|
|
27
|
-
* Dynamic fields enable:
|
|
28
|
-
* - Mutable on-chain metadata
|
|
29
|
-
* - Query/filter by attributes
|
|
30
|
-
* - Indexed searchability
|
|
31
|
-
* - No re-upload needed for metadata changes
|
|
32
|
-
*/
|
|
33
|
-
export class BlobAttributesManager {
|
|
34
|
-
constructor(private suiClient: SuiClient) {}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Set attributes on a Walrus Blob object
|
|
38
|
-
*
|
|
39
|
-
* Adds dynamic fields to the Sui Blob object for:
|
|
40
|
-
* - On-chain metadata indexing
|
|
41
|
-
* - Queryable attributes
|
|
42
|
-
* - Mutable metadata
|
|
43
|
-
*/
|
|
44
|
-
async setBlobAttributes(
|
|
45
|
-
blobObjectId: string,
|
|
46
|
-
attributes: Record<string, string>,
|
|
47
|
-
signer: UnifiedSigner
|
|
48
|
-
): Promise<string> {
|
|
49
|
-
try {
|
|
50
|
-
console.log(`🏷️ Setting ${Object.keys(attributes).length} attributes on blob ${blobObjectId.slice(0, 10)}...`);
|
|
51
|
-
|
|
52
|
-
const tx = new Transaction();
|
|
53
|
-
|
|
54
|
-
// Add each attribute as a dynamic field
|
|
55
|
-
for (const [key, value] of Object.entries(attributes)) {
|
|
56
|
-
tx.moveCall({
|
|
57
|
-
target: '0x2::dynamic_field::add',
|
|
58
|
-
arguments: [
|
|
59
|
-
tx.object(blobObjectId),
|
|
60
|
-
tx.pure.string(key),
|
|
61
|
-
tx.pure.string(value),
|
|
62
|
-
],
|
|
63
|
-
typeArguments: [
|
|
64
|
-
'0x1::string::String',
|
|
65
|
-
'0x1::string::String',
|
|
66
|
-
],
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
console.log(` ✓ ${key}: ${value.slice(0, 50)}${value.length > 50 ? '...' : ''}`);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
tx.setSender(signer.getAddress());
|
|
73
|
-
|
|
74
|
-
const result = await signer.signAndExecuteTransaction(tx);
|
|
75
|
-
|
|
76
|
-
console.log(`✅ Attributes set successfully!`);
|
|
77
|
-
console.log(` Transaction: ${result.digest}`);
|
|
78
|
-
|
|
79
|
-
return result.digest;
|
|
80
|
-
|
|
81
|
-
} catch (error) {
|
|
82
|
-
console.error(`❌ Failed to set blob attributes:`, error);
|
|
83
|
-
throw new Error(`Failed to set blob attributes: ${error}`);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Get attributes from a Walrus Blob object
|
|
89
|
-
*/
|
|
90
|
-
async getBlobAttributes(
|
|
91
|
-
blobObjectId: string,
|
|
92
|
-
attributeKeys?: string[]
|
|
93
|
-
): Promise<Record<string, string>> {
|
|
94
|
-
try {
|
|
95
|
-
console.log(`🔍 Fetching attributes from blob ${blobObjectId.slice(0, 10)}...`);
|
|
96
|
-
|
|
97
|
-
const attributes: Record<string, string> = {};
|
|
98
|
-
|
|
99
|
-
// Get the object
|
|
100
|
-
const object = await this.suiClient.getObject({
|
|
101
|
-
id: blobObjectId,
|
|
102
|
-
options: {
|
|
103
|
-
showContent: true,
|
|
104
|
-
showOwner: true,
|
|
105
|
-
},
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
if (!object.data) {
|
|
109
|
-
throw new Error(`Blob object not found: ${blobObjectId}`);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Get dynamic fields
|
|
113
|
-
const dynamicFields = await this.suiClient.getDynamicFields({
|
|
114
|
-
parentId: blobObjectId,
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
console.log(` Found ${dynamicFields.data.length} dynamic fields`);
|
|
118
|
-
|
|
119
|
-
// Fetch each dynamic field value
|
|
120
|
-
for (const field of dynamicFields.data) {
|
|
121
|
-
const fieldName = field.name.value as string;
|
|
122
|
-
|
|
123
|
-
// Skip if filtering and this field isn't in the list
|
|
124
|
-
if (attributeKeys && !attributeKeys.includes(fieldName)) {
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
try {
|
|
129
|
-
const fieldData = await this.suiClient.getDynamicFieldObject({
|
|
130
|
-
parentId: blobObjectId,
|
|
131
|
-
name: {
|
|
132
|
-
type: '0x1::string::String',
|
|
133
|
-
value: fieldName,
|
|
134
|
-
},
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
if (fieldData.data?.content?.dataType === 'moveObject') {
|
|
138
|
-
const value = (fieldData.data.content as any).fields.value;
|
|
139
|
-
attributes[fieldName] = value;
|
|
140
|
-
console.log(` ✓ ${fieldName}: ${value.slice(0, 50)}${value.length > 50 ? '...' : ''}`);
|
|
141
|
-
}
|
|
142
|
-
} catch (err) {
|
|
143
|
-
console.warn(` ⚠️ Could not fetch field ${fieldName}:`, err);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
console.log(`✅ Retrieved ${Object.keys(attributes).length} attributes`);
|
|
148
|
-
|
|
149
|
-
return attributes;
|
|
150
|
-
|
|
151
|
-
} catch (error) {
|
|
152
|
-
console.error(`❌ Failed to get blob attributes:`, error);
|
|
153
|
-
throw new Error(`Failed to get blob attributes: ${error}`);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Update blob attributes (replaces existing values)
|
|
159
|
-
*/
|
|
160
|
-
async updateBlobAttributes(
|
|
161
|
-
blobObjectId: string,
|
|
162
|
-
attributes: Record<string, string>,
|
|
163
|
-
signer: UnifiedSigner
|
|
164
|
-
): Promise<string> {
|
|
165
|
-
try {
|
|
166
|
-
console.log(`📝 Updating ${Object.keys(attributes).length} attributes on blob ${blobObjectId.slice(0, 10)}...`);
|
|
167
|
-
|
|
168
|
-
const tx = new Transaction();
|
|
169
|
-
|
|
170
|
-
// For each attribute, remove old value and add new value
|
|
171
|
-
for (const [key, value] of Object.entries(attributes)) {
|
|
172
|
-
// Remove existing field (if it exists)
|
|
173
|
-
tx.moveCall({
|
|
174
|
-
target: '0x2::dynamic_field::remove_if_exists',
|
|
175
|
-
arguments: [
|
|
176
|
-
tx.object(blobObjectId),
|
|
177
|
-
tx.pure.string(key),
|
|
178
|
-
],
|
|
179
|
-
typeArguments: [
|
|
180
|
-
'0x1::string::String',
|
|
181
|
-
'0x1::string::String',
|
|
182
|
-
],
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
// Add new field
|
|
186
|
-
tx.moveCall({
|
|
187
|
-
target: '0x2::dynamic_field::add',
|
|
188
|
-
arguments: [
|
|
189
|
-
tx.object(blobObjectId),
|
|
190
|
-
tx.pure.string(key),
|
|
191
|
-
tx.pure.string(value),
|
|
192
|
-
],
|
|
193
|
-
typeArguments: [
|
|
194
|
-
'0x1::string::String',
|
|
195
|
-
'0x1::string::String',
|
|
196
|
-
],
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
console.log(` ✓ Updated ${key}: ${value.slice(0, 50)}${value.length > 50 ? '...' : ''}`);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
tx.setSender(signer.getAddress());
|
|
203
|
-
|
|
204
|
-
const result = await signer.signAndExecuteTransaction(tx);
|
|
205
|
-
|
|
206
|
-
console.log(`✅ Attributes updated successfully!`);
|
|
207
|
-
console.log(` Transaction: ${result.digest}`);
|
|
208
|
-
|
|
209
|
-
return result.digest;
|
|
210
|
-
|
|
211
|
-
} catch (error) {
|
|
212
|
-
console.error(`❌ Failed to update blob attributes:`, error);
|
|
213
|
-
throw new Error(`Failed to update blob attributes: ${error}`);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Remove specific attributes from a blob
|
|
219
|
-
*/
|
|
220
|
-
async removeBlobAttributes(
|
|
221
|
-
blobObjectId: string,
|
|
222
|
-
attributeKeys: string[],
|
|
223
|
-
signer: UnifiedSigner
|
|
224
|
-
): Promise<string> {
|
|
225
|
-
try {
|
|
226
|
-
console.log(`🗑️ Removing ${attributeKeys.length} attributes from blob ${blobObjectId.slice(0, 10)}...`);
|
|
227
|
-
|
|
228
|
-
const tx = new Transaction();
|
|
229
|
-
|
|
230
|
-
for (const key of attributeKeys) {
|
|
231
|
-
tx.moveCall({
|
|
232
|
-
target: '0x2::dynamic_field::remove_if_exists',
|
|
233
|
-
arguments: [
|
|
234
|
-
tx.object(blobObjectId),
|
|
235
|
-
tx.pure.string(key),
|
|
236
|
-
],
|
|
237
|
-
typeArguments: [
|
|
238
|
-
'0x1::string::String',
|
|
239
|
-
'0x1::string::String',
|
|
240
|
-
],
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
console.log(` ✓ Removed ${key}`);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
tx.setSender(signer.getAddress());
|
|
247
|
-
|
|
248
|
-
const result = await signer.signAndExecuteTransaction(tx);
|
|
249
|
-
|
|
250
|
-
console.log(`✅ Attributes removed successfully!`);
|
|
251
|
-
console.log(` Transaction: ${result.digest}`);
|
|
252
|
-
|
|
253
|
-
return result.digest;
|
|
254
|
-
|
|
255
|
-
} catch (error) {
|
|
256
|
-
console.error(`❌ Failed to remove blob attributes:`, error);
|
|
257
|
-
throw new Error(`Failed to remove blob attributes: ${error}`);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* Query memories by attributes
|
|
263
|
-
*
|
|
264
|
-
* Finds all Blob objects with specific attribute values
|
|
265
|
-
*/
|
|
266
|
-
async queryMemoriesByAttributes(
|
|
267
|
-
filters: Record<string, string>,
|
|
268
|
-
owner: string,
|
|
269
|
-
walrusPackageId: string
|
|
270
|
-
): Promise<BlobQueryResult[]> {
|
|
271
|
-
try {
|
|
272
|
-
console.log(`🔍 Querying memories with filters:`, filters);
|
|
273
|
-
|
|
274
|
-
const results: BlobQueryResult[] = [];
|
|
275
|
-
|
|
276
|
-
// Get all Blob objects owned by user
|
|
277
|
-
const ownedObjects = await this.suiClient.getOwnedObjects({
|
|
278
|
-
owner,
|
|
279
|
-
filter: {
|
|
280
|
-
StructType: `${walrusPackageId}::blob::Blob`,
|
|
281
|
-
},
|
|
282
|
-
options: {
|
|
283
|
-
showContent: true,
|
|
284
|
-
showType: true,
|
|
285
|
-
},
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
console.log(` Found ${ownedObjects.data.length} blob objects`);
|
|
289
|
-
|
|
290
|
-
// Filter by attributes
|
|
291
|
-
for (const obj of ownedObjects.data) {
|
|
292
|
-
if (!obj.data?.objectId) continue;
|
|
293
|
-
|
|
294
|
-
try {
|
|
295
|
-
// Get attributes for this blob
|
|
296
|
-
const attributes = await this.getBlobAttributes(
|
|
297
|
-
obj.data.objectId,
|
|
298
|
-
Object.keys(filters)
|
|
299
|
-
);
|
|
300
|
-
|
|
301
|
-
// Check if all filters match
|
|
302
|
-
const matches = Object.entries(filters).every(
|
|
303
|
-
([key, value]) => attributes[key] === value
|
|
304
|
-
);
|
|
305
|
-
|
|
306
|
-
if (matches) {
|
|
307
|
-
// Extract blob ID from content
|
|
308
|
-
const content = obj.data.content as any;
|
|
309
|
-
const blobId = content?.fields?.blob_id;
|
|
310
|
-
|
|
311
|
-
results.push({
|
|
312
|
-
blobObjectId: obj.data.objectId,
|
|
313
|
-
blobId,
|
|
314
|
-
attributes,
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
console.log(` ✓ Match: ${obj.data.objectId.slice(0, 10)}...`);
|
|
318
|
-
}
|
|
319
|
-
} catch (err) {
|
|
320
|
-
console.warn(` ⚠️ Error checking ${obj.data.objectId}:`, err);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
console.log(`✅ Found ${results.length} matching memories`);
|
|
325
|
-
|
|
326
|
-
return results;
|
|
327
|
-
|
|
328
|
-
} catch (error) {
|
|
329
|
-
console.error(`❌ Failed to query memories:`, error);
|
|
330
|
-
throw new Error(`Failed to query memories: ${error}`);
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* BlobAttributesManager - Sui Dynamic Field Operations for Blob Objects
|
|
3
|
+
*
|
|
4
|
+
* Handles mutable on-chain metadata via Sui dynamic fields.
|
|
5
|
+
* Extracted from StorageService for better separation of concerns.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Set/get/update/remove dynamic fields
|
|
9
|
+
* - On-chain indexing and querying
|
|
10
|
+
* - Mutable metadata (unlike Walrus blob content)
|
|
11
|
+
* - Query by attribute filters
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { SuiClient } from '@mysten/sui/client';
|
|
15
|
+
import { Transaction } from '@mysten/sui/transactions';
|
|
16
|
+
import type { UnifiedSigner } from '../../client/signers/UnifiedSigner';
|
|
17
|
+
|
|
18
|
+
export interface BlobQueryResult {
|
|
19
|
+
blobObjectId: string;
|
|
20
|
+
blobId: string;
|
|
21
|
+
attributes: Record<string, string>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* BlobAttributesManager - Manages Sui dynamic fields on Blob objects
|
|
26
|
+
*
|
|
27
|
+
* Dynamic fields enable:
|
|
28
|
+
* - Mutable on-chain metadata
|
|
29
|
+
* - Query/filter by attributes
|
|
30
|
+
* - Indexed searchability
|
|
31
|
+
* - No re-upload needed for metadata changes
|
|
32
|
+
*/
|
|
33
|
+
export class BlobAttributesManager {
|
|
34
|
+
constructor(private suiClient: SuiClient) {}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Set attributes on a Walrus Blob object
|
|
38
|
+
*
|
|
39
|
+
* Adds dynamic fields to the Sui Blob object for:
|
|
40
|
+
* - On-chain metadata indexing
|
|
41
|
+
* - Queryable attributes
|
|
42
|
+
* - Mutable metadata
|
|
43
|
+
*/
|
|
44
|
+
async setBlobAttributes(
|
|
45
|
+
blobObjectId: string,
|
|
46
|
+
attributes: Record<string, string>,
|
|
47
|
+
signer: UnifiedSigner
|
|
48
|
+
): Promise<string> {
|
|
49
|
+
try {
|
|
50
|
+
console.log(`🏷️ Setting ${Object.keys(attributes).length} attributes on blob ${blobObjectId.slice(0, 10)}...`);
|
|
51
|
+
|
|
52
|
+
const tx = new Transaction();
|
|
53
|
+
|
|
54
|
+
// Add each attribute as a dynamic field
|
|
55
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
56
|
+
tx.moveCall({
|
|
57
|
+
target: '0x2::dynamic_field::add',
|
|
58
|
+
arguments: [
|
|
59
|
+
tx.object(blobObjectId),
|
|
60
|
+
tx.pure.string(key),
|
|
61
|
+
tx.pure.string(value),
|
|
62
|
+
],
|
|
63
|
+
typeArguments: [
|
|
64
|
+
'0x1::string::String',
|
|
65
|
+
'0x1::string::String',
|
|
66
|
+
],
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
console.log(` ✓ ${key}: ${value.slice(0, 50)}${value.length > 50 ? '...' : ''}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
tx.setSender(signer.getAddress());
|
|
73
|
+
|
|
74
|
+
const result = await signer.signAndExecuteTransaction(tx);
|
|
75
|
+
|
|
76
|
+
console.log(`✅ Attributes set successfully!`);
|
|
77
|
+
console.log(` Transaction: ${result.digest}`);
|
|
78
|
+
|
|
79
|
+
return result.digest;
|
|
80
|
+
|
|
81
|
+
} catch (error) {
|
|
82
|
+
console.error(`❌ Failed to set blob attributes:`, error);
|
|
83
|
+
throw new Error(`Failed to set blob attributes: ${error}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Get attributes from a Walrus Blob object
|
|
89
|
+
*/
|
|
90
|
+
async getBlobAttributes(
|
|
91
|
+
blobObjectId: string,
|
|
92
|
+
attributeKeys?: string[]
|
|
93
|
+
): Promise<Record<string, string>> {
|
|
94
|
+
try {
|
|
95
|
+
console.log(`🔍 Fetching attributes from blob ${blobObjectId.slice(0, 10)}...`);
|
|
96
|
+
|
|
97
|
+
const attributes: Record<string, string> = {};
|
|
98
|
+
|
|
99
|
+
// Get the object
|
|
100
|
+
const object = await this.suiClient.getObject({
|
|
101
|
+
id: blobObjectId,
|
|
102
|
+
options: {
|
|
103
|
+
showContent: true,
|
|
104
|
+
showOwner: true,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
if (!object.data) {
|
|
109
|
+
throw new Error(`Blob object not found: ${blobObjectId}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Get dynamic fields
|
|
113
|
+
const dynamicFields = await this.suiClient.getDynamicFields({
|
|
114
|
+
parentId: blobObjectId,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
console.log(` Found ${dynamicFields.data.length} dynamic fields`);
|
|
118
|
+
|
|
119
|
+
// Fetch each dynamic field value
|
|
120
|
+
for (const field of dynamicFields.data) {
|
|
121
|
+
const fieldName = field.name.value as string;
|
|
122
|
+
|
|
123
|
+
// Skip if filtering and this field isn't in the list
|
|
124
|
+
if (attributeKeys && !attributeKeys.includes(fieldName)) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
const fieldData = await this.suiClient.getDynamicFieldObject({
|
|
130
|
+
parentId: blobObjectId,
|
|
131
|
+
name: {
|
|
132
|
+
type: '0x1::string::String',
|
|
133
|
+
value: fieldName,
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
if (fieldData.data?.content?.dataType === 'moveObject') {
|
|
138
|
+
const value = (fieldData.data.content as any).fields.value;
|
|
139
|
+
attributes[fieldName] = value;
|
|
140
|
+
console.log(` ✓ ${fieldName}: ${value.slice(0, 50)}${value.length > 50 ? '...' : ''}`);
|
|
141
|
+
}
|
|
142
|
+
} catch (err) {
|
|
143
|
+
console.warn(` ⚠️ Could not fetch field ${fieldName}:`, err);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
console.log(`✅ Retrieved ${Object.keys(attributes).length} attributes`);
|
|
148
|
+
|
|
149
|
+
return attributes;
|
|
150
|
+
|
|
151
|
+
} catch (error) {
|
|
152
|
+
console.error(`❌ Failed to get blob attributes:`, error);
|
|
153
|
+
throw new Error(`Failed to get blob attributes: ${error}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Update blob attributes (replaces existing values)
|
|
159
|
+
*/
|
|
160
|
+
async updateBlobAttributes(
|
|
161
|
+
blobObjectId: string,
|
|
162
|
+
attributes: Record<string, string>,
|
|
163
|
+
signer: UnifiedSigner
|
|
164
|
+
): Promise<string> {
|
|
165
|
+
try {
|
|
166
|
+
console.log(`📝 Updating ${Object.keys(attributes).length} attributes on blob ${blobObjectId.slice(0, 10)}...`);
|
|
167
|
+
|
|
168
|
+
const tx = new Transaction();
|
|
169
|
+
|
|
170
|
+
// For each attribute, remove old value and add new value
|
|
171
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
172
|
+
// Remove existing field (if it exists)
|
|
173
|
+
tx.moveCall({
|
|
174
|
+
target: '0x2::dynamic_field::remove_if_exists',
|
|
175
|
+
arguments: [
|
|
176
|
+
tx.object(blobObjectId),
|
|
177
|
+
tx.pure.string(key),
|
|
178
|
+
],
|
|
179
|
+
typeArguments: [
|
|
180
|
+
'0x1::string::String',
|
|
181
|
+
'0x1::string::String',
|
|
182
|
+
],
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// Add new field
|
|
186
|
+
tx.moveCall({
|
|
187
|
+
target: '0x2::dynamic_field::add',
|
|
188
|
+
arguments: [
|
|
189
|
+
tx.object(blobObjectId),
|
|
190
|
+
tx.pure.string(key),
|
|
191
|
+
tx.pure.string(value),
|
|
192
|
+
],
|
|
193
|
+
typeArguments: [
|
|
194
|
+
'0x1::string::String',
|
|
195
|
+
'0x1::string::String',
|
|
196
|
+
],
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
console.log(` ✓ Updated ${key}: ${value.slice(0, 50)}${value.length > 50 ? '...' : ''}`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
tx.setSender(signer.getAddress());
|
|
203
|
+
|
|
204
|
+
const result = await signer.signAndExecuteTransaction(tx);
|
|
205
|
+
|
|
206
|
+
console.log(`✅ Attributes updated successfully!`);
|
|
207
|
+
console.log(` Transaction: ${result.digest}`);
|
|
208
|
+
|
|
209
|
+
return result.digest;
|
|
210
|
+
|
|
211
|
+
} catch (error) {
|
|
212
|
+
console.error(`❌ Failed to update blob attributes:`, error);
|
|
213
|
+
throw new Error(`Failed to update blob attributes: ${error}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Remove specific attributes from a blob
|
|
219
|
+
*/
|
|
220
|
+
async removeBlobAttributes(
|
|
221
|
+
blobObjectId: string,
|
|
222
|
+
attributeKeys: string[],
|
|
223
|
+
signer: UnifiedSigner
|
|
224
|
+
): Promise<string> {
|
|
225
|
+
try {
|
|
226
|
+
console.log(`🗑️ Removing ${attributeKeys.length} attributes from blob ${blobObjectId.slice(0, 10)}...`);
|
|
227
|
+
|
|
228
|
+
const tx = new Transaction();
|
|
229
|
+
|
|
230
|
+
for (const key of attributeKeys) {
|
|
231
|
+
tx.moveCall({
|
|
232
|
+
target: '0x2::dynamic_field::remove_if_exists',
|
|
233
|
+
arguments: [
|
|
234
|
+
tx.object(blobObjectId),
|
|
235
|
+
tx.pure.string(key),
|
|
236
|
+
],
|
|
237
|
+
typeArguments: [
|
|
238
|
+
'0x1::string::String',
|
|
239
|
+
'0x1::string::String',
|
|
240
|
+
],
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
console.log(` ✓ Removed ${key}`);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
tx.setSender(signer.getAddress());
|
|
247
|
+
|
|
248
|
+
const result = await signer.signAndExecuteTransaction(tx);
|
|
249
|
+
|
|
250
|
+
console.log(`✅ Attributes removed successfully!`);
|
|
251
|
+
console.log(` Transaction: ${result.digest}`);
|
|
252
|
+
|
|
253
|
+
return result.digest;
|
|
254
|
+
|
|
255
|
+
} catch (error) {
|
|
256
|
+
console.error(`❌ Failed to remove blob attributes:`, error);
|
|
257
|
+
throw new Error(`Failed to remove blob attributes: ${error}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Query memories by attributes
|
|
263
|
+
*
|
|
264
|
+
* Finds all Blob objects with specific attribute values
|
|
265
|
+
*/
|
|
266
|
+
async queryMemoriesByAttributes(
|
|
267
|
+
filters: Record<string, string>,
|
|
268
|
+
owner: string,
|
|
269
|
+
walrusPackageId: string
|
|
270
|
+
): Promise<BlobQueryResult[]> {
|
|
271
|
+
try {
|
|
272
|
+
console.log(`🔍 Querying memories with filters:`, filters);
|
|
273
|
+
|
|
274
|
+
const results: BlobQueryResult[] = [];
|
|
275
|
+
|
|
276
|
+
// Get all Blob objects owned by user
|
|
277
|
+
const ownedObjects = await this.suiClient.getOwnedObjects({
|
|
278
|
+
owner,
|
|
279
|
+
filter: {
|
|
280
|
+
StructType: `${walrusPackageId}::blob::Blob`,
|
|
281
|
+
},
|
|
282
|
+
options: {
|
|
283
|
+
showContent: true,
|
|
284
|
+
showType: true,
|
|
285
|
+
},
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
console.log(` Found ${ownedObjects.data.length} blob objects`);
|
|
289
|
+
|
|
290
|
+
// Filter by attributes
|
|
291
|
+
for (const obj of ownedObjects.data) {
|
|
292
|
+
if (!obj.data?.objectId) continue;
|
|
293
|
+
|
|
294
|
+
try {
|
|
295
|
+
// Get attributes for this blob
|
|
296
|
+
const attributes = await this.getBlobAttributes(
|
|
297
|
+
obj.data.objectId,
|
|
298
|
+
Object.keys(filters)
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
// Check if all filters match
|
|
302
|
+
const matches = Object.entries(filters).every(
|
|
303
|
+
([key, value]) => attributes[key] === value
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
if (matches) {
|
|
307
|
+
// Extract blob ID from content
|
|
308
|
+
const content = obj.data.content as any;
|
|
309
|
+
const blobId = content?.fields?.blob_id;
|
|
310
|
+
|
|
311
|
+
results.push({
|
|
312
|
+
blobObjectId: obj.data.objectId,
|
|
313
|
+
blobId,
|
|
314
|
+
attributes,
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
console.log(` ✓ Match: ${obj.data.objectId.slice(0, 10)}...`);
|
|
318
|
+
}
|
|
319
|
+
} catch (err) {
|
|
320
|
+
console.warn(` ⚠️ Error checking ${obj.data.objectId}:`, err);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
console.log(`✅ Found ${results.length} matching memories`);
|
|
325
|
+
|
|
326
|
+
return results;
|
|
327
|
+
|
|
328
|
+
} catch (error) {
|
|
329
|
+
console.error(`❌ Failed to query memories:`, error);
|
|
330
|
+
throw new Error(`Failed to query memories: ${error}`);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|