fragment-ts 1.0.30 → 1.0.32

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 (52) hide show
  1. package/API.md +752 -0
  2. package/DOCS.md +555 -0
  3. package/README.md +76 -339
  4. package/USAGE.md +309 -1306
  5. package/dist/cli/commands/init.command.js +1 -1
  6. package/dist/core/container/di-container.d.ts.map +1 -1
  7. package/dist/core/container/di-container.js +62 -106
  8. package/dist/core/container/di-container.js.map +1 -1
  9. package/dist/core/decorators/exception-filter.decorator.d.ts +5 -0
  10. package/dist/core/decorators/exception-filter.decorator.d.ts.map +1 -0
  11. package/dist/core/decorators/exception-filter.decorator.js +23 -0
  12. package/dist/core/decorators/exception-filter.decorator.js.map +1 -0
  13. package/dist/core/decorators/guard.decorator.d.ts +5 -0
  14. package/dist/core/decorators/guard.decorator.d.ts.map +1 -0
  15. package/dist/core/decorators/guard.decorator.js +23 -0
  16. package/dist/core/decorators/guard.decorator.js.map +1 -0
  17. package/dist/core/decorators/injection.decorators.d.ts.map +1 -1
  18. package/dist/core/decorators/injection.decorators.js +5 -0
  19. package/dist/core/decorators/injection.decorators.js.map +1 -1
  20. package/dist/core/decorators/interceptor.decorator.d.ts +5 -0
  21. package/dist/core/decorators/interceptor.decorator.d.ts.map +1 -0
  22. package/dist/core/decorators/interceptor.decorator.js +23 -0
  23. package/dist/core/decorators/interceptor.decorator.js.map +1 -0
  24. package/dist/core/decorators/middleware.decorator.d.ts +8 -0
  25. package/dist/core/decorators/middleware.decorator.d.ts.map +1 -0
  26. package/dist/core/decorators/middleware.decorator.js +28 -0
  27. package/dist/core/decorators/middleware.decorator.js.map +1 -0
  28. package/dist/core/metadata/metadata-keys.d.ts +1 -0
  29. package/dist/core/metadata/metadata-keys.d.ts.map +1 -1
  30. package/dist/core/metadata/metadata-keys.js +1 -0
  31. package/dist/core/metadata/metadata-keys.js.map +1 -1
  32. package/dist/core/metadata/metadata-storage.d.ts +20 -4
  33. package/dist/core/metadata/metadata-storage.d.ts.map +1 -1
  34. package/dist/core/metadata/metadata-storage.js +94 -14
  35. package/dist/core/metadata/metadata-storage.js.map +1 -1
  36. package/dist/web/application.d.ts.map +1 -1
  37. package/dist/web/application.js +79 -10
  38. package/dist/web/application.js.map +1 -1
  39. package/dist/web/interfaces.d.ts +5 -1
  40. package/dist/web/interfaces.d.ts.map +1 -1
  41. package/package.json +1 -1
  42. package/src/cli/commands/init.command.ts +1 -1
  43. package/src/core/container/di-container.ts +95 -177
  44. package/src/core/decorators/exception-filter.decorator.ts +20 -0
  45. package/src/core/decorators/guard.decorator.ts +20 -0
  46. package/src/core/decorators/injection.decorators.ts +5 -0
  47. package/src/core/decorators/interceptor.decorator.ts +20 -0
  48. package/src/core/decorators/middleware.decorator.ts +25 -0
  49. package/src/core/metadata/metadata-keys.ts +1 -0
  50. package/src/core/metadata/metadata-storage.ts +128 -24
  51. package/src/web/application.ts +207 -53
  52. package/src/web/interfaces.ts +11 -2
