
Security News
/Research
Wallet-Draining npm Package Impersonates Nodemailer to Hijack Crypto Transactions
Malicious npm package impersonates Nodemailer and drains wallets by hijacking crypto transactions across multiple blockchains.
@thinman/nest-emitter
Advanced tools
Strongly 💪🏼 Typed Eventemitter Module For Nestjs Framework 🦁
Ever wondered if there is a way to have a strongly typed way to use event emitter names ?
Ever wondered why your event emitter is not working as intended and then realized that there was a typo on your events name? if so, then this ones for you :smile: .
By Declaring events using a simple interface mapping event names to their payloads to get stricter versions of emit
, on
, and other common EventEmitter APIs.
and not only that, it will work with any kind of EventEmitter
that implements NodeJS.Events
.
npm install nest-emitter
or
yarn add nest-emitter
As Normal Import NestEmitterModule
into your root module (aka AppModule
)
The NestEmitterModule#forRoot(emitter: NodeJS.Events)
takes any event emitter that implements NodeJS.Events
.
For simplicity I will use nodejs built-in eventemitter, but of course you can use whatever you need.
// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { NestEmitterModule } from 'nest-emitter';
import { EventEmitter } from 'events';
@Module({
imports: [NestEmitterModule.forRoot(new EventEmitter())],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Now it's time to define our events, let's add two events
one called notification
and it's payload will be a string.
and another one is newRequest
and it's payload will be function that has one arg of type Request
.
// app.events.ts
interface AppEvents {
notification: string;
// as a side note: that is equivalent to
// newRequest: Express.Request;
newRequest: (req: Express.Request) => void;
}
After that let's bring up our secret weapon; the StrictEventEmitter
!
// app.events.ts
import { EventEmitter } from 'events';
import { StrictEventEmitter } from 'nest-emitter';
interface AppEvents {
notification: string;
newRequest: (req: Express.Request) => void;
}
export type MyEventEmitter = StrictEventEmitter<EventEmitter, AppEvents>;
good good, now let's use it.
:+1: TIP: Keep all of your events in a separate file like
{prefix}.events.ts
.
I will use it to send a notification when we receive a request
// app.controller.ts
import { Get, Controller, Req } from '@nestjs/common';
import { AppService } from './app.service';
import { InjectEventEmitter } from 'nest-emitter';
import { MyEventEmitter } from 'app.events';
@Controller()
export class AppController {
constructor(
private readonly appService: AppService,
@InjectEventEmitter() private readonly emitter: MyEventEmitter,
) {}
@Get()
root(@Req() req: Express.Request): string {
this.emitter.emit('notification', 'new req');
// this will throw an error at compile-time
// as `notification` event only accepts `string`
// this.emitter.emit('notification', 1234);
this.emitter.emit('newRequest', req);
return this.appService.root();
}
}
Did you notice @InjectEventEmitter()
? you guessed it, it's a helper decorator to get the instance of the underlying eventemitter.
now on the other side
import { Injectable, OnModuleInit } from '@nestjs/common';
import { InjectEventEmitter } from 'nest-emitter';
import { MyEventEmitter } from 'app.events';
@Injectable()
export class AppService implements OnModuleInit {
constructor(@InjectEventEmitter() private readonly emitter: MyEventEmitter) {}
onModuleInit() {
this.emitter.on('notification', async msg => await this.onNotification(msg));
this.emitter.on('newRequest', async req => await this.onRequest(req));
}
root(): string {
return 'Hello World!';
}
private async onNotification(msg: string) {
console.log(`OnNotification: ${msg}`);
}
private async onRequest(req: Express.Request) {
console.log(`OnRequest from: ${req['ip']}`);
}
}
And that's it! Easy? now let's dive in.
Event records are interfaces or object types that map event names to the event's payload types. In the following example, three events are declared:
interface AppEvents {
req: (request: Express.Request, response: Express.Response) => void;
done: void;
conn: Connection;
}
Each event shows one of three ways to type the event payloads:
void
: A shortcut for an event with no payload, i.e. () => void
(p: number) => void
can be written as just number
.The default export. A generic type that takes three type parameters:
The third parameter is handy when typing web sockets where client and server can listen to and emit different events. For example, if you are using socket.io:
// create types representing the server side and client
// side sockets
export type ServerSocket =
StrictEventEmitter<SocketIO.Socket, EventsFromServer, EventsFromClient>;
export type ClientSocket =
StrictEventEmitter<SocketIOClient.Socket, EventsFromClient, EventsFromServer>;
// elsewhere on server
let serverSocket: ServerSocket = new SocketIO.Socket();
serverSocket.on(/* only events that are sent from the client are allowed */, ...)
serverSocket.emit(/* only events that are emitted from the server are allowed */, ...)
// elsewhere on client
let clientSocket: ClientSocket = new SocketIOClient.Socket();
clientSocket.on(/* only events that are sent from the server are allowed */, ...)
clientSocket.emit(/* only events that are emitted from the client are allowed */, ...)
For more information about StrictEventEmitter
see @bterlson 's library
See CHANGELOG for more information.
You are welcome to contribute to this project, just open a PR.
See also the list of contributors who participated in this project.
This project is licensed under the MIT License - see the LICENSE.md file for details.
FAQs
Strongly Typed Eventemitter Module For Nestjs Framework
The npm package @thinman/nest-emitter receives a total of 11 weekly downloads. As such, @thinman/nest-emitter popularity was classified as not popular.
We found that @thinman/nest-emitter demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
/Research
Malicious npm package impersonates Nodemailer and drains wallets by hijacking crypto transactions across multiple blockchains.
Security News
This episode explores the hard problem of reachability analysis, from static analysis limits to handling dynamic languages and massive dependency trees.
Security News
/Research
Malicious Nx npm versions stole secrets and wallet info using AI CLI tools; Socket’s AI scanner detected the supply chain attack and flagged the malware.