@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,616 +1,614 @@
1
- /**
2
- * SEAL Service Integration
3
- *
4
- * Production-ready SEAL service wrapper with comprehensive error handling,
5
- * session management, and performance analytics integration.
6
- */
7
-
8
- import { SuiClient } from '@mysten/sui/client';
9
- import { Transaction } from '@mysten/sui/transactions';
10
- import { fromHex, toHex, normalizeSuiAddress } from '@mysten/sui/utils';
11
- import { SealClient, SessionKey, EncryptedObject } from '@mysten/seal';
12
- import type {
13
- SealClientOptions,
14
- EncryptOptions,
15
- DecryptOptions,
16
- KeyServerConfig
17
- } from '@mysten/seal';
18
-
19
- // SEAL SDK types and interfaces
20
- interface SealConfig {
21
- suiClient: SuiClient;
22
- packageId: string;
23
- keyServerUrls: string[];
24
- keyServerObjectIds: string[];
25
- threshold: number;
26
- network: 'testnet' | 'mainnet';
27
- enableMetrics: boolean;
28
- retryAttempts: number;
29
- timeoutMs: number;
30
- }
31
-
32
- interface EncryptionOptions {
33
- data: Uint8Array;
34
- id: string;
35
- threshold?: number;
36
- }
37
-
38
- interface DecryptionOptions {
39
- encryptedObject: Uint8Array;
40
- sessionKey: any;
41
- txBytes: Uint8Array;
42
- }
43
-
44
- interface SessionConfig {
45
- address: string;
46
- packageId: string;
47
- ttlMin: number;
48
- }
49
-
50
- interface PerformanceMetric {
51
- operation: string;
52
- startTime: number;
53
- endTime: number;
54
- duration: number;
55
- success: boolean;
56
- errorType?: string;
57
- metadata?: any;
58
- }
59
-
60
- /**
61
- * SEAL Service - Production Implementation
62
- */
63
- export class SealService {
64
- private sealClient: SealClient | null = null;
65
- private sessionKey: SessionKey | null = null;
66
- private config: SealConfig;
67
- private performanceMetrics: PerformanceMetric[] = [];
68
- private activeSessions: Map<string, any> = new Map();
69
-
70
- constructor(config: SealConfig) {
71
- this.config = config;
72
- console.log('✅ SEAL SDK components loaded successfully');
73
- }
74
-
75
- /**
76
- * Initialize SEAL client with retry logic
77
- */
78
- async initializeClient(): Promise<void> {
79
- const metric = this.startMetric('seal_client_init');
80
-
81
- try {
82
- // Configure server configs from testnet servers
83
- const serverConfigs: KeyServerConfig[] = this.config.keyServerObjectIds.map((objectId, index) => ({
84
- objectId,
85
- weight: 1
86
- }));
87
-
88
- const sealClientOptions: SealClientOptions = {
89
- suiClient: this.config.suiClient,
90
- serverConfigs,
91
- verifyKeyServers: this.config.network === 'mainnet' // Only verify on mainnet
92
- };
93
-
94
- this.sealClient = new SealClient(sealClientOptions);
95
-
96
- this.completeMetric(metric, true, { serverCount: serverConfigs.length });
97
- console.log('✅ SEAL client initialized with', serverConfigs.length, 'servers');
98
-
99
- } catch (error) {
100
- this.completeMetric(metric, false, undefined, error);
101
- throw new Error(`Failed to initialize SEAL client: ${error}`);
102
- }
103
- }
104
-
105
- /**
106
- * Create and manage session key
107
- */
108
- async createSession(config: SessionConfig, signature?: Uint8Array | string): Promise<any> {
109
- const metric = this.startMetric('session_creation');
110
-
111
- try {
112
- const sessionKey = await SessionKey.create({
113
- address: config.address,
114
- packageId: config.packageId,
115
- ttlMin: config.ttlMin,
116
- suiClient: this.config.suiClient
117
- });
118
-
119
- const message = sessionKey.getPersonalMessage();
120
-
121
- // In production, signature would come from wallet
122
- if (signature) {
123
- // Convert Uint8Array to hex string if needed
124
- const signatureString = typeof signature === 'string' ? signature : toHex(signature);
125
- await sessionKey.setPersonalMessageSignature(signatureString);
126
- }
127
-
128
- // Store session for management
129
- this.activeSessions.set(config.address, {
130
- sessionKey,
131
- createdAt: Date.now(),
132
- ttl: config.ttlMin * 60 * 1000,
133
- address: config.address
134
- });
135
-
136
- this.completeMetric(metric, true, {
137
- address: config.address,
138
- ttlMin: config.ttlMin,
139
- messageLength: message.length
140
- });
141
-
142
- return { sessionKey, personalMessage: message };
143
-
144
- } catch (error) {
145
- this.completeMetric(metric, false, undefined, error);
146
- throw new Error(`Failed to create session: ${error}`);
147
- }
148
- }
149
-
150
- /**
151
- * Encrypt data with comprehensive error handling
152
- */
153
- async encryptData(options: EncryptionOptions): Promise<{ encryptedObject: Uint8Array; key: Uint8Array }> {
154
- const metric = this.startMetric('encryption');
155
-
156
- try {
157
- if (!this.sealClient) {
158
- await this.initializeClient();
159
- }
160
-
161
- if (!this.sealClient) {
162
- throw new Error('Failed to initialize SEAL client');
163
- }
164
-
165
- const threshold = options.threshold || this.config.threshold;
166
-
167
- // Validate threshold against available servers
168
- if (threshold > this.config.keyServerObjectIds.length) {
169
- throw new Error(`Threshold ${threshold} exceeds available servers ${this.config.keyServerObjectIds.length}`);
170
- }
171
-
172
- const result = await this.sealClient.encrypt({
173
- threshold,
174
- packageId: this.config.packageId,
175
- id: options.id,
176
- data: options.data
177
- });
178
-
179
- this.completeMetric(metric, true, {
180
- dataSize: options.data.length,
181
- threshold,
182
- encryptedSize: result.encryptedObject.length,
183
- keySize: result.key.length
184
- });
185
-
186
- return result;
187
-
188
- } catch (error) {
189
- this.completeMetric(metric, false, undefined, error);
190
-
191
- // Enhanced error handling
192
- const errorMessage = error instanceof Error ? error.message : String(error);
193
- if (errorMessage.includes('threshold')) {
194
- throw new Error(`Encryption threshold error: ${errorMessage}`);
195
- }
196
- if (errorMessage.includes('network')) {
197
- throw new Error(`Network error during encryption: ${errorMessage}`);
198
- }
199
-
200
- throw new Error(`Encryption failed: ${errorMessage}`);
201
- }
202
- }
203
-
204
- /**
205
- * Decrypt data with session management
206
- */
207
- async decryptData(options: DecryptionOptions): Promise<Uint8Array> {
208
- const metric = this.startMetric('decryption');
209
-
210
- try {
211
- if (!this.sealClient) {
212
- await this.initializeClient();
213
- }
214
-
215
- if (!this.sealClient) {
216
- throw new Error('Failed to initialize SEAL client');
217
- }
218
-
219
- // Add detailed debugging for SEAL decryption
220
- console.log('🔍 SEAL decrypt parameters:');
221
- console.log(` - Encrypted data type: ${typeof options.encryptedObject}`);
222
- console.log(` - Encrypted data length: ${options.encryptedObject.length}`);
223
- console.log(` - Session key type: ${typeof options.sessionKey}`);
224
- console.log(` - Session key constructor: ${options.sessionKey?.constructor?.name}`);
225
- console.log(` - Transaction bytes type: ${typeof options.txBytes}`);
226
- console.log(` - Transaction bytes length: ${options.txBytes.length}`);
227
-
228
- // Check if session key has expected methods
229
- if (options.sessionKey) {
230
- console.log(` - Session key methods: ${Object.getOwnPropertyNames(Object.getPrototypeOf(options.sessionKey)).join(', ')}`);
231
- }
232
-
233
- // Try SEAL decryption with error boundary
234
- let result;
235
- try {
236
- console.log('🔍 Attempting SEAL client decrypt...');
237
- result = await this.sealClient.decrypt({
238
- data: options.encryptedObject,
239
- sessionKey: options.sessionKey,
240
- txBytes: options.txBytes
241
- });
242
- console.log('🔍 SEAL decrypt completed without throwing');
243
- } catch (innerError) {
244
- console.log('🔍 SEAL decrypt threw an error:', innerError);
245
- throw innerError;
246
- }
247
-
248
- console.log(`🔍 SEAL decrypt result:`, {
249
- result,
250
- resultType: typeof result,
251
- resultLength: result ? result.length : 'undefined',
252
- hasResult: !!result,
253
- isUint8Array: result instanceof Uint8Array
254
- });
255
-
256
- if (!result) {
257
- throw new Error('SEAL decrypt returned undefined/null result');
258
- }
259
-
260
- this.completeMetric(metric, true, {
261
- encryptedSize: options.encryptedObject.length,
262
- decryptedSize: result ? result.length : 0
263
- });
264
-
265
- return result;
266
-
267
- } catch (error) {
268
- this.completeMetric(metric, false, undefined, error);
269
-
270
- // Enhanced error handling for decryption with detailed logging
271
- console.log('🚨 SEAL decrypt error details:', {
272
- error,
273
- errorType: typeof error,
274
- errorConstructor: error?.constructor?.name,
275
- errorMessage: error instanceof Error ? error.message : String(error),
276
- errorStack: error instanceof Error ? error.stack : 'No stack trace'
277
- });
278
-
279
- const errorMessage = error instanceof Error ? error.message : String(error);
280
- if (errorMessage.includes('access')) {
281
- throw new Error(`Access denied for decryption: ${errorMessage}`);
282
- }
283
- if (errorMessage.includes('session')) {
284
- throw new Error(`Session error during decryption: ${errorMessage}`);
285
- }
286
-
287
- throw new Error(`Decryption failed: ${errorMessage}`);
288
- }
289
- }
290
-
291
- /**
292
- * Create transaction for seal_approve using wallet-based allowlists
293
- * Matches Move signature: seal_approve(id: vector<u8>, requesting_wallet: address, ...)
294
- */
295
- async createSealApproveTransaction(
296
- id: string,
297
- userAddress: string,
298
- requestingWallet: string,
299
- accessRegistry?: string
300
- ): Promise<Uint8Array> {
301
- const metric = this.startMetric('transaction_creation');
302
-
303
- try {
304
- const tx = new Transaction();
305
-
306
- // Use the deployed AccessRegistry ID from environment or parameter
307
- const registryId = accessRegistry || process.env.ACCESS_REGISTRY_ID || "0xc2b8a9705516370e245f4d7ce58286ccbb56554edf31d1cc5a02155ac24d43c0";
308
- const normalizedWallet = normalizeSuiAddress(requestingWallet);
309
-
310
- // Wallet-based seal_approve call
311
- // entry fun seal_approve(id: vector<u8>, requesting_wallet: address, registry: &AccessRegistry, clock: &Clock, ctx: &TxContext)
312
- tx.moveCall({
313
- target: `${this.config.packageId}::seal_access_control::seal_approve`,
314
- arguments: [
315
- tx.pure.vector("u8", fromHex(id)), // Arg 1: Content ID (SEAL key ID)
316
- tx.pure.address(normalizedWallet), // Arg 2: Requesting wallet address
317
- tx.object(registryId), // Arg 3: AccessRegistry reference
318
- tx.object('0x6') // Arg 4: Clock object (system clock)
319
- ]
320
- });
321
-
322
- // Set the sender for the transaction
323
- tx.setSender(userAddress);
324
-
325
- const txBytes = await tx.build({
326
- client: this.config.suiClient,
327
- onlyTransactionKind: true
328
- });
329
-
330
- this.completeMetric(metric, true, {
331
- id,
332
- txSize: txBytes.length,
333
- registryId,
334
- clockId: '0x6',
335
- requestingWallet: normalizedWallet
336
- });
337
-
338
- return txBytes;
339
-
340
- } catch (error) {
341
- this.completeMetric(metric, false, undefined, error);
342
- const errorMessage = error instanceof Error ? error.message : String(error);
343
- throw new Error(`Failed to create transaction: ${errorMessage}`);
344
- }
345
- }
346
-
347
- /**
348
- * Build a seal_approve transaction for a specific requesting wallet
349
- */
350
- buildSealApproveTransaction(
351
- contentId: Uint8Array,
352
- requestingWallet: string,
353
- accessRegistry?: string
354
- ): Transaction {
355
- const metric = this.startMetric('transaction_creation_wallet');
356
-
357
- try {
358
- const tx = new Transaction();
359
-
360
- // Use the deployed AccessRegistry ID from environment or parameter
361
- const registryId = accessRegistry || process.env.ACCESS_REGISTRY_ID || "0x8088cc36468b53f210696f1c6b1a4de1b1666dd36a7c36f92c394ff1d342f6dd";
362
- const normalizedWallet = normalizeSuiAddress(requestingWallet);
363
-
364
- // Wallet-based seal_approve call
365
- tx.moveCall({
366
- target: `${this.config.packageId}::seal_access_control::seal_approve`,
367
- arguments: [
368
- tx.pure.vector('u8', Array.from(contentId)), // Content identifier
369
- tx.pure.address(normalizedWallet), // Requesting wallet address
370
- tx.object(registryId), // AccessRegistry reference
371
- tx.object('0x6') // Clock object (system clock)
372
- ]
373
- });
374
-
375
- this.completeMetric(metric, true, {
376
- requestingWallet: normalizedWallet,
377
- contentIdLength: contentId.length,
378
- registryId,
379
- clockId: '0x6'
380
- });
381
-
382
- return tx;
383
-
384
- } catch (error) {
385
- this.completeMetric(metric, false, undefined, error);
386
- const errorMessage = error instanceof Error ? error.message : String(error);
387
- throw new Error(`Failed to create transaction for wallet: ${errorMessage}`);
388
- }
389
- }
390
-
391
- /**
392
- * Parse encrypted object structure
393
- */
394
- parseEncryptedObject(encryptedBytes: Uint8Array): any {
395
- const metric = this.startMetric('object_parsing');
396
-
397
- try {
398
- const parsed = EncryptedObject.parse(encryptedBytes);
399
-
400
- this.completeMetric(metric, true, {
401
- version: parsed.version,
402
- packageId: parsed.packageId,
403
- threshold: parsed.threshold,
404
- dataSize: encryptedBytes.length
405
- });
406
-
407
- return parsed;
408
-
409
- } catch (error) {
410
- this.completeMetric(metric, false, undefined, error);
411
- throw new Error(`Failed to parse encrypted object: ${error}`);
412
- }
413
- }
414
-
415
- /**
416
- * Session management utilities
417
- */
418
- getActiveSession(address: string): any | null {
419
- const session = this.activeSessions.get(address);
420
- if (!session) return null;
421
-
422
- // Check if session is expired
423
- const now = Date.now();
424
- if (now > session.createdAt + session.ttl) {
425
- this.activeSessions.delete(address);
426
- return null;
427
- }
428
-
429
- return session.sessionKey;
430
- }
431
-
432
- cleanupExpiredSessions(): number {
433
- const now = Date.now();
434
- let cleanedCount = 0;
435
-
436
- for (const [address, session] of this.activeSessions.entries()) {
437
- if (now > session.createdAt + session.ttl) {
438
- this.activeSessions.delete(address);
439
- cleanedCount++;
440
- }
441
- }
442
-
443
- console.log(`🧹 Cleaned up ${cleanedCount} expired sessions`);
444
- return cleanedCount;
445
- }
446
-
447
- getSessionStats(): { total: number; expired: number; active: number } {
448
- const now = Date.now();
449
- let active = 0;
450
- let expired = 0;
451
-
452
- for (const session of this.activeSessions.values()) {
453
- if (now > session.createdAt + session.ttl) {
454
- expired++;
455
- } else {
456
- active++;
457
- }
458
- }
459
-
460
- return { total: this.activeSessions.size, active, expired };
461
- }
462
-
463
- /**
464
- * Performance metrics and analytics
465
- */
466
- private startMetric(operation: string): PerformanceMetric {
467
- const metric: PerformanceMetric = {
468
- operation,
469
- startTime: Date.now(),
470
- endTime: 0,
471
- duration: 0,
472
- success: false
473
- };
474
-
475
- return metric;
476
- }
477
-
478
- private completeMetric(metric: PerformanceMetric, success: boolean, metadata?: any, error?: any): void {
479
- metric.endTime = Date.now();
480
- metric.duration = metric.endTime - metric.startTime;
481
- metric.success = success;
482
- metric.metadata = metadata;
483
-
484
- if (error) {
485
- metric.errorType = error.constructor.name;
486
- }
487
-
488
- this.performanceMetrics.push(metric);
489
-
490
- // Limit metrics storage to prevent memory leaks
491
- if (this.performanceMetrics.length > 1000) {
492
- this.performanceMetrics.splice(0, 500); // Keep last 500 metrics
493
- }
494
- }
495
-
496
- getPerformanceMetrics(): PerformanceMetric[] {
497
- return [...this.performanceMetrics];
498
- }
499
-
500
- getPerformanceStats() {
501
- if (this.performanceMetrics.length === 0) {
502
- return { totalOperations: 0, averageTime: 0, successRate: 0 };
503
- }
504
-
505
- const successful = this.performanceMetrics.filter(m => m.success);
506
- const totalTime = this.performanceMetrics.reduce((sum, m) => sum + m.duration, 0);
507
-
508
- return {
509
- totalOperations: this.performanceMetrics.length,
510
- successfulOperations: successful.length,
511
- successRate: (successful.length / this.performanceMetrics.length) * 100,
512
- averageTime: totalTime / this.performanceMetrics.length,
513
- averageSuccessTime: successful.length > 0 ?
514
- successful.reduce((sum, m) => sum + m.duration, 0) / successful.length : 0,
515
- operationBreakdown: this.getOperationBreakdown()
516
- };
517
- }
518
-
519
- private getOperationBreakdown(): Record<string, any> {
520
- const breakdown: Record<string, any> = {};
521
-
522
- for (const metric of this.performanceMetrics) {
523
- if (!breakdown[metric.operation]) {
524
- breakdown[metric.operation] = {
525
- count: 0,
526
- totalTime: 0,
527
- successCount: 0,
528
- avgTime: 0,
529
- successRate: 0
530
- };
531
- }
532
-
533
- const op = breakdown[metric.operation];
534
- op.count++;
535
- op.totalTime += metric.duration;
536
- if (metric.success) op.successCount++;
537
- }
538
-
539
- // Calculate averages and rates
540
- for (const op of Object.values(breakdown) as any[]) {
541
- op.avgTime = op.totalTime / op.count;
542
- op.successRate = (op.successCount / op.count) * 100;
543
- }
544
-
545
- return breakdown;
546
- }
547
-
548
- /**
549
- * Health checks and diagnostics
550
- */
551
- async healthCheck(): Promise<{ status: 'healthy' | 'degraded' | 'unhealthy'; details: any }> {
552
- const checks = {
553
- sealClientInitialized: !!this.sealClient,
554
- activeSessions: this.activeSessions.size,
555
- performanceMetrics: this.performanceMetrics.length,
556
- keyServers: this.config.keyServerObjectIds.length
557
- };
558
-
559
- // Test key server connectivity
560
- const serverHealth = await Promise.allSettled(
561
- this.config.keyServerUrls.map(async (url) => {
562
- const response = await fetch(url, { signal: AbortSignal.timeout(5000) });
563
- return { url, status: response.status, ok: response.ok };
564
- })
565
- );
566
-
567
- const healthyServers = serverHealth.filter(result =>
568
- result.status === 'fulfilled' && result.value.ok
569
- ).length;
570
-
571
- let status: 'healthy' | 'degraded' | 'unhealthy';
572
- if (healthyServers === this.config.keyServerUrls.length) {
573
- status = 'healthy';
574
- } else if (healthyServers >= this.config.threshold) {
575
- status = 'degraded';
576
- } else {
577
- status = 'unhealthy';
578
- }
579
-
580
- return {
581
- status,
582
- details: {
583
- ...checks,
584
- serverHealth: {
585
- total: this.config.keyServerUrls.length,
586
- healthy: healthyServers,
587
- threshold: this.config.threshold
588
- },
589
- performanceStats: this.getPerformanceStats()
590
- }
591
- };
592
- }
593
-
594
- /**
595
- * Configuration and utilities
596
- */
597
- getConfiguration(): Partial<SealConfig> {
598
- return {
599
- packageId: this.config.packageId,
600
- network: this.config.network,
601
- threshold: this.config.threshold,
602
- enableMetrics: this.config.enableMetrics,
603
- retryAttempts: this.config.retryAttempts,
604
- timeoutMs: this.config.timeoutMs
605
- };
606
- }
607
-
608
- updateConfiguration(updates: Partial<SealConfig>): void {
609
- this.config = { ...this.config, ...updates };
610
-
611
- // Reinitialize client if critical settings changed
612
- if (updates.keyServerObjectIds || updates.suiClient) {
613
- this.sealClient = null;
614
- }
615
- }
1
+ /**
2
+ * SEAL Service Integration
3
+ *
4
+ * Production-ready SEAL service wrapper with comprehensive error handling,
5
+ * session management, and performance analytics integration.
6
+ */
7
+
8
+ import { SuiClient } from '@mysten/sui/client';
9
+ import { Transaction } from '@mysten/sui/transactions';
10
+ import { fromHex, toHex, normalizeSuiAddress } from '@mysten/sui/utils';
11
+ import { SealClient, SessionKey, EncryptedObject } from '@mysten/seal';
12
+ import type {
13
+ SealClientOptions,
14
+ EncryptOptions,
15
+ DecryptOptions,
16
+ KeyServerConfig
17
+ } from '@mysten/seal';
18
+
19
+ // SEAL SDK types and interfaces
20
+ interface SealConfig {
21
+ suiClient: SuiClient;
22
+ packageId: string;
23
+ keyServerUrls: string[];
24
+ keyServerObjectIds: string[];
25
+ threshold: number;
26
+ network: 'testnet' | 'mainnet';
27
+ enableMetrics: boolean;
28
+ retryAttempts: number;
29
+ timeoutMs: number;
30
+ }
31
+
32
+ interface EncryptionOptions {
33
+ data: Uint8Array;
34
+ id: string;
35
+ threshold?: number;
36
+ }
37
+
38
+ interface DecryptionOptions {
39
+ encryptedObject: Uint8Array;
40
+ sessionKey: any;
41
+ txBytes: Uint8Array;
42
+ }
43
+
44
+ interface SessionConfig {
45
+ address: string;
46
+ packageId: string;
47
+ ttlMin: number;
48
+ }
49
+
50
+ interface PerformanceMetric {
51
+ operation: string;
52
+ startTime: number;
53
+ endTime: number;
54
+ duration: number;
55
+ success: boolean;
56
+ errorType?: string;
57
+ metadata?: any;
58
+ }
59
+
60
+ /**
61
+ * SEAL Service - Production Implementation
62
+ */
63
+ export class SealService {
64
+ private sealClient: SealClient | null = null;
65
+ private sessionKey: SessionKey | null = null;
66
+ private config: SealConfig;
67
+ private performanceMetrics: PerformanceMetric[] = [];
68
+ private activeSessions: Map<string, any> = new Map();
69
+
70
+ constructor(config: SealConfig) {
71
+ this.config = config;
72
+ console.log('✅ SEAL SDK components loaded successfully');
73
+ }
74
+
75
+ /**
76
+ * Initialize SEAL client with retry logic
77
+ */
78
+ async initializeClient(): Promise<void> {
79
+ const metric = this.startMetric('seal_client_init');
80
+
81
+ try {
82
+ // Configure server configs from testnet servers
83
+ const serverConfigs: KeyServerConfig[] = this.config.keyServerObjectIds.map((objectId, index) => ({
84
+ objectId,
85
+ weight: 1
86
+ }));
87
+
88
+ const sealClientOptions: SealClientOptions = {
89
+ suiClient: this.config.suiClient,
90
+ serverConfigs,
91
+ verifyKeyServers: this.config.network === 'mainnet' // Only verify on mainnet
92
+ };
93
+
94
+ this.sealClient = new SealClient(sealClientOptions);
95
+
96
+ this.completeMetric(metric, true, { serverCount: serverConfigs.length });
97
+ console.log('✅ SEAL client initialized with', serverConfigs.length, 'servers');
98
+
99
+ } catch (error) {
100
+ this.completeMetric(metric, false, undefined, error);
101
+ throw new Error(`Failed to initialize SEAL client: ${error}`);
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Create and manage session key
107
+ */
108
+ async createSession(config: SessionConfig, signature?: Uint8Array | string): Promise<any> {
109
+ const metric = this.startMetric('session_creation');
110
+
111
+ try {
112
+ const sessionKey = await SessionKey.create({
113
+ address: config.address,
114
+ packageId: config.packageId,
115
+ ttlMin: config.ttlMin,
116
+ suiClient: this.config.suiClient
117
+ });
118
+
119
+ const message = sessionKey.getPersonalMessage();
120
+
121
+ // In production, signature would come from wallet
122
+ if (signature) {
123
+ // Convert Uint8Array to hex string if needed
124
+ const signatureString = typeof signature === 'string' ? signature : toHex(signature);
125
+ await sessionKey.setPersonalMessageSignature(signatureString);
126
+ }
127
+
128
+ // Store session for management
129
+ this.activeSessions.set(config.address, {
130
+ sessionKey,
131
+ createdAt: Date.now(),
132
+ ttl: config.ttlMin * 60 * 1000,
133
+ address: config.address
134
+ });
135
+
136
+ this.completeMetric(metric, true, {
137
+ address: config.address,
138
+ ttlMin: config.ttlMin,
139
+ messageLength: message.length
140
+ });
141
+
142
+ return { sessionKey, personalMessage: message };
143
+
144
+ } catch (error) {
145
+ this.completeMetric(metric, false, undefined, error);
146
+ throw new Error(`Failed to create session: ${error}`);
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Encrypt data with comprehensive error handling
152
+ */
153
+ async encryptData(options: EncryptionOptions): Promise<{ encryptedObject: Uint8Array; key: Uint8Array }> {
154
+ const metric = this.startMetric('encryption');
155
+
156
+ try {
157
+ if (!this.sealClient) {
158
+ await this.initializeClient();
159
+ }
160
+
161
+ if (!this.sealClient) {
162
+ throw new Error('Failed to initialize SEAL client');
163
+ }
164
+
165
+ const threshold = options.threshold || this.config.threshold;
166
+
167
+ // Validate threshold against available servers
168
+ if (threshold > this.config.keyServerObjectIds.length) {
169
+ throw new Error(`Threshold ${threshold} exceeds available servers ${this.config.keyServerObjectIds.length}`);
170
+ }
171
+
172
+ const result = await this.sealClient.encrypt({
173
+ threshold,
174
+ packageId: this.config.packageId,
175
+ id: options.id,
176
+ data: options.data
177
+ });
178
+
179
+ this.completeMetric(metric, true, {
180
+ dataSize: options.data.length,
181
+ threshold,
182
+ encryptedSize: result.encryptedObject.length,
183
+ keySize: result.key.length
184
+ });
185
+
186
+ return result;
187
+
188
+ } catch (error) {
189
+ this.completeMetric(metric, false, undefined, error);
190
+
191
+ // Enhanced error handling
192
+ const errorMessage = error instanceof Error ? error.message : String(error);
193
+ if (errorMessage.includes('threshold')) {
194
+ throw new Error(`Encryption threshold error: ${errorMessage}`);
195
+ }
196
+ if (errorMessage.includes('network')) {
197
+ throw new Error(`Network error during encryption: ${errorMessage}`);
198
+ }
199
+
200
+ throw new Error(`Encryption failed: ${errorMessage}`);
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Decrypt data with session management
206
+ */
207
+ async decryptData(options: DecryptionOptions): Promise<Uint8Array> {
208
+ const metric = this.startMetric('decryption');
209
+
210
+ try {
211
+ if (!this.sealClient) {
212
+ await this.initializeClient();
213
+ }
214
+
215
+ if (!this.sealClient) {
216
+ throw new Error('Failed to initialize SEAL client');
217
+ }
218
+
219
+ // Add detailed debugging for SEAL decryption
220
+ console.log('🔍 SEAL decrypt parameters:');
221
+ console.log(` - Encrypted data type: ${typeof options.encryptedObject}`);
222
+ console.log(` - Encrypted data length: ${options.encryptedObject.length}`);
223
+ console.log(` - Session key type: ${typeof options.sessionKey}`);
224
+ console.log(` - Session key constructor: ${options.sessionKey?.constructor?.name}`);
225
+ console.log(` - Transaction bytes type: ${typeof options.txBytes}`);
226
+ console.log(` - Transaction bytes length: ${options.txBytes.length}`);
227
+
228
+ // Check if session key has expected methods
229
+ if (options.sessionKey) {
230
+ console.log(` - Session key methods: ${Object.getOwnPropertyNames(Object.getPrototypeOf(options.sessionKey)).join(', ')}`);
231
+ }
232
+
233
+ // Try SEAL decryption with error boundary
234
+ let result;
235
+ try {
236
+ console.log('🔍 Attempting SEAL client decrypt...');
237
+ result = await this.sealClient.decrypt({
238
+ data: options.encryptedObject,
239
+ sessionKey: options.sessionKey,
240
+ txBytes: options.txBytes
241
+ });
242
+ console.log('🔍 SEAL decrypt completed without throwing');
243
+ } catch (innerError) {
244
+ console.log('🔍 SEAL decrypt threw an error:', innerError);
245
+ throw innerError;
246
+ }
247
+
248
+ console.log(`🔍 SEAL decrypt result:`, {
249
+ result,
250
+ resultType: typeof result,
251
+ resultLength: result ? result.length : 'undefined',
252
+ hasResult: !!result,
253
+ isUint8Array: result instanceof Uint8Array
254
+ });
255
+
256
+ if (!result) {
257
+ throw new Error('SEAL decrypt returned undefined/null result');
258
+ }
259
+
260
+ this.completeMetric(metric, true, {
261
+ encryptedSize: options.encryptedObject.length,
262
+ decryptedSize: result ? result.length : 0
263
+ });
264
+
265
+ return result;
266
+
267
+ } catch (error) {
268
+ this.completeMetric(metric, false, undefined, error);
269
+
270
+ // Enhanced error handling for decryption with detailed logging
271
+ console.log('🚨 SEAL decrypt error details:', {
272
+ error,
273
+ errorType: typeof error,
274
+ errorConstructor: error?.constructor?.name,
275
+ errorMessage: error instanceof Error ? error.message : String(error),
276
+ errorStack: error instanceof Error ? error.stack : 'No stack trace'
277
+ });
278
+
279
+ const errorMessage = error instanceof Error ? error.message : String(error);
280
+ if (errorMessage.includes('access')) {
281
+ throw new Error(`Access denied for decryption: ${errorMessage}`);
282
+ }
283
+ if (errorMessage.includes('session')) {
284
+ throw new Error(`Session error during decryption: ${errorMessage}`);
285
+ }
286
+
287
+ throw new Error(`Decryption failed: ${errorMessage}`);
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Create transaction for seal_approve using capability pattern
293
+ * Matches Move signature: seal_approve(cap: &MemoryCap, key_id: vector<u8>, ctx: &TxContext)
294
+ *
295
+ * @param keyId - SEAL key ID (hex string or bytes)
296
+ * @param userAddress - User's wallet address (sender)
297
+ * @param memoryCapId - Object ID of the MemoryCap
298
+ */
299
+ async createSealApproveTransaction(
300
+ keyId: string,
301
+ userAddress: string,
302
+ memoryCapId: string,
303
+ _accessRegistry?: string // Deprecated, kept for backward compatibility
304
+ ): Promise<Uint8Array> {
305
+ const metric = this.startMetric('transaction_creation');
306
+
307
+ try {
308
+ const tx = new Transaction();
309
+
310
+ // Capability-based seal_approve call
311
+ // CRITICAL: key_id MUST be first argument for SEAL key server!
312
+ // entry fun seal_approve(key_id: vector<u8>, cap: &MemoryCap, ctx: &TxContext)
313
+ tx.moveCall({
314
+ target: `${this.config.packageId}::capability::seal_approve`,
315
+ arguments: [
316
+ tx.pure.vector("u8", fromHex(keyId)), // Arg 1: SEAL key ID (MUST BE FIRST!)
317
+ tx.object(memoryCapId), // Arg 2: MemoryCap object reference
318
+ // ctx: &TxContext is auto-provided by Sui
319
+ ]
320
+ });
321
+
322
+ // Set the sender for the transaction
323
+ tx.setSender(userAddress);
324
+
325
+ const txBytes = await tx.build({
326
+ client: this.config.suiClient,
327
+ onlyTransactionKind: true
328
+ });
329
+
330
+ this.completeMetric(metric, true, {
331
+ keyId,
332
+ memoryCapId,
333
+ txSize: txBytes.length,
334
+ userAddress
335
+ });
336
+
337
+ return txBytes;
338
+
339
+ } catch (error) {
340
+ this.completeMetric(metric, false, undefined, error);
341
+ const errorMessage = error instanceof Error ? error.message : String(error);
342
+ throw new Error(`Failed to create transaction: ${errorMessage}`);
343
+ }
344
+ }
345
+
346
+ /**
347
+ * Build a seal_approve transaction using capability pattern
348
+ * Matches Move signature: seal_approve(cap: &MemoryCap, key_id: vector<u8>, ctx: &TxContext)
349
+ *
350
+ * @param keyId - SEAL key ID (bytes)
351
+ * @param memoryCapId - Object ID of the MemoryCap
352
+ */
353
+ buildSealApproveTransaction(
354
+ keyId: Uint8Array,
355
+ memoryCapId: string,
356
+ _accessRegistry?: string // Deprecated, kept for backward compatibility
357
+ ): Transaction {
358
+ const metric = this.startMetric('transaction_creation_wallet');
359
+
360
+ try {
361
+ const tx = new Transaction();
362
+
363
+ // Capability-based seal_approve call
364
+ // CRITICAL: key_id MUST be first argument for SEAL key server!
365
+ // entry fun seal_approve(key_id: vector<u8>, cap: &MemoryCap, ctx: &TxContext)
366
+ tx.moveCall({
367
+ target: `${this.config.packageId}::capability::seal_approve`,
368
+ arguments: [
369
+ tx.pure.vector('u8', Array.from(keyId)), // Arg 1: SEAL key ID (MUST BE FIRST!)
370
+ tx.object(memoryCapId), // Arg 2: MemoryCap object reference
371
+ // ctx: &TxContext is auto-provided by Sui
372
+ ]
373
+ });
374
+
375
+ this.completeMetric(metric, true, {
376
+ keyIdLength: keyId.length,
377
+ memoryCapId
378
+ });
379
+
380
+ return tx;
381
+
382
+ } catch (error) {
383
+ this.completeMetric(metric, false, undefined, error);
384
+ const errorMessage = error instanceof Error ? error.message : String(error);
385
+ throw new Error(`Failed to create transaction for capability: ${errorMessage}`);
386
+ }
387
+ }
388
+
389
+ /**
390
+ * Parse encrypted object structure
391
+ */
392
+ parseEncryptedObject(encryptedBytes: Uint8Array): any {
393
+ const metric = this.startMetric('object_parsing');
394
+
395
+ try {
396
+ const parsed = EncryptedObject.parse(encryptedBytes);
397
+
398
+ this.completeMetric(metric, true, {
399
+ version: parsed.version,
400
+ packageId: parsed.packageId,
401
+ threshold: parsed.threshold,
402
+ dataSize: encryptedBytes.length
403
+ });
404
+
405
+ return parsed;
406
+
407
+ } catch (error) {
408
+ this.completeMetric(metric, false, undefined, error);
409
+ throw new Error(`Failed to parse encrypted object: ${error}`);
410
+ }
411
+ }
412
+
413
+ /**
414
+ * Session management utilities
415
+ */
416
+ getActiveSession(address: string): any | null {
417
+ const session = this.activeSessions.get(address);
418
+ if (!session) return null;
419
+
420
+ // Check if session is expired
421
+ const now = Date.now();
422
+ if (now > session.createdAt + session.ttl) {
423
+ this.activeSessions.delete(address);
424
+ return null;
425
+ }
426
+
427
+ return session.sessionKey;
428
+ }
429
+
430
+ cleanupExpiredSessions(): number {
431
+ const now = Date.now();
432
+ let cleanedCount = 0;
433
+
434
+ for (const [address, session] of this.activeSessions.entries()) {
435
+ if (now > session.createdAt + session.ttl) {
436
+ this.activeSessions.delete(address);
437
+ cleanedCount++;
438
+ }
439
+ }
440
+
441
+ console.log(`🧹 Cleaned up ${cleanedCount} expired sessions`);
442
+ return cleanedCount;
443
+ }
444
+
445
+ getSessionStats(): { total: number; expired: number; active: number } {
446
+ const now = Date.now();
447
+ let active = 0;
448
+ let expired = 0;
449
+
450
+ for (const session of this.activeSessions.values()) {
451
+ if (now > session.createdAt + session.ttl) {
452
+ expired++;
453
+ } else {
454
+ active++;
455
+ }
456
+ }
457
+
458
+ return { total: this.activeSessions.size, active, expired };
459
+ }
460
+
461
+ /**
462
+ * Performance metrics and analytics
463
+ */
464
+ private startMetric(operation: string): PerformanceMetric {
465
+ const metric: PerformanceMetric = {
466
+ operation,
467
+ startTime: Date.now(),
468
+ endTime: 0,
469
+ duration: 0,
470
+ success: false
471
+ };
472
+
473
+ return metric;
474
+ }
475
+
476
+ private completeMetric(metric: PerformanceMetric, success: boolean, metadata?: any, error?: any): void {
477
+ metric.endTime = Date.now();
478
+ metric.duration = metric.endTime - metric.startTime;
479
+ metric.success = success;
480
+ metric.metadata = metadata;
481
+
482
+ if (error) {
483
+ metric.errorType = error.constructor.name;
484
+ }
485
+
486
+ this.performanceMetrics.push(metric);
487
+
488
+ // Limit metrics storage to prevent memory leaks
489
+ if (this.performanceMetrics.length > 1000) {
490
+ this.performanceMetrics.splice(0, 500); // Keep last 500 metrics
491
+ }
492
+ }
493
+
494
+ getPerformanceMetrics(): PerformanceMetric[] {
495
+ return [...this.performanceMetrics];
496
+ }
497
+
498
+ getPerformanceStats() {
499
+ if (this.performanceMetrics.length === 0) {
500
+ return { totalOperations: 0, averageTime: 0, successRate: 0 };
501
+ }
502
+
503
+ const successful = this.performanceMetrics.filter(m => m.success);
504
+ const totalTime = this.performanceMetrics.reduce((sum, m) => sum + m.duration, 0);
505
+
506
+ return {
507
+ totalOperations: this.performanceMetrics.length,
508
+ successfulOperations: successful.length,
509
+ successRate: (successful.length / this.performanceMetrics.length) * 100,
510
+ averageTime: totalTime / this.performanceMetrics.length,
511
+ averageSuccessTime: successful.length > 0 ?
512
+ successful.reduce((sum, m) => sum + m.duration, 0) / successful.length : 0,
513
+ operationBreakdown: this.getOperationBreakdown()
514
+ };
515
+ }
516
+
517
+ private getOperationBreakdown(): Record<string, any> {
518
+ const breakdown: Record<string, any> = {};
519
+
520
+ for (const metric of this.performanceMetrics) {
521
+ if (!breakdown[metric.operation]) {
522
+ breakdown[metric.operation] = {
523
+ count: 0,
524
+ totalTime: 0,
525
+ successCount: 0,
526
+ avgTime: 0,
527
+ successRate: 0
528
+ };
529
+ }
530
+
531
+ const op = breakdown[metric.operation];
532
+ op.count++;
533
+ op.totalTime += metric.duration;
534
+ if (metric.success) op.successCount++;
535
+ }
536
+
537
+ // Calculate averages and rates
538
+ for (const op of Object.values(breakdown) as any[]) {
539
+ op.avgTime = op.totalTime / op.count;
540
+ op.successRate = (op.successCount / op.count) * 100;
541
+ }
542
+
543
+ return breakdown;
544
+ }
545
+
546
+ /**
547
+ * Health checks and diagnostics
548
+ */
549
+ async healthCheck(): Promise<{ status: 'healthy' | 'degraded' | 'unhealthy'; details: any }> {
550
+ const checks = {
551
+ sealClientInitialized: !!this.sealClient,
552
+ activeSessions: this.activeSessions.size,
553
+ performanceMetrics: this.performanceMetrics.length,
554
+ keyServers: this.config.keyServerObjectIds.length
555
+ };
556
+
557
+ // Test key server connectivity
558
+ const serverHealth = await Promise.allSettled(
559
+ this.config.keyServerUrls.map(async (url) => {
560
+ const response = await fetch(url, { signal: AbortSignal.timeout(5000) });
561
+ return { url, status: response.status, ok: response.ok };
562
+ })
563
+ );
564
+
565
+ const healthyServers = serverHealth.filter(result =>
566
+ result.status === 'fulfilled' && result.value.ok
567
+ ).length;
568
+
569
+ let status: 'healthy' | 'degraded' | 'unhealthy';
570
+ if (healthyServers === this.config.keyServerUrls.length) {
571
+ status = 'healthy';
572
+ } else if (healthyServers >= this.config.threshold) {
573
+ status = 'degraded';
574
+ } else {
575
+ status = 'unhealthy';
576
+ }
577
+
578
+ return {
579
+ status,
580
+ details: {
581
+ ...checks,
582
+ serverHealth: {
583
+ total: this.config.keyServerUrls.length,
584
+ healthy: healthyServers,
585
+ threshold: this.config.threshold
586
+ },
587
+ performanceStats: this.getPerformanceStats()
588
+ }
589
+ };
590
+ }
591
+
592
+ /**
593
+ * Configuration and utilities
594
+ */
595
+ getConfiguration(): Partial<SealConfig> {
596
+ return {
597
+ packageId: this.config.packageId,
598
+ network: this.config.network,
599
+ threshold: this.config.threshold,
600
+ enableMetrics: this.config.enableMetrics,
601
+ retryAttempts: this.config.retryAttempts,
602
+ timeoutMs: this.config.timeoutMs
603
+ };
604
+ }
605
+
606
+ updateConfiguration(updates: Partial<SealConfig>): void {
607
+ this.config = { ...this.config, ...updates };
608
+
609
+ // Reinitialize client if critical settings changed
610
+ if (updates.keyServerObjectIds || updates.suiClient) {
611
+ this.sealClient = null;
612
+ }
613
+ }
616
614
  }