@cmdoss/memwal-sdk 0.7.0 → 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 (192) hide show
  1. package/README.md +129 -0
  2. package/dist/client/ClientMemoryManager.js +2 -2
  3. package/dist/client/ClientMemoryManager.js.map +1 -1
  4. package/dist/client/PersonalDataWallet.d.ts.map +1 -1
  5. package/dist/client/SimplePDWClient.d.ts +28 -0
  6. package/dist/client/SimplePDWClient.d.ts.map +1 -1
  7. package/dist/client/SimplePDWClient.js +29 -6
  8. package/dist/client/SimplePDWClient.js.map +1 -1
  9. package/dist/client/namespaces/MemoryNamespace.d.ts +4 -0
  10. package/dist/client/namespaces/MemoryNamespace.d.ts.map +1 -1
  11. package/dist/client/namespaces/MemoryNamespace.js +168 -39
  12. package/dist/client/namespaces/MemoryNamespace.js.map +1 -1
  13. package/dist/client/namespaces/consolidated/BlockchainNamespace.d.ts +12 -2
  14. package/dist/client/namespaces/consolidated/BlockchainNamespace.d.ts.map +1 -1
  15. package/dist/client/namespaces/consolidated/BlockchainNamespace.js +40 -2
  16. package/dist/client/namespaces/consolidated/BlockchainNamespace.js.map +1 -1
  17. package/dist/client/namespaces/consolidated/StorageNamespace.d.ts +67 -2
  18. package/dist/client/namespaces/consolidated/StorageNamespace.d.ts.map +1 -1
  19. package/dist/client/namespaces/consolidated/StorageNamespace.js +549 -16
  20. package/dist/client/namespaces/consolidated/StorageNamespace.js.map +1 -1
  21. package/dist/config/ConfigurationHelper.js +61 -61
  22. package/dist/config/defaults.js +2 -2
  23. package/dist/config/defaults.js.map +1 -1
  24. package/dist/graph/GraphService.js +20 -20
  25. package/dist/infrastructure/seal/EncryptionService.d.ts +9 -5
  26. package/dist/infrastructure/seal/EncryptionService.d.ts.map +1 -1
  27. package/dist/infrastructure/seal/EncryptionService.js +37 -15
  28. package/dist/infrastructure/seal/EncryptionService.js.map +1 -1
  29. package/dist/infrastructure/seal/SealService.d.ts +13 -5
  30. package/dist/infrastructure/seal/SealService.d.ts.map +1 -1
  31. package/dist/infrastructure/seal/SealService.js +36 -34
  32. package/dist/infrastructure/seal/SealService.js.map +1 -1
  33. package/dist/langchain/createPDWRAG.js +30 -30
  34. package/dist/retrieval/MemoryDecryptionPipeline.d.ts.map +1 -1
  35. package/dist/retrieval/MemoryDecryptionPipeline.js +2 -1
  36. package/dist/retrieval/MemoryDecryptionPipeline.js.map +1 -1
  37. package/dist/services/CapabilityService.d.ts.map +1 -1
  38. package/dist/services/CapabilityService.js +30 -14
  39. package/dist/services/CapabilityService.js.map +1 -1
  40. package/dist/services/CrossContextPermissionService.d.ts.map +1 -1
  41. package/dist/services/CrossContextPermissionService.js +9 -7
  42. package/dist/services/CrossContextPermissionService.js.map +1 -1
  43. package/dist/services/EncryptionService.d.ts.map +1 -1
  44. package/dist/services/EncryptionService.js +6 -5
  45. package/dist/services/EncryptionService.js.map +1 -1
  46. package/dist/services/GeminiAIService.js +309 -309
  47. package/dist/services/StorageService.d.ts +1 -0
  48. package/dist/services/StorageService.d.ts.map +1 -1
  49. package/dist/services/StorageService.js +60 -10
  50. package/dist/services/StorageService.js.map +1 -1
  51. package/dist/services/TransactionService.d.ts +20 -0
  52. package/dist/services/TransactionService.d.ts.map +1 -1
  53. package/dist/services/TransactionService.js +43 -0
  54. package/dist/services/TransactionService.js.map +1 -1
  55. package/dist/services/ViewService.js +2 -2
  56. package/dist/services/ViewService.js.map +1 -1
  57. package/package.json +1 -1
  58. package/src/access/PermissionService.ts +635 -635
  59. package/src/access/index.ts +8 -8
  60. package/src/aggregation/AggregationService.ts +389 -389
  61. package/src/aggregation/index.ts +8 -8
  62. package/src/ai-sdk/PDWVectorStore.ts +715 -715
  63. package/src/ai-sdk/index.ts +65 -65
  64. package/src/ai-sdk/tools.ts +460 -460
  65. package/src/ai-sdk/types.ts +404 -404
  66. package/src/batch/BatchManager.ts +597 -597
  67. package/src/batch/BatchingService.ts +429 -429
  68. package/src/batch/MemoryProcessingCache.ts +492 -492
  69. package/src/batch/index.ts +30 -30
  70. package/src/browser.ts +200 -200
  71. package/src/client/ClientMemoryManager.ts +987 -987
  72. package/src/client/PersonalDataWallet.ts +345 -345
  73. package/src/client/SimplePDWClient.ts +1289 -1237
  74. package/src/client/factory.ts +154 -154
  75. package/src/client/namespaces/AnalyticsNamespace.ts +377 -377
  76. package/src/client/namespaces/BatchNamespace.ts +356 -356
  77. package/src/client/namespaces/CacheNamespace.ts +123 -123
  78. package/src/client/namespaces/CapabilityNamespace.ts +217 -217
  79. package/src/client/namespaces/ClassifyNamespace.ts +169 -169
  80. package/src/client/namespaces/ContextNamespace.ts +297 -297
  81. package/src/client/namespaces/EmbeddingsNamespace.ts +99 -99
  82. package/src/client/namespaces/EncryptionNamespace.ts +221 -221
  83. package/src/client/namespaces/GraphNamespace.ts +468 -468
  84. package/src/client/namespaces/IndexNamespace.ts +361 -361
  85. package/src/client/namespaces/MemoryNamespace.ts +1422 -1272
  86. package/src/client/namespaces/PermissionsNamespace.ts +254 -254
  87. package/src/client/namespaces/PipelineNamespace.ts +220 -220
  88. package/src/client/namespaces/SearchNamespace.ts +1049 -1049
  89. package/src/client/namespaces/StorageNamespace.ts +458 -458
  90. package/src/client/namespaces/TxNamespace.ts +260 -260
  91. package/src/client/namespaces/WalletNamespace.ts +243 -243
  92. package/src/client/namespaces/consolidated/AINamespace.ts +449 -449
  93. package/src/client/namespaces/consolidated/BlockchainNamespace.ts +607 -564
  94. package/src/client/namespaces/consolidated/SecurityNamespace.ts +648 -648
  95. package/src/client/namespaces/consolidated/StorageNamespace.ts +1141 -497
  96. package/src/client/namespaces/consolidated/index.ts +39 -39
  97. package/src/client/signers/DappKitSigner.ts +207 -207
  98. package/src/client/signers/KeypairSigner.ts +108 -108
  99. package/src/client/signers/UnifiedSigner.ts +110 -110
  100. package/src/client/signers/WalletAdapterSigner.ts +159 -159
  101. package/src/client/signers/index.ts +26 -26
  102. package/src/config/ConfigurationHelper.ts +412 -412
  103. package/src/config/defaults.ts +51 -51
  104. package/src/config/index.ts +8 -8
  105. package/src/config/validation.ts +70 -70
  106. package/src/core/index.ts +14 -14
  107. package/src/core/interfaces/IService.ts +307 -307
  108. package/src/core/interfaces/index.ts +8 -8
  109. package/src/core/types/capability.ts +297 -297
  110. package/src/core/types/index.ts +870 -870
  111. package/src/core/types/wallet.ts +270 -270
  112. package/src/core/types.ts +9 -9
  113. package/src/core/wallet.ts +222 -222
  114. package/src/embedding/index.ts +19 -19
  115. package/src/embedding/types.ts +357 -357
  116. package/src/errors/index.ts +602 -602
  117. package/src/errors/recovery.ts +461 -461
  118. package/src/errors/validation.ts +567 -567
  119. package/src/generated/pdw/capability.ts +319 -319
  120. package/src/generated/pdw/deps/sui/object.ts +12 -12
  121. package/src/generated/pdw/deps/sui/vec_map.ts +32 -32
  122. package/src/generated/pdw/memory.ts +1087 -1087
  123. package/src/generated/pdw/wallet.ts +123 -123
  124. package/src/generated/utils/index.ts +159 -159
  125. package/src/graph/GraphService.ts +887 -887
  126. package/src/graph/KnowledgeGraphManager.ts +728 -728
  127. package/src/graph/index.ts +25 -25
  128. package/src/index.ts +498 -498
  129. package/src/infrastructure/index.ts +22 -22
  130. package/src/infrastructure/seal/EncryptionService.ts +628 -603
  131. package/src/infrastructure/seal/SealService.ts +613 -615
  132. package/src/infrastructure/seal/index.ts +9 -9
  133. package/src/infrastructure/sui/BlockchainManager.ts +627 -627
  134. package/src/infrastructure/sui/SuiService.ts +888 -888
  135. package/src/infrastructure/sui/index.ts +9 -9
  136. package/src/infrastructure/walrus/StorageManager.ts +604 -604
  137. package/src/infrastructure/walrus/WalrusStorageService.ts +612 -612
  138. package/src/infrastructure/walrus/index.ts +9 -9
  139. package/src/langchain/PDWEmbeddings.ts +145 -145
  140. package/src/langchain/PDWVectorStore.ts +456 -456
  141. package/src/langchain/createPDWRAG.ts +303 -303
  142. package/src/langchain/index.ts +47 -47
  143. package/src/permissions/ConsentRepository.browser.ts +249 -249
  144. package/src/permissions/ConsentRepository.ts +364 -364
  145. package/src/permissions/index.ts +9 -9
  146. package/src/pipeline/MemoryPipeline.ts +862 -862
  147. package/src/pipeline/PipelineManager.ts +683 -683
  148. package/src/pipeline/index.ts +26 -26
  149. package/src/retrieval/AdvancedSearchService.ts +629 -629
  150. package/src/retrieval/MemoryAnalyticsService.ts +711 -711
  151. package/src/retrieval/MemoryDecryptionPipeline.ts +825 -824
  152. package/src/retrieval/MemoryRetrievalService.ts +904 -904
  153. package/src/retrieval/index.ts +42 -42
  154. package/src/services/BatchService.ts +352 -352
  155. package/src/services/CapabilityService.ts +464 -448
  156. package/src/services/ClassifierService.ts +465 -465
  157. package/src/services/CrossContextPermissionService.ts +486 -484
  158. package/src/services/EmbeddingService.ts +771 -771
  159. package/src/services/EncryptionService.ts +712 -711
  160. package/src/services/GeminiAIService.ts +753 -753
  161. package/src/services/IndexManager.ts +977 -977
  162. package/src/services/MemoryIndexService.ts +1003 -1003
  163. package/src/services/MemoryService.ts +369 -369
  164. package/src/services/QueryService.ts +890 -890
  165. package/src/services/StorageService.ts +1182 -1126
  166. package/src/services/TransactionService.ts +838 -790
  167. package/src/services/VectorService.ts +462 -462
  168. package/src/services/ViewService.ts +484 -484
  169. package/src/services/index.ts +25 -25
  170. package/src/services/storage/BlobAttributesManager.ts +333 -333
  171. package/src/services/storage/KnowledgeGraphManager.ts +425 -425
  172. package/src/services/storage/MemorySearchManager.ts +387 -387
  173. package/src/services/storage/QuiltBatchManager.ts +1130 -1130
  174. package/src/services/storage/WalrusMetadataManager.ts +268 -268
  175. package/src/services/storage/WalrusStorageManager.ts +287 -287
  176. package/src/services/storage/index.ts +57 -57
  177. package/src/types/index.ts +13 -13
  178. package/src/utils/LRUCache.ts +378 -378
  179. package/src/utils/index.ts +76 -76
  180. package/src/utils/memoryIndexOnChain.ts +507 -507
  181. package/src/utils/rebuildIndex.ts +290 -290
  182. package/src/utils/rebuildIndexNode.ts +771 -771
  183. package/src/vector/BrowserHnswIndexService.ts +758 -758
  184. package/src/vector/HnswWasmService.ts +731 -731
  185. package/src/vector/IHnswService.ts +233 -233
  186. package/src/vector/NodeHnswService.ts +833 -833
  187. package/src/vector/VectorManager.ts +478 -478
  188. package/src/vector/createHnswService.ts +135 -135
  189. package/src/vector/index.ts +56 -56
  190. package/src/wallet/ContextWalletService.ts +656 -656
  191. package/src/wallet/MainWalletService.ts +317 -317
  192. package/src/wallet/index.ts +17 -17
