@onebun/core 0.2.0 → 0.2.2

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/src/types.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { BaseMiddleware } from './module/middleware';
1
2
  import type { Type } from 'arktype';
2
3
  import type { Effect, Layer } from 'effect';
3
4
 
@@ -12,6 +13,31 @@ import type { Logger, LoggerOptions } from '@onebun/logger';
12
13
  */
13
14
  export type OneBunRequest = import('bun').BunRequest;
14
15
 
16
+ /**
17
+ * A middleware class constructor.
18
+ *
19
+ * Pass class references (not instances) to `@UseMiddleware()`,
20
+ * `ApplicationOptions.middleware`, and `OnModuleConfigure.configureMiddleware()`.
21
+ * The framework will instantiate them once at startup with DI support.
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * @UseMiddleware(AuthMiddleware)
26
+ * ```
27
+ */
28
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
+ export type MiddlewareClass = new (...args: any[]) => BaseMiddleware;
30
+
31
+ /**
32
+ * Resolved middleware function — a bound `use()` method of an instantiated
33
+ * `BaseMiddleware`. Used internally by the execution pipeline.
34
+ * @internal
35
+ */
36
+ export type ResolvedMiddleware = (
37
+ req: OneBunRequest,
38
+ next: () => Promise<OneBunResponse>,
39
+ ) => Promise<OneBunResponse> | OneBunResponse;
40
+
15
41
  /**
16
42
  * HTTP Response type used in OneBun controllers.
17
43
  * Standard Web API Response.
@@ -50,6 +76,37 @@ export interface ModuleProviders {
50
76
  exports?: Function[];
51
77
  }
52
78
 
79
+ /**
80
+ * Interface for modules that configure middleware.
81
+ * Implement this interface on your `@Module()` class to apply middleware
82
+ * to all controllers within the module (including imported child modules).
83
+ *
84
+ * Module-level middleware runs after global middleware but before
85
+ * controller-level and route-level middleware.
86
+ *
87
+ * Execution order: global → module → controller → route → handler
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * @Module({
92
+ * controllers: [UserController],
93
+ * imports: [AuthModule],
94
+ * })
95
+ * export class UserModule implements OnModuleConfigure {
96
+ * configureMiddleware(): MiddlewareClass[] {
97
+ * return [TenantMiddleware, AuditMiddleware];
98
+ * }
99
+ * }
100
+ * ```
101
+ */
102
+ export interface OnModuleConfigure {
103
+ /**
104
+ * Return an array of middleware class constructors to apply to all controllers
105
+ * in this module and its imported child modules.
106
+ */
107
+ configureMiddleware(): MiddlewareClass[];
108
+ }
109
+
53
110
  /**
54
111
  * Module instance interface
55
112
  */
@@ -98,6 +155,19 @@ export interface ModuleInstance {
98
155
  * Get service instance by class
99
156
  */
100
157
  getServiceByClass?<T>(serviceClass: new (...args: unknown[]) => T): T | undefined;
158
+
159
+ /**
160
+ * Get accumulated module-level middleware (resolved bound functions)
161
+ * for a given controller class.
162
+ * Includes middleware from ancestor modules (root → child → … → owner module).
163
+ */
164
+ getModuleMiddleware?(controllerClass: Function): Function[];
165
+
166
+ /**
167
+ * Resolve middleware class constructors into bound `use()` functions
168
+ * using this module's DI scope (services + logger + config).
169
+ */
170
+ resolveMiddleware?(classes: Function[]): Function[];
101
171
  }
102
172
 
103
173
  /**
@@ -128,6 +198,14 @@ export interface ApplicationOptions {
128
198
  */
129
199
  host?: string;
130
200
 
201
+ /**
202
+ * Maximum idle time (in seconds) before the server closes a connection.
203
+ * A connection is idle when no data is sent or received.
204
+ * Set to 0 to disable the timeout entirely.
205
+ * @defaultValue 120
206
+ */
207
+ idleTimeout?: number;
208
+
131
209
  /**
132
210
  * Base path prefix for all routes
133
211
  * @example '/api/v1'
@@ -342,6 +420,25 @@ export interface ApplicationOptions {
342
420
  */
343
421
  docs?: DocsApplicationOptions;
344
422
 
