@dangao/bun-server 1.1.2 → 1.1.3

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/docs/api.md ADDED
@@ -0,0 +1,602 @@
1
+ # API Overview
2
+
3
+ This document provides an overview of the main APIs provided by Bun Server
4
+ Framework for quick reference.
5
+
6
+ ## Core
7
+
8
+ | API | Description |
9
+ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
10
+ | `Application(options?)` | Main application class, supports `use` for global middleware, `registerController`/`registerWebSocketGateway` for components, and `listen/stop` for lifecycle management |
11
+ | `Context` | Unified request context, wraps `Request` and provides methods like `getQuery/getParam/getBody/setHeader/setStatus/createResponse` |
12
+ | `ResponseBuilder` | Provides convenient response builders: `json/text/html/empty/redirect/error/file` |
13
+ | `RouteRegistry` / `Router` | Can directly register functional routes or get the underlying `Router` for manual control |
14
+
15
+ ## Controllers and Route Decorators
16
+
17
+ - `@Controller(path)`: Declare controller prefix.
18
+ - `@GET/@POST/@PUT/@PATCH/@DELETE(path)`: Declare HTTP methods.
19
+ - Parameter decorators:
20
+ `@Body() / @Query(key) / @Param(key) / @Header(key) / @Session()`.
21
+ - `ControllerRegistry` automatically parses decorators and registers routes.
22
+
23
+ **Example**:
24
+
25
+ ```typescript
26
+ @Controller("/api/users")
27
+ class UserController {
28
+ @GET("/:id")
29
+ public async getUser(@Param("id") id: string) {
30
+ return { id, name: "User" };
31
+ }
32
+
33
+ @POST("/")
34
+ public async createUser(@Body() user: CreateUserDto) {
35
+ return await this.userService.create(user);
36
+ }
37
+
38
+ @GET("/")
39
+ public async listUsers(@Query("page") page: number = 1) {
40
+ return await this.userService.findAll(page);
41
+ }
42
+ }
43
+ ```
44
+
45
+ ## Dependency Injection
46
+
47
+ - `Container`: `register`, `registerInstance`, `resolve`, `clear`,
48
+ `isRegistered`.
49
+ - Decorators: `@Injectable(config?)` sets lifecycle, `@Inject(token?)` specifies
50
+ dependencies.
51
+ - `Lifecycle` enum: `Singleton`, `Transient`, `Scoped` (reserved).
52
+
53
+ **Example**:
54
+
55
+ ```typescript
56
+ @Injectable()
57
+ class UserService {
58
+ public async find(id: string) {
59
+ return { id, name: "User" };
60
+ }
61
+ }
62
+
63
+ @Controller("/api/users")
64
+ class UserController {
65
+ public constructor(
66
+ @Inject(UserService) private readonly userService: UserService,
67
+ @Inject(CACHE_SERVICE_TOKEN) private readonly cache: CacheService,
68
+ ) {}
69
+
70
+ @GET("/:id")
71
+ public async getUser(@Param("id") id: string) {
72
+ return await this.userService.find(id);
73
+ }
74
+ }
75
+ ```
76
+
77
+ ## Extension System
78
+
79
+ ### Middleware
80
+
81
+ - `Middleware` type:
82
+ `(context: Context, next: NextFunction) => Response | Promise<Response>`
83
+ - `app.use(middleware)`: Register global middleware
84
+ - `@UseMiddleware(...middlewares)`: Controller or method-level middleware
85
+ - Built-in middleware factories: `createLoggerMiddleware`,
86
+ `createCorsMiddleware`, `createErrorHandlingMiddleware`,
87
+ `createFileUploadMiddleware`, `createStaticFileMiddleware`
88
+
89
+ ### Application Extensions
90
+
91
+ - `ApplicationExtension` interface: `register(container: Container): void`
92
+ - `app.registerExtension(extension)`: Register application extension
93
+ - Official extensions: `LoggerExtension`, `SwaggerExtension`
94
+
95
+ ### Module System
96
+
97
+ - `@Module(metadata)`: Module decorator
98
+ - `ModuleMetadata`: Supports `imports`, `controllers`, `providers`, `exports`,
99
+ `extensions`, `middlewares`
100
+ - `app.registerModule(moduleClass)`: Register module
101
+
102
+ ### Interceptor System
103
+
104
+ - `Interceptor` interface: Core interface for interceptors
105
+ - `InterceptorRegistry`: Central registry for managing interceptors
106
+ - `InterceptorChain`: Executes multiple interceptors in priority order
107
+ - `BaseInterceptor`: Base class for creating custom interceptors
108
+ - `scanInterceptorMetadata`: Scans method metadata for interceptors
109
+
110
+ **Built-in Interceptors**:
111
+ - `@Cache(options)`: Cache method results
112
+ - `@Permission(options)`: Check permissions before method execution
113
+ - `@Log(options)`: Log method execution with timing
114
+
115
+ **Example**:
116
+
117
+ ```typescript
118
+ import { BaseInterceptor, INTERCEPTOR_REGISTRY_TOKEN } from '@dangao/bun-server';
119
+ import type { InterceptorRegistry } from '@dangao/bun-server';
120
+
121
+ // Create custom decorator
122
+ const MY_METADATA_KEY = Symbol('@my-app:my-decorator');
123
+
124
+ function MyDecorator(): MethodDecorator {
125
+ return (target, propertyKey) => {
126
+ Reflect.defineMetadata(MY_METADATA_KEY, true, target, propertyKey);
127
+ };
128
+ }
129
+
130
+ // Create interceptor
131
+ class MyInterceptor extends BaseInterceptor {
132
+ public async execute<T>(...): Promise<T> {
133
+ // Pre-processing
134
+ await this.before(...);
135
+
136
+ // Execute original method
137
+ const result = await Promise.resolve(originalMethod.apply(target, args));
138
+
139
+ // Post-processing
140
+ return await this.after(...) as T;
141
+ }
142
+ }
143
+
144
+ // Register interceptor
145
+ const registry = app.getContainer().resolve<InterceptorRegistry>(INTERCEPTOR_REGISTRY_TOKEN);
146
+ registry.register(MY_METADATA_KEY, new MyInterceptor(), 100);
147
+
148
+ // Use decorator
149
+ @Controller('/api/users')
150
+ class UserController {
151
+ @GET('/:id')
152
+ @MyDecorator()
153
+ public getUser(@Param('id') id: string) {
154
+ return { id, name: 'User' };
155
+ }
156
+ }
157
+ ```
158
+
159
+ See [Custom Decorators Guide](./custom-decorators.md) for detailed documentation.
160
+ - Official modules: `ConfigModule.forRoot(options)`,
161
+ `CacheModule.forRoot(options)`, `QueueModule.forRoot(options)`,
162
+ `SessionModule.forRoot(options)`, `HealthModule.forRoot(options)`,
163
+ `LoggerModule.forRoot(options)`, `SwaggerModule.forRoot(options)`,
164
+ `DatabaseModule.forRoot(options)`, `MetricsModule.forRoot(options)`,
165
+ `SecurityModule.forRoot(options)`
166
+
167
+ **Example**:
168
+
169
+ ```typescript
170
+ // Configure modules
171
+ ConfigModule.forRoot({
172
+ defaultConfig: { app: { name: "MyApp", port: 3000 } },
173
+ });
174
+
175
+ CacheModule.forRoot({
176
+ defaultTtl: 3600000,
177
+ });
178
+
179
+ // Register modules
180
+ const app = new Application({ port: 3000 });
181
+ app.registerModule(ConfigModule);
182
+ app.registerModule(CacheModule);
183
+ app.registerModule(AppModule);
184
+ ```
185
+
186
+ For detailed information, please refer to
187
+ [Extension System Documentation](./extensions.md).
188
+
189
+ ## Middleware System
190
+
191
+ - `Middleware` type: `(context, next) => Response`.
192
+ - `MiddlewarePipeline`: `use`, `run`, `hasMiddlewares`, `clear`.
193
+ - `@UseMiddleware(...middlewares)`: Applied to controller classes or methods.
194
+ - Built-in middleware:
195
+ - `createLoggerMiddleware`
196
+ - `createRequestLoggingMiddleware`
197
+ - `createCorsMiddleware`
198
+ - `createErrorHandlingMiddleware`
199
+ - `createFileUploadMiddleware`
200
+ - `createStaticFileMiddleware`
201
+
202
+ ## Validation
203
+
204
+ - Decorators: `@Validate(rule...)`, `IsString`, `IsNumber`, `IsEmail`,
205
+ `IsOptional`, `MinLength`.
206
+ - `ValidationError`: `issues` array contains `index / rule / message`.
207
+ - `validateParameters(params, metadata)` can be reused in custom scenarios.
208
+
209
+ ## Errors and Exceptions
210
+
211
+ - `HttpException` and subclasses: `BadRequestException`,
212
+ `UnauthorizedException`, `ForbiddenException`, `NotFoundException`,
213
+ `InternalServerErrorException`.
214
+ - `ExceptionFilter` interface and `ExceptionFilterRegistry`: Can register custom
215
+ filters.
216
+ - `handleError(error, context)`: Core global error handling logic; default error
217
+ middleware is automatically called.
218
+
219
+ ## WebSocket
220
+
221
+ - Decorators: `@WebSocketGateway(path)` + `@OnOpen`, `@OnMessage`, `@OnClose`.
222
+ - `WebSocketGatewayRegistry`: Automatically manages dependency injection,
223
+ registers when `Application.registerWebSocketGateway` is called.
224
+ - Server automatically handles handshakes and delegates events to gateway
225
+ instances.
226
+
227
+ ## Request Utilities
228
+
229
+ - `BodyParser`: `parse(request)`, automatically caches parsed results.
230
+ - `FileHandler`: Parses `multipart/form-data`, returns structured file objects.
231
+ - `RequestWrapper`: Lightweight wrapper for compatibility scenarios.
232
+
233
+ ## Database Module
234
+
235
+ - `DatabaseModule.forRoot(options)`: Configure database connection (PostgreSQL,
236
+ MySQL, SQLite)
237
+ - `DatabaseService`: `query()`, `initialize()`, `closePool()`, `healthCheck()`,
238
+ `getConnectionInfo()`
239
+ - `DATABASE_SERVICE_TOKEN`: Token for dependency injection
240
+
241
+ **Example**:
242
+
243
+ ```typescript
244
+ DatabaseModule.forRoot({
245
+ database: {
246
+ type: "postgres",
247
+ config: {
248
+ host: "localhost",
249
+ port: 5432,
250
+ database: "mydb",
251
+ user: "user",
252
+ password: "password",
253
+ },
254
+ },
255
+ });
256
+
257
+ @Injectable()
258
+ class UserService {
259
+ public constructor(
260
+ @Inject(DATABASE_SERVICE_TOKEN) private readonly db: DatabaseService,
261
+ ) {}
262
+
263
+ public async findUser(id: string) {
264
+ const result = await this.db.query("SELECT * FROM users WHERE id = $1", [
265
+ id,
266
+ ]);
267
+ return result[0];
268
+ }
269
+ }
270
+ ```
271
+
272
+ ## ORM Integration
273
+
274
+ - `@Entity(tableName)`: Mark class as database entity
275
+ - `@Column(options)`: Define column metadata
276
+ - `@PrimaryKey()`: Mark column as primary key
277
+ - `@Repository(tableName, primaryKey)`: Create repository for entity
278
+ - `BaseRepository<T>`: Base repository class with CRUD operations
279
+ - `DrizzleBaseRepository<T>`: Drizzle ORM integration
280
+
281
+ **Example**:
282
+
283
+ ```typescript
284
+ @Entity("users")
285
+ class User {
286
+ @PrimaryKey()
287
+ @Column({ type: "INTEGER", autoIncrement: true })
288
+ public id!: number;
289
+
290
+ @Column({ type: "TEXT", nullable: false })
291
+ public name!: string;
292
+
293
+ @Column({ type: "TEXT", nullable: true })
294
+ public email?: string;
295
+ }
296
+
297
+ @Repository("users", "id")
298
+ class UserRepository extends DrizzleBaseRepository<User> {}
299
+
300
+ @Injectable()
301
+ class UserService {
302
+ public constructor(
303
+ @Inject(UserRepository) private readonly repo: UserRepository,
304
+ ) {}
305
+
306
+ public async findAll() {
307
+ return await this.repo.findAll();
308
+ }
309
+ }
310
+ ```
311
+
312
+ ## Transaction Support
313
+
314
+ - `@Transactional(options?)`: Declare method as transactional
315
+ - `Propagation`: Transaction propagation behavior (REQUIRED, REQUIRES_NEW,
316
+ SUPPORTS, etc.)
317
+ - `IsolationLevel`: Transaction isolation level (READ_COMMITTED,
318
+ REPEATABLE_READ, etc.)
319
+ - `TransactionManager`: Manually manage transactions
320
+
321
+ **Example**:
322
+
323
+ ```typescript
324
+ @Injectable()
325
+ class OrderService {
326
+ public constructor(
327
+ @Inject(DATABASE_SERVICE_TOKEN) private readonly db: DatabaseService,
328
+ ) {}
329
+
330
+ @Transactional({
331
+ propagation: Propagation.REQUIRED,
332
+ isolationLevel: IsolationLevel.READ_COMMITTED,
333
+ })
334
+ public async createOrder(orderData: OrderData) {
335
+ // All database operations in this method run in a transaction
336
+ await this.db.query("INSERT INTO orders ...");
337
+ await this.db.query("INSERT INTO order_items ...");
338
+ // If any operation fails, all changes are rolled back
339
+ }
340
+ }
341
+ ```
342
+
343
+ ## Cache Module
344
+
345
+ - `CacheModule.forRoot(options)`: Configure caching
346
+ - `CacheService`: `get()`, `set()`, `delete()`, `getOrSet()`, `clear()`
347
+ - `@Cacheable(key?, ttl?)`: Cache method result
348
+ - `@CacheEvict(key?)`: Evict cache entry
349
+ - `@CachePut(key?, ttl?)`: Update cache entry
350
+ - `CACHE_SERVICE_TOKEN`: Token for dependency injection
351
+
352
+ **Example**:
353
+
354
+ ```typescript
355
+ CacheModule.forRoot({
356
+ defaultTtl: 3600000, // 1 hour
357
+ });
358
+
359
+ @Injectable()
360
+ class ProductService {
361
+ public constructor(
362
+ @Inject(CACHE_SERVICE_TOKEN) private readonly cache: CacheService,
363
+ ) {}
364
+
365
+ @Cacheable("product", 60000)
366
+ public async getProduct(id: string) {
367
+ // Expensive database query
368
+ return await this.db.query("SELECT * FROM products WHERE id = $1", [id]);
369
+ }
370
+
371
+ @CacheEvict("product")
372
+ public async updateProduct(id: string, data: ProductData) {
373
+ await this.db.query("UPDATE products ...");
374
+ }
375
+ }
376
+ ```
377
+
378
+ ## Queue Module
379
+
380
+ - `QueueModule.forRoot(options)`: Configure job queue
381
+ - `QueueService`: `add()`, `get()`, `delete()`, `clear()`, `count()`
382
+ - `@Queue(name, options?)`: Register job handler
383
+ - `@Cron(cronExpression, options?)`: Register cron job
384
+ - `QUEUE_SERVICE_TOKEN`: Token for dependency injection
385
+
386
+ **Example**:
387
+
388
+ ```typescript
389
+ QueueModule.forRoot({
390
+ defaultRetries: 3,
391
+ });
392
+
393
+ @Injectable()
394
+ class EmailService {
395
+ @Queue("send-email")
396
+ public async sendEmail(data: { to: string; subject: string }) {
397
+ // Send email logic
398
+ }
399
+
400
+ @Cron("0 0 * * *") // Daily at midnight
401
+ public async sendDailyReport() {
402
+ // Send daily report
403
+ }
404
+ }
405
+ ```
406
+
407
+ ## Session Module
408
+
409
+ - `SessionModule.forRoot(options)`: Configure session management
410
+ - `SessionService`: `create()`, `get()`, `set()`, `delete()`, `touch()`
411
+ - `createSessionMiddleware()`: Create session middleware
412
+ - `@Session()`: Inject session object in controller
413
+ - `SESSION_SERVICE_TOKEN`: Token for dependency injection
414
+
415
+ **Example**:
416
+
417
+ ```typescript
418
+ SessionModule.forRoot({
419
+ secret: "your-secret-key",
420
+ maxAge: 3600000, // 1 hour
421
+ });
422
+
423
+ @Controller("/api/auth")
424
+ class AuthController {
425
+ public constructor(
426
+ @Inject(SESSION_SERVICE_TOKEN) private readonly session: SessionService,
427
+ ) {}
428
+
429
+ @POST("/login")
430
+ public async login(@Body() credentials: LoginDto, @Session() session: any) {
431
+ // Session is automatically injected
432
+ session.userId = credentials.userId;
433
+ return { success: true };
434
+ }
435
+ }
436
+ ```
437
+
438
+ ## Health Module
439
+
440
+ - `HealthModule.forRoot(options)`: Configure health checks
441
+ - `HealthIndicator`: Custom health check indicator
442
+ - Automatically provides `/health` and `/ready` endpoints
443
+
444
+ **Example**:
445
+
446
+ ```typescript
447
+ HealthModule.forRoot({
448
+ indicators: [
449
+ {
450
+ name: "database",
451
+ check: async () => {
452
+ const isHealthy = await dbService.healthCheck();
453
+ return { status: isHealthy ? "up" : "down" };
454
+ },
455
+ },
456
+ ],
457
+ });
458
+ ```
459
+
460
+ ## Metrics Module
461
+
462
+ - `MetricsModule.forRoot(options)`: Configure metrics collection
463
+ - `MetricsCollector`: Collect and expose metrics
464
+ - `PrometheusFormatter`: Format metrics for Prometheus
465
+ - `createHttpMetricsMiddleware()`: HTTP metrics middleware
466
+ - `METRICS_SERVICE_TOKEN`: Token for dependency injection
467
+
468
+ **Example**:
469
+
470
+ ```typescript
471
+ MetricsModule.forRoot({
472
+ enableHttpMetrics: true,
473
+ });
474
+
475
+ @Injectable()
476
+ class OrderService {
477
+ public constructor(
478
+ @Inject(METRICS_SERVICE_TOKEN) private readonly metrics: MetricsCollector,
479
+ ) {}
480
+
481
+ public async createOrder() {
482
+ this.metrics.increment("orders.created");
483
+ // Create order logic
484
+ }
485
+ }
486
+ ```
487
+
488
+ ## Security Module
489
+
490
+ - `SecurityModule.forRoot(options)`: Configure security and authentication
491
+ - `@Auth(options?)`: Require authentication/authorization
492
+ - `SecurityContextHolder`: Access current security context
493
+ - `AuthenticationManager`: Manage authentication
494
+ - `JwtAuthenticationProvider`: JWT authentication provider
495
+ - `OAuth2AuthenticationProvider`: OAuth2 authentication provider
496
+
497
+ **Example**:
498
+
499
+ ```typescript
500
+ SecurityModule.forRoot({
501
+ jwt: {
502
+ secret: "your-secret-key",
503
+ accessTokenExpiresIn: 3600,
504
+ },
505
+ });
506
+
507
+ @Controller("/api/users")
508
+ class UserController {
509
+ @GET("/profile")
510
+ @Auth() // Require authentication
511
+ public getProfile() {
512
+ const context = SecurityContextHolder.getContext();
513
+ return context.getPrincipal();
514
+ }
515
+
516
+ @GET("/admin")
517
+ @Auth({ roles: ["admin"] }) // Require admin role
518
+ public getAdmin() {
519
+ return { message: "Admin access" };
520
+ }
521
+ }
522
+ ```
523
+
524
+ ## Export Entry
525
+
526
+ All above APIs can be exported from `src/index.ts`, via
527
+
528
+ ```ts
529
+ import {
530
+ // Core
531
+ Application,
532
+ // Security
533
+ Auth,
534
+ BadRequestException,
535
+ CACHE_SERVICE_TOKEN,
536
+ Cacheable,
537
+ CacheEvict,
538
+ CacheModule,
539
+ // Cache
540
+ CacheService,
541
+ Column,
542
+ // Modules
543
+ ConfigModule,
544
+ Container,
545
+ Context,
546
+ Controller,
547
+ createCorsMiddleware,
548
+ createErrorHandlingMiddleware,
549
+ createLoggerMiddleware,
550
+ Cron,
551
+ DATABASE_SERVICE_TOKEN,
552
+ DatabaseModule,
553
+ // Database
554
+ DatabaseService,
555
+ DELETE,
556
+ Entity,
557
+ GET,
558
+ HealthModule,
559
+ // Errors
560
+ HttpException,
561
+ Inject,
562
+ // Dependency Injection
563
+ Injectable,
564
+ IsEmail,
565
+ IsNumber,
566
+ IsString,
567
+ LoggerModule,
568
+ MetricsModule,
569
+ Module,
570
+ NotFoundException,
571
+ OnMessage,
572
+ PATCH,
573
+ // Testing
574
+ PerformanceHarness,
575
+ POST,
576
+ PrimaryKey,
577
+ PUT,
578
+ Queue,
579
+ QUEUE_SERVICE_TOKEN,
580
+ QueueModule,
581
+ // Queue
582
+ QueueService,
583
+ Repository,
584
+ SecurityContextHolder,
585
+ SecurityModule,
586
+ Session,
587
+ SESSION_SERVICE_TOKEN,
588
+ SessionModule,
589
+ // Session
590
+ SessionService,
591
+ SwaggerModule,
592
+ Transactional,
593
+ // Middleware
594
+ UseMiddleware,
595
+ // Validation
596
+ Validate,
597
+ // WebSocket
598
+ WebSocketGateway,
599
+ } from "@dangao/bun-server";
600
+ ```
601
+
602
+ for use in applications.
@@ -0,0 +1,12 @@
1
+ # Best Practices (English Draft)
2
+
3
+ The Chinese document (`docs/best-practices.md`) is the source of truth. This file lists the
4
+ main topics that still need translation:
5
+
6
+ - Coding conventions & comment style
7
+ - Logger usage (English-only requirement)
8
+ - Recommended middleware layering
9
+ - Testing strategy
10
+ - Benchmark workflow
11
+
12
+ Help us by submitting translations or summaries for each section.