@dangao/bun-server 1.7.1 → 1.8.0

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 (116) hide show
  1. package/README.md +129 -21
  2. package/dist/di/decorators.d.ts +37 -0
  3. package/dist/di/decorators.d.ts.map +1 -1
  4. package/dist/di/index.d.ts +1 -1
  5. package/dist/di/index.d.ts.map +1 -1
  6. package/dist/di/module-registry.d.ts +17 -0
  7. package/dist/di/module-registry.d.ts.map +1 -1
  8. package/dist/events/decorators.d.ts +52 -0
  9. package/dist/events/decorators.d.ts.map +1 -0
  10. package/dist/events/event-module.d.ts +97 -0
  11. package/dist/events/event-module.d.ts.map +1 -0
  12. package/dist/events/index.d.ts +5 -0
  13. package/dist/events/index.d.ts.map +1 -0
  14. package/dist/events/service.d.ts +76 -0
  15. package/dist/events/service.d.ts.map +1 -0
  16. package/dist/events/types.d.ts +184 -0
  17. package/dist/events/types.d.ts.map +1 -0
  18. package/dist/index.d.ts +5 -3
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +1511 -11
  21. package/dist/security/filter.d.ts +23 -0
  22. package/dist/security/filter.d.ts.map +1 -1
  23. package/dist/security/guards/builtin/auth-guard.d.ts +44 -0
  24. package/dist/security/guards/builtin/auth-guard.d.ts.map +1 -0
  25. package/dist/security/guards/builtin/index.d.ts +3 -0
  26. package/dist/security/guards/builtin/index.d.ts.map +1 -0
  27. package/dist/security/guards/builtin/roles-guard.d.ts +66 -0
  28. package/dist/security/guards/builtin/roles-guard.d.ts.map +1 -0
  29. package/dist/security/guards/decorators.d.ts +50 -0
  30. package/dist/security/guards/decorators.d.ts.map +1 -0
  31. package/dist/security/guards/execution-context.d.ts +56 -0
  32. package/dist/security/guards/execution-context.d.ts.map +1 -0
  33. package/dist/security/guards/guard-registry.d.ts +67 -0
  34. package/dist/security/guards/guard-registry.d.ts.map +1 -0
  35. package/dist/security/guards/index.d.ts +7 -0
  36. package/dist/security/guards/index.d.ts.map +1 -0
  37. package/dist/security/guards/reflector.d.ts +57 -0
  38. package/dist/security/guards/reflector.d.ts.map +1 -0
  39. package/dist/security/guards/types.d.ts +126 -0
  40. package/dist/security/guards/types.d.ts.map +1 -0
  41. package/dist/security/index.d.ts +1 -0
  42. package/dist/security/index.d.ts.map +1 -1
  43. package/dist/security/security-module.d.ts +20 -0
  44. package/dist/security/security-module.d.ts.map +1 -1
  45. package/dist/validation/class-validator.d.ts +108 -0
  46. package/dist/validation/class-validator.d.ts.map +1 -0
  47. package/dist/validation/custom-validator.d.ts +130 -0
  48. package/dist/validation/custom-validator.d.ts.map +1 -0
  49. package/dist/validation/errors.d.ts +22 -2
  50. package/dist/validation/errors.d.ts.map +1 -1
  51. package/dist/validation/index.d.ts +7 -1
  52. package/dist/validation/index.d.ts.map +1 -1
  53. package/dist/validation/rules/array.d.ts +33 -0
  54. package/dist/validation/rules/array.d.ts.map +1 -0
  55. package/dist/validation/rules/common.d.ts +90 -0
  56. package/dist/validation/rules/common.d.ts.map +1 -0
  57. package/dist/validation/rules/conditional.d.ts +30 -0
  58. package/dist/validation/rules/conditional.d.ts.map +1 -0
  59. package/dist/validation/rules/index.d.ts +5 -0
  60. package/dist/validation/rules/index.d.ts.map +1 -0
  61. package/dist/validation/rules/object.d.ts +30 -0
  62. package/dist/validation/rules/object.d.ts.map +1 -0
  63. package/dist/validation/types.d.ts +52 -1
  64. package/dist/validation/types.d.ts.map +1 -1
  65. package/docs/events.md +494 -0
  66. package/docs/guards.md +376 -0
  67. package/docs/guide.md +309 -1
  68. package/docs/request-lifecycle.md +444 -0
  69. package/docs/validation.md +407 -0
  70. package/docs/zh/events.md +494 -0
  71. package/docs/zh/guards.md +376 -0
  72. package/docs/zh/guide.md +309 -1
  73. package/docs/zh/request-lifecycle.md +444 -0
  74. package/docs/zh/validation.md +407 -0
  75. package/package.json +1 -1
  76. package/src/di/decorators.ts +46 -0
  77. package/src/di/index.ts +10 -1
  78. package/src/di/module-registry.ts +39 -0
  79. package/src/events/decorators.ts +103 -0
  80. package/src/events/event-module.ts +272 -0
  81. package/src/events/index.ts +32 -0
  82. package/src/events/service.ts +352 -0
  83. package/src/events/types.ts +223 -0
  84. package/src/index.ts +133 -1
  85. package/src/security/filter.ts +88 -8
  86. package/src/security/guards/builtin/auth-guard.ts +68 -0
  87. package/src/security/guards/builtin/index.ts +3 -0
  88. package/src/security/guards/builtin/roles-guard.ts +165 -0
  89. package/src/security/guards/decorators.ts +124 -0
  90. package/src/security/guards/execution-context.ts +152 -0
  91. package/src/security/guards/guard-registry.ts +164 -0
  92. package/src/security/guards/index.ts +7 -0
  93. package/src/security/guards/reflector.ts +99 -0
  94. package/src/security/guards/types.ts +144 -0
  95. package/src/security/index.ts +1 -0
  96. package/src/security/security-module.ts +72 -2
  97. package/src/validation/class-validator.ts +322 -0
  98. package/src/validation/custom-validator.ts +289 -0
  99. package/src/validation/errors.ts +50 -2
  100. package/src/validation/index.ts +103 -1
  101. package/src/validation/rules/array.ts +118 -0
  102. package/src/validation/rules/common.ts +286 -0
  103. package/src/validation/rules/conditional.ts +52 -0
  104. package/src/validation/rules/index.ts +51 -0
  105. package/src/validation/rules/object.ts +86 -0
  106. package/src/validation/types.ts +61 -1
  107. package/tests/di/global-module.test.ts +487 -0
  108. package/tests/events/event-decorators.test.ts +173 -0
  109. package/tests/events/event-emitter.test.ts +373 -0
  110. package/tests/events/event-module.test.ts +373 -0
  111. package/tests/security/guards/guards-integration.test.ts +371 -0
  112. package/tests/security/guards/guards.test.ts +775 -0
  113. package/tests/security/security-module.test.ts +2 -2
  114. package/tests/validation/class-validator.test.ts +349 -0
  115. package/tests/validation/custom-validator.test.ts +335 -0
  116. package/tests/validation/rules.test.ts +543 -0
