diff --git a/README.md b/README.md index 347d2d3..2b5f6e7 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ BootBot is a simple but powerful JavaScript Framework to build Facebook Messenge $ npm install bootbot --save ``` +### Without express ```javascript 'use strict'; const BootBot = require('bootbot'); @@ -44,6 +45,30 @@ bot.on('message', (payload, chat) => { bot.start(); ``` +### With an existent express instance +```javascript +'use strict'; +const BootBot = require('bootbot'); +const express = require('express'); +const app = express(); + +const bot = new BootBot({ + accessToken: 'FB_ACCESS_TOKEN', + verifyToken: 'FB_VERIFY_TOKEN', + appSecret: 'FB_APP_SECRET' +}); + +bot.on('message', (payload, chat) => { + const text = payload.message.text; + chat.say(`Echo: ${text}`); +}); + +app.use(bot.middleware()); +app.listen(3000, ()=>{ + console.log('listen on port 3000'); +}); +``` + ## Video Example Creating a Giphy Chat Bot in 3 minutes: diff --git a/examples/echo-express-example.js b/examples/echo-express-example.js new file mode 100644 index 0000000..be0d3d2 --- /dev/null +++ b/examples/echo-express-example.js @@ -0,0 +1,21 @@ +const BootBot = require('../'); +const express = require('express'); +const app = express(); +const config = require('config'); + +const bot = new BootBot({ + accessToken: config.get('access_token'), + verifyToken: config.get('verify_token'), + appSecret: config.get('app_secret') +}); + +bot.on('message', (payload, chat) => { + const text = payload.message.text; + chat.say(`Echo: ${text}`); +}); + +app.use(bot.middleware()); + +app.listen(3000, () => { + console.log(`Listen on port 3000`); +}); diff --git a/lib/BootBot.js b/lib/BootBot.js index 5df40f8..b36f9f1 100644 --- a/lib/BootBot.js +++ b/lib/BootBot.js @@ -3,7 +3,6 @@ const Chat = require('./Chat'); const Conversation = require('./Conversation'); const EventEmitter = require('eventemitter3'); const express = require('express'); -const bodyParser = require('body-parser'); const crypto = require('crypto'); const fetch = require('node-fetch'); const normalizeString = require('./utils/normalize-string'); @@ -20,7 +19,7 @@ class BootBot extends EventEmitter { * @param {Boolean} [options.broadcastEchoes=false] * @param {String} [options.graphApiVersion=v2.12] */ - constructor(options) { + constructor (options) { super(); if (!options || (options && (!options.accessToken || !options.verifyToken || !options.appSecret))) { throw new Error('You need to specify an accessToken, verifyToken and appSecret'); @@ -30,10 +29,8 @@ class BootBot extends EventEmitter { this.appSecret = options.appSecret; this.broadcastEchoes = options.broadcastEchoes || false; this.graphApiVersion = options.graphApiVersion || 'v2.12'; - this.app = express(); this.webhook = options.webhook || '/webhook'; this.webhook = this.webhook.charAt(0) !== '/' ? `/${this.webhook}` : this.webhook; - this.app.use(this.webhook, bodyParser.json({ verify: this._verifyRequestSignature.bind(this) })); this._hearMap = []; this._conversations = []; } @@ -43,6 +40,8 @@ class BootBot extends EventEmitter { * @param {Number} [port=3000] */ start(port) { + this.app = express(); + this.app.use(this.webhook, express.json({ verify: this._verifyRequestSignature.bind(this) })); this._initWebhook(); this.app.set('port', port || 3000); this.server = this.app.listen(this.app.get('port'), () => { @@ -59,6 +58,38 @@ class BootBot extends EventEmitter { this.server.close(); } + /** + * getting a middleware for existent express instance + */ + middleware() { + const router = express.Router(); + router.use(express.json({ verify: this._verifyRequestSignature.bind(this) })); + + router.get(this.webhook, (req, res) => { + if (req.query['hub.mode'] === 'subscribe' && req.query['hub.verify_token'] === this.verifyToken) { + console.log('Validation Succeded.') + res.status(200).send(req.query['hub.challenge']); + } else { + console.error('Failed validation. Make sure the validation tokens match.'); + res.sendStatus(403); + } + }); + + router.post(this.webhook, (req, res) => { + var data = req.body; + if (data.object !== 'page') { + return; + } + + this.handleFacebookData(data); + + // Must send back a 200 within 20 seconds or the request will time out. + res.sendStatus(200); + }).bind(this); + + return router; + } + /** * See https://developers.facebook.com/docs/messenger-platform/reference/send-api/quick-replies/#quick_reply * @typedef {Object} QuickReply @@ -279,15 +310,15 @@ class BootBot extends EventEmitter { }, body: JSON.stringify(body) }) - .then(res => res.json()) - .then(res => { - if (res.error) { - console.log('Messenger Error received. For more information about error codes, see: https://goo.gl/d76uvB'); - console.log(res.error); - } - return res; - }) - .catch(err => console.log(`Error sending message: ${err}`)); + .then(res => res.json()) + .then(res => { + if (res.error) { + console.log('Messenger Error received. For more information about error codes, see: https://goo.gl/d76uvB'); + console.log(res.error); + } + return res; + }) + .catch(err => console.log(`Error sending message: ${err}`)); } /** diff --git a/package-lock.json b/package-lock.json index de872ff..ca8e732 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", "requires": { - "mime-types": "2.1.18", + "mime-types": "~2.1.18", "negotiator": "0.6.1" } }, @@ -30,30 +30,13 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "body-parser": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", - "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", - "requires": { - "bytes": "3.0.0", - "content-type": "1.0.4", - "debug": "2.6.9", - "depd": "1.1.2", - "http-errors": "1.6.3", - "iconv-lite": "0.4.23", - "on-finished": "2.3.0", - "qs": "6.5.2", - "raw-body": "2.3.3", - "type-is": "1.6.16" - } - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -74,9 +57,9 @@ "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", "dev": true, "requires": { - "assertion-error": "1.1.0", - "deep-eql": "0.1.3", - "type-detect": "1.0.0" + "assertion-error": "^1.0.1", + "deep-eql": "^0.1.3", + "type-detect": "^1.0.0" } }, "commander": { @@ -176,7 +159,7 @@ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", "requires": { - "iconv-lite": "0.4.23" + "iconv-lite": "~0.4.13" } }, "escape-html": { @@ -205,36 +188,36 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", "requires": { - "accepts": "1.3.5", + "accepts": "~1.3.5", "array-flatten": "1.1.1", "body-parser": "1.18.2", "content-disposition": "0.5.2", - "content-type": "1.0.4", + "content-type": "~1.0.4", "cookie": "0.3.1", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "1.1.2", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "finalhandler": "1.1.1", "fresh": "0.5.2", "merge-descriptors": "1.0.1", - "methods": "1.1.2", - "on-finished": "2.3.0", - "parseurl": "1.3.2", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", "path-to-regexp": "0.1.7", - "proxy-addr": "2.0.3", + "proxy-addr": "~2.0.3", "qs": "6.5.1", - "range-parser": "1.2.0", + "range-parser": "~1.2.0", "safe-buffer": "5.1.1", "send": "0.16.2", "serve-static": "1.13.2", "setprototypeof": "1.1.0", - "statuses": "1.4.0", - "type-is": "1.6.16", + "statuses": "~1.4.0", + "type-is": "~1.6.16", "utils-merge": "1.0.1", - "vary": "1.1.2" + "vary": "~1.1.2" }, "dependencies": { "body-parser": { @@ -243,15 +226,15 @@ "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", "requires": { "bytes": "3.0.0", - "content-type": "1.0.4", + "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "1.1.2", - "http-errors": "1.6.3", + "depd": "~1.1.1", + "http-errors": "~1.6.2", "iconv-lite": "0.4.19", - "on-finished": "2.3.0", + "on-finished": "~2.3.0", "qs": "6.5.1", "raw-body": "2.3.2", - "type-is": "1.6.16" + "type-is": "~1.6.15" } }, "iconv-lite": { @@ -288,7 +271,7 @@ "depd": "1.1.1", "inherits": "2.0.3", "setprototypeof": "1.0.3", - "statuses": "1.4.0" + "statuses": ">= 1.3.1 < 2" } }, "setprototypeof": { @@ -311,12 +294,12 @@ "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", "requires": { "debug": "2.6.9", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "statuses": "1.4.0", - "unpipe": "1.0.0" + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" }, "dependencies": { "statuses": { @@ -332,7 +315,7 @@ "integrity": "sha1-XtPM1jZVEJc4NGXZlhmRAOhhYek=", "dev": true, "requires": { - "samsam": "1.1.2" + "samsam": "~1.1" } }, "forwarded": { @@ -357,12 +340,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "growl": { @@ -388,10 +371,10 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "requires": { - "depd": "1.1.2", + "depd": "~1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", - "statuses": "1.5.0" + "statuses": ">= 1.4.0 < 2" } }, "iconv-lite": { @@ -399,7 +382,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "inflight": { @@ -408,8 +391,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -468,7 +451,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "requires": { - "mime-db": "1.33.0" + "mime-db": "~1.33.0" } }, "minimatch": { @@ -477,7 +460,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -539,8 +522,8 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", "requires": { - "encoding": "0.1.12", - "is-stream": "1.1.0" + "encoding": "^0.1.11", + "is-stream": "^1.0.1" } }, "on-finished": { @@ -557,7 +540,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "os-homedir": { @@ -586,31 +569,15 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz", "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==", "requires": { - "forwarded": "0.1.2", + "forwarded": "~0.1.2", "ipaddr.js": "1.6.0" } }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" - }, "range-parser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" }, - "raw-body": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", - "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", - "requires": { - "bytes": "3.0.0", - "http-errors": "1.6.3", - "iconv-lite": "0.4.23", - "unpipe": "1.0.0" - } - }, "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", @@ -633,18 +600,18 @@ "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", "requires": { "debug": "2.6.9", - "depd": "1.1.2", - "destroy": "1.0.4", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "1.6.3", + "http-errors": "~1.6.2", "mime": "1.4.1", "ms": "2.0.0", - "on-finished": "2.3.0", - "range-parser": "1.2.0", - "statuses": "1.4.0" + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" }, "dependencies": { "statuses": { @@ -659,9 +626,9 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", "requires": { - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "parseurl": "1.3.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", "send": "0.16.2" } }, @@ -679,7 +646,7 @@ "formatio": "1.1.1", "lolex": "1.3.2", "samsam": "1.1.2", - "util": "0.11.0" + "util": ">=0.10.3 <1" } }, "statuses": { @@ -693,7 +660,7 @@ "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", "dev": true, "requires": { - "has-flag": "2.0.0" + "has-flag": "^2.0.0" } }, "type-detect": { @@ -708,7 +675,7 @@ "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", "requires": { "media-typer": "0.3.0", - "mime-types": "2.1.18" + "mime-types": "~2.1.18" } }, "unpipe": { diff --git a/package.json b/package.json index af3d251..f6ad120 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ }, "homepage": "https://github.com/Charca/bootbot#readme", "dependencies": { - "body-parser": "^1.15.2", "config": "^1.21.0", "eventemitter3": "^1.2.0", "express": "^4.14.0",