├── .nvmrc ├── CNAME ├── src ├── dashboard │ └── .gitkeep ├── structures │ ├── ping.dto.ts │ ├── message.dto.ts │ ├── media.s3.dto.ts │ ├── base.dto.ts │ ├── environment.dto.ts │ ├── calls.dto.ts │ ├── pagination.dto.ts │ ├── presence.dto.ts │ ├── properties.dto.ts │ ├── auth.dto.ts │ ├── media.dto.ts │ ├── sessions.deprecated.dto.ts │ ├── contacts.dto.ts │ ├── server.dto.ts │ ├── enums.dto.ts │ ├── groups.dto.ts │ ├── status.dto.ts │ ├── channels.dto.ts │ ├── webhooks.config.dto.ts │ ├── labels.dto.ts │ ├── chatting.buttons.dto.ts │ ├── chats.dto.ts │ └── responses.dto.ts ├── core │ ├── engines │ │ ├── gows │ │ │ ├── store │ │ │ │ ├── GowsAuth.ts │ │ │ │ ├── GowsAuthSimple.ts │ │ │ │ └── GowsAuthFactoryCore.ts │ │ │ ├── types.ts │ │ │ ├── EventsFromObservable.ts │ │ │ ├── GowsBootstrap.ts │ │ │ ├── GowsEventStreamObservable.ts │ │ │ └── GowsSubprocess.ts │ │ ├── noweb │ │ │ ├── store │ │ │ │ ├── ILabelsRepository.ts │ │ │ │ ├── IContactRepository.ts │ │ │ │ ├── IGroupRepository.ts │ │ │ │ ├── sqlite3 │ │ │ │ │ ├── Sqlite3LabelsRepository.ts │ │ │ │ │ ├── Sqlite3ContactRepository.ts │ │ │ │ │ ├── Sqlite3GroupRepository.ts │ │ │ │ │ ├── NOWEBSqlite3KVRepository.ts │ │ │ │ │ ├── Sqlite3ChatRepository.ts │ │ │ │ │ ├── Sqlite3LabelAssociationsRepository.ts │ │ │ │ │ ├── Sqlite3SchemaValidation.ts │ │ │ │ │ ├── Sqlite3MessagesRepository.ts │ │ │ │ │ └── Sqlite3Storage.ts │ │ │ │ ├── metadata.ts │ │ │ │ ├── IChatRepository.ts │ │ │ │ ├── ILabelAssociationsRepository.ts │ │ │ │ ├── NowebStorageFactoryCore.ts │ │ │ │ ├── IMessagesRepository.ts │ │ │ │ ├── sql │ │ │ │ │ ├── SqlChatMethods.ts │ │ │ │ │ ├── SqlLabelAssociationsMethods.ts │ │ │ │ │ └── SqlMessagesMethods.ts │ │ │ │ ├── INowebStorage.ts │ │ │ │ ├── INowebStore.ts │ │ │ │ └── NowebInMemoryStore.ts │ │ │ ├── NowebAuthFactoryCore.ts │ │ │ ├── utils.ts │ │ │ └── noweb.buttons.ts │ │ └── webjs │ │ │ ├── _WAHA.js │ │ │ ├── _Paginator.js │ │ │ └── LocalAuth.ts │ ├── abc │ │ ├── DataStore.ts │ │ ├── EngineBootstrap.ts │ │ └── WAHAHealthCheckService.ts │ ├── storage │ │ ├── sql │ │ │ ├── IJsonQuery.ts │ │ │ ├── ISQLEngine.ts │ │ │ └── schemas.ts │ │ ├── ISessionAuthRepository.ts │ │ ├── ISessionMeRepository.ts │ │ ├── Schema.ts │ │ ├── sqlite3 │ │ │ ├── Sqlite3JsonQuery.ts │ │ │ ├── Sqlite3KVRepository.ts │ │ │ ├── Sqlite3Engine.ts │ │ │ ├── Sqlite3SessionMeRepository.ts │ │ │ └── Sqlite3SessionWorkerRepository.ts │ │ ├── ISessionWorkerRepository.ts │ │ ├── ISessionConfigRepository.ts │ │ ├── LocalStore.ts │ │ ├── LocalSessionAuthRepository.ts │ │ ├── LocalStoreCore.ts │ │ └── LocalSessionConfigRepository.ts │ ├── media │ │ ├── MediaStorageFactory.ts │ │ ├── IMediaManager.ts │ │ ├── IMediaEngineProcessor.ts │ │ ├── local │ │ │ ├── MediaLocalStorageConfig.ts │ │ │ ├── MediaLocalStorageFactory.ts │ │ │ ├── media.local.storage.module.ts │ │ │ └── MediaLocalStorage.ts │ │ └── IMediaStorage.ts │ ├── QR.ts │ ├── health │ │ └── WAHAHealthCheckServiceCore.ts │ ├── helpers.ts │ ├── exceptions.ts │ ├── config │ │ ├── SwaggerConfigServiceCore.ts │ │ ├── DashboardConfigServiceCore.ts │ │ ├── GowsEngineConfigService.ts │ │ ├── EngineConfigService.ts │ │ └── WebJSEngineConfigService.ts │ ├── integrations │ │ └── webhooks │ │ │ └── WebhookConductor.ts │ └── helpers.proxy.ts ├── nestjs │ ├── ws │ │ ├── ws.ts │ │ └── WebsocketHeartbeatJob.ts │ ├── params │ │ ├── MessageIdApiParam.ts │ │ ├── ChatIdApiParam.ts │ │ └── SessionApiParam.ts │ ├── validation │ │ ├── BooleanString.ts │ │ └── IsDynamicObject.ts │ ├── pipes │ │ ├── WAHAValidationPipe.ts │ │ └── SessionPipe.ts │ ├── BufferJsonReplacerInterceptor.ts │ ├── ApiFileAcceptHeader.ts │ ├── BufferResponseInterceptor.ts │ └── AllExceptionsFilter.ts ├── utils │ ├── string.ts │ ├── reactive │ │ ├── ops │ │ │ ├── exclude.ts │ │ │ └── onlyEvent.ts │ │ ├── complete.ts │ │ └── SwitchObservable.ts │ ├── ids.ts │ ├── files.ts │ ├── DefaultMap.ts │ ├── events.ts │ ├── promiseTimeout.ts │ ├── SingleDelayedJobRunner.ts │ ├── SinglePeriodicJobRunner.ts │ ├── logging.ts │ └── Paginator.ts ├── api │ ├── ping.controller.ts │ ├── version.controller.ts │ ├── health.controller.ts │ ├── screenshot.controller.ts │ ├── status.controller.ts │ ├── presence.controller.ts │ ├── auth.controller.ts │ ├── contacts.controller.ts │ └── channels.controller.ts ├── helpers.ts └── version.ts ├── .yarnrc ├── .eslintignore ├── logo.png ├── examples ├── python │ ├── requirements.txt │ ├── whatsapp_download_files_bot.py │ └── whatsapp_echo_bot.py ├── waha.jpg ├── example.pdf ├── video.mp4 ├── dev.likeapro.jpg └── dev.likeapro.opus ├── .yarnrc.yml ├── tests └── smoke │ ├── goss_wait.yaml │ └── goss.yaml ├── tsconfig.build.json ├── CHANGELOG.md ├── nest-cli.json ├── .github ├── ISSUE_TEMPLATE │ ├── question.md │ ├── feature_request.md │ └── bug_report.md ├── gh-team-labels.yml ├── clear-gh-runs.sh └── FUNDING.yml ├── .prettierrc ├── entrypoint.sh ├── tsconfig.json ├── scripts ├── waha-update.sh └── waha-run.sh ├── .dockerignore ├── .gitignore ├── docker-compose ├── n8n │ └── docker-compose.yaml └── docker-compose.workers.yaml ├── .eslintrc.js ├── .precommit └── validate_commit_message.py ├── .pre-commit-config.yaml ├── Makefile └── docker-compose.yaml /.nvmrc: -------------------------------------------------------------------------------- 1 | v22.8 2 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | waha.devlike.pro -------------------------------------------------------------------------------- /src/dashboard/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | network-timeout 60000 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | src/core/engines/gows/grpc/* 2 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/waha/core/logo.png -------------------------------------------------------------------------------- /examples/python/requirements.txt: -------------------------------------------------------------------------------- 1 | flask~=1.0 2 | requests~=2.0 3 | markupsafe==2.0.1 4 | -------------------------------------------------------------------------------- /examples/waha.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/waha/core/examples/waha.jpg -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | yarnPath: .yarn/releases/yarn-3.6.3.cjs 4 | -------------------------------------------------------------------------------- /examples/example.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/waha/core/examples/example.pdf -------------------------------------------------------------------------------- /examples/video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/waha/core/examples/video.mp4 -------------------------------------------------------------------------------- /src/structures/ping.dto.ts: -------------------------------------------------------------------------------- 1 | export class PingResponse { 2 | message: string = 'pong'; 3 | } 4 | -------------------------------------------------------------------------------- /examples/dev.likeapro.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/waha/core/examples/dev.likeapro.jpg -------------------------------------------------------------------------------- /examples/dev.likeapro.opus: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marinaglancy/waha/core/examples/dev.likeapro.opus -------------------------------------------------------------------------------- /tests/smoke/goss_wait.yaml: -------------------------------------------------------------------------------- 1 | port: 2 | tcp:3000: 3 | listening: true 4 | ip: 5 | - 127.0.0.1 6 | -------------------------------------------------------------------------------- /src/core/engines/gows/store/GowsAuth.ts: -------------------------------------------------------------------------------- 1 | export interface GowsAuth { 2 | address(): string; 3 | dialect(): string; 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | You can find changelog on 4 | [the changelog page](https://waha.devlike.pro/docs/help/changelog/) 5 | -------------------------------------------------------------------------------- /src/core/abc/DataStore.ts: -------------------------------------------------------------------------------- 1 | export abstract class DataStore { 2 | abstract init(sessionName?: string): Promise; 3 | 4 | abstract close(): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /src/nestjs/ws/ws.ts: -------------------------------------------------------------------------------- 1 | import { WebSocket as WSWebSocket } from 'ws'; 2 | 3 | export interface WebSocket extends WSWebSocket { 4 | id?: string; 5 | isAlive?: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /src/core/storage/sql/IJsonQuery.ts: -------------------------------------------------------------------------------- 1 | export interface IJsonQuery { 2 | filter(field: string, key: string): string; 3 | sortBy(field: string, sortBy: string, direction: string): string; 4 | } 5 | -------------------------------------------------------------------------------- /tests/smoke/goss.yaml: -------------------------------------------------------------------------------- 1 | http: 2 | http://localhost:3000/api/server/version/: 3 | status: 200 4 | allow-insecure: true 5 | no-follow-redirects: true 6 | timeout: 5000 7 | body: ['version'] 8 | -------------------------------------------------------------------------------- /src/core/storage/ISessionAuthRepository.ts: -------------------------------------------------------------------------------- 1 | export abstract class ISessionAuthRepository { 2 | abstract init(sessionName?: string): Promise; 3 | 4 | abstract clean(sessionName: string): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /src/utils/string.ts: -------------------------------------------------------------------------------- 1 | export function noSlashAtTheEnd(value: string): string { 2 | if (!value) { 3 | return value; 4 | } 5 | if (value.startsWith('/')) { 6 | return value.slice(1); 7 | } 8 | return value; 9 | } 10 | -------------------------------------------------------------------------------- /src/utils/reactive/ops/exclude.ts: -------------------------------------------------------------------------------- 1 | import { filter } from 'rxjs'; 2 | 3 | /** 4 | * Just as filter, but opposite 5 | */ 6 | export function exclude(predicate: (...args) => boolean) { 7 | return filter((...args) => !predicate(...args)); 8 | } 9 | -------------------------------------------------------------------------------- /src/utils/ids.ts: -------------------------------------------------------------------------------- 1 | import { ulid } from 'ulid'; 2 | 3 | /** 4 | * Generate prefix uuid (but remove -) 5 | * @param prefix 6 | */ 7 | export function generatePrefixedId(prefix: string) { 8 | return `${prefix}_${ulid().toLowerCase()}`; 9 | } 10 | -------------------------------------------------------------------------------- /src/core/media/MediaStorageFactory.ts: -------------------------------------------------------------------------------- 1 | import { IMediaStorage } from '@waha/core/media/IMediaStorage'; 2 | import { Logger } from 'pino'; 3 | 4 | export abstract class MediaStorageFactory { 5 | abstract build(name: string, logger: Logger): Promise; 6 | } 7 | -------------------------------------------------------------------------------- /nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "@nestjs/schematics", 3 | "sourceRoot": "src", 4 | "compilerOptions": { 5 | "plugins": ["@nestjs/swagger"], 6 | "assets": ["dashboard/**", "core/engines/webjs/*", "plus/engines/webjs/*"], 7 | "watchAssets": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/nestjs/params/MessageIdApiParam.ts: -------------------------------------------------------------------------------- 1 | import { ApiParam } from '@nestjs/swagger'; 2 | 3 | export const MessageIdApiParam = ApiParam({ 4 | name: 'messageId', 5 | required: true, 6 | type: 'string', 7 | description: 'Message ID', 8 | example: 'true_123456789@c.us_BAE6A33293978B16', 9 | }); 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: I have a question about the project or feature 4 | title: '[Question] ' 5 | labels: 'question' 6 | assignees: '' 7 | --- 8 | 9 | 👉 Kindly use 10 | [GitHub Discussions](https://github.com/devlikeapro/waha/discussions) to ask 11 | questions! 12 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all", 4 | "endOfLine": "auto", 5 | "arrowParens": "always", 6 | "bracketSpacing": true, 7 | "useTabs": false, 8 | "tabWidth": 2, 9 | "semi": true, 10 | "quoteProps": "as-needed", 11 | "proseWrap": "always", 12 | "printWidth": 80 13 | } 14 | -------------------------------------------------------------------------------- /src/utils/files.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-var-requires 2 | const fs = require('fs-extra'); 3 | 4 | export async function fileExists(filepath: string) { 5 | try { 6 | await fs.access(filepath, fs.constants.F_OK); 7 | } catch (error) { 8 | return false; 9 | } 10 | return true; 11 | } 12 | -------------------------------------------------------------------------------- /src/core/abc/EngineBootstrap.ts: -------------------------------------------------------------------------------- 1 | export interface EngineBootstrap { 2 | bootstrap(): Promise; 3 | 4 | shutdown(): Promise; 5 | } 6 | 7 | export class NoopEngineBootstrap implements EngineBootstrap { 8 | async bootstrap(): Promise { 9 | return; 10 | } 11 | 12 | async shutdown(): Promise { 13 | return; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/utils/reactive/ops/onlyEvent.ts: -------------------------------------------------------------------------------- 1 | import { filter, pipe } from 'rxjs'; 2 | import { map } from 'rxjs/operators'; 3 | 4 | interface EventValue { 5 | event: string; 6 | data: T; 7 | } 8 | 9 | export function onlyEvent(event: any) { 10 | return pipe( 11 | filter>((obj) => obj.event === event), 12 | map((event) => event.data), 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /src/utils/DefaultMap.ts: -------------------------------------------------------------------------------- 1 | export class DefaultMap extends Map { 2 | private readonly factory: (key: K) => T; 3 | 4 | constructor(factory: (key: K) => T) { 5 | super(); 6 | this.factory = factory; 7 | } 8 | 9 | get(key: K): T { 10 | if (!this.has(key)) { 11 | this.set(key, this.factory(key)); 12 | } 13 | return super.get(key); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Calculate UV_THREADPOOL_SIZE based on number of CPUs 4 | cpus=$(node -e "const os = require('os'); console.log(os.cpus().length);") 5 | uv_threadpool_size=$(($cpus * 1)) 6 | 7 | # Set UV_THREADPOOL_SIZE as an environment variable 8 | export UV_THREADPOOL_SIZE="${UV_THREADPOOL_SIZE:-$uv_threadpool_size}" 9 | 10 | # Start your application using yarn 11 | exec node dist/main 12 | -------------------------------------------------------------------------------- /src/core/storage/ISessionMeRepository.ts: -------------------------------------------------------------------------------- 1 | import { MeInfo } from '../../structures/sessions.dto'; 2 | 3 | export abstract class ISessionMeRepository { 4 | abstract upsertMe(sessionName: string, me: MeInfo | null): Promise; 5 | 6 | abstract getMe(sessionName: string): Promise; 7 | 8 | abstract removeMe(sessionName: string): Promise; 9 | 10 | abstract init(): Promise; 11 | } 12 | -------------------------------------------------------------------------------- /src/structures/message.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | import { 3 | ChatIdProperty, 4 | MessageIdOnlyProperty, 5 | } from '@waha/structures/properties.dto'; 6 | 7 | export class ReplyToMessage { 8 | @MessageIdOnlyProperty() 9 | id: string; 10 | 11 | @ChatIdProperty() 12 | participant?: string; 13 | 14 | @ApiProperty({ 15 | example: 'Hello!', 16 | }) 17 | body?: string; 18 | } 19 | -------------------------------------------------------------------------------- /src/core/storage/Schema.ts: -------------------------------------------------------------------------------- 1 | export class Field { 2 | constructor( 3 | public fieldName: string, 4 | public type: string, 5 | ) {} 6 | } 7 | 8 | export class Index { 9 | constructor( 10 | public name: string, 11 | public columns: string[], 12 | ) {} 13 | } 14 | 15 | export class Schema { 16 | constructor( 17 | public name: string, 18 | public columns: Field[], 19 | public indexes: Index[], 20 | ) {} 21 | } 22 | -------------------------------------------------------------------------------- /src/structures/media.s3.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | 3 | export class S3MediaData { 4 | @ApiProperty({ 5 | description: 'The name of the S3 bucket', 6 | example: 'my-bucket', 7 | }) 8 | Bucket: string; 9 | 10 | @ApiProperty({ 11 | description: 'The key of the object in the S3 bucket', 12 | example: 'default/false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA.oga', 13 | }) 14 | Key: string; 15 | } 16 | -------------------------------------------------------------------------------- /src/nestjs/params/ChatIdApiParam.ts: -------------------------------------------------------------------------------- 1 | import { ApiParam } from '@nestjs/swagger'; 2 | 3 | export const ChatIdApiParam = ApiParam({ 4 | name: 'chatId', 5 | required: true, 6 | type: 'string', 7 | description: 'Chat ID', 8 | example: '123456789@c.us', 9 | }); 10 | 11 | export const GroupIdApiParam = ApiParam({ 12 | name: 'id', 13 | required: true, 14 | type: 'string', 15 | description: 'Group ID', 16 | example: '123123123@g.us', 17 | }); 18 | -------------------------------------------------------------------------------- /src/core/QR.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-var-requires 2 | const QRCode = require('qrcode'); 3 | 4 | export class QR { 5 | public raw?: string; 6 | 7 | save(raw?: string) { 8 | this.raw = raw; 9 | } 10 | 11 | async get(): Promise { 12 | const url = await QRCode.toDataURL(this.raw); 13 | const base64 = url.replace(/^data:image\/png;base64,/, ''); 14 | return Buffer.from(base64, 'base64'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/core/engines/noweb/store/ILabelsRepository.ts: -------------------------------------------------------------------------------- 1 | import { Contact } from '@adiwajshing/baileys'; 2 | import { Label } from '@adiwajshing/baileys/lib/Types/Label'; 3 | 4 | export interface ILabelsRepository { 5 | getById(id: string): Promise