@stacksjs/bun-router 0.0.2
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/LICENSE.md +21 -0
- package/README.md +397 -0
- package/bin/cli.ts +9 -0
- package/dist/auth.d.ts +77 -0
- package/dist/cache/lru-cache.d.ts +88 -0
- package/dist/cache/middleware-memoization.d.ts +101 -0
- package/dist/cache/route-cache-warmer.d.ts +125 -0
- package/dist/cache/sqlite-cache.d.ts +114 -0
- package/dist/cache/streaming-cache.d.ts +86 -0
- package/dist/chunk-r15a48wc.js +25448 -0
- package/dist/cli/colors.d.ts +12 -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 +30 -0
- package/dist/cli/utils.d.ts +68 -0
- package/dist/cli.d.ts +0 -0
- package/dist/cli.js +3195 -0
- package/dist/config.d.ts +274 -0
- package/dist/container/container.d.ts +141 -0
- package/dist/container/contextual-binding.d.ts +112 -0
- package/dist/container/decorators.d.ts +114 -0
- package/dist/container/service-provider.d.ts +221 -0
- package/dist/development/hot-reload.d.ts +129 -0
- package/dist/development/index.d.ts +144 -0
- package/dist/development/performance-profiler.d.ts +152 -0
- package/dist/development/route-debugger.d.ts +102 -0
- package/dist/development/route-inspector.d.ts +142 -0
- package/dist/development/typescript-utilities.d.ts +116 -0
- package/dist/docs.d.ts +10 -0
- package/dist/errors/circuit-breaker.d.ts +138 -0
- package/dist/errors/error-handler.d.ts +57 -0
- package/dist/errors/error-reporting.d.ts +135 -0
- package/dist/errors/exceptions.d.ts +178 -0
- package/dist/errors/graceful-degradation.d.ts +130 -0
- package/dist/errors/index.d.ts +6 -0
- package/dist/errors/router-errors.d.ts +97 -0
- package/dist/file-serving/static-files.d.ts +98 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +13417 -0
- package/dist/middleware/auth.d.ts +34 -0
- package/dist/middleware/content_security_policy.d.ts +54 -0
- package/dist/middleware/cors.d.ts +5 -0
- package/dist/middleware/csrf.d.ts +7 -0
- package/dist/middleware/ddos_protection.d.ts +47 -0
- package/dist/middleware/file_security.d.ts +23 -0
- package/dist/middleware/file_upload.d.ts +41 -0
- package/dist/middleware/helmet.d.ts +54 -0
- package/dist/middleware/index.d.ts +55 -0
- package/dist/middleware/input_validation.d.ts +46 -0
- package/dist/middleware/json_body.d.ts +4 -0
- package/dist/middleware/performance_alerting.d.ts +88 -0
- package/dist/middleware/performance_dashboard.d.ts +97 -0
- package/dist/middleware/performance_monitor.d.ts +236 -0
- package/dist/middleware/pipeline.d.ts +90 -0
- package/dist/middleware/rate_limit.d.ts +33 -0
- package/dist/middleware/request_id.d.ts +4 -0
- package/dist/middleware/request_signing.d.ts +96 -0
- package/dist/middleware/request_tracer.d.ts +76 -0
- package/dist/middleware/response_cache.d.ts +90 -0
- package/dist/middleware/security.d.ts +70 -0
- package/dist/middleware/security_suite.d.ts +46 -0
- package/dist/middleware/session.d.ts +7 -0
- package/dist/model-binding/index.d.ts +17 -0
- package/dist/model-binding/model-middleware.d.ts +80 -0
- package/dist/model-binding/model-registry.d.ts +125 -0
- package/dist/model-binding.d.ts +123 -0
- package/dist/model-resolver-factory.d.ts +31 -0
- package/dist/observability/correlation.d.ts +131 -0
- package/dist/observability/health-checks.d.ts +129 -0
- package/dist/observability/index.d.ts +92 -0
- package/dist/observability/integration.d.ts +112 -0
- package/dist/observability/metrics.d.ts +135 -0
- package/dist/observability/tracing.d.ts +112 -0
- package/dist/optimization/bun-utilities.d.ts +106 -0
- package/dist/query-builder-integration.d.ts +24 -0
- package/dist/request/enhanced-request.d.ts +143 -0
- package/dist/request/macros.d.ts +267 -0
- package/dist/response/macros.d.ts +207 -0
- package/dist/response/response-factory.d.ts +93 -0
- package/dist/router/file-based-routing.d.ts +40 -0
- package/dist/router/file-streaming.d.ts +6 -0
- package/dist/router/fluent-router.d.ts +179 -0
- package/dist/router/fluent-routing.d.ts +198 -0
- package/dist/router/group-organization.d.ts +5 -0
- package/dist/router/handler-resolver.d.ts +13 -0
- package/dist/router/http-methods.d.ts +10 -0
- package/dist/router/index.d.ts +114 -0
- package/dist/router/middleware-integration.d.ts +86 -0
- package/dist/router/middleware.d.ts +5 -0
- package/dist/router/model-binding.d.ts +7 -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 +67 -0
- package/dist/router/route-matching.d.ts +5 -0
- package/dist/router/route-trie.d.ts +69 -0
- package/dist/router/router.d.ts +133 -0
- package/dist/router/server.d.ts +5 -0
- package/dist/router/validation-integration.d.ts +116 -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 +105 -0
- package/dist/routing/route-throttling.d.ts +112 -0
- package/dist/routing/subdomain-routing.d.ts +159 -0
- package/dist/streaming/index.d.ts +15 -0
- package/dist/streaming/sse-handler.d.ts +81 -0
- package/dist/streaming/stream-handler.d.ts +81 -0
- package/dist/testing/auth-testing.d.ts +107 -0
- package/dist/testing/file-upload-testing.d.ts +139 -0
- package/dist/testing/index.d.ts +10 -0
- package/dist/testing/middleware-testing.d.ts +99 -0
- package/dist/testing/model-binding-testing.d.ts +132 -0
- package/dist/testing/performance-testing.d.ts +202 -0
- package/dist/testing/test-client.d.ts +58 -0
- package/dist/testing/test-request.d.ts +43 -0
- package/dist/testing/test-response.d.ts +45 -0
- package/dist/testing/types.d.ts +206 -0
- package/dist/testing/websocket-testing.d.ts +170 -0
- package/dist/types/controller-types.d.ts +303 -0
- package/dist/types/core.d.ts +526 -0
- package/dist/types/middleware-types.d.ts +315 -0
- package/dist/types/request-response-augmentation.d.ts +373 -0
- package/dist/types/route-inference.d.ts +287 -0
- package/dist/types.d.ts +1620 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/query-preservation.d.ts +31 -0
- package/dist/utils.d.ts +69 -0
- package/dist/validation/validator.d.ts +169 -0
- package/dist/websocket/clustering.d.ts +114 -0
- package/package.json +81 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Open Web Foundation
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
# @bun-router
|
|
2
|
+
|
|
3
|
+
A Laravel-inspired router for Bun applications.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Laravel-style routing API
|
|
8
|
+
- Support for route parameters
|
|
9
|
+
- Route grouping
|
|
10
|
+
- Action class support
|
|
11
|
+
- Middleware support (global and route-specific)
|
|
12
|
+
- Built on top of Bun's native HTTP server
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
bun add @bun-router
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Basic Usage
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { route } from '@bun-router'
|
|
24
|
+
|
|
25
|
+
// Basic route with inline handler
|
|
26
|
+
route.get('/', () => new Response('Hello World!'))
|
|
27
|
+
|
|
28
|
+
// Route with parameters
|
|
29
|
+
route.get('/users/{id}', (req) => {
|
|
30
|
+
const { id } = req.params
|
|
31
|
+
return Response.json({ userId: id })
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
// Route with action class
|
|
35
|
+
route.post('/subscribe', 'Actions/SubscribeAction')
|
|
36
|
+
|
|
37
|
+
// Route grouping
|
|
38
|
+
route.group({ prefix: '/api' }, () => {
|
|
39
|
+
route.get('/users', 'Actions/User/IndexAction')
|
|
40
|
+
route.post('/users', 'Actions/User/StoreAction')
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
// Health check route
|
|
44
|
+
route.health()
|
|
45
|
+
|
|
46
|
+
// Start the server
|
|
47
|
+
route.serve({
|
|
48
|
+
port: 3000,
|
|
49
|
+
})
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Action Classes
|
|
53
|
+
|
|
54
|
+
Action classes provide a clean way to organize your route handlers. Create a class that implements a `handle` method:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
// actions/subscribe_action.ts
|
|
58
|
+
import type { EnhancedRequest } from '@bun-router'
|
|
59
|
+
|
|
60
|
+
export default class SubscribeAction {
|
|
61
|
+
async handle(request: EnhancedRequest): Promise<Response> {
|
|
62
|
+
const data = await request.json()
|
|
63
|
+
|
|
64
|
+
// Handle subscription logic
|
|
65
|
+
|
|
66
|
+
return Response.json({
|
|
67
|
+
success: true,
|
|
68
|
+
message: 'Subscribed successfully'
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Middleware
|
|
75
|
+
|
|
76
|
+
Middleware allows you to run code before your route handlers. You can use middleware globally or for specific routes/groups.
|
|
77
|
+
|
|
78
|
+
### Creating Middleware
|
|
79
|
+
|
|
80
|
+
Create a middleware class that implements the `handle` method:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
// middleware/auth.ts
|
|
84
|
+
import type { EnhancedRequest, Middleware, NextFunction } from '@bun-router'
|
|
85
|
+
|
|
86
|
+
export default class AuthMiddleware implements Middleware {
|
|
87
|
+
async handle(req: EnhancedRequest, next: NextFunction): Promise<Response> {
|
|
88
|
+
const authHeader = req.headers.get('Authorization')
|
|
89
|
+
|
|
90
|
+
if (!authHeader) {
|
|
91
|
+
return new Response('Unauthorized', { status: 401 })
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// If auth passes, continue to next middleware or route handler
|
|
95
|
+
return next()
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Using Middleware
|
|
101
|
+
|
|
102
|
+
You can use middleware in several ways:
|
|
103
|
+
|
|
104
|
+
1. Global Middleware (applies to all routes):
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
route.use('Middleware/Auth')
|
|
108
|
+
route.use('Middleware/Logger')
|
|
109
|
+
|
|
110
|
+
// Or with inline middleware
|
|
111
|
+
route.use(async (req, next) => {
|
|
112
|
+
console.log(`${req.method} ${req.url}`)
|
|
113
|
+
return next()
|
|
114
|
+
})
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
2. Group Middleware (applies to all routes in a group):
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
route.group({
|
|
121
|
+
prefix: '/api',
|
|
122
|
+
middleware: ['Middleware/Auth']
|
|
123
|
+
}, () => {
|
|
124
|
+
route.get('/users', 'Actions/User/IndexAction')
|
|
125
|
+
route.post('/users', 'Actions/User/StoreAction')
|
|
126
|
+
})
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
3. Inline Middleware:
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
route.group({
|
|
133
|
+
middleware: [
|
|
134
|
+
async (req, next) => {
|
|
135
|
+
console.log('Processing request...')
|
|
136
|
+
const response = await next()
|
|
137
|
+
console.log('Request complete')
|
|
138
|
+
return response
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
}, () => {
|
|
142
|
+
route.get('/users', 'Actions/User/IndexAction')
|
|
143
|
+
})
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Route Groups
|
|
147
|
+
|
|
148
|
+
Group related routes with a common prefix and middleware:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
route.group({
|
|
152
|
+
prefix: '/api/v1',
|
|
153
|
+
middleware: ['Middleware/Auth', 'Middleware/RateLimit']
|
|
154
|
+
}, () => {
|
|
155
|
+
// All routes here will be prefixed with /api/v1
|
|
156
|
+
route.get('/users', 'Actions/User/IndexAction')
|
|
157
|
+
route.post('/users', 'Actions/User/StoreAction')
|
|
158
|
+
|
|
159
|
+
// Nested groups
|
|
160
|
+
route.group({
|
|
161
|
+
prefix: '/admin',
|
|
162
|
+
middleware: ['Middleware/AdminAuth']
|
|
163
|
+
}, () => {
|
|
164
|
+
route.get('/stats', 'Actions/Admin/StatsAction')
|
|
165
|
+
})
|
|
166
|
+
})
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Route Parameters
|
|
170
|
+
|
|
171
|
+
Access route parameters through the `params` object:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
route.get('/users/{id}/posts/{postId}', (req) => {
|
|
175
|
+
const { id, postId } = req.params
|
|
176
|
+
return Response.json({ userId: id, postId })
|
|
177
|
+
})
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## TypeScript Support
|
|
181
|
+
|
|
182
|
+
The router is written in TypeScript and provides full type definitions:
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
import type { ActionHandler, EnhancedRequest, Middleware, NextFunction } from '@bun-router'
|
|
186
|
+
|
|
187
|
+
// Type-safe request handling
|
|
188
|
+
const handler: ActionHandler = (req: EnhancedRequest) => {
|
|
189
|
+
const { id } = req.params
|
|
190
|
+
return Response.json({ id })
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Type-safe middleware
|
|
194
|
+
const loggerMiddleware: Middleware = {
|
|
195
|
+
handle: async (req: EnhancedRequest, next: NextFunction) => {
|
|
196
|
+
console.log(`${req.method} ${req.url}`)
|
|
197
|
+
return next()
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
route.use(loggerMiddleware.handle)
|
|
202
|
+
route.get('/users/{id}', handler)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Streaming Support
|
|
206
|
+
|
|
207
|
+
The router provides comprehensive streaming capabilities for modern web applications:
|
|
208
|
+
|
|
209
|
+
### File Streaming
|
|
210
|
+
|
|
211
|
+
Stream files with automatic content-type detection:
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
// Basic file streaming
|
|
215
|
+
route.get('/download/{filename}', (req) => {
|
|
216
|
+
const { filename } = req.params
|
|
217
|
+
return route.streamFile(`./uploads/${filename}`)
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
// File streaming with range support (for video/audio)
|
|
221
|
+
route.get('/video/{id}', async (req) => {
|
|
222
|
+
const { id } = req.params
|
|
223
|
+
const videoPath = `./videos/${id}.mp4`
|
|
224
|
+
return await route.streamFileWithRanges(videoPath, req)
|
|
225
|
+
})
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Response Streaming
|
|
229
|
+
|
|
230
|
+
Create streaming routes with clean, top-level API methods:
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
// Default streaming (uses Bun's async generator optimization)
|
|
234
|
+
route.stream('/stream-data', async function* () {
|
|
235
|
+
for (let i = 0; i < 100; i++) {
|
|
236
|
+
yield `Chunk ${i}\n`
|
|
237
|
+
await new Promise(resolve => setTimeout(resolve, 100))
|
|
238
|
+
}
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
// Direct streaming for high-performance scenarios
|
|
242
|
+
route.streamDirect('/stream-direct', async ({ write, close }) => {
|
|
243
|
+
for (let i = 0; i < 1000; i++) {
|
|
244
|
+
write(`Data chunk ${i}\n`)
|
|
245
|
+
if (i % 100 === 0) {
|
|
246
|
+
await new Promise(resolve => setTimeout(resolve, 10))
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
close()
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
// Buffered streaming using Bun.ArrayBufferSink
|
|
253
|
+
route.streamBuffered('/stream-buffered', async ({ write, flush, end }) => {
|
|
254
|
+
for (let i = 0; i < 1000; i++) {
|
|
255
|
+
write(`Item ${i}\n`)
|
|
256
|
+
if (i % 50 === 0) {
|
|
257
|
+
flush() // Flush buffer every 50 items
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
end()
|
|
261
|
+
}, { highWaterMark: 1024 * 1024 }) // 1MB buffer
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Server-Sent Events (SSE)
|
|
265
|
+
|
|
266
|
+
Real-time data streaming to web clients:
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
// Basic SSE endpoint
|
|
270
|
+
route.streamSSE('/events', async function* () {
|
|
271
|
+
let counter = 0
|
|
272
|
+
while (true) {
|
|
273
|
+
yield {
|
|
274
|
+
data: { timestamp: Date.now(), counter: counter++ },
|
|
275
|
+
event: 'update',
|
|
276
|
+
id: `msg-${counter}`
|
|
277
|
+
}
|
|
278
|
+
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
279
|
+
}
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
// SSE with custom retry interval
|
|
283
|
+
route.streamSSE('/notifications', async function* () {
|
|
284
|
+
yield {
|
|
285
|
+
data: 'Connection established',
|
|
286
|
+
event: 'connected',
|
|
287
|
+
retry: 5000 // Retry after 5 seconds if connection drops
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Stream notifications...
|
|
291
|
+
})
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### JSON Streaming (NDJSON)
|
|
295
|
+
|
|
296
|
+
Stream JSON objects line by line:
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
// Stream database results
|
|
300
|
+
route.streamJSON('/users/stream', async function* () {
|
|
301
|
+
const users = await getUsersFromDatabase()
|
|
302
|
+
for (const user of users) {
|
|
303
|
+
yield { id: user.id, name: user.name, email: user.email }
|
|
304
|
+
}
|
|
305
|
+
})
|
|
306
|
+
|
|
307
|
+
// Stream large datasets efficiently
|
|
308
|
+
route.streamJSON('/analytics/data', async function* () {
|
|
309
|
+
for (let page = 1; page <= 100; page++) {
|
|
310
|
+
const data = await fetchAnalyticsPage(page)
|
|
311
|
+
for (const record of data) {
|
|
312
|
+
yield record
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
})
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Transform Streams
|
|
319
|
+
|
|
320
|
+
Process incoming request streams using Bun's TransformStream:
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
// Transform uploaded data
|
|
324
|
+
route.post('/process-upload', route.transformStream(
|
|
325
|
+
(chunk) => {
|
|
326
|
+
// Process each chunk (e.g., uppercase text)
|
|
327
|
+
const text = new TextDecoder().decode(chunk)
|
|
328
|
+
return text.toUpperCase()
|
|
329
|
+
},
|
|
330
|
+
{ headers: { 'Content-Type': 'text/plain' } }
|
|
331
|
+
))
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Advanced Streaming Features
|
|
335
|
+
|
|
336
|
+
Leverage Bun's performance optimizations:
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
// Use direct ReadableStream for maximum performance
|
|
340
|
+
route.streamDirect('/high-performance-stream', async ({ write, close }) => {
|
|
341
|
+
// No queueing - data is written directly to the stream
|
|
342
|
+
for (let i = 0; i < 10000; i++) {
|
|
343
|
+
write(new Uint8Array([65 + (i % 26)])) // A-Z pattern
|
|
344
|
+
}
|
|
345
|
+
close()
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
// Buffered streaming with Bun.ArrayBufferSink
|
|
349
|
+
route.streamBuffered('/buffered-data', async ({ write, flush, end }) => {
|
|
350
|
+
// Efficient incremental buffer building
|
|
351
|
+
for (let batch = 0; batch < 10; batch++) {
|
|
352
|
+
for (let i = 0; i < 100; i++) {
|
|
353
|
+
write(`Batch ${batch}, Item ${i}\n`)
|
|
354
|
+
}
|
|
355
|
+
flush() // Periodically flush the buffer
|
|
356
|
+
await new Promise(resolve => setTimeout(resolve, 100))
|
|
357
|
+
}
|
|
358
|
+
end()
|
|
359
|
+
}, {
|
|
360
|
+
highWaterMark: 512 * 1024, // 512KB buffer
|
|
361
|
+
asUint8Array: true
|
|
362
|
+
})
|
|
363
|
+
|
|
364
|
+
// Mix streaming with middleware and route groups
|
|
365
|
+
route.group({ prefix: '/api/v1', middleware: ['Auth'] }, () => {
|
|
366
|
+
route.streamJSON('/live-metrics', async function* () {
|
|
367
|
+
while (true) {
|
|
368
|
+
yield await getSystemMetrics()
|
|
369
|
+
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
370
|
+
}
|
|
371
|
+
})
|
|
372
|
+
|
|
373
|
+
route.streamSSE('/notifications', async function* () {
|
|
374
|
+
// Stream user-specific notifications
|
|
375
|
+
const userId = getCurrentUserId()
|
|
376
|
+
for await (const notification of watchNotifications(userId)) {
|
|
377
|
+
yield { data: notification, event: 'notification' }
|
|
378
|
+
}
|
|
379
|
+
})
|
|
380
|
+
})
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
## Server Configuration
|
|
384
|
+
|
|
385
|
+
The `serve` method accepts all Bun server options:
|
|
386
|
+
|
|
387
|
+
```typescript
|
|
388
|
+
route.serve({
|
|
389
|
+
port: 3000,
|
|
390
|
+
hostname: 'localhost',
|
|
391
|
+
development: true,
|
|
392
|
+
})
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
## Contributing
|
|
396
|
+
|
|
397
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
package/bin/cli.ts
ADDED
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { EnhancedRequest, JwtPayload } from './types';
|
|
2
|
+
export type { JwtPayload };
|
|
3
|
+
// Types
|
|
4
|
+
export declare interface JwtVerifyOptions {
|
|
5
|
+
issuer?: string
|
|
6
|
+
audience?: string
|
|
7
|
+
subject?: string
|
|
8
|
+
algorithms?: string[]
|
|
9
|
+
expiresIn?: string | number
|
|
10
|
+
notBefore?: string | number
|
|
11
|
+
ignoreExpiration?: boolean
|
|
12
|
+
allowInvalidAsymmetricKeyTypes?: boolean
|
|
13
|
+
}
|
|
14
|
+
export declare interface JwtSignOptions {
|
|
15
|
+
algorithm?: 'HS256' | 'HS384' | 'HS512' | 'RS256' | 'RS384' | 'RS512' | 'ES256' | 'ES384' | 'ES512' | 'PS256' | 'PS384' | 'PS512' | 'none'
|
|
16
|
+
expiresIn?: string | number
|
|
17
|
+
notBefore?: string | number
|
|
18
|
+
audience?: string | string[]
|
|
19
|
+
issuer?: string
|
|
20
|
+
subject?: string
|
|
21
|
+
keyid?: string
|
|
22
|
+
jwtid?: string
|
|
23
|
+
noTimestamp?: boolean
|
|
24
|
+
header?: Record<string, any>
|
|
25
|
+
encoding?: string
|
|
26
|
+
}
|
|
27
|
+
export declare interface ApiKeyOptions {
|
|
28
|
+
source?: 'header' | 'query' | 'cookie'
|
|
29
|
+
keyName?: string
|
|
30
|
+
keyPrefix?: string
|
|
31
|
+
}
|
|
32
|
+
export declare interface OAuth2Config {
|
|
33
|
+
clientId: string
|
|
34
|
+
clientSecret: string
|
|
35
|
+
authorizeUrl: string
|
|
36
|
+
tokenUrl: string
|
|
37
|
+
redirectUri: string
|
|
38
|
+
scope?: string
|
|
39
|
+
state?: string
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Simple JWT implementation for signing and verifying tokens
|
|
43
|
+
*/
|
|
44
|
+
export declare class JWT {
|
|
45
|
+
private secret: string;
|
|
46
|
+
constructor(secret: string);
|
|
47
|
+
sign(payload: Record<string, any>, options?: JwtSignOptions): string;
|
|
48
|
+
verify(token: string, options?: JwtVerifyOptions): Record<string, any> | null;
|
|
49
|
+
decode(token: string): { header: Record<string, any>, payload: Record<string, any> } | null;
|
|
50
|
+
private createSignature(data: string, secret: string, algorithm: string): string;
|
|
51
|
+
private parseTimespan(timespan: string): number;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* API Key manager to generate, validate and handle API keys
|
|
55
|
+
*/
|
|
56
|
+
export declare class ApiKeyManager {
|
|
57
|
+
private keys: Map<string, { owner: string, scopes: string[], expiresAt?: Date }>;
|
|
58
|
+
private options: ApiKeyOptions;
|
|
59
|
+
constructor(options?: ApiKeyOptions);
|
|
60
|
+
generateKey(owner: string, scopes?: string[], expiresIn?: number): string;
|
|
61
|
+
validateKey(key: string, requiredScopes?: string[]): boolean;
|
|
62
|
+
getKeyInfo(key: string): { owner: string, scopes: string[], expiresAt?: Date } | null;
|
|
63
|
+
revokeKey(key: string): boolean;
|
|
64
|
+
extractFromRequest(req: EnhancedRequest): string | null;
|
|
65
|
+
private randomString(length: number): string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* OAuth2 helper for authorization code flow
|
|
69
|
+
*/
|
|
70
|
+
export declare class OAuth2Helper {
|
|
71
|
+
private config: OAuth2Config;
|
|
72
|
+
constructor(config: OAuth2Config);
|
|
73
|
+
getAuthorizationUrl(additionalParams?: Record<string, string>): string;
|
|
74
|
+
exchangeCodeForToken(code: string): Promise<Record<string, any>>;
|
|
75
|
+
refreshToken(refreshToken: string): Promise<Record<string, any>>;
|
|
76
|
+
}
|
|
77
|
+
export default Auth;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory function to create LRU cache with common configurations
|
|
3
|
+
*/
|
|
4
|
+
export declare const createLRUCache: {
|
|
5
|
+
/**
|
|
6
|
+
* Create a small cache for frequently accessed items
|
|
7
|
+
*/
|
|
8
|
+
small: () => unknown;
|
|
9
|
+
/**
|
|
10
|
+
* Create a medium cache for general purpose use
|
|
11
|
+
*/
|
|
12
|
+
medium: () => unknown;
|
|
13
|
+
/**
|
|
14
|
+
* Create a large cache for heavy caching scenarios
|
|
15
|
+
*/
|
|
16
|
+
large: () => unknown;
|
|
17
|
+
/**
|
|
18
|
+
* Create a custom configured cache
|
|
19
|
+
*/
|
|
20
|
+
custom: () => unknown
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* High-performance LRU (Least Recently Used) cache implementation
|
|
24
|
+
* Optimized for Bun runtime with configurable size limits and TTL support
|
|
25
|
+
*/
|
|
26
|
+
export declare interface LRUCacheOptions {
|
|
27
|
+
maxSize: number
|
|
28
|
+
ttl?: number
|
|
29
|
+
onEvict?: (key: string, value: any) => void
|
|
30
|
+
allowStale?: boolean
|
|
31
|
+
updateAgeOnGet?: boolean
|
|
32
|
+
}
|
|
33
|
+
export declare interface CacheEntry<T = any> {
|
|
34
|
+
value: T
|
|
35
|
+
timestamp: number
|
|
36
|
+
accessCount: number
|
|
37
|
+
lastAccessed: number
|
|
38
|
+
ttl?: number
|
|
39
|
+
}
|
|
40
|
+
export declare interface CacheStats {
|
|
41
|
+
size: number
|
|
42
|
+
maxSize: number
|
|
43
|
+
hits: number
|
|
44
|
+
misses: number
|
|
45
|
+
evictions: number
|
|
46
|
+
hitRate: number
|
|
47
|
+
memoryUsage: number
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Node in the doubly linked list for LRU tracking
|
|
51
|
+
*/
|
|
52
|
+
declare class LRUNode<T = any> {
|
|
53
|
+
public key: string;
|
|
54
|
+
public entry: CacheEntry<T>;
|
|
55
|
+
public prev?: LRUNode<T> | null;
|
|
56
|
+
public next?: LRUNode<T> | null;
|
|
57
|
+
constructor(key: string, entry: CacheEntry<T>, prev?: LRUNode<T> | null, next?: LRUNode<T> | null);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* High-performance LRU cache with TTL support and detailed statistics
|
|
61
|
+
*/
|
|
62
|
+
export declare class LRUCache<T = any> {
|
|
63
|
+
private cache: any;
|
|
64
|
+
private head: LRUNode<T> | null;
|
|
65
|
+
private tail: LRUNode<T> | null;
|
|
66
|
+
private stats: any;
|
|
67
|
+
private options: LRUCacheOptions;
|
|
68
|
+
constructor(options: LRUCacheOptions);
|
|
69
|
+
get(key: string): T | undefined;
|
|
70
|
+
set(key: string, value: T, ttl?: number): void;
|
|
71
|
+
delete(key: string): boolean;
|
|
72
|
+
has(key: string): boolean;
|
|
73
|
+
clear(): void;
|
|
74
|
+
keys(): string[];
|
|
75
|
+
values(): T[];
|
|
76
|
+
getStats(): CacheStats;
|
|
77
|
+
resetStats(): void;
|
|
78
|
+
prune(): number;
|
|
79
|
+
getFrequentlyUsed(limit?: number): Array<{ key: string, value: T, accessCount: number }>;
|
|
80
|
+
resize(newMaxSize: number): void;
|
|
81
|
+
private isExpired(entry: CacheEntry<T>, now: number): boolean;
|
|
82
|
+
private moveToFront(node: LRUNode<T>): void;
|
|
83
|
+
private addToFront(node: LRUNode<T>): void;
|
|
84
|
+
private removeNode(node: LRUNode<T>): void;
|
|
85
|
+
private evictLRU(): void;
|
|
86
|
+
private estimateMemoryUsage(): number;
|
|
87
|
+
private estimateValueSize(value: any): number;
|
|
88
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { LRUCache } from './lru-cache';
|
|
2
|
+
import type { EnhancedRequest, MiddlewareHandler } from '../types';
|
|
3
|
+
import type { LRUCacheOptions } from './lru-cache';
|
|
4
|
+
/**
|
|
5
|
+
* Decorator for memoizing class methods
|
|
6
|
+
*/
|
|
7
|
+
export declare function Memoize(options?: {
|
|
8
|
+
memoizer: MiddlewareMemoizer
|
|
9
|
+
keyGenerator?: (...args: any[]) => string
|
|
10
|
+
ttl?: number
|
|
11
|
+
}): MethodDecorator;
|
|
12
|
+
/**
|
|
13
|
+
* Factory functions for creating memoizers
|
|
14
|
+
*/
|
|
15
|
+
export declare const createMemoizer: {
|
|
16
|
+
/**
|
|
17
|
+
* Create memoizer for development
|
|
18
|
+
*/
|
|
19
|
+
development: () => any;
|
|
20
|
+
/**
|
|
21
|
+
* Create memoizer for production
|
|
22
|
+
*/
|
|
23
|
+
production: () => any;
|
|
24
|
+
/**
|
|
25
|
+
* Create custom memoizer
|
|
26
|
+
*/
|
|
27
|
+
custom: (options: MemoizationOptions) => any
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Middleware result memoization for expensive operations
|
|
31
|
+
* Caches middleware results based on request characteristics
|
|
32
|
+
*/
|
|
33
|
+
export declare interface MemoizationOptions extends Omit<LRUCacheOptions, 'maxSize'> {
|
|
34
|
+
maxSize: number
|
|
35
|
+
keyGenerator?: (req: EnhancedRequest) => string
|
|
36
|
+
shouldMemoize?: (req: EnhancedRequest, result: any) => boolean
|
|
37
|
+
resultSerializer?: (result: any) => any
|
|
38
|
+
resultDeserializer?: (serialized: any) => any
|
|
39
|
+
}
|
|
40
|
+
export declare interface MemoizedResult<T = any> {
|
|
41
|
+
value: T
|
|
42
|
+
timestamp: number
|
|
43
|
+
requestFingerprint: string
|
|
44
|
+
executionTime: number
|
|
45
|
+
hitCount: number
|
|
46
|
+
}
|
|
47
|
+
export declare interface MemoizationStats {
|
|
48
|
+
totalRequests: number
|
|
49
|
+
cacheHits: number
|
|
50
|
+
cacheMisses: number
|
|
51
|
+
hitRate: number
|
|
52
|
+
averageExecutionTime: number
|
|
53
|
+
totalTimeSaved: number
|
|
54
|
+
memoryUsage: number
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Middleware memoization system for caching expensive operations
|
|
58
|
+
*/
|
|
59
|
+
export declare class MiddlewareMemoizer {
|
|
60
|
+
private cache: LRUCache<MemoizedResult>;
|
|
61
|
+
private stats: MemoizationStats;
|
|
62
|
+
private options: MemoizationOptions;
|
|
63
|
+
constructor(options: MemoizationOptions);
|
|
64
|
+
memoize<_T = any>(middleware: MiddlewareHandler, options?: {
|
|
65
|
+
name?: string
|
|
66
|
+
keyGenerator?: (req: EnhancedRequest) => string
|
|
67
|
+
shouldMemoize?: (req: EnhancedRequest, result: any) => boolean
|
|
68
|
+
ttl?: number
|
|
69
|
+
}): MiddlewareHandler;
|
|
70
|
+
memoizeFunction<TArgs extends any[], TResult>(fn: (...args: TArgs) => Promise<TResult>, options?: {
|
|
71
|
+
name?: string
|
|
72
|
+
keyGenerator?: (...args: TArgs) => string
|
|
73
|
+
shouldMemoize?: (result: TResult, ...args: TArgs) => boolean
|
|
74
|
+
ttl?: number
|
|
75
|
+
}): (...args: TArgs) => Promise<TResult>;
|
|
76
|
+
invalidate(pattern: string | RegExp): number;
|
|
77
|
+
invalidateForUser(userId: string): number;
|
|
78
|
+
invalidateByTag(tag: string): number;
|
|
79
|
+
getPopularResults(limit?: number): Array<{
|
|
80
|
+
key: string
|
|
81
|
+
hitCount: number
|
|
82
|
+
executionTime: number
|
|
83
|
+
timeSaved: number
|
|
84
|
+
}>;
|
|
85
|
+
getStats(): MemoizationStats;
|
|
86
|
+
clear(): void;
|
|
87
|
+
prune(): number;
|
|
88
|
+
private generateCacheKey(req: EnhancedRequest, middlewareName: string, customKeyGenerator?: (req: EnhancedRequest) => string): string;
|
|
89
|
+
private generateRequestFingerprint(req: EnhancedRequest): string;
|
|
90
|
+
private updateHitRate(): void;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Common memoization patterns and utilities
|
|
94
|
+
*/
|
|
95
|
+
export declare class MemoizationPatterns {
|
|
96
|
+
static createDatabaseMemoizer(options?: MemoizationOptions): MiddlewareMemoizer;
|
|
97
|
+
static createApiMemoizer(options?: MemoizationOptions): MiddlewareMemoizer;
|
|
98
|
+
static createAuthMemoizer(options?: MemoizationOptions): MiddlewareMemoizer;
|
|
99
|
+
static createRateLimitMemoizer(options?: MemoizationOptions): MiddlewareMemoizer;
|
|
100
|
+
static createComputationMemoizer(options?: MemoizationOptions): MiddlewareMemoizer;
|
|
101
|
+
}
|