@stacksjs/bun-router 0.0.5 → 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.
Files changed (269) hide show
  1. package/dist/auth.d.ts +134 -0
  2. package/dist/cache/lru-cache.d.ts +139 -0
  3. package/dist/cache/middleware-memoization.d.ts +151 -0
  4. package/dist/cache/route-cache-warmer.d.ts +161 -0
  5. package/dist/cache/sqlite-cache.d.ts +209 -0
  6. package/dist/cache/streaming-cache.d.ts +132 -0
  7. package/dist/cli/colors.d.ts +15 -0
  8. package/dist/cli/index.d.ts +10 -0
  9. package/dist/cli/middleware.d.ts +31 -0
  10. package/dist/cli/openapi.d.ts +17 -0
  11. package/dist/cli/router.d.ts +15 -0
  12. package/dist/cli/routes.d.ts +29 -0
  13. package/dist/cli/utils.d.ts +74 -0
  14. package/dist/cli.d.ts +1 -1
  15. package/dist/cli.js +1 -1
  16. package/dist/config.d.ts +7 -0
  17. package/dist/container/container.d.ts +273 -0
  18. package/dist/container/contextual-binding.d.ts +240 -0
  19. package/dist/container/decorators.d.ts +141 -0
  20. package/dist/container/service-provider.d.ts +285 -0
  21. package/dist/development/hot-reload.d.ts +187 -0
  22. package/dist/development/index.d.ts +167 -0
  23. package/dist/development/performance-profiler.d.ts +217 -0
  24. package/dist/development/route-debugger.d.ts +154 -0
  25. package/dist/development/route-inspector.d.ts +211 -0
  26. package/dist/development/typescript-utilities.d.ts +209 -0
  27. package/dist/docs.d.ts +11 -0
  28. package/dist/errors/circuit-breaker.d.ts +195 -0
  29. package/dist/errors/error-handler.d.ts +88 -0
  30. package/dist/errors/error-reporting.d.ts +144 -0
  31. package/dist/errors/exceptions.d.ts +184 -0
  32. package/dist/errors/graceful-degradation.d.ts +154 -0
  33. package/dist/errors/index.d.ts +9 -0
  34. package/dist/errors/router-errors.d.ts +110 -0
  35. package/dist/file-serving/static-files.d.ts +143 -0
  36. package/dist/index.d.ts +2 -0
  37. package/dist/index.js +319 -205
  38. package/dist/middleware/auth.d.ts +63 -0
  39. package/dist/middleware/content_security_policy.d.ts +53 -0
  40. package/dist/middleware/cors.d.ts +5 -0
  41. package/dist/middleware/csrf.d.ts +7 -0
  42. package/dist/middleware/ddos_protection.d.ts +39 -0
  43. package/dist/middleware/file_security.d.ts +26 -0
  44. package/dist/middleware/file_upload.d.ts +38 -0
  45. package/dist/middleware/helmet.d.ts +54 -0
  46. package/dist/middleware/index.d.ts +44 -0
  47. package/dist/middleware/input_validation.d.ts +45 -0
  48. package/dist/middleware/json_body.d.ts +4 -0
  49. package/dist/middleware/performance_alerting.d.ts +87 -0
  50. package/dist/middleware/performance_dashboard.d.ts +87 -0
  51. package/dist/middleware/performance_monitor.d.ts +209 -0
  52. package/dist/middleware/pipeline.d.ts +131 -0
  53. package/dist/middleware/rate_limit.d.ts +36 -0
  54. package/dist/middleware/request_id.d.ts +4 -0
  55. package/dist/middleware/request_signing.d.ts +153 -0
  56. package/dist/middleware/request_tracer.d.ts +72 -0
  57. package/dist/middleware/response_cache.d.ts +97 -0
  58. package/dist/middleware/security.d.ts +69 -0
  59. package/dist/middleware/security_suite.d.ts +46 -0
  60. package/dist/middleware/session.d.ts +23 -0
  61. package/dist/model-binding/index.d.ts +2 -0
  62. package/dist/model-binding/model-middleware.d.ts +118 -0
  63. package/dist/model-binding/model-registry.d.ts +164 -0
  64. package/dist/model-binding.d.ts +185 -0
  65. package/dist/model-resolver-factory.d.ts +31 -0
  66. package/dist/observability/correlation.d.ts +187 -0
  67. package/dist/observability/health-checks.d.ts +186 -0
  68. package/dist/observability/index.d.ts +60 -0
  69. package/dist/observability/integration.d.ts +147 -0
  70. package/dist/observability/metrics.d.ts +184 -0
  71. package/dist/observability/tracing.d.ts +187 -0
  72. package/dist/optimization/bun-utilities.d.ts +224 -0
  73. package/dist/query-builder-integration.d.ts +36 -0
  74. package/dist/request/context.d.ts +34 -0
  75. package/dist/request/enhanced-request.d.ts +213 -0
  76. package/dist/request/macros.d.ts +300 -0
  77. package/dist/response/macros.d.ts +245 -0
  78. package/dist/response/response-factory.d.ts +133 -0
  79. package/dist/router/api-routes.d.ts +5 -0
  80. package/dist/router/file-based-routing.d.ts +118 -0
  81. package/dist/router/file-streaming.d.ts +5 -0
  82. package/dist/router/fluent-router.d.ts +315 -0
  83. package/dist/router/fluent-routing.d.ts +271 -0
  84. package/dist/router/group-organization.d.ts +5 -0
  85. package/dist/router/handler-resolver.d.ts +24 -0
  86. package/dist/router/http-methods.d.ts +10 -0
  87. package/dist/router/index.d.ts +113 -0
  88. package/dist/router/middleware-groups.d.ts +94 -0
  89. package/dist/router/middleware-integration.d.ts +112 -0
  90. package/dist/router/middleware.d.ts +5 -0
  91. package/dist/router/model-binding.d.ts +5 -0
  92. package/dist/router/optimized-route-matching.d.ts +6 -0
  93. package/dist/router/route-building.d.ts +5 -0
  94. package/dist/router/route-compiler.d.ts +153 -0
  95. package/dist/router/route-matching.d.ts +5 -0
  96. package/dist/router/route-trie.d.ts +114 -0
  97. package/dist/router/router.d.ts +276 -0
  98. package/dist/router/server.d.ts +5 -0
  99. package/dist/router/validation-integration.d.ts +170 -0
  100. package/dist/router/view-rendering.d.ts +5 -0
  101. package/dist/router/websocket.d.ts +5 -0
  102. package/dist/routing/route-caching.d.ts +129 -0
  103. package/dist/routing/route-throttling.d.ts +150 -0
  104. package/dist/routing/subdomain-routing.d.ts +206 -0
  105. package/dist/session/database-store.d.ts +51 -0
  106. package/dist/session/file-store.d.ts +22 -0
  107. package/dist/session/index.d.ts +106 -0
  108. package/dist/session/memory-store.d.ts +21 -0
  109. package/dist/session/redis-store.d.ts +31 -0
  110. package/dist/streaming/index.d.ts +3 -0
  111. package/dist/streaming/sse-handler.d.ts +138 -0
  112. package/dist/streaming/stream-handler.d.ts +114 -0
  113. package/dist/testing/auth-testing.d.ts +156 -0
  114. package/dist/testing/file-upload-testing.d.ts +190 -0
  115. package/dist/testing/index.d.ts +10 -0
  116. package/dist/testing/middleware-testing.d.ts +138 -0
  117. package/dist/testing/model-binding-testing.d.ts +186 -0
  118. package/dist/testing/performance-testing.d.ts +235 -0
  119. package/dist/testing/test-client.d.ts +117 -0
  120. package/dist/testing/test-request.d.ts +85 -0
  121. package/dist/testing/test-response.d.ts +90 -0
  122. package/dist/testing/types.d.ts +207 -0
  123. package/dist/testing/websocket-testing.d.ts +227 -0
  124. package/dist/types/controller-types.d.ts +208 -0
  125. package/dist/types/core.d.ts +543 -0
  126. package/dist/types/middleware-types.d.ts +227 -0
  127. package/dist/types/request-response-augmentation.d.ts +261 -0
  128. package/dist/types/route-inference.d.ts +168 -0
  129. package/dist/types.d.ts +1776 -0
  130. package/dist/url.d.ts +56 -0
  131. package/dist/utils/index.d.ts +1 -0
  132. package/dist/utils/query-preservation.d.ts +48 -0
  133. package/dist/utils.d.ts +69 -0
  134. package/dist/validation/validator.d.ts +140 -0
  135. package/dist/websocket/clustering.d.ts +185 -0
  136. package/package.json +3 -2
  137. package/src/auth.ts +469 -0
  138. package/src/cache/lru-cache.ts +457 -0
  139. package/src/cache/middleware-memoization.ts +531 -0
  140. package/src/cache/route-cache-warmer.ts +486 -0
  141. package/src/cache/sqlite-cache.ts +783 -0
  142. package/src/cache/streaming-cache.ts +572 -0
  143. package/src/cli/colors.ts +29 -0
  144. package/src/cli/index.ts +287 -0
  145. package/src/cli/middleware.ts +291 -0
  146. package/src/cli/openapi.ts +407 -0
  147. package/src/cli/router.ts +188 -0
  148. package/src/cli/routes.ts +265 -0
  149. package/src/cli/utils.ts +531 -0
  150. package/src/cli.ts +5 -0
  151. package/src/config.ts +322 -0
  152. package/src/container/container.ts +740 -0
  153. package/src/container/contextual-binding.ts +603 -0
  154. package/src/container/decorators.ts +359 -0
  155. package/src/container/service-provider.ts +596 -0
  156. package/src/development/hot-reload.ts +673 -0
  157. package/src/development/index.ts +499 -0
  158. package/src/development/performance-profiler.ts +717 -0
  159. package/src/development/route-debugger.ts +527 -0
  160. package/src/development/route-inspector.ts +749 -0
  161. package/src/development/typescript-utilities.ts +678 -0
  162. package/src/docs.ts +397 -0
  163. package/src/errors/circuit-breaker.ts +732 -0
  164. package/src/errors/error-handler.ts +569 -0
  165. package/src/errors/error-reporting.ts +672 -0
  166. package/src/errors/exceptions.ts +536 -0
  167. package/src/errors/graceful-degradation.ts +621 -0
  168. package/src/errors/index.ts +21 -0
  169. package/src/errors/router-errors.ts +632 -0
  170. package/src/file-serving/static-files.ts +581 -0
  171. package/src/index.ts +14 -0
  172. package/src/middleware/auth.ts +219 -0
  173. package/src/middleware/content_security_policy.ts +215 -0
  174. package/src/middleware/cors.ts +74 -0
  175. package/src/middleware/csrf.ts +108 -0
  176. package/src/middleware/ddos_protection.ts +255 -0
  177. package/src/middleware/file_security.ts +191 -0
  178. package/src/middleware/file_upload.ts +264 -0
  179. package/src/middleware/helmet.ts +268 -0
  180. package/src/middleware/index.ts +117 -0
  181. package/src/middleware/input_validation.ts +449 -0
  182. package/src/middleware/json_body.ts +37 -0
  183. package/src/middleware/performance_alerting.ts +538 -0
  184. package/src/middleware/performance_dashboard.ts +661 -0
  185. package/src/middleware/performance_monitor.ts +943 -0
  186. package/src/middleware/pipeline.ts +489 -0
  187. package/src/middleware/rate_limit.ts +245 -0
  188. package/src/middleware/request_id.ts +36 -0
  189. package/src/middleware/request_signing.ts +636 -0
  190. package/src/middleware/request_tracer.ts +636 -0
  191. package/src/middleware/response_cache.ts +743 -0
  192. package/src/middleware/security.ts +482 -0
  193. package/src/middleware/security_suite.ts +257 -0
  194. package/src/middleware/session.ts +91 -0
  195. package/src/model-binding/index.ts +18 -0
  196. package/src/model-binding/model-middleware.ts +425 -0
  197. package/src/model-binding/model-registry.ts +550 -0
  198. package/src/model-binding.ts +370 -0
  199. package/src/model-resolver-factory.ts +106 -0
  200. package/src/observability/correlation.ts +691 -0
  201. package/src/observability/health-checks.ts +729 -0
  202. package/src/observability/index.ts +184 -0
  203. package/src/observability/integration.ts +548 -0
  204. package/src/observability/metrics.ts +753 -0
  205. package/src/observability/tracing.ts +638 -0
  206. package/src/optimization/bun-utilities.ts +778 -0
  207. package/src/query-builder-integration.ts +137 -0
  208. package/src/request/context.ts +62 -0
  209. package/src/request/enhanced-request.ts +857 -0
  210. package/src/request/macros.ts +688 -0
  211. package/src/response/macros.ts +612 -0
  212. package/src/response/response-factory.ts +588 -0
  213. package/src/router/api-routes.ts +243 -0
  214. package/src/router/file-based-routing.ts +670 -0
  215. package/src/router/file-streaming.ts +372 -0
  216. package/src/router/fluent-router.ts +927 -0
  217. package/src/router/fluent-routing.ts +797 -0
  218. package/src/router/group-organization.ts +213 -0
  219. package/src/router/handler-resolver.ts +291 -0
  220. package/src/router/http-methods.ts +377 -0
  221. package/src/router/index.ts +185 -0
  222. package/src/router/middleware-groups.ts +222 -0
  223. package/src/router/middleware-integration.ts +399 -0
  224. package/src/router/middleware.ts +231 -0
  225. package/src/router/model-binding.ts +215 -0
  226. package/src/router/optimized-route-matching.ts +253 -0
  227. package/src/router/route-building.ts +212 -0
  228. package/src/router/route-compiler.ts +702 -0
  229. package/src/router/route-matching.ts +349 -0
  230. package/src/router/route-trie.ts +464 -0
  231. package/src/router/router.ts +1508 -0
  232. package/src/router/server.ts +406 -0
  233. package/src/router/validation-integration.ts +443 -0
  234. package/src/router/view-rendering.ts +233 -0
  235. package/src/router/websocket.ts +100 -0
  236. package/src/routing/route-caching.ts +402 -0
  237. package/src/routing/route-throttling.ts +469 -0
  238. package/src/routing/subdomain-routing.ts +492 -0
  239. package/src/session/database-store.ts +109 -0
  240. package/src/session/file-store.ts +148 -0
  241. package/src/session/index.ts +244 -0
  242. package/src/session/memory-store.ts +88 -0
  243. package/src/session/redis-store.ts +93 -0
  244. package/src/streaming/index.ts +17 -0
  245. package/src/streaming/sse-handler.ts +482 -0
  246. package/src/streaming/stream-handler.ts +552 -0
  247. package/src/testing/auth-testing.ts +446 -0
  248. package/src/testing/file-upload-testing.ts +543 -0
  249. package/src/testing/index.ts +10 -0
  250. package/src/testing/middleware-testing.ts +322 -0
  251. package/src/testing/model-binding-testing.ts +645 -0
  252. package/src/testing/performance-testing.ts +738 -0
  253. package/src/testing/test-client.ts +310 -0
  254. package/src/testing/test-request.ts +315 -0
  255. package/src/testing/test-response.ts +332 -0
  256. package/src/testing/types.ts +224 -0
  257. package/src/testing/websocket-testing.ts +590 -0
  258. package/src/types/controller-types.ts +385 -0
  259. package/src/types/core.ts +683 -0
  260. package/src/types/middleware-types.ts +419 -0
  261. package/src/types/request-response-augmentation.ts +489 -0
  262. package/src/types/route-inference.ts +357 -0
  263. package/src/types.ts +2049 -0
  264. package/src/url.ts +126 -0
  265. package/src/utils/index.ts +1 -0
  266. package/src/utils/query-preservation.ts +201 -0
  267. package/src/utils.ts +327 -0
  268. package/src/validation/validator.ts +685 -0
  269. package/src/websocket/clustering.ts +762 -0
