@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,245 @@
|
|
|
1
|
+
import type { EnhancedRequest, Middleware, MiddlewareHandler, NextFunction } from '../types'
|
|
2
|
+
import { createRateLimiter } from 'ts-rate-limiter'
|
|
3
|
+
import { config } from '../config'
|
|
4
|
+
|
|
5
|
+
export interface RateLimitOptions {
|
|
6
|
+
windowMs?: number
|
|
7
|
+
maxRequests?: number
|
|
8
|
+
standardHeaders?: boolean
|
|
9
|
+
legacyHeaders?: boolean
|
|
10
|
+
skipFailedRequests?: boolean
|
|
11
|
+
keyGenerator?: (request: Request) => string | Promise<string>
|
|
12
|
+
handler?: (request: Request, limit: { remaining: number, limit: number, resetTime: number }) => Response | Promise<Response>
|
|
13
|
+
skip?: (request: Request) => boolean | Promise<boolean>
|
|
14
|
+
storage?: any
|
|
15
|
+
algorithm?: 'fixed-window' | 'sliding-window' | 'token-bucket'
|
|
16
|
+
draftMode?: boolean
|
|
17
|
+
redis?: {
|
|
18
|
+
url?: string
|
|
19
|
+
prefix?: string
|
|
20
|
+
}
|
|
21
|
+
tokenBucket?: {
|
|
22
|
+
tokensPerInterval?: number
|
|
23
|
+
interval?: number
|
|
24
|
+
burst?: number
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Factory function to create a callable middleware instance
|
|
29
|
+
function createRateLimitMiddleware(options: RateLimitOptions = {}): MiddlewareHandler {
|
|
30
|
+
const instance = new RateLimit(options)
|
|
31
|
+
const middlewareHandler = async (req: EnhancedRequest, next: NextFunction): Promise<Response> => {
|
|
32
|
+
return instance.handle(req, next)
|
|
33
|
+
}
|
|
34
|
+
return middlewareHandler
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default class RateLimit implements Middleware {
|
|
38
|
+
private limiter: any // Will be initialized in constructor
|
|
39
|
+
private options: RateLimitOptions
|
|
40
|
+
|
|
41
|
+
constructor(options: RateLimitOptions = {}) {
|
|
42
|
+
// Get rate limit config from server config if available
|
|
43
|
+
const rateLimitConfig = config.server?.rateLimit || {}
|
|
44
|
+
const securityRateLimitConfig = config.server?.security?.rateLimit || {}
|
|
45
|
+
|
|
46
|
+
// Merge options with configuration (options take precedence)
|
|
47
|
+
this.options = {
|
|
48
|
+
// Basic settings
|
|
49
|
+
windowMs: options.windowMs || rateLimitConfig.timeWindow || securityRateLimitConfig.timeWindow || 60 * 1000,
|
|
50
|
+
maxRequests: options.maxRequests || rateLimitConfig.max || securityRateLimitConfig.max || 100,
|
|
51
|
+
|
|
52
|
+
// Headers
|
|
53
|
+
standardHeaders: options.standardHeaders ?? true,
|
|
54
|
+
legacyHeaders: options.legacyHeaders ?? false,
|
|
55
|
+
|
|
56
|
+
// Behavior options
|
|
57
|
+
skipFailedRequests: options.skipFailedRequests
|
|
58
|
+
?? (rateLimitConfig.advanced?.skipFailedRequests)
|
|
59
|
+
?? (securityRateLimitConfig.advanced?.skipFailedRequests)
|
|
60
|
+
?? false,
|
|
61
|
+
draftMode: options.draftMode ?? false,
|
|
62
|
+
|
|
63
|
+
// Custom handlers
|
|
64
|
+
keyGenerator: options.keyGenerator,
|
|
65
|
+
|
|
66
|
+
handler: options.handler || (
|
|
67
|
+
rateLimitConfig.message
|
|
68
|
+
? (_req: Request, _limit: any) => new Response(rateLimitConfig.message, { status: 429 })
|
|
69
|
+
: undefined
|
|
70
|
+
),
|
|
71
|
+
|
|
72
|
+
skip: options.skip,
|
|
73
|
+
|
|
74
|
+
// Algorithm - advanced config can override
|
|
75
|
+
algorithm: options.algorithm || 'fixed-window',
|
|
76
|
+
|
|
77
|
+
// Storage configuration from config
|
|
78
|
+
storage: options.storage,
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Enable storage from config if available
|
|
82
|
+
if (!this.options.storage && rateLimitConfig.stores?.type === 'redis' && rateLimitConfig.stores.redis) {
|
|
83
|
+
this.options.storage = 'redis'
|
|
84
|
+
|
|
85
|
+
// Set up redis config if available
|
|
86
|
+
if (rateLimitConfig.stores.redis) {
|
|
87
|
+
this.options.redis = {
|
|
88
|
+
url: rateLimitConfig.stores.redis.url,
|
|
89
|
+
prefix: rateLimitConfig.stores.redis.prefix || 'ratelimit:',
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Advanced options from config
|
|
95
|
+
if (rateLimitConfig.advanced) {
|
|
96
|
+
if (rateLimitConfig.advanced.tokensPerInterval && this.options.algorithm === 'token-bucket') {
|
|
97
|
+
this.options.tokenBucket = {
|
|
98
|
+
tokensPerInterval: rateLimitConfig.advanced.tokensPerInterval,
|
|
99
|
+
interval: rateLimitConfig.advanced.interval || this.options.windowMs,
|
|
100
|
+
burst: rateLimitConfig.advanced.burst,
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Initialize the limiter (async)
|
|
106
|
+
this.initLimiter()
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private async initLimiter() {
|
|
110
|
+
// Create a copy of the options to avoid modifying the original
|
|
111
|
+
const limiterOptions: any = { ...this.options }
|
|
112
|
+
|
|
113
|
+
// Assign specific properties for the rate limiter
|
|
114
|
+
limiterOptions.windowMs = this.options.windowMs as number
|
|
115
|
+
limiterOptions.maxRequests = this.options.maxRequests as number
|
|
116
|
+
limiterOptions.standardHeaders = this.options.standardHeaders
|
|
117
|
+
limiterOptions.legacyHeaders = this.options.legacyHeaders
|
|
118
|
+
limiterOptions.skipFailedRequests = this.options.skipFailedRequests
|
|
119
|
+
limiterOptions.keyGenerator = this.options.keyGenerator
|
|
120
|
+
limiterOptions.skip = this.options.skip
|
|
121
|
+
limiterOptions.algorithm = this.options.algorithm
|
|
122
|
+
limiterOptions.draftMode = this.options.draftMode
|
|
123
|
+
|
|
124
|
+
// Set up custom handler
|
|
125
|
+
limiterOptions.handler = this.options.handler
|
|
126
|
+
? async (req: Request, result: any) => {
|
|
127
|
+
return this.options.handler?.(req, {
|
|
128
|
+
remaining: result.remaining,
|
|
129
|
+
limit: result.limit,
|
|
130
|
+
resetTime: result.resetTime,
|
|
131
|
+
}) || this.defaultHandler(req, result)
|
|
132
|
+
}
|
|
133
|
+
: undefined
|
|
134
|
+
|
|
135
|
+
// Initialize the rate limiter (suppress noisy logs from ts-rate-limiter)
|
|
136
|
+
const originalConsoleLog = console.log
|
|
137
|
+
const originalConsoleWarn = console.warn
|
|
138
|
+
console.log = () => {}
|
|
139
|
+
console.warn = () => {}
|
|
140
|
+
try {
|
|
141
|
+
this.limiter = await createRateLimiter(limiterOptions)
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
console.log = originalConsoleLog
|
|
145
|
+
console.warn = originalConsoleWarn
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private defaultHandler(req: Request, result: any): Response {
|
|
150
|
+
const headers: Record<string, string> = {}
|
|
151
|
+
|
|
152
|
+
if (this.options.standardHeaders) {
|
|
153
|
+
headers['RateLimit-Limit'] = String(result.limit)
|
|
154
|
+
headers['RateLimit-Remaining'] = String(Math.max(0, result.limit - result.current))
|
|
155
|
+
headers['RateLimit-Reset'] = String(Math.ceil(result.resetTime / 1000))
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (this.options.legacyHeaders) {
|
|
159
|
+
headers['X-RateLimit-Limit'] = String(result.limit)
|
|
160
|
+
headers['X-RateLimit-Remaining'] = String(Math.max(0, result.limit - result.current))
|
|
161
|
+
headers['X-RateLimit-Reset'] = String(Math.ceil(result.resetTime / 1000))
|
|
162
|
+
headers['Retry-After'] = String(Math.ceil(result.remaining / 1000))
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const message = config.server?.rateLimit?.message || 'Too Many Requests'
|
|
166
|
+
|
|
167
|
+
return new Response(message, {
|
|
168
|
+
status: 429,
|
|
169
|
+
headers,
|
|
170
|
+
})
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// The middleware interface implementation
|
|
174
|
+
async handle(req: EnhancedRequest, next: NextFunction): Promise<Response> {
|
|
175
|
+
// If rate limiting is disabled in config, skip it
|
|
176
|
+
if (config.server?.rateLimit?.enabled === false) {
|
|
177
|
+
const response = await next()
|
|
178
|
+
return response || new Response('Not Found', { status: 404 })
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// If limiter isn't initialized yet, wait a bit and try again
|
|
182
|
+
if (!this.limiter) {
|
|
183
|
+
await new Promise(resolve => setTimeout(resolve, 50))
|
|
184
|
+
if (!this.limiter) {
|
|
185
|
+
// If still not initialized, just proceed
|
|
186
|
+
const response = await next()
|
|
187
|
+
return response || new Response('Not Found', { status: 404 })
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
// Check if request exceeds rate limit
|
|
193
|
+
const result = await this.limiter.check(req)
|
|
194
|
+
|
|
195
|
+
if (!result.allowed) {
|
|
196
|
+
return this.options.handler
|
|
197
|
+
? await this.options.handler(req, {
|
|
198
|
+
remaining: result.remaining,
|
|
199
|
+
limit: result.limit,
|
|
200
|
+
resetTime: result.resetTime,
|
|
201
|
+
})
|
|
202
|
+
: this.defaultHandler(req, result)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// If allowed, proceed to next middleware
|
|
206
|
+
const response = await next()
|
|
207
|
+
|
|
208
|
+
if (!response) {
|
|
209
|
+
return new Response('Not Found', { status: 404 })
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Add rate limit headers to response
|
|
213
|
+
const headers = new Headers(response.headers)
|
|
214
|
+
|
|
215
|
+
if (this.options.standardHeaders) {
|
|
216
|
+
headers.set('RateLimit-Limit', String(result.limit))
|
|
217
|
+
headers.set('RateLimit-Remaining', String(Math.max(0, result.limit - result.current)))
|
|
218
|
+
headers.set('RateLimit-Reset', String(Math.ceil(result.resetTime / 1000)))
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (this.options.legacyHeaders) {
|
|
222
|
+
headers.set('X-RateLimit-Limit', String(result.limit))
|
|
223
|
+
headers.set('X-RateLimit-Remaining', String(Math.max(0, result.limit - result.current)))
|
|
224
|
+
headers.set('X-RateLimit-Reset', String(Math.ceil(result.resetTime / 1000)))
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return new Response(response.body, {
|
|
228
|
+
status: response.status,
|
|
229
|
+
statusText: response.statusText,
|
|
230
|
+
headers,
|
|
231
|
+
})
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
console.error('[RateLimit] Error during rate limiting:', error)
|
|
235
|
+
// Proceed to next middleware in case of error
|
|
236
|
+
const response = await next()
|
|
237
|
+
return response || new Response('Not Found', { status: 404 })
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Export a factory function to create middleware handlers
|
|
243
|
+
export function rateLimit(options: RateLimitOptions = {}): MiddlewareHandler {
|
|
244
|
+
return createRateLimitMiddleware(options)
|
|
245
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { EnhancedRequest, NextFunction } from '../types'
|
|
2
|
+
import { randomUUID } from 'node:crypto'
|
|
3
|
+
|
|
4
|
+
export default class RequestId {
|
|
5
|
+
async handle(req: EnhancedRequest, next: NextFunction): Promise<Response> {
|
|
6
|
+
// Check if there's already a request ID in the headers
|
|
7
|
+
const requestId = req.headers.get('X-Request-ID') || randomUUID()
|
|
8
|
+
|
|
9
|
+
// Store the request ID on the request object
|
|
10
|
+
Object.defineProperty(req, 'requestId', {
|
|
11
|
+
value: requestId,
|
|
12
|
+
writable: false,
|
|
13
|
+
enumerable: true,
|
|
14
|
+
configurable: false,
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
// Continue to next middleware
|
|
18
|
+
const response = await next()
|
|
19
|
+
|
|
20
|
+
// Add request ID to response headers
|
|
21
|
+
if (!response) {
|
|
22
|
+
return new Response('Not Found', { status: 404 })
|
|
23
|
+
}
|
|
24
|
+
const newHeaders = new Headers(response.headers)
|
|
25
|
+
if (!newHeaders.has('X-Request-ID')) {
|
|
26
|
+
newHeaders.set('X-Request-ID', requestId)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Return modified response
|
|
30
|
+
return new Response(response.body, {
|
|
31
|
+
status: response.status,
|
|
32
|
+
statusText: response.statusText,
|
|
33
|
+
headers: newHeaders,
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
}
|