@geekmidas/errors 0.0.1 → 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/CHANGELOG.md +7 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -1
- package/src/__tests__/errors.spec.ts +519 -519
- package/src/index.ts +364 -365
- package/tsconfig.json +9 -0
- package/tsdown.config.ts +1 -1
package/src/index.ts
CHANGED
|
@@ -14,115 +14,114 @@
|
|
|
14
14
|
* ```
|
|
15
15
|
*/
|
|
16
16
|
export class HttpError extends Error {
|
|
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
|
-
}
|
|
17
|
+
/** The HTTP status code (e.g., 400, 404, 500) */
|
|
18
|
+
public readonly statusCode: number;
|
|
19
|
+
/** The standard HTTP status message (e.g., 'Bad Request', 'Not Found') */
|
|
20
|
+
public readonly statusMessage: string;
|
|
21
|
+
/** Type discriminator for runtime type checking */
|
|
22
|
+
public readonly isHttpError = true;
|
|
23
|
+
/** Additional error details for debugging or client information */
|
|
24
|
+
public readonly details?: any;
|
|
25
|
+
/** Application-specific error code for client-side handling */
|
|
26
|
+
public readonly code?: string;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Creates a new HttpError instance.
|
|
30
|
+
*
|
|
31
|
+
* @param statusCode - The HTTP status code
|
|
32
|
+
* @param message - Optional error message for the client
|
|
33
|
+
* @param options - Optional configuration object
|
|
34
|
+
* @param options.statusMessage - Override the default status message
|
|
35
|
+
* @param options.details - Additional error details or context
|
|
36
|
+
* @param options.code - Application-specific error code
|
|
37
|
+
* @param options.cause - The underlying error that caused this error (ES2022)
|
|
38
|
+
*/
|
|
39
|
+
constructor(
|
|
40
|
+
statusCode: number,
|
|
41
|
+
message?: string,
|
|
42
|
+
options?: {
|
|
43
|
+
statusMessage?: string;
|
|
44
|
+
details?: any;
|
|
45
|
+
code?: string;
|
|
46
|
+
cause?: Error;
|
|
47
|
+
},
|
|
48
|
+
) {
|
|
49
|
+
super(message || options?.statusMessage || 'HTTP Error');
|
|
50
|
+
this.name = this.constructor.name;
|
|
51
|
+
this.statusCode = statusCode;
|
|
52
|
+
this.statusMessage =
|
|
53
|
+
options?.statusMessage || this.getDefaultStatusMessage(statusCode);
|
|
54
|
+
this.details = options?.details;
|
|
55
|
+
this.code = options?.code;
|
|
56
|
+
|
|
57
|
+
// Set cause if provided (ES2022 feature)
|
|
58
|
+
if (options?.cause) {
|
|
59
|
+
this.cause = options.cause;
|
|
60
|
+
}
|
|
61
|
+
// Maintains proper stack trace for where our error was thrown
|
|
62
|
+
Error.captureStackTrace(this, this.constructor);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Gets the error response body as a JSON string.
|
|
67
|
+
* Used for sending the error response to clients.
|
|
68
|
+
*
|
|
69
|
+
* @returns JSON string containing message, code, and error details
|
|
70
|
+
*/
|
|
71
|
+
get body() {
|
|
72
|
+
return JSON.stringify({
|
|
73
|
+
message: this.message,
|
|
74
|
+
code: this.code,
|
|
75
|
+
error: this.details,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Gets the default HTTP status message for a given status code.
|
|
81
|
+
*
|
|
82
|
+
* @param statusCode - The HTTP status code
|
|
83
|
+
* @returns The standard HTTP status message or 'Unknown Error' if not found
|
|
84
|
+
* @private
|
|
85
|
+
*/
|
|
86
|
+
private getDefaultStatusMessage(statusCode: number): string {
|
|
87
|
+
const statusMessages: Record<number, string> = {
|
|
88
|
+
400: 'Bad Request',
|
|
89
|
+
401: 'Unauthorized',
|
|
90
|
+
403: 'Forbidden',
|
|
91
|
+
404: 'Not Found',
|
|
92
|
+
405: 'Method Not Allowed',
|
|
93
|
+
406: 'Not Acceptable',
|
|
94
|
+
408: 'Request Timeout',
|
|
95
|
+
409: 'Conflict',
|
|
96
|
+
410: 'Gone',
|
|
97
|
+
422: 'Unprocessable Entity',
|
|
98
|
+
429: 'Too Many Requests',
|
|
99
|
+
500: 'Internal Server Error',
|
|
100
|
+
501: 'Not Implemented',
|
|
101
|
+
502: 'Bad Gateway',
|
|
102
|
+
503: 'Service Unavailable',
|
|
103
|
+
504: 'Gateway Timeout',
|
|
104
|
+
};
|
|
105
|
+
return statusMessages[statusCode] || 'Unknown Error';
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Serializes the error to a JSON-compatible object.
|
|
110
|
+
* Useful for logging and debugging purposes.
|
|
111
|
+
*
|
|
112
|
+
* @returns Object representation of the error including stack trace
|
|
113
|
+
*/
|
|
114
|
+
toJSON() {
|
|
115
|
+
return {
|
|
116
|
+
name: this.name,
|
|
117
|
+
message: this.message,
|
|
118
|
+
statusCode: this.statusCode,
|
|
119
|
+
statusMessage: this.statusMessage,
|
|
120
|
+
code: this.code,
|
|
121
|
+
details: this.details,
|
|
122
|
+
stack: this.stack,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
126
125
|
}
|
|
127
126
|
|
|
128
127
|
// Client Error Classes (4xx)
|
|
@@ -139,9 +138,9 @@ export class HttpError extends Error {
|
|
|
139
138
|
* ```
|
|
140
139
|
*/
|
|
141
140
|
export class BadRequestError extends HttpError {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
141
|
+
constructor(message?: string, details?: any) {
|
|
142
|
+
super(400, message, { details });
|
|
143
|
+
}
|
|
145
144
|
}
|
|
146
145
|
|
|
147
146
|
/**
|
|
@@ -156,9 +155,9 @@ export class BadRequestError extends HttpError {
|
|
|
156
155
|
* ```
|
|
157
156
|
*/
|
|
158
157
|
export class UnauthorizedError extends HttpError {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
158
|
+
constructor(message?: string, details?: any) {
|
|
159
|
+
super(401, message, { details });
|
|
160
|
+
}
|
|
162
161
|
}
|
|
163
162
|
|
|
164
163
|
/**
|
|
@@ -173,9 +172,9 @@ export class UnauthorizedError extends HttpError {
|
|
|
173
172
|
* ```
|
|
174
173
|
*/
|
|
175
174
|
export class ForbiddenError extends HttpError {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
175
|
+
constructor(message?: string, details?: any) {
|
|
176
|
+
super(403, message, { details });
|
|
177
|
+
}
|
|
179
178
|
}
|
|
180
179
|
|
|
181
180
|
/**
|
|
@@ -190,9 +189,9 @@ export class ForbiddenError extends HttpError {
|
|
|
190
189
|
* ```
|
|
191
190
|
*/
|
|
192
191
|
export class NotFoundError extends HttpError {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
192
|
+
constructor(message?: string, details?: any) {
|
|
193
|
+
super(404, message, { details });
|
|
194
|
+
}
|
|
196
195
|
}
|
|
197
196
|
|
|
198
197
|
/**
|
|
@@ -207,15 +206,15 @@ export class NotFoundError extends HttpError {
|
|
|
207
206
|
* ```
|
|
208
207
|
*/
|
|
209
208
|
export class MethodNotAllowedError extends HttpError {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
209
|
+
/**
|
|
210
|
+
* @param message - Optional error message
|
|
211
|
+
* @param allowedMethods - Array of allowed HTTP methods for this resource
|
|
212
|
+
*/
|
|
213
|
+
constructor(message?: string, allowedMethods?: string[]) {
|
|
214
|
+
super(405, message, {
|
|
215
|
+
details: allowedMethods ? { allowedMethods } : undefined,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
219
218
|
}
|
|
220
219
|
|
|
221
220
|
/**
|
|
@@ -230,9 +229,9 @@ export class MethodNotAllowedError extends HttpError {
|
|
|
230
229
|
* ```
|
|
231
230
|
*/
|
|
232
231
|
export class ConflictError extends HttpError {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
232
|
+
constructor(message?: string, details?: any) {
|
|
233
|
+
super(409, message, { details });
|
|
234
|
+
}
|
|
236
235
|
}
|
|
237
236
|
|
|
238
237
|
/**
|
|
@@ -250,15 +249,15 @@ export class ConflictError extends HttpError {
|
|
|
250
249
|
* ```
|
|
251
250
|
*/
|
|
252
251
|
export class UnprocessableEntityError extends HttpError {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
252
|
+
/**
|
|
253
|
+
* @param message - Optional error message
|
|
254
|
+
* @param validationErrors - Object containing field-specific validation errors
|
|
255
|
+
*/
|
|
256
|
+
constructor(message?: string, validationErrors?: any) {
|
|
257
|
+
super(422, message, {
|
|
258
|
+
details: validationErrors ? { validationErrors } : undefined,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
262
261
|
}
|
|
263
262
|
|
|
264
263
|
/**
|
|
@@ -273,15 +272,15 @@ export class UnprocessableEntityError extends HttpError {
|
|
|
273
272
|
* ```
|
|
274
273
|
*/
|
|
275
274
|
export class TooManyRequestsError extends HttpError {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
275
|
+
/**
|
|
276
|
+
* @param message - Optional error message
|
|
277
|
+
* @param retryAfter - Number of seconds the client should wait before retrying
|
|
278
|
+
*/
|
|
279
|
+
constructor(message?: string, retryAfter?: number) {
|
|
280
|
+
super(429, message, {
|
|
281
|
+
details: retryAfter ? { retryAfter } : undefined,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
285
284
|
}
|
|
286
285
|
|
|
287
286
|
// Server Error Classes (5xx)
|
|
@@ -298,9 +297,9 @@ export class TooManyRequestsError extends HttpError {
|
|
|
298
297
|
* ```
|
|
299
298
|
*/
|
|
300
299
|
export class InternalServerError extends HttpError {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
300
|
+
constructor(message?: string, details?: any) {
|
|
301
|
+
super(500, message, { details });
|
|
302
|
+
}
|
|
304
303
|
}
|
|
305
304
|
|
|
306
305
|
/**
|
|
@@ -315,9 +314,9 @@ export class InternalServerError extends HttpError {
|
|
|
315
314
|
* ```
|
|
316
315
|
*/
|
|
317
316
|
export class NotImplementedError extends HttpError {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
317
|
+
constructor(message?: string, details?: any) {
|
|
318
|
+
super(501, message, { details });
|
|
319
|
+
}
|
|
321
320
|
}
|
|
322
321
|
|
|
323
322
|
/**
|
|
@@ -332,9 +331,9 @@ export class NotImplementedError extends HttpError {
|
|
|
332
331
|
* ```
|
|
333
332
|
*/
|
|
334
333
|
export class BadGatewayError extends HttpError {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
334
|
+
constructor(message?: string, details?: any) {
|
|
335
|
+
super(502, message, { details });
|
|
336
|
+
}
|
|
338
337
|
}
|
|
339
338
|
|
|
340
339
|
/**
|
|
@@ -349,15 +348,15 @@ export class BadGatewayError extends HttpError {
|
|
|
349
348
|
* ```
|
|
350
349
|
*/
|
|
351
350
|
export class ServiceUnavailableError extends HttpError {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
351
|
+
/**
|
|
352
|
+
* @param message - Optional error message
|
|
353
|
+
* @param retryAfter - Number of seconds the client should wait before retrying
|
|
354
|
+
*/
|
|
355
|
+
constructor(message?: string, retryAfter?: number) {
|
|
356
|
+
super(503, message, {
|
|
357
|
+
details: retryAfter ? { retryAfter } : undefined,
|
|
358
|
+
});
|
|
359
|
+
}
|
|
361
360
|
}
|
|
362
361
|
|
|
363
362
|
/**
|
|
@@ -372,9 +371,9 @@ export class ServiceUnavailableError extends HttpError {
|
|
|
372
371
|
* ```
|
|
373
372
|
*/
|
|
374
373
|
export class GatewayTimeoutError extends HttpError {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
374
|
+
constructor(message?: string, details?: any) {
|
|
375
|
+
super(504, message, { details });
|
|
376
|
+
}
|
|
378
377
|
}
|
|
379
378
|
|
|
380
379
|
// Type definitions for different error factory signatures
|
|
@@ -383,78 +382,78 @@ export class GatewayTimeoutError extends HttpError {
|
|
|
383
382
|
type StandardErrorFactory = (message?: string, details?: any) => HttpError;
|
|
384
383
|
/** Factory function for Method Not Allowed errors with allowed methods */
|
|
385
384
|
type MethodNotAllowedFactory = (
|
|
386
|
-
|
|
387
|
-
|
|
385
|
+
message?: string,
|
|
386
|
+
allowedMethods?: string[],
|
|
388
387
|
) => MethodNotAllowedError;
|
|
389
388
|
/** Factory function for errors that include retry-after information */
|
|
390
389
|
type RetryAfterFactory = (message?: string, retryAfter?: number) => HttpError;
|
|
391
390
|
/** Factory function for validation errors with field-specific errors */
|
|
392
391
|
type ValidationErrorFactory = (
|
|
393
|
-
|
|
394
|
-
|
|
392
|
+
message?: string,
|
|
393
|
+
validationErrors?: any,
|
|
395
394
|
) => UnprocessableEntityError;
|
|
396
395
|
|
|
397
396
|
/** Discriminated union for all factory types */
|
|
398
397
|
type ErrorFactory =
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
398
|
+
| { type: 'standard'; factory: StandardErrorFactory }
|
|
399
|
+
| { type: 'methodNotAllowed'; factory: MethodNotAllowedFactory }
|
|
400
|
+
| { type: 'retryAfter'; factory: RetryAfterFactory }
|
|
401
|
+
| { type: 'validation'; factory: ValidationErrorFactory };
|
|
403
402
|
|
|
404
403
|
/** Type-safe error registry mapping status codes to their factory functions */
|
|
405
404
|
const errorRegistry = {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
405
|
+
400: {
|
|
406
|
+
type: 'standard',
|
|
407
|
+
factory: (m: string, d: any) => new BadRequestError(m, d),
|
|
408
|
+
},
|
|
409
|
+
401: {
|
|
410
|
+
type: 'standard',
|
|
411
|
+
factory: (m: string, d: any) => new UnauthorizedError(m, d),
|
|
412
|
+
},
|
|
413
|
+
403: {
|
|
414
|
+
type: 'standard',
|
|
415
|
+
factory: (m: string, d: any) => new ForbiddenError(m, d),
|
|
416
|
+
},
|
|
417
|
+
404: {
|
|
418
|
+
type: 'standard',
|
|
419
|
+
factory: (m: string, d: any) => new NotFoundError(m, d),
|
|
420
|
+
},
|
|
421
|
+
405: {
|
|
422
|
+
type: 'methodNotAllowed',
|
|
423
|
+
factory: (m: string, am: string[]) => new MethodNotAllowedError(m, am),
|
|
424
|
+
},
|
|
425
|
+
409: {
|
|
426
|
+
type: 'standard',
|
|
427
|
+
factory: (m: string, d: any) => new ConflictError(m, d),
|
|
428
|
+
},
|
|
429
|
+
422: {
|
|
430
|
+
type: 'validation',
|
|
431
|
+
factory: (m: string, ve: any) => new UnprocessableEntityError(m, ve),
|
|
432
|
+
},
|
|
433
|
+
429: {
|
|
434
|
+
type: 'retryAfter',
|
|
435
|
+
factory: (m: string, ra: number) => new TooManyRequestsError(m, ra),
|
|
436
|
+
},
|
|
437
|
+
500: {
|
|
438
|
+
type: 'standard',
|
|
439
|
+
factory: (m: string, d: any) => new InternalServerError(m, d),
|
|
440
|
+
},
|
|
441
|
+
501: {
|
|
442
|
+
type: 'standard',
|
|
443
|
+
factory: (m: string, d: any) => new NotImplementedError(m, d),
|
|
444
|
+
},
|
|
445
|
+
502: {
|
|
446
|
+
type: 'standard',
|
|
447
|
+
factory: (m: string, d: any) => new BadGatewayError(m, d),
|
|
448
|
+
},
|
|
449
|
+
503: {
|
|
450
|
+
type: 'retryAfter',
|
|
451
|
+
factory: (m: string, ra: number) => new ServiceUnavailableError(m, ra),
|
|
452
|
+
},
|
|
453
|
+
504: {
|
|
454
|
+
type: 'standard',
|
|
455
|
+
factory: (m: string, d: any) => new GatewayTimeoutError(m, d),
|
|
456
|
+
},
|
|
458
457
|
} as const;
|
|
459
458
|
|
|
460
459
|
/** Valid status codes that have registered error factories */
|
|
@@ -462,26 +461,26 @@ type ValidStatusCode = keyof typeof errorRegistry;
|
|
|
462
461
|
|
|
463
462
|
/** Type-safe options based on status code, ensuring correct parameters for each error type */
|
|
464
463
|
type ErrorOptions<T extends number> = T extends 405
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
464
|
+
? { allowedMethods?: string[]; code?: string; cause?: Error }
|
|
465
|
+
: T extends 422
|
|
466
|
+
? { validationErrors?: any; code?: string; cause?: Error }
|
|
467
|
+
: T extends 429 | 503
|
|
468
|
+
? { retryAfter?: number; code?: string; cause?: Error }
|
|
469
|
+
: { details?: any; code?: string; cause?: Error };
|
|
471
470
|
|
|
472
471
|
/** Handler functions for each factory type */
|
|
473
472
|
const factoryHandlers: Record<
|
|
474
|
-
|
|
475
|
-
|
|
473
|
+
ErrorFactory['type'],
|
|
474
|
+
(entry: any, message?: string, options?: any) => HttpError
|
|
476
475
|
> = {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
476
|
+
standard: (entry, message, options) =>
|
|
477
|
+
entry.factory(message, options?.details),
|
|
478
|
+
methodNotAllowed: (entry, message, options) =>
|
|
479
|
+
entry.factory(message, options?.allowedMethods),
|
|
480
|
+
retryAfter: (entry, message, options) =>
|
|
481
|
+
entry.factory(message, options?.retryAfter),
|
|
482
|
+
validation: (entry, message, options) =>
|
|
483
|
+
entry.factory(message, options?.validationErrors),
|
|
485
484
|
};
|
|
486
485
|
|
|
487
486
|
/**
|
|
@@ -504,29 +503,29 @@ const factoryHandlers: Record<
|
|
|
504
503
|
* ```
|
|
505
504
|
*/
|
|
506
505
|
export function createHttpError<T extends ValidStatusCode>(
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
506
|
+
statusCode: T,
|
|
507
|
+
message?: string,
|
|
508
|
+
options?: ErrorOptions<T>,
|
|
510
509
|
): HttpError;
|
|
511
510
|
export function createHttpError(
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
511
|
+
statusCode: number,
|
|
512
|
+
message?: string,
|
|
513
|
+
options?: HttpErrorOptions,
|
|
515
514
|
): HttpError;
|
|
516
515
|
export function createHttpError(
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
516
|
+
statusCode: number,
|
|
517
|
+
message?: string,
|
|
518
|
+
options?: any,
|
|
520
519
|
): HttpError {
|
|
521
|
-
|
|
520
|
+
const entry = errorRegistry[statusCode as ValidStatusCode];
|
|
522
521
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
522
|
+
if (entry) {
|
|
523
|
+
const handler = factoryHandlers[entry.type];
|
|
524
|
+
return handler(entry, message, options);
|
|
525
|
+
}
|
|
527
526
|
|
|
528
|
-
|
|
529
|
-
|
|
527
|
+
// Fallback to generic HttpError for unknown status codes
|
|
528
|
+
return new HttpError(statusCode, message, options);
|
|
530
529
|
}
|
|
531
530
|
|
|
532
531
|
/**
|
|
@@ -541,44 +540,44 @@ export function createHttpError(
|
|
|
541
540
|
* ```
|
|
542
541
|
*/
|
|
543
542
|
export const createError = {
|
|
544
|
-
|
|
545
|
-
|
|
543
|
+
badRequest: (message?: string, details?: any) =>
|
|
544
|
+
new BadRequestError(message, details),
|
|
546
545
|
|
|
547
|
-
|
|
548
|
-
|
|
546
|
+
unauthorized: (message?: string, details?: any) =>
|
|
547
|
+
new UnauthorizedError(message, details),
|
|
549
548
|
|
|
550
|
-
|
|
551
|
-
|
|
549
|
+
forbidden: (message?: string, details?: any) =>
|
|
550
|
+
new ForbiddenError(message, details),
|
|
552
551
|
|
|
553
|
-
|
|
554
|
-
|
|
552
|
+
notFound: (message?: string, details?: any) =>
|
|
553
|
+
new NotFoundError(message, details),
|
|
555
554
|
|
|
556
|
-
|
|
557
|
-
|
|
555
|
+
methodNotAllowed: (message?: string, allowedMethods?: string[]) =>
|
|
556
|
+
new MethodNotAllowedError(message, allowedMethods),
|
|
558
557
|
|
|
559
|
-
|
|
560
|
-
|
|
558
|
+
conflict: (message?: string, details?: any) =>
|
|
559
|
+
new ConflictError(message, details),
|
|
561
560
|
|
|
562
|
-
|
|
563
|
-
|
|
561
|
+
unprocessableEntity: (message?: string, validationErrors?: any) =>
|
|
562
|
+
new UnprocessableEntityError(message, validationErrors),
|
|
564
563
|
|
|
565
|
-
|
|
566
|
-
|
|
564
|
+
tooManyRequests: (message?: string, retryAfter?: number) =>
|
|
565
|
+
new TooManyRequestsError(message, retryAfter),
|
|
567
566
|
|
|
568
|
-
|
|
569
|
-
|
|
567
|
+
internalServerError: (message?: string, details?: any) =>
|
|
568
|
+
new InternalServerError(message, details),
|
|
570
569
|
|
|
571
|
-
|
|
572
|
-
|
|
570
|
+
notImplemented: (message?: string, details?: any) =>
|
|
571
|
+
new NotImplementedError(message, details),
|
|
573
572
|
|
|
574
|
-
|
|
575
|
-
|
|
573
|
+
badGateway: (message?: string, details?: any) =>
|
|
574
|
+
new BadGatewayError(message, details),
|
|
576
575
|
|
|
577
|
-
|
|
578
|
-
|
|
576
|
+
serviceUnavailable: (message?: string, retryAfter?: number) =>
|
|
577
|
+
new ServiceUnavailableError(message, retryAfter),
|
|
579
578
|
|
|
580
|
-
|
|
581
|
-
|
|
579
|
+
gatewayTimeout: (message?: string, details?: any) =>
|
|
580
|
+
new GatewayTimeoutError(message, details),
|
|
582
581
|
} as const;
|
|
583
582
|
|
|
584
583
|
// Type guards
|
|
@@ -602,13 +601,13 @@ export const createError = {
|
|
|
602
601
|
* ```
|
|
603
602
|
*/
|
|
604
603
|
export function isHttpError(error: unknown): error is HttpError {
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
604
|
+
return (
|
|
605
|
+
error instanceof HttpError ||
|
|
606
|
+
(error !== null &&
|
|
607
|
+
typeof error === 'object' &&
|
|
608
|
+
'isHttpError' in error &&
|
|
609
|
+
error.isHttpError === true)
|
|
610
|
+
);
|
|
612
611
|
}
|
|
613
612
|
|
|
614
613
|
/**
|
|
@@ -625,9 +624,9 @@ export function isHttpError(error: unknown): error is HttpError {
|
|
|
625
624
|
* ```
|
|
626
625
|
*/
|
|
627
626
|
export function isClientError(error: unknown): error is HttpError {
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
627
|
+
return (
|
|
628
|
+
isHttpError(error) && error.statusCode >= 400 && error.statusCode < 500
|
|
629
|
+
);
|
|
631
630
|
}
|
|
632
631
|
|
|
633
632
|
/**
|
|
@@ -644,9 +643,9 @@ export function isClientError(error: unknown): error is HttpError {
|
|
|
644
643
|
* ```
|
|
645
644
|
*/
|
|
646
645
|
export function isServerError(error: unknown): error is HttpError {
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
646
|
+
return (
|
|
647
|
+
isHttpError(error) && error.statusCode >= 500 && error.statusCode < 600
|
|
648
|
+
);
|
|
650
649
|
}
|
|
651
650
|
|
|
652
651
|
// Utility functions
|
|
@@ -670,21 +669,21 @@ export function isServerError(error: unknown): error is HttpError {
|
|
|
670
669
|
* ```
|
|
671
670
|
*/
|
|
672
671
|
export function wrapError(
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
672
|
+
error: unknown,
|
|
673
|
+
statusCode = 500,
|
|
674
|
+
message?: string,
|
|
676
675
|
): HttpError {
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
676
|
+
if (isHttpError(error)) {
|
|
677
|
+
return error;
|
|
678
|
+
}
|
|
680
679
|
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
680
|
+
if (error instanceof HttpError) {
|
|
681
|
+
return error;
|
|
682
|
+
}
|
|
684
683
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
684
|
+
return new HttpError(statusCode, message || 'An unknown error occurred', {
|
|
685
|
+
details: { originalError: error },
|
|
686
|
+
});
|
|
688
687
|
}
|
|
689
688
|
|
|
690
689
|
// Types for better TypeScript support
|
|
@@ -693,10 +692,10 @@ export function wrapError(
|
|
|
693
692
|
* Options for creating an HttpError.
|
|
694
693
|
*/
|
|
695
694
|
export interface HttpErrorOptions {
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
695
|
+
statusMessage?: string;
|
|
696
|
+
details?: any;
|
|
697
|
+
code?: string;
|
|
698
|
+
cause?: Error;
|
|
700
699
|
}
|
|
701
700
|
|
|
702
701
|
/**
|
|
@@ -704,8 +703,8 @@ export interface HttpErrorOptions {
|
|
|
704
703
|
* Useful for factory patterns and dependency injection.
|
|
705
704
|
*/
|
|
706
705
|
export type HttpErrorConstructor = new (
|
|
707
|
-
|
|
708
|
-
|
|
706
|
+
message?: string,
|
|
707
|
+
options?: HttpErrorOptions,
|
|
709
708
|
) => HttpError;
|
|
710
709
|
|
|
711
710
|
/**
|
|
@@ -713,36 +712,36 @@ export type HttpErrorConstructor = new (
|
|
|
713
712
|
* Includes common 2xx, 3xx, 4xx, and 5xx status codes.
|
|
714
713
|
*/
|
|
715
714
|
export enum HttpStatusCode {
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
715
|
+
// 2xx Success
|
|
716
|
+
OK = 200,
|
|
717
|
+
CREATED = 201,
|
|
718
|
+
ACCEPTED = 202,
|
|
719
|
+
NO_CONTENT = 204,
|
|
720
|
+
|
|
721
|
+
// 3xx Redirection
|
|
722
|
+
MOVED_PERMANENTLY = 301,
|
|
723
|
+
FOUND = 302,
|
|
724
|
+
NOT_MODIFIED = 304,
|
|
725
|
+
|
|
726
|
+
// 4xx Client Error
|
|
727
|
+
BAD_REQUEST = 400,
|
|
728
|
+
UNAUTHORIZED = 401,
|
|
729
|
+
FORBIDDEN = 403,
|
|
730
|
+
NOT_FOUND = 404,
|
|
731
|
+
METHOD_NOT_ALLOWED = 405,
|
|
732
|
+
NOT_ACCEPTABLE = 406,
|
|
733
|
+
REQUEST_TIMEOUT = 408,
|
|
734
|
+
CONFLICT = 409,
|
|
735
|
+
GONE = 410,
|
|
736
|
+
UNPROCESSABLE_ENTITY = 422,
|
|
737
|
+
TOO_MANY_REQUESTS = 429,
|
|
738
|
+
|
|
739
|
+
// 5xx Server Error
|
|
740
|
+
INTERNAL_SERVER_ERROR = 500,
|
|
741
|
+
NOT_IMPLEMENTED = 501,
|
|
742
|
+
BAD_GATEWAY = 502,
|
|
743
|
+
SERVICE_UNAVAILABLE = 503,
|
|
744
|
+
GATEWAY_TIMEOUT = 504,
|
|
746
745
|
}
|
|
747
746
|
|
|
748
747
|
/**
|
|
@@ -756,20 +755,20 @@ export enum HttpStatusCode {
|
|
|
756
755
|
* ```
|
|
757
756
|
*/
|
|
758
757
|
export const HttpErrors = {
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
758
|
+
HttpError,
|
|
759
|
+
BadRequestError,
|
|
760
|
+
UnauthorizedError,
|
|
761
|
+
ForbiddenError,
|
|
762
|
+
NotFoundError,
|
|
763
|
+
MethodNotAllowedError,
|
|
764
|
+
ConflictError,
|
|
765
|
+
UnprocessableEntityError,
|
|
766
|
+
TooManyRequestsError,
|
|
767
|
+
InternalServerError,
|
|
768
|
+
NotImplementedError,
|
|
769
|
+
BadGatewayError,
|
|
770
|
+
ServiceUnavailableError,
|
|
771
|
+
GatewayTimeoutError,
|
|
773
772
|
};
|
|
774
773
|
|
|
775
774
|
// Usage examples:
|