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