UNPKG

@salutejs/client

Version:

Модуль взаимодействия с виртуальным ассистентом

557 lines (536 loc) 25 kB
import { e as __spreadArray, a as __rest, _ as __assign, b as __awaiter, f as createNanoObservable, d as createNanoEvents, c as __generator } from './common-ba25e019.js'; // Unique ID creation requires a high quality random # generator. In the browser we therefore // require the crypto API and do not support built-in fallback to lower quality random number // generators (like Math.random()). var getRandomValues; var rnds8 = new Uint8Array(16); function rng() { // lazy load so that environments that need to polyfill have a chance to do so if (!getRandomValues) { // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. Also, // find the complete implementation of crypto (msCrypto) on IE11. getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto !== 'undefined' && typeof msCrypto.getRandomValues === 'function' && msCrypto.getRandomValues.bind(msCrypto); if (!getRandomValues) { throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported'); } } return getRandomValues(rnds8); } var REGEX = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; function validate(uuid) { return typeof uuid === 'string' && REGEX.test(uuid); } /** * Convert array of 16 byte values to UUID string format of the form: * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */ var byteToHex = []; for (var i = 0; i < 256; ++i) { byteToHex.push((i + 0x100).toString(16).substr(1)); } function stringify(arr) { var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; // Note: Be careful editing this code! It's been tuned for performance // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 var uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one // of the following: // - One or more input array values don't map to a hex octet (leading to // "undefined" in the uuid) // - Invalid input values for the RFC `version` or `variant` fields if (!validate(uuid)) { throw TypeError('Stringified UUID is invalid'); } return uuid; } function v4(options, buf, offset) { options = options || {}; var rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` rnds[6] = rnds[6] & 0x0f | 0x40; rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided if (buf) { offset = offset || 0; for (var i = 0; i < 16; ++i) { buf[offset + i] = rnds[i]; } return buf; } return stringify(rnds); } var isDeepEqual = function (a, b) { // Простое значение if (typeof a !== 'object' || a === null) { return a === b; } // Массив if (Array.isArray(a)) { if (!Array.isArray(b) || a.length !== b.length) { return false; } return !a.some(function (valA, key) { return !isDeepEqual(valA, b[key]); }); } // Словарь if (typeof b !== 'object' || b === null) { return false; } var entriesA = Object.entries(a); var entriesB = Object.entries(b); if (entriesA.length !== entriesB.length) { return false; } return !entriesA.some(function (_a) { var key = _a[0], valA = _a[1]; return !(key in b && isDeepEqual(valA, b[key])); }); }; var findCommandIndex = function (arr, command) { var insets = ['insets', 'minimum_static_insets', 'maximum_static_insets', 'dynamic_insets']; var index = -1; if (command.type === 'character') { index = arr.findIndex(function (c) { return c.type === 'character' && c.character.id === command.character.id; }); } else if (insets.includes(command.type)) { index = arr.findIndex(function (c) { return c.type === command.type; }); } else if (command.type === 'app_context') { index = arr.findIndex(function (c) { return c.type === 'app_context'; }); } else { index = arr.findIndex(function (c) { return isDeepEqual(c, command); }); } return index; }; var appInitialData = (function () { var isPulled = false; var pulled = []; var committed = []; var diff = []; var isCommandWasPulled = function (command) { return findCommandIndex(pulled, command) >= 0; }; return { /** * Прочитать appInitialData. Запоминает состояние на момент прочтения * @returns Массив комманд */ pull: function () { isPulled = true; pulled = __spreadArray([], (window.appInitialData || [])); return __spreadArray([], pulled); }, /** * Прочитать appInitialData * @returns Массив комманд */ get: function () { return __spreadArray([], (window.appInitialData || [])); }, /** * Зафиксировать текущее состояние appInitialData */ commit: function () { committed = __spreadArray([], (window.appInitialData || [])); diff = isPulled === true ? (window.appInitialData || []).filter(function (c) { return !isCommandWasPulled(c); }) : __spreadArray([], (window.appInitialData || [])); }, /** * Возвращает диф appInitialData между pull и commit * @returns Массив комманд */ diff: function () { return __spreadArray([], diff); }, /** * Возвращает флаг наличия command в appInitialData на момент commit * @param command Команда, которую нужно проверить на наличие в appInitialData * @returns true - если команда была в appInitialData */ isCommitted: function (command) { var commandIndex = findCommandIndex(committed, command); var isCommitted = commandIndex >= 0; if (isCommitted) { committed.splice(commandIndex, 1); } return isCommitted; }, /** * Возвращает первое сообщение из appInitialData, подходящее под фильтры param * @param param Параметры: тип сообщения (например, smart_app_data) * и тип команды (значение поля smart_app_data.type) * @returns Первое сообщение, соответствующее параметрам или undefined */ find: function (_a) { var type = _a.type, command = _a.command; var initialCommands = __spreadArray([], (window.appInitialData || [])); var result = initialCommands.find(function (initialCommand) { if (!command && type && type === initialCommand.type) { return true; } var isCommandInSmartAppData = command && 'smart_app_data' in initialCommand; if (!isCommandInSmartAppData) { return; } if (command === initialCommand.smart_app_data.command || command === initialCommand.smart_app_data.type) { return true; } return false; }); return (result && 'smart_app_data' in result ? result.smart_app_data : result); }, }; })(); var excludeTags = ['A', 'AUDIO', 'BUTTON', 'INPUT', 'OPTION', 'SELECT', 'TEXTAREA', 'VIDEO']; function inIframe() { try { return window.self !== window.parent; } catch (e) { return true; } } if (/[a-zA-Z]/.test('1.35.9')) { console.info('%cPlease use the latest version of SaluteJS Client. Your version is 1.35.9', 'color: yellow; font-size: 14px'); } if (typeof window !== 'undefined' && inIframe()) { var postMessage_1 = function (action) { var _a; (_a = window.parent) === null || _a === void 0 ? void 0 : _a.postMessage(JSON.stringify(action), '*'); }; var historyBack_1 = function () { var prevPage = window.location.href; window.history.back(); setTimeout(function () { // закрываем страницу, если переход назад не поменял урл if (window.location.href === prevPage) { postMessage_1({ type: 'close' }); } }, 500); }; window.appInitialData = []; window.AssistantHost = { sendDataContainer: function (json) { postMessage_1({ type: 'sendDataContainer', payload: json }); }, close: function () { postMessage_1({ type: 'close' }); }, sendData: function (json) { postMessage_1({ type: 'sendData', payload: json }); }, setSuggests: function (suggests) { postMessage_1({ type: 'setSuggests', payload: suggests }); }, setHints: function (hints) { postMessage_1({ type: 'setHints', payload: hints }); }, ready: function () { postMessage_1({ type: 'ready' }); }, sendText: function (message) { postMessage_1({ type: 'sendText', payload: message }); }, setHeaderButtons: function (headerButtons) { postMessage_1({ type: 'setHeaderButtons', payload: typeof headerButtons === 'string' ? headerButtons : JSON.stringify(headerButtons), }); }, }; window.addEventListener('message', function (e) { var _a, _b, _c, _d, _e, _f, _g, _h; try { if (typeof e.data === 'string') { var data = JSON.parse(e.data); switch (data.type) { case 'onBack': historyBack_1(); break; case 'onData': (_b = (_a = window.AssistantClient) === null || _a === void 0 ? void 0 : _a.onData) === null || _b === void 0 ? void 0 : _b.call(_a, data.payload); break; case 'onRequestState': { var state = (_d = (_c = window.AssistantClient) === null || _c === void 0 ? void 0 : _c.onRequestState) === null || _d === void 0 ? void 0 : _d.call(_c); postMessage_1({ type: 'state', payload: state, requestId: data.requestId }); break; } case 'onRequestRecoveryState': { var recoverystate = (_f = (_e = window.AssistantClient) === null || _e === void 0 ? void 0 : _e.onRequestRecoveryState) === null || _f === void 0 ? void 0 : _f.call(_e); postMessage_1({ type: 'recoveryState', payload: recoverystate }); break; } case 'onStart': (_h = (_g = window.AssistantClient) === null || _g === void 0 ? void 0 : _g.onStart) === null || _h === void 0 ? void 0 : _h.call(_g); break; default: // eslint-disable-next-line no-console console.error(e, 'Unknown parsed message'); break; } } } catch (err) { // eslint-disable-next-line no-console console.error(err, 'Unknown message'); } }); window.addEventListener('keydown', function (_a) { var _b, _c; var code = _a.code; switch (code) { case 'Enter': if (document.activeElement && !excludeTags.includes(document.activeElement.tagName)) { (_c = (_b = document.activeElement).click) === null || _c === void 0 ? void 0 : _c.call(_b); } break; case 'Escape': historyBack_1(); break; } }); } var createAssistant = function (_a) { var _b, _c; var getState = _a.getState, getRecoveryState = _a.getRecoveryState, _d = _a.ready, ready = _d === void 0 ? true : _d; var _e = createNanoEvents(), on = _e.on, emitOriginal = _e.emit; var _f = createNanoEvents(), subscribeToCommand = _f.on, emitAllCommands = _f.emit; var observables = new Map(); var currentGetState = getState; var currentGetRecoveryState = getRecoveryState; var isInitialCommandsEmitted = false; var readyRetries = 0; var emitCommand = function (command) { if (command.type === 'smart_app_data') { emitOriginal('command', command.smart_app_data); } if (command.type === 'smart_app_error') { emitOriginal('error', command.smart_app_error); } return emitOriginal('data', command); }; var cancelTts = typeof ((_b = window.AssistantHost) === null || _b === void 0 ? void 0 : _b.cancelTts) !== 'undefined' ? function () { var _a, _b; (_b = (_a = window.AssistantHost).cancelTts) === null || _b === void 0 ? void 0 : _b.call(_a, ''); } : undefined; var emitAppInitialData = function () { if (!isInitialCommandsEmitted) { appInitialData.diff().forEach(function (c) { return emitCommand(c); }); isInitialCommandsEmitted = true; } }; var saveFirstSmartAppDataMid = function (mid) { // eslint-disable-next-line no-underscore-dangle if (typeof window.__ASSISTANT_CLIENT__.firstSmartAppDataMid === 'undefined') { // eslint-disable-next-line no-underscore-dangle window.__ASSISTANT_CLIENT__.firstSmartAppDataMid = mid; } }; window.AssistantClient = { onData: function (command) { var _a, _b, _c, _d, _e; if (appInitialData.isCommitted(command)) { return; } emitAllCommands(command.type, command); if (command.type === 'smart_app_data' && (((_a = command.sdk_meta) === null || _a === void 0 ? void 0 : _a.mid) || '-1') !== '-1') { saveFirstSmartAppDataMid((_b = command.sdk_meta) === null || _b === void 0 ? void 0 : _b.mid); } /// фильтр команды 'назад' /// может приходить type='system', но в типах это не отражаем // @ts-ignore if (command.type === 'system' && ((_d = (_c = command.system) === null || _c === void 0 ? void 0 : _c.command) === null || _d === void 0 ? void 0 : _d.toUpperCase()) === 'BACK') { return; } if (command.type === 'tts_state_update') { emitOriginal('tts', { state: command.state, owner: command.owner, }); } if ((command.type === 'smart_app_data' || command.type === 'smart_app_error') && ((_e = command.sdk_meta) === null || _e === void 0 ? void 0 : _e.requestId) && observables.has(command.sdk_meta.requestId)) { // eslint-disable-next-line @typescript-eslint/no-unused-vars var _f = command.sdk_meta; _f.requestId; var meta = __rest(_f, ["requestId"]); var _g = observables.get(command.sdk_meta.requestId) || {}, requestId = _g.requestId, next = _g.next; if (Object.keys(meta).length > 0 || requestId) { // eslint-disable-next-line camelcase command.sdk_meta = __assign({}, meta); if (requestId) { // eslint-disable-next-line camelcase command.sdk_meta = { requestId: requestId }; } } next === null || next === void 0 ? void 0 : next(command.type === 'smart_app_data' ? command : command); } emitCommand(command); }, onRequestState: function () { return currentGetState(); }, onRequestRecoveryState: function () { if (currentGetRecoveryState) { return currentGetRecoveryState(); } return undefined; }, onStart: function () { emitOriginal('start'); emitAppInitialData(); }, }; var readyFn = function () { return __awaiter(void 0, void 0, void 0, function () { var firstSmartAppDataMid; var _a, _b, _c; return __generator(this, function (_d) { readyRetries += 1; if (typeof ((_a = window.AssistantHost) === null || _a === void 0 ? void 0 : _a.ready) !== 'function') { return [2 /*return*/, new Promise(function (resolve, reject) { var _a; if (readyRetries > 3) { throw new Error("window.AssistantHost is not ready. The ready method has the type \"" + typeof ((_a = window.AssistantHost) === null || _a === void 0 ? void 0 : _a.ready) + "\""); } window.setTimeout(function () { readyFn().then(resolve, reject); }, 500); })]; } firstSmartAppDataMid = ((_c = (_b = appInitialData.get().find(function (c) { var _a; return c.type === 'smart_app_data' && (((_a = c.sdk_meta) === null || _a === void 0 ? void 0 : _a.mid) || '-1') !== '-1'; // @ts-ignore })) === null || _b === void 0 ? void 0 : _b.sdk_meta) === null || _c === void 0 ? void 0 : _c.mid) || '-1'; if (firstSmartAppDataMid !== '-1') { saveFirstSmartAppDataMid(firstSmartAppDataMid); } appInitialData.commit(); window.AssistantHost.ready(); return [2 /*return*/]; }); }); }; if (ready) { window.setTimeout(readyFn); // таймаут для подписки на start } var sendData = function (_a, onData) { var _b, _c, _d; var action = _a.action, name = _a.name, requestId = _a.requestId, mode = _a.mode; if ((_b = window.AssistantHost) === null || _b === void 0 ? void 0 : _b.sendDataContainer) { if (onData == null) { (_c = window.AssistantHost) === null || _c === void 0 ? void 0 : _c.sendDataContainer( /* eslint-disable-next-line camelcase */ JSON.stringify({ data: action, message_name: name || '', requestId: requestId, mode: mode })); return function () { }; } if (requestId && observables.has(requestId)) { throw new Error('requestId должен быть уникальным'); } var realRequestId_1 = requestId || v4(); var subscribe = createNanoObservable(function (_a) { var _b; var next = _a.next; (_b = window.AssistantHost) === null || _b === void 0 ? void 0 : _b.sendDataContainer( /* eslint-disable-next-line camelcase */ JSON.stringify({ data: action, message_name: name || '', requestId: realRequestId_1, mode: mode })); observables.set(realRequestId_1, { next: next, requestId: requestId }); }).subscribe; var unsubscribe_1 = subscribe({ next: onData }).unsubscribe; return function () { unsubscribe_1(); observables.delete(realRequestId_1); }; } if (onData != null) { throw new Error('Не поддерживается в данной версии клиента'); } (_d = window.AssistantHost) === null || _d === void 0 ? void 0 : _d.sendData(JSON.stringify(action), name || null); return function () { }; }; var sendAction = function (action, onData, onError, params) { if (params === void 0) { params = {}; } return sendData(__assign(__assign({}, params), { action: action }), function (data) { if (data.type === 'smart_app_data') { onData === null || onData === void 0 ? void 0 : onData(data.smart_app_data); } if (data.type === 'smart_app_error') { // @ts-ignore onError === null || onError === void 0 ? void 0 : onError(data.smart_app_error); } }); }; return { cancelTts: cancelTts, close: function () { var _a; return (_a = window.AssistantHost) === null || _a === void 0 ? void 0 : _a.close(); }, getGeo: typeof ((_c = window.AssistantHost) === null || _c === void 0 ? void 0 : _c.getGeo) !== 'undefined' ? function () { var _a, _b; (_b = (_a = window.AssistantHost).getGeo) === null || _b === void 0 ? void 0 : _b.call(_a); } : undefined, getInitialData: appInitialData.pull, findInInitialData: appInitialData.find, getRecoveryState: function () { return window.appRecoveryState; }, on: on, subscribeToCommand: subscribeToCommand, sendAction: sendAction, sendData: sendData, sendActionPromisified: function (action, params) { if (params === void 0) { params = {}; } return new Promise(function (resolve, reject) { var off = sendAction(action, function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } off(); resolve.apply(void 0, args); }, function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } off(); reject.apply(void 0, args); }, params); }); }, sendDataPromisified: function (params) { return new Promise(function (resolve) { var off = sendData(params, function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } off(); resolve.apply(void 0, args); }); }); }, setGetState: function (nextGetState) { currentGetState = nextGetState; }, setGetRecoveryState: function (nextGetRecoveryState) { currentGetRecoveryState = nextGetRecoveryState; }, setSuggests: function (suggestions) { var _a; (_a = window.AssistantHost) === null || _a === void 0 ? void 0 : _a.setSuggests(JSON.stringify({ suggestions: { buttons: suggestions } })); }, setHints: function (hints) { var _a; (_a = window.AssistantHost) === null || _a === void 0 ? void 0 : _a.setHints(JSON.stringify({ hints: hints })); }, sendText: function (message) { var _a; return (_a = window.AssistantHost) === null || _a === void 0 ? void 0 : _a.sendText(message); }, setHeaderButtons: function (headerButtons) { var _a, _b; if (!((_a = window.AssistantHost) === null || _a === void 0 ? void 0 : _a.setHeaderButtons)) { throw new Error('setHeaderButtons не поддерживается в данной версии клиента'); } (_b = window.AssistantHost) === null || _b === void 0 ? void 0 : _b.setHeaderButtons(JSON.stringify(headerButtons)); }, ready: readyFn, }; }; if (typeof window !== 'undefined') { // eslint-disable-next-line no-underscore-dangle window.__ASSISTANT_CLIENT__ = { version: '1.35.9' }; } export { createAssistant };