@@ -0,0 +1,444 @@
1
+ # Request Lifecycle
2
+
3
+ This document provides a detailed explanation of how Bun Server processes HTTP requests, from the moment a request is received to when a response is sent.
4
+
5
+ ## Overview
6
+
7
+ ```
8
+ HTTP Request
9
+
10
+ ┌─────────────────────────────────────┐
11
+ │ Middleware Pipeline │
12
+ └─────────────────────────────────────┘
13
+
14
+ ┌─────────────────────────────────────┐
15
+ │ Security Filter │
16
+ └─────────────────────────────────────┘
17
+
18
+ ┌─────────────────────────────────────┐
19
+ │ Router Matching │
20
+ └─────────────────────────────────────┘
21
+
22
+ ┌─────────────────────────────────────┐
23
+ │ Interceptors (Pre) │
24
+ └─────────────────────────────────────┘
25
+
26
+ ┌─────────────────────────────────────┐
27
+ │ Parameter Binding + Validation │
28
+ └─────────────────────────────────────┘
29
+
30
+ ┌─────────────────────────────────────┐
31
+ │ Controller Method │
32
+ └─────────────────────────────────────┘
33
+
34
+ ┌─────────────────────────────────────┐
35
+ │ Interceptors (Post) │
36
+ └─────────────────────────────────────┘
37
+
38
+ ┌─────────────────────────────────────┐
39
+ │ Exception Filter │
40
+ └─────────────────────────────────────┘
41
+
42
+ HTTP Response
43
+ ```
44
+
45
+ ## 1. Middleware Pipeline
46
+
47
+ Middleware is executed first when a request arrives. Middleware can be registered at multiple levels:
48
+
49
+ ### Execution Order
50
+
51
+ 1. **Global Middleware** - Registered via `app.use()`
52
+ 2. **Module Middleware** - Defined in module configuration
53
+ 3. **Controller Middleware** - Decorated with `@UseMiddleware()` on class
54
+ 4. **Method Middleware** - Decorated with `@UseMiddleware()` on method
55
+
56
+ ### Example
57
+
58
+ ```typescript
59
+ // Global middleware
60
+ app.use(createLoggerMiddleware({ prefix: '[App]' }));
61
+ app.use(createCorsMiddleware({ origin: '*' }));
62
+
63
+ // Controller-level middleware
64
+ @Controller('/api')
65
+ @UseMiddleware(authMiddleware)
66
+ class ApiController {
67
+ // Method-level middleware
68
+ @GET('/admin')
69
+ @UseMiddleware(adminOnlyMiddleware)
70
+ public admin() {}
71
+ }
72
+ ```
73
+
74
+ ### Built-in Middleware
75
+
76
+ | Middleware | Purpose |
77
+ |------------|---------|
78
+ | `createLoggerMiddleware` | Request/response logging |
79
+ | `createCorsMiddleware` | CORS headers |
80
+ | `createErrorHandlingMiddleware` | Global error handling |
81
+ | `createRateLimitMiddleware` | Rate limiting |
82
+ | `createStaticFileMiddleware` | Static file serving |
83
+ | `createFileUploadMiddleware` | File upload handling |
84
+ | `createSessionMiddleware` | Session management |
85
+ | `createHttpMetricsMiddleware` | HTTP metrics collection |
86
+
87
+ ### When to Use Middleware
88
+
89
+ - Cross-cutting concerns (logging, metrics)
90
+ - Request/response transformation
91
+ - Authentication token extraction
92
+ - CORS handling
93
+ - Rate limiting
94
+ - Static file serving
95
+
96
+ ## 2. Security Filter
97
+
98
+ After middleware, the security filter checks authentication and authorization.
99
+
100
+ ### Flow
101
+
102
+ 1. Check if path is in `excludePaths`
103
+ 2. Extract credentials (JWT, OAuth2 token)
104
+ 3. Authenticate using `AuthenticationManager`
105
+ 4. Set `SecurityContext` for the request
106
+ 5. Check roles if `@Auth({ roles: [...] })` is specified
107
+
108
+ ### Configuration
109
+
110
+ ```typescript
111
+ SecurityModule.forRoot({
112
+ jwt: {
113
+ secret: 'your-secret-key',
114
+ accessTokenExpiresIn: 3600,
115
+ },
116
+ oauth2Clients: [/* ... */],
117
+ excludePaths: ['/public', '/health'],
118
+ });
119
+ ```
120
+
121
+ ### Usage
122
+
123
+ ```typescript
124
+ @Controller('/api/users')
125
+ class UserController {
126
+ @GET('/profile')
127
+ @Auth() // Requires authentication
128
+ public getProfile() {
129
+ const context = SecurityContextHolder.getContext();
130
+ return context.getPrincipal();
131
+ }
132
+
133
+ @GET('/admin')
134
+ @Auth({ roles: ['admin'] }) // Requires admin role
135
+ public adminOnly() {}
136
+ }
137
+ ```
138
+
139
+ ## 3. Router Matching
140
+
141
+ The router matches the request path and method to a registered route.
142
+
143
+ ### Matching Priority
144
+
145
+ 1. **Static Routes** - Exact path match (`/api/users`)
146
+ 2. **Dynamic Routes** - Path with parameters (`/api/users/:id`)
147
+ 3. **Wildcard Routes** - Catch-all patterns (`/api/*`)
148
+
149
+ ### Route Registration
150
+
151
+ Routes are automatically registered when you use decorators:
152
+
153
+ ```typescript
154
+ @Controller('/api/users')
155
+ class UserController {
156
+ @GET('/:id') // GET /api/users/:id
157
+ public getUser() {}
158
+
159
+ @POST('/') // POST /api/users
160
+ public createUser() {}
161
+
162
+ @PUT('/:id') // PUT /api/users/:id
163
+ public updateUser() {}
164
+
165
+ @DELETE('/:id') // DELETE /api/users/:id
166
+ public deleteUser() {}
167
+ }
168
+ ```
169
+
170
+ ## 4. Interceptors (Pre-processing)
171
+
172
+ Interceptors run before and after the controller method. Pre-interceptors execute in order:
173
+
174
+ 1. **Global Interceptors**
175
+ 2. **Controller Interceptors**
176
+ 3. **Method Interceptors**
177
+
178
+ ### Example
179
+
180
+ ```typescript
181
+ @Injectable()
182
+ class LoggingInterceptor implements Interceptor {
183
+ public async intercept(context: ExecutionContext, next: () => Promise<Response>): Promise<Response> {
184
+ console.log('Before handler...');
185
+ const response = await next();
186
+ console.log('After handler...');
187
+ return response;
188
+ }
189
+ }
190
+
191
+ @Controller('/api')
192
+ @UseInterceptors(LoggingInterceptor)
193
+ class ApiController {}
194
+ ```
195
+
196
+ ### Use Cases
197
+
198
+ - Logging
199
+ - Caching
200
+ - Response transformation
201
+ - Performance monitoring
202
+
203
+ ## 5. Parameter Binding and Validation
204
+
205
+ ### Parameter Decorators
206
+
207
+ | Decorator | Source | Example |
208
+ |-----------|--------|---------|
209
+ | `@Param(name)` | URL path parameter | `/users/:id` → `@Param('id')` |
210
+ | `@Query(name)` | Query string | `?page=1` → `@Query('page')` |
211
+ | `@Body()` | Request body | JSON body |
212
+ | `@Body(name)` | Body property | `body.name` → `@Body('name')` |
213
+ | `@Header(name)` | Request header | `@Header('Authorization')` |
214
+ | `@Context()` | Full context | Request context object |
215
+ | `@Session()` | Session data | Session object |
216
+
217
+ ### Validation
218
+
219
+ Validation is performed using the `@Validate()` decorator:
220
+
221
+ ```typescript
222
+ @POST('/users')
223
+ public createUser(
224
+ @Body('name') @Validate(IsString(), MinLength(3)) name: string,
225
+ @Body('email') @Validate(IsEmail()) email: string,
226
+ @Body('age') @Validate(IsNumber(), Min(0), Max(150)) age: number,
227
+ ) {
228
+ return { name, email, age };
229
+ }
230
+ ```
231
+
232
+ ### Built-in Validators
233
+
234
+ | Validator | Description |
235
+ |-----------|-------------|
236
+ | `IsString()` | Must be a string |
237
+ | `IsNumber()` | Must be a number |
238
+ | `IsEmail()` | Must be valid email |
239
+ | `MinLength(n)` | Minimum string length |
240
+ | `MaxLength(n)` | Maximum string length |
241
+ | `Min(n)` | Minimum number value |
242
+ | `Max(n)` | Maximum number value |
243
+ | `IsOptional()` | Field is optional |
244
+ | `IsEnum(enum)` | Must be enum value |
245
+ | `Matches(regex)` | Must match pattern |
246
+
247
+ ### Validation Error Handling
248
+
249
+ When validation fails, a `ValidationError` is thrown with detailed information:
250
+
251
+ ```json
252
+ {
253
+ "status": 400,
254
+ "message": "Validation failed",
255
+ "issues": [
256
+ {
257
+ "field": "email",
258
+ "message": "Must be a valid email address",
259
+ "value": "invalid"
260
+ }
261
+ ]
262
+ }
263
+ ```
264
+
265
+ ## 6. Controller Method Execution
266
+
267
+ After validation, the controller method is invoked with resolved dependencies and bound parameters.
268
+
269
+ ### Dependency Injection
270
+
271
+ Services are injected via constructor:
272
+
273
+ ```typescript
274
+ @Controller('/api/users')
275
+ class UserController {
276
+ public constructor(
277
+ private readonly userService: UserService,
278
+ @Inject(CONFIG_SERVICE_TOKEN) private readonly config: ConfigService,
279
+ ) {}
280
+
281
+ @GET('/:id')
282
+ public async getUser(@Param('id') id: string) {
283
+ return await this.userService.findById(id);
284
+ }
285
+ }
286
+ ```
287
+
288
+ ### Return Values
289
+
290
+ Controller methods can return:
291
+
292
+ - **Plain objects** - Serialized as JSON
293
+ - **Response** - Native Response object
294
+ - **void** - Empty response (204)
295
+ - **Promise** - Async operations
296
+
297
+ ## 7. Interceptors (Post-processing)
298
+
299
+ After the handler executes, post-interceptors run in reverse order:
300
+
301
+ 1. **Method Interceptors**
302
+ 2. **Controller Interceptors**
303
+ 3. **Global Interceptors**
304
+
305
+ This allows interceptors to transform the response:
306
+
307
+ ```typescript
308
+ @Injectable()
309
+ class TransformInterceptor implements Interceptor {
310
+ public async intercept(context: ExecutionContext, next: () => Promise<Response>): Promise<Response> {
311
+ const response = await next();
312
+ // Transform response here
313
+ return new Response(JSON.stringify({
314
+ data: await response.json(),
315
+ timestamp: Date.now(),
316
+ }));
317
+ }
318
+ }
319
+ ```
320
+
321
+ ## 8. Exception Filter
322
+
323
+ If any exception is thrown during the request lifecycle, it's caught by the exception filter.
324
+
325
+ ### Built-in Exceptions
326
+
327
+ | Exception | Status Code | Usage |
328
+ |-----------|-------------|-------|
329
+ | `HttpException` | Custom | Base exception class |
330
+ | `BadRequestException` | 400 | Invalid request |
331
+ | `UnauthorizedException` | 401 | Authentication required |
332
+ | `ForbiddenException` | 403 | Access denied |
333
+ | `NotFoundException` | 404 | Resource not found |
334
+ | `ValidationError` | 400 | Validation failed |
335
+
336
+ ### Custom Exception Filter
337
+
338
+ ```typescript
339
+ ExceptionFilterRegistry.getInstance().register({
340
+ catch(error: Error, context: Context): Response | undefined {
341
+ if (error instanceof CustomException) {
342
+ return context.createResponse(
343
+ { error: error.message, code: error.code },
344
+ { status: error.status }
345
+ );
346
+ }
347
+ return undefined; // Pass to next filter
348
+ }
349
+ });
350
+ ```
351
+
352
+ ### Error Response Format
353
+
354
+ Default error responses follow this format:
355
+
356
+ ```json
357
+ {
358
+ "status": 400,
359
+ "message": "Error message",
360
+ "code": "ERROR_CODE",
361
+ "timestamp": "2024-01-01T00:00:00.000Z"
362
+ }
363
+ ```
364
+
365
+ ## Component Comparison
366
+
367
+ | Component | Execution Point | Use Case |
368
+ |-----------|-----------------|----------|
369
+ | **Middleware** | Before routing | Cross-cutting concerns, request transformation |
370
+ | **Guards** | After routing, before handler | Authentication, authorization |
371
+ | **Interceptors** | Before/after handler | Logging, caching, response transformation |
372
+ | **Pipes** | Parameter binding | Validation, transformation |
373
+ | **Exception Filters** | On exception | Error handling |
374
+
375
+ ## Best Practices
376
+
377
+ ### 1. Middleware for Cross-Cutting Concerns
378
+
379
+ Use middleware for concerns that apply to all or most requests:
380
+
381
+ ```typescript
382
+ // Good: Global logging
383
+ app.use(createLoggerMiddleware({ prefix: '[App]' }));
384
+
385
+ // Good: CORS for all API routes
386
+ app.use(createCorsMiddleware({ origin: '*' }));
387
+ ```
388
+
389
+ ### 2. Guards for Authorization
390
+
391
+ Use security decorators for route-specific authorization:
392
+
393
+ ```typescript
394
+ // Good: Role-based access control
395
+ @Auth({ roles: ['admin'] })
396
+ @GET('/admin/dashboard')
397
+ public dashboard() {}
398
+ ```
399
+
400
+ ### 3. Interceptors for Response Transformation
401
+
402
+ Use interceptors when you need to modify responses:
403
+
404
+ ```typescript
405
+ // Good: Add metadata to all responses
406
+ @UseInterceptors(ResponseMetadataInterceptor)
407
+ @Controller('/api')
408
+ class ApiController {}
409
+ ```
410
+
411
+ ### 4. Validation at Parameter Level
412
+
413
+ Validate early and fail fast:
414
+
415
+ ```typescript
416
+ // Good: Validate at parameter binding
417
+ @POST('/users')
418
+ public createUser(
419
+ @Body('email') @Validate(IsEmail()) email: string,
420
+ ) {}
421
+ ```
422
+
423
+ ### 5. Specific Exception Types
424
+
425
+ Throw specific exceptions for clear error handling:
426
+
427
+ ```typescript
428
+ // Good: Specific exception
429
+ if (!user) {
430
+ throw new NotFoundException('User not found');
431
+ }
432
+
433
+ // Avoid: Generic error
434
+ if (!user) {
435
+ throw new Error('Not found');
436
+ }
437
+ ```
438
+
439
+ ## See Also
440
+
441
+ - [API Reference](./api.md)
442
+ - [Usage Guide](./guide.md)
443
+ - [Error Handling](./error-handling.md)
444
+ - [Security](./guide.md#15-security-and-authentication)