@stacksjs/bun-router 0.0.14 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +261 -584
- package/bin/cli.ts +9 -0
- package/dist/auth.d.ts +134 -0
- package/dist/cache/lru-cache.d.ts +139 -0
- package/dist/cache/middleware-memoization.d.ts +151 -0
- package/dist/cache/route-cache-warmer.d.ts +161 -0
- package/dist/cache/sqlite-cache.d.ts +209 -0
- package/dist/cache/streaming-cache.d.ts +132 -0
- package/dist/chunk-j0e7z7hd.js +18053 -0
- package/dist/cli/colors.d.ts +15 -0
- package/dist/cli/index.d.ts +10 -0
- package/dist/cli/middleware.d.ts +31 -0
- package/dist/cli/openapi.d.ts +17 -0
- package/dist/cli/router.d.ts +15 -0
- package/dist/cli/routes.d.ts +29 -0
- package/dist/cli/utils.d.ts +74 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +3360 -0
- package/dist/config.d.ts +7 -0
- package/dist/container/container.d.ts +273 -0
- package/dist/container/contextual-binding.d.ts +240 -0
- package/dist/container/decorators.d.ts +141 -0
- package/dist/container/service-provider.d.ts +285 -0
- package/dist/development/hot-reload.d.ts +187 -0
- package/dist/development/index.d.ts +167 -0
- package/dist/development/performance-profiler.d.ts +217 -0
- package/dist/development/route-debugger.d.ts +154 -0
- package/dist/development/route-inspector.d.ts +211 -0
- package/dist/development/typescript-utilities.d.ts +209 -0
- package/dist/docs.d.ts +11 -0
- package/dist/errors/circuit-breaker.d.ts +195 -0
- package/dist/errors/error-handler.d.ts +88 -0
- package/dist/errors/error-reporting.d.ts +144 -0
- package/dist/errors/exceptions.d.ts +184 -0
- package/dist/errors/graceful-degradation.d.ts +154 -0
- package/dist/errors/index.d.ts +9 -0
- package/dist/errors/router-errors.d.ts +110 -0
- package/dist/file-serving/static-files.d.ts +143 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +13968 -0
- package/dist/middleware/auth.d.ts +63 -0
- package/dist/middleware/content_security_policy.d.ts +53 -0
- package/dist/middleware/cors.d.ts +5 -0
- package/dist/middleware/csrf.d.ts +7 -0
- package/dist/middleware/ddos_protection.d.ts +39 -0
- package/dist/middleware/file_security.d.ts +26 -0
- package/dist/middleware/file_upload.d.ts +38 -0
- package/dist/middleware/helmet.d.ts +54 -0
- package/dist/middleware/index.d.ts +44 -0
- package/dist/middleware/input_validation.d.ts +45 -0
- package/dist/middleware/json_body.d.ts +4 -0
- package/dist/middleware/performance_alerting.d.ts +87 -0
- package/dist/middleware/performance_dashboard.d.ts +87 -0
- package/dist/middleware/performance_monitor.d.ts +209 -0
- package/dist/middleware/pipeline.d.ts +131 -0
- package/dist/middleware/rate_limit.d.ts +36 -0
- package/dist/middleware/request_id.d.ts +4 -0
- package/dist/middleware/request_signing.d.ts +153 -0
- package/dist/middleware/request_tracer.d.ts +72 -0
- package/dist/middleware/response_cache.d.ts +97 -0
- package/dist/middleware/security.d.ts +69 -0
- package/dist/middleware/security_suite.d.ts +46 -0
- package/dist/middleware/session.d.ts +23 -0
- package/dist/model-binding/index.d.ts +2 -0
- package/dist/model-binding/model-middleware.d.ts +118 -0
- package/dist/model-binding/model-registry.d.ts +164 -0
- package/dist/model-binding.d.ts +185 -0
- package/dist/model-resolver-factory.d.ts +31 -0
- package/dist/observability/correlation.d.ts +187 -0
- package/dist/observability/health-checks.d.ts +186 -0
- package/dist/observability/index.d.ts +60 -0
- package/dist/observability/integration.d.ts +147 -0
- package/dist/observability/metrics.d.ts +184 -0
- package/dist/observability/tracing.d.ts +187 -0
- package/dist/optimization/bun-utilities.d.ts +224 -0
- package/dist/query-builder-integration.d.ts +36 -0
- package/dist/request/context.d.ts +34 -0
- package/dist/request/enhanced-request.d.ts +213 -0
- package/dist/request/macros.d.ts +300 -0
- package/dist/response/macros.d.ts +256 -0
- package/dist/response/response-factory.d.ts +133 -0
- package/dist/router/api-routes.d.ts +5 -0
- package/dist/router/file-based-routing.d.ts +118 -0
- package/dist/router/file-streaming.d.ts +5 -0
- package/dist/router/fluent-router.d.ts +315 -0
- package/dist/router/fluent-routing.d.ts +271 -0
- package/dist/router/group-organization.d.ts +5 -0
- package/dist/router/handler-resolver.d.ts +24 -0
- package/dist/router/http-methods.d.ts +10 -0
- package/dist/router/index.d.ts +114 -0
- package/dist/router/middleware-groups.d.ts +94 -0
- package/dist/router/middleware-integration.d.ts +112 -0
- package/dist/router/middleware.d.ts +5 -0
- package/dist/router/model-binding.d.ts +5 -0
- package/dist/router/optimized-route-matching.d.ts +6 -0
- package/dist/router/route-building.d.ts +5 -0
- package/dist/router/route-compiler.d.ts +153 -0
- package/dist/router/route-matching.d.ts +5 -0
- package/dist/router/route-trie.d.ts +114 -0
- package/dist/router/router.d.ts +317 -0
- package/dist/router/server.d.ts +5 -0
- package/dist/router/validation-integration.d.ts +170 -0
- package/dist/router/view-rendering.d.ts +5 -0
- package/dist/router/websocket.d.ts +5 -0
- package/dist/routing/route-caching.d.ts +129 -0
- package/dist/routing/route-throttling.d.ts +150 -0
- package/dist/routing/subdomain-routing.d.ts +206 -0
- package/dist/session/database-store.d.ts +51 -0
- package/dist/session/file-store.d.ts +22 -0
- package/dist/session/index.d.ts +106 -0
- package/dist/session/memory-store.d.ts +21 -0
- package/dist/session/redis-store.d.ts +31 -0
- package/dist/streaming/index.d.ts +3 -0
- package/dist/streaming/sse-handler.d.ts +138 -0
- package/dist/streaming/stream-handler.d.ts +114 -0
- package/dist/testing/auth-testing.d.ts +156 -0
- package/dist/testing/file-upload-testing.d.ts +190 -0
- package/dist/testing/index.d.ts +10 -0
- package/dist/testing/middleware-testing.d.ts +138 -0
- package/dist/testing/model-binding-testing.d.ts +186 -0
- package/dist/testing/performance-testing.d.ts +235 -0
- package/dist/testing/test-client.d.ts +117 -0
- package/dist/testing/test-request.d.ts +85 -0
- package/dist/testing/test-response.d.ts +90 -0
- package/dist/testing/types.d.ts +207 -0
- package/dist/testing/websocket-testing.d.ts +227 -0
- package/dist/types/controller-types.d.ts +208 -0
- package/dist/types/core.d.ts +543 -0
- package/dist/types/middleware-types.d.ts +227 -0
- package/dist/types/request-response-augmentation.d.ts +261 -0
- package/dist/types/route-inference.d.ts +168 -0
- package/dist/types.d.ts +1794 -0
- package/dist/url.d.ts +56 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/query-preservation.d.ts +48 -0
- package/dist/utils.d.ts +69 -0
- package/dist/validation/validator.d.ts +140 -0
- package/dist/websocket/clustering.d.ts +185 -0
- package/package.json +45 -44
- package/src/auth.ts +469 -0
- package/src/cache/lru-cache.ts +457 -0
- package/src/cache/middleware-memoization.ts +531 -0
- package/src/cache/route-cache-warmer.ts +486 -0
- package/src/cache/sqlite-cache.ts +783 -0
- package/src/cache/streaming-cache.ts +572 -0
- package/src/cli/colors.ts +29 -0
- package/src/cli/index.ts +287 -0
- package/src/cli/middleware.ts +291 -0
- package/src/cli/openapi.ts +407 -0
- package/src/cli/router.ts +188 -0
- package/src/cli/routes.ts +265 -0
- package/src/cli/utils.ts +531 -0
- package/src/cli.ts +5 -0
- package/src/config.ts +322 -0
- package/src/container/container.ts +740 -0
- package/src/container/contextual-binding.ts +603 -0
- package/src/container/decorators.ts +359 -0
- package/src/container/service-provider.ts +596 -0
- package/src/development/hot-reload.ts +673 -0
- package/src/development/index.ts +499 -0
- package/src/development/performance-profiler.ts +717 -0
- package/src/development/route-debugger.ts +527 -0
- package/src/development/route-inspector.ts +749 -0
- package/src/development/typescript-utilities.ts +682 -0
- package/src/docs.ts +397 -0
- package/src/errors/circuit-breaker.ts +732 -0
- package/src/errors/error-handler.ts +569 -0
- package/src/errors/error-reporting.ts +672 -0
- package/src/errors/exceptions.ts +536 -0
- package/src/errors/graceful-degradation.ts +621 -0
- package/src/errors/index.ts +21 -0
- package/src/errors/router-errors.ts +632 -0
- package/src/file-serving/static-files.ts +581 -0
- package/src/index.ts +14 -0
- package/src/middleware/auth.ts +220 -0
- package/src/middleware/content_security_policy.ts +215 -0
- package/src/middleware/cors.ts +74 -0
- package/src/middleware/csrf.ts +108 -0
- package/src/middleware/ddos_protection.ts +255 -0
- package/src/middleware/file_security.ts +191 -0
- package/src/middleware/file_upload.ts +275 -0
- package/src/middleware/helmet.ts +268 -0
- package/src/middleware/index.ts +117 -0
- package/src/middleware/input_validation.ts +449 -0
- package/src/middleware/json_body.ts +37 -0
- package/src/middleware/performance_alerting.ts +538 -0
- package/src/middleware/performance_dashboard.ts +661 -0
- package/src/middleware/performance_monitor.ts +943 -0
- package/src/middleware/pipeline.ts +489 -0
- package/src/middleware/rate_limit.ts +245 -0
- package/src/middleware/request_id.ts +36 -0
- package/src/middleware/request_signing.ts +636 -0
- package/src/middleware/request_tracer.ts +636 -0
- package/src/middleware/response_cache.ts +743 -0
- package/src/middleware/security.ts +482 -0
- package/src/middleware/security_suite.ts +257 -0
- package/src/middleware/session.ts +91 -0
- package/src/model-binding/index.ts +18 -0
- package/src/model-binding/model-middleware.ts +425 -0
- package/src/model-binding/model-registry.ts +550 -0
- package/src/model-binding.ts +370 -0
- package/src/model-resolver-factory.ts +106 -0
- package/src/observability/correlation.ts +691 -0
- package/src/observability/health-checks.ts +729 -0
- package/src/observability/index.ts +184 -0
- package/src/observability/integration.ts +548 -0
- package/src/observability/metrics.ts +753 -0
- package/src/observability/tracing.ts +638 -0
- package/src/optimization/bun-utilities.ts +778 -0
- package/src/query-builder-integration.ts +137 -0
- package/src/request/context.ts +62 -0
- package/src/request/enhanced-request.ts +857 -0
- package/src/request/macros.ts +688 -0
- package/src/response/macros.ts +665 -0
- package/src/response/response-factory.ts +596 -0
- package/src/router/api-routes.ts +243 -0
- package/src/router/file-based-routing.ts +690 -0
- package/src/router/file-streaming.ts +383 -0
- package/src/router/fluent-router.ts +927 -0
- package/src/router/fluent-routing.ts +797 -0
- package/src/router/group-organization.ts +213 -0
- package/src/router/handler-resolver.ts +291 -0
- package/src/router/http-methods.ts +377 -0
- package/src/router/index.ts +187 -0
- package/src/router/middleware-groups.ts +222 -0
- package/src/router/middleware-integration.ts +399 -0
- package/src/router/middleware.ts +231 -0
- package/src/router/model-binding.ts +215 -0
- package/src/router/optimized-route-matching.ts +253 -0
- package/src/router/route-building.ts +221 -0
- package/src/router/route-compiler.ts +702 -0
- package/src/router/route-matching.ts +349 -0
- package/src/router/route-trie.ts +464 -0
- package/src/router/router.ts +1604 -0
- package/src/router/server.ts +462 -0
- package/src/router/validation-integration.ts +443 -0
- package/src/router/view-rendering.ts +233 -0
- package/src/router/websocket.ts +100 -0
- package/src/routing/route-caching.ts +402 -0
- package/src/routing/route-throttling.ts +469 -0
- package/src/routing/subdomain-routing.ts +492 -0
- package/src/session/database-store.ts +109 -0
- package/src/session/file-store.ts +148 -0
- package/src/session/index.ts +244 -0
- package/src/session/memory-store.ts +88 -0
- package/src/session/redis-store.ts +93 -0
- package/src/streaming/index.ts +17 -0
- package/src/streaming/sse-handler.ts +482 -0
- package/src/streaming/stream-handler.ts +552 -0
- package/src/testing/auth-testing.ts +446 -0
- package/src/testing/file-upload-testing.ts +543 -0
- package/src/testing/index.ts +10 -0
- package/src/testing/middleware-testing.ts +322 -0
- package/src/testing/model-binding-testing.ts +645 -0
- package/src/testing/performance-testing.ts +738 -0
- package/src/testing/test-client.ts +310 -0
- package/src/testing/test-request.ts +315 -0
- package/src/testing/test-response.ts +332 -0
- package/src/testing/types.ts +224 -0
- package/src/testing/websocket-testing.ts +590 -0
- package/src/types/controller-types.ts +385 -0
- package/src/types/core.ts +683 -0
- package/src/types/middleware-types.ts +419 -0
- package/src/types/request-response-augmentation.ts +489 -0
- package/src/types/route-inference.ts +357 -0
- package/src/types.ts +2067 -0
- package/src/url.ts +126 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/query-preservation.ts +201 -0
- package/src/utils.ts +327 -0
- package/src/validation/validator.ts +685 -0
- package/src/websocket/clustering.ts +762 -0
- package/CHANGELOG.md +0 -770
package/README.md
CHANGED
|
@@ -1,720 +1,397 @@
|
|
|
1
|
-
|
|
1
|
+
# @bun-router
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[![GitHub Actions][github-actions-src]][github-actions-href]
|
|
5
|
-
[](http://commitizen.github.io/cz-cli/)
|
|
6
|
-
<!-- [![npm downloads][npm-downloads-src]][npm-downloads-href] -->
|
|
7
|
-
<!-- [![Codecov][codecov-src]][codecov-href] -->
|
|
8
|
-
|
|
9
|
-
# bun-router
|
|
10
|
-
|
|
11
|
-
A high-performance, feature-rich router for Bun applications.
|
|
3
|
+
A Laravel-inspired router for Bun applications.
|
|
12
4
|
|
|
13
5
|
## Features
|
|
14
6
|
|
|
15
|
-
-
|
|
16
|
-
- Support for
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
- Domain and subdomain routing
|
|
22
|
-
- CSRF protection and session management
|
|
23
|
-
- Type-safe API
|
|
24
|
-
- Native Bun.serve() integration
|
|
25
|
-
- WebSocket support
|
|
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
|
|
26
13
|
|
|
27
14
|
## Installation
|
|
28
15
|
|
|
29
16
|
```bash
|
|
30
|
-
bun add bun-router
|
|
17
|
+
bun add @bun-router
|
|
31
18
|
```
|
|
32
19
|
|
|
33
20
|
## Basic Usage
|
|
34
21
|
|
|
35
22
|
```typescript
|
|
36
|
-
import {
|
|
23
|
+
import { route } from '@bun-router'
|
|
37
24
|
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
// Define routes
|
|
42
|
-
router.get('/', () => new Response('Hello, World!'))
|
|
43
|
-
router.post('/users', async (req) => {
|
|
44
|
-
const data = await req.json()
|
|
45
|
-
return Response.json({ message: 'User created', data })
|
|
46
|
-
})
|
|
25
|
+
// Basic route with inline handler
|
|
26
|
+
route.get('/', () => new Response('Hello World!'))
|
|
47
27
|
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
port: 3000,
|
|
51
|
-
})
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
## Route Options
|
|
55
|
-
|
|
56
|
-
```typescript
|
|
57
|
-
// Route with path parameters
|
|
58
|
-
router.get('/users/{id}', (req) => {
|
|
28
|
+
// Route with parameters
|
|
29
|
+
route.get('/users/{id}', (req) => {
|
|
59
30
|
const { id } = req.params
|
|
60
|
-
return Response.json({ id })
|
|
31
|
+
return Response.json({ userId: id })
|
|
61
32
|
})
|
|
62
33
|
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
// Generate URL for named route
|
|
67
|
-
const url = router.route('users.show', { id: '123' })
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## Middleware
|
|
34
|
+
// Route with action class
|
|
35
|
+
route.post('/subscribe', 'Actions/SubscribeAction')
|
|
71
36
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
37
|
+
// Route grouping
|
|
38
|
+
route.group({ prefix: '/api' }, () => {
|
|
39
|
+
route.get('/users', 'Actions/User/IndexAction')
|
|
40
|
+
route.post('/users', 'Actions/User/StoreAction')
|
|
41
|
+
})
|
|
76
42
|
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
router.use(cors())
|
|
43
|
+
// Health check route
|
|
44
|
+
route.health()
|
|
80
45
|
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
middleware: [jsonBody(), cors()]
|
|
85
|
-
}, () => {
|
|
86
|
-
router.get('/users', () => Response.json({ users: [] }))
|
|
46
|
+
// Start the server
|
|
47
|
+
route.serve({
|
|
48
|
+
port: 3000,
|
|
87
49
|
})
|
|
88
50
|
```
|
|
89
51
|
|
|
90
|
-
|
|
52
|
+
## Action Classes
|
|
91
53
|
|
|
92
|
-
|
|
93
|
-
- **JsonBody** - Parses JSON request bodies into `req.jsonBody`
|
|
94
|
-
- **RequestId** - Adds unique IDs to requests with `X-Request-ID` header
|
|
95
|
-
- **Session** - Provides session management with `req.session`
|
|
96
|
-
- **Csrf** - Protects against cross-site request forgery
|
|
97
|
-
- **Auth** - Basic authentication middleware
|
|
98
|
-
|
|
99
|
-
### Creating Custom Middleware
|
|
54
|
+
Action classes provide a clean way to organize your route handlers. Create a class that implements a `handle` method:
|
|
100
55
|
|
|
101
56
|
```typescript
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
class LoggerMiddleware {
|
|
105
|
-
async handle(req: EnhancedRequest, next: NextFunction): Promise<Response> {
|
|
106
|
-
console.log(`${req.method} ${req.url}`)
|
|
107
|
-
return next()
|
|
108
|
-
}
|
|
109
|
-
}
|
|
57
|
+
// actions/subscribe_action.ts
|
|
58
|
+
import type { EnhancedRequest } from '@bun-router'
|
|
110
59
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
## WebSocket Support
|
|
60
|
+
export default class SubscribeAction {
|
|
61
|
+
async handle(request: EnhancedRequest): Promise<Response> {
|
|
62
|
+
const data = await request.json()
|
|
116
63
|
|
|
117
|
-
|
|
64
|
+
// Handle subscription logic
|
|
118
65
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
interface ClientData {
|
|
125
|
-
userId: string
|
|
126
|
-
room: string
|
|
66
|
+
return Response.json({
|
|
67
|
+
success: true,
|
|
68
|
+
message: 'Subscribed successfully'
|
|
69
|
+
})
|
|
70
|
+
}
|
|
127
71
|
}
|
|
72
|
+
```
|
|
128
73
|
|
|
129
|
-
|
|
130
|
-
const router = new Router<ClientData>() // Type-safe WebSockets
|
|
131
|
-
|
|
132
|
-
// Add a regular HTTP route
|
|
133
|
-
router.get('/', () => new Response('WebSocket Server'))
|
|
134
|
-
|
|
135
|
-
// Configure WebSocket handling
|
|
136
|
-
router.websocket({
|
|
137
|
-
// Handle new connections
|
|
138
|
-
open(ws) {
|
|
139
|
-
console.log('Client connected from:', ws.remoteAddress)
|
|
140
|
-
|
|
141
|
-
// Set client data (available in all handlers as ws.data)
|
|
142
|
-
ws.data = { userId: 'user_123', room: 'general' }
|
|
143
|
-
|
|
144
|
-
// Subscribe to topics for pub/sub messaging
|
|
145
|
-
ws.subscribe('general')
|
|
146
|
-
ws.send('Welcome to the server!')
|
|
147
|
-
},
|
|
148
|
-
|
|
149
|
-
// Handle incoming messages
|
|
150
|
-
message(ws, message) {
|
|
151
|
-
// Handle different message types (string, ArrayBuffer, Uint8Array)
|
|
152
|
-
const content = typeof message === 'string' ? message : 'Binary data received'
|
|
153
|
-
console.log(`Received from ${ws.data.userId}: ${content}`)
|
|
154
|
-
|
|
155
|
-
// Send response and check for backpressure
|
|
156
|
-
const sendResult = ws.send(`Echo: ${content}`)
|
|
157
|
-
|
|
158
|
-
if (sendResult === -1) {
|
|
159
|
-
console.log('Backpressure detected, message queued')
|
|
160
|
-
}
|
|
161
|
-
else if (sendResult === 0) {
|
|
162
|
-
console.log('Send failed, connection may be closed')
|
|
163
|
-
}
|
|
164
|
-
else {
|
|
165
|
-
console.log(`Sent ${sendResult} bytes`)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Broadcast to all subscribers of a topic (except sender)
|
|
169
|
-
router.publish('general', `${ws.data.userId}: ${content}`)
|
|
170
|
-
},
|
|
171
|
-
|
|
172
|
-
// Handle disconnections
|
|
173
|
-
close(ws, code, reason) {
|
|
174
|
-
console.log(`Client ${ws.data.userId} disconnected: ${reason || 'No reason'} (${code})`)
|
|
175
|
-
ws.unsubscribe('general')
|
|
176
|
-
},
|
|
177
|
-
|
|
178
|
-
// Handle errors
|
|
179
|
-
error(ws, error) {
|
|
180
|
-
console.error(`Error for client ${ws.data.userId}:`, error)
|
|
181
|
-
},
|
|
182
|
-
|
|
183
|
-
// Handle backpressure relief
|
|
184
|
-
drain(ws) {
|
|
185
|
-
console.log(`Backpressure relieved for ${ws.data.userId}, socket ready for more data`)
|
|
186
|
-
},
|
|
74
|
+
## Middleware
|
|
187
75
|
|
|
188
|
-
|
|
189
|
-
maxPayloadLength: 16 _ 1024 _ 1024, // 16MB max message size (default)
|
|
190
|
-
idleTimeout: 120, // 2 minutes (default)
|
|
191
|
-
backpressureLimit: 1024 _ 1024, // 1MB (default)
|
|
192
|
-
closeOnBackpressureLimit: false, // Don't close on backpressure limit (default)
|
|
76
|
+
Middleware allows you to run code before your route handlers. You can use middleware globally or for specific routes/groups.
|
|
193
77
|
|
|
194
|
-
|
|
195
|
-
perMessageDeflate: {
|
|
196
|
-
compress: '16KB', // Use 16KB compression level
|
|
197
|
-
decompress: true
|
|
198
|
-
},
|
|
78
|
+
### Creating Middleware
|
|
199
79
|
|
|
200
|
-
|
|
201
|
-
publishToSelf: false // Don't send published messages to publisher (default)
|
|
202
|
-
})
|
|
80
|
+
Create a middleware class that implements the `handle` method:
|
|
203
81
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
### WebSocket Utility Methods
|
|
82
|
+
```typescript
|
|
83
|
+
// middleware/auth.ts
|
|
84
|
+
import type { EnhancedRequest, Middleware, NextFunction } from '@bun-router'
|
|
209
85
|
|
|
210
|
-
|
|
86
|
+
export default class AuthMiddleware implements Middleware {
|
|
87
|
+
async handle(req: EnhancedRequest, next: NextFunction): Promise<Response> {
|
|
88
|
+
const authHeader = req.headers.get('Authorization')
|
|
211
89
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
// Returns: Number of bytes sent (or negative on error)
|
|
215
|
-
const result = router.publish('room-123', JSON.stringify({
|
|
216
|
-
type: 'message',
|
|
217
|
-
text: 'Hello!'
|
|
218
|
-
}), true) // Optional: enable compression
|
|
219
|
-
|
|
220
|
-
// Get the number of subscribers for a topic
|
|
221
|
-
const count = router.subscriberCount('room-123')
|
|
222
|
-
|
|
223
|
-
// Upgrade an HTTP request to a WebSocket connection
|
|
224
|
-
router.get('/custom-upgrade', (req) => {
|
|
225
|
-
const success = router.upgrade(req, {
|
|
226
|
-
// Optional custom headers for the 101 Switching Protocols response
|
|
227
|
-
headers: { 'X-Custom-Header': 'value' },
|
|
228
|
-
|
|
229
|
-
// Custom data to attach to the WebSocket
|
|
230
|
-
data: {
|
|
231
|
-
userId: '123',
|
|
232
|
-
authenticated: true,
|
|
233
|
-
permissions: ['read', 'write']
|
|
90
|
+
if (!authHeader) {
|
|
91
|
+
return new Response('Unauthorized', { status: 401 })
|
|
234
92
|
}
|
|
235
|
-
})
|
|
236
93
|
|
|
237
|
-
|
|
238
|
-
return
|
|
94
|
+
// If auth passes, continue to next middleware or route handler
|
|
95
|
+
return next()
|
|
239
96
|
}
|
|
240
|
-
|
|
241
|
-
// If upgrade is successful, this response is ignored
|
|
242
|
-
return new Response('Upgraded to WebSocket')
|
|
243
|
-
})
|
|
244
|
-
|
|
245
|
-
// Get client IP address
|
|
246
|
-
router.get('/ip', (req) => {
|
|
247
|
-
const ip = router.requestIP(req)
|
|
248
|
-
return Response.json(ip)
|
|
249
|
-
})
|
|
250
|
-
|
|
251
|
-
// Set custom timeout for a request
|
|
252
|
-
router.get('/long-operation', (req) => {
|
|
253
|
-
// Extend timeout to 5 minutes for this specific request
|
|
254
|
-
router.timeout(req, 300)
|
|
255
|
-
|
|
256
|
-
// Perform long operation...
|
|
257
|
-
return new Response('Operation completed')
|
|
258
|
-
})
|
|
97
|
+
}
|
|
259
98
|
```
|
|
260
99
|
|
|
261
|
-
###
|
|
100
|
+
### Using Middleware
|
|
262
101
|
|
|
263
|
-
|
|
102
|
+
You can use middleware in several ways:
|
|
264
103
|
|
|
265
|
-
|
|
104
|
+
1. Global Middleware (applies to all routes):
|
|
266
105
|
|
|
267
106
|
```typescript
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
try {
|
|
276
|
-
const data = JSON.parse(message.toString())
|
|
277
|
-
|
|
278
|
-
switch (data.type) {
|
|
279
|
-
case 'login':
|
|
280
|
-
handleLogin(ws, data.userId)
|
|
281
|
-
break
|
|
282
|
-
case 'message':
|
|
283
|
-
handleMessage(ws, data)
|
|
284
|
-
break
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
catch (e) {
|
|
288
|
-
ws.send(JSON.stringify({ error: 'Invalid JSON' }))
|
|
289
|
-
}
|
|
290
|
-
}
|
|
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()
|
|
291
114
|
})
|
|
292
115
|
```
|
|
293
116
|
|
|
294
|
-
|
|
117
|
+
2. Group Middleware (applies to all routes in a group):
|
|
295
118
|
|
|
296
119
|
```typescript
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
message(ws, message) {
|
|
305
|
-
const text = message.toString()
|
|
306
|
-
|
|
307
|
-
if (text.startsWith('/join ')) {
|
|
308
|
-
const newRoom = text.slice(6).trim()
|
|
309
|
-
|
|
310
|
-
// Leave current room
|
|
311
|
-
const oldRoom = ws.data.room
|
|
312
|
-
ws.unsubscribe(oldRoom)
|
|
313
|
-
broadcastToRoom(oldRoom, `${ws.data.userId} left the room`)
|
|
314
|
-
|
|
315
|
-
// Join new room
|
|
316
|
-
ws.data.room = newRoom
|
|
317
|
-
ws.subscribe(newRoom)
|
|
318
|
-
broadcastToRoom(newRoom, `${ws.data.userId} joined the room`)
|
|
319
|
-
|
|
320
|
-
ws.send(`You joined ${newRoom}`)
|
|
321
|
-
}
|
|
322
|
-
else {
|
|
323
|
-
// Regular message
|
|
324
|
-
broadcastToRoom(ws.data.room, `${ws.data.userId}: ${text}`)
|
|
325
|
-
}
|
|
326
|
-
}
|
|
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')
|
|
327
126
|
})
|
|
328
|
-
|
|
329
|
-
function broadcastToRoom(room, message) {
|
|
330
|
-
router.publish(room, message)
|
|
331
|
-
}
|
|
332
127
|
```
|
|
333
128
|
|
|
334
|
-
|
|
129
|
+
3. Inline Middleware:
|
|
335
130
|
|
|
336
131
|
```typescript
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
// Message was queued due to backpressure
|
|
345
|
-
console.log('Backpressure detected, will process more in drain event')
|
|
346
|
-
|
|
347
|
-
// Store state to resume in drain handler
|
|
348
|
-
ws.data.pendingOperations = [/_ ...operations to complete _/]
|
|
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
|
|
349
139
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
// Socket is ready to receive more data
|
|
354
|
-
if (ws.data.pendingOperations?.length) {
|
|
355
|
-
const nextOp = ws.data.pendingOperations.shift()
|
|
356
|
-
processOperation(ws, nextOp)
|
|
357
|
-
}
|
|
358
|
-
}
|
|
140
|
+
]
|
|
141
|
+
}, () => {
|
|
142
|
+
route.get('/users', 'Actions/User/IndexAction')
|
|
359
143
|
})
|
|
360
144
|
```
|
|
361
145
|
|
|
362
|
-
##
|
|
363
|
-
|
|
364
|
-
bun-router fully integrates with Bun's native `Bun.serve()` API, leveraging the latest Bun features for optimal performance.
|
|
365
|
-
|
|
366
|
-
### Static Responses
|
|
146
|
+
## Route Groups
|
|
367
147
|
|
|
368
|
-
|
|
148
|
+
Group related routes with a common prefix and middleware:
|
|
369
149
|
|
|
370
150
|
```typescript
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
})
|
|
375
|
-
|
|
376
|
-
|
|
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
|
+
})
|
|
377
167
|
```
|
|
378
168
|
|
|
379
|
-
|
|
169
|
+
## Route Parameters
|
|
380
170
|
|
|
381
|
-
|
|
171
|
+
Access route parameters through the `params` object:
|
|
382
172
|
|
|
383
173
|
```typescript
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
// These will be organized into a more efficient format:
|
|
390
|
-
// '/api/posts': {
|
|
391
|
-
// GET: getPosts,
|
|
392
|
-
// POST: createPost
|
|
393
|
-
// },
|
|
394
|
-
// '/api/posts/{id}': {
|
|
395
|
-
// PUT: updatePost,
|
|
396
|
-
// DELETE: deletePost
|
|
397
|
-
// }
|
|
174
|
+
route.get('/users/{id}/posts/{postId}', (req) => {
|
|
175
|
+
const { id, postId } = req.params
|
|
176
|
+
return Response.json({ userId: id, postId })
|
|
177
|
+
})
|
|
398
178
|
```
|
|
399
179
|
|
|
400
|
-
|
|
180
|
+
## TypeScript Support
|
|
401
181
|
|
|
402
|
-
|
|
182
|
+
The router is written in TypeScript and provides full type definitions:
|
|
403
183
|
|
|
404
184
|
```typescript
|
|
405
|
-
|
|
406
|
-
const router = new Router()
|
|
407
|
-
router.get('/api/version', () => Response.json({ version: '1.0.0' }))
|
|
408
|
-
const server = await router.serve({ port: 3000 })
|
|
409
|
-
|
|
410
|
-
// Later, update routes without downtime
|
|
411
|
-
router.get('/api/version', () => Response.json({ version: '2.0.0' }))
|
|
412
|
-
await router.reload()
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
### Error Handling
|
|
416
|
-
|
|
417
|
-
Add a global error handler for all routes:
|
|
185
|
+
import type { ActionHandler, EnhancedRequest, Middleware, NextFunction } from '@bun-router'
|
|
418
186
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
return
|
|
423
|
-
|
|
424
|
-
headers: { 'Content-Type': 'text/plain' }
|
|
425
|
-
})
|
|
426
|
-
})
|
|
187
|
+
// Type-safe request handling
|
|
188
|
+
const handler: ActionHandler = (req: EnhancedRequest) => {
|
|
189
|
+
const { id } = req.params
|
|
190
|
+
return Response.json({ id })
|
|
191
|
+
}
|
|
427
192
|
|
|
428
|
-
//
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
})
|
|
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
|
+
}
|
|
432
200
|
|
|
433
|
-
|
|
434
|
-
|
|
201
|
+
route.use(loggerMiddleware.handle)
|
|
202
|
+
route.get('/users/{id}', handler)
|
|
435
203
|
```
|
|
436
204
|
|
|
437
|
-
|
|
205
|
+
## Streaming Support
|
|
438
206
|
|
|
439
|
-
|
|
207
|
+
The router provides comprehensive streaming capabilities for modern web applications:
|
|
440
208
|
|
|
441
|
-
|
|
442
|
-
router.get('/orgs/{orgId}/repos/{repoId}', (req) => {
|
|
443
|
-
// TypeScript knows the shape of req.params
|
|
444
|
-
const { orgId, repoId } = req.params
|
|
445
|
-
return Response.json({ orgId, repoId })
|
|
446
|
-
})
|
|
447
|
-
```
|
|
448
|
-
|
|
449
|
-
### Cookie Handling
|
|
209
|
+
### File Streaming
|
|
450
210
|
|
|
451
|
-
|
|
211
|
+
Stream files with automatic content-type detection:
|
|
452
212
|
|
|
453
213
|
```typescript
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
const
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
return Response.json({ userId, theme })
|
|
460
|
-
})
|
|
461
|
-
|
|
462
|
-
router.get('/login', (req) => {
|
|
463
|
-
// Set cookies
|
|
464
|
-
req.cookies.set('user_id', '12345', {
|
|
465
|
-
httpOnly: true,
|
|
466
|
-
secure: true,
|
|
467
|
-
maxAge: 60 _ 60 * 24 // 1 day
|
|
468
|
-
})
|
|
469
|
-
|
|
470
|
-
return new Response('Logged in')
|
|
214
|
+
// Basic file streaming
|
|
215
|
+
route.get('/download/{filename}', (req) => {
|
|
216
|
+
const { filename } = req.params
|
|
217
|
+
return route.streamFile(`./uploads/${filename}`)
|
|
471
218
|
})
|
|
472
219
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
req.
|
|
476
|
-
|
|
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)
|
|
477
225
|
})
|
|
478
226
|
```
|
|
479
227
|
|
|
480
|
-
###
|
|
228
|
+
### Response Streaming
|
|
481
229
|
|
|
482
|
-
|
|
230
|
+
Create streaming routes with clean, top-level API methods:
|
|
483
231
|
|
|
484
232
|
```typescript
|
|
485
|
-
//
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
return auth.unauthorized('Protected area')
|
|
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))
|
|
491
238
|
}
|
|
492
|
-
|
|
493
|
-
const { username, password } = auth.credentials()
|
|
494
|
-
// Verify against your user database
|
|
495
|
-
|
|
496
|
-
return Response.json({ message: 'Authenticated' })
|
|
497
239
|
})
|
|
498
240
|
|
|
499
|
-
//
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
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
|
+
}
|
|
505
248
|
}
|
|
506
|
-
|
|
507
|
-
const token = auth.token()
|
|
508
|
-
// Verify token validity
|
|
509
|
-
|
|
510
|
-
return Response.json({ message: 'Valid token' })
|
|
249
|
+
close()
|
|
511
250
|
})
|
|
512
251
|
|
|
513
|
-
//
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
expiresIn: '1h',
|
|
521
|
-
secret: 'your-secret-key'
|
|
522
|
-
})
|
|
523
|
-
|
|
524
|
-
return Response.json({ token })
|
|
525
|
-
})
|
|
526
|
-
|
|
527
|
-
router.get('/api/dashboard', (req) => {
|
|
528
|
-
const auth = req.auth.jwt()
|
|
529
|
-
|
|
530
|
-
if (!auth.verify({ secret: 'your-secret-key' })) {
|
|
531
|
-
return auth.unauthorized('Invalid JWT')
|
|
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
|
+
}
|
|
532
259
|
}
|
|
260
|
+
end()
|
|
261
|
+
}, { highWaterMark: 1024 * 1024 }) // 1MB buffer
|
|
262
|
+
```
|
|
533
263
|
|
|
534
|
-
|
|
535
|
-
return Response.json({ user: payload })
|
|
536
|
-
})
|
|
264
|
+
### Server-Sent Events (SSE)
|
|
537
265
|
|
|
538
|
-
|
|
539
|
-
router.get('/api/data', (req) => {
|
|
540
|
-
const auth = req.auth.apiKey('x-api-key')
|
|
266
|
+
Real-time data streaming to web clients:
|
|
541
267
|
|
|
542
|
-
|
|
543
|
-
|
|
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))
|
|
544
279
|
}
|
|
545
|
-
|
|
546
|
-
const apiKey = auth.key()
|
|
547
|
-
// Verify API key against database and check scopes
|
|
548
|
-
|
|
549
|
-
return Response.json({ data: 'Secure data' })
|
|
550
280
|
})
|
|
551
281
|
|
|
552
|
-
//
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
})
|
|
562
|
-
|
|
563
|
-
router.get('/auth/callback', async (req) => {
|
|
564
|
-
const auth = req.auth.oauth2({
|
|
565
|
-
provider: 'github',
|
|
566
|
-
clientId: 'your-client-id',
|
|
567
|
-
clientSecret: 'your-client-secret',
|
|
568
|
-
redirectUri: 'http://localhost:3000/auth/callback'
|
|
569
|
-
})
|
|
570
|
-
|
|
571
|
-
const { accessToken, profile } = await auth.handleCallback(req)
|
|
572
|
-
// Create or update user record
|
|
573
|
-
|
|
574
|
-
return Response.redirect('/dashboard')
|
|
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...
|
|
575
291
|
})
|
|
292
|
+
```
|
|
576
293
|
|
|
577
|
-
###
|
|
294
|
+
### JSON Streaming (NDJSON)
|
|
578
295
|
|
|
579
|
-
|
|
296
|
+
Stream JSON objects line by line:
|
|
580
297
|
|
|
581
298
|
```typescript
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
const
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
headers: {
|
|
589
|
-
'Content-Type': 'application/octet-stream',
|
|
590
|
-
'Content-Disposition': `attachment; filename="${filename}"`
|
|
591
|
-
}
|
|
592
|
-
})
|
|
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
|
+
}
|
|
593
305
|
})
|
|
594
306
|
|
|
595
|
-
//
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
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
|
+
}
|
|
599
315
|
})
|
|
600
316
|
```
|
|
601
317
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
```typescript
|
|
605
|
-
router.group({
|
|
606
|
-
prefix: '/api',
|
|
607
|
-
middleware: [jsonBody()]
|
|
608
|
-
}, () => {
|
|
609
|
-
router.get('/users', getUsersHandler)
|
|
610
|
-
router.post('/users', createUserHandler)
|
|
611
|
-
})
|
|
612
|
-
```
|
|
318
|
+
### Transform Streams
|
|
613
319
|
|
|
614
|
-
|
|
320
|
+
Process incoming request streams using Bun's TransformStream:
|
|
615
321
|
|
|
616
322
|
```typescript
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
router.whereAlphaNumeric('username')
|
|
627
|
-
router.whereUuid('id')
|
|
628
|
-
router.whereIn('status', ['active', 'pending'])
|
|
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
|
+
))
|
|
629
332
|
```
|
|
630
333
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
```typescript
|
|
634
|
-
// Creates all RESTful routes for 'posts'
|
|
635
|
-
router.resource('posts', 'PostsController')
|
|
636
|
-
|
|
637
|
-
// Equivalent to:
|
|
638
|
-
router.get('/posts', 'PostsController/index')
|
|
639
|
-
router.get('/posts/{id}', 'PostsController/show')
|
|
640
|
-
router.post('/posts', 'PostsController/store')
|
|
641
|
-
router.put('/posts/{id}', 'PostsController/update')
|
|
642
|
-
router.delete('/posts/{id}', 'PostsController/destroy')
|
|
643
|
-
```
|
|
334
|
+
### Advanced Streaming Features
|
|
644
335
|
|
|
645
|
-
|
|
336
|
+
Leverage Bun's performance optimizations:
|
|
646
337
|
|
|
647
338
|
```typescript
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
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
|
+
})
|
|
651
347
|
|
|
652
|
-
|
|
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
|
+
})
|
|
653
363
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
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
|
+
}
|
|
659
379
|
})
|
|
660
380
|
})
|
|
661
381
|
```
|
|
662
382
|
|
|
663
|
-
## Configuration
|
|
383
|
+
## Server Configuration
|
|
384
|
+
|
|
385
|
+
The `serve` method accepts all Bun server options:
|
|
664
386
|
|
|
665
387
|
```typescript
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
api: ['Middleware/Cors', 'Middleware/JsonBody'],
|
|
671
|
-
web: ['Middleware/Session', 'Middleware/Csrf']
|
|
672
|
-
}
|
|
388
|
+
route.serve({
|
|
389
|
+
port: 3000,
|
|
390
|
+
hostname: 'localhost',
|
|
391
|
+
development: true,
|
|
673
392
|
})
|
|
674
393
|
```
|
|
675
394
|
|
|
676
|
-
## Changelog
|
|
677
|
-
|
|
678
|
-
Please see our [releases](https://github.com/stackjs/bun-router/releases) page for more information on what has changed recently.
|
|
679
|
-
|
|
680
395
|
## Contributing
|
|
681
396
|
|
|
682
|
-
Please
|
|
683
|
-
|
|
684
|
-
## Community
|
|
685
|
-
|
|
686
|
-
For help, discussion about best practices, or any other conversation that would benefit from being searchable:
|
|
687
|
-
|
|
688
|
-
[Discussions on GitHub](https://github.com/stacksjs/bun-router/discussions)
|
|
689
|
-
|
|
690
|
-
For casual chit-chat with others using this package:
|
|
691
|
-
|
|
692
|
-
[Join the Stacks Discord Server](https://discord.gg/stacksjs)
|
|
693
|
-
|
|
694
|
-
## Postcardware
|
|
695
|
-
|
|
696
|
-
"Software that is free, but hopes for a postcard." We love receiving postcards from around the world showing where Stacks is being used! We showcase them on our website too.
|
|
697
|
-
|
|
698
|
-
Our address: Stacks.js, 12665 Village Ln #2306, Playa Vista, CA 90094, United States 🌎
|
|
699
|
-
|
|
700
|
-
## Sponsors
|
|
701
|
-
|
|
702
|
-
We would like to extend our thanks to the following sponsors for funding Stacks development. If you are interested in becoming a sponsor, please reach out to us.
|
|
703
|
-
|
|
704
|
-
- [JetBrains](https://www.jetbrains.com/)
|
|
705
|
-
- [The Solana Foundation](https://solana.com/)
|
|
706
|
-
|
|
707
|
-
## License
|
|
708
|
-
|
|
709
|
-
The MIT License (MIT). Please see [LICENSE](LICENSE.md) for more information.
|
|
710
|
-
|
|
711
|
-
Made with 💙
|
|
712
|
-
|
|
713
|
-
<!-- Badges -->
|
|
714
|
-
[npm-version-src]: https://img.shields.io/npm/v/bun-router?style=flat-square
|
|
715
|
-
[npm-version-href]: https://npmjs.com/package/bun-router
|
|
716
|
-
[github-actions-src]: https://img.shields.io/github/actions/workflow/status/stacksjs/bun-router/ci.yml?style=flat-square&branch=main
|
|
717
|
-
[github-actions-href]: https://github.com/stacksjs/bun-router/actions?query=workflow%3Aci
|
|
718
|
-
|
|
719
|
-
<!-- [codecov-src]: https://img.shields.io/codecov/c/gh/stacksjs/bun-router/main?style=flat-square
|
|
720
|
-
[codecov-href]: https://codecov.io/gh/stacksjs/bun-router -->
|
|
397
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|