@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,688 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request/Response Enhancements - Request Macros
|
|
3
|
+
*
|
|
4
|
+
* Laravel-style request macros for enhanced request functionality
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { EnhancedRequest } from '../types'
|
|
8
|
+
|
|
9
|
+
export interface RequestMacro {
|
|
10
|
+
name: string
|
|
11
|
+
handler: (this: EnhancedRequest, ...args: any[]) => any
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Request macro registry
|
|
16
|
+
*/
|
|
17
|
+
class RequestMacroRegistry {
|
|
18
|
+
private macros: Map<string, RequestMacro> = new Map()
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Register a request macro
|
|
22
|
+
*/
|
|
23
|
+
register(name: string, handler: (this: EnhancedRequest, ...args: any[]) => any): void {
|
|
24
|
+
this.macros.set(name, { name, handler })
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get a registered macro
|
|
29
|
+
*/
|
|
30
|
+
get(name: string): RequestMacro | undefined {
|
|
31
|
+
return this.macros.get(name)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Check if macro exists
|
|
36
|
+
*/
|
|
37
|
+
has(name: string): boolean {
|
|
38
|
+
return this.macros.has(name)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Get all registered macros
|
|
43
|
+
*/
|
|
44
|
+
all(): RequestMacro[] {
|
|
45
|
+
return Array.from(this.macros.values())
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Remove a macro
|
|
50
|
+
*/
|
|
51
|
+
remove(name: string): boolean {
|
|
52
|
+
return this.macros.delete(name)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Clear all macros
|
|
57
|
+
*/
|
|
58
|
+
clear(): void {
|
|
59
|
+
this.macros.clear()
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Global request macro registry
|
|
65
|
+
*/
|
|
66
|
+
export const requestMacroRegistry: RequestMacroRegistry = new RequestMacroRegistry()
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Request class with macro support
|
|
70
|
+
*/
|
|
71
|
+
export class RequestWithMacros {
|
|
72
|
+
/**
|
|
73
|
+
* Register a request macro
|
|
74
|
+
*/
|
|
75
|
+
static macro(name: string, handler: (this: EnhancedRequest, ...args: any[]) => any): void {
|
|
76
|
+
requestMacroRegistry.register(name, handler)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Apply macros to a request object
|
|
81
|
+
*/
|
|
82
|
+
static applyMacros(request: EnhancedRequest): EnhancedRequest {
|
|
83
|
+
const macros = requestMacroRegistry.all()
|
|
84
|
+
|
|
85
|
+
macros.forEach((macro) => {
|
|
86
|
+
;(request as any)[macro.name] = macro.handler.bind(request)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
return request
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Check if macro exists
|
|
94
|
+
*/
|
|
95
|
+
static hasMacro(name: string): boolean {
|
|
96
|
+
return requestMacroRegistry.has(name)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Built-in request macros
|
|
102
|
+
*/
|
|
103
|
+
export const BuiltInRequestMacros = {
|
|
104
|
+
/**
|
|
105
|
+
* Check if request wants JSON response
|
|
106
|
+
*/
|
|
107
|
+
wantsJson(this: EnhancedRequest): boolean {
|
|
108
|
+
const accept = this.headers.get('accept') || ''
|
|
109
|
+
return accept.includes('application/json') || accept.includes('json')
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Check if request wants HTML response
|
|
114
|
+
*/
|
|
115
|
+
wantsHtml(this: EnhancedRequest): boolean {
|
|
116
|
+
const accept = this.headers.get('accept') || ''
|
|
117
|
+
return accept.includes('text/html') || accept.includes('html')
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Check if request wants XML response
|
|
122
|
+
*/
|
|
123
|
+
wantsXml(this: EnhancedRequest): boolean {
|
|
124
|
+
const accept = this.headers.get('accept') || ''
|
|
125
|
+
return accept.includes('application/xml') || accept.includes('xml')
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Check if request expects JSON response
|
|
130
|
+
*/
|
|
131
|
+
expectsJson(this: EnhancedRequest): boolean {
|
|
132
|
+
return this.wantsJson() || this.isAjax() || this.isPjax()
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Check if request is AJAX
|
|
137
|
+
*/
|
|
138
|
+
isAjax(this: EnhancedRequest): boolean {
|
|
139
|
+
return this.headers.get('x-requested-with') === 'XMLHttpRequest'
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Check if request is PJAX
|
|
144
|
+
*/
|
|
145
|
+
isPjax(this: EnhancedRequest): boolean {
|
|
146
|
+
return this.headers.get('x-pjax') === 'true'
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Check if request is from mobile device
|
|
151
|
+
*/
|
|
152
|
+
isMobile(this: EnhancedRequest): boolean {
|
|
153
|
+
const userAgent = this.headers.get('user-agent') || ''
|
|
154
|
+
const mobileRegex = /Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i
|
|
155
|
+
return mobileRegex.test(userAgent)
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Check if request is from bot/crawler
|
|
160
|
+
*/
|
|
161
|
+
isBot(this: EnhancedRequest): boolean {
|
|
162
|
+
const userAgent = this.headers.get('user-agent') || ''
|
|
163
|
+
const botRegex = /bot|crawler|spider|crawling/i
|
|
164
|
+
return botRegex.test(userAgent)
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Check if request is secure (HTTPS)
|
|
169
|
+
*/
|
|
170
|
+
isSecure(this: EnhancedRequest): boolean {
|
|
171
|
+
return this.url.startsWith('https://')
|
|
172
|
+
|| this.headers.get('x-forwarded-proto') === 'https'
|
|
173
|
+
|| this.headers.get('x-forwarded-ssl') === 'on'
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Get client IP address
|
|
178
|
+
*/
|
|
179
|
+
ip(this: EnhancedRequest): string {
|
|
180
|
+
return this.headers.get('x-forwarded-for')?.split(',')[0]?.trim()
|
|
181
|
+
|| this.headers.get('x-real-ip')
|
|
182
|
+
|| this.headers.get('cf-connecting-ip')
|
|
183
|
+
|| this.headers.get('x-client-ip')
|
|
184
|
+
|| 'unknown'
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Get all client IPs (including proxies)
|
|
189
|
+
*/
|
|
190
|
+
ips(this: EnhancedRequest): string[] {
|
|
191
|
+
const forwardedFor = this.headers.get('x-forwarded-for')
|
|
192
|
+
if (forwardedFor) {
|
|
193
|
+
return forwardedFor.split(',').map(ip => ip.trim())
|
|
194
|
+
}
|
|
195
|
+
return [BuiltInRequestMacros.ip.call(this)]
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Get user agent
|
|
200
|
+
*/
|
|
201
|
+
userAgent(this: EnhancedRequest): string {
|
|
202
|
+
return this.headers.get('user-agent') || ''
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Get referer URL
|
|
207
|
+
*/
|
|
208
|
+
referer(this: EnhancedRequest): string | null {
|
|
209
|
+
return this.headers.get('referer') || this.headers.get('referrer') || null
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Get authorization header
|
|
214
|
+
*/
|
|
215
|
+
bearerToken(this: EnhancedRequest): string | null {
|
|
216
|
+
const auth = this.headers.get('authorization')
|
|
217
|
+
if (auth && auth.startsWith('Bearer ')) {
|
|
218
|
+
return auth.substring(7)
|
|
219
|
+
}
|
|
220
|
+
return null
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Get basic auth credentials
|
|
225
|
+
*/
|
|
226
|
+
basicAuth(this: EnhancedRequest): { username: string, password: string } | null {
|
|
227
|
+
const auth = this.headers.get('authorization')
|
|
228
|
+
if (auth && auth.startsWith('Basic ')) {
|
|
229
|
+
try {
|
|
230
|
+
const decoded = atob(auth.substring(6))
|
|
231
|
+
const [username, password] = decoded.split(':')
|
|
232
|
+
return { username, password }
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
return null
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return null
|
|
239
|
+
},
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Check if request has specific header
|
|
243
|
+
*/
|
|
244
|
+
hasHeader(this: EnhancedRequest, name: string): boolean {
|
|
245
|
+
return this.headers.has(name.toLowerCase())
|
|
246
|
+
},
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Get header value with default
|
|
250
|
+
*/
|
|
251
|
+
header(this: EnhancedRequest, name: string, defaultValue?: string): string | null {
|
|
252
|
+
return this.headers.get(name.toLowerCase()) || defaultValue || null
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Get all headers as object
|
|
257
|
+
*/
|
|
258
|
+
allHeaders(this: EnhancedRequest): Record<string, string> {
|
|
259
|
+
const headers: Record<string, string> = {}
|
|
260
|
+
this.headers.forEach((value, key) => {
|
|
261
|
+
headers[key] = value
|
|
262
|
+
})
|
|
263
|
+
return headers
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Get input value from query, body, or params
|
|
268
|
+
*/
|
|
269
|
+
input(this: EnhancedRequest, key: string, defaultValue?: any): any {
|
|
270
|
+
// Check validated data first
|
|
271
|
+
if (this.validated && key in this.validated) {
|
|
272
|
+
return this.validated[key]
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Check query parameters
|
|
276
|
+
if (this.query && key in this.query) {
|
|
277
|
+
return this.query[key]
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Check route parameters
|
|
281
|
+
if (this.params && key in this.params) {
|
|
282
|
+
return this.params[key]
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Check JSON body
|
|
286
|
+
if (this.jsonBody && typeof this.jsonBody === 'object' && key in this.jsonBody) {
|
|
287
|
+
return (this.jsonBody as Record<string, unknown>)[key]
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Check form body
|
|
291
|
+
if (this.formBody && typeof this.formBody === 'object' && key in this.formBody) {
|
|
292
|
+
return (this.formBody as Record<string, unknown>)[key]
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return defaultValue
|
|
296
|
+
},
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Get all input data
|
|
300
|
+
*/
|
|
301
|
+
all(this: EnhancedRequest): Record<string, unknown> {
|
|
302
|
+
return {
|
|
303
|
+
...this.params,
|
|
304
|
+
...this.query,
|
|
305
|
+
...(typeof this.jsonBody === 'object' && this.jsonBody !== null ? this.jsonBody : {}),
|
|
306
|
+
...(typeof this.formBody === 'object' && this.formBody !== null ? this.formBody : {}),
|
|
307
|
+
...(typeof this.validated === 'object' && this.validated !== null ? this.validated : {}),
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Get only specified input keys
|
|
313
|
+
*/
|
|
314
|
+
only(this: EnhancedRequest, keys: string[]): Record<string, any> {
|
|
315
|
+
const all = this.all()
|
|
316
|
+
const result: Record<string, any> = {}
|
|
317
|
+
|
|
318
|
+
keys.forEach((key) => {
|
|
319
|
+
if (key in all) {
|
|
320
|
+
result[key] = all[key]
|
|
321
|
+
}
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
return result
|
|
325
|
+
},
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Get all input except specified keys
|
|
329
|
+
*/
|
|
330
|
+
except(this: EnhancedRequest, keys: string[]): Record<string, any> {
|
|
331
|
+
const all = this.all()
|
|
332
|
+
const result: Record<string, any> = {}
|
|
333
|
+
|
|
334
|
+
Object.keys(all).forEach((key) => {
|
|
335
|
+
if (!keys.includes(key)) {
|
|
336
|
+
result[key] = all[key]
|
|
337
|
+
}
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
return result
|
|
341
|
+
},
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Check if input has specific key
|
|
345
|
+
*/
|
|
346
|
+
has(this: EnhancedRequest, key: string): boolean {
|
|
347
|
+
const all = this.all()
|
|
348
|
+
return key in all && all[key] !== undefined && all[key] !== null && all[key] !== ''
|
|
349
|
+
},
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Check if input has any of the specified keys
|
|
353
|
+
*/
|
|
354
|
+
hasAny(this: EnhancedRequest, keys: string[]): boolean {
|
|
355
|
+
return keys.some(key => this.has(key))
|
|
356
|
+
},
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Check if input is missing specific key
|
|
360
|
+
*/
|
|
361
|
+
missing(this: EnhancedRequest, key: string): boolean {
|
|
362
|
+
return !this.has(key)
|
|
363
|
+
},
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Check if input is filled (not empty)
|
|
367
|
+
*/
|
|
368
|
+
filled(this: EnhancedRequest, key: string): boolean {
|
|
369
|
+
const value = this.input(key)
|
|
370
|
+
if (value === null || value === undefined)
|
|
371
|
+
return false
|
|
372
|
+
if (typeof value === 'string')
|
|
373
|
+
return value.trim().length > 0
|
|
374
|
+
if (Array.isArray(value))
|
|
375
|
+
return value.length > 0
|
|
376
|
+
if (typeof value === 'object')
|
|
377
|
+
return Object.keys(value).length > 0
|
|
378
|
+
return true
|
|
379
|
+
},
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Get query parameter
|
|
383
|
+
*/
|
|
384
|
+
getQuery(this: EnhancedRequest, key?: string, defaultValue?: any): any {
|
|
385
|
+
if (!key)
|
|
386
|
+
return this.query || {}
|
|
387
|
+
return this.query?.[key] || defaultValue
|
|
388
|
+
},
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Get route parameter
|
|
392
|
+
*/
|
|
393
|
+
param(this: EnhancedRequest, key: string, defaultValue?: any): any {
|
|
394
|
+
return this.params?.[key] || defaultValue
|
|
395
|
+
},
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Get cookie value
|
|
399
|
+
*/
|
|
400
|
+
cookie(this: EnhancedRequest, name: string, defaultValue?: string): string | null {
|
|
401
|
+
const cookies = this.headers.get('cookie')
|
|
402
|
+
if (!cookies)
|
|
403
|
+
return defaultValue || null
|
|
404
|
+
|
|
405
|
+
const cookieArray = cookies.split(';')
|
|
406
|
+
for (const cookie of cookieArray) {
|
|
407
|
+
const [key, value] = cookie.trim().split('=')
|
|
408
|
+
if (key === name) {
|
|
409
|
+
return decodeURIComponent(value)
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return defaultValue || null
|
|
414
|
+
},
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Get all cookies
|
|
418
|
+
*/
|
|
419
|
+
cookies(this: EnhancedRequest): Record<string, string> {
|
|
420
|
+
const cookies: Record<string, string> = {}
|
|
421
|
+
const cookieHeader = this.headers.get('cookie')
|
|
422
|
+
|
|
423
|
+
if (cookieHeader) {
|
|
424
|
+
cookieHeader.split(';').forEach((cookie) => {
|
|
425
|
+
const [key, value] = cookie.trim().split('=')
|
|
426
|
+
if (key && value) {
|
|
427
|
+
cookies[key] = decodeURIComponent(value)
|
|
428
|
+
}
|
|
429
|
+
})
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
return cookies
|
|
433
|
+
},
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Get file from upload
|
|
437
|
+
*/
|
|
438
|
+
file(this: EnhancedRequest, name: string): any {
|
|
439
|
+
return this.files?.find(f => f.fieldName === name)
|
|
440
|
+
},
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Check if request has file upload
|
|
444
|
+
*/
|
|
445
|
+
hasFile(this: EnhancedRequest, name: string): boolean {
|
|
446
|
+
return !!this.files?.find(f => f.fieldName === name)
|
|
447
|
+
},
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Get request path without query string
|
|
451
|
+
*/
|
|
452
|
+
path(this: EnhancedRequest): string {
|
|
453
|
+
return new URL(this.url).pathname
|
|
454
|
+
},
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Get request URL
|
|
458
|
+
*/
|
|
459
|
+
fullUrl(this: EnhancedRequest): string {
|
|
460
|
+
return this.url
|
|
461
|
+
},
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Get request root URL
|
|
465
|
+
*/
|
|
466
|
+
root(this: EnhancedRequest): string {
|
|
467
|
+
const url = new URL(this.url)
|
|
468
|
+
return `${url.protocol}//${url.host}`
|
|
469
|
+
},
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Check if path matches pattern
|
|
473
|
+
*/
|
|
474
|
+
is(this: EnhancedRequest, pattern: string): boolean {
|
|
475
|
+
const path = this.path()
|
|
476
|
+
|
|
477
|
+
// Convert pattern to regex
|
|
478
|
+
const regexPattern = pattern
|
|
479
|
+
.replace(/\*/g, '.*')
|
|
480
|
+
.replace(/\?/g, '.')
|
|
481
|
+
|
|
482
|
+
const regex = new RegExp(`^${regexPattern}$`)
|
|
483
|
+
return regex.test(path)
|
|
484
|
+
},
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Get route name (if available)
|
|
488
|
+
*/
|
|
489
|
+
route(this: EnhancedRequest): string | null {
|
|
490
|
+
return (this as any).routeName || null
|
|
491
|
+
},
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Get request fingerprint for caching
|
|
495
|
+
*/
|
|
496
|
+
fingerprint(this: EnhancedRequest): string {
|
|
497
|
+
const url = new URL(this.url)
|
|
498
|
+
const data = {
|
|
499
|
+
method: this.method,
|
|
500
|
+
path: url.pathname,
|
|
501
|
+
query: url.search,
|
|
502
|
+
ip: BuiltInRequestMacros.ip.call(this),
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
return btoa(JSON.stringify(data))
|
|
506
|
+
},
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Get request signature for security
|
|
510
|
+
*/
|
|
511
|
+
signature(this: EnhancedRequest, secret: string): string {
|
|
512
|
+
const data = `${this.method}${this.url}${BuiltInRequestMacros.ip.call(this)}${secret}`
|
|
513
|
+
|
|
514
|
+
// Simple hash function (in production, use crypto)
|
|
515
|
+
let hash = 0
|
|
516
|
+
for (let i = 0; i < data.length; i++) {
|
|
517
|
+
const char = data.charCodeAt(i)
|
|
518
|
+
hash = ((hash << 5) - hash) + char
|
|
519
|
+
hash = hash & hash // Convert to 32-bit integer
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
return Math.abs(hash).toString(36)
|
|
523
|
+
},
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Merge additional data into request
|
|
527
|
+
*/
|
|
528
|
+
merge(this: EnhancedRequest, data: Record<string, any>): void {
|
|
529
|
+
if (!this.validated) {
|
|
530
|
+
this.validated = {}
|
|
531
|
+
}
|
|
532
|
+
Object.assign(this.validated, data)
|
|
533
|
+
},
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Replace request data
|
|
537
|
+
*/
|
|
538
|
+
replace(this: EnhancedRequest, data: Record<string, any>): void {
|
|
539
|
+
this.validated = { ...data }
|
|
540
|
+
},
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Get request age in milliseconds
|
|
544
|
+
*/
|
|
545
|
+
age(this: EnhancedRequest): number {
|
|
546
|
+
const startTime = (this as any).startTime || Date.now()
|
|
547
|
+
return Date.now() - startTime
|
|
548
|
+
},
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Check if request is from trusted proxy
|
|
552
|
+
*/
|
|
553
|
+
isFromTrustedProxy(this: EnhancedRequest, trustedProxies: string[] = []): boolean {
|
|
554
|
+
const ip = BuiltInRequestMacros.ip.call(this)
|
|
555
|
+
return trustedProxies.includes(ip)
|
|
556
|
+
},
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Get request content length
|
|
560
|
+
*/
|
|
561
|
+
contentLength(this: EnhancedRequest): number {
|
|
562
|
+
const length = this.headers.get('content-length')
|
|
563
|
+
return length ? Number.parseInt(length, 10) : 0
|
|
564
|
+
},
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Get request content type
|
|
568
|
+
*/
|
|
569
|
+
contentType(this: EnhancedRequest): string | null {
|
|
570
|
+
return this.headers.get('content-type')
|
|
571
|
+
},
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Check if request content type matches
|
|
575
|
+
*/
|
|
576
|
+
isContentType(this: EnhancedRequest, type: string): boolean {
|
|
577
|
+
const contentType = this.contentType()
|
|
578
|
+
return contentType ? contentType.includes(type) : false
|
|
579
|
+
},
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Register all built-in macros
|
|
584
|
+
*/
|
|
585
|
+
export function registerBuiltInRequestMacros(): void {
|
|
586
|
+
Object.entries(BuiltInRequestMacros).forEach(([name, handler]) => {
|
|
587
|
+
RequestWithMacros.macro(name, handler)
|
|
588
|
+
})
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Request macro factory functions
|
|
593
|
+
*/
|
|
594
|
+
export const RequestMacroFactory = {
|
|
595
|
+
/**
|
|
596
|
+
* Create input validation macro
|
|
597
|
+
*/
|
|
598
|
+
validateInput: (_rules: Record<string, string>) => {
|
|
599
|
+
// eslint-disable-next-line pickier/no-unused-vars
|
|
600
|
+
return function (this: EnhancedRequest): boolean {
|
|
601
|
+
// This would integrate with the validation system
|
|
602
|
+
// For now, return true as placeholder
|
|
603
|
+
return true
|
|
604
|
+
}
|
|
605
|
+
},
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Create custom header checker macro
|
|
609
|
+
*/
|
|
610
|
+
hasCustomHeader: (headerName: string) => {
|
|
611
|
+
return function (this: EnhancedRequest): boolean {
|
|
612
|
+
return this.hasHeader(headerName)
|
|
613
|
+
}
|
|
614
|
+
},
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* Create role checker macro
|
|
618
|
+
*/
|
|
619
|
+
hasRole: (role: string) => {
|
|
620
|
+
return function (this: EnhancedRequest): boolean {
|
|
621
|
+
const user = (this as any).user
|
|
622
|
+
return user?.roles?.includes(role) || false
|
|
623
|
+
}
|
|
624
|
+
},
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* Create permission checker macro
|
|
628
|
+
*/
|
|
629
|
+
can: (permission: string) => {
|
|
630
|
+
return function (this: EnhancedRequest): boolean {
|
|
631
|
+
const user = (this as any).user
|
|
632
|
+
return user?.permissions?.includes(permission) || false
|
|
633
|
+
}
|
|
634
|
+
},
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Request helper utilities
|
|
639
|
+
*/
|
|
640
|
+
export const RequestHelpers = {
|
|
641
|
+
/**
|
|
642
|
+
* Apply macros to request
|
|
643
|
+
*/
|
|
644
|
+
withMacros: (request: EnhancedRequest): EnhancedRequest => {
|
|
645
|
+
return RequestWithMacros.applyMacros(request)
|
|
646
|
+
},
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* Create request from URL and options
|
|
650
|
+
*/
|
|
651
|
+
create: (url: string, options: RequestInit = {}): EnhancedRequest => {
|
|
652
|
+
const request = new Request(url, options) as EnhancedRequest
|
|
653
|
+
return RequestWithMacros.applyMacros(request)
|
|
654
|
+
},
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Parse query string to object
|
|
658
|
+
*/
|
|
659
|
+
parseQuery: (queryString: string): Record<string, string> => {
|
|
660
|
+
const params = new URLSearchParams(queryString)
|
|
661
|
+
const result: Record<string, string> = {}
|
|
662
|
+
|
|
663
|
+
params.forEach((value, key) => {
|
|
664
|
+
result[key] = value
|
|
665
|
+
})
|
|
666
|
+
|
|
667
|
+
return result
|
|
668
|
+
},
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Parse cookies from header
|
|
672
|
+
*/
|
|
673
|
+
parseCookies: (cookieHeader: string): Record<string, string> => {
|
|
674
|
+
const cookies: Record<string, string> = {}
|
|
675
|
+
|
|
676
|
+
cookieHeader.split(';').forEach((cookie) => {
|
|
677
|
+
const [key, value] = cookie.trim().split('=')
|
|
678
|
+
if (key && value) {
|
|
679
|
+
cookies[key] = decodeURIComponent(value)
|
|
680
|
+
}
|
|
681
|
+
})
|
|
682
|
+
|
|
683
|
+
return cookies
|
|
684
|
+
},
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// Auto-register built-in macros
|
|
688
|
+
registerBuiltInRequestMacros()
|