@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.
Files changed (247) hide show
  1. package/ARCHITECTURE.md +547 -547
  2. package/BENCHMARKS.md +238 -238
  3. package/README.md +310 -181
  4. package/dist/ai-sdk/tools.d.ts +2 -2
  5. package/dist/ai-sdk/tools.js +2 -2
  6. package/dist/client/ClientMemoryManager.js +2 -2
  7. package/dist/client/ClientMemoryManager.js.map +1 -1
  8. package/dist/client/PersonalDataWallet.d.ts.map +1 -1
  9. package/dist/client/SimplePDWClient.d.ts +29 -1
  10. package/dist/client/SimplePDWClient.d.ts.map +1 -1
  11. package/dist/client/SimplePDWClient.js +45 -13
  12. package/dist/client/SimplePDWClient.js.map +1 -1
  13. package/dist/client/namespaces/EmbeddingsNamespace.d.ts +1 -1
  14. package/dist/client/namespaces/EmbeddingsNamespace.js +1 -1
  15. package/dist/client/namespaces/MemoryNamespace.d.ts +31 -0
  16. package/dist/client/namespaces/MemoryNamespace.d.ts.map +1 -1
  17. package/dist/client/namespaces/MemoryNamespace.js +272 -39
  18. package/dist/client/namespaces/MemoryNamespace.js.map +1 -1
  19. package/dist/client/namespaces/consolidated/AINamespace.d.ts +2 -2
  20. package/dist/client/namespaces/consolidated/AINamespace.js +2 -2
  21. package/dist/client/namespaces/consolidated/BlockchainNamespace.d.ts +12 -2
  22. package/dist/client/namespaces/consolidated/BlockchainNamespace.d.ts.map +1 -1
  23. package/dist/client/namespaces/consolidated/BlockchainNamespace.js +62 -4
  24. package/dist/client/namespaces/consolidated/BlockchainNamespace.js.map +1 -1
  25. package/dist/client/namespaces/consolidated/StorageNamespace.d.ts +67 -2
  26. package/dist/client/namespaces/consolidated/StorageNamespace.d.ts.map +1 -1
  27. package/dist/client/namespaces/consolidated/StorageNamespace.js +549 -16
  28. package/dist/client/namespaces/consolidated/StorageNamespace.js.map +1 -1
  29. package/dist/config/ConfigurationHelper.js +61 -61
  30. package/dist/config/defaults.js +2 -2
  31. package/dist/config/defaults.js.map +1 -1
  32. package/dist/graph/GraphService.js +21 -21
  33. package/dist/graph/GraphService.js.map +1 -1
  34. package/dist/index.d.ts +3 -1
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +3 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/infrastructure/seal/EncryptionService.d.ts +9 -5
  39. package/dist/infrastructure/seal/EncryptionService.d.ts.map +1 -1
  40. package/dist/infrastructure/seal/EncryptionService.js +37 -15
  41. package/dist/infrastructure/seal/EncryptionService.js.map +1 -1
  42. package/dist/infrastructure/seal/SealService.d.ts +13 -5
  43. package/dist/infrastructure/seal/SealService.d.ts.map +1 -1
  44. package/dist/infrastructure/seal/SealService.js +36 -34
  45. package/dist/infrastructure/seal/SealService.js.map +1 -1
  46. package/dist/langchain/createPDWRAG.js +30 -30
  47. package/dist/retrieval/MemoryDecryptionPipeline.d.ts.map +1 -1
  48. package/dist/retrieval/MemoryDecryptionPipeline.js +2 -1
  49. package/dist/retrieval/MemoryDecryptionPipeline.js.map +1 -1
  50. package/dist/retrieval/MemoryRetrievalService.d.ts +31 -0
  51. package/dist/retrieval/MemoryRetrievalService.d.ts.map +1 -1
  52. package/dist/retrieval/MemoryRetrievalService.js +44 -4
  53. package/dist/retrieval/MemoryRetrievalService.js.map +1 -1
  54. package/dist/services/CapabilityService.d.ts.map +1 -1
  55. package/dist/services/CapabilityService.js +30 -14
  56. package/dist/services/CapabilityService.js.map +1 -1
  57. package/dist/services/CrossContextPermissionService.d.ts.map +1 -1
  58. package/dist/services/CrossContextPermissionService.js +9 -7
  59. package/dist/services/CrossContextPermissionService.js.map +1 -1
  60. package/dist/services/EmbeddingService.d.ts +28 -1
  61. package/dist/services/EmbeddingService.d.ts.map +1 -1
  62. package/dist/services/EmbeddingService.js +54 -0
  63. package/dist/services/EmbeddingService.js.map +1 -1
  64. package/dist/services/EncryptionService.d.ts.map +1 -1
  65. package/dist/services/EncryptionService.js +6 -5
  66. package/dist/services/EncryptionService.js.map +1 -1
  67. package/dist/services/GeminiAIService.js +309 -309
  68. package/dist/services/IndexManager.d.ts +5 -1
  69. package/dist/services/IndexManager.d.ts.map +1 -1
  70. package/dist/services/IndexManager.js +17 -40
  71. package/dist/services/IndexManager.js.map +1 -1
  72. package/dist/services/QueryService.js +1 -1
  73. package/dist/services/QueryService.js.map +1 -1
  74. package/dist/services/StorageService.d.ts +11 -0
  75. package/dist/services/StorageService.d.ts.map +1 -1
  76. package/dist/services/StorageService.js +73 -10
  77. package/dist/services/StorageService.js.map +1 -1
  78. package/dist/services/TransactionService.d.ts +20 -0
  79. package/dist/services/TransactionService.d.ts.map +1 -1
  80. package/dist/services/TransactionService.js +43 -0
  81. package/dist/services/TransactionService.js.map +1 -1
  82. package/dist/services/ViewService.js +2 -2
  83. package/dist/services/ViewService.js.map +1 -1
  84. package/dist/services/storage/QuiltBatchManager.d.ts +101 -1
  85. package/dist/services/storage/QuiltBatchManager.d.ts.map +1 -1
  86. package/dist/services/storage/QuiltBatchManager.js +410 -20
  87. package/dist/services/storage/QuiltBatchManager.js.map +1 -1
  88. package/dist/services/storage/index.d.ts +1 -1
  89. package/dist/services/storage/index.d.ts.map +1 -1
  90. package/dist/services/storage/index.js.map +1 -1
  91. package/dist/utils/LRUCache.d.ts +106 -0
  92. package/dist/utils/LRUCache.d.ts.map +1 -0
  93. package/dist/utils/LRUCache.js +281 -0
  94. package/dist/utils/LRUCache.js.map +1 -0
  95. package/dist/utils/index.d.ts +1 -0
  96. package/dist/utils/index.d.ts.map +1 -1
  97. package/dist/utils/index.js +2 -0
  98. package/dist/utils/index.js.map +1 -1
  99. package/dist/utils/memoryIndexOnChain.d.ts +212 -0
  100. package/dist/utils/memoryIndexOnChain.d.ts.map +1 -0
  101. package/dist/utils/memoryIndexOnChain.js +312 -0
  102. package/dist/utils/memoryIndexOnChain.js.map +1 -0
  103. package/dist/utils/rebuildIndexNode.d.ts +29 -0
  104. package/dist/utils/rebuildIndexNode.d.ts.map +1 -1
  105. package/dist/utils/rebuildIndexNode.js +366 -98
  106. package/dist/utils/rebuildIndexNode.js.map +1 -1
  107. package/dist/vector/HnswWasmService.d.ts +20 -5
  108. package/dist/vector/HnswWasmService.d.ts.map +1 -1
  109. package/dist/vector/HnswWasmService.js +73 -40
  110. package/dist/vector/HnswWasmService.js.map +1 -1
  111. package/dist/vector/IHnswService.d.ts +10 -1
  112. package/dist/vector/IHnswService.d.ts.map +1 -1
  113. package/dist/vector/IHnswService.js.map +1 -1
  114. package/dist/vector/NodeHnswService.d.ts +16 -0
  115. package/dist/vector/NodeHnswService.d.ts.map +1 -1
  116. package/dist/vector/NodeHnswService.js +84 -5
  117. package/dist/vector/NodeHnswService.js.map +1 -1
  118. package/dist/vector/createHnswService.d.ts +1 -1
  119. package/dist/vector/createHnswService.js +1 -1
  120. package/dist/vector/index.d.ts +1 -1
  121. package/dist/vector/index.js +1 -1
  122. package/package.json +157 -157
  123. package/src/access/PermissionService.ts +635 -635
  124. package/src/aggregation/AggregationService.ts +389 -389
  125. package/src/ai-sdk/PDWVectorStore.ts +715 -715
  126. package/src/ai-sdk/index.ts +65 -65
  127. package/src/ai-sdk/tools.ts +460 -460
  128. package/src/ai-sdk/types.ts +404 -404
  129. package/src/batch/BatchManager.ts +597 -597
  130. package/src/batch/BatchingService.ts +429 -429
  131. package/src/batch/MemoryProcessingCache.ts +492 -492
  132. package/src/batch/index.ts +30 -30
  133. package/src/browser.ts +200 -200
  134. package/src/client/ClientMemoryManager.ts +987 -987
  135. package/src/client/PersonalDataWallet.ts +345 -345
  136. package/src/client/SimplePDWClient.ts +1289 -1222
  137. package/src/client/factory.ts +154 -154
  138. package/src/client/namespaces/AnalyticsNamespace.ts +377 -377
  139. package/src/client/namespaces/BatchNamespace.ts +356 -356
  140. package/src/client/namespaces/CacheNamespace.ts +123 -123
  141. package/src/client/namespaces/CapabilityNamespace.ts +217 -217
  142. package/src/client/namespaces/ClassifyNamespace.ts +169 -169
  143. package/src/client/namespaces/ContextNamespace.ts +297 -297
  144. package/src/client/namespaces/EmbeddingsNamespace.ts +99 -99
  145. package/src/client/namespaces/EncryptionNamespace.ts +221 -221
  146. package/src/client/namespaces/GraphNamespace.ts +468 -468
  147. package/src/client/namespaces/IndexNamespace.ts +361 -361
  148. package/src/client/namespaces/MemoryNamespace.ts +1422 -1135
  149. package/src/client/namespaces/PermissionsNamespace.ts +254 -254
  150. package/src/client/namespaces/PipelineNamespace.ts +220 -220
  151. package/src/client/namespaces/SearchNamespace.ts +1049 -1049
  152. package/src/client/namespaces/StorageNamespace.ts +458 -458
  153. package/src/client/namespaces/TxNamespace.ts +260 -260
  154. package/src/client/namespaces/WalletNamespace.ts +243 -243
  155. package/src/client/namespaces/consolidated/AINamespace.ts +449 -449
  156. package/src/client/namespaces/consolidated/BlockchainNamespace.ts +607 -546
  157. package/src/client/namespaces/consolidated/SecurityNamespace.ts +648 -648
  158. package/src/client/namespaces/consolidated/StorageNamespace.ts +1141 -497
  159. package/src/client/namespaces/consolidated/index.ts +39 -39
  160. package/src/client/signers/KeypairSigner.ts +108 -108
  161. package/src/client/signers/UnifiedSigner.ts +110 -110
  162. package/src/client/signers/WalletAdapterSigner.ts +159 -159
  163. package/src/client/signers/index.ts +26 -26
  164. package/src/config/ConfigurationHelper.ts +412 -412
  165. package/src/config/defaults.ts +51 -51
  166. package/src/config/index.ts +8 -8
  167. package/src/config/validation.ts +70 -70
  168. package/src/core/index.ts +14 -14
  169. package/src/core/interfaces/IService.ts +307 -307
  170. package/src/core/interfaces/index.ts +8 -8
  171. package/src/core/types/capability.ts +297 -297
  172. package/src/core/types/index.ts +870 -870
  173. package/src/core/types/wallet.ts +270 -270
  174. package/src/core/types.ts +9 -9
  175. package/src/core/wallet.ts +222 -222
  176. package/src/embedding/index.ts +19 -19
  177. package/src/embedding/types.ts +357 -357
  178. package/src/errors/index.ts +602 -602
  179. package/src/errors/recovery.ts +461 -461
  180. package/src/errors/validation.ts +567 -567
  181. package/src/generated/pdw/capability.ts +319 -319
  182. package/src/graph/GraphService.ts +887 -887
  183. package/src/graph/KnowledgeGraphManager.ts +728 -728
  184. package/src/graph/index.ts +25 -25
  185. package/src/index.ts +498 -474
  186. package/src/infrastructure/index.ts +22 -22
  187. package/src/infrastructure/seal/EncryptionService.ts +628 -603
  188. package/src/infrastructure/seal/SealService.ts +613 -615
  189. package/src/infrastructure/seal/index.ts +9 -9
  190. package/src/infrastructure/sui/BlockchainManager.ts +627 -627
  191. package/src/infrastructure/sui/SuiService.ts +888 -888
  192. package/src/infrastructure/sui/index.ts +9 -9
  193. package/src/infrastructure/walrus/StorageManager.ts +604 -604
  194. package/src/infrastructure/walrus/WalrusStorageService.ts +612 -612
  195. package/src/infrastructure/walrus/index.ts +9 -9
  196. package/src/langchain/PDWEmbeddings.ts +145 -145
  197. package/src/langchain/PDWVectorStore.ts +456 -456
  198. package/src/langchain/createPDWRAG.ts +303 -303
  199. package/src/langchain/index.ts +47 -47
  200. package/src/permissions/ConsentRepository.browser.ts +249 -249
  201. package/src/permissions/ConsentRepository.ts +364 -364
  202. package/src/pipeline/MemoryPipeline.ts +862 -862
  203. package/src/pipeline/PipelineManager.ts +683 -683
  204. package/src/pipeline/index.ts +26 -26
  205. package/src/retrieval/AdvancedSearchService.ts +629 -629
  206. package/src/retrieval/MemoryAnalyticsService.ts +711 -711
  207. package/src/retrieval/MemoryDecryptionPipeline.ts +825 -824
  208. package/src/retrieval/MemoryRetrievalService.ts +904 -830
  209. package/src/retrieval/index.ts +42 -42
  210. package/src/services/BatchService.ts +352 -352
  211. package/src/services/CapabilityService.ts +464 -448
  212. package/src/services/ClassifierService.ts +465 -465
  213. package/src/services/CrossContextPermissionService.ts +486 -484
  214. package/src/services/EmbeddingService.ts +771 -706
  215. package/src/services/EncryptionService.ts +712 -711
  216. package/src/services/GeminiAIService.ts +753 -753
  217. package/src/services/IndexManager.ts +977 -1004
  218. package/src/services/MemoryIndexService.ts +1003 -1003
  219. package/src/services/MemoryService.ts +369 -369
  220. package/src/services/QueryService.ts +890 -890
  221. package/src/services/StorageService.ts +1182 -1111
  222. package/src/services/TransactionService.ts +838 -790
  223. package/src/services/VectorService.ts +462 -462
  224. package/src/services/ViewService.ts +484 -484
  225. package/src/services/index.ts +25 -25
  226. package/src/services/storage/BlobAttributesManager.ts +333 -333
  227. package/src/services/storage/KnowledgeGraphManager.ts +425 -425
  228. package/src/services/storage/MemorySearchManager.ts +387 -387
  229. package/src/services/storage/QuiltBatchManager.ts +1130 -660
  230. package/src/services/storage/WalrusMetadataManager.ts +268 -268
  231. package/src/services/storage/WalrusStorageManager.ts +287 -287
  232. package/src/services/storage/index.ts +57 -52
  233. package/src/types/index.ts +13 -13
  234. package/src/utils/LRUCache.ts +378 -0
  235. package/src/utils/index.ts +76 -68
  236. package/src/utils/memoryIndexOnChain.ts +507 -0
  237. package/src/utils/rebuildIndex.ts +290 -290
  238. package/src/utils/rebuildIndexNode.ts +771 -424
  239. package/src/vector/BrowserHnswIndexService.ts +758 -758
  240. package/src/vector/HnswWasmService.ts +731 -679
  241. package/src/vector/IHnswService.ts +233 -224
  242. package/src/vector/NodeHnswService.ts +833 -735
  243. package/src/vector/VectorManager.ts +478 -478
  244. package/src/vector/createHnswService.ts +135 -135
  245. package/src/vector/index.ts +56 -56
  246. package/src/wallet/ContextWalletService.ts +656 -656
  247. 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
+ }