package/DOCS.md ADDED
@@ -0,0 +1,555 @@
1
+
2
+ # In-Depth Documentation
3
+
4
+ ## Architecture Overview
5
+
6
+ Fragment TS follows a component-based architecture with dependency injection at its core. The framework is designed around several key principles:
7
+
8
+ 1. **Inversion of Control (IoC)**: Components declare their dependencies rather than creating them directly
9
+ 2. **Separation of Concerns**: Clear separation between controllers, services, and repositories
10
+ 3. **Convention over Configuration**: Automatic component scanning and registration
11
+ 4. **Type Safety**: Leveraging TypeScript's type system for compile-time validation
12
+
13
+ ![Architecture Diagram](https://example.com/fragment-architecture.png)
14
+
15
+ ### Core Components
16
+
17
+ 1. **DI Container**: Manages the lifecycle and dependencies of all components
18
+ 2. **Metadata Storage**: Stores decorator metadata for runtime processing
19
+ 3. **Component Scanner**: Discovers and registers components automatically
20
+ 4. **Web Application**: Configures and starts the Express server
21
+ 5. **TypeORM Module**: Integrates TypeORM for database operations
22
+
23
+ ## Dependency Injection System
24
+
25
+ ### How It Works
26
+
27
+ The dependency injection system in Fragment TS works through a combination of decorators, TypeScript metadata, and reflection:
28
+
29
+ 1. **Decorator Metadata Collection**:
30
+ - Class decorators (`@Service()`, `@Controller()`, etc.) register components with the metadata storage
31
+ - Property decorators (`@Autowired()`, `@InjectRepository()`, etc.) store metadata about dependencies
32
+ - Method and parameter decorators store route and handler information
33
+
34
+ 2. **Component Registration**:
35
+ - During application bootstrap, the component scanner loads all relevant files
36
+ - The metadata storage is populated with component definitions
37
+ - Components are registered with the DI container
38
+
39
+ 3. **Dependency Resolution**:
40
+ - When a component is requested, the container creates an instance
41
+ - Constructor parameters are resolved recursively
42
+ - Property dependencies are injected based on metadata
43
+ - Post-construction hooks are called
44
+
45
+ ### Scopes
46
+
47
+ Fragment TS supports three scopes for components:
48
+
49
+ 1. **Singleton (default)**: One instance per application
50
+ 2. **Request**: One instance per HTTP request
51
+ 3. **Transient**: New instance every time it's requested
52
+
53
+ ```typescript
54
+ @Injectable('singleton')
55
+ class DatabaseConnection {}
56
+
57
+ @Injectable('request')
58
+ class RequestContext {}
59
+
60
+ @Injectable('transient')
61
+ class RandomGenerator {}
62
+ ```
63
+
64
+ ### Circular Dependencies
65
+
66
+ The framework detects circular dependencies during component resolution and throws meaningful errors:
67
+
68
+ ```typescript
69
+ @Service()
70
+ class ServiceA {
71
+ @Autowired()
72
+ private serviceB!: ServiceB;
73
+ }
74
+
75
+ @Service()
76
+ class ServiceB {
77
+ @Autowired()
78
+ private serviceA!: ServiceA; // This will cause a circular dependency error
79
+ }
80
+ ```
81
+
82
+ ## Component Lifecycle
83
+
84
+ Fragment TS components follow a well-defined lifecycle:
85
+
86
+ 1. **Registration**: Component is registered with the container
87
+ 2. **Instantiation**: Container creates a new instance
88
+ 3. **Dependency Injection**: Dependencies are injected via constructor and properties
89
+ 4. **Post-Construction**: `@PostConstruct` methods are called
90
+ 5. **Usage**: Component is ready for use
91
+ 6. **Destruction**: `@PreDestroy` methods are called before garbage collection
92
+
93
+ ```typescript
94
+ @Service()
95
+ class LifecycleService {
96
+ constructor() {
97
+ console.log('Constructor called');
98
+ }
99
+
100
+ @PostConstruct()
101
+ init() {
102
+ console.log('Post-construct called - dependencies are available');
103
+ }
104
+
105
+ @PreDestroy()
106
+ cleanup() {
107
+ console.log('Pre-destroy called - cleanup resources');
108
+ }
109
+ }
110
+ ```
111
+
112
+ ## Web Layer
113
+
114
+ ### Request Processing Pipeline
115
+
116
+ 1. **Route Registration**:
117
+ - Controllers and routes are registered during application bootstrap
118
+ - Route metadata is stored in the metadata storage
119
+
120
+ 2. **Request Handling**:
121
+ - Express middleware processes the incoming request
122
+ - Route handler is matched based on path and HTTP method
123
+ - Controller instance is retrieved from the container
124
+ - Route parameters are resolved and injected
125
+ - Handler method is invoked
126
+
127
+ 3. **Response Processing**:
128
+ - Return value is automatically converted to JSON
129
+ - Error handling middleware processes any exceptions
130
+
131
+ ### Middleware Integration
132
+
133
+ Fragment TS integrates with Express middleware through the underlying Express application:
134
+
135
+ ```typescript
136
+ const app = new FragmentWebApplication();
137
+ const expressApp = app.getExpressApp();
138
+
139
+ // Add custom middleware
140
+ expressApp.use('/api', apiMiddleware);
141
+ expressApp.use(errorHandler);
142
+ ```
143
+
144
+ ## Database Integration
145
+
146
+ ### TypeORM Configuration
147
+
148
+ TypeORM is configured via a JSON file (default: `fragment.json`):
149
+
150
+ ```json
151
+ {
152
+ "type": "mysql",
153
+ "host": "localhost",
154
+ "port": 3306,
155
+ "username": "root",
156
+ "password": "password",
157
+ "database": "my_db",
158
+ "entities": ["dist/entities/**/*.js"],
159
+ "synchronize": true,
160
+ "logging": false
161
+ }
162
+ ```
163
+
164
+ ### Repository Pattern
165
+
166
+ Fragment TS encourages the repository pattern for data access:
167
+
168
+ ```typescript
169
+ // Entity
170
+ @Entity()
171
+ export class User {
172
+ @PrimaryGeneratedColumn()
173
+ id: number;
174
+
175
+ @Column()
176
+ name: string;
177
+
178
+ @Column()
179
+ email: string;
180
+ }
181
+
182
+ // Repository interface
183
+ export interface UserRepository {
184
+ findAll(): Promise<User[]>;
185
+ findById(id: number): Promise<User | null>;
186
+ save(user: User): Promise<User>;
187
+ }
188
+
189
+ // Fragment repository implementation
190
+ @Repository()
191
+ export class TypeOrmUserRepository implements UserRepository {
192
+ @InjectRepository(User)
193
+ private repo!: Repository<User>;
194
+
195
+ async findAll(): Promise<User[]> {
196
+ return this.repo.find();
197
+ }
198
+
199
+ async findById(id: number): Promise<User | null> {
200
+ return this.repo.findOneBy({ id });
201
+ }
202
+
203
+ async save(user: User): Promise<User> {
204
+ return this.repo.save(user);
205
+ }
206
+ }
207
+ ```
208
+
209
+ ## Advanced Features
210
+
211
+ ### Conditional Components
212
+
213
+ Components can be conditionally registered based on environment, class availability, or existing beans:
214
+
215
+ ```typescript
216
+ // Only register if Redis class is available
217
+ @AutoConfiguration()
218
+ @ConditionalOnClass(Redis)
219
+ class RedisConfiguration {}
220
+
221
+ // Only register if no other logger is available
222
+ @Service()
223
+ @ConditionalOnMissingBean(LoggerService)
224
+ class DefaultLoggerService implements LoggerService {}
225
+
226
+ // Only register if environment variable is set
227
+ @Service()
228
+ @ConditionalOnProperty('ENABLE_CACHE', 'true')
229
+ class CacheService {}
230
+ ```
231
+
232
+ ### Configuration Properties
233
+
234
+ Application configuration can be injected from environment variables or config files:
235
+
236
+ ```typescript
237
+ @Service()
238
+ class AppConfig {
239
+ @Value('${PORT:3000}')
240
+ port!: number;
241
+
242
+ @Value('${DATABASE_URL}')
243
+ databaseUrl!: string;
244
+
245
+ @Value('${FEATURE_FLAG_NEW_UI:false}')
246
+ featureFlagNewUi!: boolean;
247
+ }
248
+ ```
249
+
250
+ ### Testing Support
251
+
252
+ Fragment TS is designed for testability with minimal dependencies on framework internals:
253
+
254
+ ```typescript
255
+ // Unit test example
256
+ describe('UserService', () => {
257
+ let userService: UserService;
258
+ let mockUserRepository: jest.Mocked<UserRepository>;
259
+
260
+ beforeEach(() => {
261
+ mockUserRepository = {
262
+ findAll: jest.fn(),
263
+ findById: jest.fn()
264
+ } as any;
265
+
266
+ userService = new UserService();
267
+ Object.defineProperty(userService, 'userRepository', {
268
+ value: mockUserRepository
269
+ });
270
+ });
271
+
272
+ it('should return all users', async () => {
273
+ const mockUsers = [{ id: 1, name: 'John' }];
274
+ mockUserRepository.findAll.mockResolvedValue(mockUsers);
275
+
276
+ const result = await userService.findAll();
277
+
278
+ expect(result).toEqual(mockUsers);
279
+ expect(mockUserRepository.findAll).toHaveBeenCalled();
280
+ });
281
+ });
282
+ ```
283
+
284
+ ## Performance Considerations
285
+
286
+ ### Startup Time
287
+
288
+ Component scanning and dependency resolution happen during application startup. For large applications:
289
+
290
+ - Use conditional components to limit unnecessary registrations
291
+ - Consider lazy loading for heavy dependencies
292
+ - Split application into modules if necessary
293
+
294
+ ### Memory Usage
295
+
296
+ - Singleton-scoped components are held in memory for the application lifetime
297
+ - Request-scoped components are created per request and should be lightweight
298
+ - Transient components are created on-demand and not cached
299
+
300
+ ### Optimization Techniques
301
+
302
+ 1. **Lazy Loading**:
303
+ ```typescript
304
+ @Service()
305
+ class HeavyService {
306
+ @Lazy()
307
+ @Autowired()
308
+ private resourceIntensiveService!: ResourceIntensiveService;
309
+ }
310
+ ```
311
+
312
+ 2. **Selective Component Scanning**:
313
+ ```typescript
314
+ @FragmentApplication({
315
+ autoScan: false // Disable automatic scanning
316
+ })
317
+ class Application {}
318
+
319
+ // Manually register components
320
+ const container = DIContainer.getInstance();
321
+ container.register(UserService);
322
+ container.register(UserController);
323
+ ```
324
+
325
+ 3. **Production Build**:
326
+ - Always use compiled JavaScript in production
327
+ - Enable tree-shaking and minification
328
+ - Use environment variables for configuration instead of config files when possible
329
+
330
+ ## Error Handling
331
+
332
+ ### Global Error Handling
333
+
334
+ Fragment TS provides a global error handler that catches unhandled exceptions:
335
+
336
+ ```typescript
337
+ const app = new FragmentWebApplication();
338
+
339
+ // Custom error handler
340
+ class CustomErrorHandler {
341
+ @PostConstruct()
342
+ register() {
343
+ const expressApp = app.getExpressApp();
344
+ expressApp.use((err: Error, req: Request, res: Response, next: NextFunction) => {
345
+ console.error('Global error:', err);
346
+ res.status(500).json({
347
+ error: 'Internal Server Error',
348
+ message: process.env.NODE_ENV === 'development' ? err.message : undefined
349
+ });
350
+ });
351
+ }
352
+ }
353
+ ```
354
+
355
+ ### Custom Error Types
356
+
357
+ Define custom error types for better error handling:
358
+
359
+ ```typescript
360
+ export class NotFoundError extends Error {
361
+ constructor(message: string) {
362
+ super(message);
363
+ this.name = 'NotFoundError';
364
+ }
365
+ }
366
+
367
+ export class ValidationError extends Error {
368
+ constructor(public errors: any[]) {
369
+ super('Validation failed');
370
+ this.name = 'ValidationError';
371
+ }
372
+ }
373
+ ```
374
+
375
+ ## Extensibility
376
+
377
+ ### Custom Decorators
378
+
379
+ Create custom decorators by leveraging the metadata storage:
380
+
381
+ ```typescript
382
+ function CustomDecorator(metadata: any): MethodDecorator {
383
+ return (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
384
+ const storage = MetadataStorage.getInstance();
385
+ storage.addCustomMetadata(target.constructor, propertyKey, metadata);
386
+ };
387
+ }
388
+
389
+ // Usage
390
+ class MyController {
391
+ @CustomDecorator({ role: 'admin' })
392
+ adminMethod() {}
393
+ }
394
+ ```
395
+
396
+ ### Custom Modules
397
+
398
+ Extend the framework with custom modules:
399
+
400
+ ```typescript
401
+ class CustomModule {
402
+ static async initialize() {
403
+ // Custom initialization logic
404
+ console.log('Custom module initialized');
405
+ }
406
+
407
+ static getDependency() {
408
+ // Return dependency for injection
409
+ return new CustomDependency();
410
+ }
411
+ }
412
+
413
+ // Register with application
414
+ @FragmentApplication()
415
+ class Application {
416
+ constructor() {
417
+ CustomModule.initialize();
418
+ }
419
+ }
420
+ ```
421
+
422
+ ## Best Practices
423
+
424
+ ### Component Design
425
+
426
+ 1. **Single Responsibility**: Each component should have one clear responsibility
427
+ 2. **Loose Coupling**: Depend on abstractions (interfaces) rather than concrete implementations
428
+ 3. **High Cohesion**: Related functionality should be grouped together
429
+
430
+ ### Code Organization
431
+
432
+ 1. **Feature-based Structure**:
433
+ ```
434
+ src/
435
+ ├── features/
436
+ │ ├── user/
437
+ │ │ ├── user.controller.ts
438
+ │ │ ├── user.service.ts
439
+ │ │ ├── user.repository.ts
440
+ │ │ ├── user.entity.ts
441
+ │ │ └── index.ts
442
+ │ └── product/
443
+ │ ├── product.controller.ts
444
+ │ └── ...
445
+ ```
446
+
447
+ 2. **Layer-based Structure**:
448
+ ```
449
+ src/
450
+ ├── controllers/
451
+ ├── services/
452
+ ├── repositories/
453
+ ├── entities/
454
+ └── dtos/
455
+ ```
456
+
457
+ ### Testing Strategy
458
+
459
+ 1. **Unit Tests**: Test individual components in isolation
460
+ 2. **Integration Tests**: Test component interactions
461
+ 3. **End-to-End Tests**: Test full request/response cycle
462
+
463
+ ## Migration Guide
464
+
465
+ ### From Express
466
+
467
+ 1. Create a Fragment application class:
468
+ ```typescript
469
+ @FragmentApplication()
470
+ class Application {}
471
+ ```
472
+
473
+ 2. Convert Express routes to controllers:
474
+ ```typescript
475
+ // Before (Express)
476
+ app.get('/users', (req, res) => {
477
+ // handler
478
+ });
479
+
480
+ // After (Fragment)
481
+ @Controller('/users')
482
+ class UserController {
483
+ @Get()
484
+ findAll() {
485
+ // handler
486
+ }
487
+ }
488
+ ```
489
+
490
+ 3. Extract business logic to services:
491
+ ```typescript
492
+ // Before
493
+ app.post('/users', async (req, res) => {
494
+ const user = await db.users.create(req.body);
495
+ res.json(user);
496
+ });
497
+
498
+ // After
499
+ @Service()
500
+ class UserService {
501
+ @Autowired()
502
+ private userRepository!: UserRepository;
503
+
504
+ async create(userData: any) {
505
+ return this.userRepository.save(userData);
506
+ }
507
+ }
508
+
509
+ @Controller('/users')
510
+ class UserController {
511
+ @Autowired()
512
+ private userService!: UserService;
513
+
514
+ @Post()
515
+ async create(@Body() userData: any) {
516
+ return this.userService.create(userData);
517
+ }
518
+ }
519
+ ```
520
+
521
+ ### From NestJS
522
+
523
+ Fragment TS shares many concepts with NestJS:
524
+
525
+ 1. **Dependency Injection**: Similar `@Injectable()`, `@Autowired()` patterns
526
+ 2. **Controllers and Services**: Nearly identical structure
527
+ 3. **TypeORM Integration**: Similar repository patterns
528
+
529
+ Key differences:
530
+ - Fragment TS uses property injection by default instead of constructor injection
531
+ - Simpler configuration with less boilerplate
532
+ - More lightweight with fewer dependencies
533
+
534
+ ## Roadmap
535
+
536
+ ### Planned Features
537
+
538
+ 1. **Request-scoped Components**: Full support for request-scoped dependencies
539
+ 2. **Validation Pipelines**: Built-in validation decorators
540
+ 3. **Swagger Integration**: Automatic API documentation
541
+ 4. **WebSockets Support**: Real-time communication capabilities
542
+ 5. **CLI Tooling**: Project generation and management commands
543
+
544
+ ### Community Contributions
545
+
546
+ Fragment TS welcomes community contributions:
547
+
548
+ 1. **Bug Reports**: Report issues with reproduction steps
549
+ 2. **Feature Requests**: Suggest new features and improvements
550
+ 3. **Pull Requests**: Contribute code following the contribution guidelines
551
+ 4. **Documentation**: Improve documentation and examples
552
+
553
+ ## License
554
+
555
+ Fragment TS is released under the MIT License. See [LICENSE](LICENSE) for details.