• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

agentic-dev-library / thumbcode / 21119557800

18 Jan 2026 10:18PM UTC coverage: 29.599% (+4.1%) from 25.529%
21119557800

Pull #54

github

web-flow
Merge 3e7392296 into 1c5d35a49
Pull Request #54: feat(performance): add performance monitoring and optimization utilities

321 of 1699 branches covered (18.89%)

Branch coverage included in aggregate %.

165 of 202 new or added lines in 3 files covered. (81.68%)

15 existing lines in 2 files now uncovered.

786 of 2041 relevant lines covered (38.51%)

1.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.25
/src/lib/error-handler.ts
1
/**
2
 * Global Error Handler
3
 *
4
 * Centralized error handling for the application.
5
 * Catches unhandled errors and provides consistent error processing.
6
 */
7

8
import { logger } from './logger';
9

10
// Type for React Native's ErrorUtils
11
interface ErrorUtilsType {
12
  setGlobalHandler: (handler: (error: Error, isFatal?: boolean) => void) => void;
13
  getGlobalHandler: () => ((error: Error, isFatal?: boolean) => void) | undefined;
14
}
15

16
// Access React Native's ErrorUtils
17
function getErrorUtils(): ErrorUtilsType | undefined {
18
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
  return (global as any).ErrorUtils as ErrorUtilsType | undefined;
×
20
}
21

22
export type ErrorSeverity = 'low' | 'medium' | 'high' | 'critical';
23

24
export interface AppError extends Error {
25
  code?: string;
26
  severity?: ErrorSeverity;
27
  userMessage?: string;
28
  context?: Record<string, unknown>;
29
  recoverable?: boolean;
30
}
31

32
/**
33
 * Error codes for categorization
34
 */
35
export const ErrorCodes = {
1✔
36
  // Network errors
37
  NETWORK_OFFLINE: 'NETWORK_OFFLINE',
38
  NETWORK_TIMEOUT: 'NETWORK_TIMEOUT',
39
  NETWORK_ERROR: 'NETWORK_ERROR',
40

41
  // API errors
42
  API_ERROR: 'API_ERROR',
43
  API_UNAUTHORIZED: 'API_UNAUTHORIZED',
44
  API_FORBIDDEN: 'API_FORBIDDEN',
45
  API_NOT_FOUND: 'API_NOT_FOUND',
46
  API_RATE_LIMITED: 'API_RATE_LIMITED',
47

48
  // Auth errors
49
  AUTH_EXPIRED: 'AUTH_EXPIRED',
50
  AUTH_INVALID: 'AUTH_INVALID',
51
  AUTH_MISSING: 'AUTH_MISSING',
52

53
  // Storage errors
54
  STORAGE_FULL: 'STORAGE_FULL',
55
  STORAGE_ERROR: 'STORAGE_ERROR',
56

57
  // Git errors
58
  GIT_CLONE_FAILED: 'GIT_CLONE_FAILED',
59
  GIT_PUSH_FAILED: 'GIT_PUSH_FAILED',
60
  GIT_PULL_FAILED: 'GIT_PULL_FAILED',
61
  GIT_MERGE_CONFLICT: 'GIT_MERGE_CONFLICT',
62

63
  // Agent errors
64
  AGENT_TIMEOUT: 'AGENT_TIMEOUT',
65
  AGENT_ERROR: 'AGENT_ERROR',
66

67
  // Generic
68
  UNKNOWN: 'UNKNOWN',
69
} as const;
70

71
export type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
72

73
/**
74
 * User-friendly error messages
75
 */
76
const userMessages: Record<ErrorCode, string> = {
1✔
77
  [ErrorCodes.NETWORK_OFFLINE]: 'You appear to be offline. Please check your connection.',
78
  [ErrorCodes.NETWORK_TIMEOUT]: 'The request timed out. Please try again.',
79
  [ErrorCodes.NETWORK_ERROR]: 'A network error occurred. Please try again.',
80
  [ErrorCodes.API_ERROR]: 'Something went wrong. Please try again.',
81
  [ErrorCodes.API_UNAUTHORIZED]: 'Your session has expired. Please sign in again.',
82
  [ErrorCodes.API_FORBIDDEN]: "You don't have permission to perform this action.",
83
  [ErrorCodes.API_NOT_FOUND]: 'The requested resource was not found.',
84
  [ErrorCodes.API_RATE_LIMITED]: "You've made too many requests. Please wait a moment.",
85
  [ErrorCodes.AUTH_EXPIRED]: 'Your session has expired. Please sign in again.',
86
  [ErrorCodes.AUTH_INVALID]: 'Invalid credentials. Please check and try again.',
87
  [ErrorCodes.AUTH_MISSING]: 'Please sign in to continue.',
88
  [ErrorCodes.STORAGE_FULL]: 'Device storage is full. Please free up some space.',
89
  [ErrorCodes.STORAGE_ERROR]: 'Failed to save data. Please try again.',
90
  [ErrorCodes.GIT_CLONE_FAILED]: 'Failed to clone repository. Please check your connection.',
91
  [ErrorCodes.GIT_PUSH_FAILED]: 'Failed to push changes. Please try again.',
92
  [ErrorCodes.GIT_PULL_FAILED]: 'Failed to pull changes. Please try again.',
93
  [ErrorCodes.GIT_MERGE_CONFLICT]: 'Merge conflict detected. Please resolve manually.',
94
  [ErrorCodes.AGENT_TIMEOUT]: 'The agent took too long to respond. Please try again.',
95
  [ErrorCodes.AGENT_ERROR]: 'The agent encountered an error. Please try again.',
96
  [ErrorCodes.UNKNOWN]: 'Something unexpected happened. Please try again.',
97
};
98

