Comparing version 6.0.0 to 7.0.0
{ | ||
"extends": "standard", | ||
"plugins": [ | ||
"jest" | ||
] | ||
} | ||
"extends": "airbnb-base", | ||
"env": { | ||
"node": true, | ||
"jest": true | ||
}, | ||
"rules": { | ||
"semi": ["error", "never"] | ||
} | ||
} | ||
402
lib/index.js
@@ -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]) | ||
}) | ||
}) |
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
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
22859
13
740
11
8
1
+ Added@engyalo/watchdog-sdk@^2.3.0
+ Addedfixtures@0.0.2
+ Addednock@^10.0.6
+ Addedsinon@^7.2.3
+ Added@sinonjs/commons@1.8.6(transitive)
+ Added@sinonjs/formatio@3.2.2(transitive)
+ Added@sinonjs/samsam@3.3.3(transitive)
+ Added@sinonjs/text-encoding@0.7.3(transitive)
+ Addedarray-from@2.1.1(transitive)
+ Addedassertion-error@1.1.0(transitive)
+ Addedcall-bind@1.0.8(transitive)
+ Addedcall-bind-apply-helpers@1.0.2(transitive)
+ Addedcall-bound@1.0.3(transitive)
+ Addedchai@4.5.0(transitive)
+ Addedcheck-error@1.0.3(transitive)
+ Addeddebug@4.4.0(transitive)
+ Addeddeep-eql@4.1.4(transitive)
+ Addeddeep-equal@1.1.2(transitive)
+ Addeddefine-data-property@1.1.4(transitive)
+ Addeddefine-properties@1.2.1(transitive)
+ Addeddiff@3.5.0(transitive)
+ Addeddunder-proto@1.0.1(transitive)
+ Addedes-define-property@1.0.1(transitive)
+ Addedes-errors@1.3.0(transitive)
+ Addedes-object-atoms@1.1.1(transitive)
+ Addedfixtures@0.0.2(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedfunctions-have-names@1.2.3(transitive)
+ Addedget-func-name@2.0.2(transitive)
+ Addedget-intrinsic@1.2.7(transitive)
+ Addedget-proto@1.0.1(transitive)
+ Addedgopd@1.2.0(transitive)
+ Addedhas-flag@3.0.0(transitive)
+ Addedhas-property-descriptors@1.0.2(transitive)
+ Addedhas-symbols@1.1.0(transitive)
+ Addedhas-tostringtag@1.0.2(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedis-arguments@1.2.0(transitive)
+ Addedis-date-object@1.1.0(transitive)
+ Addedis-regex@1.2.1(transitive)
+ Addedisarray@0.0.1(transitive)
+ Addedjson-stringify-safe@5.0.1(transitive)
+ Addedjust-extend@4.2.1(transitive)
+ Addedlolex@4.2.05.1.2(transitive)
+ Addedloupe@2.3.7(transitive)
+ Addedmath-intrinsics@1.1.0(transitive)
+ Addedminimist@1.2.8(transitive)
+ Addedmkdirp@0.5.6(transitive)
+ Addedms@2.1.3(transitive)
+ Addednise@1.5.3(transitive)
+ Addednock@10.0.6(transitive)
+ Addedobject-inspect@1.13.4(transitive)
+ Addedobject-is@1.1.6(transitive)
+ Addedobject-keys@1.1.1(transitive)
+ Addedpath-to-regexp@1.9.0(transitive)
+ Addedpathval@1.1.1(transitive)
+ Addedpropagate@1.0.0(transitive)
+ Addedqs@6.14.0(transitive)
+ Addedregexp.prototype.flags@1.5.4(transitive)
+ Addedsemver@5.7.2(transitive)
+ Addedset-function-length@1.2.2(transitive)
+ Addedset-function-name@2.0.2(transitive)
+ Addedside-channel@1.1.0(transitive)
+ Addedside-channel-list@1.0.0(transitive)
+ Addedside-channel-map@1.0.1(transitive)
+ Addedside-channel-weakmap@1.0.2(transitive)
+ Addedsinon@7.5.0(transitive)
+ Addedsupports-color@5.5.0(transitive)
+ Addedtype-detect@4.0.84.1.0(transitive)