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