UNPKG

botpress

Version:

The world's first CMS for bots. Easily create, manage and extend chatbots.

229 lines (184 loc) 10.8 kB
'use strict'; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash); var _bluebird = require('bluebird'); var _bluebird2 = _interopRequireDefault(_bluebird); var _engine = require('./engine'); var _engine2 = _interopRequireDefault(_engine); var _proactive = require('./proactive'); var _proactive2 = _interopRequireDefault(_proactive); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new _bluebird2.default(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return _bluebird2.default.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } /** * The Content Renderer is in charge of transforming an {@link ContentManager~Element} * into a channel-specific object. * @namespace ContentRenderer * @example * bp.renderers */ module.exports = ({ logger, middlewares, db, contentManager, botfile }) => { const processors = {}; // A map of all the platforms that can process outgoing messages const renderers = {}; // A map of all the registered renderers const registerChannel = ({ platform, processOutgoing }) => { if (!_lodash2.default.isString(platform)) { throw new Error(`[Renderers] Platform must be a string, got: ${platform}.`); } if (processors[platform]) { throw new Error(`[Renderers] Platform should only be registered once, platform: ${platform}.`); } if (!_lodash2.default.isFunction(processOutgoing)) { throw new Error(`[Renderers] processOutgoing must be a function, platform: ${platform}.`); } logger.verbose(`[Renderers] Enabled for ${platform}.`); processors[platform] = processOutgoing; }; /** * @callback Renderer * @memberof! ContentRenderer * @example * bp.renderers.register('#text', data => ({ text: data.englishText })) */ /** * Registers a new renderer * @param {String} name Unique name of the renderer (e.g. `#text`). * @param {ContentRenderer.Renderer} rendererFn The rendering function * @memberOf! ContentRenderer */ const register = (name, rendererFn) => { if (!_lodash2.default.isString(name)) { throw new Error(`Renderer name must be a string, received ${name}`); } if (name.startsWith('#')) { name = name.substr(1); } renderers[name] = rendererFn; }; /** * Removes a specific renderer if it exists * @param {String} name Unique name of the renderer (e.g. `#text`) * @memberOf! ContentRenderer */ const unregister = name => { if (!_lodash2.default.isString(name)) { throw new Error(`Renderer name must be a string, received ${name}`); } if (name.startsWith('#')) { name = name.substr(1); } delete renderers[name]; }; /** * Returns whether or not a renderer is already registered * @param {String} name Unique name of the renderer (e.g. `#text`) * @return {Boolean} * @memberOf! ContentRenderer */ const isRegistered = name => { if (!_lodash2.default.isString(name)) { throw new Error(`Renderer name must be a string, received ${name}`); } if (name.startsWith('#')) { name = name.substr(1); } return !!renderers[name]; }; const invoke = ({ rendererFn, rendererName, context, outputPlatform, incomingEvent = null }) => { // TODO throw if incomingEvents null <<<==== MOCK IT const options = { throwIfNoPlatform: true, currentPlatform: outputPlatform }; return (0, _engine2.default)({ rendererFn, rendererName, context, options, processors, incomingEvent }); }; const doSendContent = (() => { var _ref = _asyncToGenerator(function* (rendererFn, { rendererName, context, outputPlatform, incomingEvent }) { const messages = yield invoke({ rendererFn, rendererName, context, outputPlatform, incomingEvent }); return _bluebird2.default.mapSeries(messages, function (message) { if (message.__internal) { if (message.type === 'wait') { return _bluebird2.default.delay(message.wait); } } else { return middlewares.sendOutgoing(message); } }); }); return function doSendContent(_x, _x2) { return _ref.apply(this, arguments); }; })(); const sendContent = (() => { var _ref2 = _asyncToGenerator(function* (incomingEvent, rendererName, additionalData = {}) { rendererName = rendererName.startsWith('#') ? rendererName.substr(1) : rendererName; // "magic" constants that can be used in the renderers const initialData = { BOT_URL: botfile.botUrl }; if (rendererName.startsWith('!')) { const itemName = rendererName.substr(1); const contentItem = yield contentManager.getItem(itemName); if (!contentItem) { throw new Error(`Could not find content item with ID "${itemName}" in the Content Manager`); } const { categoryId: itemCategoryId } = contentItem; const itemCategory = contentManager.getCategorySchema(itemCategoryId); if (!itemCategory) { throw new Error(`Could not find category "${itemCategoryId}" in the Content Manager` + ` for item with ID "${itemName}"`); } const itemRenderer = itemCategory.renderer; if (!_lodash2.default.isString(itemRenderer) || !itemRenderer.startsWith('#') || itemRenderer.length <= 1) { throw new Error(`Invalid renderer '${itemRenderer}' in category '${itemCategoryId}' of Content Manager. A renderer must start with '#'`); } rendererName = itemRenderer.substr(1); Object.assign(initialData, _lodash2.default.isArray(contentItem.data) ? { items: contentItem.data } : contentItem.data); } const fullContext = _extends({}, initialData, { user: incomingEvent.user, event: _lodash2.default.pick(incomingEvent, ['raw', 'text', 'type', 'platform', 'user']) }, additionalData); const renderer = renderers[rendererName]; if (!renderer) { const error = `[Renderer] Renderer not defined (#${rendererName})`; logger.error(error); throw new Error(error); } yield doSendContent(renderer, { rendererName, context: fullContext, outputPlatform: incomingEvent.platform, incomingEvent }); return { renderer: rendererName, context: fullContext, outputPlatform: incomingEvent.platform }; }); return function sendContent(_x3, _x4) { return _ref2.apply(this, arguments); }; })(); const processIncoming = (event, next) => { event.reply = (rendererName, additionalData = {}) => sendContent(event, rendererName, additionalData); next(); }; const incomingMiddleware = { name: 'rendering.instrumentation', type: 'incoming', order: 2, // Should really be first module: 'botpress', description: 'Built-in Botpress middleware that adds a `.reply` to events. Works with renderers.', handler: processIncoming }; const proactiveMethods = (0, _proactive2.default)({ sendContent, db }); return _extends({ registerChannel, registerConnector: registerChannel, // DEPRECATED Use "channel" instead of "connector" register, unregister, isRegistered, incomingMiddleware }, proactiveMethods); }; //# sourceMappingURL=index.js.map