bxo 0.0.5-dev.64 โ†’ 0.0.5-dev.66

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 CHANGED
@@ -1,676 +1,154 @@
1
- # ๐ŸฆŠ BXO - A Type-Safe Web Framework for Bun
1
+ # bxo
2
2
 
3
- BXO is a fast, lightweight, and fully type-safe web framework built specifically for Bun runtime. Inspired by Elysia, it provides excellent developer experience with automatic type inference, Zod validation, and a powerful plugin system.
3
+ A fast, lightweight web framework for Bun with built-in Zod validation and lifecycle hooks.
4
4
 
5
- ## โœจ Features
5
+ ## Features
6
6
 
7
- - ๐Ÿš€ **Built for Bun** - Leverages Bun's native HTTP server for maximum performance
8
- - ๐Ÿ”’ **Type-Safe** - Full TypeScript support with automatic type inference
9
- - ๐Ÿ“‹ **Zod Validation** - Built-in request/response validation using Zod schemas
10
- - ๐Ÿ”Œ **Plugin System** - Extensible architecture with lifecycle hooks
11
- - ๐ŸŽฃ **Lifecycle Hooks** - Complete control over server and request/response lifecycle
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
- ## ๐Ÿš€ Quick Start
19
-
20
- ### Installation
13
+ ## Installation
21
14
 
22
15
  ```bash
23
- bun add bxo
16
+ bun install
24
17
  ```
25
18
 
26
- ### Basic Usage
19
+ ## Quick Start
27
20
 
28
21
  ```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
- ```
22
+ import BXO from "./src/index";
23
+ import { cors } from "./plugins";
37
24
 
38
- ## ๐Ÿ“š Documentation
25
+ const app = new BXO();
39
26
 
40
- ### HTTP Handlers
27
+ // Use CORS plugin
28
+ app.use(cors());
41
29
 
42
- BXO supports all standard HTTP methods with fluent chaining:
30
+ // Define routes
31
+ app.get("/", (ctx) => ctx.json({ message: "Hello World!" }));
43
32
 
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);
33
+ app.start();
79
34
  ```
80
35
 
81
- ### Context Object
36
+ ## Lifecycle Hooks
82
37
 
83
- The context object (`ctx`) provides access to request data and response configuration:
38
+ BXO provides powerful lifecycle hooks that allow you to intercept and modify requests and responses at different stages:
84
39
 
85
- ```typescript
86
- interface Context<TConfig> {
87
- params: InferredParamsType; // Path parameters
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
- status: (code: number, data?: any) => any; // Type-safe status method
97
- user?: any; // Added by auth plugin
98
- [key: string]: any; // Extended by plugins
99
- }
100
- ```
101
-
102
- ### Type-Safe Status Method
103
-
104
- BXO provides a type-safe `ctx.status()` method similar to Elysia, which allows you to set HTTP status codes and return data in one call:
40
+ ### beforeRequest
41
+ Runs before any route processing. Can modify the request or return a response to short-circuit processing.
105
42
 
106
43
  ```typescript
