@rolandsall24/nest-mediator 0.0.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.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +655 -0
  3. package/dist/index.d.ts +5 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +8 -0
  6. package/dist/lib/decorators/command-handler.decorator.d.ts +19 -0
  7. package/dist/lib/decorators/command-handler.decorator.d.ts.map +1 -0
  8. package/dist/lib/decorators/command-handler.decorator.js +20 -0
  9. package/dist/lib/decorators/index.d.ts +3 -0
  10. package/dist/lib/decorators/index.d.ts.map +1 -0
  11. package/dist/lib/decorators/index.js +2 -0
  12. package/dist/lib/decorators/query-handler.decorator.d.ts +19 -0
  13. package/dist/lib/decorators/query-handler.decorator.d.ts.map +1 -0
  14. package/dist/lib/decorators/query-handler.decorator.js +20 -0
  15. package/dist/lib/interfaces/command-handler.interface.d.ts +14 -0
  16. package/dist/lib/interfaces/command-handler.interface.d.ts.map +1 -0
  17. package/dist/lib/interfaces/command-handler.interface.js +1 -0
  18. package/dist/lib/interfaces/command.interface.d.ts +7 -0
  19. package/dist/lib/interfaces/command.interface.d.ts.map +1 -0
  20. package/dist/lib/interfaces/command.interface.js +1 -0
  21. package/dist/lib/interfaces/index.d.ts +5 -0
  22. package/dist/lib/interfaces/index.d.ts.map +1 -0
  23. package/dist/lib/interfaces/index.js +4 -0
  24. package/dist/lib/interfaces/query-handler.interface.d.ts +15 -0
  25. package/dist/lib/interfaces/query-handler.interface.d.ts.map +1 -0
  26. package/dist/lib/interfaces/query-handler.interface.js +1 -0
  27. package/dist/lib/interfaces/query.interface.d.ts +7 -0
  28. package/dist/lib/interfaces/query.interface.d.ts.map +1 -0
  29. package/dist/lib/interfaces/query.interface.js +1 -0
  30. package/dist/lib/nest-mediator.d.ts +2 -0
  31. package/dist/lib/nest-mediator.d.ts.map +1 -0
  32. package/dist/lib/nest-mediator.js +3 -0
  33. package/dist/lib/nest-mediator.module.d.ts +21 -0
  34. package/dist/lib/nest-mediator.module.d.ts.map +1 -0
  35. package/dist/lib/nest-mediator.module.js +58 -0
  36. package/dist/lib/services/index.d.ts +2 -0
  37. package/dist/lib/services/index.d.ts.map +1 -0
  38. package/dist/lib/services/index.js +1 -0
  39. package/dist/lib/services/mediator.service.d.ts +34 -0
  40. package/dist/lib/services/mediator.service.d.ts.map +1 -0
  41. package/dist/lib/services/mediator.service.js +68 -0
  42. package/dist/tsconfig.lib.tsbuildinfo +1 -0
  43. package/package.json +56 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Roland Salloum
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,655 @@
1
+ # NestJS Mediator
2
+
3
+ A lightweight CQRS (Command Query Responsibility Segregation) mediator pattern implementation for NestJS applications.
4
+
5
+ ## Features
6
+
7
+ - Clean separation between Commands and Queries
8
+ - Type-safe handlers with TypeScript
9
+ - Decorator-based handler registration
10
+ - Automatic handler discovery and registration
11
+ - Built on top of NestJS dependency injection
12
+ - Zero runtime dependencies beyond NestJS
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @rolandsall24/nest-mediator
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ### 1. Import the Module
23
+
24
+ Import `NestMediatorModule` in your application module and register your handlers:
25
+
26
+ ```typescript
27
+ import { Module } from '@nestjs/common';
28
+ import { NestMediatorModule } from '@rolandsall24/nest-mediator';
29
+ import { CreateUserCommandHandler } from './handlers/create-user.handler';
30
+ import { GetUserQueryHandler } from './handlers/get-user-query.handler';
31
+
32
+ @Module({
33
+ imports: [
34
+ NestMediatorModule.forRoot({
35
+ handlers: [
36
+ CreateUserCommandHandler,
37
+ GetUserQueryHandler,
38
+ ],
39
+ }),
40
+ ],
41
+ providers: [
42
+ // IMPORTANT: You must also add handlers to the providers array
43
+ // so NestJS can inject their dependencies
44
+ CreateUserCommandHandler,
45
+ GetUserQueryHandler,
46
+ ],
47
+ })
48
+ export class AppModule {}
49
+ ```
50
+
51
+ **Important Note**: Handlers must be registered in **two places**:
52
+ 1. In `NestMediatorModule.forRoot()` - for mediator pattern registration
53
+ 2. In the module's `providers` array - for NestJS dependency injection
54
+
55
+ ## Usage
56
+
57
+ ### Commands
58
+
59
+ Commands are used for operations that change state (create, update, delete).
60
+
61
+ #### 1. Define a Command
62
+
63
+ ```typescript
64
+ import { ICommand } from '@rolandsall24/nest-mediator';
65
+
66
+ export class CreateUserCommand implements ICommand {
67
+ constructor(
68
+ public readonly email: string,
69
+ public readonly name: string,
70
+ public readonly age: number
71
+ ) {}
72
+ }
73
+ ```
74
+
75
+ #### 2. Create a Command Handler
76
+
77
+ ```typescript
78
+ import { Injectable } from '@nestjs/common';
79
+ import { CommandHandler, ICommandHandler } from '@rolandsall24/nest-mediator';
80
+ import { CreateUserCommand } from '../commands/create-user.command';
81
+
82
+ @Injectable()
83
+ @CommandHandler(CreateUserCommand)
84
+ export class CreateUserCommandHandler implements ICommandHandler<CreateUserCommand> {
85
+ constructor(
86
+ // Inject your services here
87
+ // private readonly userRepository: UserRepository,
88
+ ) {}
89
+
90
+ async execute(command: CreateUserCommand): Promise<void> {
91
+ // Business logic here
92
+ console.log(`Creating user: ${command.email}`);
93
+
94
+ // Example: Save to database
95
+ // await this.userRepository.save({
96
+ // email: command.email,
97
+ // name: command.name,
98
+ // age: command.age,
99
+ // });
100
+ }
101
+ }
102
+ ```
103
+
104
+ #### 3. Send a Command from Controller
105
+
106
+ ```typescript
107
+ import { Controller, Post, Body } from '@nestjs/common';
108
+ import { MediatorService } from '@rolandsall24/nest-mediator';
109
+ import { CreateUserCommand } from './commands/create-user.command';
110
+
111
+ @Controller('users')
112
+ export class UserController {
113
+ constructor(private readonly mediator: MediatorService) {}
114
+
115
+ @Post()
116
+ async create(@Body() body: { email: string; name: string; age: number }): Promise<void> {
117
+ const command = new CreateUserCommand(
118
+ body.email,
119
+ body.name,
120
+ body.age
121
+ );
122
+
123
+ await this.mediator.send(command);
124
+ }
125
+ }
126
+ ```
127
+
128
+ ### Queries
129
+
130
+ Queries are used for operations that read data without changing state.
131
+
132
+ #### 1. Define a Query
133
+
134
+ ```typescript
135
+ import { IQuery } from '@rolandsall24/nest-mediator';
136
+
137
+ export class GetUserByIdQuery implements IQuery {
138
+ constructor(public readonly userId: string) {}
139
+ }
140
+ ```
141
+
142
+ #### 2. Define a Query Result Type
143
+
144
+ ```typescript
145
+ export interface UserDto {
146
+ id: string;
147
+ email: string;
148
+ name: string;
149
+ age: number;
150
+ createdAt: Date;
151
+ }
152
+ ```
153
+
154
+ #### 3. Create a Query Handler
155
+
156
+ ```typescript
157
+ import { Injectable } from '@nestjs/common';
158
+ import { QueryHandler, IQueryHandler } from '@rolandsall24/nest-mediator';
159
+ import { GetUserByIdQuery } from '../queries/get-user-by-id.query';
160
+ import { UserDto } from '../dtos/user.dto';
161
+
162
+ @Injectable()
163
+ @QueryHandler(GetUserByIdQuery)
164
+ export class GetUserByIdQueryHandler implements IQueryHandler<GetUserByIdQuery, UserDto> {
165
+ constructor(
166
+ // Inject your services here
167
+ // private readonly userRepository: UserRepository,
168
+ ) {}
169
+
170
+ async execute(query: GetUserByIdQuery): Promise<UserDto> {
171
+ // Business logic here
172
+ console.log(`Fetching user with ID: ${query.userId}`);
173
+
174
+ // Example: Fetch from database
175
+ // const user = await this.userRepository.findById(query.userId);
176
+
177
+ // Return mock data for demonstration
178
+ return {
179
+ id: query.userId,
180
+ email: 'john.doe@example.com',
181
+ name: 'John Doe',
182
+ age: 30,
183
+ createdAt: new Date(),
184
+ };
185
+ }
186
+ }
187
+ ```
188
+
189
+ #### 4. Execute a Query from Controller
190
+
191
+ ```typescript
192
+ import { Controller, Get, Param } from '@nestjs/common';
193
+ import { MediatorService } from '@rolandsall24/nest-mediator';
194
+ import { GetUserByIdQuery } from './queries/get-user-by-id.query';
195
+ import { UserDto } from './dtos/user.dto';
196
+
197
+ @Controller('users')
198
+ export class UserController {
199
+ constructor(private readonly mediator: MediatorService) {}
200
+
201
+ @Get(':id')
202
+ async getById(@Param('id') id: string): Promise<UserDto> {
203
+ const query = new GetUserByIdQuery(id);
204
+ const user = await this.mediator.query<GetUserByIdQuery, UserDto>(query);
205
+ return user;
206
+ }
207
+ }
208
+ ```
209
+
210
+ ## Complete Example
211
+
212
+ Here's a complete example following Domain-Driven Design principles with proper separation of concerns:
213
+
214
+ ### Project Structure
215
+
216
+ ```
217
+ src/
218
+ ├── domain/
219
+ │ ├── entities/
220
+ │ │ ├── user.ts
221
+ │ │ └── index.ts
222
+ │ └── exceptions/
223
+ │ ├── domain.exception.ts
224
+ │ ├── user-not-found.exception.ts
225
+ │ └── index.ts
226
+ ├── application/
227
+ │ └── user/
228
+ │ ├── create-user.command.ts
229
+ │ ├── create-user.handler.ts
230
+ │ ├── get-user.query.ts
231
+ │ ├── get-user.handler.ts
232
+ │ └── user-persistor.port.ts
233
+ ├── infrastructure/
234
+ │ └── persistence/
235
+ │ └── user/
236
+ │ └── user-persistence.adapter.ts
237
+ ├── presentation/
238
+ │ └── user/
239
+ │ ├── create-user-api.request.ts
240
+ │ ├── user-api.response.ts
241
+ │ └── user.controller.ts
242
+ └── app.module.ts
243
+ ```
244
+
245
+ ### Domain Layer
246
+
247
+ #### domain/entities/user.ts
248
+
249
+ ```typescript
250
+ export class User {
251
+ constructor(
252
+ public readonly id: string,
253
+ public readonly email: string,
254
+ public readonly name: string,
255
+ public readonly age: number,
256
+ public readonly createdAt: Date
257
+ ) {}
258
+
259
+ static create(params: {
260
+ id: string;
261
+ email: string;
262
+ name: string;
263
+ age: number;
264
+ }): User {
265
+ const now = new Date();
266
+ return new User(
267
+ params.id,
268
+ params.email,
269
+ params.name,
270
+ params.age,
271
+ now
272
+ );
273
+ }
274
+ }
275
+ ```
276
+
277
+ #### domain/exceptions/domain.exception.ts
278
+
279
+ ```typescript
280
+ export class DomainException extends Error {
281
+ constructor(message: string) {
282
+ super(message);
283
+ this.name = this.constructor.name;
284
+ }
285
+ }
286
+ ```
287
+
288
+ #### domain/exceptions/user-not-found.exception.ts
289
+
290
+ ```typescript
291
+ import { DomainException } from './domain.exception';
292
+
293
+ export class UserNotFoundException extends DomainException {
294
+ constructor(userId: string) {
295
+ super(`User with id ${userId} not found`);
296
+ }
297
+ }
298
+ ```
299
+
300
+ ### Application Layer
301
+
302
+ #### application/user/create-user.command.ts
303
+
304
+ ```typescript
305
+ import { ICommand } from '@rolandsall24/nest-mediator';
306
+
307
+ export class CreateUserCommand implements ICommand {
308
+ constructor(
309
+ public readonly email: string,
310
+ public readonly name: string,
311
+ public readonly age: number
312
+ ) {}
313
+ }
314
+ ```
315
+
316
+ #### application/user/user-persistor.port.ts
317
+
318
+ ```typescript
319
+ import { User } from '../../domain/entities/user';
320
+
321
+ export interface UserPersistor {
322
+ save(user: User): Promise<User>;
323
+ findById(id: string): Promise<User | null>;
324
+ }
325
+
326
+ export const USER_PERSISTOR = Symbol('USER_PERSISTOR');
327
+ ```
328
+
329
+ #### application/user/create-user.handler.ts
330
+
331
+ ```typescript
332
+ import { Injectable, Inject } from '@nestjs/common';
333
+ import { CommandHandler, ICommandHandler } from '@rolandsall24/nest-mediator';
334
+ import { randomUUID } from 'crypto';
335
+ import { CreateUserCommand } from './create-user.command';
336
+ import { User } from '../../domain/entities/user';
337
+ import { UserPersistor, USER_PERSISTOR } from './user-persistor.port';
338
+
339
+ @Injectable()
340
+ @CommandHandler(CreateUserCommand)
341
+ export class CreateUserCommandHandler implements ICommandHandler<CreateUserCommand> {
342
+ constructor(
343
+ @Inject(USER_PERSISTOR)
344
+ private readonly userPersistor: UserPersistor
345
+ ) {}
346
+
347
+ async execute(command: CreateUserCommand): Promise<void> {
348
+ const id = randomUUID();
349
+
350
+ const user = User.create({
351
+ id,
352
+ email: command.email,
353
+ name: command.name,
354
+ age: command.age,
355
+ });
356
+
357
+ await this.userPersistor.save(user);
358
+ }
359
+ }
360
+ ```
361
+
362
+ #### application/user/get-user.query.ts
363
+
364
+ ```typescript
365
+ import { IQuery } from '@rolandsall24/nest-mediator';
366
+
367
+ export class GetUserQuery implements IQuery {
368
+ constructor(public readonly id: string) {}
369
+ }
370
+ ```
371
+
372
+ #### application/user/get-user.handler.ts
373
+
374
+ ```typescript
375
+ import { Injectable, Inject } from '@nestjs/common';
376
+ import { QueryHandler, IQueryHandler } from '@rolandsall24/nest-mediator';
377
+ import { GetUserQuery } from './get-user.query';
378
+ import { User } from '../../domain/entities/user';
379
+ import { UserNotFoundException } from '../../domain/exceptions/user-not-found.exception';
380
+ import { UserPersistor, USER_PERSISTOR } from './user-persistor.port';
381
+
382
+ @Injectable()
383
+ @QueryHandler(GetUserQuery)
384
+ export class GetUserQueryHandler implements IQueryHandler<GetUserQuery, User> {
385
+ constructor(
386
+ @Inject(USER_PERSISTOR)
387
+ private readonly userPersistor: UserPersistor
388
+ ) {}
389
+
390
+ async execute(query: GetUserQuery): Promise<User> {
391
+ const user = await this.userPersistor.findById(query.id);
392
+
393
+ if (!user) {
394
+ throw new UserNotFoundException(query.id);
395
+ }
396
+
397
+ return user;
398
+ }
399
+ }
400
+ ```
401
+
402
+ ### Infrastructure Layer
403
+
404
+ #### infrastructure/persistence/user/user-persistence.adapter.ts
405
+
406
+ ```typescript
407
+ import { Injectable } from '@nestjs/common';
408
+ import { UserPersistor } from '../../../application/user/user-persistor.port';
409
+ import { User } from '../../../domain/entities/user';
410
+
411
+ @Injectable()
412
+ export class UserPersistenceAdapter implements UserPersistor {
413
+ // In-memory storage for demonstration
414
+ private users: Map<string, User> = new Map();
415
+
416
+ async save(user: User): Promise<User> {
417
+ this.users.set(user.id, user);
418
+ return user;
419
+ }
420
+
421
+ async findById(id: string): Promise<User | null> {
422
+ return this.users.get(id) || null;
423
+ }
424
+ }
425
+ ```
426
+
427
+ ### Presentation Layer
428
+
429
+ #### presentation/user/create-user-api.request.ts
430
+
431
+ ```typescript
432
+ export class CreateUserApiRequest {
433
+ email: string;
434
+ name: string;
435
+ age: number;
436
+ }
437
+ ```
438
+
439
+ #### presentation/user/user-api.response.ts
440
+
441
+ ```typescript
442
+ export class UserApiResponse {
443
+ id: string;
444
+ email: string;
445
+ name: string;
446
+ age: number;
447
+ createdAt: Date;
448
+ }
449
+ ```
450
+
451
+ #### presentation/user/user.controller.ts
452
+
453
+ ```typescript
454
+ import { Controller, Post, Body, Get, Param } from '@nestjs/common';
455
+ import { MediatorService } from '@rolandsall24/nest-mediator';
456
+ import { CreateUserCommand } from '../../application/user/create-user.command';
457
+ import { GetUserQuery } from '../../application/user/get-user.query';
458
+ import { CreateUserApiRequest } from './create-user-api.request';
459
+ import { UserApiResponse } from './user-api.response';
460
+
461
+ @Controller('users')
462
+ export class UserController {
463
+ constructor(private readonly mediator: MediatorService) {}
464
+
465
+ @Post()
466
+ async create(@Body() request: CreateUserApiRequest): Promise<void> {
467
+ const command = new CreateUserCommand(
468
+ request.email,
469
+ request.name,
470
+ request.age
471
+ );
472
+
473
+ await this.mediator.send(command);
474
+ }
475
+
476
+ @Get(':id')
477
+ async getById(@Param('id') id: string): Promise<UserApiResponse> {
478
+ const query = new GetUserQuery(id);
479
+ const user = await this.mediator.query(query);
480
+
481
+ return {
482
+ id: user.id,
483
+ email: user.email,
484
+ name: user.name,
485
+ age: user.age,
486
+ createdAt: user.createdAt,
487
+ };
488
+ }
489
+ }
490
+ ```
491
+
492
+ ### Module Configuration
493
+
494
+ #### app.module.ts
495
+
496
+ ```typescript
497
+ import { Module } from '@nestjs/common';
498
+ import { NestMediatorModule } from '@rolandsall24/nest-mediator';
499
+ import { UserController } from './presentation/user/user.controller';
500
+ import { CreateUserCommandHandler } from './application/user/create-user.handler';
501
+ import { GetUserQueryHandler } from './application/user/get-user.handler';
502
+ import { USER_PERSISTOR } from './application/user/user-persistor.port';
503
+ import { UserPersistenceAdapter } from './infrastructure/persistence/user/user-persistence.adapter';
504
+
505
+ @Module({
506
+ imports: [
507
+ NestMediatorModule.forRoot({
508
+ handlers: [
509
+ CreateUserCommandHandler,
510
+ GetUserQueryHandler,
511
+ ],
512
+ }),
513
+ ],
514
+ controllers: [UserController],
515
+ providers: [
516
+ // Infrastructure
517
+ {
518
+ provide: USER_PERSISTOR,
519
+ useClass: UserPersistenceAdapter,
520
+ },
521
+ // IMPORTANT: Handlers must also be added here for dependency injection
522
+ CreateUserCommandHandler,
523
+ GetUserQueryHandler,
524
+ ],
525
+ })
526
+ export class AppModule {}
527
+ ```
528
+
529
+ ### Key Benefits
530
+
531
+ 1. **Domain Layer**: Pure business logic, framework-agnostic
532
+ - Entities contain business rules and invariants
533
+ - Domain exceptions represent business errors
534
+
535
+ 2. **Application Layer**: Use cases and business workflows
536
+ - Commands/Queries define application operations
537
+ - Handlers orchestrate domain objects and ports
538
+ - Ports (interfaces) define contracts for infrastructure
539
+
540
+ 3. **Infrastructure Layer**: Technical implementations
541
+ - Adapters implement port interfaces
542
+ - Database, external services, file systems, etc.
543
+
544
+ 4. **Presentation Layer**: API interface
545
+ - Controllers handle HTTP concerns
546
+ - DTOs for API request/response
547
+ - No business logic
548
+
549
+ This separation enables:
550
+ - Easy testing (mock ports/adapters)
551
+ - Technology independence (swap databases/frameworks)
552
+ - Clear boundaries and responsibilities
553
+ - Scalable architecture for growing applications
554
+
555
+ ## API Reference
556
+
557
+ ### Interfaces
558
+
559
+ #### `ICommand`
560
+
561
+ Marker interface for commands.
562
+
563
+ ```typescript
564
+ export interface ICommand {}
565
+ ```
566
+
567
+ #### `ICommandHandler<TCommand>`
568
+
569
+ Interface for command handlers.
570
+
571
+ ```typescript
572
+ export interface ICommandHandler<TCommand extends ICommand> {
573
+ execute(command: TCommand): Promise<void>;
574
+ }
575
+ ```
576
+
577
+ #### `IQuery`
578
+
579
+ Marker interface for queries.
580
+
581
+ ```typescript
582
+ export interface IQuery {}
583
+ ```
584
+
585
+ #### `IQueryHandler<TQuery, TResult>`
586
+
587
+ Interface for query handlers.
588
+
589
+ ```typescript
590
+ export interface IQueryHandler<TQuery extends IQuery, TResult = any> {
591
+ execute(query: TQuery): Promise<TResult>;
592
+ }
593
+ ```
594
+
595
+ ### Decorators
596
+
597
+ #### `@CommandHandler(command)`
598
+
599
+ Marks a class as a command handler.
600
+
601
+ - **Parameters**: `command` - The command class this handler handles
602
+ - **Usage**: Apply to handler classes that implement `ICommandHandler`
603
+
604
+ #### `@QueryHandler(query)`
605
+
606
+ Marks a class as a query handler.
607
+
608
+ - **Parameters**: `query` - The query class this handler handles
609
+ - **Usage**: Apply to handler classes that implement `IQueryHandler`
610
+
611
+ ### Services
612
+
613
+ #### `MediatorService`
614
+
615
+ The main service for sending commands and queries.
616
+
617
+ ##### Methods
618
+
619
+ **`send<TCommand>(command: TCommand): Promise<void>`**
620
+
621
+ Sends a command to its registered handler.
622
+
623
+ - **Parameters**: `command` - The command instance to execute
624
+ - **Returns**: Promise that resolves when the command is executed
625
+ - **Throws**: Error if no handler is registered for the command
626
+
627
+ **`query<TQuery, TResult>(query: TQuery): Promise<TResult>`**
628
+
629
+ Executes a query through its registered handler.
630
+
631
+ - **Parameters**: `query` - The query instance to execute
632
+ - **Returns**: Promise that resolves with the query result
633
+ - **Throws**: Error if no handler is registered for the query
634
+
635
+ ## Best Practices
636
+
637
+ 1. **Keep Commands and Queries Simple**: They should be simple data containers with minimal logic.
638
+
639
+ 2. **One Handler Per Command/Query**: Each command or query should have exactly one handler.
640
+
641
+ 3. **Use Dependency Injection**: Inject required services into your handlers through the constructor.
642
+
643
+ 4. **Type Safety**: Always specify the return type for queries using the generic parameters.
644
+
645
+ 5. **Error Handling**: Implement proper error handling in your handlers.
646
+
647
+ 6. **Validation**: Validate command/query data before creating instances or in the handler.
648
+
649
+ ## License
650
+
651
+ MIT
652
+
653
+ ## Contributing
654
+
655
+ Contributions are welcome! Please feel free to submit a Pull Request.
@@ -0,0 +1,5 @@
1
+ export * from './lib/interfaces/index.js';
2
+ export * from './lib/decorators/index.js';
3
+ export * from './lib/services/index.js';
4
+ export * from './lib/nest-mediator.module.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,2BAA2B,CAAC;AAG1C,cAAc,2BAA2B,CAAC;AAG1C,cAAc,yBAAyB,CAAC;AAGxC,cAAc,+BAA+B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ // Interfaces
2
+ export * from './lib/interfaces/index.js';
3
+ // Decorators
4
+ export * from './lib/decorators/index.js';
5
+ // Services
6
+ export * from './lib/services/index.js';
7
+ // Module
8
+ export * from './lib/nest-mediator.module.js';
@@ -0,0 +1,19 @@
1
+ import { ICommand } from '../interfaces/index.js';
2
+ export declare const COMMAND_HANDLER_METADATA = "COMMAND_HANDLER_METADATA";
3
+ /**
4
+ * Decorator to mark a class as a command handler
5
+ * @param command - The command class that this handler handles
6
+ * @returns Class decorator
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * @CommandHandler(AddCategoryCommand)
11
+ * export class AddCategoryCommandHandler implements ICommandHandler<AddCategoryCommand> {
12
+ * async execute(command: AddCategoryCommand): Promise<Category> {
13
+ * // Implementation
14
+ * }
15
+ * }
16
+ * ```
17
+ */
18
+ export declare const CommandHandler: (command: new (...args: any[]) => ICommand) => ClassDecorator;
19
+ //# sourceMappingURL=command-handler.decorator.d.ts.map