keynesol-shared 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 (154) hide show
  1. package/README.md +118 -0
  2. package/dist/components/Common/ErrorBoundary.d.ts +23 -0
  3. package/dist/components/Common/ErrorBoundary.d.ts.map +1 -0
  4. package/dist/components/Common/ErrorBoundary.js +93 -0
  5. package/dist/components/Common/ErrorBoundary.jsx +103 -0
  6. package/dist/components/Common/ErrorMessage.d.ts +8 -0
  7. package/dist/components/Common/ErrorMessage.d.ts.map +1 -0
  8. package/dist/components/Common/ErrorMessage.js +36 -0
  9. package/dist/components/Common/ErrorMessage.jsx +40 -0
  10. package/dist/components/Common/Loading.d.ts +8 -0
  11. package/dist/components/Common/Loading.d.ts.map +1 -0
  12. package/dist/components/Common/Loading.js +41 -0
  13. package/dist/components/Common/Loading.jsx +44 -0
  14. package/dist/components/Common/LoadingIndicator.d.ts +17 -0
  15. package/dist/components/Common/LoadingIndicator.d.ts.map +1 -0
  16. package/dist/components/Common/LoadingIndicator.js +95 -0
  17. package/dist/components/Common/LoadingIndicator.jsx +108 -0
  18. package/dist/components/Common/ProgramStatus.d.ts +3 -0
  19. package/dist/components/Common/ProgramStatus.d.ts.map +1 -0
  20. package/dist/components/Common/ProgramStatus.js +26 -0
  21. package/dist/components/Common/ProgramStatus.jsx +27 -0
  22. package/dist/components/Common/Skeleton.d.ts +39 -0
  23. package/dist/components/Common/Skeleton.d.ts.map +1 -0
  24. package/dist/components/Common/Skeleton.js +53 -0
  25. package/dist/components/Common/Skeleton.jsx +67 -0
  26. package/dist/components/Common/SkeletonScreen.d.ts +18 -0
  27. package/dist/components/Common/SkeletonScreen.d.ts.map +1 -0
  28. package/dist/components/Common/SkeletonScreen.js +98 -0
  29. package/dist/components/Common/SkeletonScreen.jsx +108 -0
  30. package/dist/components/Common/index.d.ts +11 -0
  31. package/dist/components/Common/index.d.ts.map +1 -0
  32. package/dist/components/Common/index.js +10 -0
  33. package/dist/components/Wallet/TransactionStatus.d.ts +11 -0
  34. package/dist/components/Wallet/TransactionStatus.d.ts.map +1 -0
  35. package/dist/components/Wallet/TransactionStatus.js +97 -0
  36. package/dist/components/Wallet/TransactionStatus.jsx +106 -0
  37. package/dist/components/Wallet/WalletBalance.d.ts +4 -0
  38. package/dist/components/Wallet/WalletBalance.d.ts.map +1 -0
  39. package/dist/components/Wallet/WalletBalance.js +82 -0
  40. package/dist/components/Wallet/WalletBalance.jsx +86 -0
  41. package/dist/components/Wallet/WalletButton.d.ts +3 -0
  42. package/dist/components/Wallet/WalletButton.d.ts.map +1 -0
  43. package/dist/components/Wallet/WalletButton.js +51 -0
  44. package/dist/components/Wallet/WalletButton.jsx +53 -0
  45. package/dist/components/Wallet/WalletConnectionModal.d.ts +8 -0
  46. package/dist/components/Wallet/WalletConnectionModal.d.ts.map +1 -0
  47. package/dist/components/Wallet/WalletConnectionModal.js +150 -0
  48. package/dist/components/Wallet/WalletConnectionModal.jsx +170 -0
  49. package/dist/components/Wallet/WalletProvider.d.ts +9 -0
  50. package/dist/components/Wallet/WalletProvider.d.ts.map +1 -0
  51. package/dist/components/Wallet/WalletProvider.js +70 -0
  52. package/dist/components/Wallet/WalletProvider.jsx +75 -0
  53. package/dist/components/Wallet/index.d.ts +9 -0
  54. package/dist/components/Wallet/index.d.ts.map +1 -0
  55. package/dist/components/Wallet/index.js +8 -0
  56. package/dist/components/index.d.ts +7 -0
  57. package/dist/components/index.d.ts.map +1 -0
  58. package/dist/components/index.js +6 -0
  59. package/dist/hooks/index.d.ts +10 -0
  60. package/dist/hooks/index.d.ts.map +1 -0
  61. package/dist/hooks/index.js +9 -0
  62. package/dist/hooks/useCache.d.ts +16 -0
  63. package/dist/hooks/useCache.d.ts.map +1 -0
  64. package/dist/hooks/useCache.js +67 -0
  65. package/dist/hooks/usePolling.d.ts +16 -0
  66. package/dist/hooks/usePolling.d.ts.map +1 -0
  67. package/dist/hooks/usePolling.js +79 -0
  68. package/dist/hooks/useProgram.d.ts +14 -0
  69. package/dist/hooks/useProgram.d.ts.map +1 -0
  70. package/dist/hooks/useProgram.js +88 -0
  71. package/dist/hooks/useTokenBalance.d.ts +16 -0
  72. package/dist/hooks/useTokenBalance.d.ts.map +1 -0
  73. package/dist/hooks/useTokenBalance.js +100 -0
  74. package/dist/hooks/useVaults.d.ts +23 -0
  75. package/dist/hooks/useVaults.d.ts.map +1 -0
  76. package/dist/hooks/useVaults.js +98 -0
  77. package/dist/index.d.ts +12 -0
  78. package/dist/index.d.ts.map +1 -0
  79. package/dist/index.js +17 -0
  80. package/dist/services/index.d.ts +7 -0
  81. package/dist/services/index.d.ts.map +1 -0
  82. package/dist/services/index.js +6 -0
  83. package/dist/services/reconciliationService.d.ts +76 -0
  84. package/dist/services/reconciliationService.d.ts.map +1 -0
  85. package/dist/services/reconciliationService.js +216 -0
  86. package/dist/services/syncService.d.ts +51 -0
  87. package/dist/services/syncService.d.ts.map +1 -0
  88. package/dist/services/syncService.js +218 -0
  89. package/dist/types/index.d.ts +201 -0
  90. package/dist/types/index.d.ts.map +1 -0
  91. package/dist/types/index.js +1 -0
  92. package/dist/utils/cacheManager.d.ts +73 -0
  93. package/dist/utils/cacheManager.d.ts.map +1 -0
  94. package/dist/utils/cacheManager.js +232 -0
  95. package/dist/utils/errorHandler.d.ts +76 -0
  96. package/dist/utils/errorHandler.d.ts.map +1 -0
  97. package/dist/utils/errorHandler.js +267 -0
  98. package/dist/utils/index.d.ts +12 -0
  99. package/dist/utils/index.d.ts.map +1 -0
  100. package/dist/utils/index.js +11 -0
  101. package/dist/utils/performanceMonitor.d.ts +75 -0
  102. package/dist/utils/performanceMonitor.d.ts.map +1 -0
  103. package/dist/utils/performanceMonitor.js +197 -0
  104. package/dist/utils/rpcRetry.d.ts +12 -0
  105. package/dist/utils/rpcRetry.d.ts.map +1 -0
  106. package/dist/utils/rpcRetry.js +47 -0
  107. package/dist/utils/supabase.d.ts +198 -0
  108. package/dist/utils/supabase.d.ts.map +1 -0
  109. package/dist/utils/supabase.js +50 -0
  110. package/dist/utils/toastService.d.ts +52 -0
  111. package/dist/utils/toastService.d.ts.map +1 -0
  112. package/dist/utils/toastService.js +139 -0
  113. package/dist/utils/tokenUtils.d.ts +33 -0
  114. package/dist/utils/tokenUtils.d.ts.map +1 -0
  115. package/dist/utils/tokenUtils.js +66 -0
  116. package/dist/utils/validation.d.ts +35 -0
  117. package/dist/utils/validation.d.ts.map +1 -0
  118. package/dist/utils/validation.js +83 -0
  119. package/package.json +45 -0
  120. package/src/components/Common/ErrorBoundary.tsx +135 -0
  121. package/src/components/Common/ErrorMessage.tsx +52 -0
  122. package/src/components/Common/Loading.tsx +56 -0
  123. package/src/components/Common/LoadingIndicator.tsx +143 -0
  124. package/src/components/Common/ProgramStatus.tsx +37 -0
  125. package/src/components/Common/Skeleton.tsx +83 -0
  126. package/src/components/Common/SkeletonScreen.tsx +166 -0
  127. package/src/components/Common/index.ts +10 -0
  128. package/src/components/Wallet/TransactionStatus.tsx +138 -0
  129. package/src/components/Wallet/WalletBalance.tsx +94 -0
  130. package/src/components/Wallet/WalletButton.tsx +65 -0
  131. package/src/components/Wallet/WalletConnectionModal.tsx +193 -0
  132. package/src/components/Wallet/WalletProvider.tsx +104 -0
  133. package/src/components/Wallet/index.ts +8 -0
  134. package/src/components/index.ts +6 -0
  135. package/src/hooks/index.ts +10 -0
  136. package/src/hooks/useCache.ts +87 -0
  137. package/src/hooks/usePolling.ts +98 -0
  138. package/src/hooks/useProgram.ts +93 -0
  139. package/src/hooks/useTokenBalance.ts +113 -0
  140. package/src/hooks/useVaults.ts +122 -0
  141. package/src/index.ts +23 -0
  142. package/src/services/index.ts +6 -0
  143. package/src/services/reconciliationService.ts +246 -0
  144. package/src/services/syncService.ts +238 -0
  145. package/src/types/index.ts +233 -0
  146. package/src/utils/cacheManager.ts +286 -0
  147. package/src/utils/errorHandler.ts +336 -0
  148. package/src/utils/index.ts +12 -0
  149. package/src/utils/performanceMonitor.ts +222 -0
  150. package/src/utils/rpcRetry.ts +55 -0
  151. package/src/utils/supabase.ts +253 -0
  152. package/src/utils/toastService.ts +166 -0
  153. package/src/utils/tokenUtils.ts +75 -0
  154. package/src/utils/validation.ts +107 -0
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Cache Manager
3
+ * Multi-level caching system for blockchain data
4
+ * Requirements: 6.2, 6.3
5
+ */
6
+ export type CacheStrategy = 'lru' | 'lfu' | 'fifo';
7
+ export interface CacheConfig {
8
+ ttl: number;
9
+ maxSize?: number;
10
+ strategy: CacheStrategy;
11
+ }
12
+ export interface CacheEntry<T> {
13
+ data: T;
14
+ timestamp: number;
15
+ hits: number;
16
+ ttl: number;
17
+ }
18
+ export interface CacheStats {
19
+ hits: number;
20
+ misses: number;
21
+ hitRate: number;
22
+ size: number;
23
+ oldestEntry: number;
24
+ newestEntry: number;
25
+ }
26
+ declare class CacheManager {
27
+ private caches;
28
+ private stats;
29
+ private configs;
30
+ /**
31
+ * Get cached data
32
+ */
33
+ get<T>(namespace: string, key: string): T | null;
34
+ /**
35
+ * Set cached data
36
+ */
37
+ set<T>(namespace: string, key: string, data: T, ttl?: number): void;
38
+ /**
39
+ * Invalidate cache entry or entire namespace
40
+ */
41
+ invalidate(namespace: string, key?: string): void;
42
+ /**
43
+ * Clear all caches or specific namespace
44
+ */
45
+ clear(namespace?: string): void;
46
+ /**
47
+ * Configure cache for namespace
48
+ */
49
+ configure(namespace: string, config: CacheConfig): void;
50
+ /**
51
+ * Get cache statistics
52
+ */
53
+ getStats(namespace: string): CacheStats | null;
54
+ /**
55
+ * Evict entry based on strategy
56
+ */
57
+ private evict;
58
+ /**
59
+ * Record cache hit
60
+ */
61
+ private recordHit;
62
+ /**
63
+ * Record cache miss
64
+ */
65
+ private recordMiss;
66
+ /**
67
+ * Clean expired entries (should be called periodically)
68
+ */
69
+ cleanExpired(): void;
70
+ }
71
+ export declare const cacheManager: CacheManager;
72
+ export {};
73
+ //# sourceMappingURL=cacheManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cacheManager.d.ts","sourceRoot":"","sources":["../../src/utils/cacheManager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;AAEnD,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,aAAa,CAAC;CACzB;AAED,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,IAAI,EAAE,CAAC,CAAC;IACR,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,cAAM,YAAY;IAChB,OAAO,CAAC,MAAM,CAAwD;IACtE,OAAO,CAAC,KAAK,CAA4D;IACzE,OAAO,CAAC,OAAO,CAAuC;IAEtD;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IA4BhD;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IA8BnE;;OAEG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAWjD;;OAEG;IACH,KAAK,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI;IAU/B;;OAEG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI;IAOvD;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAoB9C;;OAEG;IACH,OAAO,CAAC,KAAK;IAqDb;;OAEG;IACH,OAAO,CAAC,SAAS;IAOjB;;OAEG;IACH,OAAO,CAAC,UAAU;IAOlB;;OAEG;IACH,YAAY,IAAI,IAAI;CAYrB;AAGD,eAAO,MAAM,YAAY,cAAqB,CAAC"}
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Cache Manager
3
+ * Multi-level caching system for blockchain data
4
+ * Requirements: 6.2, 6.3
5
+ */
6
+ class CacheManager {
7
+ constructor() {
8
+ this.caches = new Map();
9
+ this.stats = new Map();
10
+ this.configs = new Map();
11
+ }
12
+ /**
13
+ * Get cached data
14
+ */
15
+ get(namespace, key) {
16
+ const cache = this.caches.get(namespace);
17
+ if (!cache) {
18
+ this.recordMiss(namespace);
19
+ return null;
20
+ }
21
+ const entry = cache.get(key);
22
+ if (!entry) {
23
+ this.recordMiss(namespace);
24
+ return null;
25
+ }
26
+ // Check if entry is expired
27
+ const now = Date.now();
28
+ if (now - entry.timestamp > entry.ttl) {
29
+ cache.delete(key);
30
+ this.recordMiss(namespace);
31
+ return null;
32
+ }
33
+ // Update hit count
34
+ entry.hits++;
35
+ this.recordHit(namespace);
36
+ return entry.data;
37
+ }
38
+ /**
39
+ * Set cached data
40
+ */
41
+ set(namespace, key, data, ttl) {
42
+ const config = this.configs.get(namespace);
43
+ if (!config) {
44
+ console.warn(`No config found for namespace: ${namespace}`);
45
+ return;
46
+ }
47
+ let cache = this.caches.get(namespace);
48
+ if (!cache) {
49
+ cache = new Map();
50
+ this.caches.set(namespace, cache);
51
+ this.stats.set(namespace, { hits: 0, misses: 0 });
52
+ }
53
+ const entryTtl = ttl || config.ttl;
54
+ const entry = {
55
+ data,
56
+ timestamp: Date.now(),
57
+ hits: 0,
58
+ ttl: entryTtl,
59
+ };
60
+ // Check max size and evict if needed
61
+ if (config.maxSize && cache.size >= config.maxSize) {
62
+ this.evict(namespace, cache, config.strategy);
63
+ }
64
+ cache.set(key, entry);
65
+ }
66
+ /**
67
+ * Invalidate cache entry or entire namespace
68
+ */
69
+ invalidate(namespace, key) {
70
+ const cache = this.caches.get(namespace);
71
+ if (!cache)
72
+ return;
73
+ if (key) {
74
+ cache.delete(key);
75
+ }
76
+ else {
77
+ cache.clear();
78
+ }
79
+ }
80
+ /**
81
+ * Clear all caches or specific namespace
82
+ */
83
+ clear(namespace) {
84
+ if (namespace) {
85
+ this.caches.delete(namespace);
86
+ this.stats.delete(namespace);
87
+ }
88
+ else {
89
+ this.caches.clear();
90
+ this.stats.clear();
91
+ }
92
+ }
93
+ /**
94
+ * Configure cache for namespace
95
+ */
96
+ configure(namespace, config) {
97
+ this.configs.set(namespace, config);
98
+ if (!this.stats.has(namespace)) {
99
+ this.stats.set(namespace, { hits: 0, misses: 0 });
100
+ }
101
+ }
102
+ /**
103
+ * Get cache statistics
104
+ */
105
+ getStats(namespace) {
106
+ const cache = this.caches.get(namespace);
107
+ const stats = this.stats.get(namespace);
108
+ if (!cache || !stats)
109
+ return null;
110
+ const entries = Array.from(cache.values());
111
+ const timestamps = entries.map(e => e.timestamp);
112
+ const totalRequests = stats.hits + stats.misses;
113
+ const hitRate = totalRequests > 0 ? stats.hits / totalRequests : 0;
114
+ return {
115
+ hits: stats.hits,
116
+ misses: stats.misses,
117
+ hitRate,
118
+ size: cache.size,
119
+ oldestEntry: timestamps.length > 0 ? Math.min(...timestamps) : 0,
120
+ newestEntry: timestamps.length > 0 ? Math.max(...timestamps) : 0,
121
+ };
122
+ }
123
+ /**
124
+ * Evict entry based on strategy
125
+ */
126
+ evict(namespace, cache, strategy) {
127
+ let entryToEvict = null;
128
+ switch (strategy) {
129
+ case 'lru': {
130
+ // Evict least recently used (oldest timestamp)
131
+ let oldestTime = Infinity;
132
+ const entries = Array.from(cache.entries());
133
+ for (const [key, entry] of entries) {
134
+ if (entry.timestamp < oldestTime) {
135
+ oldestTime = entry.timestamp;
136
+ entryToEvict = key;
137
+ }
138
+ }
139
+ break;
140
+ }
141
+ case 'lfu': {
142
+ // Evict least frequently used (lowest hits)
143
+ let lowestHits = Infinity;
144
+ const entries = Array.from(cache.entries());
145
+ for (const [key, entry] of entries) {
146
+ if (entry.hits < lowestHits) {
147
+ lowestHits = entry.hits;
148
+ entryToEvict = key;
149
+ }
150
+ }
151
+ break;
152
+ }
153
+ case 'fifo': {
154
+ // Evict first in (oldest timestamp, same as LRU for simplicity)
155
+ let oldestTime = Infinity;
156
+ const entries = Array.from(cache.entries());
157
+ for (const [key, entry] of entries) {
158
+ if (entry.timestamp < oldestTime) {
159
+ oldestTime = entry.timestamp;
160
+ entryToEvict = key;
161
+ }
162
+ }
163
+ break;
164
+ }
165
+ }
166
+ if (entryToEvict) {
167
+ cache.delete(entryToEvict);
168
+ }
169
+ }
170
+ /**
171
+ * Record cache hit
172
+ */
173
+ recordHit(namespace) {
174
+ const stats = this.stats.get(namespace);
175
+ if (stats) {
176
+ stats.hits++;
177
+ }
178
+ }
179
+ /**
180
+ * Record cache miss
181
+ */
182
+ recordMiss(namespace) {
183
+ const stats = this.stats.get(namespace);
184
+ if (stats) {
185
+ stats.misses++;
186
+ }
187
+ }
188
+ /**
189
+ * Clean expired entries (should be called periodically)
190
+ */
191
+ cleanExpired() {
192
+ const now = Date.now();
193
+ const namespaces = Array.from(this.caches.entries());
194
+ for (const [namespace, cache] of namespaces) {
195
+ const entries = Array.from(cache.entries());
196
+ for (const [key, entry] of entries) {
197
+ if (now - entry.timestamp > entry.ttl) {
198
+ cache.delete(key);
199
+ }
200
+ }
201
+ }
202
+ }
203
+ }
204
+ // Export singleton instance
205
+ export const cacheManager = new CacheManager();
206
+ // Configure default caches
207
+ cacheManager.configure('vaults', {
208
+ ttl: 30000, // 30 seconds
209
+ maxSize: 100,
210
+ strategy: 'lru',
211
+ });
212
+ cacheManager.configure('userStakes', {
213
+ ttl: 10000, // 10 seconds
214
+ maxSize: 1000,
215
+ strategy: 'lru',
216
+ });
217
+ cacheManager.configure('platformMetrics', {
218
+ ttl: 60000, // 1 minute
219
+ maxSize: 50,
220
+ strategy: 'lru',
221
+ });
222
+ cacheManager.configure('transactions', {
223
+ ttl: 60000, // 1 minute
224
+ maxSize: 500,
225
+ strategy: 'lru',
226
+ });
227
+ // Clean expired entries every 5 minutes
228
+ if (typeof window !== 'undefined') {
229
+ setInterval(() => {
230
+ cacheManager.cleanExpired();
231
+ }, 5 * 60 * 1000);
232
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Error Handler Utility
3
+ * Comprehensive error handling system with classification, retry logic, and user-friendly messages
4
+ * Requirements: 4.1, 4.2, 4.3, 4.4, 4.5
5
+ */
6
+ export declare enum ErrorCategory {
7
+ NETWORK = "network",
8
+ BLOCKCHAIN = "blockchain",
9
+ VALIDATION = "validation",
10
+ AUTHORIZATION = "authorization",
11
+ DATA = "data",
12
+ UNKNOWN = "unknown"
13
+ }
14
+ export interface ErrorHandlerConfig {
15
+ retryAttempts?: number;
16
+ retryDelay?: number;
17
+ exponentialBackoff?: boolean;
18
+ onRetry?: (attempt: number, error: Error) => void;
19
+ }
20
+ export interface ErrorLog {
21
+ timestamp: number;
22
+ level: 'error' | 'warning' | 'info';
23
+ context: string;
24
+ message: string;
25
+ stack?: string;
26
+ metadata?: Record<string, any>;
27
+ userId?: string;
28
+ category: ErrorCategory;
29
+ }
30
+ declare class ErrorHandler {
31
+ private logs;
32
+ private maxLogs;
33
+ /**
34
+ * Classify error into category
35
+ */
36
+ classifyError(error: Error): ErrorCategory;
37
+ /**
38
+ * Get user-friendly error message
39
+ */
40
+ getErrorMessage(error: Error): string;
41
+ /**
42
+ * Get recovery suggestion based on error category
43
+ */
44
+ getRecoverySuggestion(error: Error): string | null;
45
+ /**
46
+ * Log error with context
47
+ */
48
+ logError(error: Error, context: string, metadata?: Record<string, any>): void;
49
+ /**
50
+ * Wrap async function with error handling and retry logic
51
+ */
52
+ wrapAsync<T>(fn: () => Promise<T>, config?: ErrorHandlerConfig): Promise<T>;
53
+ /**
54
+ * Handle error with appropriate recovery strategy
55
+ */
56
+ handleError(error: Error, context: string, config?: ErrorHandlerConfig): void;
57
+ /**
58
+ * Get recent errors for debugging
59
+ */
60
+ getRecentErrors(count?: number): ErrorLog[];
61
+ /**
62
+ * Clear error logs
63
+ */
64
+ clearLogs(): void;
65
+ /**
66
+ * Get current user ID (if available)
67
+ */
68
+ private getCurrentUserId;
69
+ /**
70
+ * Send error to monitoring service
71
+ */
72
+ private sendToMonitoring;
73
+ }
74
+ export declare const errorHandler: ErrorHandler;
75
+ export {};
76
+ //# sourceMappingURL=errorHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorHandler.d.ts","sourceRoot":"","sources":["../../src/utils/errorHandler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,oBAAY,aAAa;IACvB,OAAO,YAAY;IACnB,UAAU,eAAe;IACzB,UAAU,eAAe;IACzB,aAAa,kBAAkB;IAC/B,IAAI,SAAS;IACb,OAAO,YAAY;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,aAAa,CAAC;CACzB;AAED,cAAM,YAAY;IAChB,OAAO,CAAC,IAAI,CAAkB;IAC9B,OAAO,CAAC,OAAO,CAAgB;IAE/B;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,aAAa;IAgE1C;;OAEG;IACH,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM;IAiDrC;;OAEG;IACH,qBAAqB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,IAAI;IAwBlD;;OAEG;IACH,QAAQ,CACN,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC7B,IAAI;IA8BP;;OAEG;IACG,SAAS,CAAC,CAAC,EACf,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,MAAM,CAAC,EAAE,kBAAkB,GAC1B,OAAO,CAAC,CAAC,CAAC;IAgDb;;OAEG;IACH,WAAW,CACT,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,kBAAkB,GAC1B,IAAI;IAYP;;OAEG;IACH,eAAe,CAAC,KAAK,GAAE,MAAW,GAAG,QAAQ,EAAE;IAI/C;;OAEG;IACH,SAAS,IAAI,IAAI;IAIjB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IASxB;;OAEG;YACW,gBAAgB;CAU/B;AAGD,eAAO,MAAM,YAAY,cAAqB,CAAC"}
@@ -0,0 +1,267 @@
1
+ /**
2
+ * Error Handler Utility
3
+ * Comprehensive error handling system with classification, retry logic, and user-friendly messages
4
+ * Requirements: 4.1, 4.2, 4.3, 4.4, 4.5
5
+ */
6
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
7
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
8
+ return new (P || (P = Promise))(function (resolve, reject) {
9
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
10
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
11
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
12
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
13
+ });
14
+ };
15
+ export var ErrorCategory;
16
+ (function (ErrorCategory) {
17
+ ErrorCategory["NETWORK"] = "network";
18
+ ErrorCategory["BLOCKCHAIN"] = "blockchain";
19
+ ErrorCategory["VALIDATION"] = "validation";
20
+ ErrorCategory["AUTHORIZATION"] = "authorization";
21
+ ErrorCategory["DATA"] = "data";
22
+ ErrorCategory["UNKNOWN"] = "unknown";
23
+ })(ErrorCategory || (ErrorCategory = {}));
24
+ class ErrorHandler {
25
+ constructor() {
26
+ this.logs = [];
27
+ this.maxLogs = 1000;
28
+ }
29
+ /**
30
+ * Classify error into category
31
+ */
32
+ classifyError(error) {
33
+ var _a;
34
+ const message = error.message.toLowerCase();
35
+ const stack = ((_a = error.stack) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || '';
36
+ // Network errors
37
+ if (message.includes('network') ||
38
+ message.includes('fetch') ||
39
+ message.includes('timeout') ||
40
+ message.includes('connection') ||
41
+ message.includes('rpc') ||
42
+ message.includes('failed to fetch')) {
43
+ return ErrorCategory.NETWORK;
44
+ }
45
+ // Blockchain errors
46
+ if (message.includes('transaction') ||
47
+ message.includes('insufficient') ||
48
+ message.includes('program') ||
49
+ message.includes('account') ||
50
+ message.includes('anchor') ||
51
+ message.includes('solana')) {
52
+ return ErrorCategory.BLOCKCHAIN;
53
+ }
54
+ // Validation errors
55
+ if (message.includes('invalid') ||
56
+ message.includes('required') ||
57
+ message.includes('must be') ||
58
+ message.includes('out of range') ||
59
+ message.includes('validation')) {
60
+ return ErrorCategory.VALIDATION;
61
+ }
62
+ // Authorization errors
63
+ if (message.includes('unauthorized') ||
64
+ message.includes('permission') ||
65
+ message.includes('access denied') ||
66
+ message.includes('wallet not connected') ||
67
+ message.includes('signature')) {
68
+ return ErrorCategory.AUTHORIZATION;
69
+ }
70
+ // Data errors
71
+ if (message.includes('parse') ||
72
+ message.includes('json') ||
73
+ message.includes('data') ||
74
+ message.includes('supabase') ||
75
+ message.includes('database')) {
76
+ return ErrorCategory.DATA;
77
+ }
78
+ return ErrorCategory.UNKNOWN;
79
+ }
80
+ /**
81
+ * Get user-friendly error message
82
+ */
83
+ getErrorMessage(error) {
84
+ const category = this.classifyError(error);
85
+ const message = error.message;
86
+ switch (category) {
87
+ case ErrorCategory.NETWORK:
88
+ if (message.includes('timeout')) {
89
+ return 'Connection timeout. Please check your internet connection and try again.';
90
+ }
91
+ if (message.includes('rpc')) {
92
+ return 'Blockchain connection failed. Please try again in a moment.';
93
+ }
94
+ return 'Network error. Please check your connection and try again.';
95
+ case ErrorCategory.BLOCKCHAIN:
96
+ if (message.includes('insufficient')) {
97
+ return 'Insufficient balance. Please add more tokens to your wallet.';
98
+ }
99
+ if (message.includes('user rejected')) {
100
+ return 'Transaction cancelled.';
101
+ }
102
+ if (message.includes('slippage')) {
103
+ return 'Transaction failed due to price movement. Please try again.';
104
+ }
105
+ if (message.includes('simulation')) {
106
+ return 'Transaction simulation failed. Please check your inputs and try again.';
107
+ }
108
+ return 'Transaction failed. Please try again or contact support if the issue persists.';
109
+ case ErrorCategory.VALIDATION:
110
+ return message || 'Invalid input. Please check your values and try again.';
111
+ case ErrorCategory.AUTHORIZATION:
112
+ if (message.includes('wallet not connected')) {
113
+ return 'Please connect your wallet to continue.';
114
+ }
115
+ if (message.includes('unauthorized')) {
116
+ return 'You do not have permission to perform this action.';
117
+ }
118
+ return 'Authorization required. Please connect your wallet.';
119
+ case ErrorCategory.DATA:
120
+ return 'Data error. Please refresh the page and try again.';
121
+ default:
122
+ return message || 'An unexpected error occurred. Please try again.';
123
+ }
124
+ }
125
+ /**
126
+ * Get recovery suggestion based on error category
127
+ */
128
+ getRecoverySuggestion(error) {
129
+ const category = this.classifyError(error);
130
+ switch (category) {
131
+ case ErrorCategory.NETWORK:
132
+ return 'Check your internet connection and try again. If the problem persists, try refreshing the page.';
133
+ case ErrorCategory.BLOCKCHAIN:
134
+ return 'Verify your wallet has sufficient balance and try again. If the issue continues, check the transaction on Solana Explorer.';
135
+ case ErrorCategory.VALIDATION:
136
+ return 'Please review your inputs and ensure all required fields are filled correctly.';
137
+ case ErrorCategory.AUTHORIZATION:
138
+ return 'Please connect your wallet and ensure you have the necessary permissions.';
139
+ case ErrorCategory.DATA:
140
+ return 'Try refreshing the page. If the problem persists, contact support.';
141
+ default:
142
+ return null;
143
+ }
144
+ }
145
+ /**
146
+ * Log error with context
147
+ */
148
+ logError(error, context, metadata) {
149
+ var _a, _b;
150
+ const category = this.classifyError(error);
151
+ const errorLog = {
152
+ timestamp: Date.now(),
153
+ level: 'error',
154
+ context,
155
+ message: error.message,
156
+ stack: error.stack,
157
+ metadata,
158
+ userId: this.getCurrentUserId(),
159
+ category,
160
+ };
161
+ // Add to in-memory log
162
+ this.logs.push(errorLog);
163
+ if (this.logs.length > this.maxLogs) {
164
+ this.logs.shift();
165
+ }
166
+ // Log to console in development
167
+ if (typeof process !== 'undefined' && ((_a = process.env) === null || _a === void 0 ? void 0 : _a.NODE_ENV) === 'development') {
168
+ console.error(`[${context}]`, error, metadata);
169
+ }
170
+ // Send to monitoring service in production
171
+ if (typeof process !== 'undefined' && ((_b = process.env) === null || _b === void 0 ? void 0 : _b.NODE_ENV) === 'production') {
172
+ this.sendToMonitoring(errorLog);
173
+ }
174
+ }
175
+ /**
176
+ * Wrap async function with error handling and retry logic
177
+ */
178
+ wrapAsync(fn, config) {
179
+ return __awaiter(this, void 0, void 0, function* () {
180
+ const { retryAttempts = 3, retryDelay = 1000, exponentialBackoff = true, onRetry, } = config || {};
181
+ let lastError;
182
+ let attempt = 0;
183
+ while (attempt < retryAttempts) {
184
+ try {
185
+ return yield fn();
186
+ }
187
+ catch (error) {
188
+ lastError = error;
189
+ attempt++;
190
+ // Don't retry validation errors
191
+ if (this.classifyError(lastError) === ErrorCategory.VALIDATION) {
192
+ throw lastError;
193
+ }
194
+ // Don't retry on final attempt
195
+ if (attempt >= retryAttempts) {
196
+ break;
197
+ }
198
+ // Calculate delay with exponential backoff
199
+ const delay = exponentialBackoff
200
+ ? retryDelay * Math.pow(2, attempt - 1)
201
+ : retryDelay;
202
+ // Add jitter to prevent thundering herd
203
+ const jitter = Math.random() * 500;
204
+ // Call retry callback
205
+ if (onRetry) {
206
+ onRetry(attempt, lastError);
207
+ }
208
+ yield new Promise((resolve) => setTimeout(resolve, delay + jitter));
209
+ }
210
+ }
211
+ throw lastError;
212
+ });
213
+ }
214
+ /**
215
+ * Handle error with appropriate recovery strategy
216
+ */
217
+ handleError(error, context, config) {
218
+ this.logError(error, context);
219
+ const category = this.classifyError(error);
220
+ const message = this.getErrorMessage(error);
221
+ const suggestion = this.getRecoverySuggestion(error);
222
+ // In a real implementation, this would trigger toast notifications
223
+ // For now, we'll just log it
224
+ console.error(`[${context}] ${message}`, suggestion ? `Suggestion: ${suggestion}` : '');
225
+ }
226
+ /**
227
+ * Get recent errors for debugging
228
+ */
229
+ getRecentErrors(count = 10) {
230
+ return this.logs.slice(-count);
231
+ }
232
+ /**
233
+ * Clear error logs
234
+ */
235
+ clearLogs() {
236
+ this.logs = [];
237
+ }
238
+ /**
239
+ * Get current user ID (if available)
240
+ */
241
+ getCurrentUserId() {
242
+ // In a real implementation, this would get the current user's public key
243
+ if (typeof window !== 'undefined') {
244
+ // Could get from wallet connection state
245
+ return undefined;
246
+ }
247
+ return undefined;
248
+ }
249
+ /**
250
+ * Send error to monitoring service
251
+ */
252
+ sendToMonitoring(errorLog) {
253
+ return __awaiter(this, void 0, void 0, function* () {
254
+ // In production, send to monitoring service (e.g., Sentry, LogRocket)
255
+ // For now, we'll just store it locally
256
+ try {
257
+ // Could send to Supabase or external service
258
+ // await supabase.from('error_logs').insert(errorLog);
259
+ }
260
+ catch (e) {
261
+ console.error('Failed to send error to monitoring:', e);
262
+ }
263
+ });
264
+ }
265
+ }
266
+ // Export singleton instance
267
+ export const errorHandler = new ErrorHandler();
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Utils Index
3
+ * Export all utility functions
4
+ */
5
+ export * from './errorHandler';
6
+ export * from './cacheManager';
7
+ export * from './tokenUtils';
8
+ export * from './validation';
9
+ export * from './toastService';
10
+ export * from './rpcRetry';
11
+ export * from './performanceMonitor';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Utils Index
3
+ * Export all utility functions
4
+ */
5
+ export * from './errorHandler';
6
+ export * from './cacheManager';
7
+ export * from './tokenUtils';
8
+ export * from './validation';
9
+ export * from './toastService';
10
+ export * from './rpcRetry';
11
+ export * from './performanceMonitor';