@b9g/router 0.1.3 → 0.1.5
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 +199 -0
- package/package.json +4 -3
package/README.md
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# @b9g/router
|
|
2
|
+
|
|
3
|
+
Universal request router built on web standards with cache-aware routing and middleware support.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Web Standards Based**: Built on URLPattern, Request, Response, and Cache APIs
|
|
8
|
+
- **Cache-Aware Routing**: First-class cache integration with automatic population
|
|
9
|
+
- **Middleware Support**: Global and route-specific middleware with `next()` pattern
|
|
10
|
+
- **Method Routing**: HTTP method shortcuts (get, post, put, delete, etc.)
|
|
11
|
+
- **Universal**: Same code runs in browsers, Node.js, Bun, and edge platforms
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @b9g/router @b9g/match-pattern
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
import { Router } from '@b9g/router';
|
|
23
|
+
|
|
24
|
+
const router = new Router();
|
|
25
|
+
|
|
26
|
+
// Simple route
|
|
27
|
+
router.get('/hello', () => new Response('Hello World!'));
|
|
28
|
+
|
|
29
|
+
// Route with parameters
|
|
30
|
+
router.get('/posts/:id', (request, context) => {
|
|
31
|
+
const { id } = context.params;
|
|
32
|
+
return Response.json({ id, title: `Post ${id}` });
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Handle request
|
|
36
|
+
const response = await router.handler(request);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Cache-Aware Routing
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
import { Router } from '@b9g/router';
|
|
43
|
+
import { CacheStorage, MemoryCache } from '@b9g/cache';
|
|
44
|
+
|
|
45
|
+
// Setup cache storage
|
|
46
|
+
const caches = new CacheStorage();
|
|
47
|
+
caches.register('posts', () => new MemoryCache('posts'));
|
|
48
|
+
|
|
49
|
+
const router = new Router({ caches });
|
|
50
|
+
|
|
51
|
+
// Route with cache declaration
|
|
52
|
+
router.route({
|
|
53
|
+
pattern: '/api/posts/:id',
|
|
54
|
+
cache: { name: 'posts' }
|
|
55
|
+
}).get(async (request, context) => {
|
|
56
|
+
// context.cache is the opened 'posts' cache
|
|
57
|
+
const post = await db.posts.get(context.params.id);
|
|
58
|
+
return Response.json(post);
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Middleware
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
// Global middleware
|
|
66
|
+
router.use(async (request, context, next) => {
|
|
67
|
+
console.log(`${request.method} ${request.url}`);
|
|
68
|
+
const response = await next();
|
|
69
|
+
return response;
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Route-specific middleware
|
|
73
|
+
router.route('/admin/*')
|
|
74
|
+
.use(authMiddleware)
|
|
75
|
+
.use(rateLimitMiddleware)
|
|
76
|
+
.get(adminHandler);
|
|
77
|
+
|
|
78
|
+
// Pattern-based middleware
|
|
79
|
+
router.use('/api/*', corsMiddleware);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## API Reference
|
|
83
|
+
|
|
84
|
+
### Router
|
|
85
|
+
|
|
86
|
+
#### Constructor
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
new Router(options?)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Options:
|
|
93
|
+
- `caches`: CacheStorage instance for cache-aware routing
|
|
94
|
+
|
|
95
|
+
#### Methods
|
|
96
|
+
|
|
97
|
+
##### `route(pattern, options?)`
|
|
98
|
+
|
|
99
|
+
Create a route builder for the given pattern.
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
router.route('/api/posts/:id', { cache: { name: 'posts' } })
|
|
103
|
+
.use(middleware)
|
|
104
|
+
.get(handler);
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
##### HTTP Method Shortcuts
|
|
108
|
+
|
|
109
|
+
```javascript
|
|
110
|
+
router.get(pattern, handler)
|
|
111
|
+
router.post(pattern, handler)
|
|
112
|
+
router.put(pattern, handler)
|
|
113
|
+
router.delete(pattern, handler)
|
|
114
|
+
router.patch(pattern, handler)
|
|
115
|
+
router.head(pattern, handler)
|
|
116
|
+
router.options(pattern, handler)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
##### `use(pattern?, middleware)`
|
|
120
|
+
|
|
121
|
+
Add middleware globally or for specific patterns.
|
|
122
|
+
|
|
123
|
+
##### `handler(request): Promise<Response>`
|
|
124
|
+
|
|
125
|
+
Bound handler function for processing requests.
|
|
126
|
+
|
|
127
|
+
### Context Object
|
|
128
|
+
|
|
129
|
+
Handler and middleware functions receive a context object:
|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
{
|
|
133
|
+
params: Record<string, string>, // URL parameters
|
|
134
|
+
cache?: Cache, // Opened cache for this route
|
|
135
|
+
caches?: CacheStorage, // All available caches
|
|
136
|
+
// ... additional context
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Examples
|
|
141
|
+
|
|
142
|
+
### Basic API Router
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
const router = new Router();
|
|
146
|
+
|
|
147
|
+
router.get('/api/health', () =>
|
|
148
|
+
Response.json({ status: 'ok' })
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
router.get('/api/posts', async () => {
|
|
152
|
+
const posts = await db.posts.findAll();
|
|
153
|
+
return Response.json(posts);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
router.post('/api/posts', async (request) => {
|
|
157
|
+
const data = await request.json();
|
|
158
|
+
const post = await db.posts.create(data);
|
|
159
|
+
return Response.json(post, { status: 201 });
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### With Caching
|
|
164
|
+
|
|
165
|
+
```javascript
|
|
166
|
+
import { Router } from '@b9g/router';
|
|
167
|
+
import { CacheStorage, MemoryCache } from '@b9g/cache';
|
|
168
|
+
|
|
169
|
+
const caches = new CacheStorage();
|
|
170
|
+
caches.register('api', () => new MemoryCache('api'));
|
|
171
|
+
|
|
172
|
+
const router = new Router({ caches });
|
|
173
|
+
|
|
174
|
+
// Cache-aware middleware
|
|
175
|
+
router.use(async (request, context, next) => {
|
|
176
|
+
if (request.method === 'GET' && context.cache) {
|
|
177
|
+
const cached = await context.cache.match(request);
|
|
178
|
+
if (cached) return cached;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const response = await next();
|
|
182
|
+
|
|
183
|
+
if (request.method === 'GET' && context.cache && response.ok) {
|
|
184
|
+
await context.cache.put(request, response.clone());
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return response;
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
router.route('/api/posts/:id', { cache: { name: 'api' } })
|
|
191
|
+
.get(async (request, context) => {
|
|
192
|
+
const post = await db.posts.get(context.params.id);
|
|
193
|
+
return Response.json(post);
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## License
|
|
198
|
+
|
|
199
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@b9g/router",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"dependencies": {
|
|
5
|
-
"@b9g/match-pattern": "^0.1.
|
|
5
|
+
"@b9g/match-pattern": "^0.1.6"
|
|
6
6
|
},
|
|
7
7
|
"devDependencies": {
|
|
8
|
-
"@b9g/libuild": "^0.1.
|
|
8
|
+
"@b9g/libuild": "^0.1.11",
|
|
9
|
+
"bun-types": "latest"
|
|
9
10
|
},
|
|
10
11
|
"type": "module",
|
|
11
12
|
"types": "src/index.d.ts",
|