@cmdoss/memwal-sdk 0.6.2 → 0.7.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 (119) hide show
  1. package/ARCHITECTURE.md +547 -547
  2. package/BENCHMARKS.md +238 -238
  3. package/README.md +181 -181
  4. package/dist/ai-sdk/tools.d.ts +2 -2
  5. package/dist/ai-sdk/tools.js +2 -2
  6. package/dist/client/PersonalDataWallet.d.ts.map +1 -1
  7. package/dist/client/SimplePDWClient.d.ts +1 -1
  8. package/dist/client/SimplePDWClient.d.ts.map +1 -1
  9. package/dist/client/SimplePDWClient.js +16 -7
  10. package/dist/client/SimplePDWClient.js.map +1 -1
  11. package/dist/client/namespaces/EmbeddingsNamespace.d.ts +1 -1
  12. package/dist/client/namespaces/EmbeddingsNamespace.js +1 -1
  13. package/dist/client/namespaces/MemoryNamespace.d.ts +27 -0
  14. package/dist/client/namespaces/MemoryNamespace.d.ts.map +1 -1
  15. package/dist/client/namespaces/MemoryNamespace.js +104 -0
  16. package/dist/client/namespaces/MemoryNamespace.js.map +1 -1
  17. package/dist/client/namespaces/consolidated/AINamespace.d.ts +2 -2
  18. package/dist/client/namespaces/consolidated/AINamespace.js +2 -2
  19. package/dist/client/namespaces/consolidated/BlockchainNamespace.d.ts.map +1 -1
  20. package/dist/client/namespaces/consolidated/BlockchainNamespace.js +22 -2
  21. package/dist/client/namespaces/consolidated/BlockchainNamespace.js.map +1 -1
  22. package/dist/graph/GraphService.js +1 -1
  23. package/dist/graph/GraphService.js.map +1 -1
  24. package/dist/index.d.ts +3 -1
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +3 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/retrieval/MemoryRetrievalService.d.ts +31 -0
  29. package/dist/retrieval/MemoryRetrievalService.d.ts.map +1 -1
  30. package/dist/retrieval/MemoryRetrievalService.js +44 -4
  31. package/dist/retrieval/MemoryRetrievalService.js.map +1 -1
  32. package/dist/services/EmbeddingService.d.ts +28 -1
  33. package/dist/services/EmbeddingService.d.ts.map +1 -1
  34. package/dist/services/EmbeddingService.js +54 -0
  35. package/dist/services/EmbeddingService.js.map +1 -1
  36. package/dist/services/IndexManager.d.ts +5 -1
  37. package/dist/services/IndexManager.d.ts.map +1 -1
  38. package/dist/services/IndexManager.js +17 -40
  39. package/dist/services/IndexManager.js.map +1 -1
  40. package/dist/services/QueryService.js +1 -1
  41. package/dist/services/QueryService.js.map +1 -1
  42. package/dist/services/StorageService.d.ts +10 -0
  43. package/dist/services/StorageService.d.ts.map +1 -1
  44. package/dist/services/StorageService.js +13 -0
  45. package/dist/services/StorageService.js.map +1 -1
  46. package/dist/services/storage/QuiltBatchManager.d.ts +101 -1
  47. package/dist/services/storage/QuiltBatchManager.d.ts.map +1 -1
  48. package/dist/services/storage/QuiltBatchManager.js +410 -20
  49. package/dist/services/storage/QuiltBatchManager.js.map +1 -1
  50. package/dist/services/storage/index.d.ts +1 -1
  51. package/dist/services/storage/index.d.ts.map +1 -1
  52. package/dist/services/storage/index.js.map +1 -1
  53. package/dist/utils/LRUCache.d.ts +106 -0
  54. package/dist/utils/LRUCache.d.ts.map +1 -0
  55. package/dist/utils/LRUCache.js +281 -0
  56. package/dist/utils/LRUCache.js.map +1 -0
  57. package/dist/utils/index.d.ts +1 -0
  58. package/dist/utils/index.d.ts.map +1 -1
  59. package/dist/utils/index.js +2 -0
  60. package/dist/utils/index.js.map +1 -1
  61. package/dist/utils/memoryIndexOnChain.d.ts +212 -0
  62. package/dist/utils/memoryIndexOnChain.d.ts.map +1 -0
  63. package/dist/utils/memoryIndexOnChain.js +312 -0
  64. package/dist/utils/memoryIndexOnChain.js.map +1 -0
  65. package/dist/utils/rebuildIndexNode.d.ts +29 -0
  66. package/dist/utils/rebuildIndexNode.d.ts.map +1 -1
  67. package/dist/utils/rebuildIndexNode.js +366 -98
  68. package/dist/utils/rebuildIndexNode.js.map +1 -1
  69. package/dist/vector/HnswWasmService.d.ts +20 -5
  70. package/dist/vector/HnswWasmService.d.ts.map +1 -1
  71. package/dist/vector/HnswWasmService.js +73 -40
  72. package/dist/vector/HnswWasmService.js.map +1 -1
  73. package/dist/vector/IHnswService.d.ts +10 -1
  74. package/dist/vector/IHnswService.d.ts.map +1 -1
  75. package/dist/vector/IHnswService.js.map +1 -1
  76. package/dist/vector/NodeHnswService.d.ts +16 -0
  77. package/dist/vector/NodeHnswService.d.ts.map +1 -1
  78. package/dist/vector/NodeHnswService.js +84 -5
  79. package/dist/vector/NodeHnswService.js.map +1 -1
  80. package/dist/vector/createHnswService.d.ts +1 -1
  81. package/dist/vector/createHnswService.js +1 -1
  82. package/dist/vector/index.d.ts +1 -1
  83. package/dist/vector/index.js +1 -1
  84. package/package.json +157 -157
  85. package/src/access/index.ts +8 -8
  86. package/src/aggregation/index.ts +8 -8
  87. package/src/ai-sdk/tools.ts +2 -2
  88. package/src/client/SimplePDWClient.ts +23 -8
  89. package/src/client/namespaces/EmbeddingsNamespace.ts +1 -1
  90. package/src/client/namespaces/MemoryNamespace.ts +137 -0
  91. package/src/client/namespaces/consolidated/AINamespace.ts +2 -2
  92. package/src/client/namespaces/consolidated/BlockchainNamespace.ts +20 -2
  93. package/src/client/signers/DappKitSigner.ts +207 -207
  94. package/src/core/types/index.ts +1 -1
  95. package/src/generated/pdw/deps/sui/object.ts +12 -12
  96. package/src/generated/pdw/deps/sui/vec_map.ts +32 -32
  97. package/src/generated/pdw/memory.ts +1087 -1087
  98. package/src/generated/pdw/wallet.ts +123 -123
  99. package/src/generated/utils/index.ts +159 -159
  100. package/src/graph/GraphService.ts +1 -1
  101. package/src/index.ts +25 -1
  102. package/src/permissions/index.ts +9 -9
  103. package/src/retrieval/MemoryRetrievalService.ts +78 -4
  104. package/src/services/EmbeddingService.ts +66 -1
  105. package/src/services/IndexManager.ts +18 -45
  106. package/src/services/QueryService.ts +1 -1
  107. package/src/services/StorageService.ts +15 -0
  108. package/src/services/storage/QuiltBatchManager.ts +492 -22
  109. package/src/services/storage/index.ts +6 -1
  110. package/src/utils/LRUCache.ts +378 -0
  111. package/src/utils/index.ts +8 -0
  112. package/src/utils/memoryIndexOnChain.ts +507 -0
  113. package/src/utils/rebuildIndexNode.ts +453 -106
  114. package/src/vector/HnswWasmService.ts +95 -43
  115. package/src/vector/IHnswService.ts +10 -1
  116. package/src/vector/NodeHnswService.ts +103 -5
  117. package/src/vector/createHnswService.ts +1 -1
  118. package/src/vector/index.ts +1 -1
  119. package/src/wallet/index.ts +17 -17
