├── index.d.ts ├── index.js ├── package.json ├── README.md ├── .gitignore └── src └── MongoStore.js /index.d.ts: -------------------------------------------------------------------------------- 1 | export const MongoStore: typeof import("./src/MongoStore"); 2 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | MongoStore: require('./src/MongoStore') 5 | }; 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wwebjs-mongo", 3 | "version": "1.1.0", 4 | "description": "A MongoDB plugin for whatsapp-web.js library", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/jtourisNS/wwebjs-mongo.git" 12 | }, 13 | "keywords": [ 14 | "wwebjs", 15 | "mongodb", 16 | "whatsapp-web.js" 17 | ], 18 | "author": "Joaquin Touris", 19 | "license": "ISC" 20 | } 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wwebjs-mongo 2 | A MongoDB plugin for whatsapp-web.js! 3 | 4 | Use MongoStore to save your WhatsApp MultiDevice session on a MongoDB Database. 5 | 6 | ## Quick Links 7 | 8 | * [Guide / Getting Started](https://wwebjs.dev/guide/authentication.html) _(work in progress)_ 9 | * [GitHub](https://github.com/jtourisNS/wwebjs-mongo) 10 | * [npm](https://www.npmjs.com/package/wwebjs-mongo) 11 | 12 | ## Installation 13 | 14 | The module is now available on npm! `npm i wwebjs-mongo` 15 | 16 | 17 | ## Example usage 18 | 19 | ```js 20 | const { Client, RemoteAuth } = require('whatsapp-web.js'); 21 | const { MongoStore } = require('wwebjs-mongo'); 22 | const mongoose = require('mongoose'); 23 | 24 | mongoose.connect(process.env.MONGODB_URI).then(() => { 25 | const store = new MongoStore({ mongoose: mongoose }); 26 | const client = new Client({ 27 | authStrategy: new RemoteAuth({ 28 | store: store, 29 | backupSyncIntervalMs: 300000 30 | }) 31 | }); 32 | 33 | client.initialize(); 34 | }); 35 | 36 | ``` 37 | 38 | ## Delete Remote Session 39 | 40 | How to force delete a specific remote session on the Database: 41 | 42 | ```js 43 | await store.delete({session: 'yourSessionName'}); 44 | ``` -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | .DS_Store -------------------------------------------------------------------------------- /src/MongoStore.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | class MongoStore { 4 | constructor({ mongoose } = {}) { 5 | if(!mongoose) throw new Error('A valid Mongoose instance is required for MongoStore.'); 6 | this.mongoose = mongoose; 7 | } 8 | 9 | async sessionExists(options) { 10 | let multiDeviceCollection = this.mongoose.connection.db.collection(`whatsapp-${options.session}.files`); 11 | let hasExistingSession = await multiDeviceCollection.countDocuments(); 12 | return !!hasExistingSession; 13 | } 14 | 15 | async save(options) { 16 | var bucket = new this.mongoose.mongo.GridFSBucket(this.mongoose.connection.db, { 17 | bucketName: `whatsapp-${options.session}` 18 | }); 19 | await new Promise((resolve, reject) => { 20 | fs.createReadStream(`${options.session}.zip`) 21 | .pipe(bucket.openUploadStream(`${options.session}.zip`)) 22 | .on('error', err => reject(err)) 23 | .on('close', () => resolve()); 24 | }); 25 | options.bucket = bucket; 26 | await this.#deletePrevious(options); 27 | } 28 | 29 | async extract(options) { 30 | var bucket = new this.mongoose.mongo.GridFSBucket(this.mongoose.connection.db, { 31 | bucketName: `whatsapp-${options.session}` 32 | }); 33 | return new Promise((resolve, reject) => { 34 | bucket.openDownloadStreamByName(`${options.session}.zip`) 35 | .pipe(fs.createWriteStream(options.path)) 36 | .on('error', err => reject(err)) 37 | .on('close', () => resolve()); 38 | }); 39 | } 40 | 41 | async delete(options) { 42 | var bucket = new this.mongoose.mongo.GridFSBucket(this.mongoose.connection.db, { 43 | bucketName: `whatsapp-${options.session}` 44 | }); 45 | const documents = await bucket.find({ 46 | filename: `${options.session}.zip` 47 | }).toArray(); 48 | 49 | documents.map(async doc => { 50 | return bucket.delete(doc._id); 51 | }); 52 | } 53 | 54 | async #deletePrevious(options) { 55 | const documents = await options.bucket.find({ 56 | filename: `${options.session}.zip` 57 | }).toArray(); 58 | if (documents.length > 1) { 59 | const oldSession = documents.reduce((a, b) => a.uploadDate < b.uploadDate ? a : b); 60 | return options.bucket.delete(oldSession._id); 61 | } 62 | } 63 | } 64 | 65 | module.exports = MongoStore; --------------------------------------------------------------------------------