@stacksjs/bun-router 0.0.12 → 0.0.14
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/CHANGELOG.md +770 -0
- package/README.md +584 -261
- package/package.json +43 -48
- package/bin/cli.ts +0 -9
- package/dist/auth.d.ts +0 -134
- package/dist/cache/lru-cache.d.ts +0 -139
- package/dist/cache/middleware-memoization.d.ts +0 -151
- package/dist/cache/route-cache-warmer.d.ts +0 -161
- package/dist/cache/sqlite-cache.d.ts +0 -209
- package/dist/cache/streaming-cache.d.ts +0 -132
- package/dist/chunk-1mvtv6jw.js +0 -13012
- package/dist/cli/colors.d.ts +0 -15
- package/dist/cli/index.d.ts +0 -10
- package/dist/cli/middleware.d.ts +0 -31
- package/dist/cli/openapi.d.ts +0 -17
- package/dist/cli/router.d.ts +0 -15
- package/dist/cli/routes.d.ts +0 -29
- package/dist/cli/utils.d.ts +0 -74
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -3195
- package/dist/config.d.ts +0 -7
- package/dist/container/container.d.ts +0 -273
- package/dist/container/contextual-binding.d.ts +0 -240
- package/dist/container/decorators.d.ts +0 -141
- package/dist/container/service-provider.d.ts +0 -285
- package/dist/development/hot-reload.d.ts +0 -187
- package/dist/development/index.d.ts +0 -167
- package/dist/development/performance-profiler.d.ts +0 -217
- package/dist/development/route-debugger.d.ts +0 -154
- package/dist/development/route-inspector.d.ts +0 -211
- package/dist/development/typescript-utilities.d.ts +0 -209
- package/dist/docs.d.ts +0 -11
- package/dist/errors/circuit-breaker.d.ts +0 -195
- package/dist/errors/error-handler.d.ts +0 -88
- package/dist/errors/error-reporting.d.ts +0 -144
- package/dist/errors/exceptions.d.ts +0 -184
- package/dist/errors/graceful-degradation.d.ts +0 -154
- package/dist/errors/index.d.ts +0 -9
- package/dist/errors/router-errors.d.ts +0 -110
- package/dist/file-serving/static-files.d.ts +0 -143
- package/dist/index.d.ts +0 -14
- package/dist/index.js +0 -13933
- package/dist/middleware/auth.d.ts +0 -63
- package/dist/middleware/content_security_policy.d.ts +0 -53
- package/dist/middleware/cors.d.ts +0 -5
- package/dist/middleware/csrf.d.ts +0 -7
- package/dist/middleware/ddos_protection.d.ts +0 -39
- package/dist/middleware/file_security.d.ts +0 -26
- package/dist/middleware/file_upload.d.ts +0 -38
- package/dist/middleware/helmet.d.ts +0 -54
- package/dist/middleware/index.d.ts +0 -44
- package/dist/middleware/input_validation.d.ts +0 -45
- package/dist/middleware/json_body.d.ts +0 -4
- package/dist/middleware/performance_alerting.d.ts +0 -87
- package/dist/middleware/performance_dashboard.d.ts +0 -87
- package/dist/middleware/performance_monitor.d.ts +0 -209
- package/dist/middleware/pipeline.d.ts +0 -131
- package/dist/middleware/rate_limit.d.ts +0 -36
- package/dist/middleware/request_id.d.ts +0 -4
- package/dist/middleware/request_signing.d.ts +0 -153
- package/dist/middleware/request_tracer.d.ts +0 -72
- package/dist/middleware/response_cache.d.ts +0 -97
- package/dist/middleware/security.d.ts +0 -69
- package/dist/middleware/security_suite.d.ts +0 -46
- package/dist/middleware/session.d.ts +0 -23
- package/dist/model-binding/index.d.ts +0 -2
- package/dist/model-binding/model-middleware.d.ts +0 -118
- package/dist/model-binding/model-registry.d.ts +0 -164
- package/dist/model-binding.d.ts +0 -185
- package/dist/model-resolver-factory.d.ts +0 -31
- package/dist/observability/correlation.d.ts +0 -187
- package/dist/observability/health-checks.d.ts +0 -186
- package/dist/observability/index.d.ts +0 -60
- package/dist/observability/integration.d.ts +0 -147
- package/dist/observability/metrics.d.ts +0 -184
- package/dist/observability/tracing.d.ts +0 -187
- package/dist/optimization/bun-utilities.d.ts +0 -224
- package/dist/query-builder-integration.d.ts +0 -36
- package/dist/request/context.d.ts +0 -34
- package/dist/request/enhanced-request.d.ts +0 -213
- package/dist/request/macros.d.ts +0 -300
- package/dist/response/macros.d.ts +0 -245
- package/dist/response/response-factory.d.ts +0 -133
- package/dist/router/api-routes.d.ts +0 -5
- package/dist/router/file-based-routing.d.ts +0 -118
- package/dist/router/file-streaming.d.ts +0 -5
- package/dist/router/fluent-router.d.ts +0 -315
- package/dist/router/fluent-routing.d.ts +0 -271
- package/dist/router/group-organization.d.ts +0 -5
- package/dist/router/handler-resolver.d.ts +0 -24
- package/dist/router/http-methods.d.ts +0 -10
- package/dist/router/index.d.ts +0 -114
- package/dist/router/middleware-groups.d.ts +0 -94
- package/dist/router/middleware-integration.d.ts +0 -112
- package/dist/router/middleware.d.ts +0 -5
- package/dist/router/model-binding.d.ts +0 -5
- package/dist/router/optimized-route-matching.d.ts +0 -6
- package/dist/router/route-building.d.ts +0 -5
- package/dist/router/route-compiler.d.ts +0 -153
- package/dist/router/route-matching.d.ts +0 -5
- package/dist/router/route-trie.d.ts +0 -114
- package/dist/router/router.d.ts +0 -294
- package/dist/router/server.d.ts +0 -5
- package/dist/router/validation-integration.d.ts +0 -170
- package/dist/router/view-rendering.d.ts +0 -5
- package/dist/router/websocket.d.ts +0 -5
- package/dist/routing/route-caching.d.ts +0 -129
- package/dist/routing/route-throttling.d.ts +0 -150
- package/dist/routing/subdomain-routing.d.ts +0 -206
- package/dist/session/database-store.d.ts +0 -51
- package/dist/session/file-store.d.ts +0 -22
- package/dist/session/index.d.ts +0 -106
- package/dist/session/memory-store.d.ts +0 -21
- package/dist/session/redis-store.d.ts +0 -31
- package/dist/streaming/index.d.ts +0 -3
- package/dist/streaming/sse-handler.d.ts +0 -138
- package/dist/streaming/stream-handler.d.ts +0 -114
- package/dist/testing/auth-testing.d.ts +0 -156
- package/dist/testing/file-upload-testing.d.ts +0 -190
- package/dist/testing/index.d.ts +0 -10
- package/dist/testing/middleware-testing.d.ts +0 -138
- package/dist/testing/model-binding-testing.d.ts +0 -186
- package/dist/testing/performance-testing.d.ts +0 -235
- package/dist/testing/test-client.d.ts +0 -117
- package/dist/testing/test-request.d.ts +0 -85
- package/dist/testing/test-response.d.ts +0 -90
- package/dist/testing/types.d.ts +0 -207
- package/dist/testing/websocket-testing.d.ts +0 -227
- package/dist/types/controller-types.d.ts +0 -208
- package/dist/types/core.d.ts +0 -543
- package/dist/types/middleware-types.d.ts +0 -227
- package/dist/types/request-response-augmentation.d.ts +0 -261
- package/dist/types/route-inference.d.ts +0 -168
- package/dist/types.d.ts +0 -1782
- package/dist/url.d.ts +0 -56
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/query-preservation.d.ts +0 -48
- package/dist/utils.d.ts +0 -69
- package/dist/validation/validator.d.ts +0 -140
- package/dist/websocket/clustering.d.ts +0 -185
- package/src/auth.ts +0 -469
- package/src/cache/lru-cache.ts +0 -457
- package/src/cache/middleware-memoization.ts +0 -531
- package/src/cache/route-cache-warmer.ts +0 -486
- package/src/cache/sqlite-cache.ts +0 -783
- package/src/cache/streaming-cache.ts +0 -572
- package/src/cli/colors.ts +0 -29
- package/src/cli/index.ts +0 -287
- package/src/cli/middleware.ts +0 -291
- package/src/cli/openapi.ts +0 -407
- package/src/cli/router.ts +0 -188
- package/src/cli/routes.ts +0 -265
- package/src/cli/utils.ts +0 -531
- package/src/cli.ts +0 -5
- package/src/config.ts +0 -322
- package/src/container/container.ts +0 -740
- package/src/container/contextual-binding.ts +0 -603
- package/src/container/decorators.ts +0 -359
- package/src/container/service-provider.ts +0 -596
- package/src/development/hot-reload.ts +0 -673
- package/src/development/index.ts +0 -499
- package/src/development/performance-profiler.ts +0 -717
- package/src/development/route-debugger.ts +0 -527
- package/src/development/route-inspector.ts +0 -749
- package/src/development/typescript-utilities.ts +0 -682
- package/src/docs.ts +0 -397
- package/src/errors/circuit-breaker.ts +0 -732
- package/src/errors/error-handler.ts +0 -569
- package/src/errors/error-reporting.ts +0 -672
- package/src/errors/exceptions.ts +0 -536
- package/src/errors/graceful-degradation.ts +0 -621
- package/src/errors/index.ts +0 -21
- package/src/errors/router-errors.ts +0 -632
- package/src/file-serving/static-files.ts +0 -581
- package/src/index.ts +0 -14
- package/src/middleware/auth.ts +0 -219
- package/src/middleware/content_security_policy.ts +0 -215
- package/src/middleware/cors.ts +0 -74
- package/src/middleware/csrf.ts +0 -108
- package/src/middleware/ddos_protection.ts +0 -255
- package/src/middleware/file_security.ts +0 -191
- package/src/middleware/file_upload.ts +0 -264
- package/src/middleware/helmet.ts +0 -268
- package/src/middleware/index.ts +0 -117
- package/src/middleware/input_validation.ts +0 -449
- package/src/middleware/json_body.ts +0 -37
- package/src/middleware/performance_alerting.ts +0 -538
- package/src/middleware/performance_dashboard.ts +0 -661
- package/src/middleware/performance_monitor.ts +0 -943
- package/src/middleware/pipeline.ts +0 -489
- package/src/middleware/rate_limit.ts +0 -245
- package/src/middleware/request_id.ts +0 -36
- package/src/middleware/request_signing.ts +0 -636
- package/src/middleware/request_tracer.ts +0 -636
- package/src/middleware/response_cache.ts +0 -743
- package/src/middleware/security.ts +0 -482
- package/src/middleware/security_suite.ts +0 -257
- package/src/middleware/session.ts +0 -91
- package/src/model-binding/index.ts +0 -18
- package/src/model-binding/model-middleware.ts +0 -425
- package/src/model-binding/model-registry.ts +0 -550
- package/src/model-binding.ts +0 -370
- package/src/model-resolver-factory.ts +0 -106
- package/src/observability/correlation.ts +0 -691
- package/src/observability/health-checks.ts +0 -729
- package/src/observability/index.ts +0 -184
- package/src/observability/integration.ts +0 -548
- package/src/observability/metrics.ts +0 -753
- package/src/observability/tracing.ts +0 -638
- package/src/optimization/bun-utilities.ts +0 -778
- package/src/query-builder-integration.ts +0 -137
- package/src/request/context.ts +0 -62
- package/src/request/enhanced-request.ts +0 -857
- package/src/request/macros.ts +0 -688
- package/src/response/macros.ts +0 -612
- package/src/response/response-factory.ts +0 -596
- package/src/router/api-routes.ts +0 -243
- package/src/router/file-based-routing.ts +0 -670
- package/src/router/file-streaming.ts +0 -372
- package/src/router/fluent-router.ts +0 -927
- package/src/router/fluent-routing.ts +0 -797
- package/src/router/group-organization.ts +0 -213
- package/src/router/handler-resolver.ts +0 -291
- package/src/router/http-methods.ts +0 -377
- package/src/router/index.ts +0 -187
- package/src/router/middleware-groups.ts +0 -222
- package/src/router/middleware-integration.ts +0 -399
- package/src/router/middleware.ts +0 -231
- package/src/router/model-binding.ts +0 -215
- package/src/router/optimized-route-matching.ts +0 -253
- package/src/router/route-building.ts +0 -212
- package/src/router/route-compiler.ts +0 -702
- package/src/router/route-matching.ts +0 -349
- package/src/router/route-trie.ts +0 -464
- package/src/router/router.ts +0 -1581
- package/src/router/server.ts +0 -462
- package/src/router/validation-integration.ts +0 -443
- package/src/router/view-rendering.ts +0 -233
- package/src/router/websocket.ts +0 -100
- package/src/routing/route-caching.ts +0 -402
- package/src/routing/route-throttling.ts +0 -469
- package/src/routing/subdomain-routing.ts +0 -492
- package/src/session/database-store.ts +0 -109
- package/src/session/file-store.ts +0 -148
- package/src/session/index.ts +0 -244
- package/src/session/memory-store.ts +0 -88
- package/src/session/redis-store.ts +0 -93
- package/src/streaming/index.ts +0 -17
- package/src/streaming/sse-handler.ts +0 -482
- package/src/streaming/stream-handler.ts +0 -552
- package/src/testing/auth-testing.ts +0 -446
- package/src/testing/file-upload-testing.ts +0 -543
- package/src/testing/index.ts +0 -10
- package/src/testing/middleware-testing.ts +0 -322
- package/src/testing/model-binding-testing.ts +0 -645
- package/src/testing/performance-testing.ts +0 -738
- package/src/testing/test-client.ts +0 -310
- package/src/testing/test-request.ts +0 -315
- package/src/testing/test-response.ts +0 -332
- package/src/testing/types.ts +0 -224
- package/src/testing/websocket-testing.ts +0 -590
- package/src/types/controller-types.ts +0 -385
- package/src/types/core.ts +0 -683
- package/src/types/middleware-types.ts +0 -419
- package/src/types/request-response-augmentation.ts +0 -489
- package/src/types/route-inference.ts +0 -357
- package/src/types.ts +0 -2055
- package/src/url.ts +0 -126
- package/src/utils/index.ts +0 -1
- package/src/utils/query-preservation.ts +0 -201
- package/src/utils.ts +0 -327
- package/src/validation/validator.ts +0 -685
- package/src/websocket/clustering.ts +0 -762
|
@@ -1,572 +0,0 @@
|
|
|
1
|
-
import type { LRUCacheOptions } from './lru-cache'
|
|
2
|
-
import { LRUCache } from './lru-cache'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Response streaming cache for large responses
|
|
6
|
-
* Optimized for handling large payloads with memory-efficient streaming
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
export interface StreamingCacheOptions extends Omit<LRUCacheOptions, 'maxSize'> {
|
|
10
|
-
maxSize: number // Maximum number of cached responses
|
|
11
|
-
maxResponseSize: number // Maximum size of individual response in bytes
|
|
12
|
-
chunkSize: number // Size of chunks for streaming
|
|
13
|
-
compressionEnabled: boolean // Enable gzip compression
|
|
14
|
-
compressionThreshold: number // Minimum size to trigger compression
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface CachedResponse {
|
|
18
|
-
status: number
|
|
19
|
-
statusText: string
|
|
20
|
-
headers: Record<string, string>
|
|
21
|
-
body: Uint8Array | null
|
|
22
|
-
compressed: boolean
|
|
23
|
-
originalSize: number
|
|
24
|
-
timestamp: number
|
|
25
|
-
etag?: string
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface StreamingCacheStats {
|
|
29
|
-
totalResponses: number
|
|
30
|
-
totalSize: number
|
|
31
|
-
compressionRatio: number
|
|
32
|
-
averageResponseSize: number
|
|
33
|
-
largestResponse: number
|
|
34
|
-
streamingHits: number
|
|
35
|
-
streamingMisses: number
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* High-performance streaming cache for large HTTP responses
|
|
40
|
-
*/
|
|
41
|
-
export class StreamingCache {
|
|
42
|
-
private cache: LRUCache<CachedResponse>
|
|
43
|
-
private stats: StreamingCacheStats = {
|
|
44
|
-
totalResponses: 0,
|
|
45
|
-
totalSize: 0,
|
|
46
|
-
compressionRatio: 0,
|
|
47
|
-
averageResponseSize: 0,
|
|
48
|
-
largestResponse: 0,
|
|
49
|
-
streamingHits: 0,
|
|
50
|
-
streamingMisses: 0,
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
constructor(private options: StreamingCacheOptions) {
|
|
54
|
-
this.cache = new LRUCache<CachedResponse>({
|
|
55
|
-
maxSize: options.maxSize,
|
|
56
|
-
ttl: options.ttl,
|
|
57
|
-
onEvict: (key, cachedResponse) => {
|
|
58
|
-
this.updateStatsOnEviction(cachedResponse)
|
|
59
|
-
},
|
|
60
|
-
updateAgeOnGet: options.updateAgeOnGet,
|
|
61
|
-
})
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Cache a response with streaming support
|
|
66
|
-
*/
|
|
67
|
-
async cacheResponse(
|
|
68
|
-
key: string,
|
|
69
|
-
response: Response,
|
|
70
|
-
options: {
|
|
71
|
-
ttl?: number
|
|
72
|
-
forceCache?: boolean
|
|
73
|
-
generateETag?: boolean
|
|
74
|
-
} = {},
|
|
75
|
-
): Promise<void> {
|
|
76
|
-
// Check response size before caching
|
|
77
|
-
const contentLength = response.headers.get('content-length')
|
|
78
|
-
const responseSize = contentLength ? Number.parseInt(contentLength, 10) : 0
|
|
79
|
-
|
|
80
|
-
if (!options.forceCache && responseSize > this.options.maxResponseSize) {
|
|
81
|
-
return // Skip caching if response is too large
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
try {
|
|
85
|
-
// Read response body
|
|
86
|
-
const bodyBuffer = await response.arrayBuffer()
|
|
87
|
-
const bodyArray = new Uint8Array(bodyBuffer)
|
|
88
|
-
const originalSize = bodyArray.length
|
|
89
|
-
|
|
90
|
-
// Apply compression if enabled and size threshold is met
|
|
91
|
-
let finalBody = bodyArray
|
|
92
|
-
let compressed = false
|
|
93
|
-
|
|
94
|
-
if (
|
|
95
|
-
this.options.compressionEnabled
|
|
96
|
-
&& originalSize >= this.options.compressionThreshold
|
|
97
|
-
) {
|
|
98
|
-
finalBody = await this.compressData(bodyArray) as Uint8Array<ArrayBuffer>
|
|
99
|
-
compressed = true
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Generate ETag if requested
|
|
103
|
-
let etag: string | undefined
|
|
104
|
-
if (options.generateETag) {
|
|
105
|
-
etag = await this.generateETag(bodyArray)
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Create cached response
|
|
109
|
-
const cachedResponse: CachedResponse = {
|
|
110
|
-
status: response.status,
|
|
111
|
-
statusText: response.statusText,
|
|
112
|
-
headers: this.extractHeaders(response),
|
|
113
|
-
body: finalBody,
|
|
114
|
-
compressed,
|
|
115
|
-
originalSize,
|
|
116
|
-
timestamp: Date.now(),
|
|
117
|
-
etag,
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Cache the response
|
|
121
|
-
this.cache.set(key, cachedResponse, options.ttl)
|
|
122
|
-
|
|
123
|
-
// Update statistics
|
|
124
|
-
this.updateStatsOnCache(originalSize, compressed ? finalBody.length : originalSize)
|
|
125
|
-
}
|
|
126
|
-
catch (error) {
|
|
127
|
-
console.warn('Failed to cache response:', error)
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Get cached response as a streaming response
|
|
133
|
-
*/
|
|
134
|
-
async getStreamingResponse(key: string): Promise<Response | null> {
|
|
135
|
-
const cachedResponse = this.cache.get(key)
|
|
136
|
-
|
|
137
|
-
if (!cachedResponse) {
|
|
138
|
-
this.stats.streamingMisses++
|
|
139
|
-
return null
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
this.stats.streamingHits++
|
|
143
|
-
|
|
144
|
-
try {
|
|
145
|
-
// Decompress if necessary
|
|
146
|
-
let body = cachedResponse.body
|
|
147
|
-
if (body && cachedResponse.compressed) {
|
|
148
|
-
body = await this.decompressData(body)
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Create headers
|
|
152
|
-
const headers = new Headers(cachedResponse.headers)
|
|
153
|
-
|
|
154
|
-
// Add cache-related headers
|
|
155
|
-
headers.set('X-Cache', 'HIT')
|
|
156
|
-
headers.set('X-Cache-Timestamp', cachedResponse.timestamp.toString())
|
|
157
|
-
|
|
158
|
-
if (cachedResponse.etag) {
|
|
159
|
-
headers.set('ETag', cachedResponse.etag)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Create streaming response
|
|
163
|
-
if (body && body.length > this.options.chunkSize) {
|
|
164
|
-
return this.createStreamingResponse(body, cachedResponse, headers)
|
|
165
|
-
}
|
|
166
|
-
else {
|
|
167
|
-
// Small response, return directly
|
|
168
|
-
return new Response(body as any, {
|
|
169
|
-
status: cachedResponse.status,
|
|
170
|
-
statusText: cachedResponse.statusText,
|
|
171
|
-
headers,
|
|
172
|
-
})
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
catch (error) {
|
|
176
|
-
console.warn('Failed to create streaming response:', error)
|
|
177
|
-
return null
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Check if response should be cached based on headers and size
|
|
183
|
-
*/
|
|
184
|
-
shouldCache(response: Response): boolean {
|
|
185
|
-
// Don't cache error responses
|
|
186
|
-
if (response.status >= 400)
|
|
187
|
-
return false
|
|
188
|
-
|
|
189
|
-
// Don't cache if explicitly marked as no-cache
|
|
190
|
-
const cacheControl = response.headers.get('cache-control')
|
|
191
|
-
if (cacheControl?.includes('no-cache') || cacheControl?.includes('no-store')) {
|
|
192
|
-
return false
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// Check content type (only cache specific types)
|
|
196
|
-
const contentType = response.headers.get('content-type')
|
|
197
|
-
if (contentType) {
|
|
198
|
-
const cachableTypes = [
|
|
199
|
-
'application/json',
|
|
200
|
-
'text/html',
|
|
201
|
-
'text/plain',
|
|
202
|
-
'text/css',
|
|
203
|
-
'application/javascript',
|
|
204
|
-
'image/',
|
|
205
|
-
'video/',
|
|
206
|
-
'audio/',
|
|
207
|
-
]
|
|
208
|
-
|
|
209
|
-
if (!cachableTypes.some(type => contentType.includes(type))) {
|
|
210
|
-
return false
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
return true
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Warm cache with common routes
|
|
219
|
-
*/
|
|
220
|
-
async warmCache(routes: Array<{
|
|
221
|
-
key: string
|
|
222
|
-
url: string
|
|
223
|
-
method?: string
|
|
224
|
-
headers?: Record<string, string>
|
|
225
|
-
}>): Promise<number> {
|
|
226
|
-
let warmedCount = 0
|
|
227
|
-
|
|
228
|
-
for (const route of routes) {
|
|
229
|
-
try {
|
|
230
|
-
const response = await fetch(route.url, {
|
|
231
|
-
method: route.method || 'GET',
|
|
232
|
-
headers: route.headers,
|
|
233
|
-
})
|
|
234
|
-
|
|
235
|
-
if (this.shouldCache(response)) {
|
|
236
|
-
await this.cacheResponse(route.key, response, {
|
|
237
|
-
forceCache: true,
|
|
238
|
-
generateETag: true,
|
|
239
|
-
})
|
|
240
|
-
warmedCount++
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
catch (error) {
|
|
244
|
-
console.warn(`Failed to warm cache for ${route.key}:`, error)
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
return warmedCount
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Create conditional response based on ETag
|
|
253
|
-
*/
|
|
254
|
-
createConditionalResponse(key: string, ifNoneMatch?: string): Response | null {
|
|
255
|
-
const cachedResponse = this.cache.get(key)
|
|
256
|
-
|
|
257
|
-
if (!cachedResponse || !cachedResponse.etag) {
|
|
258
|
-
return null
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
if (ifNoneMatch === cachedResponse.etag) {
|
|
262
|
-
return new Response(null, {
|
|
263
|
-
status: 304,
|
|
264
|
-
statusText: 'Not Modified',
|
|
265
|
-
headers: {
|
|
266
|
-
'ETag': cachedResponse.etag,
|
|
267
|
-
'X-Cache': 'HIT-304',
|
|
268
|
-
},
|
|
269
|
-
})
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
return null
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Get cache statistics
|
|
277
|
-
*/
|
|
278
|
-
getStats(): StreamingCacheStats & { lruStats: any } {
|
|
279
|
-
return {
|
|
280
|
-
...this.stats,
|
|
281
|
-
lruStats: this.cache.getStats(),
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Clear cache and reset statistics
|
|
287
|
-
*/
|
|
288
|
-
clear(): void {
|
|
289
|
-
this.cache.clear()
|
|
290
|
-
this.stats = {
|
|
291
|
-
totalResponses: 0,
|
|
292
|
-
totalSize: 0,
|
|
293
|
-
compressionRatio: 0,
|
|
294
|
-
averageResponseSize: 0,
|
|
295
|
-
largestResponse: 0,
|
|
296
|
-
streamingHits: 0,
|
|
297
|
-
streamingMisses: 0,
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Prune expired entries
|
|
303
|
-
*/
|
|
304
|
-
prune(): number {
|
|
305
|
-
return this.cache.prune()
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* Create streaming response for large payloads
|
|
310
|
-
*/
|
|
311
|
-
private createStreamingResponse(
|
|
312
|
-
body: Uint8Array,
|
|
313
|
-
cachedResponse: CachedResponse,
|
|
314
|
-
headers: Headers,
|
|
315
|
-
): Response {
|
|
316
|
-
const chunkSize = this.options.chunkSize
|
|
317
|
-
let offset = 0
|
|
318
|
-
|
|
319
|
-
const stream = new ReadableStream({
|
|
320
|
-
start(_controller) {
|
|
321
|
-
// Set content length
|
|
322
|
-
headers.set('Content-Length', body.length.toString())
|
|
323
|
-
},
|
|
324
|
-
|
|
325
|
-
pull(controller) {
|
|
326
|
-
if (offset >= body.length) {
|
|
327
|
-
controller.close()
|
|
328
|
-
return
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
const chunk = body.slice(offset, offset + chunkSize)
|
|
332
|
-
controller.enqueue(chunk)
|
|
333
|
-
offset += chunkSize
|
|
334
|
-
},
|
|
335
|
-
})
|
|
336
|
-
|
|
337
|
-
return new Response(stream, {
|
|
338
|
-
status: cachedResponse.status,
|
|
339
|
-
statusText: cachedResponse.statusText,
|
|
340
|
-
headers,
|
|
341
|
-
})
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* Extract headers from response (excluding hop-by-hop headers)
|
|
346
|
-
*/
|
|
347
|
-
private extractHeaders(response: Response): Record<string, string> {
|
|
348
|
-
const headers: Record<string, string> = {}
|
|
349
|
-
const hopByHopHeaders = new Set([
|
|
350
|
-
'connection',
|
|
351
|
-
'keep-alive',
|
|
352
|
-
'proxy-authenticate',
|
|
353
|
-
'proxy-authorization',
|
|
354
|
-
'te',
|
|
355
|
-
'trailers',
|
|
356
|
-
'transfer-encoding',
|
|
357
|
-
'upgrade',
|
|
358
|
-
])
|
|
359
|
-
|
|
360
|
-
for (const [key, value] of response.headers.entries()) {
|
|
361
|
-
if (!hopByHopHeaders.has(key.toLowerCase())) {
|
|
362
|
-
headers[key] = value
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
return headers
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* Compress data using gzip
|
|
371
|
-
*/
|
|
372
|
-
private async compressData(data: Uint8Array): Promise<Uint8Array> {
|
|
373
|
-
try {
|
|
374
|
-
// Use Bun's built-in compression if available
|
|
375
|
-
if (typeof Bun !== 'undefined' && Bun.gzipSync) {
|
|
376
|
-
const compressed = Bun.gzipSync(new Uint8Array(data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength) as ArrayBuffer))
|
|
377
|
-
return new Uint8Array(compressed.buffer.slice(compressed.byteOffset, compressed.byteOffset + compressed.byteLength) as ArrayBuffer) as Uint8Array<ArrayBuffer>
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
// Fallback to CompressionStream API
|
|
381
|
-
const stream = new CompressionStream('gzip')
|
|
382
|
-
const writer = stream.writable.getWriter()
|
|
383
|
-
const reader = stream.readable.getReader()
|
|
384
|
-
|
|
385
|
-
writer.write(data as Uint8Array<ArrayBuffer>)
|
|
386
|
-
writer.close()
|
|
387
|
-
|
|
388
|
-
const chunks: Uint8Array[] = []
|
|
389
|
-
let result = await reader.read()
|
|
390
|
-
|
|
391
|
-
while (!result.done) {
|
|
392
|
-
chunks.push(result.value)
|
|
393
|
-
result = await reader.read()
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// Combine chunks
|
|
397
|
-
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0)
|
|
398
|
-
const compressed = new Uint8Array(totalLength)
|
|
399
|
-
let offset = 0
|
|
400
|
-
|
|
401
|
-
for (const chunk of chunks) {
|
|
402
|
-
compressed.set(chunk, offset)
|
|
403
|
-
offset += chunk.length
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
return compressed
|
|
407
|
-
}
|
|
408
|
-
catch (error) {
|
|
409
|
-
console.warn('Compression failed, using original data:', error)
|
|
410
|
-
return data
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
/**
|
|
415
|
-
* Decompress data using gzip
|
|
416
|
-
*/
|
|
417
|
-
private async decompressData(data: Uint8Array): Promise<Uint8Array> {
|
|
418
|
-
try {
|
|
419
|
-
// Use Bun's built-in decompression if available
|
|
420
|
-
if (typeof Bun !== 'undefined' && Bun.gunzipSync) {
|
|
421
|
-
const decompressed = Bun.gunzipSync(new Uint8Array(data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength) as ArrayBuffer))
|
|
422
|
-
return new Uint8Array(decompressed.buffer.slice(decompressed.byteOffset, decompressed.byteOffset + decompressed.byteLength) as ArrayBuffer) as Uint8Array<ArrayBuffer>
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
// Fallback to DecompressionStream API
|
|
426
|
-
const stream = new DecompressionStream('gzip')
|
|
427
|
-
const writer = stream.writable.getWriter()
|
|
428
|
-
const reader = stream.readable.getReader()
|
|
429
|
-
|
|
430
|
-
writer.write(data as Uint8Array<ArrayBuffer>)
|
|
431
|
-
writer.close()
|
|
432
|
-
|
|
433
|
-
const chunks: Uint8Array[] = []
|
|
434
|
-
let result = await reader.read()
|
|
435
|
-
|
|
436
|
-
while (!result.done) {
|
|
437
|
-
chunks.push(result.value)
|
|
438
|
-
result = await reader.read()
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
// Combine chunks
|
|
442
|
-
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0)
|
|
443
|
-
const decompressed = new Uint8Array(totalLength)
|
|
444
|
-
let offset = 0
|
|
445
|
-
|
|
446
|
-
for (const chunk of chunks) {
|
|
447
|
-
decompressed.set(chunk, offset)
|
|
448
|
-
offset += chunk.length
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
return decompressed
|
|
452
|
-
}
|
|
453
|
-
catch (error) {
|
|
454
|
-
console.warn('Decompression failed:', error)
|
|
455
|
-
return data
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
/**
|
|
460
|
-
* Generate ETag for response body
|
|
461
|
-
*/
|
|
462
|
-
private async generateETag(data: Uint8Array): Promise<string> {
|
|
463
|
-
try {
|
|
464
|
-
// Use Bun's built-in hashing if available
|
|
465
|
-
if (typeof Bun !== 'undefined' && Bun.hash) {
|
|
466
|
-
const hash = Bun.hash(data)
|
|
467
|
-
return `"${hash.toString(16)}"`
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
// Fallback to Web Crypto API
|
|
471
|
-
const hashBuffer = await crypto.subtle.digest('SHA-256', data as Uint8Array<ArrayBuffer>)
|
|
472
|
-
const hashArray = new Uint8Array(hashBuffer)
|
|
473
|
-
const hashHex = Array.from(hashArray)
|
|
474
|
-
.map(b => b.toString(16).padStart(2, '0'))
|
|
475
|
-
.join('')
|
|
476
|
-
|
|
477
|
-
return `"${hashHex.slice(0, 16)}"` // Use first 16 characters
|
|
478
|
-
}
|
|
479
|
-
catch {
|
|
480
|
-
// Simple fallback hash
|
|
481
|
-
let hash = 0
|
|
482
|
-
for (let i = 0; i < data.length; i++) {
|
|
483
|
-
hash = ((hash << 5) - hash + data[i]) & 0xFFFFFFFF
|
|
484
|
-
}
|
|
485
|
-
return `"${Math.abs(hash).toString(16)}"`
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
/**
|
|
490
|
-
* Update statistics when caching a response
|
|
491
|
-
*/
|
|
492
|
-
private updateStatsOnCache(originalSize: number, compressedSize: number): void {
|
|
493
|
-
this.stats.totalResponses++
|
|
494
|
-
this.stats.totalSize += compressedSize
|
|
495
|
-
this.stats.largestResponse = Math.max(this.stats.largestResponse, originalSize)
|
|
496
|
-
this.stats.averageResponseSize = this.stats.totalSize / this.stats.totalResponses
|
|
497
|
-
|
|
498
|
-
if (originalSize > 0) {
|
|
499
|
-
const currentRatio = compressedSize / originalSize
|
|
500
|
-
this.stats.compressionRatio
|
|
501
|
-
= (this.stats.compressionRatio * (this.stats.totalResponses - 1) + currentRatio)
|
|
502
|
-
/ this.stats.totalResponses
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
/**
|
|
507
|
-
* Update statistics when evicting a response
|
|
508
|
-
*/
|
|
509
|
-
private updateStatsOnEviction(cachedResponse: CachedResponse): void {
|
|
510
|
-
if (cachedResponse.body) {
|
|
511
|
-
this.stats.totalSize -= cachedResponse.body.length
|
|
512
|
-
this.stats.totalResponses--
|
|
513
|
-
|
|
514
|
-
if (this.stats.totalResponses > 0) {
|
|
515
|
-
this.stats.averageResponseSize = this.stats.totalSize / this.stats.totalResponses
|
|
516
|
-
}
|
|
517
|
-
else {
|
|
518
|
-
this.stats.averageResponseSize = 0
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
/**
|
|
525
|
-
* Factory functions for creating streaming caches with common configurations
|
|
526
|
-
*/
|
|
527
|
-
export const createStreamingCache = {
|
|
528
|
-
/**
|
|
529
|
-
* Create cache optimized for API responses
|
|
530
|
-
*/
|
|
531
|
-
api: (maxSize: number = 1000): StreamingCache =>
|
|
532
|
-
new StreamingCache({
|
|
533
|
-
maxSize,
|
|
534
|
-
maxResponseSize: 10 * 1024 * 1024, // 10MB
|
|
535
|
-
chunkSize: 64 * 1024, // 64KB chunks
|
|
536
|
-
compressionEnabled: true,
|
|
537
|
-
compressionThreshold: 1024, // 1KB
|
|
538
|
-
ttl: 5 * 60 * 1000, // 5 minutes
|
|
539
|
-
}),
|
|
540
|
-
|
|
541
|
-
/**
|
|
542
|
-
* Create cache optimized for static assets
|
|
543
|
-
*/
|
|
544
|
-
assets: (maxSize: number = 500): StreamingCache =>
|
|
545
|
-
new StreamingCache({
|
|
546
|
-
maxSize,
|
|
547
|
-
maxResponseSize: 50 * 1024 * 1024, // 50MB
|
|
548
|
-
chunkSize: 256 * 1024, // 256KB chunks
|
|
549
|
-
compressionEnabled: true,
|
|
550
|
-
compressionThreshold: 10 * 1024, // 10KB
|
|
551
|
-
ttl: 60 * 60 * 1000, // 1 hour
|
|
552
|
-
}),
|
|
553
|
-
|
|
554
|
-
/**
|
|
555
|
-
* Create cache optimized for HTML pages
|
|
556
|
-
*/
|
|
557
|
-
pages: (maxSize: number = 2000): StreamingCache =>
|
|
558
|
-
new StreamingCache({
|
|
559
|
-
maxSize,
|
|
560
|
-
maxResponseSize: 5 * 1024 * 1024, // 5MB
|
|
561
|
-
chunkSize: 32 * 1024, // 32KB chunks
|
|
562
|
-
compressionEnabled: true,
|
|
563
|
-
compressionThreshold: 512, // 512 bytes
|
|
564
|
-
ttl: 10 * 60 * 1000, // 10 minutes
|
|
565
|
-
}),
|
|
566
|
-
|
|
567
|
-
/**
|
|
568
|
-
* Create custom configured streaming cache
|
|
569
|
-
*/
|
|
570
|
-
custom: (options: StreamingCacheOptions): StreamingCache =>
|
|
571
|
-
new StreamingCache(options),
|
|
572
|
-
}
|
package/src/cli/colors.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Simple color utility for CLI output without external dependencies
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
const colors = {
|
|
6
|
-
reset: '\x1B[0m',
|
|
7
|
-
bold: '\x1B[1m',
|
|
8
|
-
dim: '\x1B[2m',
|
|
9
|
-
red: '\x1B[31m',
|
|
10
|
-
green: '\x1B[32m',
|
|
11
|
-
yellow: '\x1B[33m',
|
|
12
|
-
blue: '\x1B[34m',
|
|
13
|
-
cyan: '\x1B[36m',
|
|
14
|
-
white: '\x1B[37m',
|
|
15
|
-
gray: '\x1B[90m',
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const chalk = {
|
|
19
|
-
red: (text: string) => `${colors.red}${text}${colors.reset}`,
|
|
20
|
-
green: (text: string) => `${colors.green}${text}${colors.reset}`,
|
|
21
|
-
yellow: (text: string) => `${colors.yellow}${text}${colors.reset}`,
|
|
22
|
-
blue: (text: string) => `${colors.blue}${text}${colors.reset}`,
|
|
23
|
-
cyan: (text: string) => `${colors.cyan}${text}${colors.reset}`,
|
|
24
|
-
white: (text: string) => `${colors.white}${text}${colors.reset}`,
|
|
25
|
-
gray: (text: string) => `${colors.gray}${text}${colors.reset}`,
|
|
26
|
-
bold: (text: string) => `${colors.bold}${text}${colors.reset}`,
|
|
27
|
-
dim: (text: string) => `${colors.dim}${text}${colors.reset}`,
|
|
28
|
-
hex: (_color: string) => (text: string): string => text, // Simple passthrough for hex colors (color param ignored)
|
|
29
|
-
}
|