bxo 0.0.3 → 0.0.5-dev.1

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 +66 -10
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -9,6 +9,7 @@ interface RouteConfig {
9
9
  query?: z.ZodSchema<any>;
10
10
  body?: z.ZodSchema<any>;
11
11
  headers?: z.ZodSchema<any>;
12
+ response?: z.ZodSchema<any>;
12
13
  }
13
14
 
14
15
  // Context type that's fully typed based on the route configuration
@@ -30,10 +31,6 @@ export type Context<TConfig extends RouteConfig = {}> = {
30
31
  // Handler function type
31
32
  type Handler<TConfig extends RouteConfig = {}> = (ctx: Context<TConfig>) => Promise<any> | any;
32
33
 
33
- // Note: Plugin interface moved to plugins/index.ts as PluginFactory type
34
-
35
-
36
-
37
34
  // Route definition
38
35
  interface Route {
39
36
  method: string;
@@ -63,6 +60,7 @@ export default class BXO {
63
60
  private isRunning: boolean = false;
64
61
  private hotReloadEnabled: boolean = false;
65
62
  private watchedFiles: Set<string> = new Set();
63
+ private watchedExclude: Set<string> = new Set();
66
64
 
67
65
  constructor() { }
68
66
 
@@ -342,6 +340,20 @@ export default class BXO {
342
340
  }
343
341
  }
344
342
 
343
+ // Validate response against schema if provided
344
+ if (route.config?.response && !(response instanceof Response)) {
345
+ try {
346
+ response = this.validateData(route.config.response, response);
347
+ } catch (validationError) {
348
+ // Response validation failed
349
+ const errorMessage = validationError instanceof Error ? validationError.message : 'Response validation failed';
350
+ return new Response(JSON.stringify({ error: `Response validation error: ${errorMessage}` }), {
351
+ status: 500,
352
+ headers: { 'Content-Type': 'application/json' }
353
+ });
354
+ }
355
+ }
356
+
345
357
  // Convert response to Response object
346
358
  if (response instanceof Response) {
347
359
  return response;
@@ -398,12 +410,49 @@ export default class BXO {
398
410
  }
399
411
 
400
412
  // Hot reload functionality
401
- enableHotReload(watchPaths: string[] = ['./']): this {
413
+ enableHotReload(watchPaths: string[] = ['./'], excludePatterns: string[] = []): this {
402
414
  this.hotReloadEnabled = true;
403
415
  watchPaths.forEach(path => this.watchedFiles.add(path));
416
+ excludePatterns.forEach(pattern => this.watchedExclude.add(pattern));
404
417
  return this;
405
418
  }
406
419
 
420
+ private shouldExcludeFile(filename: string): boolean {
421
+ for (const pattern of this.watchedExclude) {
422
+ // Handle exact match
423
+ if (pattern === filename) {
424
+ return true;
425
+ }
426
+
427
+ // Handle directory patterns (e.g., "node_modules/", "dist/")
428
+ if (pattern.endsWith('/')) {
429
+ if (filename.startsWith(pattern) || filename.includes(`/${pattern}`)) {
430
+ return true;
431
+ }
432
+ }
433
+
434
+ // Handle wildcard patterns (e.g., "*.log", "temp*")
435
+ if (pattern.includes('*')) {
436
+ const regex = new RegExp(pattern.replace(/\*/g, '.*'));
437
+ if (regex.test(filename)) {
438
+ return true;
439
+ }
440
+ }
441
+
442
+ // Handle file extension patterns (e.g., ".log", ".tmp")
443
+ if (pattern.startsWith('.') && filename.endsWith(pattern)) {
444
+ return true;
445
+ }
446
+
447
+ // Handle substring matches for directories
448
+ if (filename.includes(pattern)) {
449
+ return true;
450
+ }
451
+ }
452
+
453
+ return false;
454
+ }
455
+
407
456
  private async setupFileWatcher(port: number, hostname: string): Promise<void> {
408
457
  if (!this.hotReloadEnabled) return;
409
458
 
@@ -413,11 +462,19 @@ export default class BXO {
413
462
  try {
414
463
  fs.watch(watchPath, { recursive: true }, async (eventType: string, filename: string) => {
415
464
  if (filename && (filename.endsWith('.ts') || filename.endsWith('.js'))) {
465
+ // Check if file should be excluded
466
+ if (this.shouldExcludeFile(filename)) {
467
+ return;
468
+ }
469
+
416
470
  console.log(`🔄 File changed: ${filename}, restarting server...`);
417
471
  await this.restart(port, hostname);
418
472
  }
419
473
  });
420
474
  console.log(`👀 Watching ${watchPath} for changes...`);
475
+ if (this.watchedExclude.size > 0) {
476
+ console.log(`🚫 Excluding patterns: ${Array.from(this.watchedExclude).join(', ')}`);
477
+ }
421
478
  } catch (error) {
422
479
  console.warn(`⚠️ Could not watch ${watchPath}:`, error);
423
480
  }
@@ -539,11 +596,12 @@ export default class BXO {
539
596
  return this.isRunning;
540
597
  }
541
598
 
542
- getServerInfo(): { running: boolean; hotReload: boolean; watchedFiles: string[] } {
599
+ getServerInfo(): { running: boolean; hotReload: boolean; watchedFiles: string[]; excludePatterns: string[] } {
543
600
  return {
544
601
  running: this.isRunning,
545
602
  hotReload: this.hotReloadEnabled,
546
- watchedFiles: Array.from(this.watchedFiles)
603
+ watchedFiles: Array.from(this.watchedFiles),
604
+ excludePatterns: Array.from(this.watchedExclude)
547
605
  };
548
606
  }
549
607
  }
@@ -555,7 +613,5 @@ const error = (error: Error, status: number = 500) => {
555
613
  // Export Zod for convenience
556
614
  export { z, error };
557
615
 
558
- export type { PluginFactory } from './plugins';
559
-
560
616
  // Export types for external use
561
- export type { RouteConfig };
617
+ 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.3",
4
+ "version": "0.0.5-dev.1",
5
5
  "description": "A simple and lightweight web framework for Bun",
6
6
  "type": "module",
7
7
  "devDependencies": {