@@ -260,6 +260,7 @@ export class StorageNamespace {
260
260
  * Store memory package to Walrus
261
261
  *
262
262
  * Higher-level method that stores a complete memory package.
263
+ * Automatically encrypts content if encryption is enabled in config.
263
264
  *
264
265
  * @param memoryPackage - Memory package to store
265
266
  * @returns Upload result
@@ -268,12 +269,93 @@ export class StorageNamespace {
268
269
  if (!this.services.storage) {
269
270
  throw new Error('Storage service not configured.');
270
271
  }
272
+ // Check if encryption is enabled
273
+ const encryptionEnabled = this.services.config.features?.enableEncryption ?? true;
274
+ let encryptedContent;
275
+ let encryptedEmbedding; // Option A v2: encrypted embedding
276
+ let encryptionType;
277
+ let memoryCapId;
278
+ let keyId;
279
+ console.log('🔍 Encryption check:', {
280
+ encryptionEnabled,
281
+ hasEncryptionService: !!this.services.encryption,
282
+ hasCapabilityService: !!this.services.capability,
283
+ configFeatures: this.services.config.features
284
+ });
285
+ if (encryptionEnabled && this.services.encryption && this.services.capability) {
286
+ console.log('🔒 Encrypting memory package with SEAL (capability-based)...');
287
+ try {
288
+ // Step 1: Get or create capability for this app context
289
+ const category = memoryPackage.metadata?.category || 'general';
290
+ console.log(`🔐 Getting/creating capability for category: ${category}`);
291
+ const cap = await this.services.capability.getOrCreate({
292
+ appId: category,
293
+ userAddress: this.services.config.userAddress
294
+ }, this.services.config.signer);
295
+ memoryCapId = cap.id;
296
+ console.log(`✅ Capability ready: ${memoryCapId}`);
297
+ // Step 2: Compute key_id from capability (keccak256(owner || nonce))
298
+ keyId = this.services.capability.computeKeyId(cap);
299
+ console.log(`🔑 Key ID computed: ${keyId.substring(0, 20)}...`);
300
+ // Step 3: Encrypt the content using key_id as SEAL identity
301
+ const contentBytes = new TextEncoder().encode(memoryPackage.content);
302
+ const encryptResult = await this.services.encryption.encrypt(contentBytes, keyId, // Use key_id from capability as SEAL identity!
303
+ 2 // threshold: 2 of 2 key servers
304
+ );
305
+ encryptedContent = encryptResult.encryptedObject;
306
+ encryptionType = 'seal-capability';
307
+ console.log(`✅ Content encrypted: ${contentBytes.length} bytes → ${encryptedContent?.length || 0} bytes`);
308
+ // Step 4: Also encrypt the embedding for fast index rebuild (Option A v2)
309
+ const embeddingToEncrypt = memoryPackage.embedding && memoryPackage.embedding.length > 0
310
+ ? memoryPackage.embedding
311
+ : (memoryPackage.metadata?.embedding || []);
312
+ if (embeddingToEncrypt.length > 0) {
313
+ const embeddingBytes = new TextEncoder().encode(JSON.stringify(embeddingToEncrypt));
314
+ const encryptEmbeddingResult = await this.services.encryption.encrypt(embeddingBytes, keyId, 2);
315
+ encryptedEmbedding = encryptEmbeddingResult.encryptedObject;
316
+ console.log(`✅ Embedding encrypted: ${embeddingToEncrypt.length}D → ${encryptedEmbedding?.length || 0} bytes`);
317
+ }
318
+ console.log(` Using capability: ${memoryCapId}`);
319
+ console.log(` Key ID: ${keyId.substring(0, 20)}...`);
320
+ }
321
+ catch (encryptError) {
322
+ console.error('❌ Encryption failed:', encryptError);
323
+ console.warn('⚠️ Falling back to plaintext storage');
324
+ // Fall back to plaintext if encryption fails
325
+ }
326
+ }
327
+ else {
328
+ console.log('📝 Encryption disabled or services not available - storing plaintext');
329
+ }
330
+ // Include capability metadata for decryption
331
+ const metadata = {
332
+ ...memoryPackage.metadata,
333
+ // Add capability info for decryption (CRITICAL for Option A!)
334
+ ...(memoryCapId && keyId ? {
335
+ memoryCapId,
336
+ keyId,
337
+ encryptionVersion: 'v2-capability' // Mark as new capability-based encryption
338
+ } : {})
339
+ };
340
+ // Get embedding from root level (correct API) or metadata (legacy fallback)
341
+ const rootEmbedding = memoryPackage.embedding && memoryPackage.embedding.length > 0;
342
+ const metadataEmbedding = memoryPackage.metadata?.embedding && memoryPackage.metadata.embedding.length > 0;
343
+ const embedding = rootEmbedding
344
+ ? memoryPackage.embedding
345
+ : (memoryPackage.metadata?.embedding || []);
346
+ if (metadataEmbedding && !rootEmbedding) {
347
+ console.warn('⚠️ Embedding in metadata (legacy) - should be at root level');
348
+ }
349
+ console.log(`📊 Embedding: ${embedding.length}D vector`);
271
350
  // Use uploadMemoryPackage method
272
351
  const result = await this.services.storage.uploadMemoryPackage({
273
352
  content: memoryPackage.content,
274
- embedding: memoryPackage.embedding || [],
275
- metadata: memoryPackage.metadata || {},
276
- identity: this.services.config.userAddress
353
+ embedding,
354
+ metadata,
355
+ identity: this.services.config.userAddress,
356
+ encryptedContent, // Pass encrypted content if available
357
+ encryptedEmbedding, // Pass encrypted embedding for Option A v2
358
+ encryptionType
277
359
  }, {
278
360
  signer: this.services.config.signer,
279
361
  epochs: 3,
@@ -282,32 +364,277 @@ export class StorageNamespace {
282
364
  return {
283
365
  blobId: result.blobId,
284
366
  size: 0, // Size not returned by uploadMemoryPackage
285
- contentType: 'application/json'
367
+ contentType: 'application/json',
368
+ memoryCapId, // Return capability ID for reference
369
+ keyId // Return key ID for reference
286
370
  };
287
371
  }
288
372
  /**
289
- * Retrieve memory package from Walrus
373
+ * Retrieve memory package from Walrus with optional decryption
290
374
  *
291
375
  * @param blobId - Blob ID of the memory package
376
+ * @param decryptionContext - Optional context for decrypting SEAL-encrypted content
292
377
  * @returns Retrieved memory package with decrypted content
378
+ *
379
+ * @example
380
+ * ```typescript
381
+ * // Without decryption (returns encrypted data info)
382
+ * const result = await pdw.storage.retrieveMemoryPackage(blobId);
383
+ *
384
+ * // With decryption
385
+ * const result = await pdw.storage.retrieveMemoryPackage(blobId, {
386
+ * sessionKey,
387
+ * memoryCapId,
388
+ * keyId
389
+ * });
390
+ * ```
293
391
  */
294
- async retrieveMemoryPackage(blobId) {
392
+ async retrieveMemoryPackage(blobId, decryptionContext) {
295
393
  if (!this.services.storage) {
296
394
  throw new Error('Storage service not configured.');
297
395
  }
298
396
  const result = await this.services.storage.retrieveMemoryPackage(blobId);
299
- // Map to expected return type
300
- return {
301
- memoryPackage: result.memoryPackage ? {
302
- content: result.memoryPackage.content,
303
- contentType: result.memoryPackage.contentType || 'text/plain',
397
+ // If not encrypted, return as-is
398
+ if (!result.isEncrypted && result.memoryPackage) {
399
+ return {
400
+ memoryPackage: {
401
+ content: result.memoryPackage.content,
402
+ contentType: result.memoryPackage.contentType || 'text/plain',
403
+ metadata: result.memoryPackage.metadata,
404
+ embedding: result.memoryPackage.embedding,
405
+ createdAt: result.memoryPackage.timestamp
406
+ },
407
+ decryptionStatus: 'not_encrypted'
408
+ };
409
+ }
410
+ // v2.2 JSON package with encrypted content + encrypted embedding
411
+ if (result.memoryPackage?.version === '2.2' && result.memoryPackage?.encryptedContent) {
412
+ console.log('🔐 Detected v2.2 JSON package (Full Encryption - Content + Embedding)');
413
+ const embeddingDimension = result.memoryPackage.metadata?.embeddingDimension || 0;
414
+ console.log(` embeddingDimension: ${embeddingDimension}D (encrypted on Walrus)`);
415
+ // Return base package (content encrypted, embedding encrypted)
416
+ const basePackage = {
417
+ content: '[ENCRYPTED - requires decryption]',
418
+ contentType: 'text/plain',
419
+ metadata: result.memoryPackage.metadata,
420
+ embedding: [], // Embedding is encrypted, needs decryption
421
+ createdAt: result.memoryPackage.timestamp
422
+ };
423
+ if (decryptionContext && this.services.encryption) {
424
+ try {
425
+ console.log('🔐 Decrypting v2.2 content...');
426
+ // Decrypt content
427
+ const encryptedContentBase64 = result.memoryPackage.encryptedContent;
428
+ const contentBinaryString = atob(encryptedContentBase64);
429
+ const encryptedContentBytes = new Uint8Array(contentBinaryString.length);
430
+ for (let i = 0; i < contentBinaryString.length; i++) {
431
+ encryptedContentBytes[i] = contentBinaryString.charCodeAt(i);
432
+ }
433
+ const decryptedContentData = await this.services.encryption.decrypt({
434
+ encryptedContent: encryptedContentBytes,
435
+ userAddress: this.services.config.userAddress,
436
+ sessionKey: decryptionContext.sessionKey,
437
+ memoryCapId: decryptionContext.memoryCapId,
438
+ keyId: decryptionContext.keyId
439
+ });
440
+ const decryptedContent = new TextDecoder().decode(decryptedContentData);
441
+ console.log(`✅ v2.2 content decrypted: "${decryptedContent.substring(0, 50)}..."`);
442
+ // Decrypt embedding if available
443
+ let decryptedEmbedding = [];
444
+ if (result.memoryPackage.encryptedEmbedding) {
445
+ console.log('🔐 Decrypting v2.2 embedding...');
446
+ const encryptedEmbeddingBase64 = result.memoryPackage.encryptedEmbedding;
447
+ const embeddingBinaryString = atob(encryptedEmbeddingBase64);
448
+ const encryptedEmbeddingBytes = new Uint8Array(embeddingBinaryString.length);
449
+ for (let i = 0; i < embeddingBinaryString.length; i++) {
450
+ encryptedEmbeddingBytes[i] = embeddingBinaryString.charCodeAt(i);
451
+ }
452
+ const decryptedEmbeddingData = await this.services.encryption.decrypt({
453
+ encryptedContent: encryptedEmbeddingBytes,
454
+ userAddress: this.services.config.userAddress,
455
+ sessionKey: decryptionContext.sessionKey,
456
+ memoryCapId: decryptionContext.memoryCapId,
457
+ keyId: decryptionContext.keyId
458
+ });
459
+ const embeddingJson = new TextDecoder().decode(decryptedEmbeddingData);
460
+ decryptedEmbedding = JSON.parse(embeddingJson);
461
+ console.log(`✅ v2.2 embedding decrypted: ${decryptedEmbedding.length}D vector`);
462
+ }
463
+ return {
464
+ memoryPackage: {
465
+ ...basePackage,
466
+ content: decryptedContent,
467
+ embedding: decryptedEmbedding
468
+ },
469
+ decryptionStatus: 'success'
470
+ };
471
+ }
472
+ catch (decryptError) {
473
+ console.error('❌ v2.2 decryption failed:', decryptError.message);
474
+ return {
475
+ memoryPackage: basePackage,
476
+ decryptionStatus: 'failed',
477
+ error: decryptError.message
478
+ };
479
+ }
480
+ }
481
+ // No decryption context
482
+ return {
483
+ memoryPackage: basePackage,
484
+ decryptionStatus: 'failed',
485
+ error: 'No decryption context provided for v2.2 encrypted package'
486
+ };
487
+ }
488
+ // v2.1 JSON package with encrypted content only (no embedding on Walrus)
489
+ if (result.memoryPackage?.version === '2.1' && result.memoryPackage?.encryptedContent) {
490
+ console.log('🔐 Detected v2.1 JSON package (Full Encryption - Content only)');
491
+ const embeddingDimension = result.memoryPackage.metadata?.embeddingDimension || 0;
492
+ console.log(` embeddingDimension: ${embeddingDimension}D (stored locally, not on Walrus)`);
493
+ const basePackage = {
494
+ content: '[ENCRYPTED - requires decryption]',
495
+ contentType: 'text/plain',
304
496
  metadata: result.memoryPackage.metadata,
305
- embedding: result.memoryPackage.embedding,
497
+ embedding: [], // v2.1 has no embedding on Walrus
306
498
  createdAt: result.memoryPackage.timestamp
307
- } : null,
308
- decryptionStatus: result.isEncrypted
309
- ? (result.memoryPackage ? 'success' : 'failed')
310
- : 'not_encrypted'
499
+ };
500
+ if (decryptionContext && this.services.encryption) {
501
+ try {
502
+ console.log('🔐 Decrypting v2.1 content...');
503
+ const encryptedBase64 = result.memoryPackage.encryptedContent;
504
+ const binaryString = atob(encryptedBase64);
505
+ const encryptedBytes = new Uint8Array(binaryString.length);
506
+ for (let i = 0; i < binaryString.length; i++) {
507
+ encryptedBytes[i] = binaryString.charCodeAt(i);
508
+ }
509
+ const decryptedData = await this.services.encryption.decrypt({
510
+ encryptedContent: encryptedBytes,
511
+ userAddress: this.services.config.userAddress,
512
+ sessionKey: decryptionContext.sessionKey,
513
+ memoryCapId: decryptionContext.memoryCapId,
514
+ keyId: decryptionContext.keyId
515
+ });
516
+ const decryptedContent = new TextDecoder().decode(decryptedData);
517
+ console.log(`✅ v2.1 decryption successful: "${decryptedContent.substring(0, 50)}..."`);
518
+ return {
519
+ memoryPackage: {
520
+ ...basePackage,
521
+ content: decryptedContent
522
+ },
523
+ decryptionStatus: 'success'
524
+ };
525
+ }
526
+ catch (decryptError) {
527
+ console.error('❌ v2.1 decryption failed:', decryptError.message);
528
+ return {
529
+ memoryPackage: basePackage,
530
+ decryptionStatus: 'failed',
531
+ error: decryptError.message
532
+ };
533
+ }
534
+ }
535
+ return {
536
+ memoryPackage: basePackage,
537
+ decryptionStatus: 'failed',
538
+ error: 'No decryption context provided for v2.1 encrypted package'
539
+ };
540
+ }
541
+ // v2.0 JSON package with encrypted content + plaintext embedding (legacy)
542
+ if (result.memoryPackage?.version === '2.0' && result.memoryPackage?.encryptedContent) {
543
+ console.log('📦 Detected v2.0 JSON package with encrypted content (legacy)');
544
+ // Get embedding from root level OR metadata.embedding (fallback for encryption service bug)
545
+ const embeddingArray = result.memoryPackage.embedding?.length > 0
546
+ ? result.memoryPackage.embedding
547
+ : result.memoryPackage.metadata?.embedding;
548
+ const embeddingSource = result.memoryPackage.embedding?.length > 0 ? 'root' : 'metadata';
549
+ console.log(` embedding: ${embeddingArray?.length || 0}D (from ${embeddingSource})`);
550
+ // Return embedding even without decryption (for index rebuilding)
551
+ const basePackage = {
552
+ content: '[ENCRYPTED - requires decryption]',
553
+ contentType: 'text/plain',
554
+ metadata: result.memoryPackage.metadata,
555
+ embedding: embeddingArray, // Plaintext embedding available!
556
+ createdAt: result.memoryPackage.timestamp
557
+ };
558
+ if (decryptionContext && this.services.encryption) {
559
+ try {
560
+ console.log('🔐 Decrypting v2.0 encryptedContent...');
561
+ // Convert base64 back to Uint8Array
562
+ const encryptedBase64 = result.memoryPackage.encryptedContent;
563
+ const binaryString = atob(encryptedBase64);
564
+ const encryptedBytes = new Uint8Array(binaryString.length);
565
+ for (let i = 0; i < binaryString.length; i++) {
566
+ encryptedBytes[i] = binaryString.charCodeAt(i);
567
+ }
568
+ const decryptedData = await this.services.encryption.decrypt({
569
+ encryptedContent: encryptedBytes,
570
+ userAddress: this.services.config.userAddress,
571
+ sessionKey: decryptionContext.sessionKey,
572
+ memoryCapId: decryptionContext.memoryCapId,
573
+ keyId: decryptionContext.keyId
574
+ });
575
+ const decryptedContent = new TextDecoder().decode(decryptedData);
576
+ console.log(`✅ v2.0 decryption successful, content: "${decryptedContent.substring(0, 50)}..."`);
577
+ return {
578
+ memoryPackage: {
579
+ ...basePackage,
580
+ content: decryptedContent
581
+ },
582
+ decryptionStatus: 'success'
583
+ };
584
+ }
585
+ catch (decryptError) {
586
+ console.error('❌ v2.0 decryption failed:', decryptError.message);
587
+ return {
588
+ memoryPackage: basePackage, // Return with embedding but encrypted content
589
+ decryptionStatus: 'failed',
590
+ error: decryptError.message
591
+ };
592
+ }
593
+ }
594
+ // No decryption context - return with embedding only
595
+ return {
596
+ memoryPackage: basePackage,
597
+ decryptionStatus: 'failed',
598
+ error: 'No decryption context provided (embedding still available)'
599
+ };
600
+ }
601
+ // Legacy binary format (v0) - try to decrypt if context provided
602
+ if (decryptionContext && this.services.encryption) {
603
+ try {
604
+ console.log('🔐 Decrypting legacy binary format...');
605
+ const decryptedData = await this.services.encryption.decrypt({
606
+ encryptedContent: result.content,
607
+ userAddress: this.services.config.userAddress,
608
+ sessionKey: decryptionContext.sessionKey,
609
+ memoryCapId: decryptionContext.memoryCapId,
610
+ keyId: decryptionContext.keyId
611
+ });
612
+ const decryptedContent = new TextDecoder().decode(decryptedData);
613
+ console.log(`✅ Legacy decryption successful, content length: ${decryptedContent.length}`);
614
+ return {
615
+ memoryPackage: {
616
+ content: decryptedContent,
617
+ contentType: 'text/plain',
618
+ metadata: result.metadata,
619
+ createdAt: result.metadata.createdTimestamp
620
+ },
621
+ decryptionStatus: 'success'
622
+ };
623
+ }
624
+ catch (decryptError) {
625
+ console.error('❌ Legacy decryption failed:', decryptError.message);
626
+ return {
627
+ memoryPackage: null,
628
+ decryptionStatus: 'failed',
629
+ error: decryptError.message
630
+ };
631
+ }
632
+ }
633
+ // Encrypted but no decryption context provided
634
+ return {
635
+ memoryPackage: null,
636
+ decryptionStatus: 'failed',
637
+ error: 'Content is encrypted but no decryption context provided'
311
638
  };
312
639
  }
313
640
  /**
@@ -348,6 +675,212 @@ export class StorageNamespace {
348
675
  }
349
676
  }
350
677
  // ==========================================================================
678
+ // High-Level Decrypt API
679
+ // ==========================================================================
680
+ /**
681
+ * Retrieve and decrypt a memory package with minimal boilerplate.
682
+ * SDK handles all version detection, format conversion, and decryption internally.
683
+ *
684
+ * @param blobId - Blob ID on Walrus
685
+ * @param options - Decryption options
686
+ * @returns Decrypted content, embedding, and metadata
687
+ *
688
+ * @example
689
+ * ```typescript
690
+ * // With sign function (SDK creates session key)
691
+ * const result = await pdw.storage.retrieveAndDecrypt(blobId, {
692
+ * signFn: async (message) => {
693
+ * const sig = await signPersonalMessage({ message: new TextEncoder().encode(message) });
694
+ * return { signature: sig.signature };
695
+ * }
696
+ * });
697
+ *
698
+ * // With existing session key
699
+ * const result = await pdw.storage.retrieveAndDecrypt(blobId, { sessionKey });
700
+ *
701
+ * console.log(result.content); // "my name is Aaron"
702
+ * console.log(result.embedding); // [0.12, -0.34, ...] (3072D)
703
+ * console.log(result.version); // "2.2"
704
+ * ```
705
+ */
706
+ async retrieveAndDecrypt(blobId, options = {}) {
707
+ if (!this.services.storage) {
708
+ throw new Error('Storage service not configured.');
709
+ }
710
+ console.log(`🔐 retrieveAndDecrypt: Downloading blob ${blobId}...`);
711
+ // Step 1: Download blob from Walrus
712
+ const blobData = await this.download(blobId);
713
+ console.log(` Downloaded ${blobData.length} bytes`);
714
+ // Step 2: Detect format and parse
715
+ let version = 'legacy';
716
+ let isEncrypted = false;
717
+ let encryptedContentBase64 = null;
718
+ let encryptedEmbeddingBase64 = null;
719
+ let metadata = {};
720
+ let plainEmbedding = [];
721
+ try {
722
+ const blobText = new TextDecoder().decode(blobData);
723
+ const parsed = JSON.parse(blobText);
724
+ // v2.2: Full encryption (content + embedding both encrypted)
725
+ if (parsed.version === '2.2' && parsed.encryptedContent) {
726
+ version = '2.2';
727
+ isEncrypted = true;
728
+ encryptedContentBase64 = parsed.encryptedContent;
729
+ encryptedEmbeddingBase64 = parsed.encryptedEmbedding || null;
730
+ metadata = parsed.metadata || {};
731
+ console.log(` Detected v2.2: encrypted content + encrypted embedding`);
732
+ }
733
+ // v2.1: Encrypted content only (no embedding on Walrus)
734
+ else if (parsed.version === '2.1' && parsed.encryptedContent) {
735
+ version = '2.1';
736
+ isEncrypted = true;
737
+ encryptedContentBase64 = parsed.encryptedContent;
738
+ metadata = parsed.metadata || {};
739
+ console.log(` Detected v2.1: encrypted content only`);
740
+ }
741
+ // v2.0: Encrypted content + plaintext embedding
742
+ else if (parsed.version === '2.0' && parsed.encryptedContent) {
743
+ version = '2.0';
744
+ isEncrypted = true;
745
+ encryptedContentBase64 = parsed.encryptedContent;
746
+ plainEmbedding = parsed.embedding || [];
747
+ metadata = parsed.metadata || {};
748
+ console.log(` Detected v2.0: encrypted content + ${plainEmbedding.length}D plaintext embedding`);
749
+ }
750
+ // v1.0: Plaintext JSON package
751
+ else if (parsed.version && parsed.content) {
752
+ version = 'plaintext';
753
+ isEncrypted = false;
754
+ metadata = parsed.metadata || {};
755
+ plainEmbedding = parsed.embedding || [];
756
+ console.log(` Detected plaintext JSON package`);
757
+ return {
758
+ content: parsed.content,
759
+ embedding: plainEmbedding,
760
+ version,
761
+ isEncrypted,
762
+ metadata,
763
+ blobId
764
+ };
765
+ }
766
+ }
767
+ catch {
768
+ // Not JSON - check if binary SEAL data
769
+ const isBinary = blobData.some(byte => byte < 32 && byte !== 9 && byte !== 10 && byte !== 13);
770
+ if (isBinary || blobData.some(byte => byte > 127)) {
771
+ version = 'legacy';
772
+ isEncrypted = true;
773
+ console.log(` Detected legacy binary format`);
774
+ }
775
+ else {
776
+ // Plain text content
777
+ version = 'plaintext';
778
+ isEncrypted = false;
779
+ console.log(` Detected plaintext content`);
780
+ return {
781
+ content: new TextDecoder().decode(blobData),
782
+ embedding: [],
783
+ version,
784
+ isEncrypted,
785
+ metadata: {},
786
+ blobId
787
+ };
788
+ }
789
+ }
790
+ // Step 3: If not encrypted, return as-is
791
+ if (!isEncrypted) {
792
+ return {
793
+ content: new TextDecoder().decode(blobData),
794
+ embedding: plainEmbedding,
795
+ version,
796
+ isEncrypted,
797
+ metadata,
798
+ blobId
799
+ };
800
+ }
801
+ // Step 4: Get decryption parameters (from options or metadata)
802
+ const memoryCapId = options.memoryCapId || metadata.memoryCapId;
803
+ const keyIdHex = options.keyId || metadata.keyId;
804
+ if (!memoryCapId || !keyIdHex) {
805
+ throw new Error(`Missing decryption parameters. memoryCapId=${!!memoryCapId}, keyId=${!!keyIdHex}. ` +
806
+ `Provide via options or ensure metadata contains these values.`);
807
+ }
808
+ // Step 5: Convert keyId hex string to Uint8Array (SDK handles this!)
809
+ const keyIdBytes = new Uint8Array((keyIdHex.startsWith('0x') ? keyIdHex.slice(2) : keyIdHex)
810
+ .match(/.{1,2}/g)
811
+ .map((byte) => parseInt(byte, 16)));
812
+ // Step 6: Get or create session key
813
+ let sessionKey = options.sessionKey;
814
+ if (!sessionKey) {
815
+ if (!options.signFn) {
816
+ throw new Error('Decryption requires either sessionKey or signFn. ' +
817
+ 'Provide signFn to create session key automatically.');
818
+ }
819
+ if (!this.services.encryption) {
820
+ throw new Error('Encryption service not configured.');
821
+ }
822
+ console.log(` Creating session key (will prompt for signature)...`);
823
+ sessionKey = await this.services.encryption.createSessionKey(this.services.config.userAddress, {
824
+ signPersonalMessageFn: async (message) => {
825
+ return options.signFn(message);
826
+ }
827
+ });
828
+ console.log(` Session key created`);
829
+ }
830
+ // Step 7: Decrypt content
831
+ console.log(` Decrypting content...`);
832
+ // Convert base64 to Uint8Array if needed
833
+ let dataToDecrypt;
834
+ if (encryptedContentBase64) {
835
+ const binaryString = atob(encryptedContentBase64);
836
+ dataToDecrypt = new Uint8Array(binaryString.length);
837
+ for (let i = 0; i < binaryString.length; i++) {
838
+ dataToDecrypt[i] = binaryString.charCodeAt(i);
839
+ }
840
+ }
841
+ else {
842
+ dataToDecrypt = blobData;
843
+ }
844
+ const decryptedContentData = await this.services.encryption.decrypt({
845
+ encryptedContent: dataToDecrypt,
846
+ userAddress: this.services.config.userAddress,
847
+ sessionKey,
848
+ memoryCapId,
849
+ keyId: keyIdBytes
850
+ });
851
+ const content = new TextDecoder().decode(decryptedContentData);
852
+ console.log(` Content decrypted: "${content.substring(0, 50)}${content.length > 50 ? '...' : ''}"`);
853
+ // Step 8: Decrypt embedding if v2.2
854
+ let embedding = plainEmbedding;
855
+ if (version === '2.2' && encryptedEmbeddingBase64) {
856
+ console.log(` Decrypting embedding...`);
857
+ const embeddingBinaryString = atob(encryptedEmbeddingBase64);
858
+ const encryptedEmbeddingBytes = new Uint8Array(embeddingBinaryString.length);
859
+ for (let i = 0; i < embeddingBinaryString.length; i++) {
860
+ encryptedEmbeddingBytes[i] = embeddingBinaryString.charCodeAt(i);
861
+ }
862
+ const decryptedEmbeddingData = await this.services.encryption.decrypt({
863
+ encryptedContent: encryptedEmbeddingBytes,
864
+ userAddress: this.services.config.userAddress,
865
+ sessionKey,
866
+ memoryCapId,
867
+ keyId: keyIdBytes
868
+ });
869
+ const embeddingJson = new TextDecoder().decode(decryptedEmbeddingData);
870
+ embedding = JSON.parse(embeddingJson);
871
+ console.log(` Embedding decrypted: ${embedding.length}D vector`);
872
+ }
873
+ console.log(`✅ retrieveAndDecrypt complete: ${content.length} chars, ${embedding.length}D embedding`);
874
+ return {
875
+ content,
876
+ embedding,
877
+ version,
878
+ isEncrypted,
879
+ metadata,
880
+ blobId
881
+ };
882
+ }
883
+ // ==========================================================================
351
884
  // Batch Operations (Quilt)
352
885
  // ==========================================================================
353
886
  /**