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