423
+ /**
424
+ * Application-wide middleware applied to every route before module-level,
425
+ * controller-level and route-level middleware. Useful for cross-cutting
426
+ * concerns like request logging, authentication, CORS, or request validation.
427
+ *
428
+ * Pass class constructors (not instances). The framework will instantiate
429
+ * them once at startup with full DI support from the root module.
430
+ *
431
+ * Execution order: global → module → controller → route → handler
432
+ *
433
+ * @example
434
+ * ```typescript
435
+ * const app = new OneBunApplication(AppModule, {
436
+ * middleware: [CorsMiddleware, RequestIdMiddleware],
437
+ * });
438
+ * ```
439
+ */
440
+ middleware?: MiddlewareClass[];
441
+
345
442
  /**
346
443
  * Enable graceful shutdown on SIGTERM/SIGINT
347
444
  * When enabled, the application will cleanly shutdown on process signals,
@@ -523,6 +620,9 @@ export enum ParamType {
523
620
  COOKIE = 'cookie',
524
621
  REQUEST = 'request',
525
622
  RESPONSE = 'response',
623
+ FILE = 'file',
624
+ FILES = 'files',
625
+ FORM_FIELD = 'formField',
526
626
  }
527
627
 
528
628
  /**
@@ -538,6 +638,26 @@ export interface ParamDecoratorOptions {
538
638
  required?: boolean;
539
639
  }
540
640
 
641
+ /**
642
+ * Options for file upload decorators (@UploadedFile, @UploadedFiles)
643
+ */
644
+ export interface FileUploadOptions {
645
+ /** Maximum file size in bytes */
646
+ maxSize?: number;
647
+ /** Allowed MIME types, supports wildcards like 'image/*'. Use MimeType enum for convenience. */
648
+ mimeTypes?: string[];
649
+ /** Whether the file is required (default: true for @UploadedFile/@UploadedFiles) */
650
+ required?: boolean;
651
+ }
652
+
653
+ /**
654
+ * Options for multiple file upload decorator (@UploadedFiles)
655
+ */
656
+ export interface FilesUploadOptions extends FileUploadOptions {
657
+ /** Maximum number of files allowed */
658
+ maxCount?: number;
659
+ }
660
+
541
661
  /**
542
662
  * Parameter metadata
543
663
  */
@@ -550,6 +670,10 @@ export interface ParamMetadata {
550
670
  * ArkType schema for validation
551
671
  */
552
672
  schema?: Type<unknown>;
673
+ /**
674
+ * File upload options (only for FILE/FILES param types)
675
+ */
676
+ fileOptions?: FileUploadOptions & { maxCount?: number };
553
677
  }
554
678
 
555
679
  /**
@@ -561,6 +685,26 @@ export interface ResponseSchemaMetadata {
561
685
  description?: string;
562
686
  }
563
687
 
688
+ /**
689
+ * Options for HTTP method decorators (@Get, @Post, @Put, @Delete, @Patch, etc.)
690
+ */
691
+ export interface RouteOptions {
692
+ /**
693
+ * Per-request idle timeout in seconds.
694
+ * Overrides the global `idleTimeout` from `ApplicationOptions` for this route.
695
+ * Set to 0 to disable the timeout entirely (useful for long-running requests).
696
+ * @example
697
+ * ```typescript
698
+ * @Get('/long-task', { timeout: 300 }) // 5 minutes
699
+ * async longTask() { ... }
700
+ *
701
+ * @Get('/stream', { timeout: 0 }) // no timeout
702
+ * async stream() { ... }
703
+ * ```
704
+ */
705
+ timeout?: number;
706
+ }
707
+
564
708
  /**
565
709
  * Route metadata
566
710
  */
@@ -575,6 +719,11 @@ export interface RouteMetadata {
575
719
  * Key is HTTP status code (e.g., 200, 201, 404)
576
720
  */
577
721
  responseSchemas?: ResponseSchemaMetadata[];
722
+ /**
723
+ * Per-request idle timeout in seconds.
724
+ * When set, calls `server.timeout(req, seconds)` for this route.
725
+ */
726
+ timeout?: number;
578
727
  }
579
728
 
580
729
  /**
@@ -583,6 +732,11 @@ export interface RouteMetadata {
583
732
  export interface ControllerMetadata {
584
733
  path: string;
585
734
  routes: RouteMetadata[];
735
+ /**
736
+ * Controller-level middleware class constructors applied to all routes.
737
+ * Set by applying @UseMiddleware() as a class decorator.
738
+ */
739
+ middleware?: MiddlewareClass[];
586
740
  }
587
741
 
588
742
  // ============================================================================
@@ -635,6 +789,21 @@ export interface SseOptions {
635
789
  * at this interval to keep the connection alive.
636
790
  */
637
791
  heartbeat?: number;
792
+
793
+ /**
794
+ * Callback invoked when the client disconnects or aborts the SSE connection.
795
+ * Useful for cleanup logic when using `controller.sse()` programmatically.
796
+ *
797
+ * For `@Sse()` decorator usage, prefer `try/finally` in the generator instead.
798
+ *
799
+ * @example
800
+ * ```typescript
801
+ * return this.sse(this.generateEvents(), {
802
+ * onAbort: () => this.eventService.unsubscribe(),
803
+ * });
804
+ * ```
805
+ */
806
+ onAbort?: () => void;
638
807
  }
639
808
 
640
809
  /**