UNPKG

conv-context

Version:

Conversation context manager

194 lines (157 loc) 4.96 kB
const _ = require('lodash'); const timestring = require('timestring'); const ONE_DAY = 24 * 60 * 60 * 1000; class Context { constructor (contextData = {}, thread) { this.contextKey = contextData.contextKey || '__convContext'; this.store = contextData.store || {}; this.output = contextData.output || {}; this.resolver = contextData.resolve; this.thread = thread; this.ttlBuffer = this.getTtlBuffer(contextData.ttlBuffer); } static init (contextData, thread) { return new Context(contextData, thread); } get selectStyle () { return _.get(this.output, 'selectStyle'); } get (key, defaultValue) { if (key === undefined || key === null || key === '') { return this.thread.get(this.contextKey, defaultValue); } if (_.isString(key)) { return this.thread.get(`${this.contextKey}.${key}`, defaultValue); } throw new Error('Invalid key'); } set (key, value) { if (key === undefined || key === null || key === '') { _.assign(this.store, value); // do not override an old value return this; } if (_.isString(key)) { _.set(this.store, key, value); return this; } if (_.isObject(key)) { _.forEach(key, (value, prop) => { this.set(prop, value); }); return this; } throw new Error('Invalid key'); } unset (key) { if (key === undefined || key === null || key === '') { this.store = undefined; return this.thread.unset(this.contextKey); } if (_.isString(key)) { _.set(this.store, key, undefined); return this.thread.unset(`${this.contextKey}.${key}`); } throw new Error('Invalid key'); } setStepContext (data, stepId=null) { if (!stepId) { stepId = this.thread.currentStepId; } this.set(`__steps.${stepId}`, data); return this; } getStepContext (stepId) { if (!stepId) throw new Error('Invalid step ID'); return this.get(`__steps.${stepId}`) } deleteStepContext (stepId) { if (!stepId) throw new Error('Invalid step ID'); this.unset(`__steps.${stepId}`); } filterStepContext (query={}) { return _.filter(this.get(`__steps`), query); } findStepContext (query={}) { return _.find(this.get(`__steps`), query); } findStepId (query={}) { return _.findKey(this.get(`__steps`), query); } async defaultResolver (output) { // helper resolve functions for each style const fromInherited = value => { const from = _.get(value, 'from', 'last'); return this.get(from); } const fromStepId = value => { const stepId = value.stepId || value.targetStepId || _.get(_.keys(value), '[0]'); if (!stepId || !_.isString(stepId)) throw new Error('Cannot get selected step ID'); return this.getStepContext(stepId); } const fromMergeFieldName = value => { const mfName = value.name || value.dataOutName || value.mergeFieldName || _.get(_.keys(value), '[0]'); if (!mfName || !_.isString(mfName)) throw new Error('No merge field name property found'); return this.thread.mergeFields[mfName].get(); } switch (this.selectStyle) { case 'inherited': return fromInherited(output.value); case 'step': return fromStepId(output.value); case 'dataOut': case 'mergeField': return fromMergeFieldName(output.value); case 'pick': return output.value.pickValue; default: return output.value; } } async resolve(resolver, data) { if (_.isFunction(resolver)) { return resolver.call(this.thread, this.output, this.store); } if (_.isUndefined(data) && !_.isUndefined(resolver)) { data = resolver; } if (_.isFunction(this.resolver)) { return this.resolver(this.thread, data); } return this.defaultResolver(this.output); } setSession () { this.thread.set(this.contextKey, this.store); } getTtlBuffer (ctxTtlBuffer) { if (_.isNumber(ctxTtlBuffer)) return ctxTtlBuffer; const bufferInput = _.get(ctxTtlBuffer, 'input'); if (!_.isString(bufferInput)) { return ONE_DAY; } try { return timestring(bufferInput, 'ms'); } catch { return ONE_DAY; } } async setShared (duration) { const remainingSession = new Date(this.thread.session.expirationDate) - Date.now(); const defaultTtl = remainingSession + this.ttlBuffer; const ttl = duration || defaultTtl; await this.thread.setShared(this.contextKey, this.store, ttl); } async save (shared=true, ttl=null) { this.setSession(); if (shared) { if (_.isNumber(shared) && ttl === null) ttl = shared; await this.setShared(ttl); } } } module.exports = Context; module.exports.default = Context; module.exports.Context = Context; Object.defineProperty(module.exports, "__esModule", { value: true });