| Current Path : /var/www/homesaver/www/bitrix/js/pull/configholder/dist/ |
| Current File : /var/www/homesaver/www/bitrix/js/pull/configholder/dist/pull.configholder.bundle.js.map |
{"version":3,"file":"pull.configholder.bundle.js","sources":["../../util/src/util.js","../../client/src/consts.js","../src/configholder.js"],"sourcesContent":["/* eslint-disable @bitrix24/bitrix24-rules/no-typeof */\n\nexport const browser = {\n\tIsChrome(): boolean\n\t{\n\t\treturn navigator.userAgent.toLowerCase().includes('chrome');\n\t},\n\n\tIsFirefox(): boolean\n\t{\n\t\treturn navigator.userAgent.toLowerCase().includes('firefox');\n\t},\n\n\tIsIe(): boolean\n\t{\n\t\treturn navigator.userAgent.match(/(Trident\\/|MSIE\\/)/) !== null;\n\t},\n};\n\nexport function getTimestamp(): number\n{\n\treturn Date.now();\n}\n\n/**\n * Reduces errors array to single string.\n * @param {array} errors\n * @return {string}\n */\nexport function errorsToString(errors): string\n{\n\tif (!isArray(errors))\n\t{\n\t\treturn '';\n\t}\n\n\treturn errors.reduce((accum, currentValue) => {\n\t\tconst result = accum === '' ? accum : `${accum}; `;\n\n\t\treturn `${result + currentValue.code}: ${currentValue.message}`;\n\t}, '');\n}\n\nexport function isString(item): boolean\n{\n\treturn item === '' ? true : (item ? (typeof (item) === 'string' || item instanceof String) : false);\n}\n\nexport function isArray(item): boolean\n{\n\treturn item && Object.prototype.toString.call(item) === '[object Array]';\n}\n\nexport function isFunction(item): boolean\n{\n\treturn item === null ? false : (typeof (item) === 'function' || item instanceof Function);\n}\n\nexport function getFunction(f: Function): Function\n{\n\treturn isFunction(f) ? f : function() {};\n}\n\nexport function isDomNode(item): boolean\n{\n\treturn item && typeof (item) === 'object' && 'nodeType' in item;\n}\n\nexport function isDate(item): boolean\n{\n\treturn item && Object.prototype.toString.call(item) === '[object Date]';\n}\n\nexport function isNumber(item): boolean\n{\n\treturn typeof item === 'number' && Number.isFinite(item);\n}\n\nexport function isObject(item): boolean\n{\n\treturn Boolean(item) && typeof item === 'object';\n}\n\nexport function isPlainObject(item): boolean\n{\n\treturn Boolean(item) && typeof item === 'object' && item.constructor === Object;\n}\n\nexport function isNotEmptyString(item): boolean\n{\n\treturn isString(item) ? item.length > 0 : false;\n}\n\nexport function isJsonRpcRequest(item): boolean\n{\n\treturn (\n\t\ttypeof (item) === 'object'\n\t\t&& item\n\t\t&& 'jsonrpc' in item\n\t\t&& isNotEmptyString(item.jsonrpc)\n\t\t&& 'method' in item\n\t\t&& isNotEmptyString(item.method)\n\t);\n}\n\nexport function isJsonRpcResponse(item): boolean\n{\n\treturn (\n\t\ttypeof (item) === 'object'\n\t\t&& item\n\t\t&& 'jsonrpc' in item\n\t\t&& isNotEmptyString(item.jsonrpc)\n\t\t&& 'id' in item\n\t\t&& (\n\t\t\t'result' in item\n\t\t\t|| 'error' in item\n\t\t)\n\t);\n}\n\nexport function buildQueryString(params: Object): string\n{\n\tlet result = '';\n\tfor (const key of Object.keys(params))\n\t{\n\t\tconst value = params[key];\n\t\tif (isArray(value))\n\t\t{\n\t\t\tfor (const [index, valueElement] of value.entries())\n\t\t\t{\n\t\t\t\tconst left = encodeURIComponent(`${key}[${index}]`);\n\t\t\t\tconst right = `${encodeURIComponent(valueElement)}&`;\n\t\t\t\tresult += `${left}=${right}`;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tresult += `${encodeURIComponent(key)}=${encodeURIComponent(value)}&`;\n\t\t}\n\t}\n\n\tif (result.length > 0)\n\t{\n\t\tresult = result.slice(0, Math.max(0, result.length - 1));\n\t}\n\n\treturn result;\n}\n\nexport function clone(obj: any, bCopyObj = true): any\n{\n\tlet _obj, i, l;\n\n\tif (obj === null)\n\t{\n\t\treturn null;\n\t}\n\n\tif (isDomNode(obj))\n\t{\n\t\t_obj = obj.cloneNode(bCopyObj);\n\t}\n\telse if (typeof obj === 'object')\n\t{\n\t\tif (isArray(obj))\n\t\t{\n\t\t\t_obj = [];\n\t\t\tfor (i = 0, l = obj.length; i < l; i++)\n\t\t\t{\n\t\t\t\tif (typeof obj[i] === 'object' && bCopyObj)\n\t\t\t\t{\n\t\t\t\t\t_obj[i] = clone(obj[i], bCopyObj);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t_obj[i] = obj[i];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_obj = {};\n\t\t\tif (obj.constructor)\n\t\t\t{\n\t\t\t\tif (isDate(obj))\n\t\t\t\t{\n\t\t\t\t\t_obj = new Date(obj);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t_obj = new obj.constructor();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (i in obj)\n\t\t\t{\n\t\t\t\tif (!obj.hasOwnProperty(i))\n\t\t\t\t{\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (typeof obj[i] === 'object' && bCopyObj)\n\t\t\t\t{\n\t\t\t\t\t_obj[i] = clone(obj[i], bCopyObj);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t_obj[i] = obj[i];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t_obj = obj;\n\t}\n\n\treturn _obj;\n}\n\nexport function getDateForLog(): string\n{\n\tconst d = new Date();\n\n\treturn `${d.getFullYear()}-${lpad(d.getMonth(), 2, '0')}-${lpad(d.getDate(), 2, '0')} ${lpad(d.getHours(), 2, '0')}:${lpad(d.getMinutes(), 2, '0')}`;\n}\n\nexport function lpad(str: string, length, chr = ' '): string\n{\n\tif (str.length > length)\n\t{\n\t\treturn str;\n\t}\n\n\tlet result = '';\n\tfor (let i = 0; i < length - result.length; i++)\n\t{\n\t\tresult += chr;\n\t}\n\n\treturn result + str;\n}\n\nexport function isWebSocketSupported(): boolean\n{\n\treturn typeof 'WebSocket' !== 'undefined';\n}\n\nexport class CircularBuffer<T>\n{\n\tstorage: T[];\n\tcapacity: number;\n\tpointer = 0;\n\n\tconstructor(capacity: number)\n\t{\n\t\tif (capacity <= 0)\n\t\t{\n\t\t\tthrow new Error('capacity must be > 0');\n\t\t}\n\n\t\tthis.capacity = capacity;\n\t\tthis.storage = [];\n\t}\n\n\tpush(element: T)\n\t{\n\t\tthis.storage[this.pointer] = element;\n\t\tthis.pointer++;\n\t\tif (this.pointer >= this.capacity)\n\t\t{\n\t\t\tthis.pointer = 0;\n\t\t}\n\t}\n\n\tgetAll(): T[]\n\t{\n\t\tif (this.pointer === 0)\n\t\t{\n\t\t\treturn this.storage;\n\t\t}\n\n\t\treturn [...this.storage.slice(this.pointer), ...this.storage.slice(0, this.pointer)];\n\t}\n}\n","export const REVISION = 19; // api revision - check module/pull/include.php\n\nexport const ConnectionType = {\n\tWebSocket: 'webSocket',\n\tLongPolling: 'longPolling',\n};\n\nexport const PullStatus = {\n\tOnline: 'online',\n\tOffline: 'offline',\n\tConnecting: 'connect',\n};\n\nexport const SenderType = {\n\tUnknown: 0,\n\tClient: 1,\n\tBackend: 2,\n};\n\nexport const SubscriptionType = {\n\tServer: 'server',\n\tClient: 'client',\n\tOnline: 'online',\n\tStatus: 'status',\n\tRevision: 'revision',\n};\n\nexport const CloseReasons = {\n\tNORMAL_CLOSURE: 1000,\n\tSERVER_DIE: 1001,\n\tCONFIG_REPLACED: 3000,\n\tCHANNEL_EXPIRED: 3001,\n\tSERVER_RESTARTED: 3002,\n\tCONFIG_EXPIRED: 3003,\n\tMANUAL: 3004,\n\tSTUCK: 3005,\n\tBACKEND_ERROR: 3006,\n\tWRONG_CHANNEL_ID: 4010,\n};\n\nexport const SystemCommands = {\n\tCHANNEL_EXPIRE: 'CHANNEL_EXPIRE',\n\tCONFIG_EXPIRE: 'CONFIG_EXPIRE',\n\tSERVER_RESTART: 'SERVER_RESTART',\n};\n\nexport const ServerMode = {\n\tShared: 'shared',\n\tPersonal: 'personal',\n};\n\nexport const RpcMethod = {\n\tPublish: 'publish',\n\tGetUsersLastSeen: 'getUsersLastSeen',\n\tPing: 'ping',\n\tListChannels: 'listChannels',\n\tSubscribeStatusChange: 'subscribeStatusChange',\n\tUnsubscribeStatusChange: 'unsubscribeStatusChange',\n};\n","/* eslint-disable @bitrix24/bitrix24-rules/no-native-events-binding */\n// noinspection ES6PreferShortImport\n\nimport { getTimestamp, isNumber, isPlainObject } from '../../util/src/util';\nimport { REVISION } from '../../client/src/consts';\nimport type { RestCaller } from '../../minirest/src/restcaller';\n\ntype ConfigHolderOptions = {\n\tconfigGetMethod: ?string,\n\trestClient: RestCaller,\n\tevents: { [k: $Values<typeof ConfigHolderEvents>]: (e: CustomEvent) => void }\n}\n\ntype ChannelDescription = {\n\tid: string,\n\tpublic_id: ?string,\n\ttype: string,\n\tstart: string, // DATE_ATOM\n\tend: string, // DATE_ATOM\n}\n\ntype PublicChannelDescription = {\n\tuser_id: number,\n\tpublic_id: string,\n\tsignature: string,\n\tstart: string, // DATE_ATOM\n\tend: string, // DATE_ATOM\n}\n\nexport type PullConfig = {\n\tapi: {\n\t\trevision_mobile: number,\n\t\trevision_web: number,\n\t},\n\tchannels: {\n\t\tprivate: ?ChannelDescription,\n\t\tshared: ?ChannelDescription,\n\t},\n\tpublicChannels: { [user_id: number]: PublicChannelDescription },\n\tserver: {\n\t\tconfig_timestamp: number,\n\t\tlong_polling: string,\n\t\tlong_pooling_secure: string,\n\t\tmode: string,\n\t\tpublish: string,\n\t\tpublish_enabled: boolean,\n\t\tpublish_secure: string,\n\t\tserver_enabled: boolean,\n\t\ttimeShift: number,\n\t\tversion: number,\n\t\twebsocket: string,\n\t\twebsocket_enabled: boolean,\n\t\twebsocket_secure: string,\n\t},\n\tclientId: null,\n\tjwt: null,\n\texp: 0,\n}\n\nconst CONFIG_CHECK_INTERVAL = 60000;\n\nexport const ConfigHolderEvents = {\n\tConfigExpired: 'configExpired',\n\tRevisionChanged: 'revisionChanged',\n};\n\nexport class ConfigHolder extends EventTarget\n{\n\tconfigGetMethod = 'pull.config.get';\n\trestClient: RestCaller;\n\n\tconfig: ?PullConfig;\n\n\tcheckInterval: ?number;\n\n\tconstructor(options: ConfigHolderOptions = {})\n\t{\n\t\tsuper();\n\n\t\tif (options.configGetMethod)\n\t\t{\n\t\t\tthis.configGetMethod = options.configGetMethod;\n\t\t}\n\t\tthis.restClient = options.restClient;\n\n\t\tfor (const eventName of Object.keys(options.events || {}))\n\t\t{\n\t\t\tthis.addEventListener(eventName, options.events[eventName]);\n\t\t}\n\t}\n\n\tloadConfig(logTag): Promise<Config>\n\t{\n\t\tthis.stopCheckConfig();\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.restClient.callMethod(this.configGetMethod, { CACHE: 'N' }, undefined, undefined, logTag).then((response) => {\n\t\t\t\tconst data = response.data();\n\t\t\t\tconst timeShift = Math.floor((getTimestamp() - new Date(data.serverTime).getTime()) / 1000);\n\t\t\t\tdelete data.serverTime;\n\n\t\t\t\tthis.config = { ...data };\n\t\t\t\tthis.config.server.timeShift = timeShift;\n\t\t\t\tthis.startCheckConfig();\n\n\t\t\t\tresolve(this.config);\n\t\t\t}).catch((response) => {\n\t\t\t\tthis.config = undefined;\n\n\t\t\t\tconst error = response.error();\n\t\t\t\tif (error.getError().error === 'AUTHORIZE_ERROR' || error.getError().error === 'WRONG_AUTH_TYPE')\n\t\t\t\t{\n\t\t\t\t\terror.status = 403;\n\t\t\t\t}\n\t\t\t\treject(error);\n\t\t\t});\n\t\t});\n\t}\n\n\tstartCheckConfig()\n\t{\n\t\tif (this.checkInterval)\n\t\t{\n\t\t\tclearInterval(this.checkInterval);\n\t\t}\n\n\t\tthis.checkInterval = setInterval(() => this.checkConfig(), CONFIG_CHECK_INTERVAL);\n\t}\n\n\tstopCheckConfig()\n\t{\n\t\tif (this.checkInterval)\n\t\t{\n\t\t\tclearInterval(this.checkInterval);\n\t\t}\n\t\tthis.checkInterval = null;\n\t}\n\n\tcheckConfig()\n\t{\n\t\tif (!this.isConfigActual(this.config))\n\t\t{\n\t\t\tthis.dispatchEvent(new CustomEvent(ConfigHolderEvents.ConfigExpired));\n\t\t}\n\t\telse if (this.config.api.revision_web !== REVISION)\n\t\t{\n\t\t\tthis.dispatchEvent(new CustomEvent(ConfigHolderEvents.RevisionChanged, {\n\t\t\t\tdetail: { revision: this.config.api.revision_web },\n\t\t\t}));\n\t\t}\n\t}\n\n\tisConfigActual(config): boolean\n\t{\n\t\tif (!isPlainObject(config))\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\tif (config.server.config_timestamp < this.configTimestamp)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\tconst now = new Date();\n\n\t\tif (isNumber(config.exp) && config.exp > 0 && config.exp < now.getTime() / 1000)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\tconst channelTypes = Object.keys(config.channels || {});\n\t\tif (channelTypes.length === 0)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (const channelType of channelTypes)\n\t\t{\n\t\t\tconst channel = config.channels[channelType];\n\t\t\tconst channelEnd = new Date(channel.end);\n\n\t\t\tif (channelEnd < now)\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tdispose()\n\t{\n\t\tthis.stopCheckConfig();\n\t}\n}\n"],"names":["getTimestamp","Date","now","isNumber","item","Number","isFinite","isPlainObject","Boolean","constructor","Object","REVISION","CONFIG_CHECK_INTERVAL","ConfigHolderEvents","ConfigExpired","RevisionChanged","ConfigHolder","EventTarget","options","configGetMethod","restClient","eventName","keys","events","addEventListener","loadConfig","logTag","stopCheckConfig","Promise","resolve","reject","callMethod","CACHE","undefined","then","response","data","timeShift","Math","floor","serverTime","getTime","config","server","startCheckConfig","catch","error","getError","status","checkInterval","clearInterval","setInterval","checkConfig","isConfigActual","dispatchEvent","CustomEvent","api","revision_web","detail","revision","config_timestamp","configTimestamp","exp","channelTypes","channels","length","channelType","channel","channelEnd","end","dispose"],"mappings":"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"}