@@ -0,0 +1,100 @@
1
+ import type { WebSocketConfig } from '../types'
2
+ import type { Router } from './router'
3
+
4
+ /**
5
+ * WebSocket extension for Router class
6
+ */
7
+ export function registerWebSocketHandling(RouterClass: typeof Router): void {
8
+ Object.defineProperties(RouterClass.prototype, {
9
+ /**
10
+ * Configure WebSocket handling
11
+ */
12
+ websocket: {
13
+ value(config: WebSocketConfig): Router {
14
+ this.wsConfig = config
15
+ return this
16
+ },
17
+ writable: true,
18
+ configurable: true,
19
+ },
20
+
21
+ /**
22
+ * Publish a message to a WebSocket topic
23
+ */
24
+ publish: {
25
+ value(topic: string, data: string | ArrayBuffer | Uint8Array, compress = false): number {
26
+ if (!this.serverInstance) {
27
+ throw new Error('Server not started, cannot publish to WebSocket topics')
28
+ }
29
+
30
+ return this.serverInstance.publish(topic, data, compress)
31
+ },
32
+ writable: true,
33
+ configurable: true,
34
+ },
35
+
36
+ /**
37
+ * Get the number of subscribers for a WebSocket topic
38
+ */
39
+ subscriberCount: {
40
+ value(topic: string): number {
41
+ if (!this.serverInstance) {
42
+ throw new Error('Server not started, cannot get subscriber count')
43
+ }
44
+
45
+ return this.serverInstance.subscriberCount(topic)
46
+ },
47
+ writable: true,
48
+ configurable: true,
49
+ },
50
+
51
+ /**
52
+ * Upgrade an HTTP request to a WebSocket connection
53
+ */
54
+ upgrade: {
55
+ value(request: Request, options?: { headers?: Record<string, string>, data?: any }): boolean {
56
+ if (!this.serverInstance) {
57
+ throw new Error('Server not started, cannot upgrade to WebSocket')
58
+ }
59
+
60
+ if (!this.wsConfig) {
61
+ throw new Error('WebSocket configuration not set, use router.websocket() to configure')
62
+ }
63
+
64
+ return this.serverInstance.upgrade(request, options)
65
+ },
66
+ writable: true,
67
+ configurable: true,
68
+ },
69
+
70
+ /**
71
+ * Set a timeout for a request
72
+ */
73
+ timeout: {
74
+ value(request: Request, seconds: number): void {
75
+ if (!this.serverInstance) {
76
+ throw new Error('Server not started, cannot set timeout')
77
+ }
78
+
79
+ this.serverInstance.timeout(request, seconds)
80
+ },
81
+ writable: true,
82
+ configurable: true,
83
+ },
84
+
85
+ /**
86
+ * Get the IP address of a request
87
+ */
88
+ requestIP: {
89
+ value(request: Request): { address: string, port: number } | null {
90
+ if (!this.serverInstance) {
91
+ throw new Error('Server not started, cannot get request IP')
92
+ }
93
+
94
+ return this.serverInstance.requestIP(request)
95
+ },
96
+ writable: true,
97
+ configurable: true,
98
+ },
99
+ })
100
+ }
@@ -0,0 +1,402 @@
1
+ import type { EnhancedRequest } from '../types'
2
+ import { LRUCache } from '../cache/lru-cache'
3
+
4
+ /**
5
+ * Route caching configuration
6
+ */
7
+ export interface RouteCacheConfig {
8
+ ttl?: number // Time to live in milliseconds
9
+ maxSize?: number // Maximum number of cached responses
10
+ tags?: string[] // Cache tags for invalidation
11
+ varyBy?: string[] // Headers to vary cache by
12
+ excludeQuery?: string[] // Query parameters to exclude from cache key
13
+ condition?: (req: EnhancedRequest) => boolean // Condition to determine if response should be cached
14
+ }
15
+
16
+ /**
17
+ * Cached response metadata
18
+ */
19
+ export interface CachedResponse {
20
+ response: Response
21
+ headers: Record<string, string>
22
+ status: number
23
+ body: string | Uint8Array
24
+ timestamp: number
25
+ ttl?: number
26
+ tags: string[]
27
+ etag?: string
28
+ }
29
+
30
+ /**
31
+ * Cache key generator for route responses
32
+ */
33
+ export class RouteCacheKeyGenerator {
34
+ /**
35
+ * Generate cache key from request
36
+ */
37
+ static generateKey(req: EnhancedRequest, config: RouteCacheConfig): string {
38
+ const url = new URL(req.url)
39
+ const method = req.method
40
+ const path = url.pathname
41
+
42
+ // Base key components
43
+ const keyParts = [method, path]
44
+
45
+ // Add query parameters (excluding specified ones)
46
+ const queryParams = new URLSearchParams(url.search)
47
+ const excludeQuery = config.excludeQuery || []
48
+
49
+ const relevantQuery: string[] = []
50
+ for (const [key, value] of queryParams.entries()) {
51
+ if (!excludeQuery.includes(key)) {
52
+ relevantQuery.push(`${key}=${value}`)
53
+ }
54
+ }
55
+
56
+ if (relevantQuery.length > 0) {
57
+ keyParts.push(relevantQuery.sort().join('&'))
58
+ }
59
+
60
+ // Add vary headers
61
+ if (config.varyBy) {
62
+ const varyValues: string[] = []
63
+ for (const header of config.varyBy) {
64
+ const value = req.headers.get(header)
65
+ if (value) {
66
+ varyValues.push(`${header}:${value}`)
67
+ }
68
+ }
69
+ if (varyValues.length > 0) {
70
+ keyParts.push(varyValues.join('|'))
71
+ }
72
+ }
73
+
74
+ return keyParts.join('::')
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Route cache manager with tag-based invalidation
80
+ */
81
+ export class RouteCacheManager {
82
+ private cache: LRUCache<CachedResponse>
83
+ private tagIndex: Map<string, Set<string>> = new Map() // tag -> cache keys
84
+ private keyTags: Map<string, Set<string>> = new Map() // cache key -> tags
85
+
86
+ constructor(maxSize: number = 1000) {
87
+ this.cache = new LRUCache<CachedResponse>({ maxSize })
88
+ }
89
+
90
+ /**
91
+ * Get cached response
92
+ */
93
+ async get(key: string): Promise<CachedResponse | null> {
94
+ const cached = this.cache.get(key)
95
+ if (!cached) {
96
+ return null
97
+ }
98
+
99
+ // Check TTL
100
+ if (cached.ttl && Date.now() - cached.timestamp > cached.ttl) {
101
+ this.delete(key)
102
+ return null
103
+ }
104
+
105
+ return cached
106
+ }
107
+
108
+ /**
109
+ * Set cached response
110
+ */
111
+ async set(key: string, response: CachedResponse): Promise<void> {
112
+ // Store in cache
113
+ this.cache.set(key, response)
114
+
115
+ // Update tag indexes
116
+ this.keyTags.set(key, new Set(response.tags))
117
+
118
+ for (const tag of response.tags) {
119
+ if (!this.tagIndex.has(tag)) {
120
+ this.tagIndex.set(tag, new Set())
121
+ }
122
+ this.tagIndex.get(tag)!.add(key)
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Delete cached response
128
+ */
129
+ delete(key: string): boolean {
130
+ const tags = this.keyTags.get(key)
131
+ if (tags) {
132
+ // Remove from tag indexes
133
+ for (const tag of tags) {
134
+ const tagKeys = this.tagIndex.get(tag)
135
+ if (tagKeys) {
136
+ tagKeys.delete(key)
137
+ if (tagKeys.size === 0) {
138
+ this.tagIndex.delete(tag)
139
+ }
140
+ }
141
+ }
142
+ this.keyTags.delete(key)
143
+ }
144
+
145
+ return this.cache.delete(key)
146
+ }
147
+
148
+ /**
149
+ * Invalidate cache by tags
150
+ */
151
+ invalidateByTags(tags: string[]): number {
152
+ const keysToDelete = new Set<string>()
153
+
154
+ for (const tag of tags) {
155
+ const tagKeys = this.tagIndex.get(tag)
156
+ if (tagKeys) {
157
+ for (const key of tagKeys) {
158
+ keysToDelete.add(key)
159
+ }
160
+ }
161
+ }
162
+
163
+ for (const key of keysToDelete) {
164
+ this.delete(key)
165
+ }
166
+
167
+ return keysToDelete.size
168
+ }
169
+
170
+ /**
171
+ * Clear all cache
172
+ */
173
+ clear(): void {
174
+ this.cache.clear()
175
+ this.tagIndex.clear()
176
+ this.keyTags.clear()
177
+ }
178
+
179
+ /**
180
+ * Get cache statistics
181
+ */
182
+ getStats(): ReturnType<LRUCache<CachedResponse>['getStats']> & { totalTags: number, totalKeyTagMappings: number } {
183
+ return {
184
+ ...this.cache.getStats(),
185
+ totalTags: this.tagIndex.size,
186
+ totalKeyTagMappings: this.keyTags.size,
187
+ }
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Global route cache manager instance
193
+ */
194
+ export const routeCacheManager: RouteCacheManager = new RouteCacheManager()
195
+
196
+ /**
197
+ * Create route caching middleware
198
+ */
199
+ export function createRouteCacheMiddleware(config: RouteCacheConfig) {
200
+ return async (req: EnhancedRequest, next: () => Promise<Response>): Promise<Response> => {
201
+ // Check if caching condition is met
202
+ if (config.condition && !config.condition(req)) {
203
+ return await next()
204
+ }
205
+
206
+ // Only cache GET and HEAD requests by default
207
+ if (req.method !== 'GET' && req.method !== 'HEAD') {
208
+ return await next()
209
+ }
210
+
211
+ // Generate cache key
212
+ const cacheKey = RouteCacheKeyGenerator.generateKey(req, config)
213
+
214
+ // Try to get from cache
215
+ const cached = await routeCacheManager.get(cacheKey)
216
+ if (cached) {
217
+ // Return cached response
218
+ const headers = new Headers(cached.headers)
219
+
220
+ // Add cache headers
221
+ headers.set('X-Cache', 'HIT')
222
+ headers.set('X-Cache-Key', cacheKey)
223
+
224
+ if (cached.etag) {
225
+ headers.set('ETag', cached.etag)
226
+
227
+ // Check if client has matching ETag
228
+ const clientETag = req.headers.get('If-None-Match')
229
+ if (clientETag === cached.etag) {
230
+ return new Response(null, { status: 304, headers })
231
+ }
232
+ }
233
+
234
+ return new Response(cached.body as any, {
235
+ status: cached.status,
236
+ headers,
237
+ })
238
+ }
239
+
240
+ // Execute route handler
241
+ const response = await next()
242
+
243
+ // Only cache successful responses
244
+ if (response.status >= 200 && response.status < 300) {
245
+ try {
246
+ // Clone response to cache it
247
+ const responseClone = response.clone()
248
+ const body = await responseClone.arrayBuffer()
249
+
250
+ // Generate ETag
251
+ const etag = await generateETag(body)
252
+
253
+ // Prepare headers for caching
254
+ const headers: Record<string, string> = {}
255
+ responseClone.headers.forEach((value, key) => {
256
+ headers[key] = value
257
+ })
258
+
259
+ // Create cached response
260
+ const cachedResponse: CachedResponse = {
261
+ response: responseClone as Response,
262
+ headers,
263
+ status: response.status,
264
+ body: new Uint8Array(body),
265
+ timestamp: Date.now(),
266
+ ttl: config.ttl,
267
+ tags: config.tags || [],
268
+ etag,
269
+ }
270
+
271
+ // Store in cache
272
+ await routeCacheManager.set(cacheKey, cachedResponse)
273
+
274
+ // Add cache headers to original response
275
+ const originalHeaders = new Headers(response.headers)
276
+ originalHeaders.set('X-Cache', 'MISS')
277
+ originalHeaders.set('X-Cache-Key', cacheKey)
278
+ originalHeaders.set('ETag', etag)
279
+
280
+ return new Response(response.body, {
281
+ status: response.status,
282
+ headers: originalHeaders,
283
+ })
284
+ }
285
+ catch (error) {
286
+ console.error('Error caching response:', error)
287
+ // Return original response if caching fails
288
+ return response
289
+ }
290
+ }
291
+
292
+ return response
293
+ }
294
+ }
295
+
296
+ /**
297
+ * Generate ETag from response body
298
+ */
299
+ async function generateETag(body: ArrayBuffer): Promise<string> {
300
+ const hash = await crypto.subtle.digest('SHA-256', body)
301
+ const hashArray = Array.from(new Uint8Array(hash))
302
+ const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
303
+ return `"${hashHex.substring(0, 16)}"` // Use first 16 chars for ETag
304
+ }
305
+
306
+ /**
307
+ * Factory functions for common cache configurations
308
+ */
309
+ export const RouteCacheFactory = {
310
+ /**
311
+ * Short-term cache (5 minutes)
312
+ */
313
+ short: (tags: string[] = []): RouteCacheConfig => ({
314
+ ttl: 5 * 60 * 1000, // 5 minutes
315
+ maxSize: 500,
316
+ tags,
317
+ }),
318
+
319
+ /**
320
+ * Medium-term cache (1 hour)
321
+ */
322
+ medium: (tags: string[] = []): RouteCacheConfig => ({
323
+ ttl: 60 * 60 * 1000, // 1 hour
324
+ maxSize: 1000,
325
+ tags,
326
+ }),
327
+
328
+ /**
329
+ * Long-term cache (24 hours)
330
+ */
331
+ long: (tags: string[] = []): RouteCacheConfig => ({
332
+ ttl: 24 * 60 * 60 * 1000, // 24 hours
333
+ maxSize: 2000,
334
+ tags,
335
+ }),
336
+
337
+ /**
338
+ * API response cache with common settings
339
+ */
340
+ api: (tags: string[] = []): RouteCacheConfig => ({
341
+ ttl: 15 * 60 * 1000, // 15 minutes
342
+ maxSize: 1000,
343
+ tags,
344
+ varyBy: ['Authorization', 'Accept', 'Accept-Language'],
345
+ excludeQuery: ['_t', 'timestamp', 'cache_bust'],
346
+ }),
347
+
348
+ /**
349
+ * Static content cache
350
+ */
351
+ static: (tags: string[] = []): RouteCacheConfig => ({
352
+ ttl: 7 * 24 * 60 * 60 * 1000, // 7 days
353
+ maxSize: 5000,
354
+ tags,
355
+ varyBy: ['Accept-Encoding'],
356
+ }),
357
+
358
+ /**
359
+ * User-specific cache
360
+ */
361
+ user: (tags: string[] = []): RouteCacheConfig => ({
362
+ ttl: 30 * 60 * 1000, // 30 minutes
363
+ maxSize: 2000,
364
+ tags,
365
+ varyBy: ['Authorization'],
366
+ condition: req => !!req.headers.get('Authorization'),
367
+ }),
368
+ }
369
+
370
+ /**
371
+ * Cache invalidation utilities
372
+ */
373
+ export const CacheInvalidation = {
374
+ /**
375
+ * Invalidate by tags
376
+ */
377
+ byTags: (tags: string[]): number => {
378
+ return routeCacheManager.invalidateByTags(tags)
379
+ },
380
+
381
+ /**
382
+ * Invalidate all user-related cache
383
+ */
384
+ forUser: (userId: string): number => {
385
+ return routeCacheManager.invalidateByTags([`user:${userId}`])
386
+ },
387
+
388
+ /**
389
+ * Invalidate model-related cache
390
+ */
391
+ forModel: (modelName: string, id?: string): number => {
392
+ const tags = id ? [`${modelName}:${id}`, modelName] : [modelName]
393
+ return routeCacheManager.invalidateByTags(tags)
394
+ },
395
+
396
+ /**
397
+ * Clear all cache
398
+ */
399
+ all: (): void => {
400
+ routeCacheManager.clear()
401
+ },
402
+ }