@oxyhq/services 5.9.1 → 5.9.3
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 +1 -33
- package/lib/commonjs/core/OxyServices.js +159 -0
- package/lib/commonjs/core/OxyServices.js.map +1 -0
- package/lib/commonjs/core/OxyServicesMain.js +51 -0
- package/lib/commonjs/core/OxyServicesMain.js.map +1 -0
- package/lib/commonjs/core/analytics/AnalyticsService.js +67 -0
- package/lib/commonjs/core/analytics/AnalyticsService.js.map +1 -0
- package/lib/commonjs/core/auth/AuthService.js +526 -0
- package/lib/commonjs/core/auth/AuthService.js.map +1 -0
- package/lib/commonjs/core/devices/DeviceService.js +61 -0
- package/lib/commonjs/core/devices/DeviceService.js.map +1 -0
- package/lib/commonjs/core/files/FileService.js +176 -0
- package/lib/commonjs/core/files/FileService.js.map +1 -0
- package/lib/commonjs/core/index.js +103 -1707
- package/lib/commonjs/core/index.js.map +1 -1
- package/lib/commonjs/core/karma/KarmaService.js +100 -0
- package/lib/commonjs/core/karma/KarmaService.js.map +1 -0
- package/lib/commonjs/core/locations/LocationService.js +131 -0
- package/lib/commonjs/core/locations/LocationService.js.map +1 -0
- package/lib/commonjs/core/payments/PaymentService.js +124 -0
- package/lib/commonjs/core/payments/PaymentService.js.map +1 -0
- package/lib/commonjs/core/users/UserService.js +234 -0
- package/lib/commonjs/core/users/UserService.js.map +1 -0
- package/lib/commonjs/index.js +164 -2
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/models/session.js +2 -0
- package/lib/{module/types/middleware.js.map → commonjs/models/session.js.map} +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +28 -24
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +2 -2
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FileManagementScreen.js +12 -12
- package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ProfileScreen.js +2 -2
- package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignInScreen.js +1 -1
- package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
- package/lib/commonjs/ui/stores/followStore.js +4 -4
- package/lib/commonjs/ui/stores/followStore.js.map +1 -1
- package/lib/commonjs/utils/apiUtils.js +93 -0
- package/lib/commonjs/utils/apiUtils.js.map +1 -0
- package/lib/commonjs/utils/asyncUtils.js +219 -0
- package/lib/commonjs/utils/asyncUtils.js.map +1 -0
- package/lib/commonjs/utils/errorUtils.js +148 -0
- package/lib/commonjs/utils/errorUtils.js.map +1 -0
- package/lib/commonjs/utils/hookUtils.js +399 -0
- package/lib/commonjs/utils/hookUtils.js.map +1 -0
- package/lib/commonjs/utils/loggerUtils.js +160 -0
- package/lib/commonjs/utils/loggerUtils.js.map +1 -0
- package/lib/commonjs/utils/validationUtils.js +174 -0
- package/lib/commonjs/utils/validationUtils.js.map +1 -0
- package/lib/module/core/OxyServices.js +153 -0
- package/lib/module/core/OxyServices.js.map +1 -0
- package/lib/module/core/OxyServicesMain.js +47 -0
- package/lib/module/core/OxyServicesMain.js.map +1 -0
- package/lib/module/core/analytics/AnalyticsService.js +62 -0
- package/lib/module/core/analytics/AnalyticsService.js.map +1 -0
- package/lib/module/core/auth/AuthService.js +521 -0
- package/lib/module/core/auth/AuthService.js.map +1 -0
- package/lib/module/core/devices/DeviceService.js +57 -0
- package/lib/module/core/devices/DeviceService.js.map +1 -0
- package/lib/module/core/files/FileService.js +171 -0
- package/lib/module/core/files/FileService.js.map +1 -0
- package/lib/module/core/index.js +25 -1694
- package/lib/module/core/index.js.map +1 -1
- package/lib/module/core/karma/KarmaService.js +95 -0
- package/lib/module/core/karma/KarmaService.js.map +1 -0
- package/lib/module/core/locations/LocationService.js +127 -0
- package/lib/module/core/locations/LocationService.js.map +1 -0
- package/lib/module/core/payments/PaymentService.js +119 -0
- package/lib/module/core/payments/PaymentService.js.map +1 -0
- package/lib/module/core/users/UserService.js +230 -0
- package/lib/module/core/users/UserService.js.map +1 -0
- package/lib/module/index.js +8 -4
- package/lib/module/index.js.map +1 -1
- package/lib/module/models/session.js +2 -0
- package/lib/{commonjs/types/middleware.js.map → module/models/session.js.map} +1 -1
- package/lib/module/ui/context/OxyContext.js +28 -24
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/screens/AccountSwitcherScreen.js +2 -2
- package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/module/ui/screens/FileManagementScreen.js +12 -12
- package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/ProfileScreen.js +2 -2
- package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/SignInScreen.js +1 -1
- package/lib/module/ui/screens/SignInScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaCenterScreen.js +1 -1
- package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js +1 -1
- package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaRulesScreen.js +1 -1
- package/lib/module/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
- package/lib/module/ui/stores/followStore.js +4 -4
- package/lib/module/ui/stores/followStore.js.map +1 -1
- package/lib/module/utils/apiUtils.js +85 -0
- package/lib/module/utils/apiUtils.js.map +1 -0
- package/lib/module/utils/asyncUtils.js +202 -0
- package/lib/module/utils/asyncUtils.js.map +1 -0
- package/lib/module/utils/errorUtils.js +139 -0
- package/lib/module/utils/errorUtils.js.map +1 -0
- package/lib/module/utils/hookUtils.js +381 -0
- package/lib/module/utils/hookUtils.js.map +1 -0
- package/lib/module/utils/loggerUtils.js +149 -0
- package/lib/module/utils/loggerUtils.js.map +1 -0
- package/lib/module/utils/validationUtils.js +154 -0
- package/lib/module/utils/validationUtils.js.map +1 -0
- package/lib/typescript/core/OxyServices.d.ts +64 -0
- package/lib/typescript/core/OxyServices.d.ts.map +1 -0
- package/lib/typescript/core/OxyServicesMain.d.ts +33 -0
- package/lib/typescript/core/OxyServicesMain.d.ts.map +1 -0
- package/lib/typescript/core/analytics/AnalyticsService.d.ts +26 -0
- package/lib/typescript/core/analytics/AnalyticsService.d.ts.map +1 -0
- package/lib/typescript/core/auth/AuthService.d.ts +165 -0
- package/lib/typescript/core/auth/AuthService.d.ts.map +1 -0
- package/lib/typescript/core/devices/DeviceService.d.ts +20 -0
- package/lib/typescript/core/devices/DeviceService.d.ts.map +1 -0
- package/lib/typescript/core/files/FileService.d.ts +59 -0
- package/lib/typescript/core/files/FileService.d.ts.map +1 -0
- package/lib/typescript/core/index.d.ts +19 -657
- package/lib/typescript/core/index.d.ts.map +1 -1
- package/lib/typescript/core/karma/KarmaService.d.ts +50 -0
- package/lib/typescript/core/karma/KarmaService.d.ts.map +1 -0
- package/lib/typescript/core/locations/LocationService.d.ts +39 -0
- package/lib/typescript/core/locations/LocationService.d.ts.map +1 -0
- package/lib/typescript/core/payments/PaymentService.d.ts +50 -0
- package/lib/typescript/core/payments/PaymentService.d.ts.map +1 -0
- package/lib/typescript/core/users/UserService.d.ts +111 -0
- package/lib/typescript/core/users/UserService.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +7 -3
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/models/{secureSession.d.ts → session.d.ts} +4 -4
- package/lib/typescript/models/session.d.ts.map +1 -0
- package/lib/typescript/ui/context/OxyContext.d.ts +2 -2
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/utils/apiUtils.d.ts +61 -0
- package/lib/typescript/utils/apiUtils.d.ts.map +1 -0
- package/lib/typescript/utils/asyncUtils.d.ts +64 -0
- package/lib/typescript/utils/asyncUtils.d.ts.map +1 -0
- package/lib/typescript/utils/errorUtils.d.ts +45 -0
- package/lib/typescript/utils/errorUtils.d.ts.map +1 -0
- package/lib/typescript/utils/hookUtils.d.ts +102 -0
- package/lib/typescript/utils/hookUtils.d.ts.map +1 -0
- package/lib/typescript/utils/loggerUtils.d.ts +49 -0
- package/lib/typescript/utils/loggerUtils.d.ts.map +1 -0
- package/lib/typescript/utils/validationUtils.d.ts +80 -0
- package/lib/typescript/utils/validationUtils.d.ts.map +1 -0
- package/package.json +2 -8
- package/src/core/OxyServices.ts +168 -0
- package/src/core/OxyServicesMain.ts +57 -0
- package/src/core/analytics/AnalyticsService.ts +64 -0
- package/src/core/auth/AuthService.ts +544 -0
- package/src/core/devices/DeviceService.ts +55 -0
- package/src/core/files/FileService.ts +194 -0
- package/src/core/index.ts +26 -1769
- package/src/core/karma/KarmaService.ts +104 -0
- package/src/core/locations/LocationService.ts +141 -0
- package/src/core/payments/PaymentService.ts +133 -0
- package/src/core/users/UserService.ts +241 -0
- package/src/index.ts +29 -8
- package/src/models/{secureSession.ts → session.ts} +5 -5
- package/src/ui/context/OxyContext.tsx +34 -30
- package/src/ui/screens/AccountSwitcherScreen.tsx +4 -4
- package/src/ui/screens/FileManagementScreen.tsx +12 -12
- package/src/ui/screens/ProfileScreen.tsx +3 -3
- package/src/ui/screens/SessionManagementScreen.tsx +2 -2
- package/src/ui/screens/SignInScreen.tsx +1 -1
- package/src/ui/screens/karma/KarmaCenterScreen.tsx +2 -2
- package/src/ui/screens/karma/KarmaLeaderboardScreen.tsx +3 -3
- package/src/ui/screens/karma/KarmaRulesScreen.tsx +3 -3
- package/src/ui/stores/followStore.ts +4 -4
- package/src/utils/apiUtils.ts +102 -0
- package/src/utils/asyncUtils.ts +265 -0
- package/src/utils/errorUtils.ts +172 -0
- package/src/utils/hookUtils.ts +397 -0
- package/src/utils/loggerUtils.ts +153 -0
- package/src/utils/validationUtils.ts +158 -0
- package/lib/commonjs/models/secureSession.js +0 -2
- package/lib/commonjs/models/secureSession.js.map +0 -1
- package/lib/commonjs/types/middleware.js +0 -6
- package/lib/module/models/secureSession.js +0 -2
- package/lib/module/models/secureSession.js.map +0 -1
- package/lib/module/types/middleware.js +0 -4
- package/lib/typescript/models/secureSession.d.ts.map +0 -1
- package/lib/typescript/types/middleware.d.ts +0 -19
- package/lib/typescript/types/middleware.d.ts.map +0 -1
- package/src/types/middleware.ts +0 -20
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Async utilities for common asynchronous patterns and error handling
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Wrapper for async operations with automatic error handling
|
|
7
|
+
*/
|
|
8
|
+
export async function withErrorHandling<T>(
|
|
9
|
+
operation: () => Promise<T>,
|
|
10
|
+
errorHandler?: (error: any) => void,
|
|
11
|
+
context?: string
|
|
12
|
+
): Promise<T | null> {
|
|
13
|
+
try {
|
|
14
|
+
return await operation();
|
|
15
|
+
} catch (error) {
|
|
16
|
+
if (errorHandler) {
|
|
17
|
+
errorHandler(error);
|
|
18
|
+
} else {
|
|
19
|
+
console.error(`Error in ${context || 'operation'}:`, error);
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Execute multiple async operations in parallel with error handling
|
|
27
|
+
*/
|
|
28
|
+
export async function parallelWithErrorHandling<T>(
|
|
29
|
+
operations: (() => Promise<T>)[],
|
|
30
|
+
errorHandler?: (error: any, index: number) => void
|
|
31
|
+
): Promise<(T | null)[]> {
|
|
32
|
+
const results = await Promise.allSettled(
|
|
33
|
+
operations.map((op, index) =>
|
|
34
|
+
withErrorHandling(op, error => errorHandler?.(error, index))
|
|
35
|
+
)
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
return results.map(result =>
|
|
39
|
+
result.status === 'fulfilled' ? result.value : null
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Retry an async operation with exponential backoff
|
|
45
|
+
*/
|
|
46
|
+
export async function retryAsync<T>(
|
|
47
|
+
operation: () => Promise<T>,
|
|
48
|
+
maxRetries: number = 3,
|
|
49
|
+
baseDelay: number = 1000,
|
|
50
|
+
shouldRetry?: (error: any) => boolean
|
|
51
|
+
): Promise<T> {
|
|
52
|
+
let lastError: any;
|
|
53
|
+
|
|
54
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
55
|
+
try {
|
|
56
|
+
return await operation();
|
|
57
|
+
} catch (error) {
|
|
58
|
+
lastError = error;
|
|
59
|
+
|
|
60
|
+
if (attempt === maxRetries) {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (shouldRetry && !shouldRetry(error)) {
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const delay = baseDelay * Math.pow(2, attempt);
|
|
69
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
throw lastError;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Debounce async function calls
|
|
78
|
+
*/
|
|
79
|
+
export function debounceAsync<T extends (...args: any[]) => Promise<any>>(
|
|
80
|
+
func: T,
|
|
81
|
+
delay: number
|
|
82
|
+
): (...args: Parameters<T>) => Promise<ReturnType<T>> {
|
|
83
|
+
let timeoutId: NodeJS.Timeout;
|
|
84
|
+
let lastPromise: Promise<ReturnType<T>> | null = null;
|
|
85
|
+
|
|
86
|
+
return (...args: Parameters<T>): Promise<ReturnType<T>> => {
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
clearTimeout(timeoutId);
|
|
89
|
+
|
|
90
|
+
timeoutId = setTimeout(async () => {
|
|
91
|
+
try {
|
|
92
|
+
const result = await func(...args);
|
|
93
|
+
resolve(result);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
reject(error);
|
|
96
|
+
}
|
|
97
|
+
}, delay);
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Throttle async function calls
|
|
104
|
+
*/
|
|
105
|
+
export function throttleAsync<T extends (...args: any[]) => Promise<any>>(
|
|
106
|
+
func: T,
|
|
107
|
+
limit: number,
|
|
108
|
+
interval: number
|
|
109
|
+
): (...args: Parameters<T>) => Promise<ReturnType<T>> {
|
|
110
|
+
let inThrottle = false;
|
|
111
|
+
let lastPromise: Promise<ReturnType<T>> | null = null;
|
|
112
|
+
|
|
113
|
+
return (...args: Parameters<T>): Promise<ReturnType<T>> => {
|
|
114
|
+
if (inThrottle) {
|
|
115
|
+
return lastPromise!;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
inThrottle = true;
|
|
119
|
+
lastPromise = func(...args);
|
|
120
|
+
|
|
121
|
+
setTimeout(() => {
|
|
122
|
+
inThrottle = false;
|
|
123
|
+
}, interval);
|
|
124
|
+
|
|
125
|
+
return lastPromise;
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Execute async operations sequentially with progress tracking
|
|
131
|
+
*/
|
|
132
|
+
export async function sequentialWithProgress<T>(
|
|
133
|
+
operations: (() => Promise<T>)[],
|
|
134
|
+
onProgress?: (completed: number, total: number) => void
|
|
135
|
+
): Promise<T[]> {
|
|
136
|
+
const results: T[] = [];
|
|
137
|
+
|
|
138
|
+
for (let i = 0; i < operations.length; i++) {
|
|
139
|
+
const result = await operations[i]();
|
|
140
|
+
results.push(result);
|
|
141
|
+
onProgress?.(i + 1, operations.length);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return results;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Batch async operations
|
|
149
|
+
*/
|
|
150
|
+
export async function batchAsync<T>(
|
|
151
|
+
items: T[],
|
|
152
|
+
batchSize: number,
|
|
153
|
+
processor: (batch: T[]) => Promise<void>
|
|
154
|
+
): Promise<void> {
|
|
155
|
+
for (let i = 0; i < items.length; i += batchSize) {
|
|
156
|
+
const batch = items.slice(i, i + batchSize);
|
|
157
|
+
await processor(batch);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Create a cancellable async operation
|
|
163
|
+
*/
|
|
164
|
+
export function createCancellableAsync<T>(
|
|
165
|
+
operation: (signal: AbortSignal) => Promise<T>
|
|
166
|
+
): { execute: () => Promise<T>; cancel: () => void } {
|
|
167
|
+
let abortController: AbortController | null = null;
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
execute: async () => {
|
|
171
|
+
abortController = new AbortController();
|
|
172
|
+
return await operation(abortController.signal);
|
|
173
|
+
},
|
|
174
|
+
cancel: () => {
|
|
175
|
+
abortController?.abort();
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Timeout wrapper for async operations
|
|
182
|
+
*/
|
|
183
|
+
export async function withTimeout<T>(
|
|
184
|
+
operation: Promise<T>,
|
|
185
|
+
timeoutMs: number,
|
|
186
|
+
timeoutMessage?: string
|
|
187
|
+
): Promise<T> {
|
|
188
|
+
const timeoutPromise = new Promise<never>((_, reject) => {
|
|
189
|
+
setTimeout(() => {
|
|
190
|
+
reject(new Error(timeoutMessage || `Operation timed out after ${timeoutMs}ms`));
|
|
191
|
+
}, timeoutMs);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
return Promise.race([operation, timeoutPromise]);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Cache async operation results
|
|
199
|
+
*/
|
|
200
|
+
export function createAsyncCache<T>(
|
|
201
|
+
ttl: number = 5 * 60 * 1000 // 5 minutes default
|
|
202
|
+
) {
|
|
203
|
+
const cache = new Map<string, { data: T; timestamp: number }>();
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
get: (key: string): T | null => {
|
|
207
|
+
const item = cache.get(key);
|
|
208
|
+
if (!item) return null;
|
|
209
|
+
|
|
210
|
+
if (Date.now() - item.timestamp > ttl) {
|
|
211
|
+
cache.delete(key);
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return item.data;
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
set: (key: string, data: T): void => {
|
|
219
|
+
cache.set(key, { data, timestamp: Date.now() });
|
|
220
|
+
},
|
|
221
|
+
|
|
222
|
+
clear: (): void => {
|
|
223
|
+
cache.clear();
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
delete: (key: string): boolean => {
|
|
227
|
+
return cache.delete(key);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Execute async operation with loading state
|
|
234
|
+
*/
|
|
235
|
+
export async function withLoadingState<T>(
|
|
236
|
+
operation: () => Promise<T>,
|
|
237
|
+
setLoading: (loading: boolean) => void
|
|
238
|
+
): Promise<T> {
|
|
239
|
+
setLoading(true);
|
|
240
|
+
try {
|
|
241
|
+
return await operation();
|
|
242
|
+
} finally {
|
|
243
|
+
setLoading(false);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Create a promise that resolves after a delay
|
|
249
|
+
*/
|
|
250
|
+
export const delay = (ms: number): Promise<void> =>
|
|
251
|
+
new Promise(resolve => setTimeout(resolve, ms));
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Execute async operation with retry on specific errors
|
|
255
|
+
*/
|
|
256
|
+
export async function retryOnError<T>(
|
|
257
|
+
operation: () => Promise<T>,
|
|
258
|
+
retryableErrors: (string | number)[],
|
|
259
|
+
maxRetries: number = 3
|
|
260
|
+
): Promise<T> {
|
|
261
|
+
return retryAsync(operation, maxRetries, 1000, (error) => {
|
|
262
|
+
const errorCode = error?.code || error?.status || error?.message;
|
|
263
|
+
return retryableErrors.includes(errorCode);
|
|
264
|
+
});
|
|
265
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { ApiError } from '../models/interfaces';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Error handling utilities for consistent error processing
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Common error codes
|
|
9
|
+
*/
|
|
10
|
+
export const ErrorCodes = {
|
|
11
|
+
// Authentication errors
|
|
12
|
+
UNAUTHORIZED: 'UNAUTHORIZED',
|
|
13
|
+
FORBIDDEN: 'FORBIDDEN',
|
|
14
|
+
INVALID_TOKEN: 'INVALID_TOKEN',
|
|
15
|
+
MISSING_TOKEN: 'MISSING_TOKEN',
|
|
16
|
+
|
|
17
|
+
// Validation errors
|
|
18
|
+
VALIDATION_ERROR: 'VALIDATION_ERROR',
|
|
19
|
+
MISSING_PARAMETER: 'MISSING_PARAMETER',
|
|
20
|
+
INVALID_FORMAT: 'INVALID_FORMAT',
|
|
21
|
+
|
|
22
|
+
// Resource errors
|
|
23
|
+
NOT_FOUND: 'NOT_FOUND',
|
|
24
|
+
ALREADY_EXISTS: 'ALREADY_EXISTS',
|
|
25
|
+
CONFLICT: 'CONFLICT',
|
|
26
|
+
|
|
27
|
+
// Server errors
|
|
28
|
+
INTERNAL_ERROR: 'INTERNAL_ERROR',
|
|
29
|
+
SERVICE_UNAVAILABLE: 'SERVICE_UNAVAILABLE',
|
|
30
|
+
TIMEOUT: 'TIMEOUT',
|
|
31
|
+
|
|
32
|
+
// Network errors
|
|
33
|
+
NETWORK_ERROR: 'NETWORK_ERROR',
|
|
34
|
+
CONNECTION_FAILED: 'CONNECTION_FAILED'
|
|
35
|
+
} as const;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Create a standardized API error
|
|
39
|
+
*/
|
|
40
|
+
export function createApiError(
|
|
41
|
+
message: string,
|
|
42
|
+
code: string = ErrorCodes.INTERNAL_ERROR,
|
|
43
|
+
status: number = 500,
|
|
44
|
+
details?: any
|
|
45
|
+
): ApiError {
|
|
46
|
+
return {
|
|
47
|
+
message,
|
|
48
|
+
code,
|
|
49
|
+
status,
|
|
50
|
+
details
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Handle common HTTP errors and convert to ApiError
|
|
56
|
+
*/
|
|
57
|
+
export function handleHttpError(error: any): ApiError {
|
|
58
|
+
// If it's already an ApiError, return it
|
|
59
|
+
if (error && typeof error === 'object' && 'code' in error && 'status' in error) {
|
|
60
|
+
return error as ApiError;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Handle axios errors
|
|
64
|
+
if (error?.response) {
|
|
65
|
+
const { status, data } = error.response;
|
|
66
|
+
|
|
67
|
+
return createApiError(
|
|
68
|
+
data?.message || `HTTP ${status} error`,
|
|
69
|
+
data?.code || getErrorCodeFromStatus(status),
|
|
70
|
+
status,
|
|
71
|
+
data
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Handle network errors
|
|
76
|
+
if (error?.request) {
|
|
77
|
+
return createApiError(
|
|
78
|
+
'Network error - no response received',
|
|
79
|
+
ErrorCodes.NETWORK_ERROR,
|
|
80
|
+
0
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Handle other errors
|
|
85
|
+
return createApiError(
|
|
86
|
+
error?.message || 'Unknown error occurred',
|
|
87
|
+
ErrorCodes.INTERNAL_ERROR,
|
|
88
|
+
500
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get error code from HTTP status
|
|
94
|
+
*/
|
|
95
|
+
function getErrorCodeFromStatus(status: number): string {
|
|
96
|
+
switch (status) {
|
|
97
|
+
case 400:
|
|
98
|
+
return ErrorCodes.VALIDATION_ERROR;
|
|
99
|
+
case 401:
|
|
100
|
+
return ErrorCodes.UNAUTHORIZED;
|
|
101
|
+
case 403:
|
|
102
|
+
return ErrorCodes.FORBIDDEN;
|
|
103
|
+
case 404:
|
|
104
|
+
return ErrorCodes.NOT_FOUND;
|
|
105
|
+
case 409:
|
|
106
|
+
return ErrorCodes.CONFLICT;
|
|
107
|
+
case 422:
|
|
108
|
+
return ErrorCodes.VALIDATION_ERROR;
|
|
109
|
+
case 500:
|
|
110
|
+
return ErrorCodes.INTERNAL_ERROR;
|
|
111
|
+
case 503:
|
|
112
|
+
return ErrorCodes.SERVICE_UNAVAILABLE;
|
|
113
|
+
default:
|
|
114
|
+
return ErrorCodes.INTERNAL_ERROR;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Validate required fields and throw error if missing
|
|
120
|
+
*/
|
|
121
|
+
export function validateRequiredFields(data: Record<string, any>, fields: string[]): void {
|
|
122
|
+
const missing = fields.filter(field => !data[field]);
|
|
123
|
+
|
|
124
|
+
if (missing.length > 0) {
|
|
125
|
+
throw createApiError(
|
|
126
|
+
`Missing required fields: ${missing.join(', ')}`,
|
|
127
|
+
ErrorCodes.MISSING_PARAMETER,
|
|
128
|
+
400
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Safe error logging with context
|
|
135
|
+
*/
|
|
136
|
+
export function logError(error: any, context?: string): void {
|
|
137
|
+
const prefix = context ? `[${context}]` : '[Error]';
|
|
138
|
+
|
|
139
|
+
if (error instanceof Error) {
|
|
140
|
+
console.error(`${prefix} ${error.message}`, error.stack);
|
|
141
|
+
} else {
|
|
142
|
+
console.error(`${prefix}`, error);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Retry function with exponential backoff
|
|
148
|
+
*/
|
|
149
|
+
export async function retryWithBackoff<T>(
|
|
150
|
+
fn: () => Promise<T>,
|
|
151
|
+
maxRetries: number = 3,
|
|
152
|
+
baseDelay: number = 1000
|
|
153
|
+
): Promise<T> {
|
|
154
|
+
let lastError: any;
|
|
155
|
+
|
|
156
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
157
|
+
try {
|
|
158
|
+
return await fn();
|
|
159
|
+
} catch (error) {
|
|
160
|
+
lastError = error;
|
|
161
|
+
|
|
162
|
+
if (attempt === maxRetries) {
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const delay = baseDelay * Math.pow(2, attempt);
|
|
167
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
throw lastError;
|
|
172
|
+
}
|