@stacksjs/bun-router 0.0.14 ā 0.0.15
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/README.md +261 -584
- package/bin/cli.ts +9 -0
- package/dist/auth.d.ts +134 -0
- package/dist/cache/lru-cache.d.ts +139 -0
- package/dist/cache/middleware-memoization.d.ts +151 -0
- package/dist/cache/route-cache-warmer.d.ts +161 -0
- package/dist/cache/sqlite-cache.d.ts +209 -0
- package/dist/cache/streaming-cache.d.ts +132 -0
- package/dist/chunk-j0e7z7hd.js +18053 -0
- package/dist/cli/colors.d.ts +15 -0
- package/dist/cli/index.d.ts +10 -0
- package/dist/cli/middleware.d.ts +31 -0
- package/dist/cli/openapi.d.ts +17 -0
- package/dist/cli/router.d.ts +15 -0
- package/dist/cli/routes.d.ts +29 -0
- package/dist/cli/utils.d.ts +74 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +3360 -0
- package/dist/config.d.ts +7 -0
- package/dist/container/container.d.ts +273 -0
- package/dist/container/contextual-binding.d.ts +240 -0
- package/dist/container/decorators.d.ts +141 -0
- package/dist/container/service-provider.d.ts +285 -0
- package/dist/development/hot-reload.d.ts +187 -0
- package/dist/development/index.d.ts +167 -0
- package/dist/development/performance-profiler.d.ts +217 -0
- package/dist/development/route-debugger.d.ts +154 -0
- package/dist/development/route-inspector.d.ts +211 -0
- package/dist/development/typescript-utilities.d.ts +209 -0
- package/dist/docs.d.ts +11 -0
- package/dist/errors/circuit-breaker.d.ts +195 -0
- package/dist/errors/error-handler.d.ts +88 -0
- package/dist/errors/error-reporting.d.ts +144 -0
- package/dist/errors/exceptions.d.ts +184 -0
- package/dist/errors/graceful-degradation.d.ts +154 -0
- package/dist/errors/index.d.ts +9 -0
- package/dist/errors/router-errors.d.ts +110 -0
- package/dist/file-serving/static-files.d.ts +143 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +13968 -0
- package/dist/middleware/auth.d.ts +63 -0
- package/dist/middleware/content_security_policy.d.ts +53 -0
- package/dist/middleware/cors.d.ts +5 -0
- package/dist/middleware/csrf.d.ts +7 -0
- package/dist/middleware/ddos_protection.d.ts +39 -0
- package/dist/middleware/file_security.d.ts +26 -0
- package/dist/middleware/file_upload.d.ts +38 -0
- package/dist/middleware/helmet.d.ts +54 -0
- package/dist/middleware/index.d.ts +44 -0
- package/dist/middleware/input_validation.d.ts +45 -0
- package/dist/middleware/json_body.d.ts +4 -0
- package/dist/middleware/performance_alerting.d.ts +87 -0
- package/dist/middleware/performance_dashboard.d.ts +87 -0
- package/dist/middleware/performance_monitor.d.ts +209 -0
- package/dist/middleware/pipeline.d.ts +131 -0
- package/dist/middleware/rate_limit.d.ts +36 -0
- package/dist/middleware/request_id.d.ts +4 -0
- package/dist/middleware/request_signing.d.ts +153 -0
- package/dist/middleware/request_tracer.d.ts +72 -0
- package/dist/middleware/response_cache.d.ts +97 -0
- package/dist/middleware/security.d.ts +69 -0
- package/dist/middleware/security_suite.d.ts +46 -0
- package/dist/middleware/session.d.ts +23 -0
- package/dist/model-binding/index.d.ts +2 -0
- package/dist/model-binding/model-middleware.d.ts +118 -0
- package/dist/model-binding/model-registry.d.ts +164 -0
- package/dist/model-binding.d.ts +185 -0
- package/dist/model-resolver-factory.d.ts +31 -0
- package/dist/observability/correlation.d.ts +187 -0
- package/dist/observability/health-checks.d.ts +186 -0
- package/dist/observability/index.d.ts +60 -0
- package/dist/observability/integration.d.ts +147 -0
- package/dist/observability/metrics.d.ts +184 -0
- package/dist/observability/tracing.d.ts +187 -0
- package/dist/optimization/bun-utilities.d.ts +224 -0
- package/dist/query-builder-integration.d.ts +36 -0
- package/dist/request/context.d.ts +34 -0
- package/dist/request/enhanced-request.d.ts +213 -0
- package/dist/request/macros.d.ts +300 -0
- package/dist/response/macros.d.ts +256 -0
- package/dist/response/response-factory.d.ts +133 -0
- package/dist/router/api-routes.d.ts +5 -0
- package/dist/router/file-based-routing.d.ts +118 -0
- package/dist/router/file-streaming.d.ts +5 -0
- package/dist/router/fluent-router.d.ts +315 -0
- package/dist/router/fluent-routing.d.ts +271 -0
- package/dist/router/group-organization.d.ts +5 -0
- package/dist/router/handler-resolver.d.ts +24 -0
- package/dist/router/http-methods.d.ts +10 -0
- package/dist/router/index.d.ts +114 -0
- package/dist/router/middleware-groups.d.ts +94 -0
- package/dist/router/middleware-integration.d.ts +112 -0
- package/dist/router/middleware.d.ts +5 -0
- package/dist/router/model-binding.d.ts +5 -0
- package/dist/router/optimized-route-matching.d.ts +6 -0
- package/dist/router/route-building.d.ts +5 -0
- package/dist/router/route-compiler.d.ts +153 -0
- package/dist/router/route-matching.d.ts +5 -0
- package/dist/router/route-trie.d.ts +114 -0
- package/dist/router/router.d.ts +317 -0
- package/dist/router/server.d.ts +5 -0
- package/dist/router/validation-integration.d.ts +170 -0
- package/dist/router/view-rendering.d.ts +5 -0
- package/dist/router/websocket.d.ts +5 -0
- package/dist/routing/route-caching.d.ts +129 -0
- package/dist/routing/route-throttling.d.ts +150 -0
- package/dist/routing/subdomain-routing.d.ts +206 -0
- package/dist/session/database-store.d.ts +51 -0
- package/dist/session/file-store.d.ts +22 -0
- package/dist/session/index.d.ts +106 -0
- package/dist/session/memory-store.d.ts +21 -0
- package/dist/session/redis-store.d.ts +31 -0
- package/dist/streaming/index.d.ts +3 -0
- package/dist/streaming/sse-handler.d.ts +138 -0
- package/dist/streaming/stream-handler.d.ts +114 -0
- package/dist/testing/auth-testing.d.ts +156 -0
- package/dist/testing/file-upload-testing.d.ts +190 -0
- package/dist/testing/index.d.ts +10 -0
- package/dist/testing/middleware-testing.d.ts +138 -0
- package/dist/testing/model-binding-testing.d.ts +186 -0
- package/dist/testing/performance-testing.d.ts +235 -0
- package/dist/testing/test-client.d.ts +117 -0
- package/dist/testing/test-request.d.ts +85 -0
- package/dist/testing/test-response.d.ts +90 -0
- package/dist/testing/types.d.ts +207 -0
- package/dist/testing/websocket-testing.d.ts +227 -0
- package/dist/types/controller-types.d.ts +208 -0
- package/dist/types/core.d.ts +543 -0
- package/dist/types/middleware-types.d.ts +227 -0
- package/dist/types/request-response-augmentation.d.ts +261 -0
- package/dist/types/route-inference.d.ts +168 -0
- package/dist/types.d.ts +1794 -0
- package/dist/url.d.ts +56 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/query-preservation.d.ts +48 -0
- package/dist/utils.d.ts +69 -0
- package/dist/validation/validator.d.ts +140 -0
- package/dist/websocket/clustering.d.ts +185 -0
- package/package.json +45 -44
- package/src/auth.ts +469 -0
- package/src/cache/lru-cache.ts +457 -0
- package/src/cache/middleware-memoization.ts +531 -0
- package/src/cache/route-cache-warmer.ts +486 -0
- package/src/cache/sqlite-cache.ts +783 -0
- package/src/cache/streaming-cache.ts +572 -0
- package/src/cli/colors.ts +29 -0
- package/src/cli/index.ts +287 -0
- package/src/cli/middleware.ts +291 -0
- package/src/cli/openapi.ts +407 -0
- package/src/cli/router.ts +188 -0
- package/src/cli/routes.ts +265 -0
- package/src/cli/utils.ts +531 -0
- package/src/cli.ts +5 -0
- package/src/config.ts +322 -0
- package/src/container/container.ts +740 -0
- package/src/container/contextual-binding.ts +603 -0
- package/src/container/decorators.ts +359 -0
- package/src/container/service-provider.ts +596 -0
- package/src/development/hot-reload.ts +673 -0
- package/src/development/index.ts +499 -0
- package/src/development/performance-profiler.ts +717 -0
- package/src/development/route-debugger.ts +527 -0
- package/src/development/route-inspector.ts +749 -0
- package/src/development/typescript-utilities.ts +682 -0
- package/src/docs.ts +397 -0
- package/src/errors/circuit-breaker.ts +732 -0
- package/src/errors/error-handler.ts +569 -0
- package/src/errors/error-reporting.ts +672 -0
- package/src/errors/exceptions.ts +536 -0
- package/src/errors/graceful-degradation.ts +621 -0
- package/src/errors/index.ts +21 -0
- package/src/errors/router-errors.ts +632 -0
- package/src/file-serving/static-files.ts +581 -0
- package/src/index.ts +14 -0
- package/src/middleware/auth.ts +220 -0
- package/src/middleware/content_security_policy.ts +215 -0
- package/src/middleware/cors.ts +74 -0
- package/src/middleware/csrf.ts +108 -0
- package/src/middleware/ddos_protection.ts +255 -0
- package/src/middleware/file_security.ts +191 -0
- package/src/middleware/file_upload.ts +275 -0
- package/src/middleware/helmet.ts +268 -0
- package/src/middleware/index.ts +117 -0
- package/src/middleware/input_validation.ts +449 -0
- package/src/middleware/json_body.ts +37 -0
- package/src/middleware/performance_alerting.ts +538 -0
- package/src/middleware/performance_dashboard.ts +661 -0
- package/src/middleware/performance_monitor.ts +943 -0
- package/src/middleware/pipeline.ts +489 -0
- package/src/middleware/rate_limit.ts +245 -0
- package/src/middleware/request_id.ts +36 -0
- package/src/middleware/request_signing.ts +636 -0
- package/src/middleware/request_tracer.ts +636 -0
- package/src/middleware/response_cache.ts +743 -0
- package/src/middleware/security.ts +482 -0
- package/src/middleware/security_suite.ts +257 -0
- package/src/middleware/session.ts +91 -0
- package/src/model-binding/index.ts +18 -0
- package/src/model-binding/model-middleware.ts +425 -0
- package/src/model-binding/model-registry.ts +550 -0
- package/src/model-binding.ts +370 -0
- package/src/model-resolver-factory.ts +106 -0
- package/src/observability/correlation.ts +691 -0
- package/src/observability/health-checks.ts +729 -0
- package/src/observability/index.ts +184 -0
- package/src/observability/integration.ts +548 -0
- package/src/observability/metrics.ts +753 -0
- package/src/observability/tracing.ts +638 -0
- package/src/optimization/bun-utilities.ts +778 -0
- package/src/query-builder-integration.ts +137 -0
- package/src/request/context.ts +62 -0
- package/src/request/enhanced-request.ts +857 -0
- package/src/request/macros.ts +688 -0
- package/src/response/macros.ts +665 -0
- package/src/response/response-factory.ts +596 -0
- package/src/router/api-routes.ts +243 -0
- package/src/router/file-based-routing.ts +690 -0
- package/src/router/file-streaming.ts +383 -0
- package/src/router/fluent-router.ts +927 -0
- package/src/router/fluent-routing.ts +797 -0
- package/src/router/group-organization.ts +213 -0
- package/src/router/handler-resolver.ts +291 -0
- package/src/router/http-methods.ts +377 -0
- package/src/router/index.ts +187 -0
- package/src/router/middleware-groups.ts +222 -0
- package/src/router/middleware-integration.ts +399 -0
- package/src/router/middleware.ts +231 -0
- package/src/router/model-binding.ts +215 -0
- package/src/router/optimized-route-matching.ts +253 -0
- package/src/router/route-building.ts +221 -0
- package/src/router/route-compiler.ts +702 -0
- package/src/router/route-matching.ts +349 -0
- package/src/router/route-trie.ts +464 -0
- package/src/router/router.ts +1604 -0
- package/src/router/server.ts +462 -0
- package/src/router/validation-integration.ts +443 -0
- package/src/router/view-rendering.ts +233 -0
- package/src/router/websocket.ts +100 -0
- package/src/routing/route-caching.ts +402 -0
- package/src/routing/route-throttling.ts +469 -0
- package/src/routing/subdomain-routing.ts +492 -0
- package/src/session/database-store.ts +109 -0
- package/src/session/file-store.ts +148 -0
- package/src/session/index.ts +244 -0
- package/src/session/memory-store.ts +88 -0
- package/src/session/redis-store.ts +93 -0
- package/src/streaming/index.ts +17 -0
- package/src/streaming/sse-handler.ts +482 -0
- package/src/streaming/stream-handler.ts +552 -0
- package/src/testing/auth-testing.ts +446 -0
- package/src/testing/file-upload-testing.ts +543 -0
- package/src/testing/index.ts +10 -0
- package/src/testing/middleware-testing.ts +322 -0
- package/src/testing/model-binding-testing.ts +645 -0
- package/src/testing/performance-testing.ts +738 -0
- package/src/testing/test-client.ts +310 -0
- package/src/testing/test-request.ts +315 -0
- package/src/testing/test-response.ts +332 -0
- package/src/testing/types.ts +224 -0
- package/src/testing/websocket-testing.ts +590 -0
- package/src/types/controller-types.ts +385 -0
- package/src/types/core.ts +683 -0
- package/src/types/middleware-types.ts +419 -0
- package/src/types/request-response-augmentation.ts +489 -0
- package/src/types/route-inference.ts +357 -0
- package/src/types.ts +2067 -0
- package/src/url.ts +126 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/query-preservation.ts +201 -0
- package/src/utils.ts +327 -0
- package/src/validation/validator.ts +685 -0
- package/src/websocket/clustering.ts +762 -0
- package/CHANGELOG.md +0 -770
|
@@ -0,0 +1,749 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Development Tools - Route Inspector
|
|
3
|
+
*
|
|
4
|
+
* Route listing, metadata inspection, and route analysis
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface RouteMetadata {
|
|
8
|
+
id: string
|
|
9
|
+
method: string
|
|
10
|
+
pattern: string
|
|
11
|
+
originalPattern: string
|
|
12
|
+
handler: {
|
|
13
|
+
name: string
|
|
14
|
+
source?: string
|
|
15
|
+
parameters: string[]
|
|
16
|
+
isAsync: boolean
|
|
17
|
+
}
|
|
18
|
+
middleware: Array<{
|
|
19
|
+
name: string
|
|
20
|
+
source?: string
|
|
21
|
+
order: number
|
|
22
|
+
}>
|
|
23
|
+
params: Array<{
|
|
24
|
+
name: string
|
|
25
|
+
type: 'string' | 'number' | 'uuid' | 'slug'
|
|
26
|
+
optional: boolean
|
|
27
|
+
constraint?: string
|
|
28
|
+
}>
|
|
29
|
+
constraints: Record<string, any>
|
|
30
|
+
cache?: {
|
|
31
|
+
enabled: boolean
|
|
32
|
+
ttl?: number
|
|
33
|
+
tags?: string[]
|
|
34
|
+
}
|
|
35
|
+
throttling?: {
|
|
36
|
+
enabled: boolean
|
|
37
|
+
limit: number
|
|
38
|
+
window: number
|
|
39
|
+
}
|
|
40
|
+
validation?: {
|
|
41
|
+
rules: Record<string, string>
|
|
42
|
+
messages?: Record<string, string>
|
|
43
|
+
}
|
|
44
|
+
metadata: {
|
|
45
|
+
registeredAt: number
|
|
46
|
+
file?: string
|
|
47
|
+
line?: number
|
|
48
|
+
group?: string
|
|
49
|
+
name?: string
|
|
50
|
+
description?: string
|
|
51
|
+
}
|
|
52
|
+
stats: {
|
|
53
|
+
hits: number
|
|
54
|
+
averageResponseTime: number
|
|
55
|
+
lastAccessed?: number
|
|
56
|
+
errors: number
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface RouteGroup {
|
|
61
|
+
name: string
|
|
62
|
+
prefix: string
|
|
63
|
+
middleware: string[]
|
|
64
|
+
routes: RouteMetadata[]
|
|
65
|
+
subgroups: RouteGroup[]
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface RouteAnalysis {
|
|
69
|
+
totalRoutes: number
|
|
70
|
+
routesByMethod: Record<string, number>
|
|
71
|
+
duplicatePatterns: Array<{
|
|
72
|
+
pattern: string
|
|
73
|
+
routes: RouteMetadata[]
|
|
74
|
+
}>
|
|
75
|
+
unusedRoutes: RouteMetadata[]
|
|
76
|
+
slowRoutes: RouteMetadata[]
|
|
77
|
+
errorProneRoutes: RouteMetadata[]
|
|
78
|
+
middlewareUsage: Record<string, number>
|
|
79
|
+
parameterAnalysis: {
|
|
80
|
+
mostUsedParams: Array<{ name: string, count: number }>
|
|
81
|
+
parameterTypes: Record<string, number>
|
|
82
|
+
}
|
|
83
|
+
recommendations: string[]
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Route inspector for development and debugging
|
|
88
|
+
*/
|
|
89
|
+
export class RouteInspector {
|
|
90
|
+
private routes = new Map<string, RouteMetadata>()
|
|
91
|
+
private groups = new Map<string, RouteGroup>()
|
|
92
|
+
private routeStats = new Map<string, RouteMetadata['stats']>()
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Register a route for inspection
|
|
96
|
+
*/
|
|
97
|
+
registerRoute(
|
|
98
|
+
method: string,
|
|
99
|
+
pattern: string,
|
|
100
|
+
handler: (...args: any[]) => any,
|
|
101
|
+
middleware: Array<(...args: any[]) => any> = [],
|
|
102
|
+
options: Partial<RouteMetadata> = {},
|
|
103
|
+
): string {
|
|
104
|
+
const id = this.generateRouteId(method, pattern)
|
|
105
|
+
|
|
106
|
+
const metadata: RouteMetadata = {
|
|
107
|
+
id,
|
|
108
|
+
method: method.toUpperCase(),
|
|
109
|
+
pattern,
|
|
110
|
+
originalPattern: pattern,
|
|
111
|
+
handler: {
|
|
112
|
+
name: handler.name || 'anonymous',
|
|
113
|
+
source: this.getFunctionSource(handler),
|
|
114
|
+
parameters: this.extractFunctionParameters(handler),
|
|
115
|
+
isAsync: this.isAsyncFunction(handler),
|
|
116
|
+
},
|
|
117
|
+
middleware: middleware.map((mw, index) => ({
|
|
118
|
+
name: mw.name || 'anonymous',
|
|
119
|
+
source: this.getFunctionSource(mw),
|
|
120
|
+
order: index,
|
|
121
|
+
})),
|
|
122
|
+
params: this.extractRouteParameters(pattern),
|
|
123
|
+
constraints: {},
|
|
124
|
+
metadata: {
|
|
125
|
+
registeredAt: Date.now(),
|
|
126
|
+
...this.getCallSiteInfo(),
|
|
127
|
+
...options.metadata,
|
|
128
|
+
},
|
|
129
|
+
stats: {
|
|
130
|
+
hits: 0,
|
|
131
|
+
averageResponseTime: 0,
|
|
132
|
+
errors: 0,
|
|
133
|
+
},
|
|
134
|
+
...options,
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
this.routes.set(id, metadata)
|
|
138
|
+
this.routeStats.set(id, metadata.stats)
|
|
139
|
+
|
|
140
|
+
return id
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get all registered routes
|
|
145
|
+
*/
|
|
146
|
+
getRoutes(filter?: {
|
|
147
|
+
method?: string
|
|
148
|
+
pattern?: string
|
|
149
|
+
group?: string
|
|
150
|
+
hasMiddleware?: string
|
|
151
|
+
hasParams?: boolean
|
|
152
|
+
}): RouteMetadata[] {
|
|
153
|
+
let routes = Array.from(this.routes.values())
|
|
154
|
+
|
|
155
|
+
if (filter) {
|
|
156
|
+
if (filter.method) {
|
|
157
|
+
routes = routes.filter(route => route.method === filter.method!.toUpperCase())
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (filter.pattern) {
|
|
161
|
+
const regex = new RegExp(filter.pattern.replace(/\*/g, '.*'))
|
|
162
|
+
routes = routes.filter(route => regex.test(route.pattern))
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (filter.group) {
|
|
166
|
+
routes = routes.filter(route => route.metadata.group === filter.group)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (filter.hasMiddleware) {
|
|
170
|
+
routes = routes.filter(route =>
|
|
171
|
+
route.middleware.some(mw => mw.name.includes(filter.hasMiddleware!)),
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (filter.hasParams !== undefined) {
|
|
176
|
+
routes = routes.filter(route =>
|
|
177
|
+
filter.hasParams ? route.params.length > 0 : route.params.length === 0,
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return routes.sort((a, b) => {
|
|
183
|
+
// Sort by method first, then by pattern
|
|
184
|
+
if (a.method !== b.method) {
|
|
185
|
+
const methodOrder = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD']
|
|
186
|
+
return methodOrder.indexOf(a.method) - methodOrder.indexOf(b.method)
|
|
187
|
+
}
|
|
188
|
+
return a.pattern.localeCompare(b.pattern)
|
|
189
|
+
})
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Get route by ID
|
|
194
|
+
*/
|
|
195
|
+
getRoute(id: string): RouteMetadata | undefined {
|
|
196
|
+
return this.routes.get(id)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Find routes matching a request
|
|
201
|
+
*/
|
|
202
|
+
findMatchingRoutes(method: string, path: string): RouteMetadata[] {
|
|
203
|
+
return this.getRoutes({ method }).filter((route) => {
|
|
204
|
+
const regex = this.patternToRegex(route.pattern)
|
|
205
|
+
return regex.test(path)
|
|
206
|
+
})
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Register route group
|
|
211
|
+
*/
|
|
212
|
+
registerGroup(name: string, prefix: string, middleware: Array<(...args: any[]) => any> = []): void {
|
|
213
|
+
const group: RouteGroup = {
|
|
214
|
+
name,
|
|
215
|
+
prefix,
|
|
216
|
+
middleware: middleware.map(mw => mw.name || 'anonymous'),
|
|
217
|
+
routes: [],
|
|
218
|
+
subgroups: [],
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
this.groups.set(name, group)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Get route groups
|
|
226
|
+
*/
|
|
227
|
+
getGroups(): RouteGroup[] {
|
|
228
|
+
const groups = Array.from(this.groups.values())
|
|
229
|
+
|
|
230
|
+
// Populate routes for each group
|
|
231
|
+
groups.forEach((group) => {
|
|
232
|
+
group.routes = this.getRoutes({ group: group.name })
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
return groups
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Record route access for statistics
|
|
240
|
+
*/
|
|
241
|
+
recordRouteAccess(routeId: string, responseTime: number, error?: boolean): void {
|
|
242
|
+
const stats = this.routeStats.get(routeId)
|
|
243
|
+
if (!stats)
|
|
244
|
+
return
|
|
245
|
+
|
|
246
|
+
stats.hits++
|
|
247
|
+
stats.lastAccessed = Date.now()
|
|
248
|
+
|
|
249
|
+
// Update average response time
|
|
250
|
+
stats.averageResponseTime = (
|
|
251
|
+
(stats.averageResponseTime * (stats.hits - 1) + responseTime) / stats.hits
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
if (error) {
|
|
255
|
+
stats.errors++
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Update route metadata
|
|
259
|
+
const route = this.routes.get(routeId)
|
|
260
|
+
if (route) {
|
|
261
|
+
route.stats = stats
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Analyze routes for insights and recommendations
|
|
267
|
+
*/
|
|
268
|
+
analyzeRoutes(): RouteAnalysis {
|
|
269
|
+
const routes = this.getRoutes()
|
|
270
|
+
const analysis: RouteAnalysis = {
|
|
271
|
+
totalRoutes: routes.length,
|
|
272
|
+
routesByMethod: {},
|
|
273
|
+
duplicatePatterns: [],
|
|
274
|
+
unusedRoutes: [],
|
|
275
|
+
slowRoutes: [],
|
|
276
|
+
errorProneRoutes: [],
|
|
277
|
+
middlewareUsage: {},
|
|
278
|
+
parameterAnalysis: {
|
|
279
|
+
mostUsedParams: [],
|
|
280
|
+
parameterTypes: {},
|
|
281
|
+
},
|
|
282
|
+
recommendations: [],
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Routes by method
|
|
286
|
+
routes.forEach((route) => {
|
|
287
|
+
analysis.routesByMethod[route.method] = (analysis.routesByMethod[route.method] || 0) + 1
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
// Find duplicate patterns
|
|
291
|
+
const patternGroups = new Map<string, RouteMetadata[]>()
|
|
292
|
+
routes.forEach((route) => {
|
|
293
|
+
const key = `${route.method}:${route.pattern}`
|
|
294
|
+
if (!patternGroups.has(key)) {
|
|
295
|
+
patternGroups.set(key, [])
|
|
296
|
+
}
|
|
297
|
+
patternGroups.get(key)!.push(route)
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
patternGroups.forEach((routeGroup, pattern) => {
|
|
301
|
+
if (routeGroup.length > 1) {
|
|
302
|
+
analysis.duplicatePatterns.push({
|
|
303
|
+
pattern,
|
|
304
|
+
routes: routeGroup,
|
|
305
|
+
})
|
|
306
|
+
}
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
// Unused routes (no hits)
|
|
310
|
+
analysis.unusedRoutes = routes.filter(route => route.stats.hits === 0)
|
|
311
|
+
|
|
312
|
+
// Slow routes (average response time > 1000ms)
|
|
313
|
+
analysis.slowRoutes = routes.filter(route => route.stats.averageResponseTime > 1000)
|
|
314
|
+
|
|
315
|
+
// Error-prone routes (error rate > 5%)
|
|
316
|
+
analysis.errorProneRoutes = routes.filter((route) => {
|
|
317
|
+
const errorRate = route.stats.hits > 0 ? (route.stats.errors / route.stats.hits) : 0
|
|
318
|
+
return errorRate > 0.05
|
|
319
|
+
})
|
|
320
|
+
|
|
321
|
+
// Middleware usage
|
|
322
|
+
routes.forEach((route) => {
|
|
323
|
+
route.middleware.forEach((mw) => {
|
|
324
|
+
analysis.middlewareUsage[mw.name] = (analysis.middlewareUsage[mw.name] || 0) + 1
|
|
325
|
+
})
|
|
326
|
+
})
|
|
327
|
+
|
|
328
|
+
// Parameter analysis
|
|
329
|
+
const paramCounts = new Map<string, number>()
|
|
330
|
+
const typeCounts = new Map<string, number>()
|
|
331
|
+
|
|
332
|
+
routes.forEach((route) => {
|
|
333
|
+
route.params.forEach((param) => {
|
|
334
|
+
paramCounts.set(param.name, (paramCounts.get(param.name) || 0) + 1)
|
|
335
|
+
typeCounts.set(param.type, (typeCounts.get(param.type) || 0) + 1)
|
|
336
|
+
})
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
analysis.parameterAnalysis.mostUsedParams = Array.from(paramCounts.entries())
|
|
340
|
+
.map(([name, count]) => ({ name, count }))
|
|
341
|
+
.sort((a, b) => b.count - a.count)
|
|
342
|
+
.slice(0, 10)
|
|
343
|
+
|
|
344
|
+
analysis.parameterAnalysis.parameterTypes = Object.fromEntries(typeCounts)
|
|
345
|
+
|
|
346
|
+
// Generate recommendations
|
|
347
|
+
analysis.recommendations = this.generateRecommendations(analysis)
|
|
348
|
+
|
|
349
|
+
return analysis
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Export routes in various formats
|
|
354
|
+
*/
|
|
355
|
+
exportRoutes(format: 'json' | 'csv' | 'markdown' | 'openapi' = 'json'): string {
|
|
356
|
+
const routes = this.getRoutes()
|
|
357
|
+
|
|
358
|
+
switch (format) {
|
|
359
|
+
case 'json':
|
|
360
|
+
return JSON.stringify(routes, null, 2)
|
|
361
|
+
|
|
362
|
+
case 'csv':
|
|
363
|
+
return this.exportToCsv(routes)
|
|
364
|
+
|
|
365
|
+
case 'markdown':
|
|
366
|
+
return this.exportToMarkdown(routes)
|
|
367
|
+
|
|
368
|
+
case 'openapi':
|
|
369
|
+
return this.exportToOpenAPI(routes)
|
|
370
|
+
|
|
371
|
+
default:
|
|
372
|
+
throw new Error(`Unsupported export format: ${format}`)
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Clear all routes and statistics
|
|
378
|
+
*/
|
|
379
|
+
clear(): void {
|
|
380
|
+
this.routes.clear()
|
|
381
|
+
this.groups.clear()
|
|
382
|
+
this.routeStats.clear()
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Generate unique route ID
|
|
387
|
+
*/
|
|
388
|
+
private generateRouteId(method: string, pattern: string): string {
|
|
389
|
+
return `${method.toLowerCase()}_${pattern.replace(/[^a-z0-9]/gi, '_')}_${Date.now()}`
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Extract function source code
|
|
394
|
+
*/
|
|
395
|
+
private getFunctionSource(fn: (...args: any[]) => any): string | undefined {
|
|
396
|
+
try {
|
|
397
|
+
const source = fn.toString()
|
|
398
|
+
return source.length > 200 ? `${source.substring(0, 200)}...` : source
|
|
399
|
+
}
|
|
400
|
+
catch {
|
|
401
|
+
return undefined
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Extract function parameters
|
|
407
|
+
*/
|
|
408
|
+
private extractFunctionParameters(fn: (...args: any[]) => any): string[] {
|
|
409
|
+
try {
|
|
410
|
+
const source = fn.toString()
|
|
411
|
+
const match = source.match(/\(([^)]*)\)/)
|
|
412
|
+
if (!match)
|
|
413
|
+
return []
|
|
414
|
+
|
|
415
|
+
return match[1]
|
|
416
|
+
.split(',')
|
|
417
|
+
.map(param => param.trim().split(/\s+/)[0])
|
|
418
|
+
.filter(param => param.length > 0)
|
|
419
|
+
}
|
|
420
|
+
catch {
|
|
421
|
+
return []
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Check if function is async
|
|
427
|
+
*/
|
|
428
|
+
private isAsyncFunction(fn: (...args: any[]) => any): boolean {
|
|
429
|
+
return fn.constructor.name === 'AsyncFunction'
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Extract route parameters from pattern
|
|
434
|
+
*/
|
|
435
|
+
private extractRouteParameters(pattern: string): RouteMetadata['params'] {
|
|
436
|
+
const params: RouteMetadata['params'] = []
|
|
437
|
+
const paramRegex = /\{([^}]+)\}/g
|
|
438
|
+
|
|
439
|
+
for (const match of pattern.matchAll(paramRegex)) {
|
|
440
|
+
const paramDef = match[1]
|
|
441
|
+
const [name, constraint] = paramDef.split(':')
|
|
442
|
+
|
|
443
|
+
params.push({
|
|
444
|
+
name: name.trim(),
|
|
445
|
+
type: this.inferParameterType(constraint),
|
|
446
|
+
optional: paramDef.includes('?'),
|
|
447
|
+
constraint,
|
|
448
|
+
})
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
return params
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Infer parameter type from constraint
|
|
456
|
+
*/
|
|
457
|
+
private inferParameterType(constraint?: string): 'string' | 'number' | 'uuid' | 'slug' {
|
|
458
|
+
if (!constraint)
|
|
459
|
+
return 'string'
|
|
460
|
+
|
|
461
|
+
if (constraint.includes('uuid'))
|
|
462
|
+
return 'uuid'
|
|
463
|
+
if (constraint.includes('slug'))
|
|
464
|
+
return 'slug'
|
|
465
|
+
if (constraint.includes('number') || constraint.includes('int'))
|
|
466
|
+
return 'number'
|
|
467
|
+
|
|
468
|
+
return 'string'
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Get call site information
|
|
473
|
+
*/
|
|
474
|
+
private getCallSiteInfo(): { file?: string, line?: number } {
|
|
475
|
+
try {
|
|
476
|
+
const stack = new Error('route-inspector callsite').stack
|
|
477
|
+
if (!stack)
|
|
478
|
+
return {}
|
|
479
|
+
|
|
480
|
+
const lines = stack.split('\n')
|
|
481
|
+
const callerLine = lines.find(line =>
|
|
482
|
+
line.includes('.ts:') && !line.includes('route-inspector.ts'),
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
if (callerLine) {
|
|
486
|
+
const match = callerLine.match(/([^/\\]+\.ts):(\d+)/)
|
|
487
|
+
if (match) {
|
|
488
|
+
return {
|
|
489
|
+
file: match[1],
|
|
490
|
+
line: Number.parseInt(match[2]),
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
catch {
|
|
496
|
+
// Ignore errors
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
return {}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Convert route pattern to regex
|
|
504
|
+
*/
|
|
505
|
+
private patternToRegex(pattern: string): RegExp {
|
|
506
|
+
const regexPattern = pattern
|
|
507
|
+
.replace(/\{[^}]+\}/g, '([^/]+)')
|
|
508
|
+
.replace(/\*/g, '.*')
|
|
509
|
+
|
|
510
|
+
return new RegExp(`^${regexPattern}$`)
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Generate recommendations based on analysis
|
|
515
|
+
*/
|
|
516
|
+
private generateRecommendations(analysis: RouteAnalysis): string[] {
|
|
517
|
+
const recommendations: string[] = []
|
|
518
|
+
|
|
519
|
+
if (analysis.duplicatePatterns.length > 0) {
|
|
520
|
+
recommendations.push(`Found ${analysis.duplicatePatterns.length} duplicate route patterns. Consider consolidating or using different patterns.`)
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
if (analysis.unusedRoutes.length > 0) {
|
|
524
|
+
recommendations.push(`${analysis.unusedRoutes.length} routes have never been accessed. Consider removing unused routes.`)
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (analysis.slowRoutes.length > 0) {
|
|
528
|
+
recommendations.push(`${analysis.slowRoutes.length} routes have slow average response times (>1000ms). Consider optimization.`)
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if (analysis.errorProneRoutes.length > 0) {
|
|
532
|
+
recommendations.push(`${analysis.errorProneRoutes.length} routes have high error rates (>5%). Review error handling.`)
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
const totalMiddleware = Object.keys(analysis.middlewareUsage).length
|
|
536
|
+
if (totalMiddleware > 20) {
|
|
537
|
+
recommendations.push(`High number of middleware (${totalMiddleware}). Consider consolidating similar middleware.`)
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
return recommendations
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Export routes to CSV format
|
|
545
|
+
*/
|
|
546
|
+
private exportToCsv(routes: RouteMetadata[]): string {
|
|
547
|
+
const headers = ['Method', 'Pattern', 'Handler', 'Middleware', 'Hits', 'Avg Response Time', 'Errors']
|
|
548
|
+
const rows = routes.map(route => [
|
|
549
|
+
route.method,
|
|
550
|
+
route.pattern,
|
|
551
|
+
route.handler.name,
|
|
552
|
+
route.middleware.map(mw => mw.name).join(';'),
|
|
553
|
+
route.stats.hits.toString(),
|
|
554
|
+
route.stats.averageResponseTime.toFixed(2),
|
|
555
|
+
route.stats.errors.toString(),
|
|
556
|
+
])
|
|
557
|
+
|
|
558
|
+
return [headers, ...rows].map(row => row.join(',')).join('\n')
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Export routes to Markdown format
|
|
563
|
+
*/
|
|
564
|
+
private exportToMarkdown(routes: RouteMetadata[]): string {
|
|
565
|
+
let markdown = '# Route Documentation\n\n'
|
|
566
|
+
|
|
567
|
+
const groupedRoutes = new Map<string, RouteMetadata[]>()
|
|
568
|
+
routes.forEach((route) => {
|
|
569
|
+
const group = route.metadata.group || 'Default'
|
|
570
|
+
if (!groupedRoutes.has(group)) {
|
|
571
|
+
groupedRoutes.set(group, [])
|
|
572
|
+
}
|
|
573
|
+
groupedRoutes.get(group)!.push(route)
|
|
574
|
+
})
|
|
575
|
+
|
|
576
|
+
groupedRoutes.forEach((groupRoutes, groupName) => {
|
|
577
|
+
markdown += `## ${groupName}\n\n`
|
|
578
|
+
markdown += '| Method | Pattern | Handler | Middleware | Stats |\n'
|
|
579
|
+
markdown += '|--------|---------|---------|------------|-------|\n'
|
|
580
|
+
|
|
581
|
+
groupRoutes.forEach((route) => {
|
|
582
|
+
const middleware = route.middleware.map(mw => mw.name).join(', ')
|
|
583
|
+
const stats = `${route.stats.hits} hits, ${route.stats.averageResponseTime.toFixed(2)}ms avg`
|
|
584
|
+
|
|
585
|
+
markdown += `| ${route.method} | \`${route.pattern}\` | ${route.handler.name} | ${middleware} | ${stats} |\n`
|
|
586
|
+
})
|
|
587
|
+
|
|
588
|
+
markdown += '\n'
|
|
589
|
+
})
|
|
590
|
+
|
|
591
|
+
return markdown
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Export routes to OpenAPI format
|
|
596
|
+
*/
|
|
597
|
+
private exportToOpenAPI(routes: RouteMetadata[]): string {
|
|
598
|
+
const openapi = {
|
|
599
|
+
openapi: '3.0.0',
|
|
600
|
+
info: {
|
|
601
|
+
title: 'API Documentation',
|
|
602
|
+
version: '1.0.0',
|
|
603
|
+
},
|
|
604
|
+
paths: {} as Record<string, any>,
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
routes.forEach((route) => {
|
|
608
|
+
const path = route.pattern.replace(/\{([^}]+)\}/g, '{$1}')
|
|
609
|
+
const method = route.method.toLowerCase()
|
|
610
|
+
|
|
611
|
+
if (!openapi.paths[path]) {
|
|
612
|
+
openapi.paths[path] = {}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
openapi.paths[path][method] = {
|
|
616
|
+
summary: route.metadata.description || `${route.method} ${route.pattern}`,
|
|
617
|
+
operationId: route.id,
|
|
618
|
+
parameters: route.params.map(param => ({
|
|
619
|
+
name: param.name,
|
|
620
|
+
in: 'path',
|
|
621
|
+
required: !param.optional,
|
|
622
|
+
schema: {
|
|
623
|
+
type: param.type === 'number' ? 'integer' : 'string',
|
|
624
|
+
},
|
|
625
|
+
})),
|
|
626
|
+
responses: {
|
|
627
|
+
200: {
|
|
628
|
+
description: 'Success',
|
|
629
|
+
},
|
|
630
|
+
},
|
|
631
|
+
}
|
|
632
|
+
})
|
|
633
|
+
|
|
634
|
+
return JSON.stringify(openapi, null, 2)
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Global route inspector instance
|
|
640
|
+
*/
|
|
641
|
+
let globalInspector: RouteInspector | null = null
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Initialize global route inspector
|
|
645
|
+
*/
|
|
646
|
+
export function initializeRouteInspector(): RouteInspector {
|
|
647
|
+
globalInspector = new RouteInspector()
|
|
648
|
+
return globalInspector
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* Get global route inspector
|
|
653
|
+
*/
|
|
654
|
+
export function getRouteInspector(): RouteInspector | null {
|
|
655
|
+
return globalInspector
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Route inspection helpers
|
|
660
|
+
*/
|
|
661
|
+
export const RouteInspectionHelpers = {
|
|
662
|
+
/**
|
|
663
|
+
* List all routes in a formatted table
|
|
664
|
+
*/
|
|
665
|
+
listRoutes: (filter?: Parameters<RouteInspector['getRoutes']>[0]): void => {
|
|
666
|
+
const inspector = getRouteInspector()
|
|
667
|
+
if (!inspector) {
|
|
668
|
+
console.log('Route inspector not initialized')
|
|
669
|
+
return
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
const routes = inspector.getRoutes(filter)
|
|
673
|
+
|
|
674
|
+
console.log('\nš Registered Routes:')
|
|
675
|
+
console.log('ā'.repeat(80))
|
|
676
|
+
|
|
677
|
+
if (routes.length === 0) {
|
|
678
|
+
console.log('No routes found')
|
|
679
|
+
return
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
routes.forEach((route) => {
|
|
683
|
+
const middleware = route.middleware.length > 0
|
|
684
|
+
? ` [${route.middleware.map(mw => mw.name).join(', ')}]`
|
|
685
|
+
: ''
|
|
686
|
+
|
|
687
|
+
const stats = route.stats.hits > 0
|
|
688
|
+
? ` (${route.stats.hits} hits, ${route.stats.averageResponseTime.toFixed(2)}ms avg)`
|
|
689
|
+
: ' (unused)'
|
|
690
|
+
|
|
691
|
+
console.log(`${route.method.padEnd(6)} ${route.pattern}${middleware}${stats}`)
|
|
692
|
+
})
|
|
693
|
+
|
|
694
|
+
console.log('ā'.repeat(80))
|
|
695
|
+
console.log(`Total: ${routes.length} routes`)
|
|
696
|
+
},
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Analyze routes and show recommendations
|
|
700
|
+
*/
|
|
701
|
+
analyzeRoutes: (): void => {
|
|
702
|
+
const inspector = getRouteInspector()
|
|
703
|
+
if (!inspector) {
|
|
704
|
+
console.log('Route inspector not initialized')
|
|
705
|
+
return
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
const analysis = inspector.analyzeRoutes()
|
|
709
|
+
|
|
710
|
+
console.log('\nš Route Analysis:')
|
|
711
|
+
console.log('ā'.repeat(50))
|
|
712
|
+
console.log(`Total Routes: ${analysis.totalRoutes}`)
|
|
713
|
+
console.log('Routes by Method:', analysis.routesByMethod)
|
|
714
|
+
console.log(`Unused Routes: ${analysis.unusedRoutes.length}`)
|
|
715
|
+
console.log(`Slow Routes: ${analysis.slowRoutes.length}`)
|
|
716
|
+
console.log(`Error-prone Routes: ${analysis.errorProneRoutes.length}`)
|
|
717
|
+
console.log(`Duplicate Patterns: ${analysis.duplicatePatterns.length}`)
|
|
718
|
+
|
|
719
|
+
if (analysis.recommendations.length > 0) {
|
|
720
|
+
console.log('\nš” Recommendations:')
|
|
721
|
+
analysis.recommendations.forEach((rec, index) => {
|
|
722
|
+
console.log(`${index + 1}. ${rec}`)
|
|
723
|
+
})
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
console.log('ā'.repeat(50))
|
|
727
|
+
},
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
* Export routes to file
|
|
731
|
+
*/
|
|
732
|
+
exportRoutes: (format: 'json' | 'csv' | 'markdown' | 'openapi' = 'json', filename?: string): void => {
|
|
733
|
+
const inspector = getRouteInspector()
|
|
734
|
+
if (!inspector) {
|
|
735
|
+
console.log('Route inspector not initialized')
|
|
736
|
+
return
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
const content = inspector.exportRoutes(format)
|
|
740
|
+
|
|
741
|
+
if (filename) {
|
|
742
|
+
// In a real implementation, you'd write to file
|
|
743
|
+
console.log(`Routes exported to ${filename}`)
|
|
744
|
+
}
|
|
745
|
+
else {
|
|
746
|
+
console.log(content)
|
|
747
|
+
}
|
|
748
|
+
},
|
|
749
|
+
}
|