UNPKG

@klevu/core

Version:

Typescript SDK that simplifies development on Klevu backend. Klevu provides advanced AI-powered search and discovery solutions for online retailers.

289 lines (288 loc) 12.8 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MoiSession = exports.startMoi = void 0; const index_js_1 = require("../../index.js"); const storage_js_1 = require("../../utils/storage.js"); const fetch_js_1 = require("../fetch.js"); const STORAGE_KEY = "klevu-moi-session"; const MAX_MESSAGES = 10; const saveProductInfo = (config, productInfo, widgetId) => __awaiter(void 0, void 0, void 0, function* () { return yield (0, fetch_js_1.post)(`${config.moiApiUrl}chat/${widgetId}/productInfo`, productInfo); }); function startMoi(options = {}) { var _a, _b, _c, _d, _e; return __awaiter(this, void 0, void 0, function* () { const config = ((_a = options.settings) === null || _a === void 0 ? void 0 : _a.configOverride) || index_js_1.KlevuConfig.getDefault(); let startingMessages = []; let questions = []; let ctx = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ klevuApiKey: config.apiKey, sessionId: "", visitorId: "", mode: options.mode, url: options.url, productId: options.productId, pqaWidgetId: options.pqaWidgetId, additionalData: options.additionalData }, (options.itemId && { itemId: options.itemId })), (options.itemGroupId && { itemGroupId: options.itemGroupId })), (options.itemVariantId && { itemVariantId: options.itemVariantId })), (options.channelId && { channelId: options.channelId })), (options.locale && { locale: options.locale })); const storedSession = yield getStoredSession(); let menu; let genericOptions; let feedbacks = []; let shouldSendMessage = (_b = options.settings) === null || _b === void 0 ? void 0 : _b.alwaysStartConversation; const PQAKey = options.productId || options.url; if (storedSession && storedSession.context) { switch (options.mode) { case undefined: ctx.sessionId = storedSession.context.sessionId; ctx.visitorId = storedSession.context.visitorId; if (storedSession.MOI) { startingMessages = storedSession.MOI.messages; menu = storedSession.MOI.menu; genericOptions = storedSession.MOI.genericOptions; feedbacks = storedSession.MOI.feedbacks; if ((_c = options.settings) === null || _c === void 0 ? void 0 : _c.alwaysStartConversation) { shouldSendMessage = storedSession.MOI.messages.length === 0; } } break; case "PQA": ctx.sessionId = storedSession.context.sessionId; ctx.visitorId = storedSession.context.visitorId; if (PQAKey && storedSession.PQA && storedSession.PQA[PQAKey]) { startingMessages = storedSession.PQA[PQAKey].messages; menu = storedSession.PQA[PQAKey].menu; genericOptions = storedSession.PQA[PQAKey].genericOptions; feedbacks = storedSession.PQA[PQAKey].feedbacks; questions = storedSession.PQA[PQAKey].questions || []; if ((_d = options.settings) === null || _d === void 0 ? void 0 : _d.alwaysStartConversation) { shouldSendMessage = storedSession.PQA[PQAKey].messages.length === 0; } } } } if (shouldSendMessage) { try { if (options.productInfo && options.mode === "PQA") yield saveProductInfo(config, options.productInfo, options.pqaWidgetId || 'NA'); } catch (err) { console.warn("Failed to save product Info", err); } const result = yield queryMoi({ context: ctx, }, config); if (!(result === null || result === void 0 ? void 0 : result.data) || !((_e = result === null || result === void 0 ? void 0 : result.data[0]) === null || _e === void 0 ? void 0 : _e.context)) { throw new Error("No context found"); } const parsed = parseResponse(result); ctx = Object.assign(Object.assign({}, ctx), parsed.context); startingMessages = parsed.messages; menu = parsed.menu; genericOptions = parsed.genericOptions; questions = parsed.questions || []; } return new MoiSession({ feedbacks, messages: startingMessages, questions, menu, genericOptions, }, options, ctx, config); }); } exports.startMoi = startMoi; class MoiSession { constructor(state, options, context, config) { var _a; this.messages = state.messages; this.questions = state.questions; this.menu = state.menu; this.genericOptions = state.genericOptions; this.feedbacks = (_a = state.feedbacks) !== null && _a !== void 0 ? _a : []; this.options = options; this.context = context; this.config = config; if (this.context.url && this.context.productId) { throw new Error("Cannot set both url and productId for PQA"); } this.save(); } query(request, target) { var _a, _b, _c, _d, _e, _f, _g; return __awaiter(this, void 0, void 0, function* () { if (request.message) { this.messages = [ ...((_a = this.messages) !== null && _a !== void 0 ? _a : []), { local: { message: request.message } }, ]; (_c = (_b = this.options).onMessage) === null || _c === void 0 ? void 0 : _c.call(_b); } const res = yield queryMoi(Object.assign({ context: this.context }, request), this.config, target); if (!res) { throw new Error("No response from MOI"); } // run actions first for (const obj of res.data) { if ("actions" in obj) { for (const action of obj.actions.actions) { //notify listeners if they want to do something const response = (_e = (_d = this.options).onAction) === null || _e === void 0 ? void 0 : _e.call(_d, action); // allow listeners to cancel the default actions if (response === false) { continue; } if (action.type === "purgeHistory") { this.clear(); } else if (action.type === "redirectToUrl" && action.context.link) { if (this.options.onRedirect) { this.options.onRedirect(action.context.link); } else { window.location.href = action.context.link; } } } } } const { messages, genericOptions, menu, context, questions } = parseResponse(res); this.messages = [...this.messages, ...messages]; if (this.messages.length > MAX_MESSAGES) { this.messages.shift(); } if (target === "send") { this.questions = [...questions]; } (_g = (_f = this.options).onMessage) === null || _g === void 0 ? void 0 : _g.call(_f); this.genericOptions = genericOptions; this.menu = menu; this.context = Object.assign(Object.assign({}, this.context), context); this.save(); return res; }); } clear() { var _a, _b; this.messages = []; this.feedbacks = []; this.save(); (_b = (_a = this.options).onMessage) === null || _b === void 0 ? void 0 : _b.call(_a); } save() { const PQAkey = this.context.productId || this.context.url; switch (this.context.mode) { case undefined: saveSession({ context: this.context, MOI: { menu: this.menu, genericOptions: this.genericOptions, messages: this.messages, feedbacks: this.feedbacks, }, }); break; case "PQA": if (!PQAkey) { throw new Error("Cannot save PQA session without url or productId"); } saveSession({ context: this.context, PQA: { [PQAkey]: { menu: this.menu, genericOptions: this.genericOptions, messages: this.messages, feedbacks: this.feedbacks, questions: this.questions || [], }, }, }); } } addFeedback(messageId, thumbs, reason) { return __awaiter(this, void 0, void 0, function* () { const oldFeedback = this.feedbacks.find((f) => f.id === messageId); if (oldFeedback) { oldFeedback.thumbs = thumbs; oldFeedback.reason = reason; } else { this.feedbacks.push({ id: messageId, thumbs, reason }); } return this.query({ feedback: { messageId, thumbs: thumbs.toUpperCase(), reason, }, }, "feedback"); }); } } exports.MoiSession = MoiSession; function getStoredSession() { const storedSession = storage_js_1.KlevuStorage.getItem(STORAGE_KEY); if (!storedSession) { return undefined; } return JSON.parse(storedSession); } function saveSession(session) { const saved = storage_js_1.KlevuStorage.getItem(STORAGE_KEY); let parsed = {}; if (saved) { parsed = JSON.parse(saved); } const key = session.context.productId || session.context.url; switch (session.context.mode) { case undefined: parsed.context = session.context; parsed.MOI = session.MOI; break; case "PQA": parsed.context = session.context; if (!parsed.PQA) { parsed.PQA = {}; } if (!key || !session.PQA) { throw new Error("No url, productId or PQA session"); } parsed.PQA[key] = session.PQA[key]; break; } storage_js_1.KlevuStorage.setItem(STORAGE_KEY, JSON.stringify(parsed)); } function queryMoi(request, config, target = "send") { return __awaiter(this, void 0, void 0, function* () { return yield (0, fetch_js_1.post)(`${config.moiApiUrl}chat/${target}`, request); }); } function parseResponse(response) { var _a; const messages = []; const questions = []; let genericOptions = undefined; let menu = undefined; const context = response.data[0].context; for (const d of response.data) { "message" in d && messages.push(d); "filter" in d && messages.push(d); "productData" in d && messages.push(d); "questions" in d && questions.push(...(((_a = d.questions) === null || _a === void 0 ? void 0 : _a.options) || [])); if ("genericOptions" in d) { genericOptions = d.genericOptions; } if ("menuOptions" in d) { menu = d.menuOptions; } } return { context, messages, menu, genericOptions, questions, }; }