UNPKG

@botonic/plugin-flow-builder

Version:

Use Flow Builder to show your contents

194 lines 9.75 kB
import { __awaiter } from "tslib"; import { v7 as uuidv7 } from 'uuid'; import { FlowBuilderApi } from './api'; import { FLOW_BUILDER_API_URL_PROD, SEPARATOR, SOURCE_INFO_SEPARATOR, } from './constants'; import { FlowAiAgent, FlowBotAction, FlowCarousel, FlowHandoff, FlowImage, FlowKnowledgeBase, FlowRating, FlowText, FlowVideo, FlowWhatsappButtonList, FlowWhatsappCtaUrlButtonNode, } from './content-fields'; import { HtNodeWithContentType, } from './content-fields/hubtype-fields'; import { DEFAULT_FUNCTIONS } from './functions'; import { FlowBuilderJSONVersion, } from './types'; import { getNodeByUserInput } from './user-input'; import { inputHasTextData, resolveGetAccessToken } from './utils'; // TODO: Create a proper service to wrap all calls and allow api versioning export default class BotonicPluginFlowBuilder { constructor(options) { var _a, _b, _c; this.apiUrl = options.apiUrl || FLOW_BUILDER_API_URL_PROD; this.jsonVersion = options.jsonVersion || FlowBuilderJSONVersion.LATEST; this.flow = options.flow; this.getAccessToken = resolveGetAccessToken(options.getAccessToken); this.trackEvent = options.trackEvent; this.getKnowledgeBaseResponse = options.getKnowledgeBaseResponse; this.getAiAgentResponse = options.getAiAgentResponse; this.smartIntentsConfig = Object.assign(Object.assign({}, options === null || options === void 0 ? void 0 : options.smartIntentsConfig), { useLatest: this.jsonVersion === FlowBuilderJSONVersion.LATEST }); const customFunctions = options.customFunctions || {}; this.functions = Object.assign(Object.assign({}, DEFAULT_FUNCTIONS), customFunctions); this.inShadowing = { allowKeywords: ((_a = options.inShadowing) === null || _a === void 0 ? void 0 : _a.allowKeywords) || false, allowSmartIntents: ((_b = options.inShadowing) === null || _b === void 0 ? void 0 : _b.allowSmartIntents) || false, allowKnowledgeBases: ((_c = options.inShadowing) === null || _c === void 0 ? void 0 : _c.allowKnowledgeBases) || false, }; this.contentFilters = options.contentFilters || []; this.customRatingMessageEnabled = options.customRatingMessageEnabled || false; } resolveFlowUrl(request) { if (request.session.is_test_integration) { return `${this.apiUrl}/v1/bot_flows/{bot_id}/versions/${FlowBuilderJSONVersion.DRAFT}/`; } return `${this.apiUrl}/v1/bot_flows/{bot_id}/versions/${this.jsonVersion}/`; } pre(request) { return __awaiter(this, void 0, void 0, function* () { this.currentRequest = request; this.cmsApi = yield FlowBuilderApi.create({ flowUrl: this.resolveFlowUrl(request), url: this.apiUrl, flow: this.flow, accessToken: this.getAccessToken(request.session), request: this.currentRequest, }); const checkUserTextInput = inputHasTextData(request.input) && !request.input.payload; if (checkUserTextInput) { const resolvedLocale = this.cmsApi.getResolvedLocale(); const nodeByUserInput = yield getNodeByUserInput(this.cmsApi, resolvedLocale, request, this.smartIntentsConfig); request.input.payload = this.cmsApi.getPayload(nodeByUserInput === null || nodeByUserInput === void 0 ? void 0 : nodeByUserInput.target); } this.updateRequestBeforeRoutes(request); }); } updateRequestBeforeRoutes(request) { if (request.input.payload) { request.input.payload = this.removeSourceSuffix(request.input.payload); if (this.cmsApi.isBotAction(request.input.payload)) { const cmsBotAction = this.cmsApi.getNodeById(request.input.payload); request.input.payload = this.cmsApi.createPayloadWithParams(cmsBotAction); } } } removeSourceSuffix(payload) { return payload.split(SOURCE_INFO_SEPARATOR)[0]; } post(request) { request.input.nluResolution = undefined; } getContentsByContentID(contentID, prevContents) { return __awaiter(this, void 0, void 0, function* () { const node = this.cmsApi.getNodeByContentID(contentID); return yield this.getContentsByNode(node, prevContents); }); } getUUIDByContentID(contentID) { const node = this.cmsApi.getNodeByContentID(contentID); return node.id; } getContentsById(id, prevContents) { return __awaiter(this, void 0, void 0, function* () { const node = this.cmsApi.getNodeById(id); return yield this.getContentsByNode(node, prevContents); }); } getStartContents() { return __awaiter(this, void 0, void 0, function* () { const startNode = this.cmsApi.getStartNode(); this.currentRequest.session.flow_thread_id = uuidv7(); return yield this.getContentsByNode(startNode); }); } getContentsByNode(node, prevContents) { return __awaiter(this, void 0, void 0, function* () { const contents = prevContents || []; const resolvedLocale = this.cmsApi.getResolvedLocale(); if (node.type === HtNodeWithContentType.FUNCTION) { const targetId = yield this.callFunction(node, resolvedLocale); return this.getContentsById(targetId, contents); } const content = this.getFlowContent(node, resolvedLocale); if (content) { contents.push(content); } // If node is BOT_ACTION not add more contents to render, next nodes render after execute action if (node.type === HtNodeWithContentType.BOT_ACTION) { return contents; } // TODO: prevent infinite recursive calls if (node.follow_up) { return this.getContentsById(node.follow_up.id, contents); } return contents; }); } getFlowContent(hubtypeContent, locale) { switch (hubtypeContent.type) { case HtNodeWithContentType.TEXT: return FlowText.fromHubtypeCMS(hubtypeContent, locale, this.cmsApi); case HtNodeWithContentType.IMAGE: return FlowImage.fromHubtypeCMS(hubtypeContent, locale); case HtNodeWithContentType.CAROUSEL: return FlowCarousel.fromHubtypeCMS(hubtypeContent, locale, this.cmsApi); case HtNodeWithContentType.VIDEO: return FlowVideo.fromHubtypeCMS(hubtypeContent, locale); case HtNodeWithContentType.WHATSAPP_BUTTON_LIST: return FlowWhatsappButtonList.fromHubtypeCMS(hubtypeContent, locale, this.cmsApi); case HtNodeWithContentType.WHATSAPP_CTA_URL_BUTTON: return FlowWhatsappCtaUrlButtonNode.fromHubtypeCMS(hubtypeContent, locale, this.cmsApi); case HtNodeWithContentType.HANDOFF: return FlowHandoff.fromHubtypeCMS(hubtypeContent, locale, this.cmsApi); case HtNodeWithContentType.KNOWLEDGE_BASE: return FlowKnowledgeBase.fromHubtypeCMS(hubtypeContent); case HtNodeWithContentType.AI_AGENT: return FlowAiAgent.fromHubtypeCMS(hubtypeContent); case HtNodeWithContentType.RATING: return FlowRating.fromHubtypeCMS(hubtypeContent, locale); case HtNodeWithContentType.BOT_ACTION: return FlowBotAction.fromHubtypeCMS(hubtypeContent, locale, this.cmsApi); default: return undefined; } } callFunction(functionNode, locale) { return __awaiter(this, void 0, void 0, function* () { const functionNodeId = functionNode.id; const functionArguments = this.getArgumentsByLocale(functionNode.content.arguments, locale); const nameValues = functionArguments.map(arg => { return { [arg.name]: arg.value }; }); const args = Object.assign({ request: this.currentRequest, results: functionNode.content.result_mapping.map(r => r.result), }, ...nameValues); const functionResult = yield this.functions[functionNode.content.action](args); // TODO define result_mapping per locale?? const result = functionNode.content.result_mapping.find(r => r.result === functionResult); if (!(result === null || result === void 0 ? void 0 : result.target)) { throw new Error(`No result found for result_mapping for node with id: ${functionNodeId}`); } return result.target.id; }); } getArgumentsByLocale(args, locale) { let resultArguments = []; for (const arg of args) { if ('locale' in arg && arg.locale === locale) { resultArguments = [...resultArguments, ...arg.values]; } if ('type' in arg) { resultArguments = [...resultArguments, arg]; } } return resultArguments; } getPayloadParams(payload) { const payloadParams = JSON.parse(payload.split(SEPARATOR)[1] || '{}'); return payloadParams; } getFlowName(flowId) { return this.cmsApi.getFlowName(flowId); } } export * from './action'; export * from './content-fields'; export { trackFlowContent } from './tracking'; export { FlowBuilderJSONVersion, } from './types'; export * from './webview'; //# sourceMappingURL=index.js.map