nestwhats
v2.4.0
Published
A whatsapp-web.js wrapper for NestJS to create WhatsApp bots
Downloads
1,824
Maintainers
Readme
❓ About
NestWhats is a module for NestJS that abstracts methods from whatsapp-web.js to facilitate the creation of bots for WhatsApp.
whatsapp-web.js is a WhatsApp API client that connects through WhatsApp Web browser app using Puppeteer
[!IMPORTANT] It is not guaranteed you will not be blocked by using this method. WhatsApp does not allow bots or unofficial clients on their platform, so this shouldn't be considered totally safe.
⬇️ Installation
[!NOTE] NodeJS
v20+is required
$ npm i nestwhats whatsapp-web.js
$ yarn add nestwhats whatsapp-web.js
$ pnpm add nestwhats whatsapp-web.js⚙️ Usage
Single client
Import NestWhatsModule into the root AppModule:
import { NestWhatsModule } from 'nestwhats';
import { Module } from '@nestjs/common';
import { AppUpdate } from './app.update';
@Module({
imports: [
NestWhatsModule.forRoot({
prefix: '!'
})
],
providers: [AppUpdate]
})
export class AppModule {}Use @On/@Once decorators to handle whatsapp-web.js events, and inject the Client directly:
import { Injectable, Logger } from '@nestjs/common';
import { Context, On, Once, ContextOf } from 'nestwhats';
import { Client } from 'whatsapp-web.js';
@Injectable()
export class AppUpdate {
private readonly logger = new Logger(AppUpdate.name);
public constructor(private readonly client: Client) {}
@Once('ready')
public onReady() {
this.logger.log(`Bot logged in as ${this.client.info.pushname}`);
}
@On('message_create')
public onMessage(@Context() [message]: ContextOf<'message_create'>) {
this.logger.log(message);
}
}Event options
Both @On and @Once accept an optional second argument to filter which clients trigger the listener.
| Option | Type | Description |
|----------|------------------------|----------------------------------------------------------|
| client | string \| string[] | Client name(s) that should trigger this listener. When omitted, all clients trigger it. |
Async configuration
NestWhatsModule.forRootAsync({
imports: [ConfigModule],
useFactory: (config: ConfigService) => ({
prefix: config.get('BOT_PREFIX'),
}),
inject: [ConfigService],
})👥 Multiple Clients
Register each client independently with its own forRoot call. NestJS deduplicates shared infrastructure automatically.
import { NestWhatsModule } from 'nestwhats';
import { Module } from '@nestjs/common';
@Module({
imports: [
NestWhatsModule.forRoot({ name: 'PERSONAL', prefix: '!' }),
NestWhatsModule.forRoot({ name: 'BUSINESS', prefix: '/' }),
],
})
export class AppModule {}Inject a specific client using @InjectClient(name):
import { Injectable } from '@nestjs/common';
import { InjectClient } from 'nestwhats';
import { Client } from 'whatsapp-web.js';
@Injectable()
export class MyService {
public constructor(
@InjectClient('PERSONAL') private readonly personal: Client,
@InjectClient('BUSINESS') private readonly business: Client,
) {}
public async sendFromBusiness(chatId: string, text: string) {
await this.business.sendMessage(chatId, text);
}
}For async registration of a named client, pass name as a static option:
NestWhatsModule.forRootAsync({
name: 'BUSINESS',
imports: [ConfigModule],
useFactory: (config: ConfigService) => ({
prefix: config.get('BUSINESS_PREFIX'),
}),
inject: [ConfigService],
})[!NOTE] When registering a single unnamed client,
namedefaults to'default'and theClienttoken remains available for injection without@InjectClient, preserving backward compatibility.
Filtering events by client
When using multiple clients, listeners fire on all of them by default. Use the client option to restrict a listener to one or more specific clients:
import { Injectable } from '@nestjs/common';
import { On, Once, Context, ContextOf } from 'nestwhats';
@Injectable()
export class AppUpdate {
// fires on every client
@On('message_create')
public onAnyMessage(@Context() [message]: ContextOf<'message_create'>) {}
// fires only on PERSONAL
@On('message_create', { client: 'PERSONAL' })
public onPersonalMessage(@Context() [message]: ContextOf<'message_create'>) {}
// fires on PERSONAL and BUSINESS, but not a third client
@On('message_create', { client: ['PERSONAL', 'BUSINESS'] })
public onTwoClients(@Context() [message]: ContextOf<'message_create'>) {}
// once listener scoped to a single client
@Once('ready', { client: 'BUSINESS' })
public onBusinessReady() {}
}📜 Commands
Register a command handler with the @Command decorator. The global prefix defined in forRoot applies to all commands by default.
import { Injectable } from '@nestjs/common';
import { Command, Message, Author } from 'nestwhats';
import { Message as WWebMessage } from 'whatsapp-web.js';
@Injectable()
export class BotUpdate {
@Command({ name: 'ping', description: 'Replies with pong' })
public async ping(@Message() message: WWebMessage) {
await message.reply('pong!');
}
@Command({ name: 'hello', description: 'Greets the author', aliases: ['hi', 'hey'] })
public async hello(@Author() author: string) {
console.log(`Hello, ${author}!`);
}
}Per-command prefix
Override the global prefix for a specific command using the prefix option:
@Command({ name: 'start', description: 'Start command', prefix: '/' })
public async start(@Message() message: WWebMessage) {
// responds to "/start" regardless of the global prefix
await message.reply('Starting...');
}Filtering commands by client
Use the client option to restrict a command to one or more specific clients. Commands without client respond on all clients.
// responds on every client
@Command({ name: 'ping', description: 'Ping' })
public async ping(@Message() message: WWebMessage) {}
// responds only on PERSONAL
@Command({ name: 'status', description: 'Personal status', client: 'PERSONAL' })
public async status(@Message() message: WWebMessage) {}
// responds on PERSONAL and BUSINESS, but not a third client
@Command({ name: 'info', description: 'Info', client: ['PERSONAL', 'BUSINESS'] })
public async info(@Message() message: WWebMessage) {}Command options
| Option | Type | Description |
|---------------|------------------------|---------------------------------------------------------------------------|
| name | string | The command name (matched after the prefix) |
| description | string | A short description of the command |
| aliases | string[] | Additional names that trigger the same command |
| prefix | string | Overrides the global prefix for this command only |
| client | string \| string[] | Client name(s) that should handle this command. When omitted, all clients handle it. |
ParseArgsPipe
ParseArgsPipe requires class-transformer and class-validator, which are optional peer dependencies. Install them only if you use the pipe:
$ npm i class-transformer class-validator
$ yarn add class-transformer class-validator
$ pnpm add class-transformer class-validator📝 To-Do
- [ ] Docs
- [ ] GH Pages or Wiki
- [ ] JSDoc in code
- [ ] New Providers
📖 License
🗞️ Credits
This project is inspired in Necord - 🤖 A module for creating Discord bots using NestJS, based on Discord.js
NestWhats is an adaptation of Necord to work with whatsapp-web.js
I NedcloarBR am a contributor to NecordWant to see your name on this list? - see the Contribution page.
