bxo 0.0.5-dev.4 → 0.0.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.
Files changed (2) hide show
  1. package/index.ts +11 -133
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -3,26 +3,12 @@ import { z } from 'zod';
3
3
  // Type utilities for extracting types from Zod schemas
4
4
  type InferZodType<T> = T extends z.ZodType<infer U> ? U : never;
5
5
 
6
- // OpenAPI detail information
7
- interface RouteDetail {
8
- summary?: string;
9
- description?: string;
10
- tags?: string[];
11
- operationId?: string;
12
- deprecated?: boolean;
13
- produces?: string[];
14
- consumes?: string[];
15
- [key: string]: any; // Allow additional OpenAPI properties
16
- }
17
-
18
6
  // Configuration interface for route handlers
19
7
  interface RouteConfig {
20
8
  params?: z.ZodSchema<any>;
21
9
  query?: z.ZodSchema<any>;
22
10
  body?: z.ZodSchema<any>;
23
11
  headers?: z.ZodSchema<any>;
24
- response?: z.ZodSchema<any>;
25
- detail?: RouteDetail;
26
12
  }
27
13
 
28
14
  // Context type that's fully typed based on the route configuration
@@ -66,16 +52,13 @@ interface LifecycleHooks {
66
52
  }
67
53
 
68
54
  export default class BXO {
69
- private _routes: Route[] = [];
55
+ private routes: Route[] = [];
70
56
  private plugins: BXO[] = [];
71
57
  private hooks: LifecycleHooks = {};
72
58
  private server?: any;
73
59
  private isRunning: boolean = false;
74
60
  private hotReloadEnabled: boolean = false;
75
61
  private watchedFiles: Set<string> = new Set();
76
- private watchedExclude: Set<string> = new Set();
77
- private serverPort?: number;
78
- private serverHostname?: string;
79
62
 
80
63
  constructor() { }
81
64
 
@@ -146,7 +129,7 @@ export default class BXO {
146
129
  handler: Handler<TConfig>,
147
130
  config?: TConfig
148
131
  ): this {
149
- this._routes.push({ method: 'GET', path, handler, config });
132
+ this.routes.push({ method: 'GET', path, handler, config });
150
133
  return this;
151
134
  }
152
135
 
@@ -164,7 +147,7 @@ export default class BXO {
164
147
  handler: Handler<TConfig>,
165
148
  config?: TConfig
166
149
  ): this {
167
- this._routes.push({ method: 'POST', path, handler, config });
150
+ this.routes.push({ method: 'POST', path, handler, config });
168
151
  return this;
169
152
  }
170
153
 
@@ -182,7 +165,7 @@ export default class BXO {
182
165
  handler: Handler<TConfig>,
183
166
  config?: TConfig
184
167
  ): this {
185
- this._routes.push({ method: 'PUT', path, handler, config });
168
+ this.routes.push({ method: 'PUT', path, handler, config });
186
169
  return this;
187
170
  }
188
171
 
@@ -200,7 +183,7 @@ export default class BXO {
200
183
  handler: Handler<TConfig>,
201
184
  config?: TConfig
202
185
  ): this {
203
- this._routes.push({ method: 'DELETE', path, handler, config });
186
+ this.routes.push({ method: 'DELETE', path, handler, config });
204
187
  return this;
205
188
  }
206
189
 
@@ -218,13 +201,13 @@ export default class BXO {
218
201
  handler: Handler<TConfig>,
219
202
  config?: TConfig
220
203
  ): this {
221
- this._routes.push({ method: 'PATCH', path, handler, config });
204
+ this.routes.push({ method: 'PATCH', path, handler, config });
222
205
  return this;
223
206
  }
224
207
 
225
208
  // Route matching utility
226
209
  private matchRoute(method: string, pathname: string): { route: Route; params: Record<string, string> } | null {
227
- for (const route of this._routes) {
210
+ for (const route of this.routes) {
228
211
  if (route.method !== method) continue;
229
212
 
230
213
  const routeSegments = route.path.split('/').filter(Boolean);
@@ -355,20 +338,6 @@ export default class BXO {
355
338
  }
356
339
  }
357
340
 
358
- // Validate response against schema if provided
359
- if (route.config?.response && !(response instanceof Response)) {
360
- try {
361
- response = this.validateData(route.config.response, response);
362
- } catch (validationError) {
363
- // Response validation failed
364
- const errorMessage = validationError instanceof Error ? validationError.message : 'Response validation failed';
365
- return new Response(JSON.stringify({ error: `Response validation error: ${errorMessage}` }), {
366
- status: 500,
367
- headers: { 'Content-Type': 'application/json' }
368
- });
369
- }
370
- }
371
-
372
341
  // Convert response to Response object
373
342
  if (response instanceof Response) {
374
343
  return response;
@@ -425,49 +394,12 @@ export default class BXO {
425
394
  }
426
395
 
427
396
  // Hot reload functionality
428
- enableHotReload(watchPaths: string[] = ['./'], excludePatterns: string[] = []): this {
397
+ enableHotReload(watchPaths: string[] = ['./']): this {
429
398
  this.hotReloadEnabled = true;
430
399
  watchPaths.forEach(path => this.watchedFiles.add(path));
431
- excludePatterns.forEach(pattern => this.watchedExclude.add(pattern));
432
400
  return this;
433
401
  }
434
402
 
435
- private shouldExcludeFile(filename: string): boolean {
436
- for (const pattern of this.watchedExclude) {
437
- // Handle exact match
438
- if (pattern === filename) {
439
- return true;
440
- }
441
-
442
- // Handle directory patterns (e.g., "node_modules/", "dist/")
443
- if (pattern.endsWith('/')) {
444
- if (filename.startsWith(pattern) || filename.includes(`/${pattern}`)) {
445
- return true;
446
- }
447
- }
448
-
449
- // Handle wildcard patterns (e.g., "*.log", "temp*")
450
- if (pattern.includes('*')) {
451
- const regex = new RegExp(pattern.replace(/\*/g, '.*'));
452
- if (regex.test(filename)) {
453
- return true;
454
- }
455
- }
456
-
457
- // Handle file extension patterns (e.g., ".log", ".tmp")
458
- if (pattern.startsWith('.') && filename.endsWith(pattern)) {
459
- return true;
460
- }
461
-
462
- // Handle substring matches for directories
463
- if (filename.includes(pattern)) {
464
- return true;
465
- }
466
- }
467
-
468
- return false;
469
- }
470
-
471
403
  private async setupFileWatcher(port: number, hostname: string): Promise<void> {
472
404
  if (!this.hotReloadEnabled) return;
473
405
 
@@ -477,19 +409,11 @@ export default class BXO {
477
409
  try {
478
410
  fs.watch(watchPath, { recursive: true }, async (eventType: string, filename: string) => {
479
411
  if (filename && (filename.endsWith('.ts') || filename.endsWith('.js'))) {
480
- // Check if file should be excluded
481
- if (this.shouldExcludeFile(filename)) {
482
- return;
483
- }
484
-
485
412
  console.log(`🔄 File changed: ${filename}, restarting server...`);
486
413
  await this.restart(port, hostname);
487
414
  }
488
415
  });
489
416
  console.log(`👀 Watching ${watchPath} for changes...`);
490
- if (this.watchedExclude.size > 0) {
491
- console.log(`🚫 Excluding patterns: ${Array.from(this.watchedExclude).join(', ')}`);
492
- }
493
417
  } catch (error) {
494
418
  console.warn(`⚠️ Could not watch ${watchPath}:`, error);
495
419
  }
@@ -516,8 +440,6 @@ export default class BXO {
516
440
  });
517
441
 
518
442
  this.isRunning = true;
519
- this.serverPort = port;
520
- this.serverHostname = hostname;
521
443
 
522
444
  console.log(`🦊 BXO server running at http://${hostname}:${port}`);
523
445
 
@@ -562,8 +484,6 @@ export default class BXO {
562
484
  }
563
485
 
564
486
  this.isRunning = false;
565
- this.serverPort = undefined;
566
- this.serverHostname = undefined;
567
487
 
568
488
  console.log('🛑 BXO server stopped');
569
489
 
@@ -615,55 +535,13 @@ export default class BXO {
615
535
  return this.isRunning;
616
536
  }
617
537
 
618
- getServerInfo(): { running: boolean; hotReload: boolean; watchedFiles: string[]; excludePatterns: string[] } {
619
- return {
620
- running: this.isRunning,
621
- hotReload: this.hotReloadEnabled,
622
- watchedFiles: Array.from(this.watchedFiles),
623
- excludePatterns: Array.from(this.watchedExclude)
624
- };
625
- }
626
-
627
- // Get server information (alias for getServerInfo)
628
- get info() {
538
+ getServerInfo(): { running: boolean; hotReload: boolean; watchedFiles: string[] } {
629
539
  return {
630
- // Server status
631
540
  running: this.isRunning,
632
- server: this.server ? 'Bun' : null,
633
-
634
- // Connection details
635
- hostname: this.serverHostname,
636
- port: this.serverPort,
637
- url: this.isRunning && this.serverHostname && this.serverPort
638
- ? `http://${this.serverHostname}:${this.serverPort}`
639
- : null,
640
-
641
- // Application statistics
642
- totalRoutes: this._routes.length,
643
- totalPlugins: this.plugins.length,
644
-
645
- // Hot reload configuration
646
541
  hotReload: this.hotReloadEnabled,
647
- watchedFiles: Array.from(this.watchedFiles),
648
- excludePatterns: Array.from(this.watchedExclude),
649
-
650
- // System information
651
- runtime: 'Bun',
652
- version: typeof Bun !== 'undefined' ? Bun.version : 'unknown',
653
- pid: process.pid,
654
- uptime: this.isRunning ? process.uptime() : 0
542
+ watchedFiles: Array.from(this.watchedFiles)
655
543
  };
656
544
  }
657
-
658
- // Get all routes information
659
- get routes() {
660
- return this._routes.map((route: Route) => ({
661
- method: route.method,
662
- path: route.path,
663
- hasConfig: !!route.config,
664
- config: route.config || null
665
- }));
666
- }
667
545
  }
668
546
 
669
547
  const error = (error: Error, status: number = 500) => {
@@ -674,4 +552,4 @@ const error = (error: Error, status: number = 500) => {
674
552
  export { z, error };
675
553
 
676
554
  // Export types for external use
677
- export type { RouteConfig, RouteDetail, Handler };
555
+ export type { RouteConfig, Handler };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bxo",
3
3
  "module": "index.ts",
4
- "version": "0.0.5-dev.4",
4
+ "version": "0.0.5",
5
5
  "description": "A simple and lightweight web framework for Bun",
6
6
  "type": "module",
7
7
  "devDependencies": {