-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy patherrors.ts
More file actions
186 lines (169 loc) · 4.7 KB
/
errors.ts
File metadata and controls
186 lines (169 loc) · 4.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/**
* Custom Error Classes
* Provides structured error handling with proper typing and error codes
*/
export enum ErrorCode {
// Client Errors (4xx)
BAD_REQUEST = 'BAD_REQUEST',
UNAUTHORIZED = 'UNAUTHORIZED',
FORBIDDEN = 'FORBIDDEN',
NOT_FOUND = 'NOT_FOUND',
VALIDATION_ERROR = 'VALIDATION_ERROR',
RATE_LIMIT_EXCEEDED = 'RATE_LIMIT_EXCEEDED',
// Server Errors (5xx)
INTERNAL_ERROR = 'INTERNAL_ERROR',
SERVICE_UNAVAILABLE = 'SERVICE_UNAVAILABLE',
DATABASE_ERROR = 'DATABASE_ERROR',
CACHE_ERROR = 'CACHE_ERROR',
EXTERNAL_API_ERROR = 'EXTERNAL_API_ERROR',
// GitHub Specific
GITHUB_API_ERROR = 'GITHUB_API_ERROR',
GITHUB_RATE_LIMIT = 'GITHUB_RATE_LIMIT',
GITHUB_AUTH_FAILED = 'GITHUB_AUTH_FAILED',
GITHUB_USER_NOT_FOUND = 'GITHUB_USER_NOT_FOUND',
}
/**
* Base application error class
*/
export class AppError extends Error {
constructor(
public readonly code: ErrorCode,
public readonly message: string,
public readonly statusCode: number,
public readonly isOperational: boolean = true,
public readonly details?: Record<string, any>
) {
super(message);
this.name = this.constructor.name;
Error.captureStackTrace(this, this.constructor);
}
toJSON() {
return {
code: this.code,
message: this.message,
statusCode: this.statusCode,
...(this.details && { details: this.details }),
};
}
}
/**
* Validation error (400)
*/
export class ValidationError extends AppError {
constructor(message: string, details?: Record<string, any>) {
super(ErrorCode.VALIDATION_ERROR, message, 400, true, details);
}
}
/**
* Not found error (404)
*/
export class NotFoundError extends AppError {
constructor(resource: string) {
super(ErrorCode.NOT_FOUND, `${resource} not found`, 404, true);
}
}
/**
* GitHub API error
*/
export class GitHubApiError extends AppError {
constructor(message: string, statusCode: number = 500, details?: Record<string, any>) {
super(ErrorCode.GITHUB_API_ERROR, message, statusCode, true, details);
}
}
/**
* GitHub rate limit error (429)
*/
export class GitHubRateLimitError extends AppError {
constructor(resetTime?: Date) {
super(
ErrorCode.GITHUB_RATE_LIMIT,
'GitHub API rate limit exceeded. Please set a valid GITHUB_TOKEN or wait for rate limit reset.',
429,
true,
resetTime ? { resetAt: resetTime.toISOString() } : undefined
);
}
}
/**
* GitHub authentication error (401)
*/
export class GitHubAuthError extends AppError {
constructor() {
super(
ErrorCode.GITHUB_AUTH_FAILED,
'GitHub authentication failed. Your GITHUB_TOKEN may be invalid or expired.',
401,
true
);
}
}
/**
* GitHub user not found error (404)
*/
export class GitHubUserNotFoundError extends AppError {
constructor(username: string) {
super(
ErrorCode.GITHUB_USER_NOT_FOUND,
`GitHub user '${username}' not found`,
404,
true,
{ username }
);
}
}
/**
* Database error (500)
*/
export class DatabaseError extends AppError {
constructor(message: string, details?: Record<string, any>) {
super(ErrorCode.DATABASE_ERROR, message, 500, true, details);
}
}
/**
* Cache error (500)
*/
export class CacheError extends AppError {
constructor(message: string, details?: Record<string, any>) {
super(ErrorCode.CACHE_ERROR, message, 500, true, details);
}
}
/**
* Service unavailable error (503)
*/
export class ServiceUnavailableError extends AppError {
constructor(service: string) {
super(
ErrorCode.SERVICE_UNAVAILABLE,
`${service} is temporarily unavailable`,
503,
true
);
}
}
/**
* Check if error is an operational error (expected/handled)
*/
export function isOperationalError(error: Error): boolean {
if (error instanceof AppError) {
return error.isOperational;
}
return false;
}
/**
* Extract HTTP status code from error
*/
export function getErrorStatusCode(error: Error): number {
if (error instanceof AppError) {
return error.statusCode;
}
return 500;
}
/**
* Get error code from error
*/
export function getErrorCode(error: Error): ErrorCode {
if (error instanceof AppError) {
return error.code;
}
return ErrorCode.INTERNAL_ERROR;
}