diff --git a/docker-compose.yaml b/docker-compose.yaml
index 23fe3830..4fe7b0bd 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -30,3 +30,15 @@ services:
- WHATSAPP_SWAGGER_PASSWORD=123
- WHATSAPP_API_HOSTNAME=localhost
restart: always
+
+ mongodb:
+ image: mongo
+ container_name: mongodb
+ ports:
+ - '27017:27017/tcp'
+ volumes:
+ - mongodb_data:/data/db
+ restart: always
+
+volumes:
+ mongodb_data: {}
diff --git a/docs/site/content/en/docs/how-to/config/index.md b/docs/site/content/en/docs/how-to/config/index.md
index 189c1794..b5ed46ac 100644
--- a/docs/site/content/en/docs/how-to/config/index.md
+++ b/docs/site/content/en/docs/how-to/config/index.md
@@ -38,6 +38,8 @@ The following environment variables can be used to configure the WAHA.
response.
- `WHATSAPP_START_SESSION=session1,session2`: This variable can be used to start sessions with the specified names right
after launching the API. Separate session names with a comma.
+- Also read more about [Sessions ->]({{< relref "/docs/how-to/sessions" >}})
+- Also read more about [Session Storages on the dedicated page ->]({{< relref "/docs/how-to/storages#sessions" >}})
### Swagger
- `WHATSAPP_SWAGGER_CONFIG_ADVANCED=true` - enables advanced configuration options for Swagger documentation - you can customize host, port and base URL for the requests.
@@ -66,14 +68,18 @@ Read more about it on [**Session page** ->]({{< relref "/docs/how-to/sessions#co
Keep in mind that session's proxy configuration takes precedence over proxy configuration set by environment variables!
-### Security 
+### Security
+Security is available in [WAHA Plus ]({{< relref "/docs/how-to/plus-version" >}}) only.
+
- `WHATSAPP_API_KEY=mysecret`: If you set this variable, you must include the `X-Api-Key: mysecret` header in all
requests to the API. This will protect the API with a secret code.
- `WHATSAPP_SWAGGER_USERNAME=admin` and `WHATSAPP_SWAGGER_PASSWORD=admin`: These variables can be used to protect the
Swagger panel with `admin / admin` credentials. This does not affect API access.
+Read more about security settings for Swagger and API on [**Security page** ->]({{< relref "/docs/how-to/security" >}}).
-### Files 
+### Files
+Files configuration is available in [WAHA Plus ]({{< relref "/docs/how-to/plus-version" >}}) only.
The following environment variables can be used to configure the file storage options for the WAHA:
@@ -85,8 +91,11 @@ The following environment variables can be used to configure the file storage op
- Under the hood, it sets `WHATSAPP_FILES_MIMETYPES=mimetype/ignore-all-media` to ignore all media files.
- `WHATSAPP_FILES_LIFETIME`: This variable can be used to set the time (in seconds) after which files will be removed to
free up space. The default value is `180`.
+ - Set this variable to `0` to disable the file lifetime.
- `WHATSAPP_FILES_FOLDER`: This variable can be used to set the folder where files from chats (images, voice messages)
will be stored. The default value is `/tmp/whatsapp-files`.
+ - The folder must be mounted to the host machine to keep the files between container restarts. [ Read more about how to persist files ->]({{< relref "/docs/how-to/storages#media" >}})
+- Also read more about [Media Storages on the dedicated page ->]({{< relref "/docs/how-to/storages#media" >}})
💡 Even if WAHA doesn't process the message media because of `WHATSAPP_FILES_MIMETYPES` or `WHATSAPP_DOWNLOAD_MEDIA`
you'll get a webhook event with `hasMedia: True` field, but with no `media.url`.
diff --git a/docs/site/content/en/docs/how-to/sessions/index.md b/docs/site/content/en/docs/how-to/sessions/index.md
index 7f07e6be..3a098d6a 100644
--- a/docs/site/content/en/docs/how-to/sessions/index.md
+++ b/docs/site/content/en/docs/how-to/sessions/index.md
@@ -298,28 +298,8 @@ configure autostart options so when the docker container restarts - it restores
### Session persistent
-#### File storage
-If you want to save your session and do not scan QR code everytime when you launch WAHA - connect a local file storage
-to the container. WAHA stores authentication information in the directory and reuses it after restart.
-
-[Attach volume](https://docs.docker.com/storage/volumes/) part to the command:
-
-```bash
--v `pwd`/.sessions:/app/.sessions
-```
-
-The full command would be:
-
-```bash
-docker run -d -v `pwd`/.sessions:/app/.sessions -p 3000:3000/tcp --name whatsapp-http-api devlikeapro/whatsapp-http-api-plus
-```
-
-#### Remote storage 
-
-If you're interested in using some "remote" storage (like Redis or other Databases) to save sessions - please create an
-issue on GitHub.
-
-For instances, it may be useful if you run WAHA in a cluster of servers and do not have shared file storage
+If you want to save your session and do not scan QR code everytime when you launch WAHA -
+[connect the session storage to the container ->]({{< relref "/docs/how-to/storages#sessions" >}})
### Autostart
If you don't want to call `POST /api/sessions/start` for every session each time when the container restart -
diff --git a/docs/site/content/en/docs/how-to/storages/index.md b/docs/site/content/en/docs/how-to/storages/index.md
new file mode 100644
index 00000000..9b257744
--- /dev/null
+++ b/docs/site/content/en/docs/how-to/storages/index.md
@@ -0,0 +1,139 @@
+---
+title: "Storages"
+description: "Storages"
+lead: ""
+date: 2020-10-06T08:48:45+00:00
+lastmod: 2020-10-06T08:48:45+00:00
+draft: false
+images: [ ]
+weight: 700
+---
+There are several storages that are used by the WAHA, below you can find the list of them and the way to configure them.
+1. [Sessions](#sessions) - used to store the session data, such as authentication information, configuration, and other data that is required to keep the session alive and connected to WhatsApp.
+2. [Media](#media) - used to store the media files, such as images, videos, and other files that are received from the WhatsApp instance.
+
+Storages are available in [WAHA Plus ]({{< relref "/docs/how-to/plus-version" >}}) only.
+
+## Sessions
+The "Sessions" storage is used to store the session data, such as authentication information, configuration,
+and other data that is required to keep the session alive and connected to WhatsApp.
+
+If you want to save your session and do not scan QR code everytime when you launch WAHA -
+connect the session storage to the container.
+
+For the session storage, you can use the following options:
+1. [Local (files)](#local-files) - the default option, stores the session data in the local storage using files.
+2. [MongoDB](#mongodb) - stores the session data in the MongoDB database.
+
+The following table shows the compatibility of the session storage with the engines:
+
+| | WEBJS | NOWEB | VENOM |
+|---------------|:-----:|:-----:|:-----:|
+| Local (files) | ✔️ | ✔️ | ✔️ |
+| MongoDB | ✔️ | ✔️ | ➖ |
+
+## Sessions - Local (files)
+By default, the WAHA uses the **local storage (files)** to store the session data.
+
+{{< alert icon="💡" text="It's well tested solution even for production" />}}
+
+In order to use the local storage and save the session data between the container restarts,
+you need to mount the volume to the `/app/.sessions` directory using the `-v` option in `docker run` command:
+
+```bash
+-v /path/to/on/host/.sessions:/app/.sessions
+```
+
+The full command to run the WAHA with the local storage and save the session data
+in the current directory and `.sessions` directory:
+```bash
+docker run -v `pwd`/.sessions:/app/.sessions -p 3000:3000/tcp devlikeapro/whatsapp-http-api-plus
+```
+This is the only action you need to do to use the local storage - all session data will be available between the container restarts.
+
+### How it works
+In the host machine, the session data will be stored in the current directory in the `.sessions` directory.
+
+Under the hood, the WAHA stores the session data in the following directory structure:
+```
+.sessions/{engine}/{sessionName}/...
+```
+when you "logout" the session using [POST /api/sessions/logout]({{< relref "/docs/how-to/sessions#logout">}}) or providing `logout: True` in [POST /api/sessions/stop]({{< relref "/docs/how-to/sessions#stop">}})
+it removes the directory with the session data.
+
+
+## Sessions - MongoDB
+If you want to use the MongoDB to store the session data, you need to:
+1. Start the MongoDB server (using docker or any other way). You can either start your own MongoDB server or use the one of cloud providers, like [MongoDB Atlas](https://www.mongodb.com/atlas/database).
+2. Set `WHATSAPP_SESSIONS_MONGO_URL=mongodb://user:password@host:port/` environment variable to connect to the MongoDB server.
+
+
+**We recommend using your own MongoDB server as close as possible to WAHA server** for the best performance and security reasons.
+
+### Example
+First, you need to start MongoDB server:
+```bash
+docker run -d -p 27017:27017 --name mongodb mongo
+```
+
+Then, you need to run the WAHA with the `WHATSAPP_SESSIONS_MONGO_URL` environment variable:
+```bash
+docker run -e WHATSAPP_SESSIONS_MONGO_URL=mongodb://localhost:27017/ -p 3000:3000/tcp devlikeapro/whatsapp-http-api-plus
+```
+
+This is the only action you need to do to use the MongoDB storage -
+all session authentication data will be stored in the MongoDB database.
+
+### How it works
+When you start a session, it stores the session data in the MongoDB database in two databases:
+1. `waha_{engine}` - it saves the session configuration in `sessions` collection with `name: {sessionName}` field.
+2. `waha_{engine}_{sessionName}` - it saves the WhatsApp authentication data and other session data. Each engine saves different data in this database.
+
+When you "logout" the session using [POST /api/sessions/logout]({{< relref "/docs/how-to/sessions#logout">}}) or providing `logout: True` in [POST /api/sessions/stop]({{< relref "/docs/how-to/sessions#stop">}}) it removes those databases or elements from them.
+
+For dealing and troubleshooting with the MongoDB, we recommend using [MongoDB Compass](https://www.mongodb.com/products/tools/compass).
+
+
+
+### MongoDB Atlas
+If you use the [MongoDB Atlas](https://www.mongodb.com/atlas/database) you must grant
+`Atlas Admin` role in **Security => Database Access** before you connect to the database.
+
+For production please consider running the MongoDB server close to the WAHA server for the best performance and security reasons.
+
+## Media
+When your WhatsApp instance receives media files, it stores them in the media storage.
+
+You can use the following options to store the media files:
+1. [Local](#local) - the default option, stores the media files in the local storage using files.
+2. [S3](#s3) - stores the media files in the S3 storage.
+
+Read more about [available configuration options ->]({{}}).
+
+The following table shows the compatibility of the storage with the engines:
+
+| | WEBJS | NOWEB | VENOM |
+|-------|:-----:|:-----:|:-----:|
+| Local | ✔️ | ✔️ | ✔️ |
+| S3 | 🕒 | 🕒 | ➖ |
+
+## Media - Local
+By default, the WAHA uses the **local file storage** to store the media files and those files has a short lifetime (180 seconds).
+So it's your app responsibility to download and store them in a safe persistent place during this time.
+
+### Save media files between the container restarts
+If you want to use the local storage and **save the media files between the container restarts for a long time** - you need to:
+1. Specify a dedicated folder to store the media files using `WHATSAPP_FILES_FOLDER=/app/.media` environment variable
+2. Disable automatic media files cleanup using `WHATSAPP_FILES_LIFETIME=0` environment variable
+3. Connect the volume to the specified folder using the `-v /path/to/files/on/host:/app/.media` option in `docker run` command to the folder specified in `WHATSAPP_FILES_FOLDER` environment variable.
+
+Read more about [available configuration options ->]({{}}).
+
+Here's all the steps in one command:
+```bash
+docker run -v /path/to/on/host/.media:/app/.media -e WHATSAPP_FILES_FOLDER=/app/.media -e WHATSAPP_FILES_LIFETIME=0 -p 3000:3000/tcp devlikeapro/whatsapp-http-api-plus
+```
+
+## Media - S3
+If you're interested in using the S3 storage or any other cloud storage (like [self-hosted S3 - Minio](https://min.io/)),
+please create an issue or vote for the S3 issue in [the GitHub repository](https://github.com/devlikeapro/whatsapp-http-api/issues?q=is%3Aissue+is%3Aopen+S3).
diff --git a/docs/site/content/en/docs/how-to/storages/waha-mongodb.png b/docs/site/content/en/docs/how-to/storages/waha-mongodb.png
new file mode 100644
index 00000000..04a6c1d8
Binary files /dev/null and b/docs/site/content/en/docs/how-to/storages/waha-mongodb.png differ
diff --git a/docs/site/content/en/docs/overview/changelog.md b/docs/site/content/en/docs/overview/changelog.md
index 8f467e6e..f5467efc 100644
--- a/docs/site/content/en/docs/overview/changelog.md
+++ b/docs/site/content/en/docs/overview/changelog.md
@@ -19,6 +19,16 @@ If you wish to get and read Release Notes - read them on one of our platforms, *
You even can **subscribe to get new updates** there!
+## 2024.2
+- Add support for [MongoDB as storage for Session data]({{< relref "/docs/how-to/storages" >}})
+- Support persistent file storage for media files - [now you can save media files between container restarts]({{< relref "/docs/how-to/storages#media" >}})
+- If you set `WHATSAPP_FILES_LIFETIME=0` environment variable - media files will be never deleted.
+
+## 2024.1
+- Implement [Patron Portal](https://portal.devlike.pro/) where you can get your personal API key and manage your perks.
+ - Read more on [Patreon ->](https://www.patreon.com/posts/waha-patron-97637416)
+ - Read more on [Boosty ->](https://boosty.to/wa-http-api/posts/8319079f-dac1-4179-b954-fcc559097c76)
+
## 2024.2
- Listen for browser disconnected and page close events in **WEBJS** engine [#262](https://github.com/devlikeapro/whatsapp-http-api/issues/262)
diff --git a/package.json b/package.json
index e81997a4..28f2cb78 100644
--- a/package.json
+++ b/package.json
@@ -42,6 +42,7 @@
"link-preview-js": "^3.0.4",
"lodash": "^4.17.21",
"mime-types": "^2.1.27",
+ "mongodb": "^6.3.0",
"passport": "^0.6.0",
"passport-headerapikey": "^1.2.2",
"qrcode": "^1.5.1",
@@ -53,7 +54,7 @@
"rxjs": "^7.1.0",
"swagger-ui-express": "^4.1.4",
"venom-bot": "5.0.1",
- "whatsapp-web.js": "https://github.com/pedroslopez/whatsapp-web.js"
+ "whatsapp-web.js": "https://github.com/devlikeapro/whatsapp-web.js#main-fork"
},
"devDependencies": {
"@nestjs/cli": "^9.0.0",
diff --git a/src/api/sessions.controller.ts b/src/api/sessions.controller.ts
index 5b420eac..3cfcd320 100644
--- a/src/api/sessions.controller.ts
+++ b/src/api/sessions.controller.ts
@@ -29,7 +29,7 @@ class SessionsController {
@Post('/start/')
async start(@Body() request: SessionStartRequest): Promise {
const result = await this.manager.start(request);
- await this.manager.sessionStorage.configRepository.save(
+ await this.manager.sessionConfigRepository.save(
request.name,
request.config || null,
);
diff --git a/src/config.service.ts b/src/config.service.ts
index b47ae18a..4e414910 100644
--- a/src/config.service.ts
+++ b/src/config.service.ts
@@ -108,6 +108,10 @@ export class WhatsappConfigService {
return value ? value.split(',') : [];
}
+ getSessionMongoUrl(): string | undefined {
+ return this.configService.get('WHATSAPP_SESSIONS_MONGO_URL', undefined);
+ }
+
getDefaultEngineName(): WAHAEngine {
const value = getEngineName();
if (value in WAHAEngine) {
diff --git a/src/core/abc/DataStore.ts b/src/core/abc/DataStore.ts
new file mode 100644
index 00000000..23e5a723
--- /dev/null
+++ b/src/core/abc/DataStore.ts
@@ -0,0 +1 @@
+export abstract class DataStore {}
diff --git a/src/core/abc/manager.abc.ts b/src/core/abc/manager.abc.ts
index 239ec0f7..a1369d7e 100644
--- a/src/core/abc/manager.abc.ts
+++ b/src/core/abc/manager.abc.ts
@@ -8,12 +8,15 @@ import {
SessionStartRequest,
SessionStopRequest,
} from '../../structures/sessions.dto';
+import { ISessionAuthRepository } from '../storage/ISessionAuthRepository';
+import { ISessionConfigRepository } from '../storage/ISessionConfigRepository';
import { WhatsappSession } from './session.abc';
-import { LocalSessionStorage } from './storage.abc';
import { WebhookConductor } from './webhooks.abc';
export abstract class SessionManager implements OnApplicationShutdown {
- public sessionStorage: LocalSessionStorage;
+ public store: any;
+ public sessionAuthRepository: ISessionAuthRepository;
+ public sessionConfigRepository: ISessionConfigRepository;
protected abstract getEngine(engine: WAHAEngine): typeof WhatsappSession;
diff --git a/src/core/abc/session.abc.ts b/src/core/abc/session.abc.ts
index cd14f998..9c6e2fcf 100644
--- a/src/core/abc/session.abc.ts
+++ b/src/core/abc/session.abc.ts
@@ -3,7 +3,6 @@ import { EventEmitter } from 'events';
import * as fs from 'fs';
import { MessageId } from 'whatsapp-web.js';
-import { OTPRequest, RequestCodeRequest } from '../../structures/auth.dto';
import {
ChatRequest,
CheckNumberStatusQuery,
@@ -47,8 +46,8 @@ import {
import { WASessionStatusBody } from '../../structures/webhooks.dto';
import { NotImplementedByEngineError } from '../exceptions';
import { QR } from '../QR';
+import { DataStore } from './DataStore';
import { MediaManager } from './media.abc';
-import { LocalSessionStorage } from './storage.abc';
const CHROME_PATH = '/usr/bin/google-chrome-stable';
const CHROMIUM_PATH = '/usr/bin/chromium';
@@ -77,7 +76,7 @@ export interface SessionParams {
name: string;
mediaManager: MediaManager;
log: ConsoleLogger;
- sessionStorage: LocalSessionStorage;
+ sessionStore: DataStore;
proxyConfig?: ProxyConfig;
sessionConfig?: SessionConfig;
}
@@ -89,7 +88,7 @@ export abstract class WhatsappSession {
public name: string;
protected mediaManager: MediaManager;
protected log: ConsoleLogger;
- protected sessionStorage: LocalSessionStorage;
+ protected sessionStore: DataStore;
protected proxyConfig?: ProxyConfig;
public sessionConfig?: SessionConfig;
@@ -98,7 +97,7 @@ export abstract class WhatsappSession {
public constructor({
name,
log,
- sessionStorage,
+ sessionStore,
proxyConfig,
mediaManager,
sessionConfig,
@@ -107,7 +106,7 @@ export abstract class WhatsappSession {
this.name = name;
this.proxyConfig = proxyConfig;
this.log = log;
- this.sessionStorage = sessionStorage;
+ this.sessionStore = sessionStore;
this.mediaManager = mediaManager;
this.sessionConfig = sessionConfig;
}
diff --git a/src/core/abc/storage.abc.ts b/src/core/abc/storage.abc.ts
deleted file mode 100644
index 5c4c005a..00000000
--- a/src/core/abc/storage.abc.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { SessionConfig } from '../../structures/sessions.dto';
-
-abstract class SessionConfigRepository {
- abstract save(
- sessionName: string,
- config: SessionConfig | null,
- ): Promise;
-
- abstract get(sessionName: string): Promise;
-}
-
-abstract class SessionStorage {
- protected constructor(public engine: string) {
- this.engine = engine;
- }
-
- abstract init(sessionName?: string): Promise;
-
- abstract clean(sessionName: string): Promise;
-
- abstract getAll(): Promise;
-
- //
- // Repositories
- //
- abstract get configRepository(): SessionConfigRepository;
-}
-
-abstract class LocalSessionStorage extends SessionStorage {
- public sessionsFolder: string;
-
- abstract getFolderPath(sessionName: string): string;
-}
-
-export { LocalSessionStorage, SessionConfigRepository };
diff --git a/src/core/engines/noweb/NowebAuthFactoryCore.ts b/src/core/engines/noweb/NowebAuthFactoryCore.ts
new file mode 100644
index 00000000..df7c1c87
--- /dev/null
+++ b/src/core/engines/noweb/NowebAuthFactoryCore.ts
@@ -0,0 +1,19 @@
+import { useMultiFileAuthState } from '@adiwajshing/baileys';
+import { Store } from 'whatsapp-web.js';
+
+import { DataStore } from '../../abc/DataStore';
+import { LocalStore } from '../../storage/LocalStore';
+
+export class NowebAuthFactoryCore {
+ buildAuth(store: DataStore, name: string) {
+ if (store instanceof LocalStore) return this.buildLocalAuth(store, name);
+ throw new Error(`Unsupported store type '${store.constructor.name}'`);
+ }
+
+ protected async buildLocalAuth(store: LocalStore, name: string) {
+ await store.init(name);
+ const authFolder = store.getSessionDirectory(name);
+ const { state, saveCreds } = await useMultiFileAuthState(authFolder);
+ return { state, saveCreds };
+ }
+}
diff --git a/src/core/session.noweb.core.ts b/src/core/engines/noweb/session.noweb.core.ts
similarity index 95%
rename from src/core/session.noweb.core.ts
rename to src/core/engines/noweb/session.noweb.core.ts
index f35334dc..c799cedc 100644
--- a/src/core/session.noweb.core.ts
+++ b/src/core/engines/noweb/session.noweb.core.ts
@@ -5,6 +5,7 @@ import makeWASocket, {
getKeyAuthor,
isJidGroup,
jidNormalizedUser,
+ makeCacheableSignalKeyStore,
makeInMemoryStore,
PresenceData,
proto,
@@ -19,7 +20,7 @@ import { Agent } from 'https';
import * as lodash from 'lodash';
import { PairingCodeResponse } from 'src/structures/auth.dto';
-import { flipObject, splitAt } from '../helpers';
+import { flipObject, splitAt } from '../../../helpers';
import {
ChatRequest,
CheckNumberStatusQuery,
@@ -35,8 +36,8 @@ import {
MessageVoiceRequest,
SendSeenRequest,
WANumberExistResult,
-} from '../structures/chatting.dto';
-import { ContactQuery, ContactRequest } from '../structures/contacts.dto';
+} from '../../../structures/chatting.dto';
+import { ContactQuery, ContactRequest } from '../../../structures/contacts.dto';
import {
ACK_UNKNOWN,
SECOND,
@@ -45,35 +46,36 @@ import {
WAHAPresenceStatus,
WAHASessionStatus,
WAMessageAck,
-} from '../structures/enums.dto';
+} from '../../../structures/enums.dto';
import {
CreateGroupRequest,
ParticipantsRequest,
-} from '../structures/groups.dto';
+} from '../../../structures/groups.dto';
import {
WAHAChatPresences,
WAHAPresenceData,
-} from '../structures/presence.dto';
-import { WAMessage } from '../structures/responses.dto';
-import { MeInfo } from '../structures/sessions.dto';
-import { BROADCAST_ID, TextStatus } from '../structures/status.dto';
+} from '../../../structures/presence.dto';
+import { WAMessage } from '../../../structures/responses.dto';
+import { MeInfo } from '../../../structures/sessions.dto';
+import { BROADCAST_ID, TextStatus } from '../../../structures/status.dto';
import {
PollVote,
PollVotePayload,
WAMessageAckBody,
-} from '../structures/webhooks.dto';
-import { IEngineMediaProcessor } from './abc/media.abc';
+} from '../../../structures/webhooks.dto';
+import { IEngineMediaProcessor } from '../../abc/media.abc';
import {
ensureSuffix,
WAHAInternalEvent,
WhatsappSession,
-} from './abc/session.abc';
+} from '../../abc/session.abc';
import {
AvailableInPlusVersion,
NotImplementedByEngineError,
-} from './exceptions';
-import { createAgentProxy } from './helpers.proxy';
-import { QR } from './QR';
+} from '../../exceptions';
+import { createAgentProxy } from '../../helpers.proxy';
+import { QR } from '../../QR';
+import { NowebAuthFactoryCore } from './NowebAuthFactoryCore';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const QRCode = require('qrcode');
@@ -101,6 +103,8 @@ const ToEnginePresenceStatus = flipObject(PresenceStatuses);
export class WhatsappSessionNoWebCore extends WhatsappSession {
engine = WAHAEngine.NOWEB;
+ authFactory = new NowebAuthFactoryCore();
+
get listenConnectionEventsFromTheStart() {
return true;
}
@@ -123,7 +127,11 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
return {
agent: agent,
fetchAgent: agent,
- auth: state,
+ auth: {
+ creds: state.creds,
+ /** caching makes the store faster to send/recv messages */
+ keys: makeCacheableSignalKeyStore(state.keys, logger),
+ },
printQRInTerminal: true,
browser: Browsers.macOS('Chrome'),
logger: logger,
@@ -134,9 +142,10 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
}
async makeSocket() {
- const authFolder = this.sessionStorage.getFolderPath(this.name);
- await fs.mkdir(authFolder, { recursive: true });
- const { state, saveCreds } = await useMultiFileAuthState(authFolder);
+ const { state, saveCreds } = await this.authFactory.buildAuth(
+ this.sessionStore,
+ this.name,
+ );
const agent = this.makeAgent();
const socketConfig = this.getSocketConfig(agent, state);
const sock: any = makeWASocket(socketConfig);
diff --git a/src/core/session.venom.core.ts b/src/core/engines/venom/session.venom.core.ts
similarity index 95%
rename from src/core/session.venom.core.ts
rename to src/core/engines/venom/session.venom.core.ts
index fc52ab2d..4ab10414 100644
--- a/src/core/session.venom.core.ts
+++ b/src/core/engines/venom/session.venom.core.ts
@@ -15,17 +15,17 @@ import {
MessageReplyRequest,
MessageTextRequest,
WANumberExistResult,
-} from '../structures/chatting.dto';
+} from '../../../structures/chatting.dto';
import {
WAHAEngine,
WAHAEvents,
WAHASessionStatus,
-} from '../structures/enums.dto';
-import { WAMessage } from '../structures/responses.dto';
-import { IEngineMediaProcessor } from './abc/media.abc';
-import { WAHAInternalEvent, WhatsappSession } from './abc/session.abc';
-import { NotImplementedByEngineError } from './exceptions';
-import { QR } from './QR';
+} from '../../../structures/enums.dto';
+import { WAMessage } from '../../../structures/responses.dto';
+import { IEngineMediaProcessor } from '../../abc/media.abc';
+import { WAHAInternalEvent, WhatsappSession } from '../../abc/session.abc';
+import { NotImplementedByEngineError } from '../../exceptions';
+import { QR } from '../../QR';
export class WhatsappSessionVenomCore extends WhatsappSession {
engine = WAHAEngine.VENOM;
diff --git a/src/core/session.webjs.core.ts b/src/core/engines/webjs/session.webjs.core.ts
similarity index 96%
rename from src/core/session.webjs.core.ts
rename to src/core/engines/webjs/session.webjs.core.ts
index 5bf6494e..c7a0ed76 100644
--- a/src/core/session.webjs.core.ts
+++ b/src/core/engines/webjs/session.webjs.core.ts
@@ -24,8 +24,8 @@ import {
MessageVoiceRequest,
SendSeenRequest,
WANumberExistResult,
-} from '../structures/chatting.dto';
-import { ContactQuery, ContactRequest } from '../structures/contacts.dto';
+} from '../../../structures/chatting.dto';
+import { ContactQuery, ContactRequest } from '../../../structures/contacts.dto';
import {
ACK_UNKNOWN,
WAHAEngine,
@@ -33,22 +33,22 @@ import {
WAHAPresenceStatus,
WAHASessionStatus,
WAMessageAck,
-} from '../structures/enums.dto';
+} from '../../../structures/enums.dto';
import {
CreateGroupRequest,
ParticipantsRequest,
SettingsSecurityChangeInfo,
-} from '../structures/groups.dto';
-import { WAMessage } from '../structures/responses.dto';
-import { MeInfo } from '../structures/sessions.dto';
-import { WAMessageRevokedBody } from '../structures/webhooks.dto';
-import { IEngineMediaProcessor } from './abc/media.abc';
-import { WAHAInternalEvent, WhatsappSession } from './abc/session.abc';
+} from '../../../structures/groups.dto';
+import { WAMessage } from '../../../structures/responses.dto';
+import { MeInfo } from '../../../structures/sessions.dto';
+import { WAMessageRevokedBody } from '../../../structures/webhooks.dto';
+import { IEngineMediaProcessor } from '../../abc/media.abc';
+import { WAHAInternalEvent, WhatsappSession } from '../../abc/session.abc';
import {
AvailableInPlusVersion,
NotImplementedByEngineError,
-} from './exceptions';
-import { QR } from './QR';
+} from '../../exceptions';
+import { QR } from '../../QR';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const QRCode = require('qrcode');
@@ -67,7 +67,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
this.qr = new QR();
}
- protected buildClient() {
+ protected async buildClient() {
const clientOptions: ClientOptions = {
puppeteer: {
headless: true,
@@ -98,7 +98,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
async start() {
this.status = WAHASessionStatus.STARTING;
- this.whatsapp = this.buildClient();
+ this.whatsapp = await this.buildClient();
this.whatsapp
.initialize()
.then(() => {
diff --git a/src/core/manager.core.ts b/src/core/manager.core.ts
index ea37bf86..47b2e8a3 100644
--- a/src/core/manager.core.ts
+++ b/src/core/manager.core.ts
@@ -19,13 +19,15 @@ import {
import { WebhookConfig } from '../structures/webhooks.config.dto';
import { SessionManager } from './abc/manager.abc';
import { SessionParams, WhatsappSession } from './abc/session.abc';
+import { WhatsappSessionNoWebCore } from './engines/noweb/session.noweb.core';
+import { WhatsappSessionVenomCore } from './engines/venom/session.venom.core';
+import { WhatsappSessionWebJSCore } from './engines/webjs/session.webjs.core';
import { DOCS_URL } from './exceptions';
import { getProxyConfig } from './helpers.proxy';
import { CoreMediaManager, MediaStorageCore } from './media.core';
-import { WhatsappSessionNoWebCore } from './session.noweb.core';
-import { WhatsappSessionVenomCore } from './session.venom.core';
-import { WhatsappSessionWebJSCore } from './session.webjs.core';
-import { SessionStorageCore } from './storage.core';
+import { LocalSessionAuthRepository } from './storage/LocalSessionAuthRepository';
+import { LocalSessionConfigRepository } from './storage/LocalSessionConfigRepository';
+import { LocalStoreCore } from './storage/LocalStoreCore';
import { WebhookConductorCore } from './webhooks.core';
export class OnlyDefaultSessionIsAllowed extends UnprocessableEntityException {
@@ -59,8 +61,9 @@ export class SessionManagerCore extends SessionManager {
this.session = undefined;
const engineName = this.config.getDefaultEngineName();
this.EngineClass = this.getEngine(engineName);
- this.sessionStorage = new SessionStorageCore(engineName.toLowerCase());
-
+ this.store = new LocalStoreCore(engineName.toLowerCase());
+ this.sessionAuthRepository = new LocalSessionAuthRepository(this.store);
+ this.sessionConfigRepository = new LocalSessionConfigRepository(this.store);
this.startPredefinedSessions();
}
@@ -116,11 +119,11 @@ export class SessionManagerCore extends SessionManager {
name,
mediaManager,
log,
- sessionStorage: this.sessionStorage,
+ sessionStore: this.store,
proxyConfig: proxyConfig,
sessionConfig: request.config,
};
- await this.sessionStorage.init(name);
+ await this.sessionAuthRepository.init(name);
// @ts-ignore
const session = new this.EngineClass(sessionConfig);
this.session = session;
@@ -181,7 +184,7 @@ export class SessionManagerCore extends SessionManager {
}
async logout(request: SessionLogoutRequest) {
- await this.sessionStorage.clean(request.name);
+ await this.sessionAuthRepository.clean(request.name);
}
getSession(name: string): WhatsappSession {
diff --git a/src/core/storage.core.ts b/src/core/storage.core.ts
deleted file mode 100644
index d08eac24..00000000
--- a/src/core/storage.core.ts
+++ /dev/null
@@ -1,97 +0,0 @@
-import * as crypto from 'crypto';
-import * as fs from 'fs/promises';
-import * as os from 'os';
-import * as path from 'path';
-
-import { SessionConfig } from '../structures/sessions.dto';
-import {
- LocalSessionStorage,
- SessionConfigRepository,
-} from './abc/storage.abc';
-
-class LocalSessionConfigRepository extends SessionConfigRepository {
- FILENAME = '.waha.session.config.json';
-
- constructor(private storage: LocalSessionStorage) {
- super();
- }
-
- async get(sessionName: string): Promise {
- const filepath = this.getFilePath(sessionName);
- // Check file exists
- try {
- await fs.access(filepath, fs.constants.F_OK);
- } catch (error) {
- return null;
- }
-
- // Try to load config
- let content;
- try {
- content = await fs.readFile(filepath, 'utf-8');
- } catch (error) {
- return null;
- }
-
- return JSON.parse(content);
- }
-
- async save(sessionName: string, config: SessionConfig | null) {
- // Create folder if not exist
- const folder = this.storage.getFolderPath(sessionName);
- await fs.mkdir(folder, { recursive: true });
- // Save config
- const filepath = this.getFilePath(sessionName);
- const content = JSON.stringify(config || null);
- await fs.writeFile(filepath, content);
- }
-
- private getFilePath(sessionName): string {
- const folder = this.storage.getFolderPath(sessionName);
- return path.join(folder, this.FILENAME);
- }
-}
-
-export class SessionStorageCore extends LocalSessionStorage {
- public sessionsFolder: string;
-
- constructor(engine: string) {
- super(engine);
- this.sessionsFolder = path.join(os.tmpdir(), 'waha-sessions');
- }
-
- get engineFolder() {
- return path.join(this.sessionsFolder, this.engine);
- }
-
- async init(sessionName?: string) {
- const folder = sessionName
- ? this.getFolderPath(sessionName)
- : this.engineFolder;
- await fs.mkdir(folder, { recursive: true });
- }
-
- getFolderPath(name: string): string {
- const suffix = crypto.createHash('md5').update(name).digest('hex');
- return path.join(this.engineFolder, `${name}-${suffix}`);
- }
-
- async clean(sessionName: string) {
- const folder = this.getFolderPath(sessionName);
- await fs.rm(folder, { recursive: true });
- }
-
- async getAll(): Promise {
- await this.init();
- const content = await fs.readdir(this.engineFolder, {
- withFileTypes: true,
- });
- return content
- .filter((dirent) => dirent.isDirectory())
- .map((dirent) => dirent.name);
- }
-
- get configRepository(): LocalSessionConfigRepository {
- return new LocalSessionConfigRepository(this);
- }
-}
diff --git a/src/core/storage/ISessionAuthRepository.ts b/src/core/storage/ISessionAuthRepository.ts
new file mode 100644
index 00000000..f9b2a4e3
--- /dev/null
+++ b/src/core/storage/ISessionAuthRepository.ts
@@ -0,0 +1,7 @@
+export abstract class ISessionAuthRepository {
+ abstract init(sessionName?: string): Promise;
+
+ abstract clean(sessionName: string): Promise;
+
+ abstract getAll(): Promise;
+}
diff --git a/src/core/storage/ISessionConfigRepository.ts b/src/core/storage/ISessionConfigRepository.ts
new file mode 100644
index 00000000..f5cb3d19
--- /dev/null
+++ b/src/core/storage/ISessionConfigRepository.ts
@@ -0,0 +1,12 @@
+import { SessionConfig } from '../../structures/sessions.dto';
+
+export abstract class ISessionConfigRepository {
+ abstract save(
+ sessionName: string,
+ config: SessionConfig | null,
+ ): Promise;
+
+ abstract get(sessionName: string): Promise;
+
+ abstract delete(sessionName: string): Promise;
+}
diff --git a/src/core/storage/LocalSessionAuthRepository.ts b/src/core/storage/LocalSessionAuthRepository.ts
new file mode 100644
index 00000000..2a7ef56c
--- /dev/null
+++ b/src/core/storage/LocalSessionAuthRepository.ts
@@ -0,0 +1,32 @@
+import * as fs from 'fs/promises';
+
+import { ISessionAuthRepository } from './ISessionAuthRepository';
+import { LocalStore } from './LocalStore';
+
+export class LocalSessionAuthRepository extends ISessionAuthRepository {
+ private store: LocalStore;
+
+ constructor(store: LocalStore) {
+ super();
+ this.store = store;
+ }
+
+ async init(sessionName?: string) {
+ await this.store.init(sessionName);
+ }
+
+ async clean(sessionName: string) {
+ const folder = this.store.getSessionDirectory(sessionName);
+ await fs.rm(folder, { recursive: true });
+ }
+
+ async getAll(): Promise {
+ await this.init();
+ const content = await fs.readdir(this.store.getEngineDirectory(), {
+ withFileTypes: true,
+ });
+ return content
+ .filter((dirent) => dirent.isDirectory())
+ .map((dirent) => dirent.name);
+ }
+}
diff --git a/src/core/storage/LocalSessionConfigRepository.ts b/src/core/storage/LocalSessionConfigRepository.ts
new file mode 100644
index 00000000..3c2c30fa
--- /dev/null
+++ b/src/core/storage/LocalSessionConfigRepository.ts
@@ -0,0 +1,56 @@
+import * as fs from 'fs/promises';
+import * as path from 'path';
+
+import { SessionConfig } from '../../structures/sessions.dto';
+import { ISessionConfigRepository } from './ISessionConfigRepository';
+import { LocalStore } from './LocalStore';
+
+export class LocalSessionConfigRepository extends ISessionConfigRepository {
+ FILENAME = '.waha.session.config.json';
+ private store: LocalStore;
+
+ constructor(store: LocalStore) {
+ super();
+ this.store = store;
+ }
+
+ async get(sessionName: string): Promise {
+ const filepath = this.getFilePath(sessionName);
+ // Check file exists
+ try {
+ await fs.access(filepath, fs.constants.F_OK);
+ } catch (error) {
+ return null;
+ }
+
+ // Try to load config
+ let content;
+ try {
+ content = await fs.readFile(filepath, 'utf-8');
+ } catch (error) {
+ return null;
+ }
+
+ return JSON.parse(content);
+ }
+
+ async save(sessionName: string, config: SessionConfig | null) {
+ // Create folder if not exist
+ const folder = this.store.getSessionDirectory(sessionName);
+ await fs.mkdir(folder, { recursive: true });
+ // Save config
+ const filepath = this.getFilePath(sessionName);
+ const content = JSON.stringify(config || null);
+ await fs.writeFile(filepath, content);
+ }
+
+ private getFilePath(sessionName): string {
+ const folder = this.store.getSessionDirectory(sessionName);
+ return path.join(folder, this.FILENAME);
+ }
+
+ async delete(sessionName: string): Promise {
+ const filepath = this.getFilePath(sessionName);
+ await fs.unlink(filepath);
+ }
+}
diff --git a/src/core/storage/LocalStore.ts b/src/core/storage/LocalStore.ts
new file mode 100644
index 00000000..eed83f19
--- /dev/null
+++ b/src/core/storage/LocalStore.ts
@@ -0,0 +1,20 @@
+import { DataStore } from '../abc/DataStore';
+
+export abstract class LocalStore extends DataStore {
+ abstract init(sessionName?: string): Promise;
+
+ /**
+ * Get the directory where all the engines and sessions are stored
+ */
+ abstract getBaseDirectory(): string;
+
+ /**
+ * Get the directory where the engine sessions are stored
+ */
+ abstract getEngineDirectory(): string;
+
+ /**
+ * Get the directory where the session data is stored
+ */
+ abstract getSessionDirectory(name: string): string;
+}
diff --git a/src/core/storage/LocalStoreCore.ts b/src/core/storage/LocalStoreCore.ts
new file mode 100644
index 00000000..fd19eb98
--- /dev/null
+++ b/src/core/storage/LocalStoreCore.ts
@@ -0,0 +1,51 @@
+import * as crypto from 'crypto';
+import * as fs from 'fs/promises';
+import * as os from 'os';
+import * as path from 'path';
+
+import { LocalStore } from './LocalStore';
+
+export class LocalStoreCore implements LocalStore {
+ protected readonly baseDirectory: string = path.join(
+ os.tmpdir(),
+ 'waha-sessions',
+ );
+
+ private readonly engine: string;
+
+ constructor(engine: string) {
+ this.engine = engine;
+ }
+
+ async init(sessionName?: string) {
+ await fs.mkdir(this.getEngineDirectory(), { recursive: true });
+ if (sessionName) {
+ await fs.mkdir(this.getSessionDirectory(sessionName), {
+ recursive: true,
+ });
+ }
+ }
+
+ /**
+ * Get the directory where all the engines and sessions are stored
+ */
+ getBaseDirectory() {
+ return path.join(this.baseDirectory);
+ }
+
+ /**
+ * Get the directory where the engine sessions are stored
+ */
+ getEngineDirectory() {
+ return path.join(this.baseDirectory, this.engine);
+ }
+
+ getSessionDirectory(name: string): string {
+ return this.getDirectoryPath(name);
+ }
+
+ protected getDirectoryPath(name: string): string {
+ const suffix = crypto.createHash('md5').update(name).digest('hex');
+ return path.join(this.getEngineDirectory(), `${name}-${suffix}`);
+ }
+}
diff --git a/yarn.lock b/yarn.lock
index 8e7d727d..04448adb 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -935,6 +935,15 @@ __metadata:
languageName: node
linkType: hard
+"@mongodb-js/saslprep@npm:^1.1.0":
+ version: 1.1.4
+ resolution: "@mongodb-js/saslprep@npm:1.1.4"
+ dependencies:
+ sparse-bitfield: ^3.0.3
+ checksum: 208fd6f82136fd4332d0a6c667f8090b08f365dd7aa5880b8c485501caed7b058a99c231085c51ad7fa25f4a590d96c87af9a5b3fc0aea4de8c527657e33e548
+ languageName: node
+ linkType: hard
+
"@nestjs/cli@npm:^9.0.0":
version: 9.5.0
resolution: "@nestjs/cli@npm:9.5.0"
@@ -1818,6 +1827,22 @@ __metadata:
languageName: node
linkType: hard
+"@types/webidl-conversions@npm:*":
+ version: 7.0.3
+ resolution: "@types/webidl-conversions@npm:7.0.3"
+ checksum: 535ead9de4d3d6c8e4f4fa14e9db780d2a31e8020debc062f337e1420a41c3265e223e4f4b628f97a11ecf3b96390962cd88a9ffe34f44e159dec583ff49aa34
+ languageName: node
+ linkType: hard
+
+"@types/whatwg-url@npm:^11.0.2":
+ version: 11.0.4
+ resolution: "@types/whatwg-url@npm:11.0.4"
+ dependencies:
+ "@types/webidl-conversions": "*"
+ checksum: 5acd60dbd49df34b9131ea75dc5e24b03e084cc4ed5a273ddd801fdaf21c896abbbb846bb3ba71ffd5c715120bac0454debe569f39b9177887fb7636d65cdae4
+ languageName: node
+ linkType: hard
+
"@types/ws@npm:^8.5.4":
version: 8.5.5
resolution: "@types/ws@npm:8.5.5"
@@ -2355,6 +2380,13 @@ __metadata:
languageName: node
linkType: hard
+"adm-zip@npm:^0.5.10":
+ version: 0.5.10
+ resolution: "adm-zip@npm:0.5.10"
+ checksum: 07ed91cf6423bf5dca4ee63977bc7635e91b8d21829c00829d48dce4c6932e1b19e6cfcbe44f1931c956e68795ae97183fc775913883fa48ce88a1ac11fb2034
+ languageName: node
+ linkType: hard
+
"agent-base@npm:6, agent-base@npm:^6.0.2":
version: 6.0.2
resolution: "agent-base@npm:6.0.2"
@@ -3257,6 +3289,13 @@ __metadata:
languageName: node
linkType: hard
+"bson@npm:^6.2.0":
+ version: 6.2.0
+ resolution: "bson@npm:6.2.0"
+ checksum: 950fccd2abd0ff5a1bd3637f4697631298f1538314994ab8c9e13f1c9851d0fd042b54fe8340e00151c2acee43917ea40e64b800ceeea811b00f2de3e900c77e
+ languageName: node
+ linkType: hard
+
"buffer-crc32@npm:^0.2.1, buffer-crc32@npm:^0.2.13, buffer-crc32@npm:~0.2.3":
version: 0.2.13
resolution: "buffer-crc32@npm:0.2.13"
@@ -8634,6 +8673,13 @@ __metadata:
languageName: node
linkType: hard
+"memory-pager@npm:^1.0.2":
+ version: 1.5.0
+ resolution: "memory-pager@npm:1.5.0"
+ checksum: d1a2e684583ef55c61cd3a49101da645b11ad57014dfc565e0b43baa9004b743f7e4ab81493d8fff2ab24e9950987cc3209c94bcc4fc8d7e30a475489a1f15e9
+ languageName: node
+ linkType: hard
+
"merge-deep@npm:^3.0.1":
version: 3.0.3
resolution: "merge-deep@npm:3.0.3"
@@ -8970,6 +9016,50 @@ __metadata:
languageName: node
linkType: hard
+"mongodb-connection-string-url@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "mongodb-connection-string-url@npm:3.0.0"
+ dependencies:
+ "@types/whatwg-url": ^11.0.2
+ whatwg-url: ^13.0.0
+ checksum: 9d4885377345b14e2ba2ee63cb3085364a01aeae3aca622bbd568e7761caa58fdc664528f19f125c762cff230c9349f99e98396dd2271a4260286cf241a8c477
+ languageName: node
+ linkType: hard
+
+"mongodb@npm:^6.3.0":
+ version: 6.3.0
+ resolution: "mongodb@npm:6.3.0"
+ dependencies:
+ "@mongodb-js/saslprep": ^1.1.0
+ bson: ^6.2.0
+ mongodb-connection-string-url: ^3.0.0
+ peerDependencies:
+ "@aws-sdk/credential-providers": ^3.188.0
+ "@mongodb-js/zstd": ^1.1.0
+ gcp-metadata: ^5.2.0
+ kerberos: ^2.0.1
+ mongodb-client-encryption: ">=6.0.0 <7"
+ snappy: ^7.2.2
+ socks: ^2.7.1
+ peerDependenciesMeta:
+ "@aws-sdk/credential-providers":
+ optional: true
+ "@mongodb-js/zstd":
+ optional: true
+ gcp-metadata:
+ optional: true
+ kerberos:
+ optional: true
+ mongodb-client-encryption:
+ optional: true
+ snappy:
+ optional: true
+ socks:
+ optional: true
+ checksum: ebc5d9dbd1299321b6873e86eb4ea635316f97450644811db24ce2b01432b1c641def864facf2eab6f0c0c5c360c318108ea5555142f55177ca4c33991c6d7c4
+ languageName: node
+ linkType: hard
+
"mpg123-decoder@npm:^0.4.8":
version: 0.4.8
resolution: "mpg123-decoder@npm:0.4.8"
@@ -10176,6 +10266,13 @@ __metadata:
languageName: node
linkType: hard
+"punycode@npm:^2.3.0":
+ version: 2.3.1
+ resolution: "punycode@npm:2.3.1"
+ checksum: bb0a0ceedca4c3c57a9b981b90601579058903c62be23c5e8e843d2c2d4148a3ecf029d5133486fb0e1822b098ba8bba09e89d6b21742d02fa26bda6441a6fb2
+ languageName: node
+ linkType: hard
+
"puppeteer-core@npm:20.9.0":
version: 20.9.0
resolution: "puppeteer-core@npm:20.9.0"
@@ -11449,6 +11546,15 @@ __metadata:
languageName: node
linkType: hard
+"sparse-bitfield@npm:^3.0.3":
+ version: 3.0.3
+ resolution: "sparse-bitfield@npm:3.0.3"
+ dependencies:
+ memory-pager: ^1.0.2
+ checksum: 174da88dbbcc783d5dbd26921931cc83830280b8055fb05333786ebe6fc015b9601b24972b3d55920dd2d9f5fb120576fbfa2469b08e5222c9cadf3f05210aab
+ languageName: node
+ linkType: hard
+
"spdx-correct@npm:^3.0.0":
version: 3.2.0
resolution: "spdx-correct@npm:3.2.0"
@@ -12196,6 +12302,15 @@ __metadata:
languageName: node
linkType: hard
+"tr46@npm:^4.1.1":
+ version: 4.1.1
+ resolution: "tr46@npm:4.1.1"
+ dependencies:
+ punycode: ^2.3.0
+ checksum: aeeb821ac2cd792e63ec84888b4fd6598ac6ed75d861579e21a5cf9d4ee78b2c6b94e7d45036f2ca2088bc85b9b46560ad23c4482979421063b24137349dbd96
+ languageName: node
+ linkType: hard
+
"tr46@npm:~0.0.3":
version: 0.0.3
resolution: "tr46@npm:0.0.3"
@@ -13015,6 +13130,13 @@ __metadata:
languageName: node
linkType: hard
+"webidl-conversions@npm:^7.0.0":
+ version: 7.0.0
+ resolution: "webidl-conversions@npm:7.0.0"
+ checksum: f05588567a2a76428515333eff87200fae6c83c3948a7482ebb109562971e77ef6dc49749afa58abb993391227c5697b3ecca52018793e0cb4620a48f10bd21b
+ languageName: node
+ linkType: hard
+
"webpack-node-externals@npm:3.0.0":
version: 3.0.0
resolution: "webpack-node-externals@npm:3.0.0"
@@ -13104,6 +13226,7 @@ __metadata:
link-preview-js: ^3.0.4
lodash: ^4.17.21
mime-types: ^2.1.27
+ mongodb: ^6.3.0
passport: ^0.6.0
passport-headerapikey: ^1.2.2
prettier: ^1.19.1
@@ -13122,15 +13245,16 @@ __metadata:
tsconfig-paths: ^4.1.0
typescript: ^4.8.4
venom-bot: 5.0.1
- whatsapp-web.js: "https://github.com/pedroslopez/whatsapp-web.js"
+ whatsapp-web.js: "https://github.com/devlikeapro/whatsapp-web.js#main-fork"
languageName: unknown
linkType: soft
-"whatsapp-web.js@https://github.com/pedroslopez/whatsapp-web.js":
+"whatsapp-web.js@https://github.com/devlikeapro/whatsapp-web.js#main-fork":
version: 1.23.1-alpha.4
- resolution: "whatsapp-web.js@https://github.com/pedroslopez/whatsapp-web.js.git#commit=ef2f725bce1bd1afd8491f9de0cd2ed06a6febc3"
+ resolution: "whatsapp-web.js@https://github.com/devlikeapro/whatsapp-web.js.git#commit=6ab7270e9a2c86a81efb8831b7817da10daffff2"
dependencies:
"@pedroslopez/moduleraid": ^5.0.2
+ adm-zip: ^0.5.10
archiver: ^5.3.1
fluent-ffmpeg: 2.1.2
fs-extra: ^10.1.0
@@ -13146,7 +13270,7 @@ __metadata:
optional: true
unzipper:
optional: true
- checksum: 36062f9aa97e5d3f2ae50235a1535ae4b67550ea40f875794590cbaed6045b6b5ae56bd3edd79092419018f5509ff8dfb8f03cb894ed76315f9583d546a4f4be
+ checksum: 425fa37ba93bc42a32609dde9e102a11e2783750119972153593a887200afbdf555dc3b559c346274b72d92ceb00cc363cf714b6ff40c8c35103676234170837
languageName: node
linkType: hard
@@ -13166,6 +13290,16 @@ __metadata:
languageName: node
linkType: hard
+"whatwg-url@npm:^13.0.0":
+ version: 13.0.0
+ resolution: "whatwg-url@npm:13.0.0"
+ dependencies:
+ tr46: ^4.1.1
+ webidl-conversions: ^7.0.0
+ checksum: 7f69272a1bfd5f0d994988b9e234e35d21071a9bffe0d6fd4477d295552665c566b176ff8e0251a0a79c61c5a67a7a392e248aae5887d7e22bdff0125209e26b
+ languageName: node
+ linkType: hard
+
"whatwg-url@npm:^5.0.0":
version: 5.0.0
resolution: "whatwg-url@npm:5.0.0"