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.
- package/README.md +118 -0
- package/dist/components/Common/ErrorBoundary.d.ts +23 -0
- package/dist/components/Common/ErrorBoundary.d.ts.map +1 -0
- package/dist/components/Common/ErrorBoundary.js +93 -0
- package/dist/components/Common/ErrorBoundary.jsx +103 -0
- package/dist/components/Common/ErrorMessage.d.ts +8 -0
- package/dist/components/Common/ErrorMessage.d.ts.map +1 -0
- package/dist/components/Common/ErrorMessage.js +36 -0
- package/dist/components/Common/ErrorMessage.jsx +40 -0
- package/dist/components/Common/Loading.d.ts +8 -0
- package/dist/components/Common/Loading.d.ts.map +1 -0
- package/dist/components/Common/Loading.js +41 -0
- package/dist/components/Common/Loading.jsx +44 -0
- package/dist/components/Common/LoadingIndicator.d.ts +17 -0
- package/dist/components/Common/LoadingIndicator.d.ts.map +1 -0
- package/dist/components/Common/LoadingIndicator.js +95 -0
- package/dist/components/Common/LoadingIndicator.jsx +108 -0
- package/dist/components/Common/ProgramStatus.d.ts +3 -0
- package/dist/components/Common/ProgramStatus.d.ts.map +1 -0
- package/dist/components/Common/ProgramStatus.js +26 -0
- package/dist/components/Common/ProgramStatus.jsx +27 -0
- package/dist/components/Common/Skeleton.d.ts +39 -0
- package/dist/components/Common/Skeleton.d.ts.map +1 -0
- package/dist/components/Common/Skeleton.js +53 -0
- package/dist/components/Common/Skeleton.jsx +67 -0
- package/dist/components/Common/SkeletonScreen.d.ts +18 -0
- package/dist/components/Common/SkeletonScreen.d.ts.map +1 -0
- package/dist/components/Common/SkeletonScreen.js +98 -0
- package/dist/components/Common/SkeletonScreen.jsx +108 -0
- package/dist/components/Common/index.d.ts +11 -0
- package/dist/components/Common/index.d.ts.map +1 -0
- package/dist/components/Common/index.js +10 -0
- package/dist/components/Wallet/TransactionStatus.d.ts +11 -0
- package/dist/components/Wallet/TransactionStatus.d.ts.map +1 -0
- package/dist/components/Wallet/TransactionStatus.js +97 -0
- package/dist/components/Wallet/TransactionStatus.jsx +106 -0
- package/dist/components/Wallet/WalletBalance.d.ts +4 -0
- package/dist/components/Wallet/WalletBalance.d.ts.map +1 -0
- package/dist/components/Wallet/WalletBalance.js +82 -0
- package/dist/components/Wallet/WalletBalance.jsx +86 -0
- package/dist/components/Wallet/WalletButton.d.ts +3 -0
- package/dist/components/Wallet/WalletButton.d.ts.map +1 -0
- package/dist/components/Wallet/WalletButton.js +51 -0
- package/dist/components/Wallet/WalletButton.jsx +53 -0
- package/dist/components/Wallet/WalletConnectionModal.d.ts +8 -0
- package/dist/components/Wallet/WalletConnectionModal.d.ts.map +1 -0
- package/dist/components/Wallet/WalletConnectionModal.js +150 -0
- package/dist/components/Wallet/WalletConnectionModal.jsx +170 -0
- package/dist/components/Wallet/WalletProvider.d.ts +9 -0
- package/dist/components/Wallet/WalletProvider.d.ts.map +1 -0
- package/dist/components/Wallet/WalletProvider.js +70 -0
- package/dist/components/Wallet/WalletProvider.jsx +75 -0
- package/dist/components/Wallet/index.d.ts +9 -0
- package/dist/components/Wallet/index.d.ts.map +1 -0
- package/dist/components/Wallet/index.js +8 -0
- package/dist/components/index.d.ts +7 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +6 -0
- package/dist/hooks/index.d.ts +10 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +9 -0
- package/dist/hooks/useCache.d.ts +16 -0
- package/dist/hooks/useCache.d.ts.map +1 -0
- package/dist/hooks/useCache.js +67 -0
- package/dist/hooks/usePolling.d.ts +16 -0
- package/dist/hooks/usePolling.d.ts.map +1 -0
- package/dist/hooks/usePolling.js +79 -0
- package/dist/hooks/useProgram.d.ts +14 -0
- package/dist/hooks/useProgram.d.ts.map +1 -0
- package/dist/hooks/useProgram.js +88 -0
- package/dist/hooks/useTokenBalance.d.ts +16 -0
- package/dist/hooks/useTokenBalance.d.ts.map +1 -0
- package/dist/hooks/useTokenBalance.js +100 -0
- package/dist/hooks/useVaults.d.ts +23 -0
- package/dist/hooks/useVaults.d.ts.map +1 -0
- package/dist/hooks/useVaults.js +98 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/services/index.d.ts +7 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +6 -0
- package/dist/services/reconciliationService.d.ts +76 -0
- package/dist/services/reconciliationService.d.ts.map +1 -0
- package/dist/services/reconciliationService.js +216 -0
- package/dist/services/syncService.d.ts +51 -0
- package/dist/services/syncService.d.ts.map +1 -0
- package/dist/services/syncService.js +218 -0
- package/dist/types/index.d.ts +201 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +1 -0
- package/dist/utils/cacheManager.d.ts +73 -0
- package/dist/utils/cacheManager.d.ts.map +1 -0
- package/dist/utils/cacheManager.js +232 -0
- package/dist/utils/errorHandler.d.ts +76 -0
- package/dist/utils/errorHandler.d.ts.map +1 -0
- package/dist/utils/errorHandler.js +267 -0
- package/dist/utils/index.d.ts +12 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +11 -0
- package/dist/utils/performanceMonitor.d.ts +75 -0
- package/dist/utils/performanceMonitor.d.ts.map +1 -0
- package/dist/utils/performanceMonitor.js +197 -0
- package/dist/utils/rpcRetry.d.ts +12 -0
- package/dist/utils/rpcRetry.d.ts.map +1 -0
- package/dist/utils/rpcRetry.js +47 -0
- package/dist/utils/supabase.d.ts +198 -0
- package/dist/utils/supabase.d.ts.map +1 -0
- package/dist/utils/supabase.js +50 -0
- package/dist/utils/toastService.d.ts +52 -0
- package/dist/utils/toastService.d.ts.map +1 -0
- package/dist/utils/toastService.js +139 -0
- package/dist/utils/tokenUtils.d.ts +33 -0
- package/dist/utils/tokenUtils.d.ts.map +1 -0
- package/dist/utils/tokenUtils.js +66 -0
- package/dist/utils/validation.d.ts +35 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +83 -0
- package/package.json +45 -0
- package/src/components/Common/ErrorBoundary.tsx +135 -0
- package/src/components/Common/ErrorMessage.tsx +52 -0
- package/src/components/Common/Loading.tsx +56 -0
- package/src/components/Common/LoadingIndicator.tsx +143 -0
- package/src/components/Common/ProgramStatus.tsx +37 -0
- package/src/components/Common/Skeleton.tsx +83 -0
- package/src/components/Common/SkeletonScreen.tsx +166 -0
- package/src/components/Common/index.ts +10 -0
- package/src/components/Wallet/TransactionStatus.tsx +138 -0
- package/src/components/Wallet/WalletBalance.tsx +94 -0
- package/src/components/Wallet/WalletButton.tsx +65 -0
- package/src/components/Wallet/WalletConnectionModal.tsx +193 -0
- package/src/components/Wallet/WalletProvider.tsx +104 -0
- package/src/components/Wallet/index.ts +8 -0
- package/src/components/index.ts +6 -0
- package/src/hooks/index.ts +10 -0
- package/src/hooks/useCache.ts +87 -0
- package/src/hooks/usePolling.ts +98 -0
- package/src/hooks/useProgram.ts +93 -0
- package/src/hooks/useTokenBalance.ts +113 -0
- package/src/hooks/useVaults.ts +122 -0
- package/src/index.ts +23 -0
- package/src/services/index.ts +6 -0
- package/src/services/reconciliationService.ts +246 -0
- package/src/services/syncService.ts +238 -0
- package/src/types/index.ts +233 -0
- package/src/utils/cacheManager.ts +286 -0
- package/src/utils/errorHandler.ts +336 -0
- package/src/utils/index.ts +12 -0
- package/src/utils/performanceMonitor.ts +222 -0
- package/src/utils/rpcRetry.ts +55 -0
- package/src/utils/supabase.ts +253 -0
- package/src/utils/toastService.ts +166 -0
- package/src/utils/tokenUtils.ts +75 -0
- 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';
|