@stacksjs/bun-router 0.0.17 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/dist/container/service-provider.d.ts +3 -3
- package/dist/development/performance-profiler.d.ts +3 -3
- package/dist/development/route-debugger.d.ts +1 -1
- package/dist/development/route-inspector.d.ts +2 -2
- package/dist/observability/integration.d.ts +1 -1
- package/dist/response/macros.d.ts +1 -1
- package/dist/router/index.d.ts +7 -7
- package/dist/router/router.d.ts +0 -32
- package/dist/testing/performance-testing.d.ts +2 -2
- package/dist/testing/test-client.d.ts +1 -1
- package/dist/testing/websocket-testing.d.ts +1 -1
- package/package.json +2 -3
- package/src/auth.ts +0 -489
- package/src/cache/lru-cache.ts +0 -457
- package/src/cache/middleware-memoization.ts +0 -531
- package/src/cache/route-cache-warmer.ts +0 -486
- package/src/cache/sqlite-cache.ts +0 -783
- package/src/cache/streaming-cache.ts +0 -572
- package/src/cli/colors.ts +0 -29
- package/src/cli/index.ts +0 -287
- package/src/cli/middleware.ts +0 -291
- package/src/cli/openapi.ts +0 -407
- package/src/cli/router.ts +0 -188
- package/src/cli/routes.ts +0 -265
- package/src/cli/utils.ts +0 -531
- package/src/cli.ts +0 -5
- package/src/config.ts +0 -322
- package/src/container/container.ts +0 -786
- package/src/container/contextual-binding.ts +0 -606
- package/src/container/decorators.ts +0 -368
- package/src/container/index.ts +0 -49
- package/src/container/service-provider.ts +0 -596
- package/src/development/hot-reload.ts +0 -673
- package/src/development/index.ts +0 -499
- package/src/development/performance-profiler.ts +0 -717
- package/src/development/route-debugger.ts +0 -527
- package/src/development/route-inspector.ts +0 -749
- package/src/development/typescript-utilities.ts +0 -682
- package/src/docs.ts +0 -397
- package/src/errors/circuit-breaker.ts +0 -733
- package/src/errors/error-handler.ts +0 -569
- package/src/errors/error-reporting.ts +0 -672
- package/src/errors/exceptions.ts +0 -536
- package/src/errors/graceful-degradation.ts +0 -623
- package/src/errors/index.ts +0 -21
- package/src/errors/router-errors.ts +0 -632
- package/src/file-serving/static-files.ts +0 -718
- package/src/index.ts +0 -66
- package/src/middleware/auth.ts +0 -220
- package/src/middleware/content_security_policy.ts +0 -215
- package/src/middleware/cors.ts +0 -142
- package/src/middleware/csrf.ts +0 -166
- package/src/middleware/ddos_protection.ts +0 -279
- package/src/middleware/file_security.ts +0 -191
- package/src/middleware/file_upload.ts +0 -275
- package/src/middleware/helmet.ts +0 -268
- package/src/middleware/index.ts +0 -117
- package/src/middleware/input_validation.ts +0 -453
- package/src/middleware/json_body.ts +0 -37
- package/src/middleware/performance_alerting.ts +0 -540
- package/src/middleware/performance_dashboard.ts +0 -661
- package/src/middleware/performance_monitor.ts +0 -945
- package/src/middleware/pipeline.ts +0 -489
- package/src/middleware/rate_limit.ts +0 -251
- package/src/middleware/request_id.ts +0 -36
- package/src/middleware/request_signing.ts +0 -638
- package/src/middleware/request_tracer.ts +0 -653
- package/src/middleware/response_cache.ts +0 -778
- package/src/middleware/security.ts +0 -482
- package/src/middleware/security_suite.ts +0 -257
- package/src/middleware/session.ts +0 -91
- package/src/model-binding/index.ts +0 -18
- package/src/model-binding/model-middleware.ts +0 -425
- package/src/model-binding/model-registry.ts +0 -550
- package/src/model-binding.ts +0 -370
- package/src/model-resolver-factory.ts +0 -106
- package/src/observability/correlation.ts +0 -691
- package/src/observability/health-checks.ts +0 -729
- package/src/observability/index.ts +0 -184
- package/src/observability/integration.ts +0 -548
- package/src/observability/metrics.ts +0 -753
- package/src/observability/tracing.ts +0 -638
- package/src/optimization/bun-utilities.ts +0 -778
- package/src/query-builder-integration.ts +0 -137
- package/src/request/context.ts +0 -109
- package/src/request/enhanced-request.ts +0 -876
- package/src/request/macros.ts +0 -822
- package/src/response/macros.ts +0 -665
- package/src/response/response-factory.ts +0 -596
- package/src/router/api-routes.ts +0 -243
- package/src/router/file-based-routing.ts +0 -697
- package/src/router/file-streaming.ts +0 -383
- package/src/router/fluent-routing.ts +0 -866
- package/src/router/group-organization.ts +0 -229
- package/src/router/handler-resolver.ts +0 -327
- package/src/router/http-methods.ts +0 -407
- package/src/router/index.ts +0 -193
- package/src/router/middleware-groups.ts +0 -222
- package/src/router/middleware-integration.ts +0 -399
- package/src/router/middleware.ts +0 -234
- package/src/router/model-binding.ts +0 -215
- package/src/router/optimized-route-matching.ts +0 -302
- package/src/router/route-building.ts +0 -221
- package/src/router/route-compiler.ts +0 -691
- package/src/router/route-matching.ts +0 -368
- package/src/router/route-trie.ts +0 -450
- package/src/router/router.ts +0 -1616
- package/src/router/server.ts +0 -684
- package/src/router/validation-integration.ts +0 -449
- package/src/router/view-rendering.ts +0 -233
- package/src/router/websocket.ts +0 -100
- package/src/routing/route-caching.ts +0 -402
- package/src/routing/route-throttling.ts +0 -469
- package/src/routing/subdomain-routing.ts +0 -492
- package/src/session/database-store.ts +0 -109
- package/src/session/file-store.ts +0 -148
- package/src/session/index.ts +0 -244
- package/src/session/memory-store.ts +0 -88
- package/src/session/redis-store.ts +0 -93
- package/src/streaming/index.ts +0 -17
- package/src/streaming/sse-handler.ts +0 -482
- package/src/streaming/stream-handler.ts +0 -552
- package/src/testing/auth-testing.ts +0 -448
- package/src/testing/file-upload-testing.ts +0 -543
- package/src/testing/index.ts +0 -10
- package/src/testing/middleware-testing.ts +0 -322
- package/src/testing/model-binding-testing.ts +0 -645
- package/src/testing/performance-testing.ts +0 -738
- package/src/testing/test-client.ts +0 -310
- package/src/testing/test-request.ts +0 -315
- package/src/testing/test-response.ts +0 -332
- package/src/testing/types.ts +0 -224
- package/src/testing/websocket-testing.ts +0 -590
- package/src/types/controller-types.ts +0 -385
- package/src/types/core.ts +0 -683
- package/src/types/middleware-types.ts +0 -422
- package/src/types/request-response-augmentation.ts +0 -489
- package/src/types/route-inference.ts +0 -372
- package/src/types.ts +0 -2123
- package/src/url.ts +0 -131
- package/src/utils/index.ts +0 -1
- package/src/utils/query-preservation.ts +0 -201
- package/src/utils.ts +0 -395
- package/src/validation/validator.ts +0 -688
- package/src/websocket/clustering.ts +0 -769
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
import type { HTTPMethod, MatchResult, Route } from '../types'
|
|
2
|
-
import type { Router } from './router'
|
|
3
|
-
import { RouteCompiler } from './route-compiler'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Optimized route matching extension for Router class
|
|
7
|
-
* Replaces the original route matching with high-performance trie-based matching
|
|
8
|
-
*/
|
|
9
|
-
export function registerOptimizedRouteMatching(RouterClass: typeof Router): void {
|
|
10
|
-
Object.defineProperties(RouterClass.prototype, {
|
|
11
|
-
/**
|
|
12
|
-
* Initialize the route compiler
|
|
13
|
-
*/
|
|
14
|
-
initializeRouteCompiler: {
|
|
15
|
-
value() {
|
|
16
|
-
if (!this.routeCompiler) {
|
|
17
|
-
this.routeCompiler = new RouteCompiler({
|
|
18
|
-
enableCaching: true,
|
|
19
|
-
enableMethodGrouping: true,
|
|
20
|
-
enablePriorityOptimization: true,
|
|
21
|
-
cacheSize: 1000,
|
|
22
|
-
precompilePatterns: true,
|
|
23
|
-
})
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
writable: true,
|
|
27
|
-
configurable: true,
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Add route to the optimized compiler
|
|
32
|
-
*/
|
|
33
|
-
addRouteToCompiler: {
|
|
34
|
-
value(route: Route) {
|
|
35
|
-
this.initializeRouteCompiler()
|
|
36
|
-
this.routeCompiler.addRoute(route)
|
|
37
|
-
},
|
|
38
|
-
writable: true,
|
|
39
|
-
configurable: true,
|
|
40
|
-
},
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Optimized route matching using trie structure
|
|
44
|
-
*/
|
|
45
|
-
matchRoute: {
|
|
46
|
-
value(path: string, method: HTTPMethod, domain?: string): MatchResult | undefined {
|
|
47
|
-
this.initializeRouteCompiler()
|
|
48
|
-
|
|
49
|
-
// Domain-scoped routes are matched by the domain-aware fallback.
|
|
50
|
-
// The trie (and its cache key) is method+path only, so letting it
|
|
51
|
-
// answer for hosts with registered domain routes would let one
|
|
52
|
-
// domain's cached match poison another's.
|
|
53
|
-
if (domain && this.domains[domain]) {
|
|
54
|
-
const domainMatch = this.fallbackMatchRoute(path, method, domain)
|
|
55
|
-
if (domainMatch) {
|
|
56
|
-
return domainMatch
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
// Use the optimized compiler for matching
|
|
61
|
-
const match = this.routeCompiler.match(path, method)
|
|
62
|
-
|
|
63
|
-
if (match && (!domain || !match.route.domain || match.route.domain === domain)) {
|
|
64
|
-
return match
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Fallback to original matching for edge cases (optional params, etc.)
|
|
68
|
-
const fallback = this.fallbackMatchRoute(path, method, domain)
|
|
69
|
-
if (fallback) {
|
|
70
|
-
return fallback
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// A HEAD request is served by the matching GET route when no
|
|
75
|
-
// explicit HEAD route exists (RFC 9110 §9.3.2)
|
|
76
|
-
if (method === 'HEAD') {
|
|
77
|
-
return this.matchRoute(path, 'GET', domain)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return undefined
|
|
81
|
-
},
|
|
82
|
-
writable: true,
|
|
83
|
-
configurable: true,
|
|
84
|
-
},
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Fallback to original route matching logic
|
|
88
|
-
*/
|
|
89
|
-
fallbackMatchRoute: {
|
|
90
|
-
value(path: string, method: HTTPMethod, domain?: string): MatchResult | undefined {
|
|
91
|
-
const url = new URL(path, 'http://localhost')
|
|
92
|
-
|
|
93
|
-
// Generate cache key
|
|
94
|
-
const cacheKey = `${domain || ''}:${method}:${url.pathname}`
|
|
95
|
-
|
|
96
|
-
// Check legacy cache first
|
|
97
|
-
if (this.routeCache.has(cacheKey)) {
|
|
98
|
-
return this.routeCache.get(cacheKey)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Bound the legacy cache — high-cardinality dynamic paths would
|
|
102
|
-
// otherwise grow it without limit
|
|
103
|
-
if (this.routeCache.size >= 10_000) {
|
|
104
|
-
this.routeCache.clear()
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Fast path for static routes
|
|
108
|
-
if (this.staticRoutes.has(method)) {
|
|
109
|
-
const staticRoute = this.staticRoutes.get(method)!.get(url.pathname)
|
|
110
|
-
if (staticRoute && (!domain || !staticRoute.domain || staticRoute.domain === domain)) {
|
|
111
|
-
const result = {
|
|
112
|
-
route: staticRoute,
|
|
113
|
-
params: {},
|
|
114
|
-
}
|
|
115
|
-
this.routeCache.set(cacheKey, result)
|
|
116
|
-
return result
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Get potential routes - either all routes or domain-specific routes
|
|
121
|
-
const potentialRoutes: Route[] = domain && this.domains[domain]
|
|
122
|
-
? this.domains[domain]
|
|
123
|
-
: this.routes
|
|
124
|
-
|
|
125
|
-
// Filter routes to only those matching the HTTP method
|
|
126
|
-
const methodRoutes = potentialRoutes.filter((route: Route) => route.method === method)
|
|
127
|
-
|
|
128
|
-
// First, try to find an exact match
|
|
129
|
-
for (const route of methodRoutes) {
|
|
130
|
-
if (route.path === url.pathname) {
|
|
131
|
-
const result = {
|
|
132
|
-
route,
|
|
133
|
-
params: {},
|
|
134
|
-
}
|
|
135
|
-
this.routeCache.set(cacheKey, result)
|
|
136
|
-
return result
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// If no exact match, try matching patterns
|
|
141
|
-
for (const route of methodRoutes) {
|
|
142
|
-
if (route.pattern) {
|
|
143
|
-
const match = route.pattern.exec(url)
|
|
144
|
-
if (match) {
|
|
145
|
-
const result = {
|
|
146
|
-
route,
|
|
147
|
-
params: match.pathname.groups,
|
|
148
|
-
}
|
|
149
|
-
this.routeCache.set(cacheKey, result)
|
|
150
|
-
return result
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Try wildcard routes — domain-scoped first, then global
|
|
156
|
-
const wildcardPools: Route[][] = domain && this.domains[domain]
|
|
157
|
-
? [this.domains[domain], this.routes]
|
|
158
|
-
: [this.routes]
|
|
159
|
-
|
|
160
|
-
for (const pool of wildcardPools) {
|
|
161
|
-
for (const route of pool) {
|
|
162
|
-
if (route.method !== method || !route.path.endsWith('*')) {
|
|
163
|
-
continue
|
|
164
|
-
}
|
|
165
|
-
const basePath = route.path.slice(0, -1) // Remove the '*'
|
|
166
|
-
if (url.pathname.startsWith(basePath)) {
|
|
167
|
-
const result = {
|
|
168
|
-
route,
|
|
169
|
-
params: { wildcard: url.pathname.slice(basePath.length) },
|
|
170
|
-
}
|
|
171
|
-
this.routeCache.set(cacheKey, result)
|
|
172
|
-
return result
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Cache the miss too — repeated requests for an unknown path skip
|
|
178
|
-
// the full scan (the cache is cleared whenever routes change)
|
|
179
|
-
this.routeCache.set(cacheKey, undefined)
|
|
180
|
-
return undefined
|
|
181
|
-
},
|
|
182
|
-
writable: true,
|
|
183
|
-
configurable: true,
|
|
184
|
-
},
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Get route matching statistics
|
|
188
|
-
*/
|
|
189
|
-
getRouteStats: {
|
|
190
|
-
value() {
|
|
191
|
-
this.initializeRouteCompiler()
|
|
192
|
-
return this.routeCompiler.getStats()
|
|
193
|
-
},
|
|
194
|
-
writable: true,
|
|
195
|
-
configurable: true,
|
|
196
|
-
},
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Get cache statistics
|
|
200
|
-
*/
|
|
201
|
-
getCacheStats: {
|
|
202
|
-
value() {
|
|
203
|
-
this.initializeRouteCompiler()
|
|
204
|
-
return this.routeCompiler.getCacheStats()
|
|
205
|
-
},
|
|
206
|
-
writable: true,
|
|
207
|
-
configurable: true,
|
|
208
|
-
},
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Warm up the route cache with common paths
|
|
212
|
-
*/
|
|
213
|
-
warmRouteCache: {
|
|
214
|
-
value(commonPaths: Array<{ path: string, method: HTTPMethod }>) {
|
|
215
|
-
this.initializeRouteCompiler()
|
|
216
|
-
this.routeCompiler.warmCache(commonPaths)
|
|
217
|
-
},
|
|
218
|
-
writable: true,
|
|
219
|
-
configurable: true,
|
|
220
|
-
},
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Get routes grouped by HTTP method for debugging
|
|
224
|
-
*/
|
|
225
|
-
getRoutesByMethod: {
|
|
226
|
-
value() {
|
|
227
|
-
this.initializeRouteCompiler()
|
|
228
|
-
return this.routeCompiler.getRoutesByMethod()
|
|
229
|
-
},
|
|
230
|
-
writable: true,
|
|
231
|
-
configurable: true,
|
|
232
|
-
},
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Get route conflicts for debugging
|
|
236
|
-
*/
|
|
237
|
-
getRouteConflicts: {
|
|
238
|
-
value() {
|
|
239
|
-
this.initializeRouteCompiler()
|
|
240
|
-
return this.routeCompiler.getRouteConflicts()
|
|
241
|
-
},
|
|
242
|
-
writable: true,
|
|
243
|
-
configurable: true,
|
|
244
|
-
},
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Clear route compiler caches
|
|
248
|
-
*/
|
|
249
|
-
clearRouteCache: {
|
|
250
|
-
value() {
|
|
251
|
-
if (this.routeCompiler) {
|
|
252
|
-
this.routeCompiler.clear()
|
|
253
|
-
}
|
|
254
|
-
// Also clear legacy caches
|
|
255
|
-
this.routeCache.clear()
|
|
256
|
-
},
|
|
257
|
-
writable: true,
|
|
258
|
-
configurable: true,
|
|
259
|
-
},
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* Rebuild route compiler with current routes
|
|
263
|
-
*/
|
|
264
|
-
rebuildRouteCompiler: {
|
|
265
|
-
value() {
|
|
266
|
-
this.routeCompiler = new RouteCompiler({
|
|
267
|
-
enableCaching: true,
|
|
268
|
-
enableMethodGrouping: true,
|
|
269
|
-
enablePriorityOptimization: true,
|
|
270
|
-
cacheSize: 1000,
|
|
271
|
-
precompilePatterns: true,
|
|
272
|
-
})
|
|
273
|
-
|
|
274
|
-
// Re-add all routes
|
|
275
|
-
for (const route of this.routes) {
|
|
276
|
-
this.routeCompiler.addRoute(route)
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// Re-add domain-specific routes
|
|
280
|
-
for (const domainRoutes of Object.values(this.domains) as Route[][]) {
|
|
281
|
-
for (const route of domainRoutes) {
|
|
282
|
-
this.routeCompiler.addRoute(route)
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
},
|
|
286
|
-
writable: true,
|
|
287
|
-
configurable: true,
|
|
288
|
-
},
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Optimize route order based on usage patterns
|
|
292
|
-
*/
|
|
293
|
-
optimizeRoutes: {
|
|
294
|
-
value(usageStats: Record<string, number> = {}) {
|
|
295
|
-
this.initializeRouteCompiler()
|
|
296
|
-
this.routeCompiler.optimizeRouteOrder(usageStats)
|
|
297
|
-
},
|
|
298
|
-
writable: true,
|
|
299
|
-
configurable: true,
|
|
300
|
-
},
|
|
301
|
-
})
|
|
302
|
-
}
|
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
import type { Route, RouteDefinition } from '../types'
|
|
2
|
-
import type { Router } from './router'
|
|
3
|
-
import { matchPath } from '../utils'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Route building extension for Router class
|
|
7
|
-
*/
|
|
8
|
-
export function registerRouteBuilding(RouterClass: typeof Router): void {
|
|
9
|
-
Object.defineProperties(RouterClass.prototype, {
|
|
10
|
-
/**
|
|
11
|
-
* Convert existing routes to the Bun.serve routes format
|
|
12
|
-
*/
|
|
13
|
-
buildBunServeRoutes: {
|
|
14
|
-
value(): Record<string, any> {
|
|
15
|
-
const bunRoutes: Record<string, any> = {}
|
|
16
|
-
|
|
17
|
-
// Group routes by path to build method-specific handlers
|
|
18
|
-
const routesByPath = new Map<string, Route[]>()
|
|
19
|
-
|
|
20
|
-
for (const route of this.routes) {
|
|
21
|
-
if (!routesByPath.has(route.path)) {
|
|
22
|
-
routesByPath.set(route.path, [])
|
|
23
|
-
}
|
|
24
|
-
routesByPath.get(route.path)!.push(route)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Build route handlers
|
|
28
|
-
for (const [path, routes] of routesByPath.entries()) {
|
|
29
|
-
if (routes.length === 1) {
|
|
30
|
-
// Single route handler
|
|
31
|
-
const route = routes[0]
|
|
32
|
-
|
|
33
|
-
// For static responses like health checks, use direct Response objects
|
|
34
|
-
if (
|
|
35
|
-
typeof route.handler === 'function'
|
|
36
|
-
&& route.handler.toString().includes('new Response')
|
|
37
|
-
&& !route.handler.toString().includes('await')
|
|
38
|
-
&& route.middleware.length === 0
|
|
39
|
-
) {
|
|
40
|
-
try {
|
|
41
|
-
// Create an enhanced request with empty params and cookie support
|
|
42
|
-
const mockReq = this.enhanceRequest(new Request('https://example.com'), {})
|
|
43
|
-
const testResult = (route.handler as any)(mockReq)
|
|
44
|
-
|
|
45
|
-
// If it returns a Response directly, use it as a static route
|
|
46
|
-
if (testResult instanceof Response) {
|
|
47
|
-
bunRoutes[path] = testResult
|
|
48
|
-
continue
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
catch {
|
|
52
|
-
// If there's an error, fall back to the dynamic handler
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Dynamic route handler
|
|
57
|
-
bunRoutes[path] = async (req: Request) => {
|
|
58
|
-
// Create enhanced request with params
|
|
59
|
-
const url = new URL(req.url)
|
|
60
|
-
const params: Record<string, string> = {}
|
|
61
|
-
const constraintsRecord = route.constraints && !Array.isArray(route.constraints)
|
|
62
|
-
? route.constraints as Record<string, string>
|
|
63
|
-
: undefined
|
|
64
|
-
matchPath(path, url.pathname, params, constraintsRecord)
|
|
65
|
-
const enhancedReq = this.enhanceRequest(req, params)
|
|
66
|
-
|
|
67
|
-
// Treat the route handler as the terminal middleware so the
|
|
68
|
-
// chain reaches it. Previously this code called
|
|
69
|
-
// `runMiddleware(stack)` without the handler and then only
|
|
70
|
-
// called `resolveHandler()` if middlewareResult was falsy.
|
|
71
|
-
// The chain in `buildMiddlewareChain` bottoms out in
|
|
72
|
-
// `return result || new Response(null, { status: 200 })` —
|
|
73
|
-
// so any user middleware that does `await next()` (cors,
|
|
74
|
-
// request-id, auth gates, etc.) gets a truthy empty Response
|
|
75
|
-
// back from the bottom of the chain, returns it, and the
|
|
76
|
-
// outer `if (middlewareResult)` short-circuits before the
|
|
77
|
-
// handler runs. Visible symptom: every route returns
|
|
78
|
-
// `200 OK` with `Content-Length: 0`.
|
|
79
|
-
const routeHandlerMiddleware = async (req2: any, _next: any) =>
|
|
80
|
-
await this.resolveHandler(route.handler, req2)
|
|
81
|
-
const middlewareStack = [...this.globalMiddleware, ...route.middleware, routeHandlerMiddleware]
|
|
82
|
-
const response = await this.runMiddleware(enhancedReq, middlewareStack)
|
|
83
|
-
return this.applyModifiedCookies(
|
|
84
|
-
response ?? new Response('No response from middleware chain', { status: 500 }),
|
|
85
|
-
enhancedReq,
|
|
86
|
-
)
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
else {
|
|
90
|
-
// Multiple routes for same path (method-specific)
|
|
91
|
-
const methodHandlers: Record<string, any> = {}
|
|
92
|
-
|
|
93
|
-
for (const route of routes) {
|
|
94
|
-
const method = route.method
|
|
95
|
-
|
|
96
|
-
methodHandlers[method] = async (req: Request) => {
|
|
97
|
-
// Create enhanced request with params
|
|
98
|
-
const url = new URL(req.url)
|
|
99
|
-
const params: Record<string, string> = {}
|
|
100
|
-
const constraintsRecord = route.constraints && !Array.isArray(route.constraints)
|
|
101
|
-
? route.constraints as Record<string, string>
|
|
102
|
-
: undefined
|
|
103
|
-
matchPath(path, url.pathname, params, constraintsRecord)
|
|
104
|
-
const enhancedReq = this.enhanceRequest(req, params)
|
|
105
|
-
|
|
106
|
-
// See the long comment above the single-method branch:
|
|
107
|
-
// include the route handler as the terminal middleware so
|
|
108
|
-
// the chain reaches it. Without this, any user middleware
|
|
109
|
-
// (cors, request-id) short-circuits to a 200-empty default
|
|
110
|
-
// and the handler never runs.
|
|
111
|
-
const routeHandlerMiddleware = async (req2: any, _next: any) =>
|
|
112
|
-
await this.resolveHandler(route.handler, req2)
|
|
113
|
-
const middlewareStack = [...this.globalMiddleware, ...route.middleware, routeHandlerMiddleware]
|
|
114
|
-
const response = await this.runMiddleware(enhancedReq, middlewareStack)
|
|
115
|
-
return this.applyModifiedCookies(
|
|
116
|
-
response ?? new Response('No response from middleware chain', { status: 500 }),
|
|
117
|
-
enhancedReq,
|
|
118
|
-
)
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
bunRoutes[path] = methodHandlers
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return bunRoutes
|
|
127
|
-
},
|
|
128
|
-
writable: true,
|
|
129
|
-
configurable: true,
|
|
130
|
-
},
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Load routes from files
|
|
134
|
-
*/
|
|
135
|
-
loadRoutes: {
|
|
136
|
-
async value(): Promise<void> {
|
|
137
|
-
if (!this.config.routesPath) {
|
|
138
|
-
return
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
try {
|
|
142
|
-
// Try to import API routes if configured
|
|
143
|
-
if (this.config.apiRoutesPath) {
|
|
144
|
-
try {
|
|
145
|
-
const apiRoutes = await import(this.config.apiRoutesPath)
|
|
146
|
-
if (apiRoutes.default && Array.isArray(apiRoutes.default)) {
|
|
147
|
-
// Register each route
|
|
148
|
-
for (const route of apiRoutes.default) {
|
|
149
|
-
this.registerRoute(route, 'api')
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
catch (error) {
|
|
154
|
-
if (this.config.verbose) {
|
|
155
|
-
console.warn(`Failed to load API routes: ${error}`)
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Try to import Web routes if configured
|
|
161
|
-
if (this.config.webRoutesPath) {
|
|
162
|
-
try {
|
|
163
|
-
const webRoutes = await import(this.config.webRoutesPath)
|
|
164
|
-
if (webRoutes.default && Array.isArray(webRoutes.default)) {
|
|
165
|
-
// Register each route
|
|
166
|
-
for (const route of webRoutes.default) {
|
|
167
|
-
this.registerRoute(route, 'web')
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
catch (error) {
|
|
172
|
-
if (this.config.verbose) {
|
|
173
|
-
console.warn(`Failed to load Web routes: ${error}`)
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
catch (error) {
|
|
179
|
-
console.error('Error loading routes:', error)
|
|
180
|
-
}
|
|
181
|
-
},
|
|
182
|
-
writable: true,
|
|
183
|
-
configurable: true,
|
|
184
|
-
},
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Register a route definition
|
|
188
|
-
*/
|
|
189
|
-
registerRoute: {
|
|
190
|
-
value(route: RouteDefinition, type: 'api' | 'web'): void {
|
|
191
|
-
const { path, method, handler, middleware = [], name } = route
|
|
192
|
-
|
|
193
|
-
// Map HTTP method to Router method
|
|
194
|
-
switch (method) {
|
|
195
|
-
case 'GET':
|
|
196
|
-
this.get(path, handler, type, name, middleware)
|
|
197
|
-
break
|
|
198
|
-
case 'POST':
|
|
199
|
-
this.post(path, handler, type, name, middleware)
|
|
200
|
-
break
|
|
201
|
-
case 'PUT':
|
|
202
|
-
this.put(path, handler, type, name, middleware)
|
|
203
|
-
break
|
|
204
|
-
case 'DELETE':
|
|
205
|
-
this.delete(path, handler, type, name, middleware)
|
|
206
|
-
break
|
|
207
|
-
case 'PATCH':
|
|
208
|
-
this.patch(path, handler, type, name, middleware)
|
|
209
|
-
break
|
|
210
|
-
case 'OPTIONS':
|
|
211
|
-
this.options(path, handler, type, name, middleware)
|
|
212
|
-
break
|
|
213
|
-
default:
|
|
214
|
-
console.warn(`Unsupported HTTP method: ${method}`)
|
|
215
|
-
}
|
|
216
|
-
},
|
|
217
|
-
writable: true,
|
|
218
|
-
configurable: true,
|
|
219
|
-
},
|
|
220
|
-
})
|
|
221
|
-
}
|