107
- // Simple usage
108
- app.get('/hello', (ctx) => {
109
- return ctx.status(200, { message: 'Hello World' });
44
+ app.beforeRequest(async (req) => {
45
+ console.log(`${req.method} ${req.url}`);
46
+ return req; // Continue with request
110
47
  });
111
-
112
- // With response validation
113
- app.get('/user/:id', (ctx) => {
114
- const userId = ctx.params.id;
115
-
116
- if (userId === 'not-found') {
117
- // TypeScript suggests 404 as valid status
118
- return ctx.status(404, { error: 'User not found' });
119
- }
120
-
121
- // TypeScript suggests 200 as valid status
122
- return ctx.status(200, { user: { id: userId, name: 'John Doe' } });
123
- }, {
124
- response: {
125
- 200: z.object({
126
- user: z.object({
127
- id: z.string(),
128
- name: z.string()
129
- })
130
- }),
131
- 404: z.object({
132
- error: z.string()
133
- })
134
- }
135
- });
136
-
137
- // POST with validation and status responses
138
- app.post('/users', (ctx) => {
139
- const { name, email } = ctx.body;
140
-
141
- if (!name || !email) {
142
- return ctx.status(400, { error: 'Missing required fields' });
143
- }
144
-
145
- return ctx.status(201, {
146
- success: true,
147
- user: { id: 1, name, email }
148
- });
149
- }, {
150
- body: z.object({
151
- name: z.string(),
152
- email: z.string().email()
153
- }),
154
- response: {
155
- 201: z.object({
156
- success: z.boolean(),
157
- user: z.object({
158
- id: z.number(),
159
- name: z.string(),
160
- email: z.string()
161
- })
162
- }),
163
- 400: z.object({
164
- error: z.string()
165
- })
166
- }
167
- });
168
- ```
169
-
170
- **Key Features:**
171
- - **Type Safety**: Status codes are suggested based on your response configuration
172
- - **Data Validation**: Return data is validated against the corresponding schema
173
- - **Autocomplete**: TypeScript provides autocomplete for valid status codes
174
- - **Return Type Inference**: Return types are properly inferred from schemas
175
-
176
- ### Validation Configuration
177
-
178
- Each route can specify validation schemas for different parts of the request:
179
-
180
- ```typescript
181
- const config = {
182
- params: z.object({ id: z.string().uuid() }),
183
- query: z.object({
184
- page: z.coerce.number().default(1),
185
- limit: z.coerce.number().max(100).default(10)
186
- }),
187
- body: z.object({
188
- name: z.string().min(1),
189
- email: z.string().email()
190
- }),
191
- headers: z.object({
192
- 'content-type': z.literal('application/json')
193
- })
194
- };
195
-
196
- app.post('/api/users/:id', async (ctx) => {
197
- // All properties are fully typed based on schemas
198
- const { id } = ctx.params; // string (UUID)
199
- const { page, limit } = ctx.query; // number, number
200
- const { name, email } = ctx.body; // string, string
201
- }, config);
202
- ```
203
-
204
- ## ๐Ÿ”Œ Plugin System
205
-
206
- BXO has a powerful plugin system with lifecycle hooks. Plugins can be either middleware-style plugins or full BXO instances. Middleware plugins are separate modules imported from `./plugins` and are executed in the order they are added.
207
-
208
- ### Available Plugins
209
-
210
- #### CORS Plugin
211
-
212
- ```typescript
213
- import { cors } from './plugins';
214
-
215
- app.use(cors({
216
- origin: ['http://localhost:3000', 'https://example.com'],
217
- methods: ['GET', 'POST', 'PUT', 'DELETE'],
218
- allowedHeaders: ['Content-Type', 'Authorization'],
219
- credentials: true,
220
- maxAge: 86400
221
- }));
222
48
  ```
223
49
 
224
- **Features:**
225
- - **Origin Header Support**: Standard CORS origin header handling
226
- - **Referer Header Fallback**: Automatically falls back to Referer header when Origin is not present
227
- - **Origin Precedence**: When both Origin and Referer are present, Origin takes precedence
228
- - **Invalid URL Handling**: Gracefully handles invalid Referer URLs
229
- - **Flexible Origin Configuration**: Supports string, array, boolean, or wildcard (`*`) origins
230
-
231
- #### Logger Plugin
50
+ ### afterRequest
51
+ Runs after route processing but before the response is sent. Can modify the final response.
232
52
 
233
53
  ```typescript
234
- import { logger } from './plugins';
235
-
236
- app.use(logger({
237
- format: 'simple', // 'simple' | 'detailed' | 'json'
238
- includeBody: false, // Log request/response bodies
239
- includeHeaders: false // Log headers
240
- }));
241
- ```
242
-
243
- #### Authentication Plugin
244
-
245
- ```typescript
246
- import { auth, createJWT } from './plugins';
247
-
248
- app.use(auth({
249
- type: 'jwt', // 'jwt' | 'bearer' | 'apikey'
250
- secret: 'your-secret-key',
251
- exclude: ['/login', '/health'], // Skip auth for these paths
252
- verify: async (token, ctx) => {
253
- // Custom token verification
254
- return { user: 'data' };
255
- }
256
- }));
257
-
258
- // Create JWT tokens
259
- const token = createJWT(
260
- { userId: 123, role: 'admin' },
261
- 'secret',
262
- 3600 // expires in 1 hour
263
- );
264
- ```
265
-
266
- #### Rate Limiting Plugin
267
-
268
- ```typescript
269
- import { rateLimit } from './plugins';
270
-
271
- app.use(rateLimit({
272
- max: 100, // Max requests
273
- window: 60, // Time window in seconds
274
- exclude: ['/health'], // Skip rate limiting for these paths
275
- keyGenerator: (ctx) => { // Custom key generation
276
- return ctx.request.headers.get('x-api-key') || 'default';
277
- },
278
- message: 'Too many requests',
279
- statusCode: 429
280
- }));
281
- ```
282
-
283
- ### Creating Custom Plugins
284
-
285
- #### Middleware-Style Plugins (Recommended)
286
-
287
- ```typescript
288
- const customPlugin = {
289
- name: 'custom',
290
- onRequest: async (ctx) => {
291
- console.log('Before request processing');
292
- ctx.startTime = Date.now();
293
- },
294
- onResponse: async (ctx, response) => {
295
- console.log(`Request took ${Date.now() - ctx.startTime}ms`);
296
- return response;
297
- },
298
- onError: async (ctx, error) => {
299
- console.error('Request failed:', error.message);
300
- return { error: 'Custom error response' };
301
- }
302
- };
303
-
304
- app.use(customPlugin);
305
- ```
306
-
307
- #### Full BXO Instance Plugins
308
-
309
- You can also use full BXO instances as plugins, which will merge their routes and hooks:
310
-
311
- ```typescript
312
- const pluginApp = new BXO();
313
- pluginApp.get('/plugin-route', async (ctx) => {
314
- return { message: 'From plugin' };
54
+ app.afterRequest(async (req, res) => {
55
+ res.headers.set("X-Response-Time", Date.now().toString());
56
+ return res;
315
57
  });
316
-
317
- app.use(pluginApp);
318
58
  ```
319
59
 
320
- ## ๐ŸŽฃ Lifecycle Hooks
321
-
322
- BXO provides comprehensive lifecycle hooks with a consistent before/after pattern for both server and request lifecycle:
323
-
324
- ### Server Lifecycle Hooks
60
+ ### beforeResponse
61
+ Runs after the route handler but before response headers are merged. Useful for modifying response metadata.
325
62
 
326
63
  ```typescript
327
- app
328
- .onBeforeStart(() => {
329
- console.log('๐Ÿ”ง Preparing to start server...');
330
- })
331
- .onAfterStart(() => {
332
- console.log('โœ… Server fully started and ready!');
333
- })
334
- .onBeforeStop(() => {
335
- console.log('๐Ÿ”ง Preparing to stop server...');
336
- })
337
- .onAfterStop(() => {
338
- console.log('โœ… Server fully stopped!');
339
- })
340
- .onBeforeRestart(() => {
341
- console.log('๐Ÿ”ง Preparing to restart server...');
342
- })
343
- .onAfterRestart(() => {
344
- console.log('โœ… Server restart completed!');
345
- });
64
+ app.beforeResponse(async (res) => {
65
+ res.headers.set("X-Custom-Header", "value");
66
+ return res;
67
+ });
346
68
  ```
347
69
 
348
- ### Request Lifecycle Hooks
70
+ ### onError
71
+ Runs when an error occurs during request processing. Can return a custom error response.
349
72
 
350
73
  ```typescript
351
- app
352
- .onRequest((ctx) => {
353
- console.log(`๐Ÿ“จ ${ctx.request.method} ${ctx.request.url}`);
354
- })
355
- .onResponse((ctx, response) => {
356
- console.log(`๐Ÿ“ค Response sent`);
357
- return response; // Can modify response
358
- })
359
- .onError((ctx, error) => {
360
- console.error(`๐Ÿ’ฅ Error:`, error.message);
361
- return { error: 'Something went wrong' }; // Can provide custom error response
362
- });
74
+ app.onError(async (error, req) => {
75
+ console.error(`Error: ${error.message}`);
76
+ return new Response("Internal Server Error", { status: 500 });
77
+ });
363
78
  ```
364
79
 
365
- ## ๐Ÿ”„ Hot Reload & Server Management
80
+ ## Plugins
366
81
 
367
- BXO includes built-in hot reload and comprehensive server management capabilities:
82
+ ### CORS Plugin
368
83
 
369
- ### Hot Reload
84
+ The CORS plugin provides comprehensive Cross-Origin Resource Sharing support:
370
85
 
371
86
  ```typescript
372
- const app = new BXO();
87
+ import { cors } from "./plugins";
373
88
 
374
- // Enable hot reload - server will restart when files change
375
- app.enableHotReload(['./']); // Watch current directory
376
-
377
- // Hot reload will automatically restart the server when:
378
- // - Any .ts or .js file changes in watched directories
379
- // - Server lifecycle hooks are properly executed during restart
89
+ app.use(cors({
90
+ origin: ["http://localhost:3000", "https://myapp.com"],
91
+ methods: ["GET", "POST", "PUT", "DELETE"],
92
+ credentials: true
93
+ }));
380
94
  ```
381
95
 
382
- ### Server Management
383
-
384
- ```typescript
385
- const app = new BXO();
386
-
387
- // Start server
388
- await app.start(3000, 'localhost');
389
-
390
- // Check if server is running
391
- if (app.isServerRunning()) {
392
- console.log('Server is running!');
393
- }
394
-
395
- // Get server information
396
- const info = app.getServerInfo();
397
- console.log(info); // { running: true, hotReload: true, watchedFiles: ['./'] }
398
-
399
- // Restart server programmatically
400
- await app.restart(3000, 'localhost');
401
-
402
- // Stop server gracefully
403
- await app.stop();
404
-
405
- // Backward compatibility - listen() still works
406
- await app.listen(3000); // Same as app.start(3000)
407
- ```
96
+ ### Creating Custom Plugins
408
97
 
409
- ### Development vs Production
98
+ Plugins are just BXO instances with lifecycle hooks:
410
99
 
411
100
  ```typescript
412
- const app = new BXO();
413
-
414
- if (process.env.NODE_ENV === 'development') {
415
- // Enable hot reload in development
416
- app.enableHotReload(['./src', './routes']);
417
- }
418
-
419
- // Add server management endpoints for development
420
- if (process.env.NODE_ENV === 'development') {
421
- app.post('/dev/restart', async (ctx) => {
422
- setTimeout(() => app.restart(3000), 100);
423
- return { message: 'Server restart initiated' };
424
- });
101
+ function loggingPlugin() {
102
+ const plugin = new BXO();
425
103
 
426
- app.get('/dev/status', async (ctx) => {
427
- return {
428
- ...app.getServerInfo(),
429
- uptime: process.uptime(),
430
- memory: process.memoryUsage()
431
- };
104
+ plugin.beforeRequest(async (req) => {
105
+ console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
106
+ return req;
432
107
  });
433
- }
434
- ```
435
-
436
- ## ๐ŸŒŸ Complete Example
437
-
438
- ```typescript
439
- import BXO, { z } from './index';
440
- import { cors, logger, auth, rateLimit, createJWT } from './plugins';
441
-
442
- const app = new BXO();
443
-
444
- // Enable hot reload for development
445
- app.enableHotReload(['./']);
446
-
447
- // Add plugins
448
- app
449
- .use(logger({ format: 'simple' }))
450
- .use(cors({
451
- origin: ['http://localhost:3000'],
452
- credentials: true
453
- }))
454
- .use(rateLimit({
455
- max: 100,
456
- window: 60,
457
- exclude: ['/health']
458
- }))
459
- .use(auth({
460
- type: 'jwt',
461
- secret: 'your-secret-key',
462
- exclude: ['/', '/login', '/health']
463
- }));
464
-
465
- // Comprehensive lifecycle hooks
466
- app
467
- .onBeforeStart(() => console.log('๐Ÿ”ง Preparing server startup...'))
468
- .onAfterStart(() => console.log('โœ… Server ready!'))
469
- .onBeforeRestart(() => console.log('๐Ÿ”„ Restarting server...'))
470
- .onAfterRestart(() => console.log('โœ… Server restarted!'))
471
- .onError((ctx, error) => ({
472
- error: 'Internal server error',
473
- timestamp: new Date().toISOString()
474
- }));
475
-
476
- // Routes
477
- app
478
- .get('/health', async () => ({
479
- status: 'ok',
480
- timestamp: new Date().toISOString(),
481
- server: app.getServerInfo()
482
- }))
483
-
484
- .post('/login', async (ctx) => {
485
- const { username, password } = ctx.body;
486
-
487
- if (username === 'admin' && password === 'password') {
488
- const token = createJWT(
489
- { username, role: 'admin' },
490
- 'your-secret-key'
491
- );
492
- return { token, user: { username, role: 'admin' } };
493
- }
494
-
495
- ctx.set.status = 401;
496
- return { error: 'Invalid credentials' };
497
- }, {
498
- body: z.object({
499
- username: z.string(),
500
- password: z.string()
501
- })
502
- })
503
-
504
- .get('/users/:id', async (ctx) => {
505
- return {
506
- user: {
507
- id: ctx.params.id,
508
- include: ctx.query.include
509
- }
510
- };
511
- }, {
512
- params: z.object({ id: z.string().uuid() }),
513
- query: z.object({ include: z.string().optional() })
514
- })
515
108
 
516
- .post('/users', async (ctx) => {
517
- return { created: ctx.body };
518
- }, {
519
- body: z.object({
520
- name: z.string(),
521
- email: z.string().email()
522
- })
523
- })
524
-
525
- .get('/protected', async (ctx) => {
526
- // ctx.user available from auth plugin
527
- return {
528
- message: 'Protected resource',
529
- user: ctx.user
530
- };
531
- })
532
-
533
- // Server management endpoints
534
- .post('/restart', async (ctx) => {
535
- setTimeout(() => app.restart(3000), 100);
536
- return { message: 'Server restart initiated' };
537
- })
538
-
539
- .get('/status', async (ctx) => {
540
- return {
541
- ...app.getServerInfo(),
542
- uptime: process.uptime(),
543
- memory: process.memoryUsage()
544
- };
545
- });
109
+ return plugin;
110
+ }
546
111
 
547
- // Start server with hot reload
548
- app.start(3000);
112
+ app.use(loggingPlugin());
549
113
  ```
550
114
 
551
- ## ๐Ÿงช Testing Endpoints
552
-
553
- With the example server running, test these endpoints:
554
-
555
- ```bash
556
- # Health check
557
- curl http://localhost:3000/health
558
-
559
- # Login to get token
560
- curl -X POST http://localhost:3000/login \
561
- -H "Content-Type: application/json" \
562
- -d '{"username": "admin", "password": "password"}'
563
-
564
- # Create user
565
- curl -X POST http://localhost:3000/users \
566
- -H "Content-Type: application/json" \
567
- -d '{"name": "John Doe", "email": "john@example.com"}'
568
-
569
- # Get user with validation
570
- curl "http://localhost:3000/users/123e4567-e89b-12d3-a456-426614174000?include=profile"
571
-
572
- # Access protected route (use token from login)
573
- curl http://localhost:3000/protected \
574
- -H "Authorization: Bearer YOUR_JWT_TOKEN"
115
+ ## Route Validation
575
116
 
576
- # Check server status
577
- curl http://localhost:3000/status
578
-
579
- # Restart server programmatically
580
- curl -X POST http://localhost:3000/restart
581
- ```
582
-
583
- ## ๐Ÿ“– API Reference
584
-
585
- ### BXO Class Methods
586
-
587
- #### HTTP Methods
588
- - `get(path, handler, config?)` - Handle GET requests
589
- - `post(path, handler, config?)` - Handle POST requests
590
- - `put(path, handler, config?)` - Handle PUT requests
591
- - `delete(path, handler, config?)` - Handle DELETE requests
592
- - `patch(path, handler, config?)` - Handle PATCH requests
593
-
594
- #### Plugins & Hooks
595
- - `use(plugin)` - Add a plugin
596
- - `onBeforeStart(handler)` - Before server start hook
597
- - `onAfterStart(handler)` - After server start hook
598
- - `onBeforeStop(handler)` - Before server stop hook
599
- - `onAfterStop(handler)` - After server stop hook
600
- - `onBeforeRestart(handler)` - Before server restart hook
601
- - `onAfterRestart(handler)` - After server restart hook
602
- - `onRequest(handler)` - Global request hook
603
- - `onResponse(handler)` - Global response hook
604
- - `onError(handler)` - Global error hook
605
-
606
- #### Server Management
607
- - `start(port?, hostname?)` - Start the server
608
- - `stop()` - Stop the server gracefully
609
- - `restart(port?, hostname?)` - Restart the server
610
- - `listen(port?, hostname?)` - Start the server (backward compatibility)
611
- - `isServerRunning()` - Check if server is running
612
- - `getServerInfo()` - Get server status information
613
-
614
- #### Hot Reload
615
- - `enableHotReload(watchPaths?)` - Enable hot reload with file watching
616
-
617
- ### Route Configuration
117
+ Define Zod schemas for request validation:
618
118
 
619
119
  ```typescript
620
- interface RouteConfig {
621
- params?: z.ZodSchema<any>; // Path parameter validation
622
- query?: z.ZodSchema<any>; // Query string validation
623
- body?: z.ZodSchema<any>; // Request body validation
624
- headers?: z.ZodSchema<any>; // Header validation
625
- }
626
- ```
120
+ import { z } from "bxo";
627
121
 
628
- ### Plugin Interface
122
+ const UserSchema = z.object({
123
+ name: z.string().min(1),
124
+ email: z.string().email()
125
+ });
629
126
 
630
- ```typescript
631
- interface Plugin {
632
- name?: string;
633
- onRequest?: (ctx: Context) => Promise<void> | void;
634
- onResponse?: (ctx: Context, response: any) => Promise<any> | any;
635
- onError?: (ctx: Context, error: Error) => Promise<any> | any;
636
- }
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
+ });
637
133
  ```
638
134
 
639
- ## ๐Ÿ› ๏ธ Development
640
-
641
- ### Running the Example
135
+ ## Running
642
136
 
643
137
  ```bash
644
- # Run with hot reload enabled
645
- bun run example.ts
646
-
647
- # The server will automatically restart when you edit any .ts/.js files!
138
+ bun run ./src/index.ts
648
139
  ```
649
140
 
650
- ### Project Structure
141
+ Or run the CORS example:
651
142
 
143
+ ```bash
144
+ bun run ./example/cors-example.ts
652
145
  ```
653
- bxo/
654
- โ”œโ”€โ”€ index.ts # Main BXO framework
655
- โ”œโ”€โ”€ plugins/
656
- โ”‚ โ”œโ”€โ”€ index.ts # Plugin exports
657
- โ”‚ โ”œโ”€โ”€ cors.ts # CORS plugin
658
- โ”‚ โ”œโ”€โ”€ logger.ts # Logger plugin
659
- โ”‚ โ”œโ”€โ”€ auth.ts # Authentication plugin
660
- โ”‚ โ””โ”€โ”€ ratelimit.ts # Rate limiting plugin
661
- โ”œโ”€โ”€ example.ts # Usage example
662
- โ”œโ”€โ”€ package.json
663
- โ””โ”€โ”€ README.md
664
- ```
665
-
666
- ## ๐Ÿค Contributing
667
-
668
- BXO is designed to be simple and extensible. Contributions are welcome!
669
146
 
670
- ## ๐Ÿ“„ License
147
+ ## Examples
671
148
 
672
- MIT License - feel free to use BXO in your projects!
149
+ Check out the `example/` directory for more usage examples:
673
150
 
674
- ---
151
+ - `cors-example.ts` - Demonstrates CORS plugin and lifecycle hooks
152
+ - `index.ts` - Basic routing example
675
153
 
676
- Built with โค๏ธ for the Bun ecosystem
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.