@@ -28,16 +28,37 @@ import { WalrusClient, WalrusFile } from '@mysten/walrus';
28
28
  import type { ClientWithExtensions } from '@mysten/sui/experimental';
29
29
  import type { SuiClient } from '@mysten/sui/client';
30
30
  import type { UnifiedSigner } from '../../client/signers/UnifiedSigner';
31
+ /**
32
+ * Input for batch memory upload
33
+ */
31
34
  export interface BatchMemory {
32
35
  content: string;
33
36
  category: string;
34
37
  importance: number;
35
38
  topic: string;
36
39
  embedding: number[];
37
- encryptedContent: Uint8Array;
40
+ encryptedContent?: Uint8Array;
38
41
  summary?: string;
39
42
  id?: string;
40
43
  }
44
+ /**
45
+ * Memory package stored in Quilt as JSON
46
+ * This format is consistent with regular memory storage
47
+ */
48
+ export interface QuiltMemoryPackage {
49
+ content: string;
50
+ embedding: number[];
51
+ metadata: {
52
+ category: string;
53
+ importance: number;
54
+ topic: string;
55
+ [key: string]: unknown;
56
+ };
57
+ timestamp: number;
58
+ version: string;
59
+ encrypted?: boolean;
60
+ encryptedContent?: string;
61
+ }
41
62
  export interface QuiltUploadOptions {
42
63
  signer: UnifiedSigner;
43
64
  epochs?: number;
@@ -65,6 +86,15 @@ export interface QuiltRetrieveResult {
65
86
  tags: Record<string, string>;
66
87
  retrievalTimeMs: number;
67
88
  }
89
+ /**
90
+ * Result when retrieving a memory package from Quilt
91
+ */
92
+ export interface QuiltMemoryRetrieveResult {
93
+ identifier: string;
94
+ memoryPackage: QuiltMemoryPackage;
95
+ tags: Record<string, string>;
96
+ retrievalTimeMs: number;
97
+ }
68
98
  export interface QuiltListResult {
69
99
  identifier: string;
70
100
  quiltPatchId: string;
@@ -195,6 +225,69 @@ export declare class QuiltBatchManager {
195
225
  * @returns Array of matching WalrusFile objects
196
226
  */
197
227
  getFilesByImportance(quiltId: string, minImportance: number): Promise<Array<WalrusFile>>;
228
+ /**
229
+ * Retrieve a memory package as JSON from a Quilt
230
+ *
231
+ * Uses file.json() for efficient parsing (SDK handles it)
232
+ *
233
+ * @param quiltId - The Quilt blob ID
234
+ * @param identifier - The file identifier within the quilt
235
+ * @returns QuiltMemoryRetrieveResult with parsed memory package
236
+ */
237
+ getMemoryPackage(quiltId: string, identifier: string): Promise<QuiltMemoryRetrieveResult>;
238
+ /**
239
+ * Retrieve all memory packages from a Quilt as JSON
240
+ *
241
+ * @param quiltId - The Quilt blob ID
242
+ * @returns Array of memory packages with metadata
243
+ */
244
+ getAllMemoryPackages(quiltId: string): Promise<QuiltMemoryRetrieveResult[]>;
245
+ /**
246
+ * Find a specific memory in a Quilt using multiple matching strategies
247
+ *
248
+ * Strategies (in order of priority):
249
+ * 1. Match by tags['memory_id'] === memoryId
250
+ * 2. Match by identifier === `memory-${memoryId}.json`
251
+ * 3. Match by JSON metadata.memoryId === memoryId
252
+ * 4. Fallback to index-based matching (if fileIndex provided)
253
+ *
254
+ * @param quiltId - The Quilt blob ID
255
+ * @param memoryId - The memory ID (usually vectorId) to find
256
+ * @param fileIndex - Optional fallback index if other strategies fail
257
+ * @returns The matching memory package result, or null if not found
258
+ */
259
+ findMemoryInQuilt(quiltId: string, memoryId: string, fileIndex?: number): Promise<QuiltMemoryRetrieveResult | null>;
260
+ /**
261
+ * Get memory content from a Quilt file
262
+ *
263
+ * Handles both encrypted and unencrypted content:
264
+ * - Unencrypted: Returns content directly from package
265
+ * - Encrypted: Returns decrypted content if sessionKey provided, otherwise throws
266
+ *
267
+ * @param quiltId - The Quilt blob ID
268
+ * @param identifier - The file identifier
269
+ * @param sessionKey - Optional session key for encrypted content
270
+ * @returns Memory content as string
271
+ */
272
+ getMemoryContent(quiltId: string, identifier: string, decryptFn?: (encryptedBase64: string) => Promise<string>): Promise<string>;
273
+ /**
274
+ * Try to recover a partially truncated memory package
275
+ *
276
+ * Handles cases where JSON was truncated (e.g., in the middle of encryptedContent)
277
+ * by extracting metadata and marking the encrypted content as corrupted.
278
+ *
279
+ * @param bytes - Raw bytes of the file
280
+ * @returns Recovered QuiltMemoryPackage or null if recovery fails
281
+ */
282
+ private tryRecoverTruncatedPackage;
283
+ /**
284
+ * Convert Uint8Array to base64 string
285
+ */
286
+ private uint8ArrayToBase64;
287
+ /**
288
+ * Convert base64 string to Uint8Array
289
+ */
290
+ private base64ToUint8Array;
198
291
  /**
199
292
  * Get statistics
200
293
  */
@@ -206,5 +299,12 @@ export declare class QuiltBatchManager {
206
299
  * Get Walrus client
207
300
  */
208
301
  getWalrusClient(useRelay?: boolean): WalrusClient;
302
+ /**
303
+ * Get base64 converter (for external use)
304
+ */
305
+ getBase64Utils(): {
306
+ encode: (bytes: Uint8Array) => string;
307
+ decode: (base64: string) => Uint8Array;
308
+ };
209
309
  }
210
310
  //# sourceMappingURL=QuiltBatchManager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"QuiltBatchManager.d.ts","sourceRoot":"","sources":["../../../src/services/storage/QuiltBatchManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAMxE,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,gBAAgB,EAAE,UAAU,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,UAAU,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAMD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,eAAe;IACvB,OAAO,CAAC,kBAAkB;IAC1B,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,MAAM;gBAJN,eAAe,EAAE,YAAY,EAC7B,kBAAkB,EAAE,YAAY,EAChC,SAAS,EAAE,oBAAoB,CAAC;QAAE,OAAO,EAAE,SAAS,CAAC;QAAC,MAAM,EAAE,YAAY,CAAA;KAAE,CAAC,EAC7E,cAAc,EAAE,OAAO,EACvB,MAAM,EAAE,MAAM;IAOxB;;;;;;;;;;;;;;;;;OAiBG;IACG,iBAAiB,CACrB,QAAQ,EAAE,WAAW,EAAE,EACvB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,iBAAiB,CAAC;IA+I7B;;;;;;;;;;;;OAYG;IACG,gBAAgB,CACpB,KAAK,EAAE,KAAK,CAAC;QACX,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,UAAU,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAC/B,CAAC,EACF,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,iBAAiB,CAAC;IAqH7B;;;;;;;;OAQG;IACG,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAkBhE;;;;;;;;OAQG;IACG,mBAAmB,CACvB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,mBAAmB,CAAC;IA2C/B;;;;;;;OAOG;IACG,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAmCnE;;;;;;OAMG;IACG,mBAAmB,CACvB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACxC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAmC7B;;;;;;OAMG;IACG,kBAAkB,CACtB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAI7B;;;;;;OAMG;IACG,oBAAoB,CACxB,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAoB7B;;OAEG;IACH,QAAQ;;;;IAOR;;OAEG;IACH,eAAe,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,YAAY;CAKlD"}
1
+ {"version":3,"file":"QuiltBatchManager.d.ts","sourceRoot":"","sources":["../../../src/services/storage/QuiltBatchManager.ts"],"names":[],"mappings":"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"}
@@ -87,30 +87,64 @@ export class QuiltBatchManager {
87
87
  let totalSize = 0;
88
88
  console.log(`📦 Uploading batch of ${memories.length} memories as Quilt (writeFilesFlow)...`);
89
89
  try {
90
- // Create WalrusFile for each memory with plaintext tags
90
+ // Create WalrusFile for each memory as JSON package
91
+ // This format is consistent with regular memory storage
91
92
  const files = memories.map((memory, index) => {
92
93
  const identifier = memory.id
93
94
  ? `memory-${memory.id}.json`
94
95
  : `memory-${Date.now()}-${index}-${Math.random().toString(36).slice(2, 9)}.json`;
95
- totalSize += memory.encryptedContent.length;
96
+ const isEncrypted = !!memory.encryptedContent && memory.encryptedContent.length > 0;
97
+ const timestamp = Date.now();
98
+ // Create memory package (JSON format - consistent with regular storage)
99
+ const memoryPackage = {
100
+ // Content: plaintext if not encrypted, empty if encrypted
101
+ content: isEncrypted ? '' : memory.content,
102
+ embedding: memory.embedding,
103
+ metadata: {
104
+ category: memory.category,
105
+ importance: memory.importance,
106
+ topic: memory.topic,
107
+ ...(memory.summary ? { summary: memory.summary } : {}),
108
+ ...(memory.id ? { memoryId: memory.id } : {})
109
+ },
110
+ timestamp,
111
+ version: '2.0.0', // Quilt JSON package version
112
+ encrypted: isEncrypted,
113
+ // Store encrypted content as base64 for JSON compatibility
114
+ ...(isEncrypted && memory.encryptedContent ? {
115
+ encryptedContent: this.uint8ArrayToBase64(memory.encryptedContent)
116
+ } : {})
117
+ };
118
+ // Serialize to JSON and encode as bytes
119
+ const jsonString = JSON.stringify(memoryPackage);
120
+ const contents = new TextEncoder().encode(jsonString);
121
+ totalSize += contents.length;
122
+ // Diagnostic logging for debugging Quilt corruption issues
123
+ console.log(` 📝 File ${index}: identifier=${identifier}`);
124
+ console.log(` JSON string length: ${jsonString.length} chars`);
125
+ console.log(` Encoded bytes: ${contents.length} bytes`);
126
+ console.log(` Last 50 chars of JSON: ...${jsonString.slice(-50)}`);
127
+ console.log(` Last 10 bytes (hex): ${Array.from(contents.slice(-10)).map(b => b.toString(16).padStart(2, '0')).join(' ')}`);
96
128
  return WalrusFile.from({
97
- contents: memory.encryptedContent,
129
+ contents,
98
130
  identifier,
99
131
  tags: {
100
- // Core metadata (plaintext for filtering)
132
+ // Core metadata (plaintext for filtering without decryption)
133
+ 'content-type': 'application/json',
101
134
  'category': memory.category,
102
135
  'importance': memory.importance.toString(),
103
136
  'topic': memory.topic,
104
- 'timestamp': new Date().toISOString(),
105
- 'created_at': new Date().toISOString(),
137
+ 'timestamp': new Date(timestamp).toISOString(),
138
+ 'created_at': new Date(timestamp).toISOString(),
106
139
  // Encryption info
107
- 'encrypted': 'true',
108
- 'encryption_type': 'seal',
140
+ 'encrypted': isEncrypted ? 'true' : 'false',
141
+ ...(isEncrypted ? { 'encryption_type': 'seal' } : {}),
109
142
  // Owner
110
143
  'owner': options.userAddress,
111
144
  // Content info
112
- 'content_size': memory.encryptedContent.length.toString(),
145
+ 'content_size': contents.length.toString(),
113
146
  'embedding_dimensions': memory.embedding.length.toString(),
147
+ 'package_version': '2.0.0',
114
148
  // Optional rich metadata
115
149
  ...(memory.summary ? { 'summary': memory.summary } : {}),
116
150
  ...(memory.id ? { 'memory_id': memory.id } : {})
@@ -179,7 +213,7 @@ export class QuiltBatchManager {
179
213
  blobId: quiltId,
180
214
  quiltPatchId,
181
215
  tags: Object.fromEntries(Object.entries(tags).map(([k, v]) => [k, String(v)])),
182
- size: memories[i]?.encryptedContent.length || 0
216
+ size: memories[i]?.encryptedContent?.length || memories[i]?.content?.length || 0
183
217
  };
184
218
  }));
185
219
  return {
@@ -314,10 +348,20 @@ export class QuiltBatchManager {
314
348
  async getQuiltFiles(quiltId) {
315
349
  try {
316
350
  console.log(`📂 Retrieving files from Quilt ${quiltId}...`);
317
- // Use getBlob().files() to correctly parse Quilt and get individual files
318
- const blob = await this.suiClient.walrus.getBlob({ blobId: quiltId });
319
- const files = await blob.files();
320
- console.log(`✅ Retrieved ${files.length} files from Quilt`);
351
+ // Try to parse as Quilt first (getBlob().files() returns ALL files in Quilt)
352
+ // Fall back to getFiles() for regular blobs
353
+ let files;
354
+ try {
355
+ const blob = await this.suiClient.walrus.getBlob({ blobId: quiltId });
356
+ files = await blob.files();
357
+ console.log(`✅ Retrieved ${files.length} files from Quilt`);
358
+ }
359
+ catch (quiltError) {
360
+ // Not a Quilt - try as regular blob
361
+ console.log(`📄 Not a Quilt format, fetching as regular blob...`);
362
+ files = await this.suiClient.walrus.getFiles({ ids: [quiltId] });
363
+ console.log(`✅ Retrieved ${files.length} file(s) as regular blob`);
364
+ }
321
365
  return files;
322
366
  }
323
367
  catch (error) {
@@ -338,9 +382,8 @@ export class QuiltBatchManager {
338
382
  const startTime = performance.now();
339
383
  try {
340
384
  console.log(`📄 Retrieving file "${identifier}" from Quilt ${quiltId}...`);
341
- // Get all files from quilt using getBlob().files()
342
- const blob = await this.suiClient.walrus.getBlob({ blobId: quiltId });
343
- const files = await blob.files();
385
+ // Get all files from the blob (Quilt or regular)
386
+ const files = await this.getQuiltFiles(quiltId);
344
387
  // Find file by identifier
345
388
  let matchingFile;
346
389
  for (const f of files) {
@@ -380,9 +423,8 @@ export class QuiltBatchManager {
380
423
  async listQuiltPatches(quiltId) {
381
424
  try {
382
425
  console.log(`📋 Listing patches in Quilt ${quiltId}...`);
383
- // Use getBlob().files() to correctly parse Quilt
384
- const blob = await this.suiClient.walrus.getBlob({ blobId: quiltId });
385
- const files = await blob.files();
426
+ // Get all files from the blob (Quilt or regular)
427
+ const files = await this.getQuiltFiles(quiltId);
386
428
  const results = await Promise.all(files.map(async (file) => {
387
429
  const identifier = await file.getIdentifier() || 'unknown';
388
430
  const tags = await file.getTags();
@@ -467,8 +509,347 @@ export class QuiltBatchManager {
467
509
  return matchingFiles;
468
510
  }
469
511
  // ==========================================================================
512
+ // JSON Memory Package Retrieval
513
+ // ==========================================================================
514
+ /**
515
+ * Retrieve a memory package as JSON from a Quilt
516
+ *
517
+ * Uses file.json() for efficient parsing (SDK handles it)
518
+ *
519
+ * @param quiltId - The Quilt blob ID
520
+ * @param identifier - The file identifier within the quilt
521
+ * @returns QuiltMemoryRetrieveResult with parsed memory package
522
+ */
523
+ async getMemoryPackage(quiltId, identifier) {
524
+ const startTime = performance.now();
525
+ try {
526
+ console.log(`📄 Retrieving memory package "${identifier}" from Quilt ${quiltId}...`);
527
+ // Get all files from the blob
528
+ const files = await this.getQuiltFiles(quiltId);
529
+ // Find file by identifier
530
+ let matchingFile;
531
+ for (const f of files) {
532
+ const fileIdentifier = await f.getIdentifier();
533
+ if (fileIdentifier === identifier) {
534
+ matchingFile = f;
535
+ break;
536
+ }
537
+ }
538
+ if (!matchingFile) {
539
+ throw new Error(`File "${identifier}" not found in Quilt`);
540
+ }
541
+ const tags = await matchingFile.getTags();
542
+ let memoryPackage;
543
+ try {
544
+ // Parse directly as JSON (SDK handles it!)
545
+ memoryPackage = await matchingFile.json();
546
+ }
547
+ catch (parseError) {
548
+ // Try partial recovery for truncated JSON
549
+ console.warn(`⚠️ JSON parse failed for "${identifier}", attempting recovery...`);
550
+ const bytes = await matchingFile.bytes();
551
+ const recovered = this.tryRecoverTruncatedPackage(bytes);
552
+ if (recovered) {
553
+ console.log(`🔧 Partially recovered "${identifier}" (encryptedContent may be corrupted)`);
554
+ memoryPackage = recovered;
555
+ }
556
+ else {
557
+ throw parseError;
558
+ }
559
+ }
560
+ const retrievalTimeMs = performance.now() - startTime;
561
+ console.log(`✅ Retrieved memory package "${identifier}" (${retrievalTimeMs.toFixed(1)}ms)`);
562
+ return {
563
+ identifier,
564
+ memoryPackage,
565
+ tags,
566
+ retrievalTimeMs
567
+ };
568
+ }
569
+ catch (error) {
570
+ console.error(`❌ Failed to retrieve memory package:`, error);
571
+ throw new Error(`Failed to retrieve memory package "${identifier}": ${error}`);
572
+ }
573
+ }
574
+ /**
575
+ * Retrieve all memory packages from a Quilt as JSON
576
+ *
577
+ * @param quiltId - The Quilt blob ID
578
+ * @returns Array of memory packages with metadata
579
+ */
580
+ async getAllMemoryPackages(quiltId) {
581
+ const startTime = performance.now();
582
+ try {
583
+ console.log(`📂 Retrieving all memory packages from Quilt ${quiltId}...`);
584
+ const files = await this.getQuiltFiles(quiltId);
585
+ const results = [];
586
+ for (const file of files) {
587
+ const identifier = await file.getIdentifier() || 'unknown';
588
+ const tags = await file.getTags();
589
+ try {
590
+ // Parse as JSON
591
+ const memoryPackage = await file.json();
592
+ results.push({
593
+ identifier,
594
+ memoryPackage,
595
+ tags,
596
+ retrievalTimeMs: 0 // Individual timing not tracked in batch
597
+ });
598
+ }
599
+ catch (parseError) {
600
+ console.warn(`⚠️ Failed to parse "${identifier}" as JSON:`, parseError);
601
+ // Try partial recovery for truncated JSON
602
+ try {
603
+ const bytes = await file.bytes();
604
+ const recoveredPackage = this.tryRecoverTruncatedPackage(bytes);
605
+ if (recoveredPackage) {
606
+ console.log(`🔧 Partially recovered "${identifier}" (encryptedContent truncated)`);
607
+ results.push({
608
+ identifier,
609
+ memoryPackage: recoveredPackage,
610
+ tags,
611
+ retrievalTimeMs: 0
612
+ });
613
+ }
614
+ }
615
+ catch {
616
+ // Skip files that can't be recovered
617
+ console.warn(`❌ Could not recover "${identifier}"`);
618
+ }
619
+ }
620
+ }
621
+ const totalTimeMs = performance.now() - startTime;
622
+ console.log(`✅ Retrieved ${results.length} memory packages (${totalTimeMs.toFixed(1)}ms)`);
623
+ return results;
624
+ }
625
+ catch (error) {
626
+ console.error(`❌ Failed to retrieve memory packages:`, error);
627
+ throw new Error(`Failed to retrieve memory packages from Quilt ${quiltId}: ${error}`);
628
+ }
629
+ }
630
+ /**
631
+ * Find a specific memory in a Quilt using multiple matching strategies
632
+ *
633
+ * Strategies (in order of priority):
634
+ * 1. Match by tags['memory_id'] === memoryId
635
+ * 2. Match by identifier === `memory-${memoryId}.json`
636
+ * 3. Match by JSON metadata.memoryId === memoryId
637
+ * 4. Fallback to index-based matching (if fileIndex provided)
638
+ *
639
+ * @param quiltId - The Quilt blob ID
640
+ * @param memoryId - The memory ID (usually vectorId) to find
641
+ * @param fileIndex - Optional fallback index if other strategies fail
642
+ * @returns The matching memory package result, or null if not found
643
+ */
644
+ async findMemoryInQuilt(quiltId, memoryId, fileIndex) {
645
+ const startTime = performance.now();
646
+ try {
647
+ console.log(`🔍 Finding memory "${memoryId}" in Quilt ${quiltId.substring(0, 20)}...`);
648
+ const files = await this.getQuiltFiles(quiltId);
649
+ let matchedFile;
650
+ let matchStrategy = '';
651
+ // Strategy 1: Match by tags['memory_id']
652
+ for (const f of files) {
653
+ const tags = await f.getTags();
654
+ if (tags?.['memory_id'] === memoryId) {
655
+ matchedFile = f;
656
+ matchStrategy = 'memory_id tag';
657
+ break;
658
+ }
659
+ }
660
+ // Strategy 2: Match by identifier pattern "memory-{memoryId}.json"
661
+ if (!matchedFile) {
662
+ for (const f of files) {
663
+ const identifier = await f.getIdentifier();
664
+ if (identifier === `memory-${memoryId}.json`) {
665
+ matchedFile = f;
666
+ matchStrategy = 'identifier pattern';
667
+ break;
668
+ }
669
+ }
670
+ }
671
+ // Strategy 3: Parse JSON to find matching metadata.memoryId
672
+ if (!matchedFile) {
673
+ for (const f of files) {
674
+ try {
675
+ const json = await f.json();
676
+ if (json?.metadata?.memoryId === memoryId) {
677
+ matchedFile = f;
678
+ matchStrategy = 'JSON metadata.memoryId';
679
+ break;
680
+ }
681
+ }
682
+ catch {
683
+ // Not valid JSON, continue
684
+ }
685
+ }
686
+ }
687
+ // Strategy 4: Fallback to index-based matching
688
+ if (!matchedFile && fileIndex !== undefined && fileIndex < files.length) {
689
+ matchedFile = files[fileIndex];
690
+ matchStrategy = `index fallback (${fileIndex})`;
691
+ }
692
+ if (!matchedFile) {
693
+ console.log(`❌ Memory "${memoryId}" not found in Quilt (${files.length} files)`);
694
+ return null;
695
+ }
696
+ const identifier = await matchedFile.getIdentifier() || 'unknown';
697
+ const tags = await matchedFile.getTags();
698
+ let memoryPackage;
699
+ try {
700
+ memoryPackage = await matchedFile.json();
701
+ }
702
+ catch (parseError) {
703
+ // Try recovery for truncated JSON
704
+ const bytes = await matchedFile.bytes();
705
+ const recovered = this.tryRecoverTruncatedPackage(bytes);
706
+ if (recovered) {
707
+ memoryPackage = recovered;
708
+ }
709
+ else {
710
+ throw parseError;
711
+ }
712
+ }
713
+ const retrievalTimeMs = performance.now() - startTime;
714
+ console.log(`✅ Found memory "${memoryId}" via ${matchStrategy} (${identifier}) in ${retrievalTimeMs.toFixed(1)}ms`);
715
+ return {
716
+ identifier,
717
+ memoryPackage,
718
+ tags,
719
+ retrievalTimeMs
720
+ };
721
+ }
722
+ catch (error) {
723
+ console.error(`❌ Failed to find memory in Quilt:`, error);
724
+ throw new Error(`Failed to find memory "${memoryId}" in Quilt ${quiltId}: ${error}`);
725
+ }
726
+ }
727
+ /**
728
+ * Get memory content from a Quilt file
729
+ *
730
+ * Handles both encrypted and unencrypted content:
731
+ * - Unencrypted: Returns content directly from package
732
+ * - Encrypted: Returns decrypted content if sessionKey provided, otherwise throws
733
+ *
734
+ * @param quiltId - The Quilt blob ID
735
+ * @param identifier - The file identifier
736
+ * @param sessionKey - Optional session key for encrypted content
737
+ * @returns Memory content as string
738
+ */
739
+ async getMemoryContent(quiltId, identifier, decryptFn) {
740
+ const result = await this.getMemoryPackage(quiltId, identifier);
741
+ const pkg = result.memoryPackage;
742
+ if (!pkg.encrypted) {
743
+ // Not encrypted - return content directly
744
+ return pkg.content;
745
+ }
746
+ if (!pkg.encryptedContent) {
747
+ throw new Error('Memory is marked as encrypted but no encrypted content found');
748
+ }
749
+ if (!decryptFn) {
750
+ throw new Error('Memory is encrypted. Provide decryptFn to decrypt content.');
751
+ }
752
+ // Decrypt using provided function
753
+ return await decryptFn(pkg.encryptedContent);
754
+ }
755
+ // ==========================================================================
470
756
  // Utility Methods
471
757
  // ==========================================================================
758
+ /**
759
+ * Try to recover a partially truncated memory package
760
+ *
761
+ * Handles cases where JSON was truncated (e.g., in the middle of encryptedContent)
762
+ * by extracting metadata and marking the encrypted content as corrupted.
763
+ *
764
+ * @param bytes - Raw bytes of the file
765
+ * @returns Recovered QuiltMemoryPackage or null if recovery fails
766
+ */
767
+ tryRecoverTruncatedPackage(bytes) {
768
+ try {
769
+ const rawString = new TextDecoder().decode(bytes);
770
+ // Find and trim trailing null bytes
771
+ let lastValidIndex = rawString.length - 1;
772
+ while (lastValidIndex >= 0 && rawString.charCodeAt(lastValidIndex) === 0) {
773
+ lastValidIndex--;
774
+ }
775
+ const trimmedString = rawString.slice(0, lastValidIndex + 1);
776
+ // First try to parse as-is (maybe nulls were the only issue)
777
+ try {
778
+ return JSON.parse(trimmedString);
779
+ }
780
+ catch {
781
+ // Continue to partial recovery
782
+ }
783
+ // Look for encryptedContent field - data likely truncated there
784
+ const encryptedIdx = trimmedString.indexOf('"encryptedContent":"');
785
+ if (encryptedIdx > 0) {
786
+ // Extract everything before encryptedContent
787
+ const beforeEncrypted = trimmedString.slice(0, encryptedIdx);
788
+ // Remove trailing comma and close the object
789
+ const cleanedJson = beforeEncrypted.replace(/,\s*$/, '') + '}';
790
+ try {
791
+ const partialPackage = JSON.parse(cleanedJson);
792
+ return {
793
+ ...partialPackage,
794
+ encrypted: true,
795
+ encryptedContent: '[CORRUPTED - data truncated during storage]'
796
+ };
797
+ }
798
+ catch {
799
+ // Partial extraction failed
800
+ }
801
+ }
802
+ // Try to find the last complete JSON object by looking for closing brace
803
+ // This handles cases where truncation happened elsewhere
804
+ for (let i = trimmedString.length - 1; i >= 0; i--) {
805
+ if (trimmedString[i] === '}') {
806
+ try {
807
+ const candidate = trimmedString.slice(0, i + 1);
808
+ return JSON.parse(candidate);
809
+ }
810
+ catch {
811
+ // This position doesn't form valid JSON, try earlier
812
+ continue;
813
+ }
814
+ }
815
+ }
816
+ return null;
817
+ }
818
+ catch {
819
+ return null;
820
+ }
821
+ }
822
+ /**
823
+ * Convert Uint8Array to base64 string
824
+ */
825
+ uint8ArrayToBase64(bytes) {
826
+ // Use Buffer in Node.js, btoa in browser
827
+ if (typeof Buffer !== 'undefined') {
828
+ return Buffer.from(bytes).toString('base64');
829
+ }
830
+ // Browser fallback
831
+ let binary = '';
832
+ for (let i = 0; i < bytes.length; i++) {
833
+ binary += String.fromCharCode(bytes[i]);
834
+ }
835
+ return btoa(binary);
836
+ }
837
+ /**
838
+ * Convert base64 string to Uint8Array
839
+ */
840
+ base64ToUint8Array(base64) {
841
+ // Use Buffer in Node.js, atob in browser
842
+ if (typeof Buffer !== 'undefined') {
843
+ return new Uint8Array(Buffer.from(base64, 'base64'));
844
+ }
845
+ // Browser fallback
846
+ const binary = atob(base64);
847
+ const bytes = new Uint8Array(binary.length);
848
+ for (let i = 0; i < binary.length; i++) {
849
+ bytes[i] = binary.charCodeAt(i);
850
+ }
851
+ return bytes;
852
+ }
472
853
  /**
473
854
  * Get statistics
474
855
  */
@@ -486,5 +867,14 @@ export class QuiltBatchManager {
486
867
  ? this.walrusWithRelay
487
868
  : this.walrusWithoutRelay;
488
869
  }
870
+ /**
871
+ * Get base64 converter (for external use)
872
+ */
873
+ getBase64Utils() {
874
+ return {
875
+ encode: this.uint8ArrayToBase64.bind(this),
876
+ decode: this.base64ToUint8Array.bind(this)
877
+ };
878
+ }
489
879
  }
490
880
  //# sourceMappingURL=QuiltBatchManager.js.map