@stacksjs/bun-router 0.0.17 → 0.0.18
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/dist/cli.js +1 -1
- package/dist/container/service-provider.d.ts +3 -3
- package/dist/development/performance-profiler.d.ts +3 -3
- package/dist/development/route-debugger.d.ts +1 -1
- package/dist/development/route-inspector.d.ts +2 -2
- package/dist/observability/integration.d.ts +1 -1
- package/dist/response/macros.d.ts +1 -1
- package/dist/router/index.d.ts +7 -7
- package/dist/router/router.d.ts +0 -32
- package/dist/testing/performance-testing.d.ts +2 -2
- package/dist/testing/test-client.d.ts +1 -1
- package/dist/testing/websocket-testing.d.ts +1 -1
- package/package.json +2 -3
- package/src/auth.ts +0 -489
- package/src/cache/lru-cache.ts +0 -457
- package/src/cache/middleware-memoization.ts +0 -531
- package/src/cache/route-cache-warmer.ts +0 -486
- package/src/cache/sqlite-cache.ts +0 -783
- package/src/cache/streaming-cache.ts +0 -572
- package/src/cli/colors.ts +0 -29
- package/src/cli/index.ts +0 -287
- package/src/cli/middleware.ts +0 -291
- package/src/cli/openapi.ts +0 -407
- package/src/cli/router.ts +0 -188
- package/src/cli/routes.ts +0 -265
- package/src/cli/utils.ts +0 -531
- package/src/cli.ts +0 -5
- package/src/config.ts +0 -322
- package/src/container/container.ts +0 -786
- package/src/container/contextual-binding.ts +0 -606
- package/src/container/decorators.ts +0 -368
- package/src/container/index.ts +0 -49
- package/src/container/service-provider.ts +0 -596
- package/src/development/hot-reload.ts +0 -673
- package/src/development/index.ts +0 -499
- package/src/development/performance-profiler.ts +0 -717
- package/src/development/route-debugger.ts +0 -527
- package/src/development/route-inspector.ts +0 -749
- package/src/development/typescript-utilities.ts +0 -682
- package/src/docs.ts +0 -397
- package/src/errors/circuit-breaker.ts +0 -733
- package/src/errors/error-handler.ts +0 -569
- package/src/errors/error-reporting.ts +0 -672
- package/src/errors/exceptions.ts +0 -536
- package/src/errors/graceful-degradation.ts +0 -623
- package/src/errors/index.ts +0 -21
- package/src/errors/router-errors.ts +0 -632
- package/src/file-serving/static-files.ts +0 -718
- package/src/index.ts +0 -66
- package/src/middleware/auth.ts +0 -220
- package/src/middleware/content_security_policy.ts +0 -215
- package/src/middleware/cors.ts +0 -142
- package/src/middleware/csrf.ts +0 -166
- package/src/middleware/ddos_protection.ts +0 -279
- package/src/middleware/file_security.ts +0 -191
- package/src/middleware/file_upload.ts +0 -275
- package/src/middleware/helmet.ts +0 -268
- package/src/middleware/index.ts +0 -117
- package/src/middleware/input_validation.ts +0 -453
- package/src/middleware/json_body.ts +0 -37
- package/src/middleware/performance_alerting.ts +0 -540
- package/src/middleware/performance_dashboard.ts +0 -661
- package/src/middleware/performance_monitor.ts +0 -945
- package/src/middleware/pipeline.ts +0 -489
- package/src/middleware/rate_limit.ts +0 -251
- package/src/middleware/request_id.ts +0 -36
- package/src/middleware/request_signing.ts +0 -638
- package/src/middleware/request_tracer.ts +0 -653
- package/src/middleware/response_cache.ts +0 -778
- package/src/middleware/security.ts +0 -482
- package/src/middleware/security_suite.ts +0 -257
- package/src/middleware/session.ts +0 -91
- package/src/model-binding/index.ts +0 -18
- package/src/model-binding/model-middleware.ts +0 -425
- package/src/model-binding/model-registry.ts +0 -550
- package/src/model-binding.ts +0 -370
- package/src/model-resolver-factory.ts +0 -106
- package/src/observability/correlation.ts +0 -691
- package/src/observability/health-checks.ts +0 -729
- package/src/observability/index.ts +0 -184
- package/src/observability/integration.ts +0 -548
- package/src/observability/metrics.ts +0 -753
- package/src/observability/tracing.ts +0 -638
- package/src/optimization/bun-utilities.ts +0 -778
- package/src/query-builder-integration.ts +0 -137
- package/src/request/context.ts +0 -109
- package/src/request/enhanced-request.ts +0 -876
- package/src/request/macros.ts +0 -822
- package/src/response/macros.ts +0 -665
- package/src/response/response-factory.ts +0 -596
- package/src/router/api-routes.ts +0 -243
- package/src/router/file-based-routing.ts +0 -697
- package/src/router/file-streaming.ts +0 -383
- package/src/router/fluent-routing.ts +0 -866
- package/src/router/group-organization.ts +0 -229
- package/src/router/handler-resolver.ts +0 -327
- package/src/router/http-methods.ts +0 -407
- package/src/router/index.ts +0 -193
- package/src/router/middleware-groups.ts +0 -222
- package/src/router/middleware-integration.ts +0 -399
- package/src/router/middleware.ts +0 -234
- package/src/router/model-binding.ts +0 -215
- package/src/router/optimized-route-matching.ts +0 -302
- package/src/router/route-building.ts +0 -221
- package/src/router/route-compiler.ts +0 -691
- package/src/router/route-matching.ts +0 -368
- package/src/router/route-trie.ts +0 -450
- package/src/router/router.ts +0 -1616
- package/src/router/server.ts +0 -684
- package/src/router/validation-integration.ts +0 -449
- package/src/router/view-rendering.ts +0 -233
- package/src/router/websocket.ts +0 -100
- package/src/routing/route-caching.ts +0 -402
- package/src/routing/route-throttling.ts +0 -469
- package/src/routing/subdomain-routing.ts +0 -492
- package/src/session/database-store.ts +0 -109
- package/src/session/file-store.ts +0 -148
- package/src/session/index.ts +0 -244
- package/src/session/memory-store.ts +0 -88
- package/src/session/redis-store.ts +0 -93
- package/src/streaming/index.ts +0 -17
- package/src/streaming/sse-handler.ts +0 -482
- package/src/streaming/stream-handler.ts +0 -552
- package/src/testing/auth-testing.ts +0 -448
- package/src/testing/file-upload-testing.ts +0 -543
- package/src/testing/index.ts +0 -10
- package/src/testing/middleware-testing.ts +0 -322
- package/src/testing/model-binding-testing.ts +0 -645
- package/src/testing/performance-testing.ts +0 -738
- package/src/testing/test-client.ts +0 -310
- package/src/testing/test-request.ts +0 -315
- package/src/testing/test-response.ts +0 -332
- package/src/testing/types.ts +0 -224
- package/src/testing/websocket-testing.ts +0 -590
- package/src/types/controller-types.ts +0 -385
- package/src/types/core.ts +0 -683
- package/src/types/middleware-types.ts +0 -422
- package/src/types/request-response-augmentation.ts +0 -489
- package/src/types/route-inference.ts +0 -372
- package/src/types.ts +0 -2123
- package/src/url.ts +0 -131
- package/src/utils/index.ts +0 -1
- package/src/utils/query-preservation.ts +0 -201
- package/src/utils.ts +0 -395
- package/src/validation/validator.ts +0 -688
- package/src/websocket/clustering.ts +0 -769
|
@@ -1,569 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Advanced Error Handling - Main Error Handler Middleware
|
|
3
|
-
*
|
|
4
|
-
* Unified error handling middleware that integrates all error handling components
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { CircuitBreakerConfig, DegradationConfig, EnhancedRequest, ErrorContext, ErrorReportingConfig } from '../types'
|
|
8
|
-
import { CircuitBreakerRegistry } from './circuit-breaker'
|
|
9
|
-
import { ErrorReportingManager } from './error-reporting'
|
|
10
|
-
import { ErrorFactory, RouterException } from './exceptions'
|
|
11
|
-
import { GracefulDegradationManager } from './graceful-degradation'
|
|
12
|
-
|
|
13
|
-
export interface AdvancedErrorHandlerConfig {
|
|
14
|
-
errorReporting?: ErrorReportingConfig[]
|
|
15
|
-
gracefulDegradation?: DegradationConfig
|
|
16
|
-
circuitBreakers?: CircuitBreakerConfig[]
|
|
17
|
-
globalErrorHandler?: (error: RouterException, req: EnhancedRequest) => Promise<Response>
|
|
18
|
-
development?: boolean
|
|
19
|
-
includeStackTrace?: boolean
|
|
20
|
-
sanitizeErrors?: boolean
|
|
21
|
-
logErrors?: boolean
|
|
22
|
-
customErrorPages?: {
|
|
23
|
-
[statusCode: number]: string | ((_error: RouterException, _req: EnhancedRequest) => Promise<Response>)
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Advanced error handler middleware
|
|
29
|
-
*/
|
|
30
|
-
export class AdvancedErrorHandler {
|
|
31
|
-
private errorReporting?: ErrorReportingManager
|
|
32
|
-
private gracefulDegradation?: GracefulDegradationManager
|
|
33
|
-
private circuitBreakerRegistry?: CircuitBreakerRegistry
|
|
34
|
-
private config: AdvancedErrorHandlerConfig
|
|
35
|
-
|
|
36
|
-
constructor(config: AdvancedErrorHandlerConfig = {}) {
|
|
37
|
-
this.config = {
|
|
38
|
-
development: false,
|
|
39
|
-
includeStackTrace: false,
|
|
40
|
-
sanitizeErrors: true,
|
|
41
|
-
logErrors: true,
|
|
42
|
-
...config,
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
this.initializeComponents()
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
private initializeComponents(): void {
|
|
49
|
-
// Initialize error reporting
|
|
50
|
-
if (this.config.errorReporting?.length) {
|
|
51
|
-
this.errorReporting = new ErrorReportingManager(this.config.errorReporting)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Initialize graceful degradation
|
|
55
|
-
if (this.config.gracefulDegradation?.enabled) {
|
|
56
|
-
this.gracefulDegradation = new GracefulDegradationManager(this.config.gracefulDegradation)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Initialize circuit breakers
|
|
60
|
-
if (this.config.circuitBreakers?.length) {
|
|
61
|
-
this.circuitBreakerRegistry = new CircuitBreakerRegistry()
|
|
62
|
-
for (const config of this.config.circuitBreakers) {
|
|
63
|
-
this.circuitBreakerRegistry.register(config)
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Main error handling middleware
|
|
70
|
-
*/
|
|
71
|
-
middleware() {
|
|
72
|
-
return async (req: EnhancedRequest, next: () => Promise<Response>): Promise<Response> => {
|
|
73
|
-
try {
|
|
74
|
-
// Add error context to request
|
|
75
|
-
const errorContext: ErrorContext = {
|
|
76
|
-
requestId: req.requestId,
|
|
77
|
-
userId: req.user?.id,
|
|
78
|
-
traceId: req.traceId,
|
|
79
|
-
spanId: req.spanId,
|
|
80
|
-
route: req.params?.route || req.url,
|
|
81
|
-
method: req.method,
|
|
82
|
-
url: req.url,
|
|
83
|
-
userAgent: (req as any).userAgent?.() || undefined,
|
|
84
|
-
ip: (req as any).ip?.() || undefined,
|
|
85
|
-
timestamp: new Date(),
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
req.context = { ...req.context, errorContext }
|
|
89
|
-
|
|
90
|
-
// Execute request with circuit breaker protection if configured
|
|
91
|
-
if (this.circuitBreakerRegistry && req.context?.serviceName) {
|
|
92
|
-
const breaker = this.circuitBreakerRegistry.get(req.context.serviceName as string)
|
|
93
|
-
if (breaker) {
|
|
94
|
-
return await breaker.execute({
|
|
95
|
-
execute: next,
|
|
96
|
-
context: errorContext,
|
|
97
|
-
})
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return await next()
|
|
102
|
-
}
|
|
103
|
-
catch (error) {
|
|
104
|
-
return this.handleError(error, req)
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Handle errors with full advanced error handling pipeline
|
|
111
|
-
*/
|
|
112
|
-
async handleError(error: unknown, req: EnhancedRequest): Promise<Response> {
|
|
113
|
-
// Convert to RouterException if needed
|
|
114
|
-
const routerError = this.normalizeError(error, req)
|
|
115
|
-
|
|
116
|
-
// Add breadcrumb for error reporting
|
|
117
|
-
if (this.errorReporting) {
|
|
118
|
-
this.errorReporting.addBreadcrumb(
|
|
119
|
-
`Error in ${req.method} ${req.url}`,
|
|
120
|
-
'error',
|
|
121
|
-
{
|
|
122
|
-
code: routerError.code,
|
|
123
|
-
severity: routerError.severity,
|
|
124
|
-
statusCode: routerError.statusCode,
|
|
125
|
-
},
|
|
126
|
-
)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Log error if configured
|
|
130
|
-
if (this.config.logErrors) {
|
|
131
|
-
this.logError(routerError, req)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Try graceful degradation if configured
|
|
135
|
-
if (this.gracefulDegradation && req.context?.serviceName) {
|
|
136
|
-
try {
|
|
137
|
-
return await this.gracefulDegradation.handleFailure(
|
|
138
|
-
req.context.serviceName as string,
|
|
139
|
-
routerError,
|
|
140
|
-
req,
|
|
141
|
-
async () => {
|
|
142
|
-
throw routerError // This will trigger fallback strategies
|
|
143
|
-
},
|
|
144
|
-
)
|
|
145
|
-
}
|
|
146
|
-
catch {
|
|
147
|
-
// Graceful degradation failed, continue with normal error handling
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Report error to external services
|
|
152
|
-
if (this.errorReporting) {
|
|
153
|
-
try {
|
|
154
|
-
await this.errorReporting.report(routerError, routerError.context)
|
|
155
|
-
}
|
|
156
|
-
catch (reportingError) {
|
|
157
|
-
console.error('Failed to report error:', reportingError)
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Use custom global error handler if provided
|
|
162
|
-
if (this.config.globalErrorHandler) {
|
|
163
|
-
try {
|
|
164
|
-
return await this.config.globalErrorHandler(routerError, req)
|
|
165
|
-
}
|
|
166
|
-
catch (handlerError) {
|
|
167
|
-
console.error('Global error handler failed:', handlerError)
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Use custom error page if configured
|
|
172
|
-
const customPage = this.config.customErrorPages?.[routerError.statusCode]
|
|
173
|
-
if (customPage) {
|
|
174
|
-
try {
|
|
175
|
-
if (typeof customPage === 'string') {
|
|
176
|
-
return new Response(customPage, {
|
|
177
|
-
status: routerError.statusCode,
|
|
178
|
-
headers: { 'Content-Type': 'text/html' },
|
|
179
|
-
})
|
|
180
|
-
}
|
|
181
|
-
else {
|
|
182
|
-
return await customPage(routerError, req)
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
catch (pageError) {
|
|
186
|
-
console.error('Custom error page failed:', pageError)
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Default error response
|
|
191
|
-
return this.createErrorResponse(routerError, req)
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Convert any error to RouterException
|
|
196
|
-
*/
|
|
197
|
-
private normalizeError(error: unknown, req: EnhancedRequest): RouterException {
|
|
198
|
-
const errorContext: ErrorContext = {
|
|
199
|
-
requestId: req.requestId,
|
|
200
|
-
userId: req.user?.id,
|
|
201
|
-
traceId: req.traceId,
|
|
202
|
-
spanId: req.spanId,
|
|
203
|
-
route: req.params?.route || req.url,
|
|
204
|
-
method: req.method,
|
|
205
|
-
url: req.url,
|
|
206
|
-
userAgent: (req as any).userAgent?.() || undefined,
|
|
207
|
-
ip: (req as any).ip?.() || undefined,
|
|
208
|
-
timestamp: new Date(),
|
|
209
|
-
metadata: req.context,
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// Already a RouterException
|
|
213
|
-
if (error instanceof RouterException) {
|
|
214
|
-
return error
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Standard Error
|
|
218
|
-
if (error instanceof Error) {
|
|
219
|
-
// Check for specific error types
|
|
220
|
-
if (error.name === 'ValidationError') {
|
|
221
|
-
return ErrorFactory.validation(error.message, {}, errorContext)
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (error.name === 'UnauthorizedError' || error.message.includes('unauthorized')) {
|
|
225
|
-
return ErrorFactory.authentication(error.message, errorContext)
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if (error.name === 'ForbiddenError' || error.message.includes('forbidden')) {
|
|
229
|
-
return ErrorFactory.authorization(error.message, [], errorContext)
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (error.name === 'NotFoundError' || error.message.includes('not found')) {
|
|
233
|
-
return ErrorFactory.notFound(undefined, undefined, errorContext)
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (error.name === 'TimeoutError' || error.message.includes('timeout')) {
|
|
237
|
-
return ErrorFactory.timeout(30000, error.message, errorContext)
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Generic internal server error
|
|
241
|
-
return ErrorFactory.internalServer(error.message, error, errorContext)
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// String error
|
|
245
|
-
if (typeof error === 'string') {
|
|
246
|
-
return ErrorFactory.internalServer(error, undefined, errorContext)
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// Unknown error type
|
|
250
|
-
return ErrorFactory.internalServer('An unknown error occurred', undefined, errorContext)
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* Create standardized error response
|
|
255
|
-
*/
|
|
256
|
-
private createErrorResponse(error: RouterException, _req: EnhancedRequest): Response {
|
|
257
|
-
const isDevelopment = this.config.development
|
|
258
|
-
const includeStackTrace = this.config.includeStackTrace || isDevelopment
|
|
259
|
-
const sanitizeErrors = this.config.sanitizeErrors && !isDevelopment
|
|
260
|
-
|
|
261
|
-
// Sanitize error message for production
|
|
262
|
-
let message = error.message
|
|
263
|
-
if (sanitizeErrors && error.statusCode >= 500) {
|
|
264
|
-
message = 'An internal server error occurred'
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
const errorResponse: any = {
|
|
268
|
-
error: {
|
|
269
|
-
code: error.code,
|
|
270
|
-
message,
|
|
271
|
-
statusCode: error.statusCode,
|
|
272
|
-
timestamp: error.timestamp.toISOString(),
|
|
273
|
-
requestId: error.context.requestId,
|
|
274
|
-
traceId: error.context.traceId,
|
|
275
|
-
},
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// Add additional fields in development
|
|
279
|
-
if (isDevelopment) {
|
|
280
|
-
errorResponse.error.category = error.category
|
|
281
|
-
errorResponse.error.severity = error.severity
|
|
282
|
-
errorResponse.error.retryable = error.retryable
|
|
283
|
-
errorResponse.error.context = error.context
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// Add stack trace if configured
|
|
287
|
-
if (includeStackTrace) {
|
|
288
|
-
errorResponse.error.stack = error.stack
|
|
289
|
-
if (error.cause) {
|
|
290
|
-
errorResponse.error.cause = {
|
|
291
|
-
name: error.cause.name,
|
|
292
|
-
message: error.cause.message,
|
|
293
|
-
stack: error.cause.stack,
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// Add validation fields for validation errors
|
|
299
|
-
if ('fields' in error) {
|
|
300
|
-
errorResponse.error.fields = (error as any).fields
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
// Add specific error type fields
|
|
304
|
-
if ('allowedMethods' in error) {
|
|
305
|
-
errorResponse.error.allowedMethods = (error as any).allowedMethods
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
if ('retryAfter' in error) {
|
|
309
|
-
errorResponse.error.retryAfter = (error as any).retryAfter
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
const headers = new Headers({
|
|
313
|
-
'Content-Type': 'application/json',
|
|
314
|
-
'X-Error-Code': error.code,
|
|
315
|
-
'X-Request-ID': error.context.requestId || '',
|
|
316
|
-
'X-Trace-ID': error.context.traceId || '',
|
|
317
|
-
})
|
|
318
|
-
|
|
319
|
-
// Add specific headers for certain error types
|
|
320
|
-
if ('allowedMethods' in error) {
|
|
321
|
-
headers.set('Allow', (error as any).allowedMethods.join(', '))
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if ('retryAfter' in error) {
|
|
325
|
-
headers.set('Retry-After', (error as any).retryAfter.toString())
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if ('limit' in error) {
|
|
329
|
-
headers.set('X-RateLimit-Limit', (error as any).limit.toString())
|
|
330
|
-
headers.set('X-RateLimit-Remaining', (error as any).remaining.toString())
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
return new Response(JSON.stringify(errorResponse), {
|
|
334
|
-
status: error.statusCode,
|
|
335
|
-
headers,
|
|
336
|
-
})
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
/**
|
|
340
|
-
* Log error with appropriate level
|
|
341
|
-
*/
|
|
342
|
-
private logError(error: RouterException, req: EnhancedRequest): void {
|
|
343
|
-
const logData = {
|
|
344
|
-
error: error.toJSON(),
|
|
345
|
-
request: {
|
|
346
|
-
method: req.method,
|
|
347
|
-
url: req.url,
|
|
348
|
-
headers: Object.fromEntries(req.headers.entries()),
|
|
349
|
-
userAgent: (req as any).userAgent?.() || undefined,
|
|
350
|
-
ip: (req as any).ip?.() || undefined,
|
|
351
|
-
requestId: req.requestId,
|
|
352
|
-
traceId: req.traceId,
|
|
353
|
-
},
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
switch (error.severity) {
|
|
357
|
-
case 'critical':
|
|
358
|
-
console.error('[CRITICAL ERROR]', logData)
|
|
359
|
-
break
|
|
360
|
-
case 'high':
|
|
361
|
-
console.error('[ERROR]', logData)
|
|
362
|
-
break
|
|
363
|
-
case 'medium':
|
|
364
|
-
console.warn('[WARNING]', logData)
|
|
365
|
-
break
|
|
366
|
-
case 'low':
|
|
367
|
-
console.warn('[INFO]', logData)
|
|
368
|
-
break
|
|
369
|
-
default:
|
|
370
|
-
console.error('[ERROR]', logData)
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
/**
|
|
375
|
-
* Get error handler statistics
|
|
376
|
-
*/
|
|
377
|
-
getStats(): {
|
|
378
|
-
errorReporting?: any
|
|
379
|
-
gracefulDegradation?: any
|
|
380
|
-
circuitBreakers?: any
|
|
381
|
-
} {
|
|
382
|
-
return {
|
|
383
|
-
errorReporting: this.errorReporting
|
|
384
|
-
? {
|
|
385
|
-
breadcrumbs: this.errorReporting.getBreadcrumbs().length,
|
|
386
|
-
}
|
|
387
|
-
: undefined,
|
|
388
|
-
gracefulDegradation: this.gracefulDegradation
|
|
389
|
-
? this.gracefulDegradation.getSystemHealth()
|
|
390
|
-
: undefined,
|
|
391
|
-
circuitBreakers: this.circuitBreakerRegistry
|
|
392
|
-
? this.circuitBreakerRegistry.getAllMetrics()
|
|
393
|
-
: undefined,
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* Cleanup resources
|
|
399
|
-
*/
|
|
400
|
-
async cleanup(): Promise<void> {
|
|
401
|
-
if (this.errorReporting) {
|
|
402
|
-
await this.errorReporting.close()
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
if (this.gracefulDegradation) {
|
|
406
|
-
this.gracefulDegradation.stop()
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
/**
|
|
412
|
-
* Factory function to create advanced error handler middleware
|
|
413
|
-
*/
|
|
414
|
-
export function createAdvancedErrorHandler(config: AdvancedErrorHandlerConfig = {}): {
|
|
415
|
-
middleware: (req: EnhancedRequest, next: () => Promise<Response>) => Promise<Response>
|
|
416
|
-
getStats: () => { errorReporting?: any, gracefulDegradation?: any, circuitBreakers?: any }
|
|
417
|
-
cleanup: () => Promise<void>
|
|
418
|
-
} {
|
|
419
|
-
const handler = new AdvancedErrorHandler(config)
|
|
420
|
-
return {
|
|
421
|
-
middleware: handler.middleware(),
|
|
422
|
-
getStats: (): { errorReporting?: any, gracefulDegradation?: any, circuitBreakers?: any } => handler.getStats(),
|
|
423
|
-
cleanup: (): Promise<void> => handler.cleanup(),
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
/**
|
|
428
|
-
* Preset configurations for different environments
|
|
429
|
-
*/
|
|
430
|
-
export const ErrorHandlerPresets = {
|
|
431
|
-
development: (): AdvancedErrorHandlerConfig => ({
|
|
432
|
-
development: true,
|
|
433
|
-
includeStackTrace: true,
|
|
434
|
-
sanitizeErrors: false,
|
|
435
|
-
logErrors: true,
|
|
436
|
-
errorReporting: [],
|
|
437
|
-
}),
|
|
438
|
-
|
|
439
|
-
production: (sentryDsn?: string, bugsnagApiKey?: string): AdvancedErrorHandlerConfig => ({
|
|
440
|
-
development: false,
|
|
441
|
-
includeStackTrace: false,
|
|
442
|
-
sanitizeErrors: true,
|
|
443
|
-
logErrors: true,
|
|
444
|
-
errorReporting: [
|
|
445
|
-
...(sentryDsn
|
|
446
|
-
? [{
|
|
447
|
-
enabled: true,
|
|
448
|
-
service: 'sentry' as const,
|
|
449
|
-
dsn: sentryDsn,
|
|
450
|
-
environment: 'production',
|
|
451
|
-
sampleRate: 1.0,
|
|
452
|
-
breadcrumbs: { enabled: true, maxBreadcrumbs: 100 },
|
|
453
|
-
performance: { enabled: true, tracesSampleRate: 0.1 },
|
|
454
|
-
}]
|
|
455
|
-
: []),
|
|
456
|
-
...(bugsnagApiKey
|
|
457
|
-
? [{
|
|
458
|
-
enabled: true,
|
|
459
|
-
service: 'bugsnag' as const,
|
|
460
|
-
apiKey: bugsnagApiKey,
|
|
461
|
-
environment: 'production',
|
|
462
|
-
breadcrumbs: { enabled: true, maxBreadcrumbs: 25 },
|
|
463
|
-
}]
|
|
464
|
-
: []),
|
|
465
|
-
],
|
|
466
|
-
}),
|
|
467
|
-
|
|
468
|
-
staging: (sentryDsn?: string): AdvancedErrorHandlerConfig => ({
|
|
469
|
-
development: false,
|
|
470
|
-
includeStackTrace: true,
|
|
471
|
-
sanitizeErrors: false,
|
|
472
|
-
logErrors: true,
|
|
473
|
-
errorReporting: sentryDsn
|
|
474
|
-
? [{
|
|
475
|
-
enabled: true,
|
|
476
|
-
service: 'sentry',
|
|
477
|
-
dsn: sentryDsn,
|
|
478
|
-
environment: 'staging',
|
|
479
|
-
sampleRate: 1.0,
|
|
480
|
-
breadcrumbs: { enabled: true, maxBreadcrumbs: 100 },
|
|
481
|
-
}]
|
|
482
|
-
: [],
|
|
483
|
-
}),
|
|
484
|
-
|
|
485
|
-
resilient: (config: {
|
|
486
|
-
sentryDsn?: string
|
|
487
|
-
bugsnagApiKey?: string
|
|
488
|
-
services?: string[]
|
|
489
|
-
} = {}): AdvancedErrorHandlerConfig => ({
|
|
490
|
-
development: false,
|
|
491
|
-
includeStackTrace: false,
|
|
492
|
-
sanitizeErrors: true,
|
|
493
|
-
logErrors: true,
|
|
494
|
-
errorReporting: [
|
|
495
|
-
...(config.sentryDsn
|
|
496
|
-
? [{
|
|
497
|
-
enabled: true,
|
|
498
|
-
service: 'sentry' as const,
|
|
499
|
-
dsn: config.sentryDsn,
|
|
500
|
-
environment: 'production',
|
|
501
|
-
sampleRate: 1.0,
|
|
502
|
-
breadcrumbs: { enabled: true, maxBreadcrumbs: 100 },
|
|
503
|
-
performance: { enabled: true, tracesSampleRate: 0.1 },
|
|
504
|
-
}]
|
|
505
|
-
: []),
|
|
506
|
-
...(config.bugsnagApiKey
|
|
507
|
-
? [{
|
|
508
|
-
enabled: true,
|
|
509
|
-
service: 'bugsnag' as const,
|
|
510
|
-
apiKey: config.bugsnagApiKey,
|
|
511
|
-
environment: 'production',
|
|
512
|
-
breadcrumbs: { enabled: true, maxBreadcrumbs: 25 },
|
|
513
|
-
}]
|
|
514
|
-
: []),
|
|
515
|
-
],
|
|
516
|
-
gracefulDegradation: {
|
|
517
|
-
enabled: true,
|
|
518
|
-
fallbackStrategies: Object.fromEntries(
|
|
519
|
-
(config.services || ['database', 'cache', 'external-api']).map(service => [
|
|
520
|
-
service,
|
|
521
|
-
{
|
|
522
|
-
type: 'cache' as const,
|
|
523
|
-
priority: 1,
|
|
524
|
-
timeout: 5000,
|
|
525
|
-
retries: 2,
|
|
526
|
-
backoff: { type: 'exponential' as const, delay: 1000, maxDelay: 5000 },
|
|
527
|
-
cacheConfig: {
|
|
528
|
-
key: `${service}:{url}:{method}`,
|
|
529
|
-
ttl: 3600,
|
|
530
|
-
staleWhileRevalidate: true,
|
|
531
|
-
},
|
|
532
|
-
},
|
|
533
|
-
]),
|
|
534
|
-
),
|
|
535
|
-
healthChecks: Object.fromEntries(
|
|
536
|
-
(config.services || []).map(service => [
|
|
537
|
-
service,
|
|
538
|
-
{
|
|
539
|
-
enabled: true,
|
|
540
|
-
endpoint: `/health/${service}`,
|
|
541
|
-
interval: 30000,
|
|
542
|
-
timeout: 5000,
|
|
543
|
-
retries: 3,
|
|
544
|
-
expectedStatus: [200],
|
|
545
|
-
},
|
|
546
|
-
]),
|
|
547
|
-
),
|
|
548
|
-
monitoring: {
|
|
549
|
-
enabled: true,
|
|
550
|
-
alertThresholds: {
|
|
551
|
-
errorRate: 10,
|
|
552
|
-
responseTime: 5000,
|
|
553
|
-
availability: 95,
|
|
554
|
-
},
|
|
555
|
-
},
|
|
556
|
-
},
|
|
557
|
-
circuitBreakers: (config.services || ['database', 'cache', 'external-api']).map(service => ({
|
|
558
|
-
name: service,
|
|
559
|
-
failureThreshold: 5,
|
|
560
|
-
recoveryTimeout: 60000,
|
|
561
|
-
timeout: 30000,
|
|
562
|
-
monitoringPeriod: 60000,
|
|
563
|
-
minimumRequests: 10,
|
|
564
|
-
errorThresholdPercentage: 50,
|
|
565
|
-
halfOpenMaxCalls: 3,
|
|
566
|
-
resetTimeout: 60000,
|
|
567
|
-
})),
|
|
568
|
-
}),
|
|
569
|
-
}
|