Comparing version 0.21.2 to 0.22.0
{ | ||
"name": "botnaut", | ||
"version": "0.21.2", | ||
"version": "0.22.0", | ||
"description": "Facebook Messenger Chatbot Framework", | ||
@@ -10,3 +10,3 @@ "main": "index.js", | ||
"test:coverage": "nyc --reporter=html mocha --opts ./mocha.opts ./test && nyc report", | ||
"test:coverage:threshold": "nyc check-coverage --lines 80 --functions 80 --branches 78", | ||
"test:coverage:threshold": "nyc check-coverage --lines 80 --functions 80 --branches 75", | ||
"test:backend": "mocha --opts ./mocha.opts ./test ./src", | ||
@@ -13,0 +13,0 @@ "test:lint": "eslint --ext .js src test *.js" |
@@ -73,7 +73,7 @@ /* | ||
function isText (response, message = 'Should be a text') { | ||
const is = typeof getText(response) === 'string'; | ||
const is = typeof getText(response) === 'string' && !response.message.quick_reply; | ||
if (message === false) { | ||
return is; | ||
} | ||
assert(typeof getText(response) === 'string', message); | ||
assert(is, message); | ||
return true; | ||
@@ -80,0 +80,0 @@ } |
@@ -215,2 +215,8 @@ /* | ||
// ensure the request was not processed | ||
if (stateObject.lastTimestamps && message.timestamp | ||
&& stateObject.lastTimestamps.indexOf(message.timestamp) !== -1) { | ||
return null; | ||
} | ||
// update the state of request | ||
@@ -267,5 +273,17 @@ state = stateObject.state; | ||
} | ||
// store the message timestamp to prevent event rotating | ||
let lastTimestamps = stateObject.lastTimestamps || []; | ||
if (message.timestamp) { | ||
lastTimestamps = lastTimestamps.slice(); | ||
lastTimestamps.push(message.timestamp); | ||
if (lastTimestamps.length > 10) { | ||
lastTimestamps.shift(); | ||
} | ||
} | ||
Object.assign(stateObject, { | ||
state, | ||
lock: 0, | ||
lastTimestamps, | ||
lastInteraction: new Date(), | ||
@@ -272,0 +290,0 @@ off: false |
@@ -141,2 +141,24 @@ /* | ||
/** | ||
* Check, that message is a quick reply | ||
* | ||
* @returns {boolean} | ||
* | ||
* @memberOf Request | ||
*/ | ||
isQuickReply () { | ||
return this.message !== null && this.message.quick_reply; | ||
} | ||
/** | ||
* Check, that message is PURE text | ||
* | ||
* @returns {boolean} | ||
*/ | ||
isText () { | ||
return this.message !== null | ||
&& !this.message.quick_reply | ||
&& !!this.message.text; | ||
} | ||
/** | ||
* Returns text of the message | ||
@@ -143,0 +165,0 @@ * |
@@ -76,43 +76,27 @@ /* | ||
const exitPoints = new Map(); | ||
let path = '/*'; | ||
const reducers = resolvers.map((reducer) => { | ||
let isReducer = false; | ||
let reduce = reducer; | ||
if (typeof reducer === 'string') { | ||
path = this._normalizePath(reducer); | ||
const pathMatch = pathToRegexp(path, [], { end: path === '' }); | ||
// or condition | ||
if (Array.isArray(reducer)) { | ||
let isAnyReducer = false; | ||
reduce = (req, res, relativePostBack, pathContext, action) => { | ||
if (action && (path === '/*' || pathMatch.exec(action))) { | ||
return Router.CONTINUE; | ||
} | ||
return Router.BREAK; | ||
}; | ||
const reducersArray = reducer.map((re) => { | ||
const { resolverPath, reduce, isReducer } = this._createReducer(re, path); | ||
path = resolverPath; | ||
isAnyReducer = isAnyReducer || isReducer; | ||
return { reduce, isReducer }; | ||
}); | ||
} else if (reducer instanceof RegExp) { | ||
reduce = req => | ||
(!req.action() && req.text(true).match(reducer) | ||
? Router.CONTINUE | ||
: Router.BREAK); | ||
} else if (typeof reduce === 'object' && reduce.reduce) { | ||
isReducer = true; | ||
reduce.on('action', (...args) => this.emit('action', ...args)); | ||
reduce.on('_action', (...args) => this.emit('_action', ...args)); | ||
const reduceFn = reduce.reduce.bind(reduce); | ||
reduce = (...args) => reduceFn(...args); | ||
return { reducers: reducersArray, isReducer: isAnyReducer, isOr: true }; | ||
} | ||
return { | ||
reduce, | ||
isReducer | ||
}; | ||
const { resolverPath, reduce, isReducer } = this._createReducer(reducer, path); | ||
path = resolverPath; | ||
return { reduce, isReducer }; | ||
}); | ||
const exitPoints = new Map(); | ||
this._routes.push({ | ||
@@ -135,4 +119,38 @@ exitPoints, | ||
_createReducer (reducer, thePath) { | ||
let resolverPath = thePath; | ||
let reduce = reducer; | ||
let isReducer = false; | ||
if (typeof reducer === 'string') { | ||
resolverPath = this._normalizePath(reducer); | ||
const pathMatch = pathToRegexp(resolverPath, [], { end: resolverPath === '' }); | ||
reduce = (req, res, relativePostBack, pathContext, action) => { | ||
if (action && (resolverPath === '/*' || pathMatch.exec(action))) { | ||
return Router.CONTINUE; | ||
} | ||
return Router.BREAK; | ||
}; | ||
} else if (reducer instanceof RegExp) { | ||
reduce = req => | ||
(req.isText() && req.text(true).match(reducer) | ||
? Router.CONTINUE | ||
: Router.BREAK); | ||
} else if (typeof reduce === 'object' && reduce.reduce) { | ||
isReducer = true; | ||
reduce.on('action', (...args) => this.emit('action', ...args)); | ||
reduce.on('_action', (...args) => this.emit('_action', ...args)); | ||
const reduceFn = reduce.reduce.bind(reduce); | ||
reduce = (...args) => reduceFn(...args); | ||
} | ||
return { resolverPath, isReducer, reduce }; | ||
} | ||
* _callExitPoint (route, req, res, postBack, path, exitPointName, data = {}) { | ||
res.setPath(path); | ||
@@ -172,42 +190,74 @@ | ||
const relativePostBack = this._makePostBackRelative(postBack, path); | ||
let iterationResult; | ||
for (const route of this._routes) { | ||
iterationResult = yield* this._reduceTheArray( | ||
route, route, action, req, res, relativePostBack, path | ||
); | ||
if (typeof iterationResult === 'string' || Array.isArray(iterationResult)) { | ||
return iterationResult; | ||
} else if (iterationResult !== Router.CONTINUE) { | ||
return Router.END; | ||
} | ||
} | ||
for (const reducer of route.reducers) { | ||
let pathContext = `${path === '/' ? '' : path}${route.path.replace(/\/\*/, '')}`; | ||
res.setPath(path); | ||
return Router.CONTINUE; | ||
}.bind(this)); | ||
} | ||
let result = reducer.reduce(req, res, relativePostBack, pathContext, action); | ||
* _reduceTheArray (route, reducerContainer, action, req, res, relativePostBack, path = '/') { | ||
let breakOn = Router.BREAK; | ||
let continueOn = Router.CONTINUE; | ||
if (result instanceof Promise) { | ||
result = yield result; | ||
} | ||
if (reducerContainer.isOr) { | ||
breakOn = Router.CONTINUE; | ||
continueOn = Router.BREAK; | ||
} | ||
if (!reducer.isReducer | ||
&& [Router.BREAK, Router.CONTINUE].indexOf(result) === -1) { | ||
pathContext = `${path === '/' ? '' : path}${route.path}`; | ||
this._emitAction(req, pathContext); | ||
} | ||
for (const reducer of reducerContainer.reducers) { | ||
if (result === Router.BREAK) { | ||
break; // skip the rest path reducers, continue with next route | ||
let pathContext = `${path === '/' ? '' : path}${route.path.replace(/\/\*/, '')}`; | ||
res.setPath(path); | ||
} else if (typeof result === 'string' || Array.isArray(result)) { | ||
const [exitPoint, data] = Array.isArray(result) ? result : [result]; | ||
let result; | ||
// NOTE exit point can cause call of an upper exit point | ||
return yield* this._callExitPoint( | ||
route, req, res, relativePostBack, path, exitPoint, data | ||
); | ||
if (reducer.reducers) { | ||
result = yield* this._reduceTheArray( | ||
route, reducer, action, req, res, relativePostBack, path | ||
); | ||
} else { | ||
result = reducer.reduce(req, res, relativePostBack, pathContext, action); | ||
} else if (result !== Router.CONTINUE) { | ||
if (result instanceof Promise) { | ||
result = yield result; | ||
} | ||
} | ||
return Router.END; | ||
} | ||
if (!reducer.isReducer | ||
&& [Router.BREAK, Router.CONTINUE].indexOf(result) === -1) { | ||
pathContext = `${path === '/' ? '' : path}${route.path}`; | ||
this._emitAction(req, pathContext); | ||
} | ||
if (result === breakOn) { | ||
if (reducerContainer.isOr) { | ||
return Router.CONTINUE; | ||
} | ||
break; // skip the rest path reducers, continue with next route | ||
} else if (typeof result === 'string' || Array.isArray(result)) { | ||
const [exitPoint, data] = Array.isArray(result) ? result : [result]; | ||
// NOTE exit point can cause call of an upper exit point | ||
return yield* this._callExitPoint( | ||
route, req, res, relativePostBack, path, exitPoint, data | ||
); | ||
} else if (result !== continueOn) { | ||
return Router.END; | ||
} | ||
} | ||
return Router.CONTINUE; | ||
}.bind(this)); | ||
return continueOn; | ||
} | ||
@@ -214,0 +264,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
2727351
93
12099
6