99
/**
100
 * Create a standardized app error
101
 */
102
export function createAppError(
103
  message: string,
104
  options: {
2✔
105
    code?: ErrorCode;
106
    severity?: ErrorSeverity;
107
    userMessage?: string;
108
    context?: Record<string, unknown>;
109
    recoverable?: boolean;
110
    cause?: Error;
111
  } = {}
112
): AppError {
113
  const error = new Error(message) as AppError;
21✔
114
  error.name = 'AppError';
21✔
115
  error.code = options.code || ErrorCodes.UNKNOWN;
21✔
116
  error.severity = options.severity || 'medium';
21✔
117
  error.userMessage = options.userMessage || userMessages[error.code as ErrorCode];
21✔
118
  error.context = options.context;
21✔
119
  error.recoverable = options.recoverable ?? true;
21✔
120
  error.cause = options.cause;
21✔
121
  return error;
21✔
122
}
123

124
/**
125
 * Parse an error into a standardized AppError
126
 */
127
export function parseError(error: unknown): AppError {
128
  // Already an AppError
129
  if (isAppError(error)) {
16✔
130
    return error;
3✔
131
  }
132

133
  // Standard Error
134
  if (error instanceof Error) {
13✔
135
    // Check for network errors
136
    if (error.message.includes('Network request failed')) {
8✔
137
      return createAppError(error.message, {
1✔
138
        code: ErrorCodes.NETWORK_ERROR,
139
        severity: 'medium',
140
        cause: error,
141
      });
142
    }
143

144
    // Check for timeout errors
145
    if (error.message.includes('timeout') || error.name === 'TimeoutError') {
7✔
146
      return createAppError(error.message, {
1✔
147
        code: ErrorCodes.NETWORK_TIMEOUT,
148
        severity: 'low',
149
        cause: error,
150
      });
151
    }
152

153
    // Generic error conversion
154
    return createAppError(error.message, {
6✔
155
      code: ErrorCodes.UNKNOWN,
156
      severity: 'medium',
157
      cause: error,
158
    });
159
  }
160

161
  // String error
162
  if (typeof error === 'string') {
5✔
163
    return createAppError(error, {
2✔
164
      code: ErrorCodes.UNKNOWN,
165
      severity: 'medium',
166
    });
167
  }
168

169
  // Unknown error type
170
  return createAppError('An unknown error occurred', {
3✔
171
    code: ErrorCodes.UNKNOWN,
172
    severity: 'medium',
173
    context: { originalError: String(error) },
174
  });
175
}
176

177
/**
178
 * Type guard for AppError
179
 */
180
export function isAppError(error: unknown): error is AppError {
181
  return error instanceof Error && 'code' in error && 'severity' in error;
27✔
182
}
183

184
/**
185
 * Get user-friendly message for an error
186
 */
187
export function getUserMessage(error: unknown): string {
188
  const appError = parseError(error);
3✔
189
  return appError.userMessage || userMessages[ErrorCodes.UNKNOWN];
3!
190
}
191

192
/**
193
 * Error handler callbacks
194
 */
195
type ErrorCallback = (error: AppError) => void;
196

197
const errorCallbacks: Set<ErrorCallback> = new Set();
1✔
198

199
/**
200
 * Register a global error callback
201
 */
202
export function onError(callback: ErrorCallback): () => void {
203
  errorCallbacks.add(callback);
2✔
204
  return () => errorCallbacks.delete(callback);
2✔
205
}
206

207
/**
208
 * Handle an error globally
209
 */
210
export function handleError(error: unknown, context?: Record<string, unknown>): AppError {
211
  const appError = parseError(error);
5✔
212

213
  // Add context if provided
214
  if (context) {
5✔
215
    appError.context = { ...appError.context, ...context };
1✔
216
  }
217

218
  // Log the error
219
  const logLevel = appError.severity === 'critical' ? 'fatal' : 'error';
5!
220
  logger[logLevel](`[${appError.code}] ${appError.message}`, appError, appError.context);
5✔
221

222
  // Notify callbacks
223
  for (const callback of errorCallbacks) {
5✔
224
    try {
2✔
225
      callback(appError);
2✔
226
    } catch (callbackError) {
UNCOV
227
      logger.warn('Error callback threw an exception', { error: String(callbackError) });
×
228
    }
229
  }
230

231
  return appError;
5✔
232
}
233

234
/**
235
 * Setup global error handlers for React Native
236
 */
237
export function setupGlobalErrorHandlers(): void {
UNCOV
238
  const errorUtils = getErrorUtils();
×
239

UNCOV
240
  if (errorUtils) {
×
241
    // Handle unhandled promise rejections
UNCOV
242
    const originalHandler = errorUtils.getGlobalHandler?.();
×
243

244
    errorUtils.setGlobalHandler?.((error: Error, isFatal?: boolean) => {
×
UNCOV
245
      handleError(error, { isFatal, source: 'globalHandler' });
×
246

247
      // Call original handler
248
      if (originalHandler) {
×
UNCOV
249
        originalHandler(error, isFatal);
×
250
      }
251
    });
252
  }
253

UNCOV
254
  logger.info('Global error handlers initialized');
×
255
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc