@hazeljs/core 0.2.0-beta.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/README.md +522 -0
- package/dist/__tests__/container.test.d.ts +2 -0
- package/dist/__tests__/container.test.d.ts.map +1 -0
- package/dist/__tests__/container.test.js +454 -0
- package/dist/__tests__/decorators.test.d.ts +2 -0
- package/dist/__tests__/decorators.test.d.ts.map +1 -0
- package/dist/__tests__/decorators.test.js +693 -0
- package/dist/__tests__/errors/http.error.test.d.ts +2 -0
- package/dist/__tests__/errors/http.error.test.d.ts.map +1 -0
- package/dist/__tests__/errors/http.error.test.js +117 -0
- package/dist/__tests__/filters/exception-filter.test.d.ts +2 -0
- package/dist/__tests__/filters/exception-filter.test.d.ts.map +1 -0
- package/dist/__tests__/filters/exception-filter.test.js +135 -0
- package/dist/__tests__/filters/http-exception.filter.test.d.ts +2 -0
- package/dist/__tests__/filters/http-exception.filter.test.d.ts.map +1 -0
- package/dist/__tests__/filters/http-exception.filter.test.js +119 -0
- package/dist/__tests__/hazel-app.test.d.ts +2 -0
- package/dist/__tests__/hazel-app.test.d.ts.map +1 -0
- package/dist/__tests__/hazel-app.test.js +682 -0
- package/dist/__tests__/hazel-module.test.d.ts +2 -0
- package/dist/__tests__/hazel-module.test.d.ts.map +1 -0
- package/dist/__tests__/hazel-module.test.js +408 -0
- package/dist/__tests__/hazel-response.test.d.ts +2 -0
- package/dist/__tests__/hazel-response.test.d.ts.map +1 -0
- package/dist/__tests__/hazel-response.test.js +138 -0
- package/dist/__tests__/health.test.d.ts +2 -0
- package/dist/__tests__/health.test.d.ts.map +1 -0
- package/dist/__tests__/health.test.js +147 -0
- package/dist/__tests__/index.test.d.ts +2 -0
- package/dist/__tests__/index.test.d.ts.map +1 -0
- package/dist/__tests__/index.test.js +239 -0
- package/dist/__tests__/interceptors/interceptor.test.d.ts +2 -0
- package/dist/__tests__/interceptors/interceptor.test.d.ts.map +1 -0
- package/dist/__tests__/interceptors/interceptor.test.js +166 -0
- package/dist/__tests__/logger.test.d.ts +2 -0
- package/dist/__tests__/logger.test.d.ts.map +1 -0
- package/dist/__tests__/logger.test.js +141 -0
- package/dist/__tests__/middleware/cors.test.d.ts +2 -0
- package/dist/__tests__/middleware/cors.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/cors.test.js +129 -0
- package/dist/__tests__/middleware/csrf.test.d.ts +2 -0
- package/dist/__tests__/middleware/csrf.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/csrf.test.js +247 -0
- package/dist/__tests__/middleware/global-middleware.test.d.ts +2 -0
- package/dist/__tests__/middleware/global-middleware.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/global-middleware.test.js +259 -0
- package/dist/__tests__/middleware/rate-limit.test.d.ts +2 -0
- package/dist/__tests__/middleware/rate-limit.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/rate-limit.test.js +264 -0
- package/dist/__tests__/middleware/security-headers.test.d.ts +2 -0
- package/dist/__tests__/middleware/security-headers.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/security-headers.test.js +229 -0
- package/dist/__tests__/middleware/timeout.test.d.ts +2 -0
- package/dist/__tests__/middleware/timeout.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/timeout.test.js +132 -0
- package/dist/__tests__/middleware.test.d.ts +2 -0
- package/dist/__tests__/middleware.test.d.ts.map +1 -0
- package/dist/__tests__/middleware.test.js +180 -0
- package/dist/__tests__/pipes/pipe.test.d.ts +2 -0
- package/dist/__tests__/pipes/pipe.test.d.ts.map +1 -0
- package/dist/__tests__/pipes/pipe.test.js +245 -0
- package/dist/__tests__/pipes/validation.pipe.test.d.ts +2 -0
- package/dist/__tests__/pipes/validation.pipe.test.d.ts.map +1 -0
- package/dist/__tests__/pipes/validation.pipe.test.js +297 -0
- package/dist/__tests__/request-parser.test.d.ts +2 -0
- package/dist/__tests__/request-parser.test.d.ts.map +1 -0
- package/dist/__tests__/request-parser.test.js +182 -0
- package/dist/__tests__/router.test.d.ts +2 -0
- package/dist/__tests__/router.test.d.ts.map +1 -0
- package/dist/__tests__/router.test.js +680 -0
- package/dist/__tests__/routing/route-matcher.test.d.ts +2 -0
- package/dist/__tests__/routing/route-matcher.test.d.ts.map +1 -0
- package/dist/__tests__/routing/route-matcher.test.js +219 -0
- package/dist/__tests__/routing/version.decorator.test.d.ts +2 -0
- package/dist/__tests__/routing/version.decorator.test.d.ts.map +1 -0
- package/dist/__tests__/routing/version.decorator.test.js +298 -0
- package/dist/__tests__/service.test.d.ts +2 -0
- package/dist/__tests__/service.test.d.ts.map +1 -0
- package/dist/__tests__/service.test.js +121 -0
- package/dist/__tests__/shutdown.test.d.ts +2 -0
- package/dist/__tests__/shutdown.test.d.ts.map +1 -0
- package/dist/__tests__/shutdown.test.js +250 -0
- package/dist/__tests__/testing/testing.module.test.d.ts +2 -0
- package/dist/__tests__/testing/testing.module.test.d.ts.map +1 -0
- package/dist/__tests__/testing/testing.module.test.js +370 -0
- package/dist/__tests__/upload/file-upload.test.d.ts +2 -0
- package/dist/__tests__/upload/file-upload.test.d.ts.map +1 -0
- package/dist/__tests__/upload/file-upload.test.js +498 -0
- package/dist/__tests__/utils/sanitize.test.d.ts +2 -0
- package/dist/__tests__/utils/sanitize.test.d.ts.map +1 -0
- package/dist/__tests__/utils/sanitize.test.js +291 -0
- package/dist/__tests__/validator.test.d.ts +2 -0
- package/dist/__tests__/validator.test.d.ts.map +1 -0
- package/dist/__tests__/validator.test.js +300 -0
- package/dist/container.d.ts +80 -0
- package/dist/container.d.ts.map +1 -0
- package/dist/container.js +271 -0
- package/dist/decorators.d.ts +92 -0
- package/dist/decorators.d.ts.map +1 -0
- package/dist/decorators.js +343 -0
- package/dist/errors/http.error.d.ts +31 -0
- package/dist/errors/http.error.d.ts.map +1 -0
- package/dist/errors/http.error.js +62 -0
- package/dist/filters/exception-filter.d.ts +39 -0
- package/dist/filters/exception-filter.d.ts.map +1 -0
- package/dist/filters/exception-filter.js +38 -0
- package/dist/filters/http-exception.filter.d.ts +9 -0
- package/dist/filters/http-exception.filter.d.ts.map +1 -0
- package/dist/filters/http-exception.filter.js +42 -0
- package/dist/hazel-app.d.ts +78 -0
- package/dist/hazel-app.d.ts.map +1 -0
- package/dist/hazel-app.js +453 -0
- package/dist/hazel-module.d.ts +20 -0
- package/dist/hazel-module.d.ts.map +1 -0
- package/dist/hazel-module.js +109 -0
- package/dist/hazel-response.d.ts +20 -0
- package/dist/hazel-response.d.ts.map +1 -0
- package/dist/hazel-response.js +68 -0
- package/dist/health.d.ts +73 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +174 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +140 -0
- package/dist/interceptors/interceptor.d.ts +22 -0
- package/dist/interceptors/interceptor.d.ts.map +1 -0
- package/dist/interceptors/interceptor.js +46 -0
- package/dist/logger.d.ts +8 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +238 -0
- package/dist/middleware/cors.middleware.d.ts +44 -0
- package/dist/middleware/cors.middleware.d.ts.map +1 -0
- package/dist/middleware/cors.middleware.js +118 -0
- package/dist/middleware/csrf.middleware.d.ts +82 -0
- package/dist/middleware/csrf.middleware.d.ts.map +1 -0
- package/dist/middleware/csrf.middleware.js +183 -0
- package/dist/middleware/global-middleware.d.ts +111 -0
- package/dist/middleware/global-middleware.d.ts.map +1 -0
- package/dist/middleware/global-middleware.js +179 -0
- package/dist/middleware/rate-limit.middleware.d.ts +73 -0
- package/dist/middleware/rate-limit.middleware.d.ts.map +1 -0
- package/dist/middleware/rate-limit.middleware.js +124 -0
- package/dist/middleware/security-headers.middleware.d.ts +76 -0
- package/dist/middleware/security-headers.middleware.d.ts.map +1 -0
- package/dist/middleware/security-headers.middleware.js +123 -0
- package/dist/middleware/timeout.middleware.d.ts +25 -0
- package/dist/middleware/timeout.middleware.d.ts.map +1 -0
- package/dist/middleware/timeout.middleware.js +74 -0
- package/dist/middleware.d.ts +13 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +47 -0
- package/dist/pipes/pipe.d.ts +50 -0
- package/dist/pipes/pipe.d.ts.map +1 -0
- package/dist/pipes/pipe.js +96 -0
- package/dist/pipes/validation.pipe.d.ts +6 -0
- package/dist/pipes/validation.pipe.d.ts.map +1 -0
- package/dist/pipes/validation.pipe.js +61 -0
- package/dist/request-context.d.ts +17 -0
- package/dist/request-context.d.ts.map +1 -0
- package/dist/request-context.js +2 -0
- package/dist/request-parser.d.ts +7 -0
- package/dist/request-parser.d.ts.map +1 -0
- package/dist/request-parser.js +60 -0
- package/dist/router.d.ts +33 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +426 -0
- package/dist/routing/route-matcher.d.ts +39 -0
- package/dist/routing/route-matcher.d.ts.map +1 -0
- package/dist/routing/route-matcher.js +93 -0
- package/dist/routing/version.decorator.d.ts +36 -0
- package/dist/routing/version.decorator.d.ts.map +1 -0
- package/dist/routing/version.decorator.js +89 -0
- package/dist/service.d.ts +9 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +39 -0
- package/dist/shutdown.d.ts +32 -0
- package/dist/shutdown.d.ts.map +1 -0
- package/dist/shutdown.js +109 -0
- package/dist/testing/testing.module.d.ts +83 -0
- package/dist/testing/testing.module.d.ts.map +1 -0
- package/dist/testing/testing.module.js +164 -0
- package/dist/types.d.ts +76 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/upload/file-upload.d.ts +75 -0
- package/dist/upload/file-upload.d.ts.map +1 -0
- package/dist/upload/file-upload.js +261 -0
- package/dist/utils/sanitize.d.ts +45 -0
- package/dist/utils/sanitize.d.ts.map +1 -0
- package/dist/utils/sanitize.js +165 -0
- package/dist/validator.d.ts +7 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +119 -0
- package/package.json +65 -0
package/README.md
ADDED
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
# @hazeljs/core
|
|
2
|
+
|
|
3
|
+
**Core HazelJS Framework - Dependency Injection, Routing, Decorators, and Base Functionality**
|
|
4
|
+
|
|
5
|
+
The foundation of the HazelJS framework, providing enterprise-grade dependency injection, decorator-based routing, middleware support, and production-ready features.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@hazeljs/core)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- 🎯 **Dependency Injection** - Advanced DI with Singleton, Transient, and Request scopes
|
|
13
|
+
- 🎨 **Decorator-Based API** - Clean, intuitive programming model
|
|
14
|
+
- 🛣️ **Routing** - Express-based routing with parameter extraction
|
|
15
|
+
- 🔌 **Middleware Support** - Global and route-level middleware
|
|
16
|
+
- 🛡️ **Guards & Interceptors** - Request validation and transformation
|
|
17
|
+
- 🔧 **Pipes** - Data transformation and validation
|
|
18
|
+
- 🏥 **Health Checks** - Built-in liveness, readiness, and startup probes
|
|
19
|
+
- 🛑 **Graceful Shutdown** - Proper cleanup and connection draining
|
|
20
|
+
- 📊 **Logging** - Winston-based structured logging
|
|
21
|
+
- ✅ **Validation** - Automatic request validation with class-validator
|
|
22
|
+
- 🧪 **Testing Utilities** - Full testing support with TestingModule
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install @hazeljs/core
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
### 1. Create a Controller
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { Controller, Get, Post, Body, Param } from '@hazeljs/core';
|
|
36
|
+
|
|
37
|
+
@Controller('/users')
|
|
38
|
+
export class UserController {
|
|
39
|
+
@Get()
|
|
40
|
+
findAll() {
|
|
41
|
+
return { users: [] };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@Get('/:id')
|
|
45
|
+
findOne(@Param('id') id: string) {
|
|
46
|
+
return { id, name: 'John Doe' };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@Post()
|
|
50
|
+
create(@Body() createUserDto: CreateUserDto) {
|
|
51
|
+
return { message: 'User created', data: createUserDto };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 2. Create a Service
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { Injectable } from '@hazeljs/core';
|
|
60
|
+
|
|
61
|
+
@Injectable()
|
|
62
|
+
export class UserService {
|
|
63
|
+
private users = [];
|
|
64
|
+
|
|
65
|
+
findAll() {
|
|
66
|
+
return this.users;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
findOne(id: string) {
|
|
70
|
+
return this.users.find(user => user.id === id);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
create(data: any) {
|
|
74
|
+
const user = { id: Date.now().toString(), ...data };
|
|
75
|
+
this.users.push(user);
|
|
76
|
+
return user;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 3. Create a Module
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import { HazelModule } from '@hazeljs/core';
|
|
85
|
+
import { UserController } from './user.controller';
|
|
86
|
+
import { UserService } from './user.service';
|
|
87
|
+
|
|
88
|
+
@HazelModule({
|
|
89
|
+
controllers: [UserController],
|
|
90
|
+
providers: [UserService],
|
|
91
|
+
})
|
|
92
|
+
export class AppModule {}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 4. Bootstrap the Application
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import { HazelApp, BuiltInHealthChecks } from '@hazeljs/core';
|
|
99
|
+
import { AppModule } from './app.module';
|
|
100
|
+
|
|
101
|
+
async function bootstrap() {
|
|
102
|
+
const app = await HazelApp.create(AppModule);
|
|
103
|
+
|
|
104
|
+
// Register health checks
|
|
105
|
+
app.registerHealthCheck(BuiltInHealthChecks.memoryCheck(500));
|
|
106
|
+
app.registerHealthCheck(BuiltInHealthChecks.eventLoopCheck(100));
|
|
107
|
+
|
|
108
|
+
// Register shutdown handlers
|
|
109
|
+
app.registerShutdownHandler({
|
|
110
|
+
name: 'cleanup',
|
|
111
|
+
handler: async () => {
|
|
112
|
+
console.log('Cleaning up resources...');
|
|
113
|
+
},
|
|
114
|
+
timeout: 5000,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
await app.listen(3000);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
bootstrap();
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Dependency Injection
|
|
124
|
+
|
|
125
|
+
### Scopes
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { Injectable, Scope } from '@hazeljs/core';
|
|
129
|
+
|
|
130
|
+
// Singleton (default) - one instance for entire app
|
|
131
|
+
@Injectable()
|
|
132
|
+
export class SingletonService {}
|
|
133
|
+
|
|
134
|
+
// Transient - new instance every time
|
|
135
|
+
@Injectable({ scope: Scope.TRANSIENT })
|
|
136
|
+
export class TransientService {}
|
|
137
|
+
|
|
138
|
+
// Request - one instance per HTTP request
|
|
139
|
+
@Injectable({ scope: Scope.REQUEST })
|
|
140
|
+
export class RequestContextService {}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Constructor Injection
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
@Injectable()
|
|
147
|
+
export class OrderService {
|
|
148
|
+
constructor(
|
|
149
|
+
private userService: UserService,
|
|
150
|
+
private paymentService: PaymentService
|
|
151
|
+
) {}
|
|
152
|
+
|
|
153
|
+
async createOrder(userId: string) {
|
|
154
|
+
const user = await this.userService.findOne(userId);
|
|
155
|
+
const payment = await this.paymentService.process(user);
|
|
156
|
+
return { user, payment };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Routing & Decorators
|
|
162
|
+
|
|
163
|
+
### HTTP Methods
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
import { Controller, Get, Post, Put, Delete, Patch } from '@hazeljs/core';
|
|
167
|
+
|
|
168
|
+
@Controller('/api')
|
|
169
|
+
export class ApiController {
|
|
170
|
+
@Get('/items')
|
|
171
|
+
getItems() {}
|
|
172
|
+
|
|
173
|
+
@Post('/items')
|
|
174
|
+
createItem() {}
|
|
175
|
+
|
|
176
|
+
@Put('/items/:id')
|
|
177
|
+
updateItem() {}
|
|
178
|
+
|
|
179
|
+
@Patch('/items/:id')
|
|
180
|
+
patchItem() {}
|
|
181
|
+
|
|
182
|
+
@Delete('/items/:id')
|
|
183
|
+
deleteItem() {}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Parameter Decorators
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
import { Controller, Get, Post, Param, Query, Body, Headers, Req, Res } from '@hazeljs/core';
|
|
191
|
+
|
|
192
|
+
@Controller('/users')
|
|
193
|
+
export class UserController {
|
|
194
|
+
@Get('/:id')
|
|
195
|
+
findOne(
|
|
196
|
+
@Param('id') id: string,
|
|
197
|
+
@Query('include') include?: string
|
|
198
|
+
) {
|
|
199
|
+
return { id, include };
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
@Post()
|
|
203
|
+
create(
|
|
204
|
+
@Body() createUserDto: CreateUserDto,
|
|
205
|
+
@Headers('authorization') auth: string
|
|
206
|
+
) {
|
|
207
|
+
return { data: createUserDto, auth };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
@Get('/raw')
|
|
211
|
+
rawAccess(@Req() req: Request, @Res() res: Response) {
|
|
212
|
+
res.json({ message: 'Direct access to req/res' });
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Middleware
|
|
218
|
+
|
|
219
|
+
### Global Middleware
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
import { Middleware, MiddlewareContext } from '@hazeljs/core';
|
|
223
|
+
|
|
224
|
+
@Injectable()
|
|
225
|
+
export class LoggerMiddleware implements Middleware {
|
|
226
|
+
async use(context: MiddlewareContext, next: () => Promise<void>) {
|
|
227
|
+
console.log(`${context.request.method} ${context.request.url}`);
|
|
228
|
+
await next();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Register globally
|
|
233
|
+
const app = await HazelApp.create(AppModule);
|
|
234
|
+
app.useGlobalMiddleware(new LoggerMiddleware());
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Route-Level Middleware
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
import { Controller, Get, UseMiddleware } from '@hazeljs/core';
|
|
241
|
+
|
|
242
|
+
@Controller('/admin')
|
|
243
|
+
@UseMiddleware(AuthMiddleware)
|
|
244
|
+
export class AdminController {
|
|
245
|
+
@Get('/dashboard')
|
|
246
|
+
@UseMiddleware(RoleCheckMiddleware)
|
|
247
|
+
getDashboard() {
|
|
248
|
+
return { data: 'admin dashboard' };
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Guards
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
import { Guard, GuardContext } from '@hazeljs/core';
|
|
257
|
+
|
|
258
|
+
@Injectable()
|
|
259
|
+
export class AuthGuard implements Guard {
|
|
260
|
+
canActivate(context: GuardContext): boolean | Promise<boolean> {
|
|
261
|
+
const token = context.request.headers.authorization;
|
|
262
|
+
return this.validateToken(token);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
private validateToken(token: string): boolean {
|
|
266
|
+
// Validate JWT token
|
|
267
|
+
return !!token;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Use in controller
|
|
272
|
+
@Controller('/protected')
|
|
273
|
+
@UseGuard(AuthGuard)
|
|
274
|
+
export class ProtectedController {
|
|
275
|
+
@Get()
|
|
276
|
+
getData() {
|
|
277
|
+
return { message: 'Protected data' };
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Interceptors
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
import { Interceptor, InterceptorContext } from '@hazeljs/core';
|
|
286
|
+
|
|
287
|
+
@Injectable()
|
|
288
|
+
export class TransformInterceptor implements Interceptor {
|
|
289
|
+
async intercept(context: InterceptorContext, next: () => Promise<any>) {
|
|
290
|
+
const result = await next();
|
|
291
|
+
|
|
292
|
+
return {
|
|
293
|
+
data: result,
|
|
294
|
+
timestamp: new Date().toISOString(),
|
|
295
|
+
path: context.request.url,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Use globally or per route
|
|
301
|
+
@Controller('/api')
|
|
302
|
+
@UseInterceptor(TransformInterceptor)
|
|
303
|
+
export class ApiController {}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
## Pipes
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
import { Pipe, PipeContext } from '@hazeljs/core';
|
|
310
|
+
|
|
311
|
+
@Injectable()
|
|
312
|
+
export class ValidationPipe implements Pipe {
|
|
313
|
+
transform(value: any, context: PipeContext) {
|
|
314
|
+
if (!value) {
|
|
315
|
+
throw new Error('Value is required');
|
|
316
|
+
}
|
|
317
|
+
return value;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Use in route
|
|
322
|
+
@Post()
|
|
323
|
+
create(@Body(ValidationPipe) createDto: CreateDto) {
|
|
324
|
+
return createDto;
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## Validation
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
import { IsEmail, IsString, MinLength } from 'class-validator';
|
|
332
|
+
|
|
333
|
+
export class CreateUserDto {
|
|
334
|
+
@IsEmail()
|
|
335
|
+
email: string;
|
|
336
|
+
|
|
337
|
+
@IsString()
|
|
338
|
+
@MinLength(8)
|
|
339
|
+
password: string;
|
|
340
|
+
|
|
341
|
+
@IsString()
|
|
342
|
+
name: string;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
@Controller('/users')
|
|
346
|
+
export class UserController {
|
|
347
|
+
@Post()
|
|
348
|
+
create(@Body() createUserDto: CreateUserDto) {
|
|
349
|
+
// Automatically validated before reaching here
|
|
350
|
+
return createUserDto;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
## Health Checks
|
|
356
|
+
|
|
357
|
+
```typescript
|
|
358
|
+
import { HazelApp, BuiltInHealthChecks } from '@hazeljs/core';
|
|
359
|
+
|
|
360
|
+
const app = await HazelApp.create(AppModule);
|
|
361
|
+
|
|
362
|
+
// Built-in checks
|
|
363
|
+
app.registerHealthCheck(BuiltInHealthChecks.memoryCheck(500)); // 500MB threshold
|
|
364
|
+
app.registerHealthCheck(BuiltInHealthChecks.eventLoopCheck(100)); // 100ms lag
|
|
365
|
+
|
|
366
|
+
// Custom health check
|
|
367
|
+
app.registerHealthCheck({
|
|
368
|
+
name: 'database',
|
|
369
|
+
check: async () => {
|
|
370
|
+
try {
|
|
371
|
+
await database.ping();
|
|
372
|
+
return { status: 'healthy' };
|
|
373
|
+
} catch (error) {
|
|
374
|
+
return {
|
|
375
|
+
status: 'unhealthy',
|
|
376
|
+
message: error.message
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
},
|
|
380
|
+
critical: true,
|
|
381
|
+
timeout: 3000,
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
// Endpoints available:
|
|
385
|
+
// GET /health - Liveness probe
|
|
386
|
+
// GET /ready - Readiness probe
|
|
387
|
+
// GET /startup - Startup probe
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
## Graceful Shutdown
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
const app = await HazelApp.create(AppModule);
|
|
394
|
+
|
|
395
|
+
app.registerShutdownHandler({
|
|
396
|
+
name: 'database',
|
|
397
|
+
handler: async () => {
|
|
398
|
+
await database.disconnect();
|
|
399
|
+
console.log('Database disconnected');
|
|
400
|
+
},
|
|
401
|
+
timeout: 5000,
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
app.registerShutdownHandler({
|
|
405
|
+
name: 'cache',
|
|
406
|
+
handler: async () => {
|
|
407
|
+
await redis.quit();
|
|
408
|
+
console.log('Redis connection closed');
|
|
409
|
+
},
|
|
410
|
+
timeout: 3000,
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
await app.listen(3000);
|
|
414
|
+
|
|
415
|
+
// On SIGTERM/SIGINT:
|
|
416
|
+
// 1. HTTP server stops accepting new connections
|
|
417
|
+
// 2. Existing requests complete (up to 10s)
|
|
418
|
+
// 3. Shutdown handlers execute in order
|
|
419
|
+
// 4. Process exits cleanly
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## Exception Handling
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
import { ExceptionFilter, ExceptionContext } from '@hazeljs/core';
|
|
426
|
+
|
|
427
|
+
@Injectable()
|
|
428
|
+
export class HttpExceptionFilter implements ExceptionFilter {
|
|
429
|
+
catch(error: Error, context: ExceptionContext) {
|
|
430
|
+
const response = context.response;
|
|
431
|
+
|
|
432
|
+
response.status(500).json({
|
|
433
|
+
statusCode: 500,
|
|
434
|
+
message: error.message,
|
|
435
|
+
timestamp: new Date().toISOString(),
|
|
436
|
+
path: context.request.url,
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Use globally
|
|
442
|
+
app.useGlobalExceptionFilter(new HttpExceptionFilter());
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
## Testing
|
|
446
|
+
|
|
447
|
+
```typescript
|
|
448
|
+
import { TestingModule } from '@hazeljs/core';
|
|
449
|
+
import { UserController } from './user.controller';
|
|
450
|
+
import { UserService } from './user.service';
|
|
451
|
+
|
|
452
|
+
describe('UserController', () => {
|
|
453
|
+
let module: TestingModule;
|
|
454
|
+
let controller: UserController;
|
|
455
|
+
let service: UserService;
|
|
456
|
+
|
|
457
|
+
beforeEach(async () => {
|
|
458
|
+
module = await TestingModule.create({
|
|
459
|
+
controllers: [UserController],
|
|
460
|
+
providers: [
|
|
461
|
+
{
|
|
462
|
+
provide: UserService,
|
|
463
|
+
useValue: {
|
|
464
|
+
findAll: jest.fn().mockResolvedValue([]),
|
|
465
|
+
},
|
|
466
|
+
},
|
|
467
|
+
],
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
controller = module.get(UserController);
|
|
471
|
+
service = module.get(UserService);
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
afterEach(async () => {
|
|
475
|
+
await module.close();
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
it('should return all users', async () => {
|
|
479
|
+
const result = await controller.findAll();
|
|
480
|
+
expect(result).toEqual([]);
|
|
481
|
+
expect(service.findAll).toHaveBeenCalled();
|
|
482
|
+
});
|
|
483
|
+
});
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
## API Reference
|
|
487
|
+
|
|
488
|
+
### Decorators
|
|
489
|
+
|
|
490
|
+
- `@HazelModule(options)` - Define a module
|
|
491
|
+
- `@Controller(path)` - Define a controller
|
|
492
|
+
- `@Injectable(options?)` - Mark class as injectable
|
|
493
|
+
- `@Get(path?)`, `@Post(path?)`, `@Put(path?)`, `@Delete(path?)`, `@Patch(path?)` - HTTP methods
|
|
494
|
+
- `@Param(name)`, `@Query(name)`, `@Body()`, `@Headers(name)` - Parameter extraction
|
|
495
|
+
- `@UseMiddleware(middleware)` - Apply middleware
|
|
496
|
+
- `@UseGuard(guard)` - Apply guard
|
|
497
|
+
- `@UseInterceptor(interceptor)` - Apply interceptor
|
|
498
|
+
|
|
499
|
+
### Classes
|
|
500
|
+
|
|
501
|
+
- `HazelApp` - Main application class
|
|
502
|
+
- `TestingModule` - Testing utilities
|
|
503
|
+
- `Logger` - Logging service
|
|
504
|
+
|
|
505
|
+
## Examples
|
|
506
|
+
|
|
507
|
+
See the [examples](../../example) directory for complete working examples.
|
|
508
|
+
|
|
509
|
+
## Contributing
|
|
510
|
+
|
|
511
|
+
Contributions are welcome! Please read our [Contributing Guide](../../CONTRIBUTING.md) for details.
|
|
512
|
+
|
|
513
|
+
## License
|
|
514
|
+
|
|
515
|
+
MIT © [HazelJS](https://hazeljs.com)
|
|
516
|
+
|
|
517
|
+
## Links
|
|
518
|
+
|
|
519
|
+
- [Documentation](https://hazeljs.com/docs)
|
|
520
|
+
- [GitHub](https://github.com/hazel-js/hazeljs)
|
|
521
|
+
- [Issues](https://github.com/hazeljs/hazel-js/issues)
|
|
522
|
+
- [Discord](https://discord.gg/hazeljs)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/container.test.ts"],"names":[],"mappings":"AACA,OAAO,kBAAkB,CAAC"}
|