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.
- package/index.ts +66 -10
- 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 };
|