@stacksjs/bun-router 0.0.4 → 0.0.6
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 +2 -2
- 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-jhsk5c5b.js +15758 -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 -1
- package/dist/cli.js +2 -2
- 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 +2 -0
- package/dist/index.js +320 -206
- 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 +245 -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 +113 -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 +276 -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 +1776 -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 +18 -4
- 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 +678 -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 +219 -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 +264 -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 +612 -0
- package/src/response/response-factory.ts +588 -0
- package/src/router/api-routes.ts +243 -0
- package/src/router/file-based-routing.ts +670 -0
- package/src/router/file-streaming.ts +372 -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 +185 -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 +212 -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 +1508 -0
- package/src/router/server.ts +406 -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 +2049 -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/dist/chunk-cjdekj87.js +0 -25886
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from '../types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Middleware Group Registry
|
|
5
|
+
*
|
|
6
|
+
* Allows defining named groups of middleware that can be applied to routes.
|
|
7
|
+
* Similar to Laravel's middleware groups (web, api).
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* // Define groups
|
|
11
|
+
* groups.define('web', ['session', 'csrf', 'cors'])
|
|
12
|
+
* groups.define('api', ['throttle:60,1', 'cors'])
|
|
13
|
+
*
|
|
14
|
+
* // Use on routes
|
|
15
|
+
* router.group({ middleware: 'web' }, () => { ... })
|
|
16
|
+
*/
|
|
17
|
+
export class MiddlewareGroupRegistry {
|
|
18
|
+
private groups = new Map<string, (string | MiddlewareHandler)[]>()
|
|
19
|
+
private globalMiddleware: (string | MiddlewareHandler)[] = []
|
|
20
|
+
private middlewarePriority: Map<string, number> = new Map()
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Define a middleware group
|
|
24
|
+
*/
|
|
25
|
+
define(name: string, middleware: (string | MiddlewareHandler)[]): this {
|
|
26
|
+
this.groups.set(name, [...middleware])
|
|
27
|
+
return this
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Extend an existing group with additional middleware
|
|
32
|
+
*/
|
|
33
|
+
extend(name: string, middleware: (string | MiddlewareHandler)[]): this {
|
|
34
|
+
const existing = this.groups.get(name) || []
|
|
35
|
+
this.groups.set(name, [...existing, ...middleware])
|
|
36
|
+
return this
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Prepend middleware to an existing group
|
|
41
|
+
*/
|
|
42
|
+
prepend(name: string, middleware: (string | MiddlewareHandler)[]): this {
|
|
43
|
+
const existing = this.groups.get(name) || []
|
|
44
|
+
this.groups.set(name, [...middleware, ...existing])
|
|
45
|
+
return this
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get middleware for a group
|
|
50
|
+
*/
|
|
51
|
+
get(name: string): (string | MiddlewareHandler)[] {
|
|
52
|
+
return this.groups.get(name) || []
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Check if a group exists
|
|
57
|
+
*/
|
|
58
|
+
has(name: string): boolean {
|
|
59
|
+
return this.groups.has(name)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Remove a group
|
|
64
|
+
*/
|
|
65
|
+
remove(name: string): this {
|
|
66
|
+
this.groups.delete(name)
|
|
67
|
+
return this
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Resolve a middleware reference, expanding group names into their middleware
|
|
72
|
+
*/
|
|
73
|
+
resolve(middleware: string | MiddlewareHandler): (string | MiddlewareHandler)[] {
|
|
74
|
+
if (typeof middleware === 'function') {
|
|
75
|
+
return [middleware]
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Check if it's a group name
|
|
79
|
+
if (this.groups.has(middleware)) {
|
|
80
|
+
return this.get(middleware)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// It's an individual middleware reference
|
|
84
|
+
return [middleware]
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Resolve multiple middleware references, expanding groups
|
|
89
|
+
*/
|
|
90
|
+
resolveAll(middleware: (string | MiddlewareHandler)[]): (string | MiddlewareHandler)[] {
|
|
91
|
+
const resolved: (string | MiddlewareHandler)[] = []
|
|
92
|
+
|
|
93
|
+
for (const mw of middleware) {
|
|
94
|
+
resolved.push(...this.resolve(mw))
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return resolved
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ─── Global Middleware Stack ────────────────────────────────────
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Add middleware to the global stack (runs on every request)
|
|
104
|
+
*/
|
|
105
|
+
pushGlobal(...middleware: (string | MiddlewareHandler)[]): this {
|
|
106
|
+
this.globalMiddleware.push(...middleware)
|
|
107
|
+
return this
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Prepend middleware to the global stack
|
|
112
|
+
*/
|
|
113
|
+
prependGlobal(...middleware: (string | MiddlewareHandler)[]): this {
|
|
114
|
+
this.globalMiddleware.unshift(...middleware)
|
|
115
|
+
return this
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Remove middleware from the global stack
|
|
120
|
+
*/
|
|
121
|
+
removeGlobal(middleware: string): this {
|
|
122
|
+
this.globalMiddleware = this.globalMiddleware.filter(mw =>
|
|
123
|
+
typeof mw === 'string' ? mw !== middleware : true,
|
|
124
|
+
)
|
|
125
|
+
return this
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Get the global middleware stack
|
|
130
|
+
*/
|
|
131
|
+
getGlobal(): (string | MiddlewareHandler)[] {
|
|
132
|
+
return [...this.globalMiddleware]
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ─── Middleware Priority ───────────────────────────────────────
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Set execution priority for a middleware (lower = runs first)
|
|
139
|
+
*/
|
|
140
|
+
setPriority(name: string, priority: number): this {
|
|
141
|
+
this.middlewarePriority.set(name, priority)
|
|
142
|
+
return this
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Sort middleware by priority
|
|
147
|
+
*/
|
|
148
|
+
sortByPriority(middleware: (string | MiddlewareHandler)[]): (string | MiddlewareHandler)[] {
|
|
149
|
+
return [...middleware].sort((a, b) => {
|
|
150
|
+
const nameA = typeof a === 'string' ? a.split(':')[0] : ''
|
|
151
|
+
const nameB = typeof b === 'string' ? b.split(':')[0] : ''
|
|
152
|
+
const priorityA = this.middlewarePriority.get(nameA) ?? 100
|
|
153
|
+
const priorityB = this.middlewarePriority.get(nameB) ?? 100
|
|
154
|
+
return priorityA - priorityB
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ─── Route-Level Exclusions ────────────────────────────────────
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Filter middleware by applying except/only rules.
|
|
162
|
+
*
|
|
163
|
+
* @param middleware - Full middleware list
|
|
164
|
+
* @param options - except or only filter
|
|
165
|
+
*/
|
|
166
|
+
filter(
|
|
167
|
+
middleware: (string | MiddlewareHandler)[],
|
|
168
|
+
options: { except?: string[], only?: string[] },
|
|
169
|
+
): (string | MiddlewareHandler)[] {
|
|
170
|
+
if (options.only && options.only.length > 0) {
|
|
171
|
+
return middleware.filter((mw) => {
|
|
172
|
+
if (typeof mw === 'string') {
|
|
173
|
+
const name = mw.split(':')[0]
|
|
174
|
+
return options.only!.includes(name)
|
|
175
|
+
}
|
|
176
|
+
return false
|
|
177
|
+
})
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (options.except && options.except.length > 0) {
|
|
181
|
+
return middleware.filter((mw) => {
|
|
182
|
+
if (typeof mw === 'string') {
|
|
183
|
+
const name = mw.split(':')[0]
|
|
184
|
+
return !options.except!.includes(name)
|
|
185
|
+
}
|
|
186
|
+
return true // Keep function middleware when using except
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return middleware
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Clear all groups and global middleware
|
|
195
|
+
*/
|
|
196
|
+
flush(): void {
|
|
197
|
+
this.groups.clear()
|
|
198
|
+
this.globalMiddleware = []
|
|
199
|
+
this.middlewarePriority.clear()
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Default middleware group registry instance
|
|
205
|
+
*/
|
|
206
|
+
export const middlewareGroups: MiddlewareGroupRegistry = new MiddlewareGroupRegistry()
|
|
207
|
+
|
|
208
|
+
// Pre-define common groups
|
|
209
|
+
middlewareGroups.define('web', ['session', 'csrf', 'cors'])
|
|
210
|
+
middlewareGroups.define('api', ['throttle:60,1', 'cors'])
|
|
211
|
+
|
|
212
|
+
// Set default priorities (lower = runs first)
|
|
213
|
+
middlewareGroups.setPriority('session', 10)
|
|
214
|
+
middlewareGroups.setPriority('cors', 20)
|
|
215
|
+
middlewareGroups.setPriority('csrf', 30)
|
|
216
|
+
middlewareGroups.setPriority('auth', 40)
|
|
217
|
+
middlewareGroups.setPriority('throttle', 50)
|
|
218
|
+
middlewareGroups.setPriority('role', 60)
|
|
219
|
+
middlewareGroups.setPriority('permission', 60)
|
|
220
|
+
middlewareGroups.setPriority('can', 70)
|
|
221
|
+
middlewareGroups.setPriority('abilities', 70)
|
|
222
|
+
middlewareGroups.setPriority('verified', 80)
|
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
import type { EnhancedRequest, MiddlewareHandler, Route } from '../types'
|
|
2
|
+
import type { Router } from './router'
|
|
3
|
+
|
|
4
|
+
// Type placeholders for middleware pipeline
|
|
5
|
+
export type SkipConditionFn = (_req: EnhancedRequest) => boolean
|
|
6
|
+
export type SkipConditionsList = SkipConditionFn[]
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Skip condition helpers
|
|
10
|
+
*/
|
|
11
|
+
export const SkipConditions = {
|
|
12
|
+
skipForPaths: (paths: string[]): SkipConditionFn => (req: EnhancedRequest) => {
|
|
13
|
+
const url = new URL(req.url)
|
|
14
|
+
return paths.some(path => url.pathname.startsWith(path))
|
|
15
|
+
},
|
|
16
|
+
skipForMethods: (methods: string[]): SkipConditionFn => (req: EnhancedRequest) => {
|
|
17
|
+
return methods.includes(req.method)
|
|
18
|
+
},
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Dependency helpers
|
|
23
|
+
*/
|
|
24
|
+
export const Dependencies = {
|
|
25
|
+
cache: (config: { type: string, ttl: number }): { type: string, config: { type: string, ttl: number } } => ({
|
|
26
|
+
type: 'cache',
|
|
27
|
+
config,
|
|
28
|
+
}),
|
|
29
|
+
logger: (level: string): { type: string, config: { level: string } } => ({
|
|
30
|
+
type: 'logger',
|
|
31
|
+
config: { level },
|
|
32
|
+
}),
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
class MiddlewarePipeline {
|
|
36
|
+
registerDependency(_key: string, _dependency: any): this { return this }
|
|
37
|
+
registerSkipConditions(_middleware: MiddlewareHandler, _conditions: SkipConditionsList): void {}
|
|
38
|
+
getStats(): any { return {} }
|
|
39
|
+
getCacheInfo(): any { return {} }
|
|
40
|
+
clearCache(): this { return this }
|
|
41
|
+
compilePipeline(_key: string, _middleware: MiddlewareHandler[], _options?: any): void {}
|
|
42
|
+
execute(_key: string, _req: EnhancedRequest, _handler: () => Promise<Response>): Promise<Response> { return _handler() }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Integration layer for middleware pipeline with the router
|
|
47
|
+
*/
|
|
48
|
+
export function registerMiddlewarePipeline(RouterClass: typeof Router): void {
|
|
49
|
+
// Add pipeline instance to router prototype
|
|
50
|
+
Object.defineProperty(RouterClass.prototype, '_middlewarePipeline', {
|
|
51
|
+
value: new MiddlewarePipeline(),
|
|
52
|
+
writable: false,
|
|
53
|
+
enumerable: false,
|
|
54
|
+
configurable: false,
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
// Override the addRoute method to compile middleware pipelines
|
|
58
|
+
const originalAddRoute = RouterClass.prototype.addRoute
|
|
59
|
+
RouterClass.prototype.addRoute = function (route: Route) {
|
|
60
|
+
// Call original addRoute
|
|
61
|
+
const result = originalAddRoute.call(this, route)
|
|
62
|
+
|
|
63
|
+
// Compile middleware pipeline for this route
|
|
64
|
+
const routeKey = `${route.method}:${route.path}`
|
|
65
|
+
if (route.middleware && route.middleware.length > 0 && this._middlewarePipeline) {
|
|
66
|
+
this._middlewarePipeline.compileMiddleware(routeKey, route.middleware)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return result
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Middleware factory for common use cases
|
|
75
|
+
*/
|
|
76
|
+
export class MiddlewareFactory {
|
|
77
|
+
private pipeline: MiddlewarePipeline
|
|
78
|
+
|
|
79
|
+
constructor(pipeline: MiddlewarePipeline) {
|
|
80
|
+
this.pipeline = pipeline
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Create authentication middleware with conditional execution
|
|
85
|
+
*/
|
|
86
|
+
createAuthMiddleware(options: {
|
|
87
|
+
skipPaths?: string[]
|
|
88
|
+
skipMethods?: string[]
|
|
89
|
+
requireRoles?: string[]
|
|
90
|
+
jwtSecret?: string
|
|
91
|
+
} = {}): MiddlewareHandler {
|
|
92
|
+
const middleware: MiddlewareHandler = async (req, next) => {
|
|
93
|
+
// Skip authentication for public paths
|
|
94
|
+
if (options.skipPaths) {
|
|
95
|
+
const url = new URL(req.url)
|
|
96
|
+
if (options.skipPaths.some(path => url.pathname.startsWith(path))) {
|
|
97
|
+
return next()
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Extract JWT token
|
|
102
|
+
const authHeader = req.headers.get('Authorization')
|
|
103
|
+
if (!authHeader?.startsWith('Bearer ')) {
|
|
104
|
+
return new Response('Unauthorized', { status: 401 })
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const _token = authHeader.slice(7)
|
|
108
|
+
|
|
109
|
+
// In a real implementation, this would verify the JWT
|
|
110
|
+
// For demo purposes, we'll simulate user extraction
|
|
111
|
+
try {
|
|
112
|
+
// Simulate JWT verification
|
|
113
|
+
const user = {
|
|
114
|
+
id: 1,
|
|
115
|
+
name: 'John Doe',
|
|
116
|
+
roles: ['user'],
|
|
117
|
+
// In real implementation: jwt.verify(token, options.jwtSecret)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Check required roles
|
|
121
|
+
if (options.requireRoles && options.requireRoles.length > 0) {
|
|
122
|
+
const hasRequiredRole = options.requireRoles.some(role =>
|
|
123
|
+
user.roles.includes(role),
|
|
124
|
+
)
|
|
125
|
+
if (!hasRequiredRole) {
|
|
126
|
+
return new Response('Forbidden', { status: 403 })
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
req.user = user
|
|
131
|
+
return next()
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
console.error(error)
|
|
135
|
+
return new Response('Invalid token', { status: 401 })
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
Object.defineProperty(middleware, 'name', { value: 'auth' })
|
|
140
|
+
|
|
141
|
+
// Register skip conditions
|
|
142
|
+
const skipConditions = []
|
|
143
|
+
if (options.skipPaths) {
|
|
144
|
+
skipConditions.push(SkipConditions.skipForPaths(options.skipPaths))
|
|
145
|
+
}
|
|
146
|
+
if (options.skipMethods) {
|
|
147
|
+
skipConditions.push(SkipConditions.skipForMethods(options.skipMethods))
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (skipConditions.length > 0) {
|
|
151
|
+
this.pipeline.registerSkipConditions(middleware, skipConditions)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return middleware
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Create rate limiting middleware with dependency injection
|
|
159
|
+
*/
|
|
160
|
+
createRateLimitMiddleware(options: {
|
|
161
|
+
maxRequests: number
|
|
162
|
+
windowMs: number
|
|
163
|
+
skipPaths?: string[]
|
|
164
|
+
}): MiddlewareHandler {
|
|
165
|
+
// Register cache dependency for rate limiting
|
|
166
|
+
this.pipeline.registerDependency('cache', Dependencies.cache({
|
|
167
|
+
type: 'memory',
|
|
168
|
+
ttl: Math.ceil(options.windowMs / 1000),
|
|
169
|
+
}))
|
|
170
|
+
|
|
171
|
+
interface RateLimitEntry {
|
|
172
|
+
count: number
|
|
173
|
+
resetTime: number
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const middleware: MiddlewareHandler = async (req, next) => {
|
|
177
|
+
const cache = req.context?.cache
|
|
178
|
+
if (!cache) {
|
|
179
|
+
// Fallback if cache not available
|
|
180
|
+
return next()
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const clientId = req.ip || req.headers.get('x-forwarded-for') || 'unknown'
|
|
184
|
+
const key = `rate_limit:${clientId}`
|
|
185
|
+
|
|
186
|
+
const current: RateLimitEntry = cache.get<RateLimitEntry>(key) || { count: 0, resetTime: Date.now() + options.windowMs }
|
|
187
|
+
|
|
188
|
+
if (Date.now() > current.resetTime) {
|
|
189
|
+
current.count = 0
|
|
190
|
+
current.resetTime = Date.now() + options.windowMs
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (current.count >= options.maxRequests) {
|
|
194
|
+
return new Response('Too Many Requests', {
|
|
195
|
+
status: 429,
|
|
196
|
+
headers: {
|
|
197
|
+
'Retry-After': Math.ceil((current.resetTime - Date.now()) / 1000).toString(),
|
|
198
|
+
},
|
|
199
|
+
})
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
current.count++
|
|
203
|
+
cache.set(key, current)
|
|
204
|
+
|
|
205
|
+
return next()
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
Object.defineProperty(middleware, 'name', { value: 'rateLimit' })
|
|
209
|
+
|
|
210
|
+
// Register skip conditions
|
|
211
|
+
if (options.skipPaths) {
|
|
212
|
+
this.pipeline.registerSkipConditions(middleware, [
|
|
213
|
+
SkipConditions.skipForPaths(options.skipPaths),
|
|
214
|
+
])
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return middleware
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Create logging middleware with dependency injection
|
|
222
|
+
*/
|
|
223
|
+
createLoggingMiddleware(options: {
|
|
224
|
+
level?: string
|
|
225
|
+
skipPaths?: string[]
|
|
226
|
+
includeBody?: boolean
|
|
227
|
+
} = {}): MiddlewareHandler {
|
|
228
|
+
// Register logger dependency
|
|
229
|
+
this.pipeline.registerDependency('logger', Dependencies.logger(options.level || 'info'))
|
|
230
|
+
|
|
231
|
+
const middleware: MiddlewareHandler = async (req, next) => {
|
|
232
|
+
const logger = req.context?.logger
|
|
233
|
+
const startTime = Date.now()
|
|
234
|
+
|
|
235
|
+
// Generate request ID
|
|
236
|
+
const requestId = Math.random().toString(36).substr(2, 9)
|
|
237
|
+
req.requestId = requestId
|
|
238
|
+
|
|
239
|
+
if (logger) {
|
|
240
|
+
logger.log(`[${requestId}] ${req.method} ${req.url} - Started`)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
const response = await next()
|
|
245
|
+
const duration = Date.now() - startTime
|
|
246
|
+
|
|
247
|
+
if (logger && response) {
|
|
248
|
+
logger.log(`[${requestId}] ${req.method} ${req.url} - ${response.status} (${duration}ms)`)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return response
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
const duration = Date.now() - startTime
|
|
255
|
+
if (logger) {
|
|
256
|
+
logger.error(`[${requestId}] ${req.method} ${req.url} - Error: ${error} (${duration}ms)`)
|
|
257
|
+
}
|
|
258
|
+
throw error
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
Object.defineProperty(middleware, 'name', { value: 'logging' })
|
|
263
|
+
|
|
264
|
+
// Register skip conditions
|
|
265
|
+
if (options.skipPaths) {
|
|
266
|
+
this.pipeline.registerSkipConditions(middleware, [
|
|
267
|
+
SkipConditions.skipForPaths(options.skipPaths),
|
|
268
|
+
])
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return middleware
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Create CORS middleware with conditional execution
|
|
276
|
+
*/
|
|
277
|
+
createCorsMiddleware(options: {
|
|
278
|
+
origin?: string | string[]
|
|
279
|
+
methods?: string[]
|
|
280
|
+
allowedHeaders?: string[]
|
|
281
|
+
credentials?: boolean
|
|
282
|
+
} = {}): MiddlewareHandler {
|
|
283
|
+
const middleware: MiddlewareHandler = async (req, next) => {
|
|
284
|
+
const origin = req.headers.get('Origin')
|
|
285
|
+
const method = req.method
|
|
286
|
+
|
|
287
|
+
// Handle preflight requests
|
|
288
|
+
if (method === 'OPTIONS') {
|
|
289
|
+
const headers = new Headers()
|
|
290
|
+
|
|
291
|
+
if (options.origin) {
|
|
292
|
+
if (Array.isArray(options.origin)) {
|
|
293
|
+
if (origin && options.origin.includes(origin)) {
|
|
294
|
+
headers.set('Access-Control-Allow-Origin', origin)
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
else if (options.origin === '*' || options.origin === origin) {
|
|
298
|
+
headers.set('Access-Control-Allow-Origin', options.origin)
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (options.methods) {
|
|
303
|
+
headers.set('Access-Control-Allow-Methods', options.methods.join(', '))
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (options.allowedHeaders) {
|
|
307
|
+
headers.set('Access-Control-Allow-Headers', options.allowedHeaders.join(', '))
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (options.credentials) {
|
|
311
|
+
headers.set('Access-Control-Allow-Credentials', 'true')
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return new Response(null, { status: 204, headers })
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Handle actual requests
|
|
318
|
+
const response = await next()
|
|
319
|
+
if (response && options.origin && origin) {
|
|
320
|
+
const newHeaders = new Headers(response.headers)
|
|
321
|
+
|
|
322
|
+
if (Array.isArray(options.origin)) {
|
|
323
|
+
if (options.origin.includes(origin)) {
|
|
324
|
+
newHeaders.set('Access-Control-Allow-Origin', origin)
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
else if (options.origin === '*' || options.origin === origin) {
|
|
328
|
+
newHeaders.set('Access-Control-Allow-Origin', options.origin)
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (options.credentials) {
|
|
332
|
+
newHeaders.set('Access-Control-Allow-Credentials', 'true')
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return new Response(response.body, {
|
|
336
|
+
status: response.status,
|
|
337
|
+
statusText: response.statusText,
|
|
338
|
+
headers: newHeaders,
|
|
339
|
+
})
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return response
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
Object.defineProperty(middleware, 'name', { value: 'cors' })
|
|
346
|
+
return middleware
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Helper function to setup common middleware stack
|
|
352
|
+
*/
|
|
353
|
+
export function setupMiddlewareStack(router: any, options: {
|
|
354
|
+
auth?: {
|
|
355
|
+
jwtSecret: string
|
|
356
|
+
skipPaths?: string[]
|
|
357
|
+
requireRoles?: string[]
|
|
358
|
+
}
|
|
359
|
+
rateLimit?: {
|
|
360
|
+
maxRequests: number
|
|
361
|
+
windowMs: number
|
|
362
|
+
skipPaths?: string[]
|
|
363
|
+
}
|
|
364
|
+
cors?: {
|
|
365
|
+
origin?: string | string[]
|
|
366
|
+
methods?: string[]
|
|
367
|
+
allowedHeaders?: string[]
|
|
368
|
+
credentials?: boolean
|
|
369
|
+
}
|
|
370
|
+
logging?: {
|
|
371
|
+
level?: string
|
|
372
|
+
skipPaths?: string[]
|
|
373
|
+
}
|
|
374
|
+
} = {}): MiddlewareHandler[] {
|
|
375
|
+
const factory = new MiddlewareFactory(router._middlewarePipeline)
|
|
376
|
+
const middleware: MiddlewareHandler[] = []
|
|
377
|
+
|
|
378
|
+
// Add CORS middleware first
|
|
379
|
+
if (options.cors) {
|
|
380
|
+
middleware.push(factory.createCorsMiddleware(options.cors))
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Add logging middleware
|
|
384
|
+
if (options.logging !== undefined) {
|
|
385
|
+
middleware.push(factory.createLoggingMiddleware(options.logging))
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Add rate limiting middleware
|
|
389
|
+
if (options.rateLimit) {
|
|
390
|
+
middleware.push(factory.createRateLimitMiddleware(options.rateLimit))
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// Add authentication middleware
|
|
394
|
+
if (options.auth) {
|
|
395
|
+
middleware.push(factory.createAuthMiddleware(options.auth))
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return middleware
|
|
399
|
+
}
|