@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 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"}
@@ -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
+ }