@stacksjs/bun-router 0.0.13 → 0.0.14
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 +770 -0
- package/README.md +584 -261
- package/package.json +43 -47
- package/bin/cli.ts +0 -9
- package/dist/auth.d.ts +0 -134
- package/dist/cache/lru-cache.d.ts +0 -139
- package/dist/cache/middleware-memoization.d.ts +0 -151
- package/dist/cache/route-cache-warmer.d.ts +0 -161
- package/dist/cache/sqlite-cache.d.ts +0 -209
- package/dist/cache/streaming-cache.d.ts +0 -132
- package/dist/chunk-1mvtv6jw.js +0 -13012
- package/dist/cli/colors.d.ts +0 -15
- package/dist/cli/index.d.ts +0 -10
- package/dist/cli/middleware.d.ts +0 -31
- package/dist/cli/openapi.d.ts +0 -17
- package/dist/cli/router.d.ts +0 -15
- package/dist/cli/routes.d.ts +0 -29
- package/dist/cli/utils.d.ts +0 -74
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -3195
- package/dist/config.d.ts +0 -7
- package/dist/container/container.d.ts +0 -273
- package/dist/container/contextual-binding.d.ts +0 -240
- package/dist/container/decorators.d.ts +0 -141
- package/dist/container/service-provider.d.ts +0 -285
- package/dist/development/hot-reload.d.ts +0 -187
- package/dist/development/index.d.ts +0 -167
- package/dist/development/performance-profiler.d.ts +0 -217
- package/dist/development/route-debugger.d.ts +0 -154
- package/dist/development/route-inspector.d.ts +0 -211
- package/dist/development/typescript-utilities.d.ts +0 -209
- package/dist/docs.d.ts +0 -11
- package/dist/errors/circuit-breaker.d.ts +0 -195
- package/dist/errors/error-handler.d.ts +0 -88
- package/dist/errors/error-reporting.d.ts +0 -144
- package/dist/errors/exceptions.d.ts +0 -184
- package/dist/errors/graceful-degradation.d.ts +0 -154
- package/dist/errors/index.d.ts +0 -9
- package/dist/errors/router-errors.d.ts +0 -110
- package/dist/file-serving/static-files.d.ts +0 -143
- package/dist/index.d.ts +0 -14
- package/dist/index.js +0 -13933
- package/dist/middleware/auth.d.ts +0 -63
- package/dist/middleware/content_security_policy.d.ts +0 -53
- package/dist/middleware/cors.d.ts +0 -5
- package/dist/middleware/csrf.d.ts +0 -7
- package/dist/middleware/ddos_protection.d.ts +0 -39
- package/dist/middleware/file_security.d.ts +0 -26
- package/dist/middleware/file_upload.d.ts +0 -38
- package/dist/middleware/helmet.d.ts +0 -54
- package/dist/middleware/index.d.ts +0 -44
- package/dist/middleware/input_validation.d.ts +0 -45
- package/dist/middleware/json_body.d.ts +0 -4
- package/dist/middleware/performance_alerting.d.ts +0 -87
- package/dist/middleware/performance_dashboard.d.ts +0 -87
- package/dist/middleware/performance_monitor.d.ts +0 -209
- package/dist/middleware/pipeline.d.ts +0 -131
- package/dist/middleware/rate_limit.d.ts +0 -36
- package/dist/middleware/request_id.d.ts +0 -4
- package/dist/middleware/request_signing.d.ts +0 -153
- package/dist/middleware/request_tracer.d.ts +0 -72
- package/dist/middleware/response_cache.d.ts +0 -97
- package/dist/middleware/security.d.ts +0 -69
- package/dist/middleware/security_suite.d.ts +0 -46
- package/dist/middleware/session.d.ts +0 -23
- package/dist/model-binding/index.d.ts +0 -2
- package/dist/model-binding/model-middleware.d.ts +0 -118
- package/dist/model-binding/model-registry.d.ts +0 -164
- package/dist/model-binding.d.ts +0 -185
- package/dist/model-resolver-factory.d.ts +0 -31
- package/dist/observability/correlation.d.ts +0 -187
- package/dist/observability/health-checks.d.ts +0 -186
- package/dist/observability/index.d.ts +0 -60
- package/dist/observability/integration.d.ts +0 -147
- package/dist/observability/metrics.d.ts +0 -184
- package/dist/observability/tracing.d.ts +0 -187
- package/dist/optimization/bun-utilities.d.ts +0 -224
- package/dist/query-builder-integration.d.ts +0 -36
- package/dist/request/context.d.ts +0 -34
- package/dist/request/enhanced-request.d.ts +0 -213
- package/dist/request/macros.d.ts +0 -300
- package/dist/response/macros.d.ts +0 -245
- package/dist/response/response-factory.d.ts +0 -133
- package/dist/router/api-routes.d.ts +0 -5
- package/dist/router/file-based-routing.d.ts +0 -118
- package/dist/router/file-streaming.d.ts +0 -5
- package/dist/router/fluent-router.d.ts +0 -315
- package/dist/router/fluent-routing.d.ts +0 -271
- package/dist/router/group-organization.d.ts +0 -5
- package/dist/router/handler-resolver.d.ts +0 -24
- package/dist/router/http-methods.d.ts +0 -10
- package/dist/router/index.d.ts +0 -114
- package/dist/router/middleware-groups.d.ts +0 -94
- package/dist/router/middleware-integration.d.ts +0 -112
- package/dist/router/middleware.d.ts +0 -5
- package/dist/router/model-binding.d.ts +0 -5
- package/dist/router/optimized-route-matching.d.ts +0 -6
- package/dist/router/route-building.d.ts +0 -5
- package/dist/router/route-compiler.d.ts +0 -153
- package/dist/router/route-matching.d.ts +0 -5
- package/dist/router/route-trie.d.ts +0 -114
- package/dist/router/router.d.ts +0 -294
- package/dist/router/server.d.ts +0 -5
- package/dist/router/validation-integration.d.ts +0 -170
- package/dist/router/view-rendering.d.ts +0 -5
- package/dist/router/websocket.d.ts +0 -5
- package/dist/routing/route-caching.d.ts +0 -129
- package/dist/routing/route-throttling.d.ts +0 -150
- package/dist/routing/subdomain-routing.d.ts +0 -206
- package/dist/session/database-store.d.ts +0 -51
- package/dist/session/file-store.d.ts +0 -22
- package/dist/session/index.d.ts +0 -106
- package/dist/session/memory-store.d.ts +0 -21
- package/dist/session/redis-store.d.ts +0 -31
- package/dist/streaming/index.d.ts +0 -3
- package/dist/streaming/sse-handler.d.ts +0 -138
- package/dist/streaming/stream-handler.d.ts +0 -114
- package/dist/testing/auth-testing.d.ts +0 -156
- package/dist/testing/file-upload-testing.d.ts +0 -190
- package/dist/testing/index.d.ts +0 -10
- package/dist/testing/middleware-testing.d.ts +0 -138
- package/dist/testing/model-binding-testing.d.ts +0 -186
- package/dist/testing/performance-testing.d.ts +0 -235
- package/dist/testing/test-client.d.ts +0 -117
- package/dist/testing/test-request.d.ts +0 -85
- package/dist/testing/test-response.d.ts +0 -90
- package/dist/testing/types.d.ts +0 -207
- package/dist/testing/websocket-testing.d.ts +0 -227
- package/dist/types/controller-types.d.ts +0 -208
- package/dist/types/core.d.ts +0 -543
- package/dist/types/middleware-types.d.ts +0 -227
- package/dist/types/request-response-augmentation.d.ts +0 -261
- package/dist/types/route-inference.d.ts +0 -168
- package/dist/types.d.ts +0 -1782
- package/dist/url.d.ts +0 -56
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/query-preservation.d.ts +0 -48
- package/dist/utils.d.ts +0 -69
- package/dist/validation/validator.d.ts +0 -140
- package/dist/websocket/clustering.d.ts +0 -185
- package/src/auth.ts +0 -469
- 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 -740
- package/src/container/contextual-binding.ts +0 -603
- package/src/container/decorators.ts +0 -359
- 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 -732
- 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 -621
- package/src/errors/index.ts +0 -21
- package/src/errors/router-errors.ts +0 -632
- package/src/file-serving/static-files.ts +0 -581
- package/src/index.ts +0 -14
- package/src/middleware/auth.ts +0 -219
- package/src/middleware/content_security_policy.ts +0 -215
- package/src/middleware/cors.ts +0 -74
- package/src/middleware/csrf.ts +0 -108
- package/src/middleware/ddos_protection.ts +0 -255
- package/src/middleware/file_security.ts +0 -191
- package/src/middleware/file_upload.ts +0 -264
- package/src/middleware/helmet.ts +0 -268
- package/src/middleware/index.ts +0 -117
- package/src/middleware/input_validation.ts +0 -449
- package/src/middleware/json_body.ts +0 -37
- package/src/middleware/performance_alerting.ts +0 -538
- package/src/middleware/performance_dashboard.ts +0 -661
- package/src/middleware/performance_monitor.ts +0 -943
- package/src/middleware/pipeline.ts +0 -489
- package/src/middleware/rate_limit.ts +0 -245
- package/src/middleware/request_id.ts +0 -36
- package/src/middleware/request_signing.ts +0 -636
- package/src/middleware/request_tracer.ts +0 -636
- package/src/middleware/response_cache.ts +0 -743
- 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 -62
- package/src/request/enhanced-request.ts +0 -857
- package/src/request/macros.ts +0 -688
- package/src/response/macros.ts +0 -612
- package/src/response/response-factory.ts +0 -596
- package/src/router/api-routes.ts +0 -243
- package/src/router/file-based-routing.ts +0 -670
- package/src/router/file-streaming.ts +0 -372
- package/src/router/fluent-router.ts +0 -927
- package/src/router/fluent-routing.ts +0 -797
- package/src/router/group-organization.ts +0 -213
- package/src/router/handler-resolver.ts +0 -291
- package/src/router/http-methods.ts +0 -377
- package/src/router/index.ts +0 -187
- package/src/router/middleware-groups.ts +0 -222
- package/src/router/middleware-integration.ts +0 -399
- package/src/router/middleware.ts +0 -231
- package/src/router/model-binding.ts +0 -215
- package/src/router/optimized-route-matching.ts +0 -253
- package/src/router/route-building.ts +0 -212
- package/src/router/route-compiler.ts +0 -702
- package/src/router/route-matching.ts +0 -349
- package/src/router/route-trie.ts +0 -464
- package/src/router/router.ts +0 -1581
- package/src/router/server.ts +0 -462
- package/src/router/validation-integration.ts +0 -443
- 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 -446
- 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 -419
- package/src/types/request-response-augmentation.ts +0 -489
- package/src/types/route-inference.ts +0 -357
- package/src/types.ts +0 -2055
- package/src/url.ts +0 -126
- package/src/utils/index.ts +0 -1
- package/src/utils/query-preservation.ts +0 -201
- package/src/utils.ts +0 -327
- package/src/validation/validator.ts +0 -685
- package/src/websocket/clustering.ts +0 -762
|
@@ -1,672 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Advanced Error Handling - Error Reporting Integration
|
|
3
|
-
*
|
|
4
|
-
* Integration with external error reporting services (Sentry, Bugsnag, etc.)
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { ErrorContext, RouterException } from './exceptions'
|
|
8
|
-
|
|
9
|
-
export interface ErrorReportingConfig {
|
|
10
|
-
enabled: boolean
|
|
11
|
-
service: 'sentry' | 'bugsnag' | 'custom'
|
|
12
|
-
dsn?: string
|
|
13
|
-
apiKey?: string
|
|
14
|
-
environment?: string
|
|
15
|
-
release?: string
|
|
16
|
-
sampleRate?: number
|
|
17
|
-
beforeSend?: (error: Error, context: ErrorContext) => Error | null
|
|
18
|
-
filters?: {
|
|
19
|
-
ignoreErrors?: (string | RegExp)[]
|
|
20
|
-
ignoreCodes?: string[]
|
|
21
|
-
ignoreUrls?: (string | RegExp)[]
|
|
22
|
-
allowUrls?: (string | RegExp)[]
|
|
23
|
-
}
|
|
24
|
-
tags?: Record<string, string>
|
|
25
|
-
user?: {
|
|
26
|
-
id?: string
|
|
27
|
-
email?: string
|
|
28
|
-
username?: string
|
|
29
|
-
}
|
|
30
|
-
extra?: Record<string, any>
|
|
31
|
-
breadcrumbs?: {
|
|
32
|
-
enabled: boolean
|
|
33
|
-
maxBreadcrumbs: number
|
|
34
|
-
}
|
|
35
|
-
performance?: {
|
|
36
|
-
enabled: boolean
|
|
37
|
-
tracesSampleRate: number
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface ErrorReport {
|
|
42
|
-
error: RouterException
|
|
43
|
-
context: ErrorContext
|
|
44
|
-
fingerprint?: string[]
|
|
45
|
-
tags?: Record<string, string>
|
|
46
|
-
extra?: Record<string, any>
|
|
47
|
-
user?: Record<string, any>
|
|
48
|
-
level?: 'debug' | 'info' | 'warning' | 'error' | 'fatal'
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export interface ErrorReporter {
|
|
52
|
-
report: (error: RouterException, context?: ErrorContext) => Promise<string | null>
|
|
53
|
-
addBreadcrumb: (message: string, category?: string, level?: string, data?: Record<string, any>) => void
|
|
54
|
-
setUser: (user: Record<string, any>) => void
|
|
55
|
-
setTag: (key: string, value: string) => void
|
|
56
|
-
setExtra: (key: string, value: any) => void
|
|
57
|
-
setContext: (key: string, context: Record<string, any>) => void
|
|
58
|
-
close: (timeout?: number) => Promise<boolean>
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Sentry error reporter implementation
|
|
63
|
-
*/
|
|
64
|
-
export class SentryReporter implements ErrorReporter {
|
|
65
|
-
private config: ErrorReportingConfig
|
|
66
|
-
private sentry: any
|
|
67
|
-
|
|
68
|
-
constructor(config: ErrorReportingConfig) {
|
|
69
|
-
this.config = config
|
|
70
|
-
this.initializeSentry()
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
private async initializeSentry(): Promise<void> {
|
|
74
|
-
try {
|
|
75
|
-
// Dynamic import to avoid bundling if not used
|
|
76
|
-
// @ts-expect-error - Optional peer dependency
|
|
77
|
-
const Sentry = await import('@sentry/node') as any
|
|
78
|
-
|
|
79
|
-
Sentry.init({
|
|
80
|
-
dsn: this.config.dsn,
|
|
81
|
-
environment: this.config.environment || 'production',
|
|
82
|
-
release: this.config.release,
|
|
83
|
-
sampleRate: this.config.sampleRate || 1.0,
|
|
84
|
-
beforeSend: (event: any, hint: any) => {
|
|
85
|
-
const error = hint.originalException as RouterException
|
|
86
|
-
if (error && this.config.beforeSend) {
|
|
87
|
-
const filteredError = this.config.beforeSend(error, error.context)
|
|
88
|
-
return filteredError ? event : null
|
|
89
|
-
}
|
|
90
|
-
return event
|
|
91
|
-
},
|
|
92
|
-
ignoreErrors: this.config.filters?.ignoreErrors,
|
|
93
|
-
denyUrls: this.config.filters?.ignoreUrls,
|
|
94
|
-
allowUrls: this.config.filters?.allowUrls,
|
|
95
|
-
initialScope: {
|
|
96
|
-
tags: this.config.tags,
|
|
97
|
-
extra: this.config.extra,
|
|
98
|
-
user: this.config.user,
|
|
99
|
-
},
|
|
100
|
-
maxBreadcrumbs: this.config.breadcrumbs?.maxBreadcrumbs || 100,
|
|
101
|
-
tracesSampleRate: this.config.performance?.tracesSampleRate || 0.1,
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
this.sentry = Sentry
|
|
105
|
-
}
|
|
106
|
-
catch (error) {
|
|
107
|
-
console.warn('Failed to initialize Sentry:', error)
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
async report(error: RouterException, context?: ErrorContext): Promise<string | null> {
|
|
112
|
-
if (!this.sentry || !this.config.enabled) {
|
|
113
|
-
return null
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
try {
|
|
117
|
-
// Check if error should be ignored
|
|
118
|
-
if (this.shouldIgnoreError(error)) {
|
|
119
|
-
return null
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const mergedContext = { ...error.context, ...context }
|
|
123
|
-
|
|
124
|
-
return this.sentry.withScope((scope: any) => {
|
|
125
|
-
// Set error context
|
|
126
|
-
if (mergedContext.requestId) {
|
|
127
|
-
scope.setTag('requestId', mergedContext.requestId)
|
|
128
|
-
}
|
|
129
|
-
if (mergedContext.userId) {
|
|
130
|
-
scope.setUser({ id: mergedContext.userId })
|
|
131
|
-
}
|
|
132
|
-
if (mergedContext.traceId) {
|
|
133
|
-
scope.setTag('traceId', mergedContext.traceId)
|
|
134
|
-
}
|
|
135
|
-
if (mergedContext.route) {
|
|
136
|
-
scope.setTag('route', mergedContext.route)
|
|
137
|
-
}
|
|
138
|
-
if (mergedContext.method) {
|
|
139
|
-
scope.setTag('method', mergedContext.method)
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Set error metadata
|
|
143
|
-
scope.setTag('errorCode', error.code)
|
|
144
|
-
scope.setTag('severity', error.severity)
|
|
145
|
-
scope.setTag('category', error.category)
|
|
146
|
-
scope.setLevel(this.mapSeverityToLevel(error.severity))
|
|
147
|
-
|
|
148
|
-
// Set extra context
|
|
149
|
-
scope.setExtra('statusCode', error.statusCode)
|
|
150
|
-
scope.setExtra('retryable', error.retryable)
|
|
151
|
-
scope.setExtra('timestamp', error.timestamp)
|
|
152
|
-
scope.setExtra('context', mergedContext)
|
|
153
|
-
|
|
154
|
-
// Set fingerprint for grouping
|
|
155
|
-
const fingerprint = this.generateFingerprint(error)
|
|
156
|
-
if (fingerprint.length > 0) {
|
|
157
|
-
scope.setFingerprint(fingerprint)
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return this.sentry.captureException(error)
|
|
161
|
-
})
|
|
162
|
-
}
|
|
163
|
-
catch (reportingError) {
|
|
164
|
-
console.error('Failed to report error to Sentry:', reportingError)
|
|
165
|
-
return null
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
addBreadcrumb(message: string, category = 'default', level = 'info', data?: Record<string, any>): void {
|
|
170
|
-
if (!this.sentry || !this.config.breadcrumbs?.enabled) {
|
|
171
|
-
return
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
this.sentry.addBreadcrumb({
|
|
175
|
-
message,
|
|
176
|
-
category,
|
|
177
|
-
level,
|
|
178
|
-
data,
|
|
179
|
-
timestamp: Date.now() / 1000,
|
|
180
|
-
})
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
setUser(user: Record<string, any>): void {
|
|
184
|
-
if (!this.sentry)
|
|
185
|
-
return
|
|
186
|
-
this.sentry.setUser(user)
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
setTag(key: string, value: string): void {
|
|
190
|
-
if (!this.sentry)
|
|
191
|
-
return
|
|
192
|
-
this.sentry.setTag(key, value)
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
setExtra(key: string, value: any): void {
|
|
196
|
-
if (!this.sentry)
|
|
197
|
-
return
|
|
198
|
-
this.sentry.setExtra(key, value)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
setContext(key: string, context: Record<string, any>): void {
|
|
202
|
-
if (!this.sentry)
|
|
203
|
-
return
|
|
204
|
-
this.sentry.setContext(key, context)
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
async close(timeout = 2000): Promise<boolean> {
|
|
208
|
-
if (!this.sentry)
|
|
209
|
-
return true
|
|
210
|
-
return this.sentry.close(timeout)
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
private shouldIgnoreError(error: RouterException): boolean {
|
|
214
|
-
const filters = this.config.filters
|
|
215
|
-
if (!filters)
|
|
216
|
-
return false
|
|
217
|
-
|
|
218
|
-
// Check ignore codes
|
|
219
|
-
if (filters.ignoreCodes?.includes(error.code)) {
|
|
220
|
-
return true
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Check ignore errors (message patterns)
|
|
224
|
-
if (filters.ignoreErrors?.some((pattern) => {
|
|
225
|
-
if (typeof pattern === 'string') {
|
|
226
|
-
return error.message.includes(pattern)
|
|
227
|
-
}
|
|
228
|
-
return pattern.test(error.message)
|
|
229
|
-
})) {
|
|
230
|
-
return true
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
return false
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
private mapSeverityToLevel(severity: string): string {
|
|
237
|
-
switch (severity) {
|
|
238
|
-
case 'low': return 'info'
|
|
239
|
-
case 'medium': return 'warning'
|
|
240
|
-
case 'high': return 'error'
|
|
241
|
-
case 'critical': return 'fatal'
|
|
242
|
-
default: return 'error'
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
private generateFingerprint(error: RouterException): string[] {
|
|
247
|
-
const fingerprint: string[] = []
|
|
248
|
-
|
|
249
|
-
// Group by error code and category
|
|
250
|
-
fingerprint.push(error.code)
|
|
251
|
-
fingerprint.push(error.category)
|
|
252
|
-
|
|
253
|
-
// Add route if available for better grouping
|
|
254
|
-
if (error.context.route) {
|
|
255
|
-
fingerprint.push(error.context.route)
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
return fingerprint
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Bugsnag error reporter implementation
|
|
264
|
-
*/
|
|
265
|
-
export class BugsnagReporter implements ErrorReporter {
|
|
266
|
-
private config: ErrorReportingConfig
|
|
267
|
-
private bugsnag: any
|
|
268
|
-
|
|
269
|
-
constructor(config: ErrorReportingConfig) {
|
|
270
|
-
this.config = config
|
|
271
|
-
this.initializeBugsnag()
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
private async initializeBugsnag(): Promise<void> {
|
|
275
|
-
try {
|
|
276
|
-
// Dynamic import to avoid bundling if not used
|
|
277
|
-
// @ts-expect-error - Optional peer dependency
|
|
278
|
-
const Bugsnag = await import('@bugsnag/js') as any
|
|
279
|
-
|
|
280
|
-
Bugsnag.start({
|
|
281
|
-
apiKey: this.config.apiKey!,
|
|
282
|
-
appVersion: this.config.release,
|
|
283
|
-
releaseStage: this.config.environment || 'production',
|
|
284
|
-
enabledReleaseStages: ['production', 'staging'],
|
|
285
|
-
maxBreadcrumbs: this.config.breadcrumbs?.maxBreadcrumbs || 25,
|
|
286
|
-
onError: (event: any) => {
|
|
287
|
-
const error = event.originalError as RouterException
|
|
288
|
-
if (error && this.config.beforeSend) {
|
|
289
|
-
const filteredError = this.config.beforeSend(error, error.context)
|
|
290
|
-
return filteredError !== null
|
|
291
|
-
}
|
|
292
|
-
return !this.shouldIgnoreError(error)
|
|
293
|
-
},
|
|
294
|
-
})
|
|
295
|
-
|
|
296
|
-
this.bugsnag = Bugsnag
|
|
297
|
-
}
|
|
298
|
-
catch (error) {
|
|
299
|
-
console.warn('Failed to initialize Bugsnag:', error)
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
async report(error: RouterException, context?: ErrorContext): Promise<string | null> {
|
|
304
|
-
if (!this.bugsnag || !this.config.enabled) {
|
|
305
|
-
return null
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
try {
|
|
309
|
-
if (this.shouldIgnoreError(error)) {
|
|
310
|
-
return null
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
const mergedContext = { ...error.context, ...context }
|
|
314
|
-
|
|
315
|
-
this.bugsnag.notify(error, (event: any) => {
|
|
316
|
-
// Set severity
|
|
317
|
-
event.severity = this.mapSeverityToBugsnag(error.severity)
|
|
318
|
-
|
|
319
|
-
// Set context
|
|
320
|
-
event.context = mergedContext.route || mergedContext.url
|
|
321
|
-
|
|
322
|
-
// Set user
|
|
323
|
-
if (mergedContext.userId) {
|
|
324
|
-
event.setUser(mergedContext.userId, undefined, undefined)
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Add metadata
|
|
328
|
-
event.addMetadata('error', {
|
|
329
|
-
code: error.code,
|
|
330
|
-
category: error.category,
|
|
331
|
-
statusCode: error.statusCode,
|
|
332
|
-
retryable: error.retryable,
|
|
333
|
-
timestamp: error.timestamp,
|
|
334
|
-
})
|
|
335
|
-
|
|
336
|
-
event.addMetadata('request', {
|
|
337
|
-
requestId: mergedContext.requestId,
|
|
338
|
-
method: mergedContext.method,
|
|
339
|
-
url: mergedContext.url,
|
|
340
|
-
userAgent: mergedContext.userAgent,
|
|
341
|
-
ip: mergedContext.ip,
|
|
342
|
-
})
|
|
343
|
-
|
|
344
|
-
// Set grouping hash
|
|
345
|
-
event.groupingHash = this.generateGroupingHash(error)
|
|
346
|
-
})
|
|
347
|
-
|
|
348
|
-
return 'reported' // Bugsnag doesn't return event ID
|
|
349
|
-
}
|
|
350
|
-
catch (reportingError) {
|
|
351
|
-
console.error('Failed to report error to Bugsnag:', reportingError)
|
|
352
|
-
return null
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
addBreadcrumb(message: string, category = 'manual', _level = 'info', data?: Record<string, any>): void {
|
|
357
|
-
if (!this.bugsnag || !this.config.breadcrumbs?.enabled) {
|
|
358
|
-
return
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
this.bugsnag.leaveBreadcrumb(message, data, category)
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
setUser(user: Record<string, any>): void {
|
|
365
|
-
if (!this.bugsnag)
|
|
366
|
-
return
|
|
367
|
-
this.bugsnag.setUser(user.id, user.email, user.username)
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
setTag(key: string, value: string): void {
|
|
371
|
-
// Bugsnag doesn't have tags, use metadata instead
|
|
372
|
-
if (!this.bugsnag)
|
|
373
|
-
return
|
|
374
|
-
this.bugsnag.addMetadata('tags', { [key]: value })
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
setExtra(key: string, value: any): void {
|
|
378
|
-
if (!this.bugsnag)
|
|
379
|
-
return
|
|
380
|
-
this.bugsnag.addMetadata('extra', { [key]: value })
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
setContext(key: string, context: Record<string, any>): void {
|
|
384
|
-
if (!this.bugsnag)
|
|
385
|
-
return
|
|
386
|
-
this.bugsnag.addMetadata(key, context)
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
async close(): Promise<boolean> {
|
|
390
|
-
// Bugsnag doesn't have a close method
|
|
391
|
-
return true
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
private shouldIgnoreError(error: RouterException): boolean {
|
|
395
|
-
const filters = this.config.filters
|
|
396
|
-
if (!filters)
|
|
397
|
-
return false
|
|
398
|
-
|
|
399
|
-
if (filters.ignoreCodes?.includes(error.code)) {
|
|
400
|
-
return true
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
if (filters.ignoreErrors?.some((pattern) => {
|
|
404
|
-
if (typeof pattern === 'string') {
|
|
405
|
-
return error.message.includes(pattern)
|
|
406
|
-
}
|
|
407
|
-
return pattern.test(error.message)
|
|
408
|
-
})) {
|
|
409
|
-
return true
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
return false
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
private mapSeverityToBugsnag(severity: string): string {
|
|
416
|
-
switch (severity) {
|
|
417
|
-
case 'low': return 'info'
|
|
418
|
-
case 'medium': return 'warning'
|
|
419
|
-
case 'high': return 'error'
|
|
420
|
-
case 'critical': return 'error'
|
|
421
|
-
default: return 'warning'
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
private generateGroupingHash(error: RouterException): string {
|
|
426
|
-
return `${error.code}-${error.category}-${error.context.route || 'unknown'}`
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/**
|
|
431
|
-
* Custom error reporter for custom implementations
|
|
432
|
-
*/
|
|
433
|
-
export class CustomReporter implements ErrorReporter {
|
|
434
|
-
private config: ErrorReportingConfig
|
|
435
|
-
private reportHandler: (report: ErrorReport) => Promise<string | null>
|
|
436
|
-
|
|
437
|
-
constructor(
|
|
438
|
-
config: ErrorReportingConfig,
|
|
439
|
-
reportHandler: (report: ErrorReport) => Promise<string | null>,
|
|
440
|
-
) {
|
|
441
|
-
this.config = config
|
|
442
|
-
this.reportHandler = reportHandler
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
async report(error: RouterException, context?: ErrorContext): Promise<string | null> {
|
|
446
|
-
if (!this.config.enabled) {
|
|
447
|
-
return null
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
try {
|
|
451
|
-
const mergedContext = { ...error.context, ...context }
|
|
452
|
-
|
|
453
|
-
if (this.config.beforeSend) {
|
|
454
|
-
const filteredError = this.config.beforeSend(error, mergedContext)
|
|
455
|
-
if (!filteredError) {
|
|
456
|
-
return null
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
const report: ErrorReport = {
|
|
461
|
-
error,
|
|
462
|
-
context: mergedContext,
|
|
463
|
-
level: this.mapSeverityToLevel(error.severity),
|
|
464
|
-
tags: this.config.tags,
|
|
465
|
-
extra: this.config.extra,
|
|
466
|
-
user: this.config.user,
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
return await this.reportHandler(report)
|
|
470
|
-
}
|
|
471
|
-
catch (reportingError) {
|
|
472
|
-
console.error('Failed to report error with custom handler:', reportingError)
|
|
473
|
-
return null
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
addBreadcrumb(): void {
|
|
478
|
-
// Custom implementation would handle this
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
setUser(): void {
|
|
482
|
-
// Custom implementation would handle this
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
setTag(): void {
|
|
486
|
-
// Custom implementation would handle this
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
setExtra(): void {
|
|
490
|
-
// Custom implementation would handle this
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
setContext(): void {
|
|
494
|
-
// Custom implementation would handle this
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
async close(): Promise<boolean> {
|
|
498
|
-
return true
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
private mapSeverityToLevel(severity: string): 'debug' | 'info' | 'warning' | 'error' | 'fatal' {
|
|
502
|
-
switch (severity) {
|
|
503
|
-
case 'low': return 'info'
|
|
504
|
-
case 'medium': return 'warning'
|
|
505
|
-
case 'high': return 'error'
|
|
506
|
-
case 'critical': return 'fatal'
|
|
507
|
-
default: return 'error'
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
/**
|
|
513
|
-
* Error reporting manager
|
|
514
|
-
*/
|
|
515
|
-
export class ErrorReportingManager {
|
|
516
|
-
private reporters: ErrorReporter[] = []
|
|
517
|
-
private breadcrumbs: Array<{ message: string, timestamp: Date, data?: any }> = []
|
|
518
|
-
private maxBreadcrumbs = 50
|
|
519
|
-
|
|
520
|
-
constructor(configs: ErrorReportingConfig[]) {
|
|
521
|
-
this.initializeReporters(configs)
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
private initializeReporters(configs: ErrorReportingConfig[]): void {
|
|
525
|
-
for (const config of configs) {
|
|
526
|
-
if (!config.enabled)
|
|
527
|
-
continue
|
|
528
|
-
|
|
529
|
-
switch (config.service) {
|
|
530
|
-
case 'sentry':
|
|
531
|
-
this.reporters.push(new SentryReporter(config))
|
|
532
|
-
break
|
|
533
|
-
case 'bugsnag':
|
|
534
|
-
this.reporters.push(new BugsnagReporter(config))
|
|
535
|
-
break
|
|
536
|
-
case 'custom':
|
|
537
|
-
// Custom reporter would be added separately
|
|
538
|
-
break
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
addReporter(reporter: ErrorReporter): void {
|
|
544
|
-
this.reporters.push(reporter)
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
async report(error: RouterException, context?: ErrorContext): Promise<string[]> {
|
|
548
|
-
const reportIds: string[] = []
|
|
549
|
-
|
|
550
|
-
// Add breadcrumb for this error
|
|
551
|
-
this.addBreadcrumb(`Error occurred: ${error.message}`, 'error', {
|
|
552
|
-
code: error.code,
|
|
553
|
-
severity: error.severity,
|
|
554
|
-
})
|
|
555
|
-
|
|
556
|
-
// Report to all configured reporters
|
|
557
|
-
const promises = this.reporters.map(async (reporter) => {
|
|
558
|
-
try {
|
|
559
|
-
const reportId = await reporter.report(error, context)
|
|
560
|
-
if (reportId) {
|
|
561
|
-
reportIds.push(reportId)
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
catch (reportingError) {
|
|
565
|
-
console.error('Reporter failed:', reportingError)
|
|
566
|
-
}
|
|
567
|
-
})
|
|
568
|
-
|
|
569
|
-
await Promise.allSettled(promises)
|
|
570
|
-
return reportIds
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
addBreadcrumb(message: string, category = 'default', data?: any): void {
|
|
574
|
-
// Add to internal breadcrumbs
|
|
575
|
-
this.breadcrumbs.push({
|
|
576
|
-
message,
|
|
577
|
-
timestamp: new Date(),
|
|
578
|
-
data: { category, ...data },
|
|
579
|
-
})
|
|
580
|
-
|
|
581
|
-
// Keep only recent breadcrumbs
|
|
582
|
-
if (this.breadcrumbs.length > this.maxBreadcrumbs) {
|
|
583
|
-
this.breadcrumbs = this.breadcrumbs.slice(-this.maxBreadcrumbs)
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
// Add to all reporters
|
|
587
|
-
this.reporters.forEach((reporter) => {
|
|
588
|
-
reporter.addBreadcrumb(message, category, 'info', data)
|
|
589
|
-
})
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
setUser(user: Record<string, any>): void {
|
|
593
|
-
this.reporters.forEach(reporter => reporter.setUser(user))
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
setTag(key: string, value: string): void {
|
|
597
|
-
this.reporters.forEach(reporter => reporter.setTag(key, value))
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
setExtra(key: string, value: any): void {
|
|
601
|
-
this.reporters.forEach(reporter => reporter.setExtra(key, value))
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
setContext(key: string, context: Record<string, any>): void {
|
|
605
|
-
this.reporters.forEach(reporter => reporter.setContext(key, context))
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
async close(timeout = 5000): Promise<boolean> {
|
|
609
|
-
const promises = this.reporters.map(reporter => reporter.close(timeout))
|
|
610
|
-
const results = await Promise.allSettled(promises)
|
|
611
|
-
return results.every(result => result.status === 'fulfilled' && result.value)
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
getBreadcrumbs(): Array<{ message: string, timestamp: Date, data?: any }> {
|
|
615
|
-
return [...this.breadcrumbs]
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
/**
|
|
620
|
-
* Factory function to create error reporting manager
|
|
621
|
-
*/
|
|
622
|
-
export function createErrorReporting(configs: ErrorReportingConfig[]): ErrorReportingManager {
|
|
623
|
-
return new ErrorReportingManager(configs)
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
/**
|
|
627
|
-
* Default configuration presets
|
|
628
|
-
*/
|
|
629
|
-
export const ErrorReportingPresets = {
|
|
630
|
-
sentry: (dsn: string, environment = 'production'): ErrorReportingConfig => ({
|
|
631
|
-
enabled: true,
|
|
632
|
-
service: 'sentry',
|
|
633
|
-
dsn,
|
|
634
|
-
environment,
|
|
635
|
-
sampleRate: 1.0,
|
|
636
|
-
breadcrumbs: {
|
|
637
|
-
enabled: true,
|
|
638
|
-
maxBreadcrumbs: 100,
|
|
639
|
-
},
|
|
640
|
-
performance: {
|
|
641
|
-
enabled: true,
|
|
642
|
-
tracesSampleRate: 0.1,
|
|
643
|
-
},
|
|
644
|
-
filters: {
|
|
645
|
-
ignoreErrors: [
|
|
646
|
-
'Non-Error promise rejection captured',
|
|
647
|
-
'ResizeObserver loop limit exceeded',
|
|
648
|
-
],
|
|
649
|
-
ignoreCodes: ['VALIDATION_ERROR'],
|
|
650
|
-
},
|
|
651
|
-
}),
|
|
652
|
-
|
|
653
|
-
bugsnag: (apiKey: string, environment = 'production'): ErrorReportingConfig => ({
|
|
654
|
-
enabled: true,
|
|
655
|
-
service: 'bugsnag',
|
|
656
|
-
apiKey,
|
|
657
|
-
environment,
|
|
658
|
-
breadcrumbs: {
|
|
659
|
-
enabled: true,
|
|
660
|
-
maxBreadcrumbs: 25,
|
|
661
|
-
},
|
|
662
|
-
filters: {
|
|
663
|
-
ignoreCodes: ['VALIDATION_ERROR'],
|
|
664
|
-
},
|
|
665
|
-
}),
|
|
666
|
-
|
|
667
|
-
development: (): ErrorReportingConfig => ({
|
|
668
|
-
enabled: false,
|
|
669
|
-
service: 'custom',
|
|
670
|
-
environment: 'development',
|
|
671
|
-
}),
|
|
672
|
-
}
|