@andygo.dev/emitter 1.3.4
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/LICENSE +21 -0
- package/README.md +278 -0
- package/dist/constants.d.ts +17 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +20 -0
- package/dist/constants.js.map +1 -0
- package/dist/decorators/on-emitter-event.decorator.d.ts +22 -0
- package/dist/decorators/on-emitter-event.decorator.d.ts.map +1 -0
- package/dist/decorators/on-emitter-event.decorator.js +63 -0
- package/dist/decorators/on-emitter-event.decorator.js.map +1 -0
- package/dist/emitter.module.d.ts +92 -0
- package/dist/emitter.module.d.ts.map +1 -0
- package/dist/emitter.module.js +139 -0
- package/dist/emitter.module.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/services/emitter.service.d.ts +7 -0
- package/dist/services/emitter.service.d.ts.map +1 -0
- package/dist/services/emitter.service.js +32 -0
- package/dist/services/emitter.service.js.map +1 -0
- package/package.json +86 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Andy Kramar
|
|
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,278 @@
|
|
|
1
|
+
# @andygo.dev/emitter
|
|
2
|
+
|
|
3
|
+
A thin, **type-safe** NestJS wrapper around
|
|
4
|
+
[`@nestjs/event-emitter`](https://docs.nestjs.com/techniques/events) with an
|
|
5
|
+
**error-catching `@OnEmitterEvent`** decorator.
|
|
6
|
+
|
|
7
|
+
Three pieces:
|
|
8
|
+
|
|
9
|
+
- `EmitterService<T>` — typed `emit(...)` / `emitAsync(...)` keyed off your
|
|
10
|
+
event map.
|
|
11
|
+
- `OnEmitterEvent(...)` — drop-in replacement for `@OnEvent` that catches
|
|
12
|
+
thrown / rejected errors and logs them via the injected
|
|
13
|
+
`EMITTER_LOGGER` (NestJS `Logger` by default), so a single bad listener
|
|
14
|
+
can't take the whole emitter loop down.
|
|
15
|
+
- `EmitterModule.forRoot({...})` — wires the underlying `EventEmitter2` with
|
|
16
|
+
whatever options you want.
|
|
17
|
+
|
|
18
|
+
> **Runnable example:** [`examples/complex/`](examples/complex/) — a NestJS
|
|
19
|
+
> app that exercises every feature (typed events, `forRoot` + `forFeature`,
|
|
20
|
+
> async + sync listeners, error catching, cross-module flows). Clone the
|
|
21
|
+
> repo and run `npm run example:complex`.
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install @andygo.dev/emitter
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Peer dependencies:
|
|
30
|
+
|
|
31
|
+
- `@nestjs/common` `^10 || ^11`
|
|
32
|
+
- `@nestjs/event-emitter` `^2 || ^3`
|
|
33
|
+
|
|
34
|
+
## Quick start
|
|
35
|
+
|
|
36
|
+
### 1. Define your event map
|
|
37
|
+
|
|
38
|
+
A plain TypeScript type — the key is the event name, the value is the payload
|
|
39
|
+
shape. This is the single source of truth for both emit and listen.
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
// app.events.ts
|
|
43
|
+
export interface AppEvents {
|
|
44
|
+
'user.created': { id: number; email: string };
|
|
45
|
+
'user.deleted': { id: number };
|
|
46
|
+
'order.paid': { orderId: number; amount: number };
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 2. Register the module
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
// app.module.ts
|
|
54
|
+
import { Module } from '@nestjs/common';
|
|
55
|
+
import { EmitterModule } from '@andygo.dev/emitter';
|
|
56
|
+
|
|
57
|
+
@Module({
|
|
58
|
+
imports: [
|
|
59
|
+
EmitterModule.forRoot({
|
|
60
|
+
// optional — these are the defaults:
|
|
61
|
+
wildcard: false,
|
|
62
|
+
delimiter: '.',
|
|
63
|
+
maxListeners: 50,
|
|
64
|
+
}),
|
|
65
|
+
],
|
|
66
|
+
})
|
|
67
|
+
export class AppModule {}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Or use the static `EmitterModule` import directly if the defaults are fine —
|
|
71
|
+
it's `@Global()` either way, so you only need it once.
|
|
72
|
+
|
|
73
|
+
### 3. Emit events
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import { Injectable } from '@nestjs/common';
|
|
77
|
+
import { EmitterService } from '@andygo.dev/emitter';
|
|
78
|
+
import { AppEvents } from './app.events';
|
|
79
|
+
|
|
80
|
+
@Injectable()
|
|
81
|
+
export class UsersService {
|
|
82
|
+
constructor(private readonly events: EmitterService<AppEvents>) {}
|
|
83
|
+
|
|
84
|
+
async create(input: CreateUserDto) {
|
|
85
|
+
const user = await this.repo.save(input);
|
|
86
|
+
|
|
87
|
+
// ✓ key + payload are checked against AppEvents
|
|
88
|
+
await this.events.emitAsync('user.created', { id: user.id, email: user.email });
|
|
89
|
+
|
|
90
|
+
return user;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Both methods are strictly typed: passing the wrong event name or a payload
|
|
96
|
+
that doesn't match `AppEvents[key]` is a compile error.
|
|
97
|
+
|
|
98
|
+
| Method | Returns | When to use |
|
|
99
|
+
|---|---|---|
|
|
100
|
+
| `emit(name, payload)` | `boolean` (was anyone listening?) | Fire-and-forget |
|
|
101
|
+
| `emitAsync(name, payload)` | `Promise<any[]>` of all listener return values | When you need to wait for handlers to finish |
|
|
102
|
+
|
|
103
|
+
### 4. Listen for events
|
|
104
|
+
|
|
105
|
+
Use `@OnEmitterEvent` instead of `@OnEvent`. Same API, but a listener that
|
|
106
|
+
throws or rejects is caught and logged via the configured logger instead of
|
|
107
|
+
crashing the emitter loop.
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { Injectable } from '@nestjs/common';
|
|
111
|
+
import { OnEmitterEvent } from '@andygo.dev/emitter';
|
|
112
|
+
import { AppEvents } from './app.events';
|
|
113
|
+
|
|
114
|
+
@Injectable()
|
|
115
|
+
export class WelcomeEmailListener {
|
|
116
|
+
@OnEmitterEvent<AppEvents>('user.created')
|
|
117
|
+
async sendWelcome(payload: AppEvents['user.created']) {
|
|
118
|
+
await this.mailer.send(payload.email, 'welcome');
|
|
119
|
+
// any throw / rejection here is caught + logged, not propagated
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Synchronous listeners
|
|
125
|
+
|
|
126
|
+
For non-async handlers, pass `promisify: false` so the wrapper uses
|
|
127
|
+
`try/catch` instead of `.catch()`:
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
@OnEmitterEvent<AppEvents>('user.deleted', { promisify: false })
|
|
131
|
+
purgeCache(payload: AppEvents['user.deleted']) {
|
|
132
|
+
this.cache.delete(`user:${payload.id}`);
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Why not just `@OnEvent`?
|
|
137
|
+
|
|
138
|
+
Vanilla `@nestjs/event-emitter` propagates exceptions out of listeners and
|
|
139
|
+
the default `EventEmitter2` will emit an `'error'` event when there's no
|
|
140
|
+
listener — easy to miss in production logs. `@OnEmitterEvent` wraps the
|
|
141
|
+
listener method exactly once (idempotent across stacked decorators on the
|
|
142
|
+
same class) and catches both sync throws and promise rejections, routing
|
|
143
|
+
them to the configured logger so they end up in your normal log pipeline.
|
|
144
|
+
|
|
145
|
+
## Custom logger
|
|
146
|
+
|
|
147
|
+
By default `@OnEmitterEvent` logs errors via `new Logger('EmitterModule')`
|
|
148
|
+
(Nest's built-in console logger). Swap in anything that implements
|
|
149
|
+
`LoggerService` via `EmitterModule.forRoot`:
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
import { EmitterModule } from '@andygo.dev/emitter';
|
|
153
|
+
import { PinoLogger } from 'nestjs-pino'; // or your own LoggerService
|
|
154
|
+
|
|
155
|
+
@Module({
|
|
156
|
+
imports: [
|
|
157
|
+
EmitterModule.forRoot({
|
|
158
|
+
logger: new PinoLogger({ pinoHttp: {} }),
|
|
159
|
+
}),
|
|
160
|
+
],
|
|
161
|
+
})
|
|
162
|
+
export class AppModule {}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Per-module overrides with `forFeature`
|
|
166
|
+
|
|
167
|
+
`EmitterModule.forFeature({ logger })` overrides `EMITTER_LOGGER` for just
|
|
168
|
+
the importing module. Listeners declared inside that module log under the
|
|
169
|
+
local logger; listeners in other modules continue to use the
|
|
170
|
+
`forRoot`-level default.
|
|
171
|
+
|
|
172
|
+
`forFeature()` called without a `logger` is effectively a no-op for
|
|
173
|
+
logging — the listener inside that module **falls through to whatever
|
|
174
|
+
`forRoot` configured** (or the package default if no `forRoot` was
|
|
175
|
+
called).
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
// app.module.ts
|
|
179
|
+
@Module({
|
|
180
|
+
imports: [EmitterModule.forRoot()], // global default
|
|
181
|
+
})
|
|
182
|
+
export class AppModule {}
|
|
183
|
+
|
|
184
|
+
// users.module.ts
|
|
185
|
+
@Module({
|
|
186
|
+
imports: [
|
|
187
|
+
EmitterModule.forFeature({
|
|
188
|
+
logger: new Logger('UsersModule'), // local override
|
|
189
|
+
}),
|
|
190
|
+
],
|
|
191
|
+
providers: [UserCreatedListener], // its @OnEmitterEvent
|
|
192
|
+
// handlers log under
|
|
193
|
+
// 'UsersModule'
|
|
194
|
+
})
|
|
195
|
+
export class UsersModule {}
|
|
196
|
+
|
|
197
|
+
// orders.module.ts
|
|
198
|
+
@Module({
|
|
199
|
+
imports: [
|
|
200
|
+
EmitterModule.forFeature({
|
|
201
|
+
logger: new Logger('OrdersModule'),
|
|
202
|
+
}),
|
|
203
|
+
],
|
|
204
|
+
providers: [OrderPaidListener],
|
|
205
|
+
})
|
|
206
|
+
export class OrdersModule {}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Under the hood `forFeature({ logger })` provides a separate
|
|
210
|
+
`EMITTER_FEATURE_LOGGER` token (also exported), and the decorator injects
|
|
211
|
+
both `EMITTER_LOGGER` (required, global) and `EMITTER_FEATURE_LOGGER`
|
|
212
|
+
(optional, local) — preferring the feature one when present. This
|
|
213
|
+
sidesteps NestJS's "global module exports beat local imports" resolution
|
|
214
|
+
order; without the two-token split, the global `forRoot` logger would
|
|
215
|
+
silently win and the override would be dropped.
|
|
216
|
+
|
|
217
|
+
## API
|
|
218
|
+
|
|
219
|
+
### `EmitterService<T>`
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
class EmitterService<T> {
|
|
223
|
+
emit<K extends string & keyof T>(eventType: K, eventValue: T[K]): boolean;
|
|
224
|
+
emitAsync<K extends string & keyof T>(eventType: K, eventValue: T[K]): Promise<any[]>;
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### `OnEmitterEvent<T>(eventType, options?)`
|
|
229
|
+
|
|
230
|
+
```ts
|
|
231
|
+
function OnEmitterEvent<T>(
|
|
232
|
+
eventType: string & keyof T,
|
|
233
|
+
options?: {
|
|
234
|
+
async?: boolean; // default: true
|
|
235
|
+
promisify?: boolean; // default: true
|
|
236
|
+
suppressErrors?: boolean; // default: false (errors caught by wrapper)
|
|
237
|
+
// plus everything @OnEvent accepts
|
|
238
|
+
},
|
|
239
|
+
): MethodDecorator;
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### `EmitterModule.forRoot(options?)`
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
EmitterModule.forRoot({
|
|
246
|
+
// forwarded to EventEmitter2
|
|
247
|
+
wildcard?: boolean; // default: false
|
|
248
|
+
delimiter?: string; // default: '.'
|
|
249
|
+
maxListeners?: number; // default: 50
|
|
250
|
+
verboseMemoryLeak?: boolean;
|
|
251
|
+
ignoreErrors?: boolean;
|
|
252
|
+
newListener?: boolean;
|
|
253
|
+
removeListener?: boolean;
|
|
254
|
+
|
|
255
|
+
// package-specific
|
|
256
|
+
logger?: LoggerService; // default: new Logger('EmitterModule')
|
|
257
|
+
});
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### `EmitterModule.forFeature(options?)`
|
|
261
|
+
|
|
262
|
+
Feature-scoped logger override. Returns a non-global `DynamicModule`, so
|
|
263
|
+
the override only applies to providers inside the importing module.
|
|
264
|
+
When `logger` is omitted, the module does not rebind `EMITTER_LOGGER` —
|
|
265
|
+
listeners inside it fall through to whatever was configured by
|
|
266
|
+
`forRoot(...)`. EventEmitter2's `wildcard` / `delimiter` / `maxListeners`
|
|
267
|
+
are process-global and cannot be changed per-feature — configure those
|
|
268
|
+
via `forRoot`.
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
EmitterModule.forFeature({
|
|
272
|
+
logger?: LoggerService; // omit to inherit from forRoot
|
|
273
|
+
});
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## License
|
|
277
|
+
|
|
278
|
+
MIT
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Injection token for the root-level logger used by `@OnEmitterEvent`.
|
|
3
|
+
* Provided by `EmitterModule` with a default `new Logger('EmitterModule')`
|
|
4
|
+
* and overridable via `EmitterModule.forRoot({ logger })`. Always
|
|
5
|
+
* available — `forRoot` exports it globally.
|
|
6
|
+
*/
|
|
7
|
+
export declare const EMITTER_LOGGER: unique symbol;
|
|
8
|
+
/**
|
|
9
|
+
* Injection token for an optional per-feature logger override.
|
|
10
|
+
* Only provided when a caller passes `logger` to
|
|
11
|
+
* `EmitterModule.forFeature({ logger })`. The `@OnEmitterEvent` decorator
|
|
12
|
+
* prefers this over `EMITTER_LOGGER` when both are available, which is
|
|
13
|
+
* how feature modules can route their listener errors to their own
|
|
14
|
+
* logger without disturbing the global default.
|
|
15
|
+
*/
|
|
16
|
+
export declare const EMITTER_FEATURE_LOGGER: unique symbol;
|
|
17
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,cAAc,eAA2B,CAAC;AAEvD;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,eAAmC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EMITTER_FEATURE_LOGGER = exports.EMITTER_LOGGER = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Injection token for the root-level logger used by `@OnEmitterEvent`.
|
|
6
|
+
* Provided by `EmitterModule` with a default `new Logger('EmitterModule')`
|
|
7
|
+
* and overridable via `EmitterModule.forRoot({ logger })`. Always
|
|
8
|
+
* available — `forRoot` exports it globally.
|
|
9
|
+
*/
|
|
10
|
+
exports.EMITTER_LOGGER = Symbol('EMITTER_LOGGER');
|
|
11
|
+
/**
|
|
12
|
+
* Injection token for an optional per-feature logger override.
|
|
13
|
+
* Only provided when a caller passes `logger` to
|
|
14
|
+
* `EmitterModule.forFeature({ logger })`. The `@OnEmitterEvent` decorator
|
|
15
|
+
* prefers this over `EMITTER_LOGGER` when both are available, which is
|
|
16
|
+
* how feature modules can route their listener errors to their own
|
|
17
|
+
* logger without disturbing the global default.
|
|
18
|
+
*/
|
|
19
|
+
exports.EMITTER_FEATURE_LOGGER = Symbol('EMITTER_FEATURE_LOGGER');
|
|
20
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAA;;;;;GAKG;AACU,QAAA,cAAc,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAEvD;;;;;;;GAOG;AACU,QAAA,sBAAsB,GAAG,MAAM,CAAC,wBAAwB,CAAC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { OnEvent } from '@nestjs/event-emitter';
|
|
2
|
+
/**
|
|
3
|
+
* Decorate a method to listen for an emitter event.
|
|
4
|
+
*
|
|
5
|
+
* Behaves like `@OnEvent` from `@nestjs/event-emitter`, but wraps the
|
|
6
|
+
* handler so any thrown / rejected error is caught and reported to the
|
|
7
|
+
* configured logger:
|
|
8
|
+
*
|
|
9
|
+
* - If the listener's module imported `EmitterModule.forFeature({ logger })`,
|
|
10
|
+
* that local logger is used.
|
|
11
|
+
* - Otherwise, the root logger registered by `EmitterModule.forRoot({ logger })`
|
|
12
|
+
* (defaulting to `new Logger('EmitterModule')`) is used.
|
|
13
|
+
*
|
|
14
|
+
* Options:
|
|
15
|
+
*
|
|
16
|
+
* - `promisify: true` (default) — the handler must return a Promise;
|
|
17
|
+
* rejections are caught with `.catch(...)`.
|
|
18
|
+
* - `promisify: false` — the handler is treated as synchronous; throws
|
|
19
|
+
* are caught with try/catch and `undefined` is returned.
|
|
20
|
+
*/
|
|
21
|
+
export declare function OnEmitterEvent<T>(eventType: string & keyof T, options?: Parameters<typeof OnEvent>[1]): (target: any, _property: string, descriptor: PropertyDescriptor) => void | TypedPropertyDescriptor<any>;
|
|
22
|
+
//# sourceMappingURL=on-emitter-event.decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"on-emitter-event.decorator.d.ts","sourceRoot":"","sources":["../../src/decorators/on-emitter-event.decorator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAMhD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAC9B,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,EAC3B,OAAO,GAAE,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,CAAM,IAEnC,QAAQ,GAAG,EAAE,WAAW,MAAM,EAAE,YAAY,kBAAkB,yCAuCvE"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OnEmitterEvent = OnEmitterEvent;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
const event_emitter_1 = require("@nestjs/event-emitter");
|
|
6
|
+
const constants_1 = require("../constants");
|
|
7
|
+
const WRAPPER_ADDED = Symbol('WRAPPER_ADDED');
|
|
8
|
+
/**
|
|
9
|
+
* Decorate a method to listen for an emitter event.
|
|
10
|
+
*
|
|
11
|
+
* Behaves like `@OnEvent` from `@nestjs/event-emitter`, but wraps the
|
|
12
|
+
* handler so any thrown / rejected error is caught and reported to the
|
|
13
|
+
* configured logger:
|
|
14
|
+
*
|
|
15
|
+
* - If the listener's module imported `EmitterModule.forFeature({ logger })`,
|
|
16
|
+
* that local logger is used.
|
|
17
|
+
* - Otherwise, the root logger registered by `EmitterModule.forRoot({ logger })`
|
|
18
|
+
* (defaulting to `new Logger('EmitterModule')`) is used.
|
|
19
|
+
*
|
|
20
|
+
* Options:
|
|
21
|
+
*
|
|
22
|
+
* - `promisify: true` (default) — the handler must return a Promise;
|
|
23
|
+
* rejections are caught with `.catch(...)`.
|
|
24
|
+
* - `promisify: false` — the handler is treated as synchronous; throws
|
|
25
|
+
* are caught with try/catch and `undefined` is returned.
|
|
26
|
+
*/
|
|
27
|
+
function OnEmitterEvent(eventType, options = {}) {
|
|
28
|
+
return (target, _property, descriptor) => {
|
|
29
|
+
// Required: every listener resolves the global root logger so we always
|
|
30
|
+
// have a working fallback.
|
|
31
|
+
(0, common_1.Inject)(constants_1.EMITTER_LOGGER)(target, constants_1.EMITTER_LOGGER);
|
|
32
|
+
// Optional: the per-feature override is only present when the listener's
|
|
33
|
+
// module imported `EmitterModule.forFeature({ logger })`.
|
|
34
|
+
(0, common_1.Inject)(constants_1.EMITTER_FEATURE_LOGGER)(target, constants_1.EMITTER_FEATURE_LOGGER);
|
|
35
|
+
(0, common_1.Optional)()(target, constants_1.EMITTER_FEATURE_LOGGER);
|
|
36
|
+
const method = descriptor.value;
|
|
37
|
+
const onEventOptions = {
|
|
38
|
+
async: true, promisify: true, suppressErrors: false, ...options,
|
|
39
|
+
};
|
|
40
|
+
if (!target[WRAPPER_ADDED]) {
|
|
41
|
+
descriptor.value = function onEmitterEventWrapper(...args) {
|
|
42
|
+
const self = this;
|
|
43
|
+
const logger = self[constants_1.EMITTER_FEATURE_LOGGER]
|
|
44
|
+
?? self[constants_1.EMITTER_LOGGER];
|
|
45
|
+
if (onEventOptions.promisify === false) {
|
|
46
|
+
try {
|
|
47
|
+
return method.apply(this, args);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
logger.error(error);
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return method.apply(this, args).catch((error) => {
|
|
55
|
+
logger.error(error);
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
target[WRAPPER_ADDED] = true;
|
|
59
|
+
}
|
|
60
|
+
return (0, event_emitter_1.OnEvent)(eventType, onEventOptions)(target, _property, descriptor);
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=on-emitter-event.decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"on-emitter-event.decorator.js","sourceRoot":"","sources":["../../src/decorators/on-emitter-event.decorator.ts"],"names":[],"mappings":";;AA0BA,wCA2CC;AArED,2CAAiE;AACjE,yDAAgD;AAEhD,4CAAsE;AAEtE,MAAM,aAAa,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;AAE9C;;;;;;;;;;;;;;;;;;GAkBG;AACH,SAAgB,cAAc,CAC5B,SAA2B,EAC3B,UAAyC,EAAE;IAE3C,OAAO,CAAC,MAAW,EAAE,SAAiB,EAAE,UAA8B,EAAE,EAAE;QACxE,wEAAwE;QACxE,2BAA2B;QAC3B,IAAA,eAAM,EAAC,0BAAc,CAAC,CAAC,MAAM,EAAE,0BAAc,CAAC,CAAC;QAE/C,yEAAyE;QACzE,0DAA0D;QAC1D,IAAA,eAAM,EAAC,kCAAsB,CAAC,CAAC,MAAM,EAAE,kCAAsB,CAAC,CAAC;QAC/D,IAAA,iBAAQ,GAAE,CAAC,MAAM,EAAE,kCAAsB,CAAC,CAAC;QAE3C,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC;QAChC,MAAM,cAAc,GAAG;YACrB,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,GAAG,OAAO;SAChE,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;YAC3B,UAAU,CAAC,KAAK,GAAG,SAAS,qBAAqB,CAAC,GAAG,IAAW;gBAC9D,MAAM,IAAI,GAAG,IAAW,CAAC;gBACzB,MAAM,MAAM,GAAI,IAAI,CAAC,kCAAsB,CAA+B;uBACpE,IAAI,CAAC,0BAAc,CAAmB,CAAC;gBAE7C,IAAI,cAAc,CAAC,SAAS,KAAK,KAAK,EAAE,CAAC;oBACvC,IAAI,CAAC;wBACH,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;oBAClC,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;wBAEpB,OAAO,SAAS,CAAC;oBACnB,CAAC;gBACH,CAAC;gBACD,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAU,EAAE,EAAE;oBACnD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBACtB,CAAC,CAAC,CAAC;YACL,CAAC,CAAC;YACF,MAAM,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC;QAC/B,CAAC;QAED,OAAO,IAAA,uBAAO,EAAC,SAAS,EAAE,cAAc,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IAC3E,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { DynamicModule, LoggerService } from '@nestjs/common';
|
|
2
|
+
export interface EmitterModuleOptions {
|
|
3
|
+
wildcard?: boolean;
|
|
4
|
+
delimiter?: string;
|
|
5
|
+
maxListeners?: number;
|
|
6
|
+
verboseMemoryLeak?: boolean;
|
|
7
|
+
ignoreErrors?: boolean;
|
|
8
|
+
newListener?: boolean;
|
|
9
|
+
removeListener?: boolean;
|
|
10
|
+
global?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Logger used by `@OnEmitterEvent` when a listener throws or rejects.
|
|
13
|
+
* Anything implementing NestJS's `LoggerService` interface works —
|
|
14
|
+
* Nest's built-in `Logger`, `pino`, `winston`, your project's
|
|
15
|
+
* `LoggerService`, etc.
|
|
16
|
+
*
|
|
17
|
+
* Defaults to `new Logger('EmitterModule')` (the NestJS console logger).
|
|
18
|
+
*/
|
|
19
|
+
logger?: LoggerService;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Options accepted by `EmitterModule.forFeature(...)` — currently just the
|
|
23
|
+
* logger. EventEmitter2's `wildcard` / `delimiter` / `maxListeners` are
|
|
24
|
+
* process-global and can only be configured via `forRoot(...)`.
|
|
25
|
+
*/
|
|
26
|
+
export interface EmitterFeatureOptions {
|
|
27
|
+
/**
|
|
28
|
+
* Logger to use for listeners declared inside the importing module.
|
|
29
|
+
* Falls back to the root-level `EMITTER_LOGGER` (set via `forRoot`,
|
|
30
|
+
* defaulting to `new Logger('EmitterModule')`) when omitted.
|
|
31
|
+
*/
|
|
32
|
+
logger?: LoggerService;
|
|
33
|
+
}
|
|
34
|
+
export declare class EmitterModule {
|
|
35
|
+
/**
|
|
36
|
+
* Use `EmitterModule.forRoot({...})` to override the default
|
|
37
|
+
* EventEmitter2 configuration and/or supply a custom logger.
|
|
38
|
+
*
|
|
39
|
+
* Default options are: `{ wildcard: false, delimiter: '.', maxListeners: 50 }`.
|
|
40
|
+
* Default logger is `new Logger('EmitterModule')`.
|
|
41
|
+
*
|
|
42
|
+
* The returned module is global — `EmitterService` and `EMITTER_LOGGER`
|
|
43
|
+
* are available app-wide without explicit imports.
|
|
44
|
+
*/
|
|
45
|
+
static forRoot(options?: EmitterModuleOptions): DynamicModule;
|
|
46
|
+
/**
|
|
47
|
+
* Override the logger used by `@OnEmitterEvent` for listeners declared
|
|
48
|
+
* inside the importing module.
|
|
49
|
+
*
|
|
50
|
+
* Implementation note: `forFeature` provides a separate
|
|
51
|
+
* `EMITTER_FEATURE_LOGGER` token, *not* a second binding of
|
|
52
|
+
* `EMITTER_LOGGER`. The decorator injects both tokens and prefers the
|
|
53
|
+
* feature one when present. This sidesteps NestJS's "global module
|
|
54
|
+
* exports beat local imports" resolution — without it, `forRoot`'s
|
|
55
|
+
* global `EMITTER_LOGGER` would always win and the override would be
|
|
56
|
+
* silently dropped.
|
|
57
|
+
*
|
|
58
|
+
* If `options.logger` is omitted, the feature module is effectively
|
|
59
|
+
* a no-op (still useful as documentation that a module wants
|
|
60
|
+
* emitter-aware logging), and listeners inside it fall through to
|
|
61
|
+
* the root-level `EMITTER_LOGGER` from `forRoot(...)`.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* // app.module.ts
|
|
66
|
+
* @Module({
|
|
67
|
+
* imports: [EmitterModule.forRoot({ logger: rootLogger })],
|
|
68
|
+
* })
|
|
69
|
+
* export class AppModule {}
|
|
70
|
+
*
|
|
71
|
+
* // users.module.ts — overrides the root logger locally
|
|
72
|
+
* @Module({
|
|
73
|
+
* imports: [
|
|
74
|
+
* EmitterModule.forFeature({
|
|
75
|
+
* logger: new Logger('UsersModule'),
|
|
76
|
+
* }),
|
|
77
|
+
* ],
|
|
78
|
+
* providers: [UserCreatedListener],
|
|
79
|
+
* })
|
|
80
|
+
* export class UsersModule {}
|
|
81
|
+
*
|
|
82
|
+
* // orders.module.ts — no override, falls back to rootLogger
|
|
83
|
+
* @Module({
|
|
84
|
+
* imports: [EmitterModule.forFeature()],
|
|
85
|
+
* providers: [OrderPaidListener],
|
|
86
|
+
* })
|
|
87
|
+
* export class OrdersModule {}
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
static forFeature(options?: EmitterFeatureOptions): DynamicModule;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=emitter.module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitter.module.d.ts","sourceRoot":"","sources":["../src/emitter.module.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAAkB,aAAa,EAC7C,MAAM,gBAAgB,CAAC;AAMxB,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AA6BD,qBASa,aAAa;IACxB;;;;;;;;;OASG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,GAAE,oBAAyB,GAAG,aAAa;IAgBjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2CG;IACH,MAAM,CAAC,UAAU,CAAC,OAAO,GAAE,qBAA0B,GAAG,aAAa;CAmBtE"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var EmitterModule_1;
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.EmitterModule = void 0;
|
|
11
|
+
const common_1 = require("@nestjs/common");
|
|
12
|
+
const event_emitter_1 = require("@nestjs/event-emitter");
|
|
13
|
+
const constants_1 = require("./constants");
|
|
14
|
+
const emitter_service_1 = require("./services/emitter.service");
|
|
15
|
+
const EVENT_EMITTER_KEYS = [
|
|
16
|
+
'wildcard',
|
|
17
|
+
'delimiter',
|
|
18
|
+
'maxListeners',
|
|
19
|
+
'verboseMemoryLeak',
|
|
20
|
+
'ignoreErrors',
|
|
21
|
+
'newListener',
|
|
22
|
+
'removeListener',
|
|
23
|
+
'global',
|
|
24
|
+
];
|
|
25
|
+
const DEFAULT_OPTIONS = {
|
|
26
|
+
wildcard: false,
|
|
27
|
+
delimiter: '.',
|
|
28
|
+
maxListeners: 50,
|
|
29
|
+
};
|
|
30
|
+
const DEFAULT_LOGGER = new common_1.Logger('EmitterModule');
|
|
31
|
+
function pickEventEmitterOptions(options) {
|
|
32
|
+
const out = {};
|
|
33
|
+
for (const key of EVENT_EMITTER_KEYS) {
|
|
34
|
+
if (options[key] !== undefined)
|
|
35
|
+
out[key] = options[key];
|
|
36
|
+
}
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
let EmitterModule = EmitterModule_1 = class EmitterModule {
|
|
40
|
+
/**
|
|
41
|
+
* Use `EmitterModule.forRoot({...})` to override the default
|
|
42
|
+
* EventEmitter2 configuration and/or supply a custom logger.
|
|
43
|
+
*
|
|
44
|
+
* Default options are: `{ wildcard: false, delimiter: '.', maxListeners: 50 }`.
|
|
45
|
+
* Default logger is `new Logger('EmitterModule')`.
|
|
46
|
+
*
|
|
47
|
+
* The returned module is global — `EmitterService` and `EMITTER_LOGGER`
|
|
48
|
+
* are available app-wide without explicit imports.
|
|
49
|
+
*/
|
|
50
|
+
static forRoot(options = {}) {
|
|
51
|
+
const merged = { ...DEFAULT_OPTIONS, ...options };
|
|
52
|
+
const logger = options.logger ?? DEFAULT_LOGGER;
|
|
53
|
+
return {
|
|
54
|
+
module: EmitterModule_1,
|
|
55
|
+
global: true,
|
|
56
|
+
imports: [event_emitter_1.EventEmitterModule.forRoot(pickEventEmitterOptions(merged))],
|
|
57
|
+
providers: [
|
|
58
|
+
emitter_service_1.EmitterService,
|
|
59
|
+
{ provide: constants_1.EMITTER_LOGGER, useValue: logger },
|
|
60
|
+
],
|
|
61
|
+
exports: [emitter_service_1.EmitterService, constants_1.EMITTER_LOGGER],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Override the logger used by `@OnEmitterEvent` for listeners declared
|
|
66
|
+
* inside the importing module.
|
|
67
|
+
*
|
|
68
|
+
* Implementation note: `forFeature` provides a separate
|
|
69
|
+
* `EMITTER_FEATURE_LOGGER` token, *not* a second binding of
|
|
70
|
+
* `EMITTER_LOGGER`. The decorator injects both tokens and prefers the
|
|
71
|
+
* feature one when present. This sidesteps NestJS's "global module
|
|
72
|
+
* exports beat local imports" resolution — without it, `forRoot`'s
|
|
73
|
+
* global `EMITTER_LOGGER` would always win and the override would be
|
|
74
|
+
* silently dropped.
|
|
75
|
+
*
|
|
76
|
+
* If `options.logger` is omitted, the feature module is effectively
|
|
77
|
+
* a no-op (still useful as documentation that a module wants
|
|
78
|
+
* emitter-aware logging), and listeners inside it fall through to
|
|
79
|
+
* the root-level `EMITTER_LOGGER` from `forRoot(...)`.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* // app.module.ts
|
|
84
|
+
* @Module({
|
|
85
|
+
* imports: [EmitterModule.forRoot({ logger: rootLogger })],
|
|
86
|
+
* })
|
|
87
|
+
* export class AppModule {}
|
|
88
|
+
*
|
|
89
|
+
* // users.module.ts — overrides the root logger locally
|
|
90
|
+
* @Module({
|
|
91
|
+
* imports: [
|
|
92
|
+
* EmitterModule.forFeature({
|
|
93
|
+
* logger: new Logger('UsersModule'),
|
|
94
|
+
* }),
|
|
95
|
+
* ],
|
|
96
|
+
* providers: [UserCreatedListener],
|
|
97
|
+
* })
|
|
98
|
+
* export class UsersModule {}
|
|
99
|
+
*
|
|
100
|
+
* // orders.module.ts — no override, falls back to rootLogger
|
|
101
|
+
* @Module({
|
|
102
|
+
* imports: [EmitterModule.forFeature()],
|
|
103
|
+
* providers: [OrderPaidListener],
|
|
104
|
+
* })
|
|
105
|
+
* export class OrdersModule {}
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
static forFeature(options = {}) {
|
|
109
|
+
// Fresh class per call so Nest doesn't dedupe the feature import.
|
|
110
|
+
class EmitterFeatureModule {
|
|
111
|
+
}
|
|
112
|
+
if (options.logger === undefined) {
|
|
113
|
+
// No override — listeners fall through to root EMITTER_LOGGER.
|
|
114
|
+
return {
|
|
115
|
+
module: EmitterFeatureModule,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
module: EmitterFeatureModule,
|
|
120
|
+
providers: [
|
|
121
|
+
{ provide: constants_1.EMITTER_FEATURE_LOGGER, useValue: options.logger },
|
|
122
|
+
],
|
|
123
|
+
exports: [constants_1.EMITTER_FEATURE_LOGGER],
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
exports.EmitterModule = EmitterModule;
|
|
128
|
+
exports.EmitterModule = EmitterModule = EmitterModule_1 = __decorate([
|
|
129
|
+
(0, common_1.Global)(),
|
|
130
|
+
(0, common_1.Module)({
|
|
131
|
+
imports: [event_emitter_1.EventEmitterModule.forRoot(pickEventEmitterOptions(DEFAULT_OPTIONS))],
|
|
132
|
+
providers: [
|
|
133
|
+
emitter_service_1.EmitterService,
|
|
134
|
+
{ provide: constants_1.EMITTER_LOGGER, useValue: DEFAULT_LOGGER },
|
|
135
|
+
],
|
|
136
|
+
exports: [emitter_service_1.EmitterService, constants_1.EMITTER_LOGGER],
|
|
137
|
+
})
|
|
138
|
+
], EmitterModule);
|
|
139
|
+
//# sourceMappingURL=emitter.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitter.module.js","sourceRoot":"","sources":["../src/emitter.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAEwB;AACxB,yDAA2D;AAE3D,2CAAqE;AACrE,gEAA4D;AAqC5D,MAAM,kBAAkB,GAAG;IACzB,UAAU;IACV,WAAW;IACX,cAAc;IACd,mBAAmB;IACnB,cAAc;IACd,aAAa;IACb,gBAAgB;IAChB,QAAQ;CACA,CAAC;AAEX,MAAM,eAAe,GAAyB;IAC5C,QAAQ,EAAE,KAAK;IACf,SAAS,EAAE,GAAG;IACd,YAAY,EAAE,EAAE;CACjB,CAAC;AAEF,MAAM,cAAc,GAAkB,IAAI,eAAM,CAAC,eAAe,CAAC,CAAC;AAElE,SAAS,uBAAuB,CAAC,OAA6B;IAC5D,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,GAAG,IAAI,kBAAkB,EAAE,CAAC;QACrC,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,SAAS;YAAE,GAAG,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAWM,IAAM,aAAa,qBAAnB,MAAM,aAAa;IACxB;;;;;;;;;OASG;IACH,MAAM,CAAC,OAAO,CAAC,UAAgC,EAAE;QAC/C,MAAM,MAAM,GAAG,EAAE,GAAG,eAAe,EAAE,GAAG,OAAO,EAAE,CAAC;QAClD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,cAAc,CAAC;QAEhD,OAAO;YACL,MAAM,EAAE,eAAa;YACrB,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,CAAC,kCAAkB,CAAC,OAAO,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC,CAAC;YACtE,SAAS,EAAE;gBACT,gCAAc;gBACd,EAAE,OAAO,EAAE,0BAAc,EAAE,QAAQ,EAAE,MAAM,EAAE;aAC9C;YACD,OAAO,EAAE,CAAC,gCAAc,EAAE,0BAAc,CAAC;SAC1C,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2CG;IACH,MAAM,CAAC,UAAU,CAAC,UAAiC,EAAE;QACnD,kEAAkE;QAClE,MAAM,oBAAoB;SAAG;QAE7B,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YACjC,+DAA+D;YAC/D,OAAO;gBACL,MAAM,EAAE,oBAAoB;aAC7B,CAAC;QACJ,CAAC;QAED,OAAO;YACL,MAAM,EAAE,oBAAoB;YAC5B,SAAS,EAAE;gBACT,EAAE,OAAO,EAAE,kCAAsB,EAAE,QAAQ,EAAE,OAAO,CAAC,MAAM,EAAE;aAC9D;YACD,OAAO,EAAE,CAAC,kCAAsB,CAAC;SAClC,CAAC;IACJ,CAAC;CACF,CAAA;AA1FY,sCAAa;wBAAb,aAAa;IATzB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,kCAAkB,CAAC,OAAO,CAAC,uBAAuB,CAAC,eAAe,CAAC,CAAC,CAAC;QAC/E,SAAS,EAAE;YACT,gCAAc;YACd,EAAE,OAAO,EAAE,0BAAc,EAAE,QAAQ,EAAE,cAAc,EAAE;SACtD;QACD,OAAO,EAAE,CAAC,gCAAc,EAAE,0BAAc,CAAC;KAC1C,CAAC;GACW,aAAa,CA0FzB"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { EmitterService } from './services/emitter.service';
|
|
2
|
+
export { EmitterModule, EmitterModuleOptions, EmitterFeatureOptions } from './emitter.module';
|
|
3
|
+
export { OnEmitterEvent } from './decorators/on-emitter-event.decorator';
|
|
4
|
+
export { EMITTER_LOGGER, EMITTER_FEATURE_LOGGER } from './constants';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC9F,OAAO,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EMITTER_FEATURE_LOGGER = exports.EMITTER_LOGGER = exports.OnEmitterEvent = exports.EmitterModule = exports.EmitterService = void 0;
|
|
4
|
+
var emitter_service_1 = require("./services/emitter.service");
|
|
5
|
+
Object.defineProperty(exports, "EmitterService", { enumerable: true, get: function () { return emitter_service_1.EmitterService; } });
|
|
6
|
+
var emitter_module_1 = require("./emitter.module");
|
|
7
|
+
Object.defineProperty(exports, "EmitterModule", { enumerable: true, get: function () { return emitter_module_1.EmitterModule; } });
|
|
8
|
+
var on_emitter_event_decorator_1 = require("./decorators/on-emitter-event.decorator");
|
|
9
|
+
Object.defineProperty(exports, "OnEmitterEvent", { enumerable: true, get: function () { return on_emitter_event_decorator_1.OnEmitterEvent; } });
|
|
10
|
+
var constants_1 = require("./constants");
|
|
11
|
+
Object.defineProperty(exports, "EMITTER_LOGGER", { enumerable: true, get: function () { return constants_1.EMITTER_LOGGER; } });
|
|
12
|
+
Object.defineProperty(exports, "EMITTER_FEATURE_LOGGER", { enumerable: true, get: function () { return constants_1.EMITTER_FEATURE_LOGGER; } });
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,8DAA4D;AAAnD,iHAAA,cAAc,OAAA;AACvB,mDAA8F;AAArF,+GAAA,aAAa,OAAA;AACtB,sFAAyE;AAAhE,4HAAA,cAAc,OAAA;AACvB,yCAAqE;AAA5D,2GAAA,cAAc,OAAA;AAAE,mHAAA,sBAAsB,OAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { EventEmitter2 } from '@nestjs/event-emitter';
|
|
2
|
+
export declare class EmitterService<T> {
|
|
3
|
+
protected emitter2: EventEmitter2;
|
|
4
|
+
emitAsync<key extends string & keyof T>(eventType: key, eventValue: T[key]): Promise<any[]>;
|
|
5
|
+
emit<key extends string & keyof T>(eventType: key, eventValue: T[key]): boolean;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=emitter.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitter.service.d.ts","sourceRoot":"","sources":["../../src/services/emitter.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,qBACa,cAAc,CAAC,CAAC;IAE3B,SAAS,CAAC,QAAQ,EAAE,aAAa,CAAC;IAElC,SAAS,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC,GAAG,CAAC;IAI1E,IAAI,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC,GAAG,CAAC;CAGtE"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.EmitterService = void 0;
|
|
13
|
+
const common_1 = require("@nestjs/common");
|
|
14
|
+
const event_emitter_1 = require("@nestjs/event-emitter");
|
|
15
|
+
let EmitterService = class EmitterService {
|
|
16
|
+
emitter2;
|
|
17
|
+
emitAsync(eventType, eventValue) {
|
|
18
|
+
return this.emitter2.emitAsync(eventType, eventValue, eventType);
|
|
19
|
+
}
|
|
20
|
+
emit(eventType, eventValue) {
|
|
21
|
+
return this.emitter2.emit(eventType, eventValue, eventType);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
exports.EmitterService = EmitterService;
|
|
25
|
+
__decorate([
|
|
26
|
+
(0, common_1.Inject)(),
|
|
27
|
+
__metadata("design:type", event_emitter_1.EventEmitter2)
|
|
28
|
+
], EmitterService.prototype, "emitter2", void 0);
|
|
29
|
+
exports.EmitterService = EmitterService = __decorate([
|
|
30
|
+
(0, common_1.Injectable)()
|
|
31
|
+
], EmitterService);
|
|
32
|
+
//# sourceMappingURL=emitter.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitter.service.js","sourceRoot":"","sources":["../../src/services/emitter.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAoD;AACpD,yDAAsD;AAG/C,IAAM,cAAc,GAApB,MAAM,cAAc;IAEf,QAAQ,CAAgB;IAElC,SAAS,CAA+B,SAAc,EAAE,UAAkB;QACxE,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,SAAS,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;IACnE,CAAC;IAED,IAAI,CAA+B,SAAc,EAAE,UAAkB;QACnE,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;IAC9D,CAAC;CACF,CAAA;AAXY,wCAAc;AAEf;IADT,IAAA,eAAM,GAAE;8BACW,6BAAa;gDAAC;yBAFvB,cAAc;IAD1B,IAAA,mBAAU,GAAE;GACA,cAAc,CAW1B"}
|
package/package.json
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@andygo.dev/emitter",
|
|
3
|
+
"version": "1.3.4",
|
|
4
|
+
"description": "Type-safe wrapper around @nestjs/event-emitter with an error-catching @OnEmitterEvent decorator.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md",
|
|
10
|
+
"LICENSE"
|
|
11
|
+
],
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=18.0.0"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc -p tsconfig.json",
|
|
17
|
+
"clean": "rm -rf dist",
|
|
18
|
+
"lint": "eslint \"{src,tests}/**/*.ts\" --max-warnings=0",
|
|
19
|
+
"lint:fix": "eslint \"{src,tests}/**/*.ts\" --max-warnings=0 --fix",
|
|
20
|
+
"test": "jest",
|
|
21
|
+
"test:watch": "jest --watch",
|
|
22
|
+
"test:cov": "jest --coverage",
|
|
23
|
+
"example:complex": "ts-node --project tsconfig.examples.json examples/main.ts",
|
|
24
|
+
"prepublishOnly": "npm run clean && npm run build",
|
|
25
|
+
"preversion": "npm run lint && npm test && npm run build",
|
|
26
|
+
"postversion": "git push --follow-tags && npm publish --access public",
|
|
27
|
+
"publish": "npm publish --access public",
|
|
28
|
+
"bump:patch": "npm version patch --no-git-tag-version",
|
|
29
|
+
"bump:minor": "npm version minor --no-git-tag-version",
|
|
30
|
+
"bump:major": "npm version major --no-git-tag-version"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"nestjs",
|
|
34
|
+
"event-emitter",
|
|
35
|
+
"events",
|
|
36
|
+
"typescript",
|
|
37
|
+
"decorator"
|
|
38
|
+
],
|
|
39
|
+
"author": "Andy Kramar <andygo.develop@gmail.com>",
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
|
43
|
+
"@nestjs/event-emitter": "^2.0.0 || ^3.0.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@nestjs/common": "^11.1.3",
|
|
47
|
+
"@nestjs/core": "^11.1.3",
|
|
48
|
+
"@nestjs/event-emitter": "^3.0.1",
|
|
49
|
+
"@nestjs/testing": "^11.1.3",
|
|
50
|
+
"@types/jest": "29.5.14",
|
|
51
|
+
"@types/node": "^20.0.0",
|
|
52
|
+
"eslint": "^9.0.0",
|
|
53
|
+
"jest": "29.7.0",
|
|
54
|
+
"reflect-metadata": "^0.2.0",
|
|
55
|
+
"rxjs": "^7.8.0",
|
|
56
|
+
"ts-jest": "29.2.5",
|
|
57
|
+
"ts-node": "^10.9.0",
|
|
58
|
+
"typescript": "^5.4.0",
|
|
59
|
+
"typescript-eslint": "^8.0.0"
|
|
60
|
+
},
|
|
61
|
+
"jest": {
|
|
62
|
+
"testEnvironment": "node",
|
|
63
|
+
"rootDir": ".",
|
|
64
|
+
"testMatch": [
|
|
65
|
+
"<rootDir>/tests/**/*.spec.ts"
|
|
66
|
+
],
|
|
67
|
+
"moduleFileExtensions": [
|
|
68
|
+
"ts",
|
|
69
|
+
"js",
|
|
70
|
+
"json"
|
|
71
|
+
],
|
|
72
|
+
"transform": {
|
|
73
|
+
"^.+\\.ts$": [
|
|
74
|
+
"ts-jest",
|
|
75
|
+
{
|
|
76
|
+
"tsconfig": "tsconfig.test.json",
|
|
77
|
+
"diagnostics": true
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
"collectCoverageFrom": [
|
|
82
|
+
"src/**/*.ts",
|
|
83
|
+
"!src/index.ts"
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
}
|