@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
package/src/cli/index.ts
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import type { GenerateMiddlewareTypesOptions, MapMiddlewareOptions } from './middleware'
|
|
2
|
+
import type { OpenAPIOptions } from './openapi'
|
|
3
|
+
import type { GenerateRouterTypesOptions } from './router'
|
|
4
|
+
import type { GenerateRouteTypesOptions, RouteListOptions } from './routes'
|
|
5
|
+
import process from 'node:process'
|
|
6
|
+
import { CLI } from '@stacksjs/clapp'
|
|
7
|
+
import { version } from '../../package.json'
|
|
8
|
+
import { generateMiddlewareMap, generateMiddlewareTypes, watchDirectoryForMiddleware, watchMiddlewareDirectory } from './middleware'
|
|
9
|
+
import { generateOpenAPISpec } from './openapi'
|
|
10
|
+
import { generateRouterTypes, watchRouterFiles } from './router'
|
|
11
|
+
import { displayRoutes, generateRouteTypes, watchRoutesDirectory } from './routes'
|
|
12
|
+
import { checkRouterHealth, clearCaches, debugRoute, testRoutes, validateRoutes } from './utils'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Create and configure the CLI
|
|
16
|
+
*/
|
|
17
|
+
export function createCLI(): CLI {
|
|
18
|
+
const cli = new CLI('router')
|
|
19
|
+
|
|
20
|
+
// Set version info
|
|
21
|
+
cli.version(version)
|
|
22
|
+
|
|
23
|
+
// Register commands
|
|
24
|
+
registerRouteCommands(cli)
|
|
25
|
+
registerMiddlewareCommands(cli)
|
|
26
|
+
registerRouterCommands(cli)
|
|
27
|
+
registerOpenAPICommands(cli)
|
|
28
|
+
registerUtilityCommands(cli)
|
|
29
|
+
|
|
30
|
+
// Add help command
|
|
31
|
+
cli.help()
|
|
32
|
+
|
|
33
|
+
return cli
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Register route-related commands
|
|
38
|
+
*/
|
|
39
|
+
function registerRouteCommands(cli: CLI): void {
|
|
40
|
+
cli
|
|
41
|
+
.command('route:list', 'List all registered routes')
|
|
42
|
+
.option('-v, --verbose', 'Show detailed information including middleware')
|
|
43
|
+
.option('-vv, --extra-verbose', 'Show very detailed information')
|
|
44
|
+
.option('--path <path>', 'Filter routes by path prefix')
|
|
45
|
+
.option('--except-vendor', 'Exclude vendor routes')
|
|
46
|
+
.option('--only-vendor', 'Show only vendor routes')
|
|
47
|
+
.example('router route:list')
|
|
48
|
+
.example('router route:list -v')
|
|
49
|
+
.example('router route:list --path=/api')
|
|
50
|
+
.action(async (options: RouteListOptions) => {
|
|
51
|
+
try {
|
|
52
|
+
await displayRoutes(options)
|
|
53
|
+
}
|
|
54
|
+
catch (error: any) {
|
|
55
|
+
console.error(`Failed to list routes: ${error.message}`)
|
|
56
|
+
process.exit(1)
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
cli
|
|
61
|
+
.command('route:types', 'Generate TypeScript types for route names')
|
|
62
|
+
.option('--output <file>', 'Output file path', { default: 'route-types.ts' })
|
|
63
|
+
.option('--watch', 'Watch for changes in routes directory')
|
|
64
|
+
.example('router route:types')
|
|
65
|
+
.example('router route:types --output src/types/routes.ts')
|
|
66
|
+
.example('router route:types --watch')
|
|
67
|
+
.action(async (options: GenerateRouteTypesOptions) => {
|
|
68
|
+
try {
|
|
69
|
+
const outputPath = options.output || 'route-types.ts'
|
|
70
|
+
if (options.watch) {
|
|
71
|
+
await watchRoutesDirectory(outputPath)
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
await generateRouteTypes(outputPath)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (error: any) {
|
|
78
|
+
console.error(`Failed to generate route types: ${error.message}`)
|
|
79
|
+
process.exit(1)
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Register middleware-related commands
|
|
86
|
+
*/
|
|
87
|
+
function registerMiddlewareCommands(cli: CLI): void {
|
|
88
|
+
cli
|
|
89
|
+
.command('middleware:types', 'Generate TypeScript types for middleware configurations')
|
|
90
|
+
.option('--output <file>', 'Output file path', { default: 'middleware-types.ts' })
|
|
91
|
+
.option('--watch', 'Watch for changes in middleware directory')
|
|
92
|
+
.example('router middleware:types')
|
|
93
|
+
.example('router middleware:types --output src/types/middleware.ts')
|
|
94
|
+
.example('router middleware:types --watch')
|
|
95
|
+
.action(async (options: GenerateMiddlewareTypesOptions) => {
|
|
96
|
+
try {
|
|
97
|
+
const outputPath = options.output || 'middleware-types.ts'
|
|
98
|
+
if (options.watch) {
|
|
99
|
+
await watchMiddlewareDirectory(outputPath)
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
await generateMiddlewareTypes(outputPath)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (error: any) {
|
|
106
|
+
console.error(`Failed to generate middleware types: ${error.message}`)
|
|
107
|
+
process.exit(1)
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
cli
|
|
112
|
+
.command('middleware:map', 'Generate TypeScript types for all middleware in the project')
|
|
113
|
+
.option('--dir <directory>', 'Directory to scan for middleware classes', { default: 'src' })
|
|
114
|
+
.option('--output <file>', 'Output file path', { default: 'middleware-map.ts' })
|
|
115
|
+
.option('--watch', 'Watch for changes in the specified directory')
|
|
116
|
+
.example('router middleware:map')
|
|
117
|
+
.example('router middleware:map --dir app')
|
|
118
|
+
.example('router middleware:map --output src/types/project-middleware.ts')
|
|
119
|
+
.example('router middleware:map --watch')
|
|
120
|
+
.action(async (options: MapMiddlewareOptions) => {
|
|
121
|
+
try {
|
|
122
|
+
const outputPath = options.output || 'middleware-map.ts'
|
|
123
|
+
const directoryPath = options.dir || 'src'
|
|
124
|
+
|
|
125
|
+
if (options.watch) {
|
|
126
|
+
await watchDirectoryForMiddleware(directoryPath, outputPath)
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
await generateMiddlewareMap(directoryPath, outputPath)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch (error: any) {
|
|
133
|
+
console.error(`Failed to generate middleware map: ${error.message}`)
|
|
134
|
+
process.exit(1)
|
|
135
|
+
}
|
|
136
|
+
})
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Register router extension-related commands
|
|
141
|
+
*/
|
|
142
|
+
function registerRouterCommands(cli: CLI): void {
|
|
143
|
+
cli
|
|
144
|
+
.command('router:types', 'Generate TypeScript types for router extensions')
|
|
145
|
+
.option('--output <file>', 'Output file path', { default: 'router-types.ts' })
|
|
146
|
+
.option('--watch', 'Watch for changes in router files')
|
|
147
|
+
.example('router router:types')
|
|
148
|
+
.example('router router:types --output src/types/router.ts')
|
|
149
|
+
.example('router router:types --watch')
|
|
150
|
+
.action(async (options: GenerateRouterTypesOptions) => {
|
|
151
|
+
try {
|
|
152
|
+
const outputPath = options.output || 'router-types.ts'
|
|
153
|
+
if (options.watch) {
|
|
154
|
+
await watchRouterFiles(outputPath)
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
await generateRouterTypes(outputPath)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch (error: any) {
|
|
161
|
+
console.error(`Failed to generate router types: ${error.message}`)
|
|
162
|
+
process.exit(1)
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Register OpenAPI-related commands
|
|
169
|
+
*/
|
|
170
|
+
function registerOpenAPICommands(cli: CLI): void {
|
|
171
|
+
cli
|
|
172
|
+
.command('openapi', 'Generate OpenAPI specification for API routes')
|
|
173
|
+
.option('--output <file>', 'Output file path', { default: 'openapi.json' })
|
|
174
|
+
.option('--title <title>', 'API title', { default: 'API Documentation' })
|
|
175
|
+
.option('--version <version>', 'API version', { default: '1.0.0' })
|
|
176
|
+
.option('--description <description>', 'API description')
|
|
177
|
+
.option('--base-path <path>', 'Base API path', { default: '/' })
|
|
178
|
+
.option('--servers <urls>', 'Comma-separated list of server URLs')
|
|
179
|
+
.option('--tags', 'Group endpoints by tags', { default: true })
|
|
180
|
+
.option('--security', 'Include security schemes if available', { default: true })
|
|
181
|
+
.example('router openapi')
|
|
182
|
+
.example('router openapi --output api-spec.json')
|
|
183
|
+
.example('router openapi --title "My API" --version 2.0')
|
|
184
|
+
.example('router openapi --servers http://localhost:3000,https://api.example.com')
|
|
185
|
+
.action(async (options: OpenAPIOptions) => {
|
|
186
|
+
try {
|
|
187
|
+
await generateOpenAPISpec(options)
|
|
188
|
+
}
|
|
189
|
+
catch (error: any) {
|
|
190
|
+
console.error(`Failed to generate OpenAPI specification: ${error.message}`)
|
|
191
|
+
process.exit(1)
|
|
192
|
+
}
|
|
193
|
+
})
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Register utility commands for debugging and development
|
|
198
|
+
*/
|
|
199
|
+
function registerUtilityCommands(cli: CLI): void {
|
|
200
|
+
cli
|
|
201
|
+
.command('health', 'Check router health and configuration')
|
|
202
|
+
.option('--verbose', 'Show detailed health information')
|
|
203
|
+
.example('router health')
|
|
204
|
+
.example('router health --verbose')
|
|
205
|
+
.action(async (options: { verbose?: boolean }) => {
|
|
206
|
+
try {
|
|
207
|
+
await checkRouterHealth(options)
|
|
208
|
+
}
|
|
209
|
+
catch (error: any) {
|
|
210
|
+
console.error(`Health check failed: ${error.message}`)
|
|
211
|
+
process.exit(1)
|
|
212
|
+
}
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
cli
|
|
216
|
+
.command('test:routes', 'Test routes by making HTTP requests')
|
|
217
|
+
.option('--base-url <url>', 'Base URL for testing', { default: 'http://localhost:3000' })
|
|
218
|
+
.option('--filter <pattern>', 'Filter routes by path pattern')
|
|
219
|
+
.option('--method <methods>', 'Test only specific HTTP methods (comma-separated)')
|
|
220
|
+
.option('--timeout <ms>', 'Request timeout in milliseconds', { default: 5000 })
|
|
221
|
+
.example('router test:routes')
|
|
222
|
+
.example('router test:routes --base-url http://localhost:8080')
|
|
223
|
+
.example('router test:routes --filter "/api/*"')
|
|
224
|
+
.example('router test:routes --method GET,POST')
|
|
225
|
+
.action(async (options: { baseUrl?: string, filter?: string, method?: string, timeout?: number }) => {
|
|
226
|
+
try {
|
|
227
|
+
await testRoutes(options)
|
|
228
|
+
}
|
|
229
|
+
catch (error: any) {
|
|
230
|
+
console.error(`Route testing failed: ${error.message}`)
|
|
231
|
+
process.exit(1)
|
|
232
|
+
}
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
cli
|
|
236
|
+
.command('debug:route <path>', 'Debug route matching for a specific path')
|
|
237
|
+
.option('--method <method>', 'HTTP method to test', { default: 'GET' })
|
|
238
|
+
.option('--verbose', 'Show detailed matching information')
|
|
239
|
+
.example('router debug:route /api/users/123')
|
|
240
|
+
.example('router debug:route /api/users/123 --method POST --verbose')
|
|
241
|
+
.action(async (path: string, options: { method?: string, verbose?: boolean }) => {
|
|
242
|
+
try {
|
|
243
|
+
await debugRoute(path, options)
|
|
244
|
+
}
|
|
245
|
+
catch (error: any) {
|
|
246
|
+
console.error(`Route debugging failed: ${error.message}`)
|
|
247
|
+
process.exit(1)
|
|
248
|
+
}
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
cli
|
|
252
|
+
.command('cache:clear', 'Clear route caches')
|
|
253
|
+
.option('--stats', 'Show cache statistics before clearing')
|
|
254
|
+
.example('router cache:clear')
|
|
255
|
+
.example('router cache:clear --stats')
|
|
256
|
+
.action(async (options: { stats?: boolean }) => {
|
|
257
|
+
try {
|
|
258
|
+
await clearCaches(options)
|
|
259
|
+
}
|
|
260
|
+
catch (error: any) {
|
|
261
|
+
console.error(`Cache clearing failed: ${error.message}`)
|
|
262
|
+
process.exit(1)
|
|
263
|
+
}
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
cli
|
|
267
|
+
.command('validate', 'Validate route definitions and configuration')
|
|
268
|
+
.option('--strict', 'Use strict validation rules')
|
|
269
|
+
.option('--fix', 'Automatically fix simple issues')
|
|
270
|
+
.example('router validate')
|
|
271
|
+
.example('router validate --strict --fix')
|
|
272
|
+
.action(async (options: { strict?: boolean, fix?: boolean }) => {
|
|
273
|
+
try {
|
|
274
|
+
await validateRoutes(options)
|
|
275
|
+
}
|
|
276
|
+
catch (error: any) {
|
|
277
|
+
console.error(`Route validation failed: ${error.message}`)
|
|
278
|
+
process.exit(1)
|
|
279
|
+
}
|
|
280
|
+
})
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export * from './middleware'
|
|
284
|
+
export * from './openapi'
|
|
285
|
+
export * from './router'
|
|
286
|
+
export * from './routes'
|
|
287
|
+
export * from './utils'
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import fs from 'node:fs/promises'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import process from 'node:process'
|
|
4
|
+
import { middleware } from '../../src/middleware'
|
|
5
|
+
import { chalk } from './colors'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Options for the middleware:types command
|
|
9
|
+
*/
|
|
10
|
+
export interface GenerateMiddlewareTypesOptions {
|
|
11
|
+
output?: string
|
|
12
|
+
watch?: boolean
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Options for the middleware:map command
|
|
17
|
+
*/
|
|
18
|
+
export interface MapMiddlewareOptions {
|
|
19
|
+
output?: string
|
|
20
|
+
dir?: string
|
|
21
|
+
watch?: boolean
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Generate TypeScript types for middleware configurations
|
|
26
|
+
*/
|
|
27
|
+
export async function generateMiddlewareTypes(outputPath: string): Promise<void> {
|
|
28
|
+
// Get middleware information
|
|
29
|
+
const middlewareInfo = Object.entries(middleware).map(([key, instance]) => ({
|
|
30
|
+
name: key,
|
|
31
|
+
className: instance.constructor.name,
|
|
32
|
+
}))
|
|
33
|
+
|
|
34
|
+
// Generate type definition
|
|
35
|
+
const typeContent = `/**
|
|
36
|
+
* This file is auto-generated.
|
|
37
|
+
* DO NOT EDIT THIS FILE DIRECTLY.
|
|
38
|
+
* To update, run 'bun router middleware:types'
|
|
39
|
+
*/
|
|
40
|
+
import type { ${middlewareInfo.map(m => m.className).join(', ')} } from './middleware'
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Available middleware map with middleware names as keys
|
|
44
|
+
*/
|
|
45
|
+
export interface MiddlewareMap {
|
|
46
|
+
${middlewareInfo.map(m => ` '${m.name}': ${m.className}`).join('\n')}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* String literal type of available middleware names
|
|
51
|
+
*/
|
|
52
|
+
export type MiddlewareName = ${middlewareInfo.map(m => `'${m.name}'`).join(' | ')}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Middleware configuration type for router setup
|
|
56
|
+
*/
|
|
57
|
+
export type MiddlewareConfig = MiddlewareName | ${middlewareInfo.map(m => m.className).join(' | ')}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Function to check if a middleware name is valid
|
|
61
|
+
*/
|
|
62
|
+
export function isValidMiddleware(name: string): name is MiddlewareName {
|
|
63
|
+
return [${middlewareInfo.map(m => `'${m.name}'`).join(', ')}].includes(name)
|
|
64
|
+
}
|
|
65
|
+
`
|
|
66
|
+
|
|
67
|
+
// Write to file
|
|
68
|
+
await fs.writeFile(outputPath, typeContent)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Find TypeScript files in a directory recursively
|
|
73
|
+
*/
|
|
74
|
+
async function findTsFiles(dir: string): Promise<string[]> {
|
|
75
|
+
const files: string[] = []
|
|
76
|
+
const entries = await fs.readdir(dir, { withFileTypes: true })
|
|
77
|
+
|
|
78
|
+
for (const entry of entries) {
|
|
79
|
+
const fullPath = path.join(dir, entry.name)
|
|
80
|
+
if (entry.isDirectory()) {
|
|
81
|
+
files.push(...await findTsFiles(fullPath))
|
|
82
|
+
}
|
|
83
|
+
else if (entry.isFile() && entry.name.endsWith('.ts')) {
|
|
84
|
+
files.push(fullPath)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return files
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Scan a file for middleware classes
|
|
93
|
+
*/
|
|
94
|
+
async function scanFileForMiddleware(filePath: string): Promise<{ name: string, path: string }[]> {
|
|
95
|
+
const middlewareClasses: { name: string, path: string }[] = []
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
const content = await fs.readFile(filePath, 'utf-8')
|
|
99
|
+
|
|
100
|
+
// Look for class declarations that implement Middleware or have "Middleware" in their name
|
|
101
|
+
const classRegex = /export\s+(?:default\s+)?class\s+(\w+)\s+(?:implements\s+Middleware|\{[\s\S]*?handle\s*\([\s\S]*?\))/g
|
|
102
|
+
let match: RegExpExecArray | null = null
|
|
103
|
+
|
|
104
|
+
// eslint-disable-next-line no-cond-assign
|
|
105
|
+
while (match = classRegex.exec(content)) {
|
|
106
|
+
const className = match[1]
|
|
107
|
+
|
|
108
|
+
// If the class name indicates it's middleware or it implements Middleware interface
|
|
109
|
+
if (className.includes('Middleware') || match[0].includes('implements Middleware')) {
|
|
110
|
+
const relativePath = path.relative(process.cwd(), filePath)
|
|
111
|
+
// Remove extension for import path
|
|
112
|
+
const importPath = relativePath.replace(/\.ts$/, '')
|
|
113
|
+
middlewareClasses.push({
|
|
114
|
+
name: className,
|
|
115
|
+
path: importPath,
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
console.warn(chalk.yellow(`Error scanning file ${filePath}: ${error}`))
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return middlewareClasses
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Generate middleware type mappings for user project
|
|
129
|
+
*/
|
|
130
|
+
export async function generateMiddlewareMap(
|
|
131
|
+
directoryPath: string,
|
|
132
|
+
outputPath: string,
|
|
133
|
+
): Promise<void> {
|
|
134
|
+
console.log(chalk.blue(`Scanning directory: ${directoryPath} for middleware classes...`))
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
// Find all TypeScript files in the directory
|
|
138
|
+
const tsFiles = await findTsFiles(directoryPath)
|
|
139
|
+
const allMiddleware: { name: string, path: string }[] = []
|
|
140
|
+
|
|
141
|
+
// Scan each file for middleware
|
|
142
|
+
for (const file of tsFiles) {
|
|
143
|
+
const middlewareInFile = await scanFileForMiddleware(file)
|
|
144
|
+
allMiddleware.push(...middlewareInFile)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (allMiddleware.length === 0) {
|
|
148
|
+
console.warn(chalk.yellow('No middleware classes found in the specified directory.'))
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Generate the type definition
|
|
153
|
+
const imports = allMiddleware.map(m => `import { ${m.name} } from '${m.path}'`).join('\n')
|
|
154
|
+
const interfaceMembers = allMiddleware.map(m => ` ${m.name}: typeof ${m.name}`).join('\n')
|
|
155
|
+
const typeNames = allMiddleware.map(m => m.name).join(' | ')
|
|
156
|
+
|
|
157
|
+
const typeContent = `/**
|
|
158
|
+
* This file is auto-generated.
|
|
159
|
+
* DO NOT EDIT THIS FILE DIRECTLY.
|
|
160
|
+
* To update, run 'bun router middleware:map'
|
|
161
|
+
*/
|
|
162
|
+
|
|
163
|
+
${imports}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Map of all available middleware in the project
|
|
167
|
+
*/
|
|
168
|
+
export interface MiddlewareMap {
|
|
169
|
+
${interfaceMembers}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Type representing all available middleware classes in the project
|
|
174
|
+
*/
|
|
175
|
+
export type MiddlewareType = ${typeNames}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Type for a middleware handler function
|
|
179
|
+
*/
|
|
180
|
+
export type MiddlewareHandler = (req: any, next: () => Promise<Response>) => Promise<Response>
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Ensure the middleware module exports all the middleware classes used in the project
|
|
184
|
+
*/
|
|
185
|
+
export const middlewareMap: MiddlewareMap = {
|
|
186
|
+
${allMiddleware.map(m => ` ${m.name}: ${m.name}`).join(',\n')}
|
|
187
|
+
}
|
|
188
|
+
`
|
|
189
|
+
|
|
190
|
+
// Write to file
|
|
191
|
+
await fs.writeFile(outputPath, typeContent)
|
|
192
|
+
console.log(chalk.green(`✨ Middleware map generated at ${outputPath} with ${allMiddleware.length} middleware classes`))
|
|
193
|
+
|
|
194
|
+
// List found middleware
|
|
195
|
+
console.log(chalk.blue('Found middleware classes:'))
|
|
196
|
+
for (const m of allMiddleware) {
|
|
197
|
+
console.log(chalk.cyan(` - ${m.name} (${m.path})`))
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
console.error(chalk.red(`Error generating middleware map: ${error}`))
|
|
202
|
+
throw error
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Watch for changes in the directory and regenerate middleware map
|
|
208
|
+
*/
|
|
209
|
+
export async function watchDirectoryForMiddleware(
|
|
210
|
+
directoryPath: string,
|
|
211
|
+
outputPath: string,
|
|
212
|
+
): Promise<void> {
|
|
213
|
+
// Check if directory exists
|
|
214
|
+
try {
|
|
215
|
+
await fs.access(directoryPath)
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
console.error(chalk.red(`Directory not found at ${directoryPath}`))
|
|
219
|
+
process.exit(1)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Initial generation
|
|
223
|
+
await generateMiddlewareMap(directoryPath, outputPath)
|
|
224
|
+
console.log(chalk.blue(`Watching for changes in ${directoryPath}...`))
|
|
225
|
+
|
|
226
|
+
// Setup file watcher
|
|
227
|
+
let timeoutId: ReturnType<typeof setTimeout> | null = null
|
|
228
|
+
const watcher = fs.watch(directoryPath, { recursive: true })
|
|
229
|
+
|
|
230
|
+
for await (const _event of watcher) {
|
|
231
|
+
// Debounce to avoid multiple regenerations when multiple files change
|
|
232
|
+
if (timeoutId) {
|
|
233
|
+
clearTimeout(timeoutId)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
timeoutId = setTimeout(async () => {
|
|
237
|
+
console.log(chalk.yellow(`Changes detected. Regenerating middleware map...`))
|
|
238
|
+
try {
|
|
239
|
+
await generateMiddlewareMap(directoryPath, outputPath)
|
|
240
|
+
}
|
|
241
|
+
catch (error: any) {
|
|
242
|
+
console.error(chalk.red(`Error regenerating middleware map: ${error.message}`))
|
|
243
|
+
}
|
|
244
|
+
timeoutId = null
|
|
245
|
+
}, 500)
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Watch for changes in the middleware directory and regenerate types
|
|
251
|
+
*/
|
|
252
|
+
export async function watchMiddlewareDirectory(outputPath: string): Promise<void> {
|
|
253
|
+
const middlewarePath = path.join(process.cwd(), 'src', 'middleware')
|
|
254
|
+
|
|
255
|
+
// Check if middleware directory exists
|
|
256
|
+
try {
|
|
257
|
+
await fs.access(middlewarePath)
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
console.error(chalk.red(`Middleware directory not found at ${middlewarePath}`))
|
|
261
|
+
process.exit(1)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Initial generation
|
|
265
|
+
await generateMiddlewareTypes(outputPath)
|
|
266
|
+
console.log(chalk.green(`✨ Middleware types generated at ${outputPath}`))
|
|
267
|
+
console.log(chalk.blue(`Watching for changes in ${middlewarePath}...`))
|
|
268
|
+
|
|
269
|
+
// Setup file watcher
|
|
270
|
+
let timeoutId: ReturnType<typeof setTimeout> | null = null
|
|
271
|
+
const watcher = fs.watch(middlewarePath, { recursive: true })
|
|
272
|
+
|
|
273
|
+
for await (const _event of watcher) {
|
|
274
|
+
// Debounce to avoid multiple regenerations when multiple files change
|
|
275
|
+
if (timeoutId) {
|
|
276
|
+
clearTimeout(timeoutId)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
timeoutId = setTimeout(async () => {
|
|
280
|
+
console.log(chalk.yellow(`Changes detected in middleware directory. Regenerating types...`))
|
|
281
|
+
try {
|
|
282
|
+
await generateMiddlewareTypes(outputPath)
|
|
283
|
+
console.log(chalk.green(`✨ Middleware types regenerated at ${outputPath}`))
|
|
284
|
+
}
|
|
285
|
+
catch (error: any) {
|
|
286
|
+
console.error(chalk.red(`Error regenerating types: ${error.message}`))
|
|
287
|
+
}
|
|
288
|
+
timeoutId = null
|
|
289
|
+
}, 500)
|
|
290
|
+
}
|
|
291
|
+
}
|