bxo 0.0.5-dev.7 โ 0.0.5-dev.70
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 +87 -512
- package/example/cors-example.ts +49 -0
- package/example/index.html +5 -0
- package/example/index.ts +58 -0
- package/package.json +8 -8
- package/plugins/cors.ts +123 -73
- package/plugins/index.ts +2 -11
- package/plugins/openapi.ts +130 -0
- package/src/index.ts +644 -0
- package/tsconfig.json +3 -5
- package/.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc +0 -111
- package/example.ts +0 -183
- package/index.ts +0 -833
- package/plugins/auth.ts +0 -119
- package/plugins/logger.ts +0 -109
- package/plugins/ratelimit.ts +0 -140
package/README.md
CHANGED
|
@@ -1,579 +1,154 @@
|
|
|
1
|
-
#
|
|
1
|
+
# bxo
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A fast, lightweight web framework for Bun with built-in Zod validation and lifecycle hooks.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
- ๐ **Hot Reload** - Automatic server restart on file changes during development
|
|
13
|
-
- ๐ฎ **Server Management** - Programmatic start, stop, and restart capabilities
|
|
14
|
-
- ๐ **Status Monitoring** - Built-in server status and runtime statistics
|
|
15
|
-
- ๐ฆ **Zero Dependencies** - Only depends on Zod for validation
|
|
16
|
-
- โก **Fast** - Minimal overhead with efficient routing
|
|
7
|
+
- **Type-safe routing** with Zod schema validation
|
|
8
|
+
- **Lifecycle hooks** for middleware and plugins
|
|
9
|
+
- **Plugin system** for extending functionality
|
|
10
|
+
- **Built-in CORS support** via plugin
|
|
11
|
+
- **Fast performance** leveraging Bun's native HTTP server
|
|
17
12
|
|
|
18
|
-
##
|
|
19
|
-
|
|
20
|
-
### Installation
|
|
13
|
+
## Installation
|
|
21
14
|
|
|
22
15
|
```bash
|
|
23
|
-
bun
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### Basic Usage
|
|
27
|
-
|
|
28
|
-
```typescript
|
|
29
|
-
import BXO, { z } from './index';
|
|
30
|
-
|
|
31
|
-
const app = new BXO()
|
|
32
|
-
.get('/', async (ctx) => {
|
|
33
|
-
return { message: 'Hello, BXO!' };
|
|
34
|
-
})
|
|
35
|
-
.start(3000);
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## ๐ Documentation
|
|
39
|
-
|
|
40
|
-
### HTTP Handlers
|
|
41
|
-
|
|
42
|
-
BXO supports all standard HTTP methods with fluent chaining:
|
|
43
|
-
|
|
44
|
-
```typescript
|
|
45
|
-
const app = new BXO()
|
|
46
|
-
// Simple handler
|
|
47
|
-
.get('/simple', async (ctx) => {
|
|
48
|
-
return { message: 'Hello World' };
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
// With validation
|
|
52
|
-
.post('/users', async (ctx) => {
|
|
53
|
-
// ctx.body is fully typed
|
|
54
|
-
return { created: ctx.body };
|
|
55
|
-
}, {
|
|
56
|
-
body: z.object({
|
|
57
|
-
name: z.string(),
|
|
58
|
-
email: z.string().email()
|
|
59
|
-
})
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
// Path parameters
|
|
63
|
-
.get('/users/:id', async (ctx) => {
|
|
64
|
-
// ctx.params.id is typed as UUID string
|
|
65
|
-
return { user: { id: ctx.params.id } };
|
|
66
|
-
}, {
|
|
67
|
-
params: z.object({
|
|
68
|
-
id: z.string().uuid()
|
|
69
|
-
}),
|
|
70
|
-
query: z.object({
|
|
71
|
-
include: z.string().optional()
|
|
72
|
-
})
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
// All HTTP methods supported
|
|
76
|
-
.put('/users/:id', handler)
|
|
77
|
-
.delete('/users/:id', handler)
|
|
78
|
-
.patch('/users/:id', handler);
|
|
16
|
+
bun install
|
|
79
17
|
```
|
|
80
18
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
The context object (`ctx`) provides access to request data and response configuration:
|
|
19
|
+
## Quick Start
|
|
84
20
|
|
|
85
21
|
```typescript
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
query: InferredQueryType; // Query string parameters
|
|
89
|
-
body: InferredBodyType; // Request body
|
|
90
|
-
headers: InferredHeadersType; // Request headers
|
|
91
|
-
request: Request; // Original Request object
|
|
92
|
-
set: { // Response configuration
|
|
93
|
-
status?: number;
|
|
94
|
-
headers?: Record<string, string>;
|
|
95
|
-
};
|
|
96
|
-
user?: any; // Added by auth plugin
|
|
97
|
-
[key: string]: any; // Extended by plugins
|
|
98
|
-
}
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### Validation Configuration
|
|
102
|
-
|
|
103
|
-
Each route can specify validation schemas for different parts of the request:
|
|
104
|
-
|
|
105
|
-
```typescript
|
|
106
|
-
const config = {
|
|
107
|
-
params: z.object({ id: z.string().uuid() }),
|
|
108
|
-
query: z.object({
|
|
109
|
-
page: z.coerce.number().default(1),
|
|
110
|
-
limit: z.coerce.number().max(100).default(10)
|
|
111
|
-
}),
|
|
112
|
-
body: z.object({
|
|
113
|
-
name: z.string().min(1),
|
|
114
|
-
email: z.string().email()
|
|
115
|
-
}),
|
|
116
|
-
headers: z.object({
|
|
117
|
-
'content-type': z.literal('application/json')
|
|
118
|
-
})
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
app.post('/api/users/:id', async (ctx) => {
|
|
122
|
-
// All properties are fully typed based on schemas
|
|
123
|
-
const { id } = ctx.params; // string (UUID)
|
|
124
|
-
const { page, limit } = ctx.query; // number, number
|
|
125
|
-
const { name, email } = ctx.body; // string, string
|
|
126
|
-
}, config);
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
## ๐ Plugin System
|
|
130
|
-
|
|
131
|
-
BXO has a powerful plugin system with lifecycle hooks. Plugins are separate modules imported from `./plugins`.
|
|
132
|
-
|
|
133
|
-
### Available Plugins
|
|
22
|
+
import BXO from "./src/index";
|
|
23
|
+
import { cors } from "./plugins";
|
|
134
24
|
|
|
135
|
-
|
|
25
|
+
const app = new BXO();
|
|
136
26
|
|
|
137
|
-
|
|
138
|
-
|
|
27
|
+
// Use CORS plugin
|
|
28
|
+
app.use(cors());
|
|
139
29
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
methods: ['GET', 'POST', 'PUT', 'DELETE'],
|
|
143
|
-
allowedHeaders: ['Content-Type', 'Authorization'],
|
|
144
|
-
credentials: true,
|
|
145
|
-
maxAge: 86400
|
|
146
|
-
}));
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
#### Logger Plugin
|
|
30
|
+
// Define routes
|
|
31
|
+
app.get("/", (ctx) => ctx.json({ message: "Hello World!" }));
|
|
150
32
|
|
|
151
|
-
|
|
152
|
-
import { logger } from './plugins';
|
|
153
|
-
|
|
154
|
-
app.use(logger({
|
|
155
|
-
format: 'simple', // 'simple' | 'detailed' | 'json'
|
|
156
|
-
includeBody: false, // Log request/response bodies
|
|
157
|
-
includeHeaders: false // Log headers
|
|
158
|
-
}));
|
|
33
|
+
app.start();
|
|
159
34
|
```
|
|
160
35
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
```typescript
|
|
164
|
-
import { auth, createJWT } from './plugins';
|
|
165
|
-
|
|
166
|
-
app.use(auth({
|
|
167
|
-
type: 'jwt', // 'jwt' | 'bearer' | 'apikey'
|
|
168
|
-
secret: 'your-secret-key',
|
|
169
|
-
exclude: ['/login', '/health'], // Skip auth for these paths
|
|
170
|
-
verify: async (token, ctx) => {
|
|
171
|
-
// Custom token verification
|
|
172
|
-
return { user: 'data' };
|
|
173
|
-
}
|
|
174
|
-
}));
|
|
36
|
+
## Lifecycle Hooks
|
|
175
37
|
|
|
176
|
-
|
|
177
|
-
const token = createJWT(
|
|
178
|
-
{ userId: 123, role: 'admin' },
|
|
179
|
-
'secret',
|
|
180
|
-
3600 // expires in 1 hour
|
|
181
|
-
);
|
|
182
|
-
```
|
|
38
|
+
BXO provides powerful lifecycle hooks that allow you to intercept and modify requests and responses at different stages:
|
|
183
39
|
|
|
184
|
-
|
|
40
|
+
### beforeRequest
|
|
41
|
+
Runs before any route processing. Can modify the request or return a response to short-circuit processing.
|
|
185
42
|
|
|
186
43
|
```typescript
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
window: 60, // Time window in seconds
|
|
192
|
-
exclude: ['/health'], // Skip rate limiting for these paths
|
|
193
|
-
keyGenerator: (ctx) => { // Custom key generation
|
|
194
|
-
return ctx.request.headers.get('x-api-key') || 'default';
|
|
195
|
-
},
|
|
196
|
-
message: 'Too many requests',
|
|
197
|
-
statusCode: 429
|
|
198
|
-
}));
|
|
44
|
+
app.beforeRequest(async (req) => {
|
|
45
|
+
console.log(`${req.method} ${req.url}`);
|
|
46
|
+
return req; // Continue with request
|
|
47
|
+
});
|
|
199
48
|
```
|
|
200
49
|
|
|
201
|
-
###
|
|
50
|
+
### afterRequest
|
|
51
|
+
Runs after route processing but before the response is sent. Can modify the final response.
|
|
202
52
|
|
|
203
53
|
```typescript
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
ctx.startTime = Date.now();
|
|
209
|
-
},
|
|
210
|
-
onResponse: async (ctx, response) => {
|
|
211
|
-
console.log(`Request took ${Date.now() - ctx.startTime}ms`);
|
|
212
|
-
return response;
|
|
213
|
-
},
|
|
214
|
-
onError: async (ctx, error) => {
|
|
215
|
-
console.error('Request failed:', error.message);
|
|
216
|
-
return { error: 'Custom error response' };
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
app.use(customPlugin);
|
|
54
|
+
app.afterRequest(async (req, res) => {
|
|
55
|
+
res.headers.set("X-Response-Time", Date.now().toString());
|
|
56
|
+
return res;
|
|
57
|
+
});
|
|
221
58
|
```
|
|
222
59
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
BXO provides comprehensive lifecycle hooks with a consistent before/after pattern for both server and request lifecycle:
|
|
226
|
-
|
|
227
|
-
### Server Lifecycle Hooks
|
|
60
|
+
### beforeResponse
|
|
61
|
+
Runs after the route handler but before response headers are merged. Useful for modifying response metadata.
|
|
228
62
|
|
|
229
63
|
```typescript
|
|
230
|
-
app
|
|
231
|
-
.
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
.onAfterStart(() => {
|
|
235
|
-
console.log('โ
Server fully started and ready!');
|
|
236
|
-
})
|
|
237
|
-
.onBeforeStop(() => {
|
|
238
|
-
console.log('๐ง Preparing to stop server...');
|
|
239
|
-
})
|
|
240
|
-
.onAfterStop(() => {
|
|
241
|
-
console.log('โ
Server fully stopped!');
|
|
242
|
-
})
|
|
243
|
-
.onBeforeRestart(() => {
|
|
244
|
-
console.log('๐ง Preparing to restart server...');
|
|
245
|
-
})
|
|
246
|
-
.onAfterRestart(() => {
|
|
247
|
-
console.log('โ
Server restart completed!');
|
|
248
|
-
});
|
|
64
|
+
app.beforeResponse(async (res) => {
|
|
65
|
+
res.headers.set("X-Custom-Header", "value");
|
|
66
|
+
return res;
|
|
67
|
+
});
|
|
249
68
|
```
|
|
250
69
|
|
|
251
|
-
###
|
|
70
|
+
### onError
|
|
71
|
+
Runs when an error occurs during request processing. Can return a custom error response.
|
|
252
72
|
|
|
253
73
|
```typescript
|
|
254
|
-
app
|
|
255
|
-
.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
.onResponse((ctx, response) => {
|
|
259
|
-
console.log(`๐ค Response sent`);
|
|
260
|
-
return response; // Can modify response
|
|
261
|
-
})
|
|
262
|
-
.onError((ctx, error) => {
|
|
263
|
-
console.error(`๐ฅ Error:`, error.message);
|
|
264
|
-
return { error: 'Something went wrong' }; // Can provide custom error response
|
|
265
|
-
});
|
|
74
|
+
app.onError(async (error, req) => {
|
|
75
|
+
console.error(`Error: ${error.message}`);
|
|
76
|
+
return new Response("Internal Server Error", { status: 500 });
|
|
77
|
+
});
|
|
266
78
|
```
|
|
267
79
|
|
|
268
|
-
##
|
|
80
|
+
## Plugins
|
|
269
81
|
|
|
270
|
-
|
|
82
|
+
### CORS Plugin
|
|
271
83
|
|
|
272
|
-
|
|
84
|
+
The CORS plugin provides comprehensive Cross-Origin Resource Sharing support:
|
|
273
85
|
|
|
274
86
|
```typescript
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
// Enable hot reload - server will restart when files change
|
|
278
|
-
app.enableHotReload(['./']); // Watch current directory
|
|
87
|
+
import { cors } from "./plugins";
|
|
279
88
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
89
|
+
app.use(cors({
|
|
90
|
+
origin: ["http://localhost:3000", "https://myapp.com"],
|
|
91
|
+
methods: ["GET", "POST", "PUT", "DELETE"],
|
|
92
|
+
credentials: true
|
|
93
|
+
}));
|
|
283
94
|
```
|
|
284
95
|
|
|
285
|
-
###
|
|
286
|
-
|
|
287
|
-
```typescript
|
|
288
|
-
const app = new BXO();
|
|
289
|
-
|
|
290
|
-
// Start server
|
|
291
|
-
await app.start(3000, 'localhost');
|
|
292
|
-
|
|
293
|
-
// Check if server is running
|
|
294
|
-
if (app.isServerRunning()) {
|
|
295
|
-
console.log('Server is running!');
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// Get server information
|
|
299
|
-
const info = app.getServerInfo();
|
|
300
|
-
console.log(info); // { running: true, hotReload: true, watchedFiles: ['./'] }
|
|
301
|
-
|
|
302
|
-
// Restart server programmatically
|
|
303
|
-
await app.restart(3000, 'localhost');
|
|
304
|
-
|
|
305
|
-
// Stop server gracefully
|
|
306
|
-
await app.stop();
|
|
307
|
-
|
|
308
|
-
// Backward compatibility - listen() still works
|
|
309
|
-
await app.listen(3000); // Same as app.start(3000)
|
|
310
|
-
```
|
|
96
|
+
### Creating Custom Plugins
|
|
311
97
|
|
|
312
|
-
|
|
98
|
+
Plugins are just BXO instances with lifecycle hooks:
|
|
313
99
|
|
|
314
100
|
```typescript
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
if (process.env.NODE_ENV === 'development') {
|
|
318
|
-
// Enable hot reload in development
|
|
319
|
-
app.enableHotReload(['./src', './routes']);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// Add server management endpoints for development
|
|
323
|
-
if (process.env.NODE_ENV === 'development') {
|
|
324
|
-
app.post('/dev/restart', async (ctx) => {
|
|
325
|
-
setTimeout(() => app.restart(3000), 100);
|
|
326
|
-
return { message: 'Server restart initiated' };
|
|
327
|
-
});
|
|
101
|
+
function loggingPlugin() {
|
|
102
|
+
const plugin = new BXO();
|
|
328
103
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
uptime: process.uptime(),
|
|
333
|
-
memory: process.memoryUsage()
|
|
334
|
-
};
|
|
104
|
+
plugin.beforeRequest(async (req) => {
|
|
105
|
+
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
|
|
106
|
+
return req;
|
|
335
107
|
});
|
|
336
|
-
}
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
## ๐ Complete Example
|
|
340
|
-
|
|
341
|
-
```typescript
|
|
342
|
-
import BXO, { z } from './index';
|
|
343
|
-
import { cors, logger, auth, rateLimit, createJWT } from './plugins';
|
|
344
|
-
|
|
345
|
-
const app = new BXO();
|
|
346
|
-
|
|
347
|
-
// Enable hot reload for development
|
|
348
|
-
app.enableHotReload(['./']);
|
|
349
|
-
|
|
350
|
-
// Add plugins
|
|
351
|
-
app
|
|
352
|
-
.use(logger({ format: 'simple' }))
|
|
353
|
-
.use(cors({
|
|
354
|
-
origin: ['http://localhost:3000'],
|
|
355
|
-
credentials: true
|
|
356
|
-
}))
|
|
357
|
-
.use(rateLimit({
|
|
358
|
-
max: 100,
|
|
359
|
-
window: 60,
|
|
360
|
-
exclude: ['/health']
|
|
361
|
-
}))
|
|
362
|
-
.use(auth({
|
|
363
|
-
type: 'jwt',
|
|
364
|
-
secret: 'your-secret-key',
|
|
365
|
-
exclude: ['/', '/login', '/health']
|
|
366
|
-
}));
|
|
367
|
-
|
|
368
|
-
// Comprehensive lifecycle hooks
|
|
369
|
-
app
|
|
370
|
-
.onBeforeStart(() => console.log('๐ง Preparing server startup...'))
|
|
371
|
-
.onAfterStart(() => console.log('โ
Server ready!'))
|
|
372
|
-
.onBeforeRestart(() => console.log('๐ Restarting server...'))
|
|
373
|
-
.onAfterRestart(() => console.log('โ
Server restarted!'))
|
|
374
|
-
.onError((ctx, error) => ({
|
|
375
|
-
error: 'Internal server error',
|
|
376
|
-
timestamp: new Date().toISOString()
|
|
377
|
-
}));
|
|
378
|
-
|
|
379
|
-
// Routes
|
|
380
|
-
app
|
|
381
|
-
.get('/health', async () => ({
|
|
382
|
-
status: 'ok',
|
|
383
|
-
timestamp: new Date().toISOString(),
|
|
384
|
-
server: app.getServerInfo()
|
|
385
|
-
}))
|
|
386
|
-
|
|
387
|
-
.post('/login', async (ctx) => {
|
|
388
|
-
const { username, password } = ctx.body;
|
|
389
|
-
|
|
390
|
-
if (username === 'admin' && password === 'password') {
|
|
391
|
-
const token = createJWT(
|
|
392
|
-
{ username, role: 'admin' },
|
|
393
|
-
'your-secret-key'
|
|
394
|
-
);
|
|
395
|
-
return { token, user: { username, role: 'admin' } };
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
ctx.set.status = 401;
|
|
399
|
-
return { error: 'Invalid credentials' };
|
|
400
|
-
}, {
|
|
401
|
-
body: z.object({
|
|
402
|
-
username: z.string(),
|
|
403
|
-
password: z.string()
|
|
404
|
-
})
|
|
405
|
-
})
|
|
406
|
-
|
|
407
|
-
.get('/users/:id', async (ctx) => {
|
|
408
|
-
return {
|
|
409
|
-
user: {
|
|
410
|
-
id: ctx.params.id,
|
|
411
|
-
include: ctx.query.include
|
|
412
|
-
}
|
|
413
|
-
};
|
|
414
|
-
}, {
|
|
415
|
-
params: z.object({ id: z.string().uuid() }),
|
|
416
|
-
query: z.object({ include: z.string().optional() })
|
|
417
|
-
})
|
|
418
108
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
}, {
|
|
422
|
-
body: z.object({
|
|
423
|
-
name: z.string(),
|
|
424
|
-
email: z.string().email()
|
|
425
|
-
})
|
|
426
|
-
})
|
|
427
|
-
|
|
428
|
-
.get('/protected', async (ctx) => {
|
|
429
|
-
// ctx.user available from auth plugin
|
|
430
|
-
return {
|
|
431
|
-
message: 'Protected resource',
|
|
432
|
-
user: ctx.user
|
|
433
|
-
};
|
|
434
|
-
})
|
|
435
|
-
|
|
436
|
-
// Server management endpoints
|
|
437
|
-
.post('/restart', async (ctx) => {
|
|
438
|
-
setTimeout(() => app.restart(3000), 100);
|
|
439
|
-
return { message: 'Server restart initiated' };
|
|
440
|
-
})
|
|
441
|
-
|
|
442
|
-
.get('/status', async (ctx) => {
|
|
443
|
-
return {
|
|
444
|
-
...app.getServerInfo(),
|
|
445
|
-
uptime: process.uptime(),
|
|
446
|
-
memory: process.memoryUsage()
|
|
447
|
-
};
|
|
448
|
-
});
|
|
109
|
+
return plugin;
|
|
110
|
+
}
|
|
449
111
|
|
|
450
|
-
|
|
451
|
-
app.start(3000);
|
|
112
|
+
app.use(loggingPlugin());
|
|
452
113
|
```
|
|
453
114
|
|
|
454
|
-
##
|
|
455
|
-
|
|
456
|
-
With the example server running, test these endpoints:
|
|
115
|
+
## Route Validation
|
|
457
116
|
|
|
458
|
-
|
|
459
|
-
# Health check
|
|
460
|
-
curl http://localhost:3000/health
|
|
461
|
-
|
|
462
|
-
# Login to get token
|
|
463
|
-
curl -X POST http://localhost:3000/login \
|
|
464
|
-
-H "Content-Type: application/json" \
|
|
465
|
-
-d '{"username": "admin", "password": "password"}'
|
|
466
|
-
|
|
467
|
-
# Create user
|
|
468
|
-
curl -X POST http://localhost:3000/users \
|
|
469
|
-
-H "Content-Type: application/json" \
|
|
470
|
-
-d '{"name": "John Doe", "email": "john@example.com"}'
|
|
471
|
-
|
|
472
|
-
# Get user with validation
|
|
473
|
-
curl "http://localhost:3000/users/123e4567-e89b-12d3-a456-426614174000?include=profile"
|
|
474
|
-
|
|
475
|
-
# Access protected route (use token from login)
|
|
476
|
-
curl http://localhost:3000/protected \
|
|
477
|
-
-H "Authorization: Bearer YOUR_JWT_TOKEN"
|
|
478
|
-
|
|
479
|
-
# Check server status
|
|
480
|
-
curl http://localhost:3000/status
|
|
481
|
-
|
|
482
|
-
# Restart server programmatically
|
|
483
|
-
curl -X POST http://localhost:3000/restart
|
|
484
|
-
```
|
|
485
|
-
|
|
486
|
-
## ๐ API Reference
|
|
487
|
-
|
|
488
|
-
### BXO Class Methods
|
|
489
|
-
|
|
490
|
-
#### HTTP Methods
|
|
491
|
-
- `get(path, handler, config?)` - Handle GET requests
|
|
492
|
-
- `post(path, handler, config?)` - Handle POST requests
|
|
493
|
-
- `put(path, handler, config?)` - Handle PUT requests
|
|
494
|
-
- `delete(path, handler, config?)` - Handle DELETE requests
|
|
495
|
-
- `patch(path, handler, config?)` - Handle PATCH requests
|
|
496
|
-
|
|
497
|
-
#### Plugins & Hooks
|
|
498
|
-
- `use(plugin)` - Add a plugin
|
|
499
|
-
- `onBeforeStart(handler)` - Before server start hook
|
|
500
|
-
- `onAfterStart(handler)` - After server start hook
|
|
501
|
-
- `onBeforeStop(handler)` - Before server stop hook
|
|
502
|
-
- `onAfterStop(handler)` - After server stop hook
|
|
503
|
-
- `onBeforeRestart(handler)` - Before server restart hook
|
|
504
|
-
- `onAfterRestart(handler)` - After server restart hook
|
|
505
|
-
- `onRequest(handler)` - Global request hook
|
|
506
|
-
- `onResponse(handler)` - Global response hook
|
|
507
|
-
- `onError(handler)` - Global error hook
|
|
508
|
-
|
|
509
|
-
#### Server Management
|
|
510
|
-
- `start(port?, hostname?)` - Start the server
|
|
511
|
-
- `stop()` - Stop the server gracefully
|
|
512
|
-
- `restart(port?, hostname?)` - Restart the server
|
|
513
|
-
- `listen(port?, hostname?)` - Start the server (backward compatibility)
|
|
514
|
-
- `isServerRunning()` - Check if server is running
|
|
515
|
-
- `getServerInfo()` - Get server status information
|
|
516
|
-
|
|
517
|
-
#### Hot Reload
|
|
518
|
-
- `enableHotReload(watchPaths?)` - Enable hot reload with file watching
|
|
519
|
-
|
|
520
|
-
### Route Configuration
|
|
117
|
+
Define Zod schemas for request validation:
|
|
521
118
|
|
|
522
119
|
```typescript
|
|
523
|
-
|
|
524
|
-
params?: z.ZodSchema<any>; // Path parameter validation
|
|
525
|
-
query?: z.ZodSchema<any>; // Query string validation
|
|
526
|
-
body?: z.ZodSchema<any>; // Request body validation
|
|
527
|
-
headers?: z.ZodSchema<any>; // Header validation
|
|
528
|
-
}
|
|
529
|
-
```
|
|
120
|
+
import { z } from "bxo";
|
|
530
121
|
|
|
531
|
-
|
|
122
|
+
const UserSchema = z.object({
|
|
123
|
+
name: z.string().min(1),
|
|
124
|
+
email: z.string().email()
|
|
125
|
+
});
|
|
532
126
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
}
|
|
127
|
+
app.post("/users", async (ctx) => {
|
|
128
|
+
const user = ctx.body; // Already validated by UserSchema
|
|
129
|
+
return ctx.json({ id: 1, ...user });
|
|
130
|
+
}, {
|
|
131
|
+
body: UserSchema
|
|
132
|
+
});
|
|
540
133
|
```
|
|
541
134
|
|
|
542
|
-
##
|
|
543
|
-
|
|
544
|
-
### Running the Example
|
|
135
|
+
## Running
|
|
545
136
|
|
|
546
137
|
```bash
|
|
547
|
-
|
|
548
|
-
bun run example.ts
|
|
549
|
-
|
|
550
|
-
# The server will automatically restart when you edit any .ts/.js files!
|
|
138
|
+
bun run ./src/index.ts
|
|
551
139
|
```
|
|
552
140
|
|
|
553
|
-
|
|
141
|
+
Or run the CORS example:
|
|
554
142
|
|
|
143
|
+
```bash
|
|
144
|
+
bun run ./example/cors-example.ts
|
|
555
145
|
```
|
|
556
|
-
bxo/
|
|
557
|
-
โโโ index.ts # Main BXO framework
|
|
558
|
-
โโโ plugins/
|
|
559
|
-
โ โโโ index.ts # Plugin exports
|
|
560
|
-
โ โโโ cors.ts # CORS plugin
|
|
561
|
-
โ โโโ logger.ts # Logger plugin
|
|
562
|
-
โ โโโ auth.ts # Authentication plugin
|
|
563
|
-
โ โโโ ratelimit.ts # Rate limiting plugin
|
|
564
|
-
โโโ example.ts # Usage example
|
|
565
|
-
โโโ package.json
|
|
566
|
-
โโโ README.md
|
|
567
|
-
```
|
|
568
|
-
|
|
569
|
-
## ๐ค Contributing
|
|
570
|
-
|
|
571
|
-
BXO is designed to be simple and extensible. Contributions are welcome!
|
|
572
146
|
|
|
573
|
-
##
|
|
147
|
+
## Examples
|
|
574
148
|
|
|
575
|
-
|
|
149
|
+
Check out the `example/` directory for more usage examples:
|
|
576
150
|
|
|
577
|
-
|
|
151
|
+
- `cors-example.ts` - Demonstrates CORS plugin and lifecycle hooks
|
|
152
|
+
- `index.ts` - Basic routing example
|
|
578
153
|
|
|
579
|
-
|
|
154
|
+
This project was created using `bun init` in bun v1.2.3. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
|