@rolandsall24/nest-mediator 0.5.1 → 0.6.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.
- package/README.md +262 -20
- package/dist/lib/decorators/pipeline-behavior.decorator.d.ts +49 -0
- package/dist/lib/decorators/pipeline-behavior.decorator.d.ts.map +1 -1
- package/dist/lib/decorators/pipeline-behavior.decorator.js +56 -1
- package/dist/lib/decorators/pipeline-behavior.decorator.js.map +1 -1
- package/dist/lib/nest-mediator.module.d.ts +1 -13
- package/dist/lib/nest-mediator.module.d.ts.map +1 -1
- package/dist/lib/nest-mediator.module.js +18 -10
- package/dist/lib/nest-mediator.module.js.map +1 -1
- package/dist/lib/services/mediator.bus.d.ts +2 -1
- package/dist/lib/services/mediator.bus.d.ts.map +1 -1
- package/dist/lib/services/mediator.bus.js +11 -5
- package/dist/lib/services/mediator.bus.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,8 @@ A lightweight CQRS (Command Query Responsibility Segregation) mediator pattern i
|
|
|
8
8
|
- Type-safe handlers with TypeScript
|
|
9
9
|
- Decorator-based handler registration
|
|
10
10
|
- Automatic handler discovery and registration
|
|
11
|
-
-
|
|
11
|
+
- Pipeline Behaviors for cross-cutting concerns (logging, validation, etc.)
|
|
12
|
+
- Type-Specific Behaviors - behaviors that only apply to specific request types (v0.6.0+)
|
|
12
13
|
- Built-in behaviors: Logging, Validation, Exception Handling, Performance Tracking
|
|
13
14
|
- Built on top of NestJS dependency injection
|
|
14
15
|
- Zero runtime dependencies beyond NestJS
|
|
@@ -32,6 +33,55 @@ This library requires TypeScript decorators to be enabled. Add the following to
|
|
|
32
33
|
}
|
|
33
34
|
```
|
|
34
35
|
|
|
36
|
+
## Upgrading to v0.6.0
|
|
37
|
+
|
|
38
|
+
Version 0.6.0 introduces **Type-Specific Pipeline Behaviors** - behaviors that only apply to specific request types.
|
|
39
|
+
|
|
40
|
+
### What's New
|
|
41
|
+
|
|
42
|
+
- New `@Handle()` decorator for the `handle` method to enable automatic request type inference
|
|
43
|
+
- Behaviors can target specific command/query types without manual `instanceof` checks
|
|
44
|
+
- Full backward compatibility - existing behaviors work unchanged
|
|
45
|
+
|
|
46
|
+
### Type-Specific Behavior Example
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { Injectable } from '@nestjs/common';
|
|
50
|
+
import { IPipelineBehavior, PipelineBehavior, Handle } from '@rolandsall24/nest-mediator';
|
|
51
|
+
import { CreateUserCommand } from './create-user.command';
|
|
52
|
+
|
|
53
|
+
@Injectable()
|
|
54
|
+
@PipelineBehavior({ priority: 100, scope: 'command' })
|
|
55
|
+
export class CreateUserValidationBehavior
|
|
56
|
+
implements IPipelineBehavior<CreateUserCommand, void>
|
|
57
|
+
{
|
|
58
|
+
@Handle() // <-- Enables type inference from method signature
|
|
59
|
+
async handle(
|
|
60
|
+
request: CreateUserCommand,
|
|
61
|
+
next: () => Promise<void>,
|
|
62
|
+
): Promise<void> {
|
|
63
|
+
// This behavior ONLY runs for CreateUserCommand
|
|
64
|
+
// No instanceof check needed!
|
|
65
|
+
if (!request.email.includes('@')) {
|
|
66
|
+
throw new Error('Invalid email');
|
|
67
|
+
}
|
|
68
|
+
return next();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### How It Works
|
|
74
|
+
|
|
75
|
+
1. Apply `@PipelineBehavior()` to the class and `@Handle()` to the `handle` method
|
|
76
|
+
2. TypeScript's `emitDecoratorMetadata` emits type information for the method parameters
|
|
77
|
+
3. The library reads this metadata at registration time and filters behaviors by request type
|
|
78
|
+
|
|
79
|
+
### No Migration Required
|
|
80
|
+
|
|
81
|
+
Existing behaviors without `@Handle()` on the method continue to work exactly as before - they apply to all requests matching their scope.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
35
85
|
## Upgrading to v0.5.0
|
|
36
86
|
|
|
37
87
|
Version 0.5.0 introduces **Pipeline Behaviors** while maintaining backward compatibility. Existing code using `NestMediatorModule.forRoot()` will continue to work without changes.
|
|
@@ -707,6 +757,38 @@ Marks a class as a pipeline behavior.
|
|
|
707
757
|
- `options.scope` - `'command'`, `'query'`, or `'all'` (default: `'all'`)
|
|
708
758
|
- **Usage**: Apply to behavior classes that implement `IPipelineBehavior`
|
|
709
759
|
|
|
760
|
+
#### `@Handle()`
|
|
761
|
+
|
|
762
|
+
Method decorator that enables automatic request type inference for pipeline behaviors.
|
|
763
|
+
|
|
764
|
+
- **Parameters**: None
|
|
765
|
+
- **Usage**: Apply to the `handle` method to make the behavior type-specific
|
|
766
|
+
|
|
767
|
+
```typescript
|
|
768
|
+
// Generic behavior - applies to ALL requests in scope
|
|
769
|
+
@Injectable()
|
|
770
|
+
@PipelineBehavior({ priority: 0 })
|
|
771
|
+
export class LoggingBehavior<TRequest, TResponse>
|
|
772
|
+
implements IPipelineBehavior<TRequest, TResponse> {
|
|
773
|
+
async handle(request: TRequest, next: () => Promise<TResponse>) {
|
|
774
|
+
// Runs for all requests
|
|
775
|
+
return next();
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
// Type-specific behavior - applies ONLY to CreateUserCommand
|
|
780
|
+
@Injectable()
|
|
781
|
+
@PipelineBehavior({ priority: 100, scope: 'command' })
|
|
782
|
+
export class CreateUserValidationBehavior
|
|
783
|
+
implements IPipelineBehavior<CreateUserCommand, void> {
|
|
784
|
+
@Handle() // <-- Enables type inference
|
|
785
|
+
async handle(request: CreateUserCommand, next: () => Promise<void>) {
|
|
786
|
+
// Only runs for CreateUserCommand
|
|
787
|
+
return next();
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
```
|
|
791
|
+
|
|
710
792
|
#### `@SkipBehavior(behavior | behaviors[])`
|
|
711
793
|
|
|
712
794
|
Excludes specific pipeline behaviors from a command or query.
|
|
@@ -758,7 +840,6 @@ Module registration with configuration options.
|
|
|
758
840
|
| `enableExceptionHandling` | boolean | false | Enable centralized exception logging |
|
|
759
841
|
| `enablePerformanceTracking` | boolean | false | Enable slow request warnings |
|
|
760
842
|
| `performanceThresholdMs` | number | 500 | Threshold for slow request warnings |
|
|
761
|
-
| `behaviors` | Type[] | [] | Additional custom behaviors to register |
|
|
762
843
|
|
|
763
844
|
## Pipeline Behaviors
|
|
764
845
|
|
|
@@ -839,28 +920,12 @@ export class MyCustomBehavior<TRequest, TResponse>
|
|
|
839
920
|
|
|
840
921
|
### Registering Custom Behaviors
|
|
841
922
|
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
```typescript
|
|
845
|
-
@Module({
|
|
846
|
-
imports: [
|
|
847
|
-
NestMediatorModule.forRoot({
|
|
848
|
-
behaviors: [MyCustomBehavior],
|
|
849
|
-
}),
|
|
850
|
-
],
|
|
851
|
-
providers: [
|
|
852
|
-
MyCustomBehavior, // Also add to providers for DI
|
|
853
|
-
],
|
|
854
|
-
})
|
|
855
|
-
export class AppModule {}
|
|
856
|
-
```
|
|
857
|
-
|
|
858
|
-
Or use the `@PipelineBehavior` decorator and add to providers - it will be auto-discovered:
|
|
923
|
+
Custom behaviors with the `@PipelineBehavior` decorator are auto-discovered. Just add them to your module's providers:
|
|
859
924
|
|
|
860
925
|
```typescript
|
|
861
926
|
@Module({
|
|
862
927
|
imports: [NestMediatorModule.forRoot()],
|
|
863
|
-
providers: [MyCustomBehavior], // Auto-discovered via decorator
|
|
928
|
+
providers: [MyCustomBehavior], // Auto-discovered via @PipelineBehavior decorator
|
|
864
929
|
})
|
|
865
930
|
export class AppModule {}
|
|
866
931
|
```
|
|
@@ -1061,6 +1126,65 @@ export class AuthorizationBehavior<TRequest, TResponse>
|
|
|
1061
1126
|
}
|
|
1062
1127
|
```
|
|
1063
1128
|
|
|
1129
|
+
### Type-Specific Behaviors
|
|
1130
|
+
|
|
1131
|
+
By default, behaviors apply to all requests matching their scope. To create a behavior that only applies to specific request types, add `@Handle()` to the `handle` method:
|
|
1132
|
+
|
|
1133
|
+
```typescript
|
|
1134
|
+
import { Injectable } from '@nestjs/common';
|
|
1135
|
+
import { IPipelineBehavior, PipelineBehavior, Handle } from '@rolandsall24/nest-mediator';
|
|
1136
|
+
import { CreateUserCommand } from './create-user.command';
|
|
1137
|
+
|
|
1138
|
+
@Injectable()
|
|
1139
|
+
@PipelineBehavior({ priority: 95, scope: 'command' })
|
|
1140
|
+
export class CreateUserValidationBehavior
|
|
1141
|
+
implements IPipelineBehavior<CreateUserCommand, void>
|
|
1142
|
+
{
|
|
1143
|
+
@Handle() // Enables type inference from method signature
|
|
1144
|
+
async handle(
|
|
1145
|
+
request: CreateUserCommand,
|
|
1146
|
+
next: () => Promise<void>,
|
|
1147
|
+
): Promise<void> {
|
|
1148
|
+
// This behavior ONLY runs for CreateUserCommand instances
|
|
1149
|
+
// No manual instanceof check needed!
|
|
1150
|
+
|
|
1151
|
+
const errors: string[] = [];
|
|
1152
|
+
|
|
1153
|
+
if (!request.name || request.name.length < 2) {
|
|
1154
|
+
errors.push('Name must be at least 2 characters');
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
if (!request.email || !request.email.includes('@')) {
|
|
1158
|
+
errors.push('Valid email is required');
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
if (errors.length > 0) {
|
|
1162
|
+
throw new Error(`Validation failed: ${errors.join(', ')}`);
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
return next();
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
```
|
|
1169
|
+
|
|
1170
|
+
**How it works:**
|
|
1171
|
+
|
|
1172
|
+
1. The `@Handle()` decorator on the `handle` method triggers TypeScript to emit `design:paramtypes` metadata
|
|
1173
|
+
2. At module initialization, the library reads this metadata to determine the request type (`CreateUserCommand`)
|
|
1174
|
+
3. During pipeline execution, the behavior is only included when `request instanceof CreateUserCommand` is true
|
|
1175
|
+
|
|
1176
|
+
**Requirements:**
|
|
1177
|
+
- TypeScript `emitDecoratorMetadata: true` must be enabled in tsconfig.json
|
|
1178
|
+
- The request parameter must be a concrete class (not an interface or `any`)
|
|
1179
|
+
|
|
1180
|
+
**Comparison:**
|
|
1181
|
+
|
|
1182
|
+
| Without `@Handle()` | With `@Handle()` |
|
|
1183
|
+
|---------------------|------------------|
|
|
1184
|
+
| Behavior runs for ALL commands | Behavior runs ONLY for specified type |
|
|
1185
|
+
| Must use `instanceof` check inside handler | No `instanceof` check needed |
|
|
1186
|
+
| Generic `<TRequest, TResponse>` | Specific type like `<CreateUserCommand, void>` |
|
|
1187
|
+
|
|
1064
1188
|
### Complete Behavior Execution Order Example
|
|
1065
1189
|
|
|
1066
1190
|
With the following behaviors configured:
|
|
@@ -1114,6 +1238,124 @@ export class CreateUserCommand implements ICommand {
|
|
|
1114
1238
|
// If validation fails, ValidationException is thrown with details
|
|
1115
1239
|
```
|
|
1116
1240
|
|
|
1241
|
+
### How `next()` Works in Pipeline Behaviors
|
|
1242
|
+
|
|
1243
|
+
The `next()` function is a delegate that invokes the next behavior in the pipeline (or the final handler). Here's how it works:
|
|
1244
|
+
|
|
1245
|
+
```
|
|
1246
|
+
┌─────────────────────────────────────────────────────────────────────────┐
|
|
1247
|
+
│ REQUEST FLOW (→) │
|
|
1248
|
+
│ │
|
|
1249
|
+
│ Request │
|
|
1250
|
+
│ │ │
|
|
1251
|
+
│ ▼ │
|
|
1252
|
+
│ ┌──────────────────────┐ │
|
|
1253
|
+
│ │ Behavior A │ 1. Pre-processing (before next()) │
|
|
1254
|
+
│ │ (priority: -100) │ - Wrap in try/catch │
|
|
1255
|
+
│ │ │ - Start timer │
|
|
1256
|
+
│ │ return next() ──────┼──► │
|
|
1257
|
+
│ └──────────────────────┘ │
|
|
1258
|
+
│ │ │
|
|
1259
|
+
│ ▼ │
|
|
1260
|
+
│ ┌──────────────────────┐ │
|
|
1261
|
+
│ │ Behavior B │ 2. Pre-processing │
|
|
1262
|
+
│ │ (priority: 0) │ - Log request │
|
|
1263
|
+
│ │ │ │
|
|
1264
|
+
│ │ return next() ──────┼──► │
|
|
1265
|
+
│ └──────────────────────┘ │
|
|
1266
|
+
│ │ │
|
|
1267
|
+
│ ▼ │
|
|
1268
|
+
│ ┌──────────────────────┐ │
|
|
1269
|
+
│ │ Behavior C │ │
|
|
1270
|
+
│ │ (priority: 100) │ │
|
|
1271
|
+
│ │ │ │
|
|
1272
|
+
│ │ return next() ──────┼──►
|
|
1273
|
+
│ └──────────────────────┘ │
|
|
1274
|
+
│ │
|
|
1275
|
+
│ │ │
|
|
1276
|
+
│ ▼ │
|
|
1277
|
+
│ ┌──────────────────────┐ │
|
|
1278
|
+
│ │ HANDLER │ │
|
|
1279
|
+
│ │ execute(request) │ │
|
|
1280
|
+
│ │ │ │
|
|
1281
|
+
│ │ return result ◄─────┼──┤
|
|
1282
|
+
│ └──────────────────────┘ │
|
|
1283
|
+
│ │
|
|
1284
|
+
└─────────────────────────────────────────────────────────────────────────┘
|
|
1285
|
+
|
|
1286
|
+
┌─────────────────────────────────────────────────────────────────────────┐
|
|
1287
|
+
│ RESPONSE FLOW (←) │
|
|
1288
|
+
│ │
|
|
1289
|
+
│ ┌──────────────────────┐ │
|
|
1290
|
+
│ │ Behavior A │ 4. Post-processing (after next() returns) │
|
|
1291
|
+
│ │ (priority: -100) │ - Catch errors │
|
|
1292
|
+
│ │ │ - Calculate duration │
|
|
1293
|
+
│ │ ◄── result ─────────┼── │
|
|
1294
|
+
│ └──────────────────────┘ │
|
|
1295
|
+
│ │ ▲ │
|
|
1296
|
+
│ ▼ │ │
|
|
1297
|
+
│ Response ┌──────────────────────┐ │
|
|
1298
|
+
│ │ Behavior B │ 3. Post-processing │
|
|
1299
|
+
│ │ (priority: 0) │ - Log response │
|
|
1300
|
+
│ │ │ - Log duration │
|
|
1301
|
+
│ │ ◄── result ─────────┼── │
|
|
1302
|
+
│ └──────────────────────┘ │
|
|
1303
|
+
│ ▲ │
|
|
1304
|
+
│ │ │
|
|
1305
|
+
│ ┌──────────────────────┐ │
|
|
1306
|
+
│ │ Behavior C │ │
|
|
1307
|
+
│ │ (priority: 100) │ │
|
|
1308
|
+
│ │ │ │
|
|
1309
|
+
│ │ ◄── result ─────────┼──┤
|
|
1310
|
+
│ └──────────────────────┘ │
|
|
1311
|
+
│ │
|
|
1312
|
+
└─────────────────────────────────────────────────────────────────────────┘
|
|
1313
|
+
```
|
|
1314
|
+
|
|
1315
|
+
**Code Example:**
|
|
1316
|
+
|
|
1317
|
+
```typescript
|
|
1318
|
+
@Injectable()
|
|
1319
|
+
@PipelineBehavior({ priority: 0 })
|
|
1320
|
+
export class LoggingBehavior<TRequest, TResponse>
|
|
1321
|
+
implements IPipelineBehavior<TRequest, TResponse>
|
|
1322
|
+
{
|
|
1323
|
+
async handle(
|
|
1324
|
+
request: TRequest,
|
|
1325
|
+
next: () => Promise<TResponse> // Delegate to next behavior/handler
|
|
1326
|
+
): Promise<TResponse> {
|
|
1327
|
+
// ═══════════════════════════════════════════
|
|
1328
|
+
// PRE-PROCESSING (runs BEFORE the handler)
|
|
1329
|
+
// ═══════════════════════════════════════════
|
|
1330
|
+
const start = Date.now();
|
|
1331
|
+
console.log(`→ Handling ${request.constructor.name}...`);
|
|
1332
|
+
|
|
1333
|
+
// ═══════════════════════════════════════════
|
|
1334
|
+
// CALL NEXT (invokes next behavior or handler)
|
|
1335
|
+
// ═══════════════════════════════════════════
|
|
1336
|
+
const response = await next();
|
|
1337
|
+
|
|
1338
|
+
// ═══════════════════════════════════════════
|
|
1339
|
+
// POST-PROCESSING (runs AFTER the handler)
|
|
1340
|
+
// ═══════════════════════════════════════════
|
|
1341
|
+
const duration = Date.now() - start;
|
|
1342
|
+
console.log(`← Handled ${request.constructor.name} in ${duration}ms`);
|
|
1343
|
+
|
|
1344
|
+
return response;
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
```
|
|
1348
|
+
|
|
1349
|
+
**Key Points:**
|
|
1350
|
+
|
|
1351
|
+
1. **`next()` is a function** that returns a `Promise` - you must `await` it
|
|
1352
|
+
2. **Code before `await next()`** runs during the request phase (pre-processing)
|
|
1353
|
+
3. **Code after `await next()`** runs during the response phase (post-processing)
|
|
1354
|
+
4. **Lower priority = outer wrapper** - executes first on request, last on response
|
|
1355
|
+
5. **Higher priority = inner wrapper** - executes last on request, first on response
|
|
1356
|
+
6. **If you don't call `next()`**, the handler never executes (useful for short-circuiting)
|
|
1357
|
+
7. **Exceptions propagate outward** through the `await next()` chain
|
|
1358
|
+
|
|
1117
1359
|
### Pipeline Execution Order
|
|
1118
1360
|
|
|
1119
1361
|
With behaviors at priorities -100, 0, 10, 100:
|
|
@@ -3,6 +3,11 @@ import { PipelineBehaviorOptions } from '../interfaces/pipeline-behavior.interfa
|
|
|
3
3
|
* Metadata key for pipeline behavior registration
|
|
4
4
|
*/
|
|
5
5
|
export declare const PIPELINE_BEHAVIOR_METADATA = "PIPELINE_BEHAVIOR_METADATA";
|
|
6
|
+
/**
|
|
7
|
+
* Metadata key to mark that the handle method has the decorator applied
|
|
8
|
+
* (used to trigger design:paramtypes emission for type inference)
|
|
9
|
+
*/
|
|
10
|
+
export declare const PIPELINE_BEHAVIOR_HANDLE_METADATA = "PIPELINE_BEHAVIOR_HANDLE_METADATA";
|
|
6
11
|
/**
|
|
7
12
|
* Decorator that marks a class as a pipeline behavior.
|
|
8
13
|
* Pipeline behaviors execute around request handlers, enabling cross-cutting concerns.
|
|
@@ -45,7 +50,51 @@ export declare const PIPELINE_BEHAVIOR_METADATA = "PIPELINE_BEHAVIOR_METADATA";
|
|
|
45
50
|
* return next();
|
|
46
51
|
* }
|
|
47
52
|
* }
|
|
53
|
+
*
|
|
54
|
+
* // Type-specific behavior - only applies to CreateUserCommand
|
|
55
|
+
* // Use @Handle() on the method to enable automatic type inference
|
|
56
|
+
* @Injectable()
|
|
57
|
+
* @PipelineBehavior({ priority: 100, scope: 'command' })
|
|
58
|
+
* export class CreateUserValidationBehavior implements IPipelineBehavior<CreateUserCommand, any> {
|
|
59
|
+
* @Handle() // Enables type inference from method signature
|
|
60
|
+
* async handle(request: CreateUserCommand, next: () => Promise<any>): Promise<any> {
|
|
61
|
+
* // This behavior only runs for CreateUserCommand - no instanceof check needed!
|
|
62
|
+
* await this.validate(request);
|
|
63
|
+
* return next();
|
|
64
|
+
* }
|
|
65
|
+
* }
|
|
48
66
|
* ```
|
|
49
67
|
*/
|
|
50
68
|
export declare const PipelineBehavior: (options?: PipelineBehaviorOptions) => ClassDecorator;
|
|
69
|
+
/**
|
|
70
|
+
* Method decorator that enables automatic request type inference for pipeline behaviors.
|
|
71
|
+
*
|
|
72
|
+
* When applied to the `handle` method of a pipeline behavior, TypeScript emits
|
|
73
|
+
* `design:paramtypes` metadata that the library reads to determine which request
|
|
74
|
+
* type the behavior should apply to.
|
|
75
|
+
*
|
|
76
|
+
* @returns Method decorator
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```typescript
|
|
80
|
+
* @Injectable()
|
|
81
|
+
* @PipelineBehavior({ priority: 100, scope: 'command' })
|
|
82
|
+
* export class CreateUserValidationBehavior
|
|
83
|
+
* implements IPipelineBehavior<CreateUserCommand, void>
|
|
84
|
+
* {
|
|
85
|
+
* @Handle() // Enables type inference - behavior only runs for CreateUserCommand
|
|
86
|
+
* async handle(
|
|
87
|
+
* request: CreateUserCommand,
|
|
88
|
+
* next: () => Promise<void>,
|
|
89
|
+
* ): Promise<void> {
|
|
90
|
+
* // No instanceof check needed - this only runs for CreateUserCommand
|
|
91
|
+
* if (!request.email.includes('@')) {
|
|
92
|
+
* throw new Error('Invalid email');
|
|
93
|
+
* }
|
|
94
|
+
* return next();
|
|
95
|
+
* }
|
|
96
|
+
* }
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
export declare const Handle: () => MethodDecorator;
|
|
51
100
|
//# sourceMappingURL=pipeline-behavior.decorator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline-behavior.decorator.d.ts","sourceRoot":"","sources":["../../../src/lib/decorators/pipeline-behavior.decorator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AAEvF;;GAEG;AACH,eAAO,MAAM,0BAA0B,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"pipeline-behavior.decorator.d.ts","sourceRoot":"","sources":["../../../src/lib/decorators/pipeline-behavior.decorator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AAEvF;;GAEG;AACH,eAAO,MAAM,0BAA0B,+BAA+B,CAAC;AAEvE;;;GAGG;AACH,eAAO,MAAM,iCAAiC,sCAAsC,CAAC;AAUrF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,eAAO,MAAM,gBAAgB,GAC3B,UAAU,uBAAuB,KAChC,cAMF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,MAAM,QAAO,eASzB,CAAC"}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PipelineBehavior = exports.PIPELINE_BEHAVIOR_METADATA = void 0;
|
|
3
|
+
exports.Handle = exports.PipelineBehavior = exports.PIPELINE_BEHAVIOR_HANDLE_METADATA = exports.PIPELINE_BEHAVIOR_METADATA = void 0;
|
|
4
4
|
const common_1 = require("@nestjs/common");
|
|
5
5
|
/**
|
|
6
6
|
* Metadata key for pipeline behavior registration
|
|
7
7
|
*/
|
|
8
8
|
exports.PIPELINE_BEHAVIOR_METADATA = 'PIPELINE_BEHAVIOR_METADATA';
|
|
9
|
+
/**
|
|
10
|
+
* Metadata key to mark that the handle method has the decorator applied
|
|
11
|
+
* (used to trigger design:paramtypes emission for type inference)
|
|
12
|
+
*/
|
|
13
|
+
exports.PIPELINE_BEHAVIOR_HANDLE_METADATA = 'PIPELINE_BEHAVIOR_HANDLE_METADATA';
|
|
9
14
|
/**
|
|
10
15
|
* Default options for pipeline behaviors
|
|
11
16
|
*/
|
|
@@ -55,6 +60,19 @@ const DEFAULT_OPTIONS = {
|
|
|
55
60
|
* return next();
|
|
56
61
|
* }
|
|
57
62
|
* }
|
|
63
|
+
*
|
|
64
|
+
* // Type-specific behavior - only applies to CreateUserCommand
|
|
65
|
+
* // Use @Handle() on the method to enable automatic type inference
|
|
66
|
+
* @Injectable()
|
|
67
|
+
* @PipelineBehavior({ priority: 100, scope: 'command' })
|
|
68
|
+
* export class CreateUserValidationBehavior implements IPipelineBehavior<CreateUserCommand, any> {
|
|
69
|
+
* @Handle() // Enables type inference from method signature
|
|
70
|
+
* async handle(request: CreateUserCommand, next: () => Promise<any>): Promise<any> {
|
|
71
|
+
* // This behavior only runs for CreateUserCommand - no instanceof check needed!
|
|
72
|
+
* await this.validate(request);
|
|
73
|
+
* return next();
|
|
74
|
+
* }
|
|
75
|
+
* }
|
|
58
76
|
* ```
|
|
59
77
|
*/
|
|
60
78
|
const PipelineBehavior = (options) => {
|
|
@@ -65,4 +83,41 @@ const PipelineBehavior = (options) => {
|
|
|
65
83
|
return (0, common_1.SetMetadata)(exports.PIPELINE_BEHAVIOR_METADATA, mergedOptions);
|
|
66
84
|
};
|
|
67
85
|
exports.PipelineBehavior = PipelineBehavior;
|
|
86
|
+
/**
|
|
87
|
+
* Method decorator that enables automatic request type inference for pipeline behaviors.
|
|
88
|
+
*
|
|
89
|
+
* When applied to the `handle` method of a pipeline behavior, TypeScript emits
|
|
90
|
+
* `design:paramtypes` metadata that the library reads to determine which request
|
|
91
|
+
* type the behavior should apply to.
|
|
92
|
+
*
|
|
93
|
+
* @returns Method decorator
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```typescript
|
|
97
|
+
* @Injectable()
|
|
98
|
+
* @PipelineBehavior({ priority: 100, scope: 'command' })
|
|
99
|
+
* export class CreateUserValidationBehavior
|
|
100
|
+
* implements IPipelineBehavior<CreateUserCommand, void>
|
|
101
|
+
* {
|
|
102
|
+
* @Handle() // Enables type inference - behavior only runs for CreateUserCommand
|
|
103
|
+
* async handle(
|
|
104
|
+
* request: CreateUserCommand,
|
|
105
|
+
* next: () => Promise<void>,
|
|
106
|
+
* ): Promise<void> {
|
|
107
|
+
* // No instanceof check needed - this only runs for CreateUserCommand
|
|
108
|
+
* if (!request.email.includes('@')) {
|
|
109
|
+
* throw new Error('Invalid email');
|
|
110
|
+
* }
|
|
111
|
+
* return next();
|
|
112
|
+
* }
|
|
113
|
+
* }
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
const Handle = () => {
|
|
117
|
+
return (target, propertyKey, descriptor) => {
|
|
118
|
+
Reflect.defineMetadata(exports.PIPELINE_BEHAVIOR_HANDLE_METADATA, true, target, propertyKey);
|
|
119
|
+
return descriptor;
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
exports.Handle = Handle;
|
|
68
123
|
//# sourceMappingURL=pipeline-behavior.decorator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline-behavior.decorator.js","sourceRoot":"","sources":["../../../src/lib/decorators/pipeline-behavior.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAA6C;AAG7C;;GAEG;AACU,QAAA,0BAA0B,GAAG,4BAA4B,CAAC;AAEvE;;GAEG;AACH,MAAM,eAAe,GAA4B;IAC/C,QAAQ,EAAE,CAAC;IACX,KAAK,EAAE,KAAK;CACb,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"pipeline-behavior.decorator.js","sourceRoot":"","sources":["../../../src/lib/decorators/pipeline-behavior.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAA6C;AAG7C;;GAEG;AACU,QAAA,0BAA0B,GAAG,4BAA4B,CAAC;AAEvE;;;GAGG;AACU,QAAA,iCAAiC,GAAG,mCAAmC,CAAC;AAErF;;GAEG;AACH,MAAM,eAAe,GAA4B;IAC/C,QAAQ,EAAE,CAAC;IACX,KAAK,EAAE,KAAK;CACb,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACI,MAAM,gBAAgB,GAAG,CAC9B,OAAiC,EACjB,EAAE;IAClB,MAAM,aAAa,GAA4B;QAC7C,GAAG,eAAe;QAClB,GAAG,OAAO;KACX,CAAC;IACF,OAAO,IAAA,oBAAW,EAAC,kCAA0B,EAAE,aAAa,CAAC,CAAC;AAChE,CAAC,CAAC;AARW,QAAA,gBAAgB,oBAQ3B;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACI,MAAM,MAAM,GAAG,GAAoB,EAAE;IAC1C,OAAO,CACL,MAAc,EACd,WAA4B,EAC5B,UAA8B,EACV,EAAE;QACtB,OAAO,CAAC,cAAc,CAAC,yCAAiC,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;QACrF,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC,CAAC;AATW,QAAA,MAAM,UASjB"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { DynamicModule,
|
|
1
|
+
import { DynamicModule, OnModuleInit } from '@nestjs/common';
|
|
2
2
|
import { Reflector, DiscoveryService } from '@nestjs/core';
|
|
3
3
|
import { MediatorBus } from './services/index.js';
|
|
4
|
-
import { IPipelineBehavior } from './interfaces/index.js';
|
|
5
4
|
/**
|
|
6
5
|
* Configuration options for NestMediatorModule
|
|
7
6
|
*/
|
|
@@ -37,12 +36,6 @@ export interface NestMediatorModuleOptions {
|
|
|
37
36
|
* Default: 500
|
|
38
37
|
*/
|
|
39
38
|
performanceThresholdMs?: number;
|
|
40
|
-
/**
|
|
41
|
-
* Custom pipeline behaviors to register.
|
|
42
|
-
* These will be registered in addition to any behaviors
|
|
43
|
-
* discovered via @PipelineBehavior decorator.
|
|
44
|
-
*/
|
|
45
|
-
behaviors?: Type<IPipelineBehavior<any, any>>[];
|
|
46
39
|
}
|
|
47
40
|
/**
|
|
48
41
|
* Token for module options injection
|
|
@@ -74,11 +67,6 @@ export declare class NestMediatorModule implements OnModuleInit {
|
|
|
74
67
|
* enablePerformanceTracking: true,
|
|
75
68
|
* performanceThresholdMs: 1000,
|
|
76
69
|
* })
|
|
77
|
-
*
|
|
78
|
-
* // With custom behaviors
|
|
79
|
-
* NestMediatorModule.forRoot({
|
|
80
|
-
* behaviors: [MyCustomBehavior],
|
|
81
|
-
* })
|
|
82
70
|
* ```
|
|
83
71
|
*/
|
|
84
72
|
static forRoot(options?: NestMediatorModuleOptions): DynamicModule;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nest-mediator.module.d.ts","sourceRoot":"","sources":["../../src/lib/nest-mediator.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"nest-mediator.module.d.ts","sourceRoot":"","sources":["../../src/lib/nest-mediator.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAgB,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAmB,MAAM,cAAc,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAqBlD;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC;;;;OAIG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IAEpC;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED;;GAEG;AACH,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAE7D,qBACa,kBAAmB,YAAW,YAAY;IAEnD,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;gBAFhB,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,SAAS,EACpB,gBAAgB,EAAE,gBAAgB;IAGrD,YAAY;IA6FZ;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,GAAE,yBAA8B,GAAG,aAAa;CAoCvE"}
|
|
@@ -53,8 +53,24 @@ let NestMediatorModule = NestMediatorModule_1 = class NestMediatorModule {
|
|
|
53
53
|
// Register pipeline behaviors
|
|
54
54
|
const behaviorMetadata = this.reflector.get(index_js_2.PIPELINE_BEHAVIOR_METADATA, handlerType);
|
|
55
55
|
if (behaviorMetadata) {
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
// Try to infer request type from handle method's first parameter
|
|
57
|
+
// This only works if @PipelineBehavior() decorator is applied to the handle method
|
|
58
|
+
const handleParamTypes = Reflect.getMetadata('design:paramtypes', handlerType.prototype, 'handle');
|
|
59
|
+
// Get the first parameter type (the request type)
|
|
60
|
+
// Only use it if it's a concrete class (not Object, Function, or undefined)
|
|
61
|
+
let requestType;
|
|
62
|
+
if (handleParamTypes && handleParamTypes[0]) {
|
|
63
|
+
const firstParamType = handleParamTypes[0];
|
|
64
|
+
// Exclude generic types like Object, Function that indicate no specific type
|
|
65
|
+
if (firstParamType !== Object &&
|
|
66
|
+
firstParamType !== Function &&
|
|
67
|
+
typeof firstParamType === 'function') {
|
|
68
|
+
requestType = firstParamType;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const requestTypeInfo = requestType ? `, requestType: ${requestType.name}` : '';
|
|
72
|
+
console.log(`[NestMediator] Registering pipeline behavior: ${handlerType.name} (priority: ${behaviorMetadata.priority ?? 0}, scope: ${behaviorMetadata.scope ?? 'all'}${requestTypeInfo})`);
|
|
73
|
+
this.mediatorBus.registerPipelineBehavior(handlerType, behaviorMetadata, requestType);
|
|
58
74
|
}
|
|
59
75
|
}
|
|
60
76
|
}
|
|
@@ -78,11 +94,6 @@ let NestMediatorModule = NestMediatorModule_1 = class NestMediatorModule {
|
|
|
78
94
|
* enablePerformanceTracking: true,
|
|
79
95
|
* performanceThresholdMs: 1000,
|
|
80
96
|
* })
|
|
81
|
-
*
|
|
82
|
-
* // With custom behaviors
|
|
83
|
-
* NestMediatorModule.forRoot({
|
|
84
|
-
* behaviors: [MyCustomBehavior],
|
|
85
|
-
* })
|
|
86
97
|
* ```
|
|
87
98
|
*/
|
|
88
99
|
static forRoot(options = {}) {
|
|
@@ -100,8 +111,6 @@ let NestMediatorModule = NestMediatorModule_1 = class NestMediatorModule {
|
|
|
100
111
|
if (options.enableValidation) {
|
|
101
112
|
builtInProviders.push(index_js_3.ValidationBehavior);
|
|
102
113
|
}
|
|
103
|
-
// Add custom behaviors
|
|
104
|
-
const customBehaviors = options.behaviors ?? [];
|
|
105
114
|
return {
|
|
106
115
|
module: NestMediatorModule_1,
|
|
107
116
|
imports: [core_1.DiscoveryModule],
|
|
@@ -109,7 +118,6 @@ let NestMediatorModule = NestMediatorModule_1 = class NestMediatorModule {
|
|
|
109
118
|
index_js_1.MediatorBus,
|
|
110
119
|
core_1.Reflector,
|
|
111
120
|
...builtInProviders,
|
|
112
|
-
...customBehaviors,
|
|
113
121
|
{
|
|
114
122
|
provide: exports.NEST_MEDIATOR_OPTIONS,
|
|
115
123
|
useValue: options,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nest-mediator.module.js","sourceRoot":"","sources":["../../src/lib/nest-mediator.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAA2E;AAC3E,uCAA4E;AAC5E,kDAAkD;AAClD,oDAI+B;AAS/B,mDAK8B;
|
|
1
|
+
{"version":3,"file":"nest-mediator.module.js","sourceRoot":"","sources":["../../src/lib/nest-mediator.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAA2E;AAC3E,uCAA4E;AAC5E,kDAAkD;AAClD,oDAI+B;AAS/B,mDAK8B;AA2C9B;;GAEG;AACU,QAAA,qBAAqB,GAAG,uBAAuB,CAAC;AAGtD,IAAM,kBAAkB,0BAAxB,MAAM,kBAAkB;IAC7B,YACmB,WAAwB,EACxB,SAAoB,EACpB,gBAAkC;QAFlC,gBAAW,GAAX,WAAW,CAAa;QACxB,cAAS,GAAT,SAAS,CAAW;QACpB,qBAAgB,GAAhB,gBAAgB,CAAkB;IAClD,CAAC;IAEJ,YAAY;QACV,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,CAAC;QAEvD,KAAK,MAAM,OAAO,IAAI,SAAS,EAAE,CAAC;YAChC,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;gBAC3C,SAAS;YACX,CAAC;YAED,MAAM,UAAU,GAAG,OAAO,OAAO,CAAC,QAAQ,KAAK,UAAU,CAAC;YAC1D,MAAM,aAAa,GACjB,UAAU,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,KAAK,SAAS,CAAC;YAEzD,IAAI,CAAC,aAAa,EAAE,CAAC;gBACnB,SAAS;YACX,CAAC;YAED,MAAM,WAAW,GAAG,OAAO,CAAC,QAAgB,CAAC;YAE7C,4BAA4B;YAC5B,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CACxC,mCAAwB,EACxB,WAAW,CACZ,CAAC;YAEF,IAAI,eAAe,EAAE,CAAC;gBACpB,OAAO,CAAC,GAAG,CACT,+CAA+C,WAAW,CAAC,IAAI,iBAAiB,eAAe,CAAC,IAAI,EAAE,CACvG,CAAC;gBACF,IAAI,CAAC,WAAW,CAAC,sBAAsB,CACrC,eAAe,EACf,WAAyC,CAC1C,CAAC;YACJ,CAAC;YAED,0BAA0B;YAC1B,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CACtC,iCAAsB,EACtB,WAAW,CACZ,CAAC;YAEF,IAAI,aAAa,EAAE,CAAC;gBAClB,OAAO,CAAC,GAAG,CACT,6CAA6C,WAAW,CAAC,IAAI,eAAe,aAAa,CAAC,IAAI,EAAE,CACjG,CAAC;gBACF,IAAI,CAAC,WAAW,CAAC,oBAAoB,CACnC,aAAa,EACb,WAA4C,CAC7C,CAAC;YACJ,CAAC;YAED,8BAA8B;YAC9B,MAAM,gBAAgB,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CACzC,qCAA0B,EAC1B,WAAW,CACZ,CAAC;YAEF,IAAI,gBAAgB,EAAE,CAAC;gBACrB,iEAAiE;gBACjE,mFAAmF;gBACnF,MAAM,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAC1C,mBAAmB,EACnB,WAAW,CAAC,SAAS,EACrB,QAAQ,CACT,CAAC;gBAEF,kDAAkD;gBAClD,4EAA4E;gBAC5E,IAAI,WAAiC,CAAC;gBACtC,IAAI,gBAAgB,IAAI,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC5C,MAAM,cAAc,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;oBAC3C,6EAA6E;oBAC7E,IACE,cAAc,KAAK,MAAM;wBACzB,cAAc,KAAK,QAAQ;wBAC3B,OAAO,cAAc,KAAK,UAAU,EACpC,CAAC;wBACD,WAAW,GAAG,cAAc,CAAC;oBAC/B,CAAC;gBACH,CAAC;gBAED,MAAM,eAAe,GAAG,WAAW,CAAC,CAAC,CAAC,kBAAkB,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChF,OAAO,CAAC,GAAG,CACT,iDAAiD,WAAW,CAAC,IAAI,eAAe,gBAAgB,CAAC,QAAQ,IAAI,CAAC,YAAY,gBAAgB,CAAC,KAAK,IAAI,KAAK,GAAG,eAAe,GAAG,CAC/K,CAAC;gBACF,IAAI,CAAC,WAAW,CAAC,wBAAwB,CACvC,WAAgD,EAChD,gBAAgB,EAChB,WAAW,CACZ,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,MAAM,CAAC,OAAO,CAAC,UAAqC,EAAE;QACpD,MAAM,gBAAgB,GAAW,EAAE,CAAC;QAEpC,0CAA0C;QAC1C,IAAI,OAAO,CAAC,uBAAuB,EAAE,CAAC;YACpC,gBAAgB,CAAC,IAAI,CAAC,oCAAyB,CAAC,CAAC;QACnD,CAAC;QAED,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;YAC1B,gBAAgB,CAAC,IAAI,CAAC,0BAAe,CAAC,CAAC;QACzC,CAAC;QAED,IAAI,OAAO,CAAC,yBAAyB,EAAE,CAAC;YACtC,gBAAgB,CAAC,IAAI,CAAC,8BAAmB,CAAC,CAAC;QAC7C,CAAC;QAED,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;YAC7B,gBAAgB,CAAC,IAAI,CAAC,6BAAkB,CAAC,CAAC;QAC5C,CAAC;QAED,OAAO;YACL,MAAM,EAAE,oBAAkB;YAC1B,OAAO,EAAE,CAAC,sBAAe,CAAC;YAC1B,SAAS,EAAE;gBACT,sBAAW;gBACX,gBAAS;gBACT,GAAG,gBAAgB;gBACnB;oBACE,OAAO,EAAE,6BAAqB;oBAC9B,QAAQ,EAAE,OAAO;iBAClB;aACF;YACD,OAAO,EAAE,CAAC,sBAAW,CAAC;YACtB,MAAM,EAAE,IAAI;SACb,CAAC;IACJ,CAAC;CACF,CAAA;AA9JY,gDAAkB;6BAAlB,kBAAkB;IAD9B,IAAA,eAAM,EAAC,EAAE,CAAC;qCAGuB,sBAAW;QACb,gBAAS;QACF,uBAAgB;GAJ1C,kBAAkB,CA8J9B"}
|
|
@@ -49,8 +49,9 @@ export declare class MediatorBus {
|
|
|
49
49
|
* Register a pipeline behavior
|
|
50
50
|
* @param behaviorType - The behavior class
|
|
51
51
|
* @param options - Behavior options (priority, scope)
|
|
52
|
+
* @param requestType - Optional specific request type this behavior applies to
|
|
52
53
|
*/
|
|
53
|
-
registerPipelineBehavior(behaviorType: Type<IPipelineBehavior<any, any>>, options: PipelineBehaviorOptions): void;
|
|
54
|
+
registerPipelineBehavior(behaviorType: Type<IPipelineBehavior<any, any>>, options: PipelineBehaviorOptions, requestType?: Function): void;
|
|
54
55
|
/**
|
|
55
56
|
* Send a command to its handler through the pipeline
|
|
56
57
|
* @param command - The command instance
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mediator.bus.d.ts","sourceRoot":"","sources":["../../../src/lib/services/mediator.bus.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EACL,QAAQ,EACR,eAAe,EACf,MAAM,EACN,aAAa,EACd,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACxB,MAAM,8CAA8C,CAAC;
|
|
1
|
+
{"version":3,"file":"mediator.bus.d.ts","sourceRoot":"","sources":["../../../src/lib/services/mediator.bus.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EACL,QAAQ,EACR,eAAe,EACf,MAAM,EACN,aAAa,EACd,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACxB,MAAM,8CAA8C,CAAC;AAkBtD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBACa,WAAW;IAQpB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAR5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IAEpD,OAAO,CAAC,eAAe,CAAiD;IACxE,OAAO,CAAC,aAAa,CAAoD;IACzE,OAAO,CAAC,iBAAiB,CAA4B;gBAGlC,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,SAAS;IAGvC;;;;OAIG;IACH,sBAAsB,CACpB,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,EACvB,OAAO,EAAE,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,GAClC,IAAI;IAUP;;;;OAIG;IACH,oBAAoB,CAClB,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,EACnB,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,GACrC,IAAI;IAQP;;;;;OAKG;IACH,wBAAwB,CACtB,YAAY,EAAE,IAAI,CAAC,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EAC/C,OAAO,EAAE,uBAAuB,EAChC,WAAW,CAAC,EAAE,QAAQ,GACrB,IAAI;IAcP;;;;OAIG;IACG,IAAI,CAAC,QAAQ,SAAS,QAAQ,EAAE,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBvE;;;;OAIG;IACG,KAAK,CAAC,MAAM,SAAS,MAAM,EAAE,OAAO,GAAG,GAAG,EAC9C,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,OAAO,CAAC;IAqBnB;;;OAGG;IACH,OAAO,CAAC,aAAa;IAsDrB;;OAEG;IACH,qBAAqB,IAAI,MAAM,EAAE;IAIjC;;OAEG;IACH,oBAAoB,IAAI,MAAM,EAAE;IAIhC;;OAEG;IACH,sBAAsB,IAAI,MAAM,EAAE;CAGnC"}
|
|
@@ -74,12 +74,14 @@ let MediatorBus = class MediatorBus {
|
|
|
74
74
|
* Register a pipeline behavior
|
|
75
75
|
* @param behaviorType - The behavior class
|
|
76
76
|
* @param options - Behavior options (priority, scope)
|
|
77
|
+
* @param requestType - Optional specific request type this behavior applies to
|
|
77
78
|
*/
|
|
78
|
-
registerPipelineBehavior(behaviorType, options) {
|
|
79
|
-
this.pipelineBehaviors.push({ type: behaviorType, options });
|
|
79
|
+
registerPipelineBehavior(behaviorType, options, requestType) {
|
|
80
|
+
this.pipelineBehaviors.push({ type: behaviorType, options, requestType });
|
|
80
81
|
// Keep behaviors sorted by priority (lower first)
|
|
81
82
|
this.pipelineBehaviors.sort((a, b) => (a.options.priority ?? 0) - (b.options.priority ?? 0));
|
|
82
|
-
|
|
83
|
+
const requestTypeInfo = requestType ? `, requestType: ${requestType.name}` : '';
|
|
84
|
+
this.logger.log(`Registered pipeline behavior: ${behaviorType.name} (priority: ${options.priority ?? 0}, scope: ${options.scope ?? 'all'}${requestTypeInfo})`);
|
|
83
85
|
}
|
|
84
86
|
/**
|
|
85
87
|
* Send a command to its handler through the pipeline
|
|
@@ -123,14 +125,18 @@ let MediatorBus = class MediatorBus {
|
|
|
123
125
|
// Get behaviors to skip from request metadata
|
|
124
126
|
const requestClass = request.constructor;
|
|
125
127
|
const behaviorsToSkip = this.reflector.get(skip_behavior_decorator_js_1.SKIP_BEHAVIORS_METADATA, requestClass) ?? [];
|
|
126
|
-
// Filter behaviors by scope and
|
|
128
|
+
// Filter behaviors by scope, skip list, and request type
|
|
127
129
|
const applicableBehaviors = this.pipelineBehaviors.filter((b) => {
|
|
128
130
|
// Check scope
|
|
129
131
|
const behaviorScope = b.options.scope ?? 'all';
|
|
130
132
|
const scopeMatches = behaviorScope === 'all' || behaviorScope === scope;
|
|
131
133
|
// Check if this behavior should be skipped
|
|
132
134
|
const shouldSkip = behaviorsToSkip.some((skipType) => skipType === b.type);
|
|
133
|
-
|
|
135
|
+
// Check request type match (if behavior has a specific request type)
|
|
136
|
+
// If behavior has no requestType, it applies to all requests
|
|
137
|
+
// If behavior has a requestType, only apply if request is an instance of that type
|
|
138
|
+
const requestTypeMatches = !b.requestType || request instanceof b.requestType;
|
|
139
|
+
return scopeMatches && !shouldSkip && requestTypeMatches;
|
|
134
140
|
});
|
|
135
141
|
// If no behaviors, just return the handler
|
|
136
142
|
if (applicableBehaviors.length === 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mediator.bus.js","sourceRoot":"","sources":["../../../src/lib/services/mediator.bus.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA0D;AAC1D,uCAAoD;AAWpD,iGAAwF;AACxF,yFAAmF;
|
|
1
|
+
{"version":3,"file":"mediator.bus.js","sourceRoot":"","sources":["../../../src/lib/services/mediator.bus.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rolandsall24/nest-mediator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "A lightweight CQRS (Command Query Responsibility Segregation) mediator pattern implementation for NestJS applications",
|
|
5
5
|
"author": "Roland Salloum",
|
|
6
6
|
"license": "MIT",
|