New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

flowx

Package Overview
Dependencies
Maintainers
2
Versions
51
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

flowx - npm Package Compare versions

Comparing version 6.0.0 to 7.0.0

.env

15

.eslintrc.json
{
"extends": "standard",
"plugins": [
"jest"
]
}
"extends": "airbnb-base",
"env": {
"node": true,
"jest": true
},
"rules": {
"semi": ["error", "never"]
}
}

@@ -5,2 +5,3 @@ const _ = require('lodash')

const Promise = require('bluebird')
const rethinkdbdash = require('rethinkdbdash')

@@ -10,3 +11,3 @@ const Matchers = require('./matchers')

const r = require('rethinkdbdash')({
const rethinkClient = rethinkdbdash({
host: process.env.RETHINKDB_HOST || 'localhost',

@@ -17,4 +18,4 @@ port: process.env.RETHINKDB_PORT || 28015,

const INITIAL_STATE = 0
const tableName = process.env.RETHINKDB_FLOWXTABLE || 'flowxtable'
const catboxOptions = {

@@ -27,237 +28,234 @@ host: process.env.RETHINKDB_HOST || 'localhost',

const client = new Catbox.Client(CatboxRethinkdb, catboxOptions)
const client = Promise.promisifyAll(new Catbox.Client(CatboxRethinkdb, catboxOptions))
const externals = {}
const INITIAL_STATE = 0
class Instance {
constructor (id, middlewares, initState) {
this.id = id
this.currentState = initState
this.middlewares = middlewares
}
}
module.exports.new = () => {
return new Promise((resolve, reject) => {
client.start((catboxError) => {
if (catboxError) {
reject(catboxError)
}
class Flow {
constructor (name, model) {
this.name = name
this.instances = []
this.middlewares = []
this.internalEmitter = {}
this.globalTransitions = model.globalTransitions || []
externals.Instance = class Instance {
constructor (id, middlewares, initState) {
this.id = id
this.currentState = initState
this.middlewares = []
this.middlewares = middlewares
}
}
// Load globalTransitions and sort all transitions
this.model = Utils.prepareModel(model)
}
externals.Flow = class Flow {
constructor (name, model) {
this.name = name
this.instances = []
this.middlewares = []
this.internalEmitter = {}
this.globalTransitions = model.globalTransitions || []
// Load globalTransitions and sort all transitions
this.model = Utils.prepareModel(model)
newInstance (id) {
return new Promise((resolve, reject) => {
const newState = _.cloneDeep(this.model.states.get(INITIAL_STATE))
const newInstance = new Instance(id, this.middlewares, newState)
console.log(`Creating new instance %j`, newInstance)
client.set(id, newInstance, this.model.ttl, (err) => {
if (err) {
return reject(err)
}
resolve(newInstance)
})
})
}
newInstance (id) {
return new Promise((resolve, reject) => {
const newState = _.cloneDeep(this.model.states.get(INITIAL_STATE))
const newInstance = new externals.Instance(id, this.middlewares, newState)
console.log(`Creating new instance %j`, newInstance)
client.set(id, newInstance, this.model.ttl, (err) => {
if (err) {
reject(err)
}
resolve(newInstance)
})
})
addInstance (instance) {
return new Promise((resolve, reject) => {
client.set(instance.id, instance, this.model.ttl, (err) => {
if (err) {
return reject(err)
}
resolve(instance)
})
})
}
addInstance (instance) {
return new Promise((resolve, reject) => {
client.set(instance.id, instance, this.model.ttl, (err) => {
if (err) {
reject(err)
}
resolve(instance)
})
getInstance (id) {
return new Promise((resolve, reject) => {
client.get(id, (err, cached) => {
if (err || !cached) {
this.newInstance(id).then((newInstance) => {
resolve(newInstance)
}).catch((newInstanceError) => {
reject(newInstanceError)
})
} else {
console.log(`Instance found: %j`, cached.item)
resolve(cached.item)
}
})
})
}
getInstance (id) {
return new Promise((resolve, reject) => {
client.get(id, (err, cached) => {
if (err || !cached) {
this.newInstance(id).then((newInstance) => {
resolve(newInstance)
}).catch((newInstanceError) => {
reject(newInstanceError)
})
} else {
console.log(`Instance found: %j`, cached.item)
resolve(cached.item)
}
})
})
}
searchNextState (stateName, global) {
return new Promise((resolve, reject) => {
const newState = this.model.states.find((state, key) => {
return (
state.id === stateName || state.id === parseInt(stateName, 10) || state.name === stateName) &&
(global === false || state.global !== undefined)
})
return newState ? resolve(_.cloneDeep(newState)) : reject(new Error(`State: ${stateName} => not found!`))
})
}
searchNextState (stateName, global) {
return new Promise((resolve, reject) => {
const newState = this.model.states.find((state, key) => {
return (
state.id === stateName || state.id === parseInt(stateName, 10) || state.name === stateName) &&
(global === false || state.global !== undefined)
validateTransition (instance, action) {
if (!(_.get(instance, 'currentState.transitions'))) {
console.log(`Transitions not found, searching for global state: ${action}`)
return action
}
return Promise.reduce(instance.currentState.transitions, (result, transition) => {
if(result.match) {
return result
}
return Matchers
.match(transition, action, { cache: result.cache, domain: this.name })
.then(match => {
if(match.match) {
return match
}
return {
action: match.action,
rule: match.rule,
match: false,
cache: match.cache,
}
})
}, {
action,
rule: action,
match: false,
cache: {},
})
.then((rule_match) => {
const rule = rule_match.match ? rule_match.rule : (rule_match.action.value || rule_match.action)
return rule
})
.catch((error) => {
console.error('Error matching transition', error)
return action
})
}
getState (instance, data) {
const updatedInstance = _.cloneDeep(instance)
return new Promise((resolve, reject) => {
if (data && data.action) {
this.validateTransition(updatedInstance, data.action)
.then((transition) => {
console.log('Moving to transition: %j', transition)
return Promise.props({
transition,
nextState: this.searchNextState(transition.to || transition, transition.to === undefined),
})
return newState ? resolve(_.cloneDeep(newState)) : reject(new Error(`State: ${stateName} => not found!`))
})
}
.then(({ transition, nextState }) => {
if (transition.use) {
updatedInstance.middlewares[transition.use](updatedInstance.currentState, (data) => {
updatedInstance.currentState = nextState
validateTransition (instance, action) {
return new Promise((resolve, reject) => {
if (instance.currentState.transitions) {
for (var i = 0; i < instance.currentState.transitions.length; i++) {
if (Array.isArray(action) && Matchers.matchList(instance.currentState.transitions[i], action)) {
return resolve(instance.currentState.transitions[i])
} else if (Matchers.matchOne(instance.currentState.transitions[i].when, action)) {
return resolve(instance.currentState.transitions[i])
}
}
console.log(`Transition not found, searching for global state: ${action}`)
return resolve(action)
} else {
console.log(`Transitions not found, searching for global state: ${action}`)
return resolve(action)
}
})
}
getState (instance, data) {
const updatedInstance = _.cloneDeep(instance)
return new Promise((resolve, reject) => {
if (data && data.action) {
this.validateTransition(updatedInstance, data.action).then((transition) => {
this.searchNextState(transition.to || transition, transition.to === undefined).then((nextState) => {
if (transition.use) {
updatedInstance.middlewares[transition.use](updatedInstance.currentState, (data) => {
updatedInstance.currentState = nextState
client.set(updatedInstance.id, updatedInstance, this.model.ttl, (err) => {
if (err) {
return reject(err)
}
if (updatedInstance.currentState.onEnter) {
if (updatedInstance.currentState.onEnter.emit) {
this.internalEmitter.emit(updatedInstance.currentState.onEnter.emit, updatedInstance.currentState.onEnter.data)
}
}
return resolve({state: updatedInstance.currentState, transition})
})
})
} else {
updatedInstance.currentState = nextState
client.set(updatedInstance.id, updatedInstance, this.model.ttl, (err) => {
console.log(`New state: %j`, updatedInstance)
if (err) {
return reject(err)
}
if (updatedInstance.currentState.onEnter) {
if (updatedInstance.currentState.onEnter.emit) {
this.internalEmitter.emit(updatedInstance.currentState.onEnter.emit, updatedInstance.currentState.onEnter.data)
}
}
return resolve({state: updatedInstance.currentState, transition})
})
client.set(updatedInstance.id, updatedInstance, this.model.ttl, (err) => {
if (err) {
return reject(err)
}
}).catch(() => {
this.goToDefault(updatedInstance).then((state) => {
return resolve({state, transition})
}).catch((err) => {
return reject(err)
})
if (updatedInstance.currentState.onEnter) {
if (updatedInstance.currentState.onEnter.emit) {
this.internalEmitter.emit(updatedInstance.currentState.onEnter.emit, updatedInstance.currentState.onEnter.data)
}
}
return resolve({state: updatedInstance.currentState, transition})
})
}).catch(() => {
this.goToDefault(updatedInstance).then((state) => {
return resolve({state, transition: {}})
}).catch((err) => {
return reject(err)
})
})
} else {
return resolve({state: updatedInstance.currentState, transition: {}})
}
})
}
goToDefault (instance) {
return new Promise((resolve, reject) => {
this.searchNextState('default', false).then((nextState) => {
instance.currentState = nextState
client.set(instance.id, instance, this.model.ttl, (err) => {
updatedInstance.currentState = nextState
client.set(updatedInstance.id, updatedInstance, this.model.ttl, (err) => {
if (err) {
reject(err)
return reject(err)
}
if (instance.currentState.onEnter) {
if (instance.currentState.onEnter.emit) {
this.internalEmitter.emit(instance.currentState.onEnter.emit, instance.currentState.onEnter.data)
}
if (_.get(updatedInstance, 'currentState.onEnter.emit', false)) {
this.internalEmitter.emit(updatedInstance.currentState.onEnter.emit, updatedInstance.currentState.onEnter.data)
}
resolve(instance.currentState)
return resolve({state: updatedInstance.currentState, transition})
})
}
}).catch((e) => {
console.error('Error searching for next state', e)
return this.goToDefault(updatedInstance).then((state) => {
return resolve({state, transition: {}})
}).catch((err) => {
return resolve({ template: err })
return reject(err)
})
})
}
} else {
return resolve({state: updatedInstance.currentState, transition: {}})
}
})
}
saveInstance (instance) {
return new Promise((resolve, reject) => {
client.set(instance.id, instance, this.model.ttl, (err) => {
if (err) {
reject(err)
}
resolve(instance)
})
})
}
goToDefault (instance) {
return new Promise((resolve, reject) => {
this.searchNextState('default', false).then((nextState) => {
instance.currentState = nextState
client.set(instance.id, instance, this.model.ttl, (err) => {
if (err) {
return reject(err)
}
if (_.get(instance, 'currentState.onEnter.emit', false)) {
this.internalEmitter.emit(instance.currentState.onEnter.emit, instance.currentState.onEnter.data)
}
resolve(instance.currentState)
})
}).catch((err) => {
return resolve({ template: err })
})
})
}
on (eventName, eventFunction) {
this.internalEmitter.on(eventName, eventFunction)
saveInstance (instance) {
return new Promise((resolve, reject) => {
client.set(instance.id, instance, this.model.ttl, (err) => {
if (err) {
return reject(err)
}
resolve(instance)
})
})
}
register (name, fn) {
this.middlewares[name] = fn
}
on (eventName, eventFunction) {
this.internalEmitter.on(eventName, eventFunction)
}
getInstancesBySegment (segment) {
return new Promise((resolve, reject) => {
r.table(tableName).filter({
value: {
id: {
segment: segment
}
}
}).run().then(instances => {
return resolve(instances)
}).catch(error => {
return reject(error)
})
})
}
register (name, fn) {
this.middlewares[name] = fn
}
findInstances (filter) {
return new Promise((resolve, reject) => {
r.table(tableName).filter(filter).run().then(instances => {
return resolve(instances)
}).catch(error => {
return reject(error)
})
})
getInstancesBySegment (segment) {
return this.findInstances({
value: {
id: {
segment: segment
}
getGlobalTransitions () {
return _.cloneDeep(this.globalTransitions)
}
}
resolve(externals)
})
}
findInstances (filter) {
return rethinkClient.table(tableName).filter(filter).run()
}
getGlobalTransitions () {
return _.cloneDeep(this.globalTransitions)
}
}
module.exports.new = () => client.startAsync()
.then(() => {
return { Instance, Flow }
})
}

@@ -1,4 +0,7 @@

'use strict'
const Promise = require('bluebird')
const watchdogSdk = require('@engyalo/watchdog-sdk')
const matchRule = (rule, action, separator) => {
const TRANSITION_TYPE_WATCHDOG = 'watchdog'
const matchRule = (rule, action, _separator) => {
return rule === action

@@ -22,21 +25,106 @@ }

const matchOne = (rule, action) => {
return matchRule(rule, action) ||
matchRegExp(rule, action) ||
matchAll(rule)
const matchWatchdogActions = (rule, wdActions, cache) => {
const { when, confidence } = rule
return wdActions.reduce((result, action) => {
if(result.match) {
return result
}
return {
action,
rule,
cache,
match: (matchRule(when, action.value) ||
matchRegExp(when, action.value) ||
matchAll(when)) && action.confidence >= confidence,
}
}, {
action: wdActions,
rule,
cache,
match: false
})
}
const matchList = (rule, actionsList) => {
for (var i = 0; i < actionsList.length; i++) {
if (matchOne(rule.when, actionsList[i].value)) {
if (((rule.type === undefined && actionsList[i].type === undefined) || actionsList[i].type === rule.type) &&
((rule.confidence === undefined && actionsList[i].confidence === undefined) || actionsList[i].confidence > rule.confidence)) {
return true
const matchWatchdog = (domain, rule, action, cache) => {
if(cache.wdCalled) {
return matchWatchdogActions(rule, cache.wdActions, cache)
}
return watchdogSdk.getIntent(domain, action.value)
.then((wdResponse) => {
const wdClassification = wdResponse.results[0]
const intents = wdClassification.intents.filter(w => w.category !== 'UKN')
const wdActions = intents.map(intent => ({
value: intent.category,
confidence: intent.confidence,
}))
return matchWatchdogActions(rule, wdActions, {
wdCalled: true,
wdClassification,
wdActions,
})
}).catch((e) => {
console.error('Error while getting intent from watchdog', e)
return {
action,
match: false, // check
cache: {
wdCalled: true,
wdClassification: null,
wdActions: [],
},
}
}
})
}
const matchOne = Promise.method((rule, action, { cache={}, domain='' }={}) => {
const { type, when } = rule
const value = action.value || action
if(type === TRANSITION_TYPE_WATCHDOG) {
return matchWatchdog(domain, rule, action, cache)
}
return false
return {
action,
rule,
cache,
match: (action.type === rule.type) &&
(matchRule(when, value) ||
matchRegExp(when, value) ||
matchAll(when)) &&
((rule.confidence === undefined && action.confidence === undefined) ||
action.confidence >= rule.confidence),
}
})
const matchList = (rule, actionsList, { cache={}, domain='' }={}) => {
return Promise
.reduce(actionsList, (result, action) => {
if(result.match) {
return result
}
return matchOne(rule, action, { domain, cache: result.cache })
}, {
action: { value: '' },
match: false,
rule: null,
cache: cache,
})
}
const match = (rule, action, options={}) => {
if (Array.isArray(action)) {
return matchList(rule, action, options)
}
return matchOne(rule, action, options)
}
module.exports = {
match,
matchRule,

@@ -43,0 +131,0 @@ matchRegExp,

{
"name": "flowx",
"version": "6.0.0",
"version": "7.0.0",
"description": "",
"main": "lib/index.js",
"scripts": {
"test": "./node_modules/jest/bin/jest.js"
"test": "./node_modules/jest/bin/jest.js --runInBand"
},

@@ -20,2 +20,3 @@ "author": {

"dependencies": {
"@engyalo/watchdog-sdk": "^2.3.0",
"bluebird": "^3.4.7",

@@ -25,5 +26,8 @@ "catbox": "^7.1.3",

"catbox-rethinkdb": "^1.2.0",
"fixtures": "0.0.2",
"immutable": "^3.8.1",
"lodash": "^4.17.4",
"rethinkdbdash": "^2.3.31"
"nock": "^10.0.6",
"rethinkdbdash": "^2.3.31",
"sinon": "^7.2.3"
},

@@ -30,0 +34,0 @@ "devDependencies": {

@@ -1,2 +0,4 @@

'use strict'
// const fx = require('fixtures')
const nock = require('nock')
const sinon = require('sinon')

@@ -29,2 +31,6 @@ const Flowx = require('../')

confidence: 0.5
},
{
when: 'toState7',
to: 7
}

@@ -95,4 +101,36 @@ ]

to: 'state1'
},
{
when: 'toState7',
to: 7
}
]
},
{
id: 7,
name: 'state7',
transitions: [
{
when: 'promo',
to: 'state1',
type: 'watchdog',
confidence: 0.6,
},
{
when: 'buy-ticket',
to: 'state8',
type: 'watchdog',
confidence: 0.6,
},
]
},
{
id: 8,
name: 'state8',
transitions: [
{
when: 'toState1',
to: 'state1',
},
]
}

@@ -103,179 +141,154 @@ ]

const preparedData = Util.prepareModel(data).states.toJS()
const watchdogBaseUri = process.env.WATCHDOG_BASE_URI
test('Get current state without action', (done) => {
Flowx.new().then((flowxServer) => {
let instance
const fakeRequestWatchdog = () => {
nock(watchdogBaseUri)
.post('/domains/myFlow/intents/search?numIntents=3')
.reply(200, {
domain: 'test',
results: [
{
classificationId: 3524063,
entities: [],
id: 4,
intents: [
{
category: 'buy-ticket',
categoryDescription: 'Flight ticket sellings',
confidence: 0.6926555037498474,
},
{
category: 'promo',
categoryDescription: 'Promotions',
confidence: 0.26473885774612427,
},
],
},
],
})
}
beforeEach(() => (Flowx.new()
.then((flowxServer) => {
const flow = new flowxServer.Flow('myFlow', data)
const key = {
id: '111',
segment: 'test'
segment: 'test',
}
flow.getInstance(key).then((bot) => {
flow.getState(bot, {}).then((state) => {
expect(state).toEqual(preparedData[0])
done()
return flow.getInstance(key)
.then((bot) => {
instance = { flow, bot }
})
})
})
))
test('Get current state without action', () => {
const { flow, bot } = instance
return flow.getState(bot, {}).then((state) => {
expect(state.state).toEqual(preparedData[0])
})
})
test('Get state with action', (done) => {
Flowx.new().then((flowxServer) => {
const flow = new flowxServer.Flow('myFlow', data)
const key = {
id: '111',
segment: 'test'
}
flow.getInstance(key).then((bot) => {
flow.getState(bot, { action: 'toState2' }).then((state) => {
expect(state).toEqual(preparedData[1])
done()
})
})
test('Get state with action', () => {
const { flow, bot } = instance
return flow.getState(bot, { action: 'toState2' }).then((state) => {
expect(state.state).toEqual(preparedData[1])
})
})
test('Get state with action regExp', (done) => {
Flowx.new().then((flowxServer) => {
const flow = new flowxServer.Flow('myFlow', data)
const key = {
id: '111',
segment: 'test'
}
flow.getInstance(key).then((bot) => {
flow.getState(bot, { action: '3' }).then((state) => {
expect(state).toEqual(preparedData[2])
done()
})
})
test('Get state with action regExp', () => {
const { flow, bot } = instance
return flow.getState(bot, { action: '3' }).then((state) => {
expect(state.state).toEqual(preparedData[2])
})
})
test('Get state with action wildcard', (done) => {
Flowx.new().then((flowxServer) => {
const flow = new flowxServer.Flow('myFlow', data)
const key = {
id: '111',
segment: 'test'
}
flow.getInstance(key).then((bot) => {
flow.getState(bot, { action: 'abc' }).then((state) => {
expect(state).toEqual(preparedData[0])
done()
})
})
test('Get state with action wildcard', () => {
const { flow, bot } = instance
return flow.getState(bot, { action: 'abc' }).then((state) => {
expect(state.state).toEqual(preparedData[0])
})
})
test('Get global state', (done) => {
Flowx.new().then((flowxServer) => {
const flow = new flowxServer.Flow('myFlow', data)
const key = {
id: '111',
segment: 'test'
}
flow.getInstance(key).then((bot) => {
flow.getState(bot, { action: 'globalState' }).then((state) => {
expect(state).toEqual(preparedData[3])
done()
})
})
test('Get global state', () => {
const { flow, bot } = instance
return flow.getState(bot, { action: 'globalState' }).then((state) => {
expect(state.state).toEqual(preparedData[3])
})
})
test('Get default state', (done) => {
Flowx.new().then((flowxServer) => {
const flow = new flowxServer.Flow('myFlow', data)
const key = {
id: '111',
segment: 'test'
}
flow.getInstance(key).then((bot) => {
flow.getState(bot, { action: 'test' }).then((state) => {
expect(state).toEqual(preparedData[4])
done()
})
})
test('Get default state', () => {
const { flow, bot } = instance
return flow.getState(bot, { action: 'test' }).then((state) => {
expect(state.state).toEqual(preparedData[4])
})
})
test('Get state using global transition', (done) => {
Flowx.new().then((flowxServer) => {
const flow = new flowxServer.Flow('myFlow', data)
const key = {
id: '111',
segment: 'test'
}
flow.getInstance(key).then((bot) => {
flow.getState(bot, { action: 'toState1' }).then((state) => {
expect(state).toEqual(preparedData[0])
done()
})
})
test('Get state using global transition', () => {
const { flow, bot } = instance
return flow.getState(bot, { action: 'toState1' }).then((state) => {
expect(state.state).toEqual(preparedData[0])
})
})
test('Get state with condifence', (done) => {
Flowx.new().then((flowxServer) => {
const flow = new flowxServer.Flow('myFlow', data)
const key = {
id: '111',
segment: 'test'
}
flow.getInstance(key).then((bot) => {
const actions = [
{
type: 'test',
value: 'toState3',
confidence: 0.6
}
]
flow.getState(bot, { action: actions }).then((state) => {
expect(state).toEqual(preparedData[2])
done()
})
})
test('Get state with confidence', () => {
const { flow, bot } = instance
const actions = [
{
type: 'test',
value: 'toState3',
confidence: 0.6,
},
]
return flow.getState(bot, { action: actions }).then((state) => {
expect(state.state).toEqual(preparedData[2])
})
})
test('Get state with actions array without type', (done) => {
Flowx.new().then((flowxServer) => {
const flow = new flowxServer.Flow('myFlow', data)
const key = {
id: '111',
segment: 'test'
}
flow.getInstance(key).then((bot) => {
const actions = [
{
value: 'toState2'
}
]
flow.getState(bot, { action: actions }).then((state) => {
expect(state).toEqual(preparedData[1])
done()
})
})
test('Get state with actions array without type', () => {
const { flow, bot } = instance
const actions = [
{
value: 'toState2',
},
]
return flow.getState(bot, { action: actions }).then((state) => {
expect(state.state).toEqual(preparedData[1])
})
})
test('Get state with actions array with type without confidence', (done) => {
Flowx.new().then((flowxServer) => {
const flow = new flowxServer.Flow('myFlow', data)
const key = {
id: '111',
segment: 'test'
}
flow.getInstance(key).then((bot) => {
const actions = [
{
value: 'init',
type: 'user'
}
]
flow.getState(bot, { action: actions }).then((state) => {
expect(state).toEqual(preparedData[5])
done()
})
test('Get state with actions array with type without confidence', () => {
const { flow, bot } = instance
const actions = [
{
value: 'init',
type: 'user',
},
]
return flow.getState(bot, { action: actions }).then((state) => {
expect(state.state).toEqual(preparedData[5])
})
})
test('Get state with a watchdog transition', () => {
fakeRequestWatchdog()
const { flow, bot } = instance
const actions = [
{
value: 'I want to buy a flight ticket',
},
]
return flow.getState(bot, { action: 'toState7' })
.then((state) => {
expect(state.state).toEqual(preparedData[6])
const bot_new = Object.assign({}, bot, { currentState: state.state })
return flow.getState(bot_new, { action: actions })
})
})
})
.then((state) => {
expect(state.state).toEqual(preparedData[7])
})
})
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc