@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,1222 +1,1289 @@
1
- /**
2
- * Simple PDW Client - Easy-to-use API for Personal Data Wallet
3
- *
4
- * Provides a simple function-based API without React dependencies.
5
- * Works in Node.js, browsers, serverless functions, and CLI tools.
6
- *
7
- * @example
8
- * ```typescript
9
- * import { createPDWClient } from 'personal-data-wallet-sdk';
10
- * import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
11
- *
12
- * const keypair = Ed25519Keypair.fromSecretKey(process.env.PRIVATE_KEY);
13
- * const pdw = await createPDWClient({
14
- * signer: keypair,
15
- * userAddress: keypair.getPublicKey().toSuiAddress(),
16
- * network: 'testnet',
17
- * geminiApiKey: process.env.GEMINI_API_KEY
18
- * });
19
- *
20
- * // Simple API - no hooks needed!
21
- * await pdw.memory.create('I love TypeScript');
22
- * const results = await pdw.search.vector('programming');
23
- * const answer = await pdw.chat.send(sessionId, 'What do I like?');
24
- * ```
25
- *
26
- * @module client/SimplePDWClient
27
- */
28
-
29
- import { SuiClient, getFullnodeUrl } from '@mysten/sui/client';
30
- import type { Keypair } from '@mysten/sui/cryptography';
31
- import type { UnifiedSigner, WalletAdapter } from './signers';
32
- import { KeypairSigner, WalletAdapterSigner } from './signers';
33
- import { StorageService } from '../services/StorageService';
34
- import { EmbeddingService } from '../services/EmbeddingService';
35
- import { MemoryService } from '../services/MemoryService';
36
- import { QueryService } from '../services/QueryService';
37
- import { ClassifierService } from '../services/ClassifierService';
38
- import { VectorService } from '../services/VectorService';
39
- import { BatchService } from '../services/BatchService';
40
- import { MemoryAnalyticsService } from '../retrieval/MemoryAnalyticsService';
41
- import { EncryptionService } from '../services/EncryptionService';
42
- import { PermissionService } from '../access/PermissionService';
43
- import { TransactionService } from '../services/TransactionService';
44
- import { PipelineManager } from '../pipeline/PipelineManager';
45
- import { MemoryNamespace } from './namespaces/MemoryNamespace';
46
- import { SearchNamespace } from './namespaces/SearchNamespace';
47
- import { ClassifyNamespace } from './namespaces/ClassifyNamespace';
48
- import { GraphNamespace } from './namespaces/GraphNamespace';
49
- import { EmbeddingsNamespace } from './namespaces/EmbeddingsNamespace';
50
- import { BatchNamespace } from './namespaces/BatchNamespace';
51
- import { CacheNamespace } from './namespaces/CacheNamespace';
52
- import { IndexNamespace } from './namespaces/IndexNamespace';
53
- import { AnalyticsNamespace } from './namespaces/AnalyticsNamespace';
54
- import { EncryptionNamespace } from './namespaces/EncryptionNamespace';
55
- import { PermissionsNamespace } from './namespaces/PermissionsNamespace';
56
- import { TxNamespace } from './namespaces/TxNamespace';
57
- import { PipelineNamespace } from './namespaces/PipelineNamespace';
58
- import { CapabilityNamespace } from './namespaces/CapabilityNamespace';
59
- import { ContextNamespace } from './namespaces/ContextNamespace';
60
- import { WalletNamespace } from './namespaces/WalletNamespace';
61
- // Consolidated namespaces (new unified API)
62
- import { AINamespace } from './namespaces/consolidated/AINamespace';
63
- import { SecurityNamespace } from './namespaces/consolidated/SecurityNamespace';
64
- import { BlockchainNamespace } from './namespaces/consolidated/BlockchainNamespace';
65
- import { StorageNamespace as ConsolidatedStorageNamespace } from './namespaces/consolidated/StorageNamespace';
66
- import type { PDWConfig, ClientWithCoreApi } from '../types';
67
- import { ClientMemoryManager } from './ClientMemoryManager';
68
- import { ViewService } from '../services/ViewService';
69
- import { CapabilityService } from '../services/CapabilityService';
70
- import { MemoryIndexService } from '../services/MemoryIndexService';
71
- import { IndexManager, type IndexManagerOptions, type IndexProgressCallback } from '../services/IndexManager';
72
- // Note: createHnswService is dynamically imported only when enableLocalIndexing is true
73
- // This prevents bundling Node.js dependencies (hnswlib-node) in browser builds
74
- import type { IHnswService } from '../vector/IHnswService';
75
-
76
- /**
77
- * Configuration for Simple PDW Client
78
- */
79
- export interface SimplePDWConfig {
80
- /**
81
- * Signer: Either Keypair (Node.js) or WalletAdapter (browser)
82
- */
83
- signer: Keypair | WalletAdapter | UnifiedSigner;
84
-
85
- /**
86
- * User's Sui address
87
- * If not provided, will be derived from signer
88
- */
89
- userAddress?: string;
90
-
91
- /**
92
- * Network to use (auto-configures endpoints)
93
- * @default 'testnet'
94
- */
95
- network?: 'testnet' | 'mainnet' | 'devnet';
96
-
97
- /**
98
- * Gemini API key for AI features (embeddings, chat, classification)
99
- * @deprecated Use `embedding.apiKey` instead for more flexibility
100
- */
101
- geminiApiKey?: string;
102
-
103
- /**
104
- * Optional: Embedding configuration
105
- * Allows customizing the embedding provider, model, and dimensions
106
- */
107
- embedding?: {
108
- /**
109
- * Embedding provider
110
- * - google: Direct Google AI API
111
- * - openai: Direct OpenAI API
112
- * - openrouter: OpenRouter API gateway (recommended - supports multiple models)
113
- * - cohere: Direct Cohere API
114
- * @default 'google'
115
- */
116
- provider?: 'google' | 'openai' | 'openrouter' | 'cohere';
117
- /**
118
- * API key for the embedding provider
119
- * Falls back to geminiApiKey for backward compatibility
120
- */
121
- apiKey?: string;
122
- /**
123
- * Model name to use
124
- * - Google: 'text-embedding-004', 'gemini-embedding-001'
125
- * - OpenAI: 'text-embedding-3-small', 'text-embedding-3-large'
126
- * - OpenRouter: 'google/gemini-embedding-001', 'openai/text-embedding-3-small', etc.
127
- * - Cohere: 'embed-english-v3.0', 'embed-multilingual-v3.0'
128
- * @default 'text-embedding-004' (for google), 'google/gemini-embedding-001' (for openrouter)
129
- */
130
- modelName?: string;
131
- /**
132
- * Embedding dimensions
133
- * @default 768 (for google/openrouter), 1536 (for openai)
134
- */
135
- dimensions?: number;
136
- };
137
-
138
- /**
139
- * Optional: Detailed Walrus configuration
140
- */
141
- walrus?: {
142
- aggregator?: string;
143
- publisher?: string;
144
- network?: 'testnet' | 'mainnet';
145
- };
146
-
147
- /**
148
- * Optional: Detailed Sui configuration
149
- */
150
- sui?: {
151
- network?: 'testnet' | 'mainnet' | 'devnet';
152
- packageId?: string;
153
- rpcUrl?: string;
154
- };
155
-
156
- /**
157
- * Optional: AI model configuration for chat and analysis
158
- */
159
- ai?: {
160
- /**
161
- * Chat/analysis model to use
162
- * Can be OpenRouter format (e.g., 'google/gemini-2.5-flash') or direct provider format
163
- * @default process.env.AI_CHAT_MODEL || 'google/gemini-2.5-flash'
164
- */
165
- chatModel?: string;
166
- /**
167
- * API key for chat model (if different from embedding)
168
- * For OpenRouter, use OPENROUTER_API_KEY
169
- */
170
- apiKey?: string;
171
- };
172
-
173
- /**
174
- * Optional: Feature flags
175
- */
176
- features?: {
177
- enableEncryption?: boolean;
178
- enableLocalIndexing?: boolean;
179
- enableKnowledgeGraph?: boolean;
180
- };
181
-
182
- /**
183
- * Optional: Index manager options for hybrid restore
184
- */
185
- indexManager?: {
186
- /** Auto-save interval in ms (default: 5 minutes) */
187
- autoSaveInterval?: number;
188
- /** Enable auto-save (default: true) */
189
- enableAutoSave?: boolean;
190
- /** Progress callback for index operations */
191
- onProgress?: IndexProgressCallback;
192
- };
193
-
194
- /**
195
- * Optional: Index backup to Walrus cloud storage
196
- * Enables syncing local HNSW index to Walrus for cross-device restoration
197
- */
198
- indexBackup?: {
199
- /** Enable Walrus backup for local index */
200
- enabled: boolean;
201
- /** Walrus aggregator URL for downloading */
202
- aggregatorUrl?: string;
203
- /** Walrus publisher URL for uploading */
204
- publisherUrl?: string;
205
- /** Auto-sync index to Walrus on every save (default: false) */
206
- autoSync?: boolean;
207
- /** Storage duration in epochs (default: 3) */
208
- epochs?: number;
209
- };
210
- }
211
-
212
- /**
213
- * Default package IDs by network
214
- */
215
- const DEFAULT_PACKAGE_IDS: Record<string, string> = {
216
- testnet: process.env.NEXT_PUBLIC_PACKAGE_ID || process.env.PACKAGE_ID || '0xf63a61b8d056ffb2e0efdd057445e15c9c64a1c6f2d13516812d7031b7e7dc9e',
217
- mainnet: '', // TODO: Add mainnet package ID when deployed
218
- devnet: ''
219
- };
220
-
221
- /**
222
- * Resolved configuration after applying defaults
223
- */
224
- interface ResolvedConfig {
225
- signer: UnifiedSigner;
226
- userAddress: string;
227
- walrus: {
228
- aggregator: string;
229
- publisher: string;
230
- network: 'testnet' | 'mainnet';
231
- };
232
- sui: {
233
- network: 'testnet' | 'mainnet' | 'devnet';
234
- packageId: string;
235
- rpcUrl: string;
236
- client: SuiClient;
237
- };
238
- ai: {
239
- geminiApiKey?: string;
240
- chatModel: string;
241
- apiKey?: string;
242
- };
243
- embedding: {
244
- provider: 'google' | 'openai' | 'openrouter' | 'cohere';
245
- apiKey?: string;
246
- modelName: string;
247
- dimensions: number;
248
- };
249
- features: {
250
- enableEncryption: boolean;
251
- enableLocalIndexing: boolean;
252
- enableKnowledgeGraph: boolean;
253
- };
254
- indexManager?: {
255
- autoSaveInterval?: number;
256
- enableAutoSave?: boolean;
257
- onProgress?: IndexProgressCallback;
258
- };
259
- indexBackup?: {
260
- enabled: boolean;
261
- aggregatorUrl?: string;
262
- publisherUrl?: string;
263
- autoSync?: boolean;
264
- epochs?: number;
265
- };
266
- }
267
-
268
- /**
269
- * Service container for dependency injection
270
- */
271
- export interface ServiceContainer {
272
- config: ResolvedConfig;
273
- storage: StorageService;
274
- embedding?: EmbeddingService;
275
- memory: MemoryService;
276
- query: QueryService;
277
- classifier?: ClassifierService;
278
- vector?: VectorService;
279
- memoryIndex?: MemoryIndexService; // For HNSW indexing with persistence
280
- batchService?: BatchService; // For batch operations and caching
281
- analytics?: MemoryAnalyticsService; // For memory insights
282
- encryption?: EncryptionService; // For SEAL encryption
283
- permissions?: PermissionService; // For access control
284
- tx?: TransactionService; // For transaction utilities
285
- pipeline?: PipelineManager; // For processing pipelines
286
- clientMemoryManager?: ClientMemoryManager; // For full create pipeline
287
- viewService?: ViewService; // For read operations
288
- capability?: CapabilityService; // For capability-based access control
289
- indexManager?: IndexManager; // For hybrid index persistence
290
- /** Shared HNSW service instance (singleton) */
291
- sharedHnswService?: IHnswService;
292
- }
293
-
294
- /**
295
- * Simple PDW Client
296
- *
297
- * Main client class providing easy-to-use API for all PDW operations
298
- */
299
- export class SimplePDWClient {
300
- private config: ResolvedConfig;
301
- private services: ServiceContainer;
302
- private initialized: boolean = false;
303
- private initPromise: Promise<void> | null = null;
304
- /** Shared HNSW service instance - created once and shared across all services */
305
- private sharedHnswService: IHnswService | null = null;
306
- private sharedHnswServicePromise: Promise<IHnswService> | null = null;
307
-
308
- constructor(config: SimplePDWConfig) {
309
- // Resolve configuration with defaults
310
- this.config = this.resolveConfig(config);
311
-
312
- // Initialize services
313
- this.services = this.initializeServices(this.config);
314
-
315
- // Start async initialization (WASM loading, etc.)
316
- this.initPromise = this.initialize();
317
- }
318
-
319
- /**
320
- * Resolve configuration with smart defaults
321
- */
322
- private resolveConfig(config: SimplePDWConfig): ResolvedConfig {
323
- const network = config.network || config.sui?.network || 'testnet';
324
-
325
- // Create unified signer
326
- let signer: UnifiedSigner;
327
- if ('signAndExecuteTransaction' in config.signer && 'signPersonalMessage' in config.signer && 'getAddress' in config.signer) {
328
- // Already a UnifiedSigner
329
- signer = config.signer as UnifiedSigner;
330
- } else if ('getPublicKey' in config.signer && 'signPersonalMessage' in config.signer) {
331
- // It's a Keypair
332
- const suiClient = new SuiClient({
333
- url: config.sui?.rpcUrl || getFullnodeUrl(network)
334
- });
335
- signer = new KeypairSigner(config.signer as Keypair, suiClient);
336
- } else {
337
- // It's a WalletAdapter
338
- signer = new WalletAdapterSigner(config.signer as WalletAdapter);
339
- }
340
-
341
- // Derive user address if not provided
342
- const userAddress = config.userAddress || signer.getAddress();
343
-
344
- // Create Sui client
345
- const suiClient = new SuiClient({
346
- url: config.sui?.rpcUrl || getFullnodeUrl(network)
347
- });
348
-
349
- // Resolve embedding configuration with defaults
350
- const embeddingProvider = config.embedding?.provider || 'google';
351
- const embeddingApiKey = config.embedding?.apiKey || config.geminiApiKey;
352
- const embeddingModelName = config.embedding?.modelName || this.getDefaultEmbeddingModel(embeddingProvider);
353
- const embeddingDimensions = config.embedding?.dimensions || this.getDefaultEmbeddingDimensions(embeddingProvider);
354
-
355
- return {
356
- signer,
357
- userAddress,
358
- walrus: {
359
- aggregator: config.walrus?.aggregator ||
360
- `https://aggregator.walrus-${network}.walrus.space`,
361
- publisher: config.walrus?.publisher ||
362
- `https://publisher.walrus-${network}.walrus.space`,
363
- network: (config.walrus?.network || network) as 'testnet' | 'mainnet'
364
- },
365
- sui: {
366
- network,
367
- packageId: config.sui?.packageId || DEFAULT_PACKAGE_IDS[network],
368
- rpcUrl: config.sui?.rpcUrl || getFullnodeUrl(network),
369
- client: suiClient
370
- },
371
- ai: {
372
- geminiApiKey: config.geminiApiKey,
373
- chatModel: config.ai?.chatModel || process.env.AI_CHAT_MODEL || 'google/gemini-2.5-flash',
374
- apiKey: config.ai?.apiKey || process.env.OPENROUTER_API_KEY || config.geminiApiKey
375
- },
376
- embedding: {
377
- provider: embeddingProvider,
378
- apiKey: embeddingApiKey,
379
- modelName: embeddingModelName,
380
- dimensions: embeddingDimensions
381
- },
382
- features: {
383
- enableEncryption: config.features?.enableEncryption ?? false,
384
- enableLocalIndexing: config.features?.enableLocalIndexing ?? true,
385
- enableKnowledgeGraph: config.features?.enableKnowledgeGraph ?? true
386
- },
387
- indexManager: config.indexManager,
388
- indexBackup: config.indexBackup
389
- };
390
- }
391
-
392
- /**
393
- * Get default embedding model for provider
394
- */
395
- private getDefaultEmbeddingModel(provider: string): string {
396
- switch (provider) {
397
- case 'google':
398
- return 'text-embedding-004';
399
- case 'openai':
400
- return 'text-embedding-3-small';
401
- case 'openrouter':
402
- return 'google/gemini-embedding-001';
403
- case 'cohere':
404
- return 'embed-english-v3.0';
405
- default:
406
- return 'text-embedding-004';
407
- }
408
- }
409
-
410
- /**
411
- * Get default embedding dimensions for provider
412
- */
413
- private getDefaultEmbeddingDimensions(provider: string): number {
414
- switch (provider) {
415
- case 'google':
416
- return 3072;
417
- case 'openai':
418
- return 1536;
419
- case 'openrouter':
420
- return 3072; // google/gemini-embedding-001 returns 3072 dimensions
421
- case 'cohere':
422
- return 1024;
423
- default:
424
- return 3072;
425
- }
426
- }
427
-
428
- /**
429
- * Create ClientWithCoreApi adapter from SuiClient
430
- */
431
- private createClientAdapter(suiClient: SuiClient): ClientWithCoreApi {
432
- return {
433
- // Expose the underlying SuiClient for services that need it (e.g., ViewService)
434
- client: suiClient,
435
- core: {
436
- getObject: (objectId: string) => suiClient.getObject({ id: objectId, options: { showContent: true } }),
437
- getObjects: (objectIds: string[]) => Promise.all(objectIds.map(id => suiClient.getObject({ id, options: { showContent: true } }))),
438
- executeTransaction: (tx: any) => suiClient.signAndExecuteTransaction(tx)
439
- },
440
- $extend: <T>(extension: T) => ({ ...suiClient, ...extension })
441
- } as ClientWithCoreApi;
442
- }
443
-
444
- /**
445
- * Initialize all services with proper dependency injection
446
- */
447
- private initializeServices(config: ResolvedConfig): ServiceContainer {
448
- const { sui, walrus, ai, embedding: embeddingConfig, userAddress } = config;
449
-
450
- // 1. Storage Service (foundation)
451
- const storage = new StorageService({
452
- packageId: sui.packageId,
453
- walrusAggregatorUrl: walrus.aggregator,
454
- walrusPublisherUrl: walrus.publisher,
455
- suiClient: sui.client,
456
- network: walrus.network,
457
- epochs: 3,
458
- useUploadRelay: true
459
- });
460
-
461
- // 2. Embedding Service (if API key provided)
462
- let embedding: EmbeddingService | undefined;
463
- if (embeddingConfig.apiKey) {
464
- embedding = new EmbeddingService({
465
- provider: embeddingConfig.provider,
466
- apiKey: embeddingConfig.apiKey,
467
- modelName: embeddingConfig.modelName,
468
- dimensions: embeddingConfig.dimensions
469
- });
470
-
471
- console.log(`✅ Embedding Service initialized: ${embeddingConfig.provider}/${embeddingConfig.modelName} (${embeddingConfig.dimensions}d)`);
472
-
473
- // Connect to storage for search
474
- storage.initializeSearch(embedding);
475
- }
476
-
477
- // 3. Create client adapter for services requiring ClientWithCoreApi
478
- const clientAdapter = this.createClientAdapter(sui.client);
479
-
480
- // 4. Memory Service (blockchain operations)
481
- const pdwConfig: PDWConfig = {
482
- packageId: sui.packageId
483
- };
484
- const memory = new MemoryService(clientAdapter, pdwConfig);
485
-
486
- // 5. Classifier Service (if AI enabled)
487
- let classifier: ClassifierService | undefined;
488
- if (embeddingConfig.apiKey) {
489
- classifier = new ClassifierService(
490
- clientAdapter, // client
491
- pdwConfig, // config
492
- embedding, // embeddingService
493
- embeddingConfig.apiKey // aiApiKey
494
- );
495
- }
496
-
497
- // 9. Create shared HNSW service (singleton for all vector operations)
498
- // Note: This starts async initialization - services will wait for it when needed
499
- let sharedHnswService: IHnswService | undefined;
500
- if (config.features.enableLocalIndexing) {
501
- // Prepare Walrus backup config if enabled
502
- const walrusBackupConfig = config.indexBackup?.enabled ? {
503
- enabled: true,
504
- aggregatorUrl: config.indexBackup.aggregatorUrl || config.walrus.aggregator,
505
- publisherUrl: config.indexBackup.publisherUrl || config.walrus.publisher,
506
- autoSync: config.indexBackup.autoSync ?? false,
507
- epochs: config.indexBackup.epochs ?? 3
508
- } : undefined;
509
-
510
- // Dynamic import to avoid bundling Node.js dependencies (hnswlib-node) in browser builds
511
- // When enableLocalIndexing is false, this code never runs and webpack won't bundle it
512
- this.sharedHnswServicePromise = import('../vector/createHnswService').then(
513
- ({ createHnswService }) => createHnswService({
514
- indexConfig: {
515
- dimension: embeddingConfig.dimensions,
516
- maxElements: 10000,
517
- efConstruction: 200,
518
- m: 16
519
- },
520
- batchConfig: {
521
- maxBatchSize: 100,
522
- batchDelayMs: 5000
523
- },
524
- walrusBackup: walrusBackupConfig
525
- })
526
- );
527
- console.log('✅ Shared HNSW service initialization started (singleton for all vector services)');
528
- if (walrusBackupConfig?.enabled) {
529
- console.log(' ☁️ Walrus backup enabled for local index');
530
- }
531
- }
532
-
533
- // 9a. Vector Service (if local indexing enabled)
534
- // Note: HNSW service will be injected after async initialization
535
- let vector: VectorService | undefined;
536
- if (config.features.enableLocalIndexing && embedding && embeddingConfig.apiKey) {
537
- vector = new VectorService(
538
- {
539
- embedding: {
540
- apiKey: embeddingConfig.apiKey,
541
- model: embeddingConfig.modelName,
542
- dimensions: embeddingConfig.dimensions
543
- },
544
- index: {
545
- maxElements: 10000,
546
- m: 16,
547
- efConstruction: 200
548
- }
549
- // Note: hnswService will be set after async init completes
550
- },
551
- embedding, // Already instantiated
552
- storage
553
- );
554
- }
555
-
556
- // 9b. MemoryIndexService (for HNSW indexing with Walrus persistence)
557
- // Note: HNSW service will be injected after async initialization
558
- let memoryIndex: MemoryIndexService | undefined;
559
- if (config.features.enableLocalIndexing) {
560
- memoryIndex = new MemoryIndexService(storage, {
561
- maxElements: 10000,
562
- dimension: embeddingConfig.dimensions,
563
- efConstruction: 200,
564
- m: 16
565
- // Note: hnswService will be set after async init completes
566
- });
567
- // Initialize with embedding service if available
568
- if (embedding) {
569
- memoryIndex.initialize(embedding, storage);
570
- }
571
- }
572
-
573
- // 10. ClientMemoryManager (for full create pipeline)
574
- // Note: HNSW service will be injected after async initialization
575
- let clientMemoryManager: ClientMemoryManager | undefined;
576
- if (ai.geminiApiKey) {
577
- clientMemoryManager = new ClientMemoryManager({
578
- packageId: sui.packageId,
579
- accessRegistryId: process.env.NEXT_PUBLIC_ACCESS_REGISTRY_ID ||
580
- '0x1d0a1936e170e54ff12ef30a042b390a8ef6dff3a642c5e7056222da038bde',
581
- walrusAggregator: walrus.aggregator,
582
- geminiApiKey: ai.geminiApiKey,
583
- walrusNetwork: walrus.network,
584
- enableLocalIndexing: config.features.enableLocalIndexing
585
- // Note: hnswService will be set after async init completes
586
- });
587
- }
588
-
589
- // 11. ViewService (for read operations)
590
- const viewService = new ViewService(clientAdapter, pdwConfig);
591
-
592
- // 12. BatchService (for batch operations and caching)
593
- const batchService = new BatchService({
594
- embedding: {
595
- batchSize: 10,
596
- delayMs: 1000
597
- },
598
- indexing: {
599
- batchSize: 20,
600
- delayMs: 500
601
- },
602
- storage: {
603
- batchSize: 5,
604
- delayMs: 2000
605
- },
606
- cache: {
607
- maxSize: 1000,
608
- ttlMs: 3600000, // 1 hour default
609
- cleanupIntervalMs: 60000, // 1 minute
610
- enableMetrics: true
611
- },
612
- enableMetrics: true
613
- });
614
-
615
- // 13. MemoryAnalyticsService (for insights and analytics)
616
- const analytics = new MemoryAnalyticsService();
617
-
618
- // 14. EncryptionService (for SEAL encryption - optional)
619
- let encryption: EncryptionService | undefined;
620
- if (config.features.enableEncryption) {
621
- encryption = new EncryptionService(clientAdapter, pdwConfig);
622
- }
623
-
624
- // 15. PermissionService (for access control)
625
- const permissions = new PermissionService({
626
- suiClient: sui.client,
627
- packageId: sui.packageId,
628
- accessRegistryId: process.env.NEXT_PUBLIC_ACCESS_REGISTRY_ID ||
629
- '0x1d0a1936e170e54ff12ef30a042b390a8ef6dff3a642c5e7056222da038bde'
630
- });
631
-
632
- // 16. TransactionService (for transaction utilities)
633
- const tx = new TransactionService(sui.client, pdwConfig);
634
-
635
- // 17. PipelineManager (for processing pipelines)
636
- const pipeline = new PipelineManager({
637
- maxConcurrentPipelines: 10,
638
- enableScheduling: true,
639
- enableHealthChecks: true,
640
- enableMetricsCollection: true
641
- });
642
-
643
- // 18. CapabilityService (for capability-based access control)
644
- const capability = new CapabilityService({
645
- suiClient: sui.client,
646
- packageId: sui.packageId,
647
- });
648
-
649
- // 19. IndexManager (for hybrid index persistence with blockchain integration)
650
- let indexManager: IndexManager | undefined;
651
- if (config.features.enableLocalIndexing && vector && embedding) {
652
- indexManager = new IndexManager(
653
- vector,
654
- storage,
655
- embedding,
656
- {
657
- autoSaveInterval: config.indexManager?.autoSaveInterval ?? 5 * 60 * 1000, // 5 minutes
658
- enableAutoSave: config.indexManager?.enableAutoSave ?? true,
659
- storageKeyPrefix: 'pdw_index_',
660
- onProgress: config.indexManager?.onProgress,
661
- // Blockchain integration
662
- transactionService: tx,
663
- getMemoryIndexFromChain: async (userAddress: string) => {
664
- return viewService.getMemoryIndex(userAddress);
665
- },
666
- executeTransaction: async (transaction: any, signer: any) => {
667
- try {
668
- const result = await sui.client.signAndExecuteTransaction({
669
- transaction,
670
- signer,
671
- options: {
672
- showEffects: true,
673
- showObjectChanges: true,
674
- },
675
- });
676
-
677
- // CRITICAL: Wait for transaction to be confirmed before returning
678
- // This ensures the gas coin version is updated on the network
679
- // before the next transaction is built
680
- if (result.digest) {
681
- try {
682
- await sui.client.waitForTransaction({
683
- digest: result.digest,
684
- options: { showEffects: true },
685
- });
686
- } catch (waitError) {
687
- console.warn('⚠️ waitForTransaction failed:', waitError);
688
- // Continue anyway - the transaction was submitted
689
- }
690
- }
691
-
692
- return {
693
- digest: result.digest,
694
- effects: result.effects,
695
- error: result.effects?.status?.status === 'failure'
696
- ? result.effects.status.error
697
- : undefined,
698
- };
699
- } catch (error: any) {
700
- return {
701
- digest: '',
702
- effects: undefined,
703
- error: error.message || String(error),
704
- };
705
- }
706
- },
707
- }
708
- );
709
- }
710
-
711
- // 20. QueryService (advanced search) - initialized with all dependencies
712
- const query = new QueryService(
713
- memoryIndex, // MemoryIndexService for vector search
714
- embedding, // EmbeddingService for query embedding generation
715
- storage, // StorageService for content retrieval
716
- undefined // GraphService - will be set if knowledge graph is enabled
717
- );
718
-
719
- return {
720
- config,
721
- storage,
722
- embedding,
723
- memory,
724
- query,
725
- classifier,
726
- vector,
727
- memoryIndex,
728
- batchService,
729
- analytics,
730
- encryption,
731
- permissions,
732
- tx,
733
- pipeline,
734
- clientMemoryManager,
735
- viewService,
736
- capability,
737
- indexManager
738
- };
739
- }
740
-
741
- /**
742
- * Initialize client (async operations like WASM loading)
743
- */
744
- private async initialize(): Promise<void> {
745
- if (this.initialized) return;
746
-
747
- try {
748
- // Initialize shared HNSW service FIRST (singleton for all vector operations)
749
- // This ensures all subsequent service initializations get the same instance
750
- if (this.sharedHnswServicePromise) {
751
- this.sharedHnswService = await this.sharedHnswServicePromise;
752
- this.services.sharedHnswService = this.sharedHnswService;
753
- console.log('✅ Shared HNSW service ready (singleton)');
754
- }
755
-
756
- // Initialize vector service if enabled (WASM loading)
757
- // Note: VectorService.initialize() will use singleton from createHnswService
758
- if (this.services.vector) {
759
- await this.services.vector.initialize();
760
- }
761
-
762
- // Initialize knowledge graph if enabled
763
- if (this.config.features.enableKnowledgeGraph && this.services.embedding) {
764
- await this.services.storage.initializeKnowledgeGraph({
765
- embeddingService: this.services.embedding,
766
- geminiApiKey: this.config.ai.geminiApiKey
767
- });
768
- }
769
-
770
- this.initialized = true;
771
- console.log('✅ SimplePDWClient initialized');
772
- } catch (error) {
773
- console.error('Failed to initialize SimplePDWClient:', error);
774
- throw error;
775
- }
776
- }
777
-
778
- /**
779
- * Ensure client is initialized before operations
780
- */
781
- private async ensureInitialized(): Promise<void> {
782
- if (this.initPromise) {
783
- await this.initPromise;
784
- }
785
- }
786
-
787
- /**
788
- * Get service container (internal use)
789
- */
790
- getServices(): ServiceContainer {
791
- return this.services;
792
- }
793
-
794
- /**
795
- * Get configuration (internal use)
796
- */
797
- getConfig(): ResolvedConfig {
798
- return this.config;
799
- }
800
-
801
- /**
802
- * Wait for initialization to complete
803
- */
804
- async ready(): Promise<void> {
805
- await this.ensureInitialized();
806
- }
807
-
808
- /**
809
- * Initialize index with hybrid restore strategy
810
- *
811
- * This method implements the hybrid pattern:
812
- * 1. Try to load from Walrus cache (fast, ~500ms)
813
- * 2. If failed, rebuild from blockchain + Walrus (slow but complete)
814
- * 3. Sync any new memories since last save
815
- * 4. Start auto-save periodically
816
- *
817
- * @param options - Optional progress callback and settings
818
- * @returns Initialization result with stats
819
- *
820
- * @example
821
- * ```typescript
822
- * const pdw = await createPDWClient(config);
823
- * await pdw.ready();
824
- *
825
- * // Initialize index with hybrid restore
826
- * const result = await pdw.initializeIndex({
827
- * onProgress: (stage, progress, message) => {
828
- * console.log(`[${stage}] ${progress}% - ${message}`);
829
- * }
830
- * });
831
- *
832
- * console.log(`Index ready: ${result.vectorCount} vectors (${result.method})`);
833
- * ```
834
- */
835
- async initializeIndex(options: {
836
- onProgress?: IndexProgressCallback;
837
- forceRebuild?: boolean;
838
- } = {}): Promise<{
839
- restored: boolean;
840
- method: 'cache' | 'rebuild' | 'empty';
841
- vectorCount: number;
842
- syncedCount: number;
843
- timeMs: number;
844
- }> {
845
- await this.ensureInitialized();
846
-
847
- if (!this.services.indexManager) {
848
- console.warn('IndexManager not available. Enable local indexing in config.');
849
- return {
850
- restored: false,
851
- method: 'empty',
852
- vectorCount: 0,
853
- syncedCount: 0,
854
- timeMs: 0,
855
- };
856
- }
857
-
858
- // Set progress callback if provided
859
- if (options.onProgress) {
860
- this.services.indexManager = new IndexManager(
861
- this.services.vector!,
862
- this.services.storage,
863
- this.services.embedding!,
864
- {
865
- autoSaveInterval: 5 * 60 * 1000,
866
- enableAutoSave: true,
867
- storageKeyPrefix: 'pdw_index_',
868
- onProgress: options.onProgress,
869
- }
870
- );
871
- }
872
-
873
- const userAddress = this.config.userAddress;
874
-
875
- // Force rebuild if requested
876
- if (options.forceRebuild) {
877
- this.services.indexManager.clearIndexState(userAddress);
878
- }
879
-
880
- // Define callbacks for fetching data
881
- const getMemoriesFromChain = async () => {
882
- const viewService = this.services.viewService;
883
- if (!viewService) {
884
- return [];
885
- }
886
-
887
- try {
888
- // Fetch memories with pagination (max 50 per page)
889
- const allMemories: any[] = [];
890
- let cursor: string | undefined;
891
- const pageSize = 50; // Max allowed by the API
892
-
893
- do {
894
- const response = await viewService.getUserMemories(userAddress, {
895
- limit: pageSize,
896
- cursor,
897
- });
898
-
899
- allMemories.push(...response.data);
900
- cursor = response.nextCursor;
901
- } while (cursor && allMemories.length < 1000); // Cap at 1000 memories
902
-
903
- return allMemories.map((m: any) => ({
904
- id: m.id,
905
- blobId: m.blobId || m.blob_id,
906
- vectorId: m.vectorId || m.vector_id,
907
- category: m.category,
908
- importance: m.importance,
909
- topic: m.topic,
910
- createdAt: m.createdAt || m.created_at || Date.now(),
911
- }));
912
- } catch (error) {
913
- console.warn('Failed to fetch memories from chain:', error);
914
- return [];
915
- }
916
- };
917
-
918
- const getMemoryContent = async (blobId: string) => {
919
- try {
920
- const result = await this.services.storage.retrieveMemoryPackage(blobId);
921
- return {
922
- content: result.memoryPackage?.content || '',
923
- embedding: result.memoryPackage?.embedding,
924
- metadata: result.memoryPackage?.metadata,
925
- };
926
- } catch (error) {
927
- console.warn(`Failed to fetch memory content for ${blobId}:`, error);
928
- return { content: '', embedding: undefined, metadata: undefined };
929
- }
930
- };
931
-
932
- // Initialize with hybrid strategy
933
- return this.services.indexManager.initialize(
934
- userAddress,
935
- getMemoriesFromChain,
936
- getMemoryContent
937
- );
938
- }
939
-
940
- /**
941
- * Save current index to Walrus
942
- *
943
- * @returns Blob ID of saved index, or null if nothing to save
944
- */
945
- async saveIndex(): Promise<string | null> {
946
- await this.ensureInitialized();
947
-
948
- if (!this.services.indexManager) {
949
- console.warn('IndexManager not available');
950
- return null;
951
- }
952
-
953
- return this.services.indexManager.saveIndexWithSigner(
954
- this.config.userAddress,
955
- this.config.signer.getSigner()
956
- );
957
- }
958
-
959
- /**
960
- * Get index statistics
961
- */
962
- getIndexStats(): {
963
- indexState: any;
964
- vectorCacheSize: number;
965
- isAutoSaveEnabled: boolean;
966
- } | null {
967
- if (!this.services.indexManager) {
968
- return null;
969
- }
970
-
971
- return this.services.indexManager.getStats(this.config.userAddress);
972
- }
973
-
974
- /**
975
- * Memory operations namespace
976
- */
977
- get memory(): MemoryNamespace {
978
- return new MemoryNamespace(this.services);
979
- }
980
-
981
- /**
982
- * Search operations namespace
983
- */
984
- get search(): SearchNamespace {
985
- return new SearchNamespace(this.services);
986
- }
987
-
988
- /**
989
- * Classification operations namespace
990
- */
991
- get classify(): ClassifyNamespace {
992
- return new ClassifyNamespace(this.services);
993
- }
994
-
995
- /**
996
- * Knowledge graph operations namespace
997
- */
998
- get graph(): GraphNamespace {
999
- return new GraphNamespace(this.services);
1000
- }
1001
-
1002
- /**
1003
- * Embeddings operations namespace
1004
- */
1005
- get embeddings(): EmbeddingsNamespace {
1006
- return new EmbeddingsNamespace(this.services);
1007
- }
1008
-
1009
- /**
1010
- * Batch operations namespace
1011
- */
1012
- get batch(): BatchNamespace {
1013
- return new BatchNamespace(this.services);
1014
- }
1015
-
1016
- /**
1017
- * Cache operations namespace
1018
- */
1019
- get cache(): CacheNamespace {
1020
- return new CacheNamespace(this.services);
1021
- }
1022
-
1023
- /**
1024
- * Vector index operations namespace
1025
- */
1026
- get index(): IndexNamespace {
1027
- return new IndexNamespace(this.services);
1028
- }
1029
-
1030
- /**
1031
- * Analytics and insights namespace
1032
- */
1033
- get analytics(): AnalyticsNamespace {
1034
- return new AnalyticsNamespace(this.services);
1035
- }
1036
-
1037
- /**
1038
- * SEAL encryption operations namespace
1039
- */
1040
- get encryption(): EncryptionNamespace {
1041
- return new EncryptionNamespace(this.services);
1042
- }
1043
-
1044
- /**
1045
- * Access control and permissions namespace
1046
- */
1047
- get permissions(): PermissionsNamespace {
1048
- return new PermissionsNamespace(this.services);
1049
- }
1050
-
1051
- /**
1052
- * Transaction utilities namespace
1053
- */
1054
- get tx(): TxNamespace {
1055
- return new TxNamespace(this.services);
1056
- }
1057
-
1058
- /**
1059
- * Processing pipelines namespace
1060
- */
1061
- get pipeline(): PipelineNamespace {
1062
- return new PipelineNamespace(this.services);
1063
- }
1064
-
1065
- /**
1066
- * Capability operations namespace
1067
- *
1068
- * Provides low-level access to MemoryCap capability objects.
1069
- * For most use cases, prefer using the `context` namespace instead.
1070
- *
1071
- * @example
1072
- * ```typescript
1073
- * const cap = await pdw.capability.create('MEMO');
1074
- * const keyId = pdw.capability.computeKeyId(cap);
1075
- * ```
1076
- */
1077
- get capability(): CapabilityNamespace {
1078
- return new CapabilityNamespace(this.services);
1079
- }
1080
-
1081
- /**
1082
- * Context operations namespace
1083
- *
1084
- * Higher-level API for managing app contexts (built on capabilities).
1085
- * Use this for managing app-scoped data and access control.
1086
- *
1087
- * @example
1088
- * ```typescript
1089
- * // Get or create context for MEMO app
1090
- * const ctx = await pdw.context.getOrCreate('MEMO');
1091
- *
1092
- * // List all contexts
1093
- * const contexts = await pdw.context.list();
1094
- *
1095
- * // Share context with another user
1096
- * await pdw.context.transfer('MEMO', recipientAddress);
1097
- * ```
1098
- */
1099
- get context(): ContextNamespace {
1100
- return new ContextNamespace(this.services);
1101
- }
1102
-
1103
- /**
1104
- * Wallet operations namespace
1105
- *
1106
- * Simplified wallet operations for address info, balance, and owned objects.
1107
- *
1108
- * @example
1109
- * ```typescript
1110
- * const address = await pdw.wallet.getAddress();
1111
- * const balance = await pdw.wallet.getFormattedBalance();
1112
- * const caps = await pdw.wallet.getMemoryCaps();
1113
- * ```
1114
- */
1115
- get wallet(): WalletNamespace {
1116
- return new WalletNamespace(this.services);
1117
- }
1118
-
1119
- // ===========================================================================
1120
- // CONSOLIDATED NAMESPACES (New Unified API)
1121
- // ===========================================================================
1122
-
1123
- /**
1124
- * AI operations namespace (consolidated)
1125
- *
1126
- * Unified API for all AI-powered operations:
1127
- * - Embeddings (generate, batch, similarity)
1128
- * - Classification (classify, shouldSave, importance)
1129
- * - Chat with memory context
1130
- *
1131
- * @example
1132
- * ```typescript
1133
- * // Generate embeddings
1134
- * const vector = await pdw.ai.embed('Hello world');
1135
- *
1136
- * // Classify content
1137
- * const category = await pdw.ai.classify('I love TypeScript');
1138
- *
1139
- * // Chat with memory context
1140
- * const session = await pdw.ai.chat.createSession();
1141
- * const response = await pdw.ai.chat.send(session.id, 'What do you know about me?');
1142
- * ```
1143
- */
1144
- get ai(): AINamespace {
1145
- return new AINamespace(this.services);
1146
- }
1147
-
1148
- /**
1149
- * Security operations namespace (consolidated)
1150
- *
1151
- * Unified API for encryption, permissions, and contexts:
1152
- * - SEAL encryption/decryption
1153
- * - App contexts (MemoryCap management)
1154
- * - OAuth-style permissions
1155
- *
1156
- * @example
1157
- * ```typescript
1158
- * // Encrypt data
1159
- * const { encryptedData } = await pdw.security.encrypt(data);
1160
- *
1161
- * // Decrypt data
1162
- * const decrypted = await pdw.security.decrypt({ encryptedData });
1163
- *
1164
- * // Manage app contexts
1165
- * const ctx = await pdw.security.context.getOrCreate('MEMO');
1166
- *
1167
- * // Grant permissions
1168
- * await pdw.security.permissions.grant('APP_ID', ['read', 'write']);
1169
- * ```
1170
- */
1171
- get security(): SecurityNamespace {
1172
- return new SecurityNamespace(this.services);
1173
- }
1174
-
1175
- /**
1176
- * Blockchain operations namespace (consolidated)
1177
- *
1178
- * Unified API for Sui blockchain operations:
1179
- * - Transaction building and execution
1180
- * - Wallet operations (balance, owned objects)
1181
- *
1182
- * @example
1183
- * ```typescript
1184
- * // Build and execute transaction
1185
- * const tx = pdw.blockchain.tx.buildCreate({ ... });
1186
- * const result = await pdw.blockchain.tx.execute(tx);
1187
- *
1188
- * // Check balance
1189
- * const balance = await pdw.blockchain.wallet.getFormattedBalance();
1190
- *
1191
- * // Get owned objects
1192
- * const memories = await pdw.blockchain.wallet.getMemories();
1193
- * ```
1194
- */
1195
- get blockchain(): BlockchainNamespace {
1196
- return new BlockchainNamespace(this.services);
1197
- }
1198
-
1199
- /**
1200
- * Storage operations namespace (consolidated)
1201
- *
1202
- * Unified API for Walrus storage and caching:
1203
- * - Upload/download data to Walrus
1204
- * - In-memory LRU cache
1205
- *
1206
- * @example
1207
- * ```typescript
1208
- * // Upload to Walrus
1209
- * const result = await pdw.storage.upload(data);
1210
- *
1211
- * // Download from Walrus
1212
- * const data = await pdw.storage.download(blobId);
1213
- *
1214
- * // Use cache
1215
- * pdw.storage.cache.set('key', value, 60000);
1216
- * const cached = pdw.storage.cache.get('key');
1217
- * ```
1218
- */
1219
- get storage(): ConsolidatedStorageNamespace {
1220
- return new ConsolidatedStorageNamespace(this.services);
1221
- }
1222
- }
1
+ /**
2
+ * Simple PDW Client - Easy-to-use API for Personal Data Wallet
3
+ *
4
+ * Provides a simple function-based API without React dependencies.
5
+ * Works in Node.js, browsers, serverless functions, and CLI tools.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { createPDWClient } from 'personal-data-wallet-sdk';
10
+ * import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
11
+ *
12
+ * const keypair = Ed25519Keypair.fromSecretKey(process.env.PRIVATE_KEY);
13
+ * const pdw = await createPDWClient({
14
+ * signer: keypair,
15
+ * userAddress: keypair.getPublicKey().toSuiAddress(),
16
+ * network: 'testnet',
17
+ * geminiApiKey: process.env.GEMINI_API_KEY
18
+ * });
19
+ *
20
+ * // Simple API - no hooks needed!
21
+ * await pdw.memory.create('I love TypeScript');
22
+ * const results = await pdw.search.vector('programming');
23
+ * const answer = await pdw.chat.send(sessionId, 'What do I like?');
24
+ * ```
25
+ *
26
+ * @module client/SimplePDWClient
27
+ */
28
+
29
+ import { SuiClient, getFullnodeUrl } from '@mysten/sui/client';
30
+ import type { Keypair } from '@mysten/sui/cryptography';
31
+ import type { UnifiedSigner, WalletAdapter } from './signers';
32
+ import { KeypairSigner, WalletAdapterSigner } from './signers';
33
+ import { StorageService } from '../services/StorageService';
34
+ import { EmbeddingService, getSharedEmbeddingService } from '../services/EmbeddingService';
35
+ import { MemoryService } from '../services/MemoryService';
36
+ import { QueryService } from '../services/QueryService';
37
+ import { ClassifierService } from '../services/ClassifierService';
38
+ import { VectorService } from '../services/VectorService';
39
+ import { BatchService } from '../services/BatchService';
40
+ import { MemoryAnalyticsService } from '../retrieval/MemoryAnalyticsService';
41
+ import { EncryptionService } from '../services/EncryptionService';
42
+ import { PermissionService } from '../access/PermissionService';
43
+ import { TransactionService } from '../services/TransactionService';
44
+ import { PipelineManager } from '../pipeline/PipelineManager';
45
+ import { MemoryNamespace } from './namespaces/MemoryNamespace';
46
+ import { SearchNamespace } from './namespaces/SearchNamespace';
47
+ import { ClassifyNamespace } from './namespaces/ClassifyNamespace';
48
+ import { GraphNamespace } from './namespaces/GraphNamespace';
49
+ import { EmbeddingsNamespace } from './namespaces/EmbeddingsNamespace';
50
+ import { BatchNamespace } from './namespaces/BatchNamespace';
51
+ import { CacheNamespace } from './namespaces/CacheNamespace';
52
+ import { IndexNamespace } from './namespaces/IndexNamespace';
53
+ import { AnalyticsNamespace } from './namespaces/AnalyticsNamespace';
54
+ import { EncryptionNamespace } from './namespaces/EncryptionNamespace';
55
+ import { PermissionsNamespace } from './namespaces/PermissionsNamespace';
56
+ import { TxNamespace } from './namespaces/TxNamespace';
57
+ import { PipelineNamespace } from './namespaces/PipelineNamespace';
58
+ import { CapabilityNamespace } from './namespaces/CapabilityNamespace';
59
+ import { ContextNamespace } from './namespaces/ContextNamespace';
60
+ import { WalletNamespace } from './namespaces/WalletNamespace';
61
+ // Consolidated namespaces (new unified API)
62
+ import { AINamespace } from './namespaces/consolidated/AINamespace';
63
+ import { SecurityNamespace } from './namespaces/consolidated/SecurityNamespace';
64
+ import { BlockchainNamespace } from './namespaces/consolidated/BlockchainNamespace';
65
+ import { StorageNamespace as ConsolidatedStorageNamespace } from './namespaces/consolidated/StorageNamespace';
66
+ import type { PDWConfig, ClientWithCoreApi } from '../types';
67
+ import { ClientMemoryManager } from './ClientMemoryManager';
68
+ import { ViewService } from '../services/ViewService';
69
+ import { CapabilityService } from '../services/CapabilityService';
70
+ import { MemoryIndexService } from '../services/MemoryIndexService';
71
+ import { IndexManager, type IndexManagerOptions, type IndexProgressCallback } from '../services/IndexManager';
72
+ // Note: createHnswService is dynamically imported only when enableLocalIndexing is true
73
+ // This prevents bundling Node.js dependencies (hnswlib-node) in browser builds
74
+ import type { IHnswService } from '../vector/IHnswService';
75
+
76
+ /**
77
+ * Configuration for Simple PDW Client
78
+ */
79
+ export interface SimplePDWConfig {
80
+ /**
81
+ * Signer: Either Keypair (Node.js) or WalletAdapter (browser)
82
+ */
83
+ signer: Keypair | WalletAdapter | UnifiedSigner;
84
+
85
+ /**
86
+ * User's Sui address
87
+ * If not provided, will be derived from signer
88
+ */
89
+ userAddress?: string;
90
+
91
+ /**
92
+ * Network to use (auto-configures endpoints)
93
+ * @default 'testnet'
94
+ */
95
+ network?: 'testnet' | 'mainnet' | 'devnet';
96
+
97
+ /**
98
+ * Gemini API key for AI features (embeddings, chat, classification)
99
+ * @deprecated Use `embedding.apiKey` instead for more flexibility
100
+ */
101
+ geminiApiKey?: string;
102
+
103
+ /**
104
+ * Optional: Embedding configuration
105
+ * Allows customizing the embedding provider, model, and dimensions
106
+ */
107
+ embedding?: {
108
+ /**
109
+ * Embedding provider
110
+ * - google: Direct Google AI API
111
+ * - openai: Direct OpenAI API
112
+ * - openrouter: OpenRouter API gateway (recommended - supports multiple models)
113
+ * - cohere: Direct Cohere API
114
+ * @default 'google'
115
+ */
116
+ provider?: 'google' | 'openai' | 'openrouter' | 'cohere';
117
+ /**
118
+ * API key for the embedding provider
119
+ * Falls back to geminiApiKey for backward compatibility
120
+ */
121
+ apiKey?: string;
122
+ /**
123
+ * Model name to use
124
+ * - Google: 'text-embedding-004', 'gemini-embedding-001'
125
+ * - OpenAI: 'text-embedding-3-small', 'text-embedding-3-large'
126
+ * - OpenRouter: 'google/gemini-embedding-001', 'openai/text-embedding-3-small', etc.
127
+ * - Cohere: 'embed-english-v3.0', 'embed-multilingual-v3.0'
128
+ * @default 'text-embedding-004' (for google), 'google/gemini-embedding-001' (for openrouter)
129
+ */
130
+ modelName?: string;
131
+ /**
132
+ * Embedding dimensions
133
+ * @default 3072 (for google/openrouter), 1536 (for openai)
134
+ */
135
+ dimensions?: number;
136
+ };
137
+
138
+ /**
139
+ * Optional: Detailed Walrus configuration
140
+ */
141
+ walrus?: {
142
+ aggregator?: string;
143
+ publisher?: string;
144
+ network?: 'testnet' | 'mainnet';
145
+ };
146
+
147
+ /**
148
+ * Optional: Detailed Sui configuration
149
+ */
150
+ sui?: {
151
+ network?: 'testnet' | 'mainnet' | 'devnet';
152
+ packageId?: string;
153
+ rpcUrl?: string;
154
+ };
155
+
156
+ /**
157
+ * Optional: AI model configuration for chat and analysis
158
+ */
159
+ ai?: {
160
+ /**
161
+ * Chat/analysis model to use
162
+ * Can be OpenRouter format (e.g., 'google/gemini-2.5-flash') or direct provider format
163
+ * @default process.env.AI_CHAT_MODEL || 'google/gemini-2.5-flash'
164
+ */
165
+ chatModel?: string;
166
+ /**
167
+ * API key for chat model (if different from embedding)
168
+ * For OpenRouter, use OPENROUTER_API_KEY
169
+ */
170
+ apiKey?: string;
171
+ };
172
+
173
+ /**
174
+ * Optional: Feature flags
175
+ */
176
+ features?: {
177
+ enableEncryption?: boolean;
178
+ enableLocalIndexing?: boolean;
179
+ enableKnowledgeGraph?: boolean;
180
+ };
181
+
182
+ /**
183
+ * Optional: SEAL encryption configuration
184
+ * Enables end-to-end encryption for memory content
185
+ */
186
+ encryption?: {
187
+ /**
188
+ * Enable SEAL encryption for memories (default: true)
189
+ */
190
+ enabled?: boolean;
191
+ /**
192
+ * SEAL key server object IDs (testnet defaults provided)
193
+ */
194
+ keyServers?: string[];
195
+ /**
196
+ * Number of key servers required for decryption threshold (default: 2)
197
+ */
198
+ threshold?: number;
199
+ /**
200
+ * Access registry ID for OAuth-style permission management
201
+ */
202
+ accessRegistryId?: string;
203
+ };
204
+
205
+ /**
206
+ * Optional: Index manager options for hybrid restore
207
+ */
208
+ indexManager?: {
209
+ /** Auto-save interval in ms (default: 5 minutes) */
210
+ autoSaveInterval?: number;
211
+ /** Enable auto-save (default: true) */
212
+ enableAutoSave?: boolean;
213
+ /** Progress callback for index operations */
214
+ onProgress?: IndexProgressCallback;
215
+ };
216
+
217
+ /**
218
+ * Optional: Index backup to Walrus cloud storage
219
+ * Enables syncing local HNSW index to Walrus for cross-device restoration
220
+ */
221
+ indexBackup?: {
222
+ /** Enable Walrus backup for local index */
223
+ enabled: boolean;
224
+ /** Walrus aggregator URL for downloading */
225
+ aggregatorUrl?: string;
226
+ /** Walrus publisher URL for uploading */
227
+ publisherUrl?: string;
228
+ /** Auto-sync index to Walrus on every save (default: false) */
229
+ autoSync?: boolean;
230
+ /** Storage duration in epochs (default: 3) */
231
+ epochs?: number;
232
+ };
233
+ }
234
+
235
+ /**
236
+ * Default package IDs by network
237
+ */
238
+ const DEFAULT_PACKAGE_IDS: Record<string, string> = {
239
+ testnet: process.env.NEXT_PUBLIC_PACKAGE_ID || process.env.PACKAGE_ID || '0xf63a61b8d056ffb2e0efdd057445e15c9c64a1c6f2d13516812d7031b7e7dc9e',
240
+ mainnet: '', // TODO: Add mainnet package ID when deployed
241
+ devnet: ''
242
+ };
243
+
244
+ /**
245
+ * Resolved configuration after applying defaults
246
+ */
247
+ interface ResolvedConfig {
248
+ signer: UnifiedSigner;
249
+ userAddress: string;
250
+ walrus: {
251
+ aggregator: string;
252
+ publisher: string;
253
+ network: 'testnet' | 'mainnet';
254
+ };
255
+ sui: {
256
+ network: 'testnet' | 'mainnet' | 'devnet';
257
+ packageId: string;
258
+ rpcUrl: string;
259
+ client: SuiClient;
260
+ };
261
+ ai: {
262
+ geminiApiKey?: string;
263
+ chatModel: string;
264
+ apiKey?: string;
265
+ };
266
+ embedding: {
267
+ provider: 'google' | 'openai' | 'openrouter' | 'cohere';
268
+ apiKey?: string;
269
+ modelName: string;
270
+ dimensions: number;
271
+ };
272
+ features: {
273
+ enableEncryption: boolean;
274
+ enableLocalIndexing: boolean;
275
+ enableKnowledgeGraph: boolean;
276
+ };
277
+ encryption: {
278
+ enabled: boolean;
279
+ keyServers: string[];
280
+ threshold: number;
281
+ accessRegistryId: string;
282
+ };
283
+ indexManager?: {
284
+ autoSaveInterval?: number;
285
+ enableAutoSave?: boolean;
286
+ onProgress?: IndexProgressCallback;
287
+ };
288
+ indexBackup?: {
289
+ enabled: boolean;
290
+ aggregatorUrl?: string;
291
+ publisherUrl?: string;
292
+ autoSync?: boolean;
293
+ epochs?: number;
294
+ };
295
+ }
296
+
297
+ /**
298
+ * Service container for dependency injection
299
+ */
300
+ export interface ServiceContainer {
301
+ config: ResolvedConfig;
302
+ storage: StorageService;
303
+ embedding?: EmbeddingService;
304
+ memory: MemoryService;
305
+ query: QueryService;
306
+ classifier?: ClassifierService;
307
+ vector?: VectorService;
308
+ memoryIndex?: MemoryIndexService; // For HNSW indexing with persistence
309
+ batchService?: BatchService; // For batch operations and caching
310
+ analytics?: MemoryAnalyticsService; // For memory insights
311
+ encryption?: EncryptionService; // For SEAL encryption
312
+ permissions?: PermissionService; // For access control
313
+ tx?: TransactionService; // For transaction utilities
314
+ pipeline?: PipelineManager; // For processing pipelines
315
+ clientMemoryManager?: ClientMemoryManager; // For full create pipeline
316
+ viewService?: ViewService; // For read operations
317
+ capability?: CapabilityService; // For capability-based access control
318
+ indexManager?: IndexManager; // For hybrid index persistence
319
+ /** Shared HNSW service instance (singleton) */
320
+ sharedHnswService?: IHnswService;
321
+ }
322
+
323
+ /**
324
+ * Simple PDW Client
325
+ *
326
+ * Main client class providing easy-to-use API for all PDW operations
327
+ */
328
+ export class SimplePDWClient {
329
+ private config: ResolvedConfig;
330
+ private services: ServiceContainer;
331
+ private initialized: boolean = false;
332
+ private initPromise: Promise<void> | null = null;
333
+ /** Shared HNSW service instance - created once and shared across all services */
334
+ private sharedHnswService: IHnswService | null = null;
335
+ private sharedHnswServicePromise: Promise<IHnswService> | null = null;
336
+
337
+ constructor(config: SimplePDWConfig) {
338
+ // Resolve configuration with defaults
339
+ this.config = this.resolveConfig(config);
340
+
341
+ // Initialize services
342
+ this.services = this.initializeServices(this.config);
343
+
344
+ // Start async initialization (WASM loading, etc.)
345
+ this.initPromise = this.initialize();
346
+ }
347
+
348
+ /**
349
+ * Resolve configuration with smart defaults
350
+ */
351
+ private resolveConfig(config: SimplePDWConfig): ResolvedConfig {
352
+ const network = config.network || config.sui?.network || 'testnet';
353
+
354
+ // Create unified signer
355
+ let signer: UnifiedSigner;
356
+ if ('signAndExecuteTransaction' in config.signer && 'signPersonalMessage' in config.signer && 'getAddress' in config.signer) {
357
+ // Already a UnifiedSigner
358
+ signer = config.signer as UnifiedSigner;
359
+ } else if ('getPublicKey' in config.signer && 'signPersonalMessage' in config.signer) {
360
+ // It's a Keypair
361
+ const suiClient = new SuiClient({
362
+ url: config.sui?.rpcUrl || getFullnodeUrl(network)
363
+ });
364
+ signer = new KeypairSigner(config.signer as Keypair, suiClient);
365
+ } else {
366
+ // It's a WalletAdapter
367
+ signer = new WalletAdapterSigner(config.signer as WalletAdapter);
368
+ }
369
+
370
+ // Derive user address if not provided
371
+ const userAddress = config.userAddress || signer.getAddress();
372
+
373
+ // Create Sui client
374
+ const suiClient = new SuiClient({
375
+ url: config.sui?.rpcUrl || getFullnodeUrl(network)
376
+ });
377
+
378
+ // Resolve embedding configuration with defaults
379
+ const embeddingProvider = config.embedding?.provider || 'google';
380
+ const embeddingApiKey = config.embedding?.apiKey || config.geminiApiKey;
381
+ const embeddingModelName = config.embedding?.modelName || this.getDefaultEmbeddingModel(embeddingProvider);
382
+ const embeddingDimensions = config.embedding?.dimensions || this.getDefaultEmbeddingDimensions(embeddingProvider);
383
+
384
+ return {
385
+ signer,
386
+ userAddress,
387
+ walrus: {
388
+ aggregator: config.walrus?.aggregator ||
389
+ `https://aggregator.walrus-${network}.walrus.space`,
390
+ publisher: config.walrus?.publisher ||
391
+ `https://publisher.walrus-${network}.walrus.space`,
392
+ network: (config.walrus?.network || network) as 'testnet' | 'mainnet'
393
+ },
394
+ sui: {
395
+ network,
396
+ packageId: config.sui?.packageId || DEFAULT_PACKAGE_IDS[network],
397
+ rpcUrl: config.sui?.rpcUrl || getFullnodeUrl(network),
398
+ client: suiClient
399
+ },
400
+ ai: {
401
+ geminiApiKey: config.geminiApiKey,
402
+ chatModel: config.ai?.chatModel || process.env.AI_CHAT_MODEL || 'google/gemini-2.5-flash',
403
+ apiKey: config.ai?.apiKey || process.env.OPENROUTER_API_KEY || config.geminiApiKey
404
+ },
405
+ embedding: {
406
+ provider: embeddingProvider,
407
+ apiKey: embeddingApiKey,
408
+ modelName: embeddingModelName,
409
+ dimensions: embeddingDimensions
410
+ },
411
+ features: {
412
+ enableEncryption: config.features?.enableEncryption ?? true, // Changed default to true
413
+ enableLocalIndexing: config.features?.enableLocalIndexing ?? true,
414
+ enableKnowledgeGraph: config.features?.enableKnowledgeGraph ?? true
415
+ },
416
+ encryption: {
417
+ enabled: config.encryption?.enabled ?? true, // Default: enabled
418
+ keyServers: config.encryption?.keyServers || [
419
+ '0x73d05d62c18d9374e3ea529e8e0ed6161da1a141a94d3f76ae3fe4e99356db75',
420
+ '0xf5d14a81a982144ae441cd7d64b09027f116a468bd36e7eca494f750591623c8'
421
+ ],
422
+ threshold: config.encryption?.threshold ?? 2, // Default: 2 of N
423
+ accessRegistryId: config.encryption?.accessRegistryId ||
424
+ process.env.NEXT_PUBLIC_ACCESS_REGISTRY_ID ||
425
+ '0x1d0a1936e170e54ff12ef30a042b390a8ef6dff3a642c5e7056222da038bde'
426
+ },
427
+ indexManager: config.indexManager,
428
+ indexBackup: config.indexBackup
429
+ };
430
+ }
431
+
432
+ /**
433
+ * Get default embedding model for provider
434
+ */
435
+ private getDefaultEmbeddingModel(provider: string): string {
436
+ switch (provider) {
437
+ case 'google':
438
+ return 'text-embedding-004';
439
+ case 'openai':
440
+ return 'text-embedding-3-small';
441
+ case 'openrouter':
442
+ return 'google/gemini-embedding-001';
443
+ case 'cohere':
444
+ return 'embed-english-v3.0';
445
+ default:
446
+ return 'text-embedding-004';
447
+ }
448
+ }
449
+
450
+ /**
451
+ * Get default embedding dimensions for provider
452
+ */
453
+ private getDefaultEmbeddingDimensions(provider: string): number {
454
+ switch (provider) {
455
+ case 'google':
456
+ return 3072;
457
+ case 'openai':
458
+ return 1536;
459
+ case 'openrouter':
460
+ return 3072; // google/gemini-embedding-001 returns 3072 dimensions
461
+ case 'cohere':
462
+ return 1024;
463
+ default:
464
+ return 3072;
465
+ }
466
+ }
467
+
468
+ /**
469
+ * Create ClientWithCoreApi adapter from SuiClient
470
+ */
471
+ private createClientAdapter(suiClient: SuiClient): ClientWithCoreApi {
472
+ return {
473
+ // Expose the underlying SuiClient for services that need it (e.g., ViewService)
474
+ client: suiClient,
475
+ core: {
476
+ getObject: (objectId: string) => suiClient.getObject({ id: objectId, options: { showContent: true } }),
477
+ getObjects: (objectIds: string[]) => Promise.all(objectIds.map(id => suiClient.getObject({ id, options: { showContent: true } }))),
478
+ executeTransaction: (tx: any) => suiClient.signAndExecuteTransaction(tx)
479
+ },
480
+ $extend: <T>(extension: T) => ({ ...suiClient, ...extension })
481
+ } as ClientWithCoreApi;
482
+ }
483
+
484
+ /**
485
+ * Initialize all services with proper dependency injection
486
+ */
487
+ private initializeServices(config: ResolvedConfig): ServiceContainer {
488
+ const { sui, walrus, ai, embedding: embeddingConfig, userAddress } = config;
489
+
490
+ // 1. Storage Service (foundation)
491
+ const storage = new StorageService({
492
+ packageId: sui.packageId,
493
+ walrusAggregatorUrl: walrus.aggregator,
494
+ walrusPublisherUrl: walrus.publisher,
495
+ suiClient: sui.client,
496
+ network: walrus.network,
497
+ epochs: 3,
498
+ useUploadRelay: true
499
+ });
500
+
501
+ // 2. Embedding Service (if API key provided) - uses singleton pattern
502
+ let embedding: EmbeddingService | undefined;
503
+ if (embeddingConfig.apiKey) {
504
+ // Use singleton to share EmbeddingService across all clients
505
+ // Reduces memory usage and connection overhead for multi-user scenarios
506
+ embedding = getSharedEmbeddingService({
507
+ provider: embeddingConfig.provider,
508
+ apiKey: embeddingConfig.apiKey,
509
+ modelName: embeddingConfig.modelName,
510
+ dimensions: embeddingConfig.dimensions
511
+ });
512
+
513
+ console.log(`✅ Embedding Service (singleton): ${embeddingConfig.provider}/${embeddingConfig.modelName} (${embeddingConfig.dimensions}d)`);
514
+
515
+ // Connect to storage for search
516
+ storage.initializeSearch(embedding);
517
+ }
518
+
519
+ // 3. Create client adapter for services requiring ClientWithCoreApi
520
+ const clientAdapter = this.createClientAdapter(sui.client);
521
+
522
+ // 4. Memory Service (blockchain operations)
523
+ const pdwConfig: PDWConfig = {
524
+ packageId: sui.packageId
525
+ };
526
+ const memory = new MemoryService(clientAdapter, pdwConfig);
527
+
528
+ // 5. Classifier Service (if AI enabled)
529
+ let classifier: ClassifierService | undefined;
530
+ if (embeddingConfig.apiKey) {
531
+ classifier = new ClassifierService(
532
+ clientAdapter, // client
533
+ pdwConfig, // config
534
+ embedding, // embeddingService
535
+ embeddingConfig.apiKey // aiApiKey
536
+ );
537
+ }
538
+
539
+ // 9. Create shared HNSW service (singleton for all vector operations)
540
+ // Note: This starts async initialization - services will wait for it when needed
541
+ let sharedHnswService: IHnswService | undefined;
542
+ if (config.features.enableLocalIndexing) {
543
+ // Prepare Walrus backup config if enabled
544
+ const walrusBackupConfig = config.indexBackup?.enabled ? {
545
+ enabled: true,
546
+ aggregatorUrl: config.indexBackup.aggregatorUrl || config.walrus.aggregator,
547
+ publisherUrl: config.indexBackup.publisherUrl || config.walrus.publisher,
548
+ autoSync: config.indexBackup.autoSync ?? false,
549
+ epochs: config.indexBackup.epochs ?? 3
550
+ } : undefined;
551
+
552
+ // Dynamic import to avoid bundling Node.js dependencies (hnswlib-node) in browser builds
553
+ // When enableLocalIndexing is false, this code never runs and webpack won't bundle it
554
+ this.sharedHnswServicePromise = import('../vector/createHnswService').then(
555
+ ({ createHnswService }) => createHnswService({
556
+ indexConfig: {
557
+ dimension: embeddingConfig.dimensions,
558
+ maxElements: 10000,
559
+ efConstruction: 200,
560
+ m: 16
561
+ },
562
+ batchConfig: {
563
+ maxBatchSize: 100,
564
+ batchDelayMs: 5000
565
+ },
566
+ walrusBackup: walrusBackupConfig
567
+ })
568
+ );
569
+ console.log('✅ Shared HNSW service initialization started (singleton for all vector services)');
570
+ if (walrusBackupConfig?.enabled) {
571
+ console.log(' ☁️ Walrus backup enabled for local index');
572
+ }
573
+ }
574
+
575
+ // 9a. Vector Service (if local indexing enabled)
576
+ // Note: HNSW service will be injected after async initialization
577
+ let vector: VectorService | undefined;
578
+ if (config.features.enableLocalIndexing && embedding && embeddingConfig.apiKey) {
579
+ vector = new VectorService(
580
+ {
581
+ embedding: {
582
+ apiKey: embeddingConfig.apiKey,
583
+ model: embeddingConfig.modelName,
584
+ dimensions: embeddingConfig.dimensions
585
+ },
586
+ index: {
587
+ maxElements: 10000,
588
+ m: 16,
589
+ efConstruction: 200
590
+ }
591
+ // Note: hnswService will be set after async init completes
592
+ },
593
+ embedding, // Already instantiated
594
+ storage
595
+ );
596
+ }
597
+
598
+ // 9b. MemoryIndexService (for HNSW indexing with Walrus persistence)
599
+ // Note: HNSW service will be injected after async initialization
600
+ let memoryIndex: MemoryIndexService | undefined;
601
+ if (config.features.enableLocalIndexing) {
602
+ memoryIndex = new MemoryIndexService(storage, {
603
+ maxElements: 10000,
604
+ dimension: embeddingConfig.dimensions,
605
+ efConstruction: 200,
606
+ m: 16
607
+ // Note: hnswService will be set after async init completes
608
+ });
609
+ // Initialize with embedding service if available
610
+ if (embedding) {
611
+ memoryIndex.initialize(embedding, storage);
612
+ }
613
+ }
614
+
615
+ // 10. ClientMemoryManager (for full create pipeline)
616
+ // Note: HNSW service will be injected after async initialization
617
+ let clientMemoryManager: ClientMemoryManager | undefined;
618
+ if (ai.geminiApiKey) {
619
+ clientMemoryManager = new ClientMemoryManager({
620
+ packageId: sui.packageId,
621
+ accessRegistryId: config.encryption.accessRegistryId,
622
+ walrusAggregator: walrus.aggregator,
623
+ geminiApiKey: ai.geminiApiKey,
624
+ walrusNetwork: walrus.network,
625
+ enableLocalIndexing: config.features.enableLocalIndexing,
626
+ enableEncryption: config.encryption.enabled, // Pass encryption config
627
+ sealServerObjectIds: config.encryption.keyServers
628
+ // Note: hnswService will be set after async init completes
629
+ });
630
+ }
631
+
632
+ // 11. ViewService (for read operations)
633
+ const viewService = new ViewService(clientAdapter, pdwConfig);
634
+
635
+ // 12. BatchService (for batch operations and caching)
636
+ const batchService = new BatchService({
637
+ embedding: {
638
+ batchSize: 10,
639
+ delayMs: 1000
640
+ },
641
+ indexing: {
642
+ batchSize: 20,
643
+ delayMs: 500
644
+ },
645
+ storage: {
646
+ batchSize: 5,
647
+ delayMs: 2000
648
+ },
649
+ cache: {
650
+ maxSize: 1000,
651
+ ttlMs: 3600000, // 1 hour default
652
+ cleanupIntervalMs: 60000, // 1 minute
653
+ enableMetrics: true
654
+ },
655
+ enableMetrics: true
656
+ });
657
+
658
+ // 13. MemoryAnalyticsService (for insights and analytics)
659
+ const analytics = new MemoryAnalyticsService();
660
+
661
+ // 14. EncryptionService (for SEAL encryption - enabled by default)
662
+ let encryption: EncryptionService | undefined;
663
+ if (config.features.enableEncryption) {
664
+ // Pass encryption configuration to PDWConfig
665
+ const encryptionEnabledConfig: PDWConfig = {
666
+ ...pdwConfig,
667
+ encryptionConfig: {
668
+ enabled: config.encryption.enabled,
669
+ keyServers: config.encryption.keyServers
670
+ },
671
+ accessRegistryId: config.encryption.accessRegistryId
672
+ };
673
+ encryption = new EncryptionService(clientAdapter, encryptionEnabledConfig);
674
+ console.log(`✅ EncryptionService initialized (SEAL enabled: ${config.encryption.enabled})`);
675
+ console.log(` Key servers: ${config.encryption.keyServers.length}, Threshold: ${config.encryption.threshold}`);
676
+ }
677
+
678
+ // 15. PermissionService (for access control)
679
+ const permissions = new PermissionService({
680
+ suiClient: sui.client,
681
+ packageId: sui.packageId,
682
+ accessRegistryId: process.env.NEXT_PUBLIC_ACCESS_REGISTRY_ID ||
683
+ '0x1d0a1936e170e54ff12ef30a042b390a8ef6dff3a642c5e7056222da038bde'
684
+ });
685
+
686
+ // 16. TransactionService (for transaction utilities)
687
+ const tx = new TransactionService(sui.client, pdwConfig);
688
+
689
+ // 17. PipelineManager (for processing pipelines)
690
+ const pipeline = new PipelineManager({
691
+ maxConcurrentPipelines: 10,
692
+ enableScheduling: true,
693
+ enableHealthChecks: true,
694
+ enableMetricsCollection: true
695
+ });
696
+
697
+ // 18. CapabilityService (for capability-based access control)
698
+ const capability = new CapabilityService({
699
+ suiClient: sui.client,
700
+ packageId: sui.packageId,
701
+ });
702
+
703
+ // 19. IndexManager (for hybrid index persistence with blockchain integration)
704
+ let indexManager: IndexManager | undefined;
705
+ if (config.features.enableLocalIndexing && vector && embedding) {
706
+ indexManager = new IndexManager(
707
+ vector,
708
+ storage,
709
+ embedding,
710
+ {
711
+ autoSaveInterval: config.indexManager?.autoSaveInterval ?? 5 * 60 * 1000, // 5 minutes
712
+ enableAutoSave: config.indexManager?.enableAutoSave ?? true,
713
+ storageKeyPrefix: 'pdw_index_',
714
+ onProgress: config.indexManager?.onProgress,
715
+ // Blockchain integration
716
+ transactionService: tx,
717
+ getMemoryIndexFromChain: async (userAddress: string) => {
718
+ return viewService.getMemoryIndex(userAddress);
719
+ },
720
+ executeTransaction: async (transaction: any, signer: any) => {
721
+ try {
722
+ const result = await sui.client.signAndExecuteTransaction({
723
+ transaction,
724
+ signer,
725
+ options: {
726
+ showEffects: true,
727
+ showObjectChanges: true,
728
+ },
729
+ });
730
+
731
+ // CRITICAL: Wait for transaction to be confirmed before returning
732
+ // This ensures the gas coin version is updated on the network
733
+ // before the next transaction is built
734
+ if (result.digest) {
735
+ try {
736
+ await sui.client.waitForTransaction({
737
+ digest: result.digest,
738
+ options: { showEffects: true },
739
+ });
740
+ } catch (waitError) {
741
+ console.warn('⚠️ waitForTransaction failed:', waitError);
742
+ // Continue anyway - the transaction was submitted
743
+ }
744
+ }
745
+
746
+ return {
747
+ digest: result.digest,
748
+ effects: result.effects,
749
+ error: result.effects?.status?.status === 'failure'
750
+ ? result.effects.status.error
751
+ : undefined,
752
+ };
753
+ } catch (error: any) {
754
+ return {
755
+ digest: '',
756
+ effects: undefined,
757
+ error: error.message || String(error),
758
+ };
759
+ }
760
+ },
761
+ }
762
+ );
763
+ }
764
+
765
+ // 20. QueryService (advanced search) - initialized with all dependencies
766
+ const query = new QueryService(
767
+ memoryIndex, // MemoryIndexService for vector search
768
+ embedding, // EmbeddingService for query embedding generation
769
+ storage, // StorageService for content retrieval
770
+ undefined // GraphService - will be set if knowledge graph is enabled
771
+ );
772
+
773
+ return {
774
+ config,
775
+ storage,
776
+ embedding,
777
+ memory,
778
+ query,
779
+ classifier,
780
+ vector,
781
+ memoryIndex,
782
+ batchService,
783
+ analytics,
784
+ encryption,
785
+ permissions,
786
+ tx,
787
+ pipeline,
788
+ clientMemoryManager,
789
+ viewService,
790
+ capability,
791
+ indexManager
792
+ };
793
+ }
794
+
795
+ /**
796
+ * Initialize client (async operations like WASM loading)
797
+ */
798
+ private async initialize(): Promise<void> {
799
+ if (this.initialized) return;
800
+
801
+ try {
802
+ // Initialize shared HNSW service FIRST (singleton for all vector operations)
803
+ // This ensures all subsequent service initializations get the same instance
804
+ if (this.sharedHnswServicePromise) {
805
+ this.sharedHnswService = await this.sharedHnswServicePromise;
806
+ this.services.sharedHnswService = this.sharedHnswService;
807
+ console.log('✅ Shared HNSW service ready (singleton)');
808
+ }
809
+
810
+ // Initialize vector service if enabled (WASM loading)
811
+ // Note: VectorService.initialize() will use singleton from createHnswService
812
+ if (this.services.vector) {
813
+ await this.services.vector.initialize();
814
+ }
815
+
816
+ // Initialize knowledge graph if enabled
817
+ // Use apiKey (OpenRouter) as primary, fallback to geminiApiKey for backward compatibility
818
+ const graphApiKey = this.config.ai.apiKey || this.config.ai.geminiApiKey;
819
+ if (this.config.features.enableKnowledgeGraph && this.services.embedding && graphApiKey) {
820
+ const graphService = await this.services.storage.initializeKnowledgeGraph({
821
+ embeddingService: this.services.embedding,
822
+ geminiApiKey: graphApiKey
823
+ });
824
+
825
+ // Update QueryService with the initialized GraphService
826
+ if (graphService && this.services.query && this.services.memoryIndex && this.services.embedding) {
827
+ this.services.query.initialize(
828
+ this.services.memoryIndex,
829
+ this.services.embedding,
830
+ this.services.storage,
831
+ graphService
832
+ );
833
+ console.log('✅ QueryService updated with Knowledge Graph');
834
+ }
835
+ }
836
+
837
+ this.initialized = true;
838
+ console.log('✅ SimplePDWClient initialized');
839
+ } catch (error) {
840
+ console.error('Failed to initialize SimplePDWClient:', error);
841
+ throw error;
842
+ }
843
+ }
844
+
845
+ /**
846
+ * Ensure client is initialized before operations
847
+ */
848
+ private async ensureInitialized(): Promise<void> {
849
+ if (this.initPromise) {
850
+ await this.initPromise;
851
+ }
852
+ }
853
+
854
+ /**
855
+ * Get service container (internal use)
856
+ */
857
+ getServices(): ServiceContainer {
858
+ return this.services;
859
+ }
860
+
861
+ /**
862
+ * Get configuration (internal use)
863
+ */
864
+ getConfig(): ResolvedConfig {
865
+ return this.config;
866
+ }
867
+
868
+ /**
869
+ * Wait for initialization to complete
870
+ */
871
+ async ready(): Promise<void> {
872
+ await this.ensureInitialized();
873
+ }
874
+
875
+ /**
876
+ * Initialize index with hybrid restore strategy
877
+ *
878
+ * This method implements the hybrid pattern:
879
+ * 1. Try to load from Walrus cache (fast, ~500ms)
880
+ * 2. If failed, rebuild from blockchain + Walrus (slow but complete)
881
+ * 3. Sync any new memories since last save
882
+ * 4. Start auto-save periodically
883
+ *
884
+ * @param options - Optional progress callback and settings
885
+ * @returns Initialization result with stats
886
+ *
887
+ * @example
888
+ * ```typescript
889
+ * const pdw = await createPDWClient(config);
890
+ * await pdw.ready();
891
+ *
892
+ * // Initialize index with hybrid restore
893
+ * const result = await pdw.initializeIndex({
894
+ * onProgress: (stage, progress, message) => {
895
+ * console.log(`[${stage}] ${progress}% - ${message}`);
896
+ * }
897
+ * });
898
+ *
899
+ * console.log(`Index ready: ${result.vectorCount} vectors (${result.method})`);
900
+ * ```
901
+ */
902
+ async initializeIndex(options: {
903
+ onProgress?: IndexProgressCallback;
904
+ forceRebuild?: boolean;
905
+ } = {}): Promise<{
906
+ restored: boolean;
907
+ method: 'cache' | 'rebuild' | 'empty';
908
+ vectorCount: number;
909
+ syncedCount: number;
910
+ timeMs: number;
911
+ }> {
912
+ await this.ensureInitialized();
913
+
914
+ if (!this.services.indexManager) {
915
+ console.warn('IndexManager not available. Enable local indexing in config.');
916
+ return {
917
+ restored: false,
918
+ method: 'empty',
919
+ vectorCount: 0,
920
+ syncedCount: 0,
921
+ timeMs: 0,
922
+ };
923
+ }
924
+
925
+ // Set progress callback if provided
926
+ if (options.onProgress) {
927
+ this.services.indexManager = new IndexManager(
928
+ this.services.vector!,
929
+ this.services.storage,
930
+ this.services.embedding!,
931
+ {
932
+ autoSaveInterval: 5 * 60 * 1000,
933
+ enableAutoSave: true,
934
+ storageKeyPrefix: 'pdw_index_',
935
+ onProgress: options.onProgress,
936
+ }
937
+ );
938
+ }
939
+
940
+ const userAddress = this.config.userAddress;
941
+
942
+ // Force rebuild if requested
943
+ if (options.forceRebuild) {
944
+ this.services.indexManager.clearIndexState(userAddress);
945
+ }
946
+
947
+ // Define callbacks for fetching data
948
+ const getMemoriesFromChain = async () => {
949
+ const viewService = this.services.viewService;
950
+ if (!viewService) {
951
+ return [];
952
+ }
953
+
954
+ try {
955
+ // Fetch memories with pagination (max 50 per page)
956
+ const allMemories: any[] = [];
957
+ let cursor: string | undefined;
958
+ const pageSize = 50; // Max allowed by the API
959
+
960
+ do {
961
+ const response = await viewService.getUserMemories(userAddress, {
962
+ limit: pageSize,
963
+ cursor,
964
+ });
965
+
966
+ allMemories.push(...response.data);
967
+ cursor = response.nextCursor;
968
+ } while (cursor && allMemories.length < 1000); // Cap at 1000 memories
969
+
970
+ return allMemories.map((m: any) => ({
971
+ id: m.id,
972
+ blobId: m.blobId || m.blob_id,
973
+ vectorId: m.vectorId || m.vector_id,
974
+ category: m.category,
975
+ importance: m.importance,
976
+ topic: m.topic,
977
+ createdAt: m.createdAt || m.created_at || Date.now(),
978
+ }));
979
+ } catch (error) {
980
+ console.warn('Failed to fetch memories from chain:', error);
981
+ return [];
982
+ }
983
+ };
984
+
985
+ const getMemoryContent = async (blobId: string) => {
986
+ try {
987
+ const result = await this.services.storage.retrieveMemoryPackage(blobId);
988
+ return {
989
+ content: result.memoryPackage?.content || '',
990
+ embedding: result.memoryPackage?.embedding,
991
+ metadata: result.memoryPackage?.metadata,
992
+ };
993
+ } catch (error) {
994
+ console.warn(`Failed to fetch memory content for ${blobId}:`, error);
995
+ return { content: '', embedding: undefined, metadata: undefined };
996
+ }
997
+ };
998
+
999
+ // Initialize with hybrid strategy
1000
+ return this.services.indexManager.initialize(
1001
+ userAddress,
1002
+ getMemoriesFromChain,
1003
+ getMemoryContent
1004
+ );
1005
+ }
1006
+
1007
+ /**
1008
+ * Save current index to Walrus
1009
+ *
1010
+ * @returns Blob ID of saved index, or null if nothing to save
1011
+ */
1012
+ async saveIndex(): Promise<string | null> {
1013
+ await this.ensureInitialized();
1014
+
1015
+ if (!this.services.indexManager) {
1016
+ console.warn('IndexManager not available');
1017
+ return null;
1018
+ }
1019
+
1020
+ return this.services.indexManager.saveIndexWithSigner(
1021
+ this.config.userAddress,
1022
+ this.config.signer.getSigner()
1023
+ );
1024
+ }
1025
+
1026
+ /**
1027
+ * Get index statistics
1028
+ */
1029
+ getIndexStats(): {
1030
+ indexState: any;
1031
+ vectorCacheSize: number;
1032
+ isAutoSaveEnabled: boolean;
1033
+ } | null {
1034
+ if (!this.services.indexManager) {
1035
+ return null;
1036
+ }
1037
+
1038
+ return this.services.indexManager.getStats(this.config.userAddress);
1039
+ }
1040
+
1041
+ /**
1042
+ * Memory operations namespace
1043
+ */
1044
+ get memory(): MemoryNamespace {
1045
+ return new MemoryNamespace(this.services);
1046
+ }
1047
+
1048
+ /**
1049
+ * Search operations namespace
1050
+ */
1051
+ get search(): SearchNamespace {
1052
+ return new SearchNamespace(this.services);
1053
+ }
1054
+
1055
+ /**
1056
+ * Classification operations namespace
1057
+ */
1058
+ get classify(): ClassifyNamespace {
1059
+ return new ClassifyNamespace(this.services);
1060
+ }
1061
+
1062
+ /**
1063
+ * Knowledge graph operations namespace
1064
+ */
1065
+ get graph(): GraphNamespace {
1066
+ return new GraphNamespace(this.services);
1067
+ }
1068
+
1069
+ /**
1070
+ * Embeddings operations namespace
1071
+ */
1072
+ get embeddings(): EmbeddingsNamespace {
1073
+ return new EmbeddingsNamespace(this.services);
1074
+ }
1075
+
1076
+ /**
1077
+ * Batch operations namespace
1078
+ */
1079
+ get batch(): BatchNamespace {
1080
+ return new BatchNamespace(this.services);
1081
+ }
1082
+
1083
+ /**
1084
+ * Cache operations namespace
1085
+ */
1086
+ get cache(): CacheNamespace {
1087
+ return new CacheNamespace(this.services);
1088
+ }
1089
+
1090
+ /**
1091
+ * Vector index operations namespace
1092
+ */
1093
+ get index(): IndexNamespace {
1094
+ return new IndexNamespace(this.services);
1095
+ }
1096
+
1097
+ /**
1098
+ * Analytics and insights namespace
1099
+ */
1100
+ get analytics(): AnalyticsNamespace {
1101
+ return new AnalyticsNamespace(this.services);
1102
+ }
1103
+
1104
+ /**
1105
+ * SEAL encryption operations namespace
1106
+ */
1107
+ get encryption(): EncryptionNamespace {
1108
+ return new EncryptionNamespace(this.services);
1109
+ }
1110
+
1111
+ /**
1112
+ * Access control and permissions namespace
1113
+ */
1114
+ get permissions(): PermissionsNamespace {
1115
+ return new PermissionsNamespace(this.services);
1116
+ }
1117
+
1118
+ /**
1119
+ * Transaction utilities namespace
1120
+ */
1121
+ get tx(): TxNamespace {
1122
+ return new TxNamespace(this.services);
1123
+ }
1124
+
1125
+ /**
1126
+ * Processing pipelines namespace
1127
+ */
1128
+ get pipeline(): PipelineNamespace {
1129
+ return new PipelineNamespace(this.services);
1130
+ }
1131
+
1132
+ /**
1133
+ * Capability operations namespace
1134
+ *
1135
+ * Provides low-level access to MemoryCap capability objects.
1136
+ * For most use cases, prefer using the `context` namespace instead.
1137
+ *
1138
+ * @example
1139
+ * ```typescript
1140
+ * const cap = await pdw.capability.create('MEMO');
1141
+ * const keyId = pdw.capability.computeKeyId(cap);
1142
+ * ```
1143
+ */
1144
+ get capability(): CapabilityNamespace {
1145
+ return new CapabilityNamespace(this.services);
1146
+ }
1147
+
1148
+ /**
1149
+ * Context operations namespace
1150
+ *
1151
+ * Higher-level API for managing app contexts (built on capabilities).
1152
+ * Use this for managing app-scoped data and access control.
1153
+ *
1154
+ * @example
1155
+ * ```typescript
1156
+ * // Get or create context for MEMO app
1157
+ * const ctx = await pdw.context.getOrCreate('MEMO');
1158
+ *
1159
+ * // List all contexts
1160
+ * const contexts = await pdw.context.list();
1161
+ *
1162
+ * // Share context with another user
1163
+ * await pdw.context.transfer('MEMO', recipientAddress);
1164
+ * ```
1165
+ */
1166
+ get context(): ContextNamespace {
1167
+ return new ContextNamespace(this.services);
1168
+ }
1169
+
1170
+ /**
1171
+ * Wallet operations namespace
1172
+ *
1173
+ * Simplified wallet operations for address info, balance, and owned objects.
1174
+ *
1175
+ * @example
1176
+ * ```typescript
1177
+ * const address = await pdw.wallet.getAddress();
1178
+ * const balance = await pdw.wallet.getFormattedBalance();
1179
+ * const caps = await pdw.wallet.getMemoryCaps();
1180
+ * ```
1181
+ */
1182
+ get wallet(): WalletNamespace {
1183
+ return new WalletNamespace(this.services);
1184
+ }
1185
+
1186
+ // ===========================================================================
1187
+ // CONSOLIDATED NAMESPACES (New Unified API)
1188
+ // ===========================================================================
1189
+
1190
+ /**
1191
+ * AI operations namespace (consolidated)
1192
+ *
1193
+ * Unified API for all AI-powered operations:
1194
+ * - Embeddings (generate, batch, similarity)
1195
+ * - Classification (classify, shouldSave, importance)
1196
+ * - Chat with memory context
1197
+ *
1198
+ * @example
1199
+ * ```typescript
1200
+ * // Generate embeddings
1201
+ * const vector = await pdw.ai.embed('Hello world');
1202
+ *
1203
+ * // Classify content
1204
+ * const category = await pdw.ai.classify('I love TypeScript');
1205
+ *
1206
+ * // Chat with memory context
1207
+ * const session = await pdw.ai.chat.createSession();
1208
+ * const response = await pdw.ai.chat.send(session.id, 'What do you know about me?');
1209
+ * ```
1210
+ */
1211
+ get ai(): AINamespace {
1212
+ return new AINamespace(this.services);
1213
+ }
1214
+
1215
+ /**
1216
+ * Security operations namespace (consolidated)
1217
+ *
1218
+ * Unified API for encryption, permissions, and contexts:
1219
+ * - SEAL encryption/decryption
1220
+ * - App contexts (MemoryCap management)
1221
+ * - OAuth-style permissions
1222
+ *
1223
+ * @example
1224
+ * ```typescript
1225
+ * // Encrypt data
1226
+ * const { encryptedData } = await pdw.security.encrypt(data);
1227
+ *
1228
+ * // Decrypt data
1229
+ * const decrypted = await pdw.security.decrypt({ encryptedData });
1230
+ *
1231
+ * // Manage app contexts
1232
+ * const ctx = await pdw.security.context.getOrCreate('MEMO');
1233
+ *
1234
+ * // Grant permissions
1235
+ * await pdw.security.permissions.grant('APP_ID', ['read', 'write']);
1236
+ * ```
1237
+ */
1238
+ get security(): SecurityNamespace {
1239
+ return new SecurityNamespace(this.services);
1240
+ }
1241
+
1242
+ /**
1243
+ * Blockchain operations namespace (consolidated)
1244
+ *
1245
+ * Unified API for Sui blockchain operations:
1246
+ * - Transaction building and execution
1247
+ * - Wallet operations (balance, owned objects)
1248
+ *
1249
+ * @example
1250
+ * ```typescript
1251
+ * // Build and execute transaction
1252
+ * const tx = pdw.blockchain.tx.buildCreate({ ... });
1253
+ * const result = await pdw.blockchain.tx.execute(tx);
1254
+ *
1255
+ * // Check balance
1256
+ * const balance = await pdw.blockchain.wallet.getFormattedBalance();
1257
+ *
1258
+ * // Get owned objects
1259
+ * const memories = await pdw.blockchain.wallet.getMemories();
1260
+ * ```
1261
+ */
1262
+ get blockchain(): BlockchainNamespace {
1263
+ return new BlockchainNamespace(this.services);
1264
+ }
1265
+
1266
+ /**
1267
+ * Storage operations namespace (consolidated)
1268
+ *
1269
+ * Unified API for Walrus storage and caching:
1270
+ * - Upload/download data to Walrus
1271
+ * - In-memory LRU cache
1272
+ *
1273
+ * @example
1274
+ * ```typescript
1275
+ * // Upload to Walrus
1276
+ * const result = await pdw.storage.upload(data);
1277
+ *
1278
+ * // Download from Walrus
1279
+ * const data = await pdw.storage.download(blobId);
1280
+ *
1281
+ * // Use cache
1282
+ * pdw.storage.cache.set('key', value, 60000);
1283
+ * const cached = pdw.storage.cache.get('key');
1284
+ * ```
1285
+ */
1286
+ get storage(): ConsolidatedStorageNamespace {
1287
+ return new ConsolidatedStorageNamespace(this.services);
1288
+ }
1289
+ }