/******/ (() => { // webpackBootstrap /******/ "use strict"; /******/ var __webpack_modules__ = ({ /***/ "./node_modules/@firebase/util/dist/index.esm2017.js": /*!***********************************************************!*\ !*** ./node_modules/@firebase/util/dist/index.esm2017.js ***! \***********************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "CONSTANTS": () => (/* binding */ CONSTANTS), /* harmony export */ "DecodeBase64StringError": () => (/* binding */ DecodeBase64StringError), /* harmony export */ "Deferred": () => (/* binding */ Deferred), /* harmony export */ "ErrorFactory": () => (/* binding */ ErrorFactory), /* harmony export */ "FirebaseError": () => (/* binding */ FirebaseError), /* harmony export */ "MAX_VALUE_MILLIS": () => (/* binding */ MAX_VALUE_MILLIS), /* harmony export */ "RANDOM_FACTOR": () => (/* binding */ RANDOM_FACTOR), /* harmony export */ "Sha1": () => (/* binding */ Sha1), /* harmony export */ "areCookiesEnabled": () => (/* binding */ areCookiesEnabled), /* harmony export */ "assert": () => (/* binding */ assert), /* harmony export */ "assertionError": () => (/* binding */ assertionError), /* harmony export */ "async": () => (/* binding */ async), /* harmony export */ "base64": () => (/* binding */ base64), /* harmony export */ "base64Decode": () => (/* binding */ base64Decode), /* harmony export */ "base64Encode": () => (/* binding */ base64Encode), /* harmony export */ "base64urlEncodeWithoutPadding": () => (/* binding */ base64urlEncodeWithoutPadding), /* harmony export */ "calculateBackoffMillis": () => (/* binding */ calculateBackoffMillis), /* harmony export */ "contains": () => (/* binding */ contains), /* harmony export */ "createMockUserToken": () => (/* binding */ createMockUserToken), /* harmony export */ "createSubscribe": () => (/* binding */ createSubscribe), /* harmony export */ "decode": () => (/* binding */ decode), /* harmony export */ "deepCopy": () => (/* binding */ deepCopy), /* harmony export */ "deepEqual": () => (/* binding */ deepEqual), /* harmony export */ "deepExtend": () => (/* binding */ deepExtend), /* harmony export */ "errorPrefix": () => (/* binding */ errorPrefix), /* harmony export */ "extractQuerystring": () => (/* binding */ extractQuerystring), /* harmony export */ "getDefaultAppConfig": () => (/* binding */ getDefaultAppConfig), /* harmony export */ "getDefaultEmulatorHost": () => (/* binding */ getDefaultEmulatorHost), /* harmony export */ "getDefaultEmulatorHostnameAndPort": () => (/* binding */ getDefaultEmulatorHostnameAndPort), /* harmony export */ "getDefaults": () => (/* binding */ getDefaults), /* harmony export */ "getExperimentalSetting": () => (/* binding */ getExperimentalSetting), /* harmony export */ "getGlobal": () => (/* binding */ getGlobal), /* harmony export */ "getModularInstance": () => (/* binding */ getModularInstance), /* harmony export */ "getUA": () => (/* binding */ getUA), /* harmony export */ "isAdmin": () => (/* binding */ isAdmin), /* harmony export */ "isBrowser": () => (/* binding */ isBrowser), /* harmony export */ "isBrowserExtension": () => (/* binding */ isBrowserExtension), /* harmony export */ "isElectron": () => (/* binding */ isElectron), /* harmony export */ "isEmpty": () => (/* binding */ isEmpty), /* harmony export */ "isIE": () => (/* binding */ isIE), /* harmony export */ "isIndexedDBAvailable": () => (/* binding */ isIndexedDBAvailable), /* harmony export */ "isMobileCordova": () => (/* binding */ isMobileCordova), /* harmony export */ "isNode": () => (/* binding */ isNode), /* harmony export */ "isNodeSdk": () => (/* binding */ isNodeSdk), /* harmony export */ "isReactNative": () => (/* binding */ isReactNative), /* harmony export */ "isSafari": () => (/* binding */ isSafari), /* harmony export */ "isUWP": () => (/* binding */ isUWP), /* harmony export */ "isValidFormat": () => (/* binding */ isValidFormat), /* harmony export */ "isValidTimestamp": () => (/* binding */ isValidTimestamp), /* harmony export */ "issuedAtTime": () => (/* binding */ issuedAtTime), /* harmony export */ "jsonEval": () => (/* binding */ jsonEval), /* harmony export */ "map": () => (/* binding */ map), /* harmony export */ "ordinal": () => (/* binding */ ordinal), /* harmony export */ "promiseWithTimeout": () => (/* binding */ promiseWithTimeout), /* harmony export */ "querystring": () => (/* binding */ querystring), /* harmony export */ "querystringDecode": () => (/* binding */ querystringDecode), /* harmony export */ "safeGet": () => (/* binding */ safeGet), /* harmony export */ "stringLength": () => (/* binding */ stringLength), /* harmony export */ "stringToByteArray": () => (/* binding */ stringToByteArray), /* harmony export */ "stringify": () => (/* binding */ stringify), /* harmony export */ "uuidv4": () => (/* binding */ uuidv4), /* harmony export */ "validateArgCount": () => (/* binding */ validateArgCount), /* harmony export */ "validateCallback": () => (/* binding */ validateCallback), /* harmony export */ "validateContextObject": () => (/* binding */ validateContextObject), /* harmony export */ "validateIndexedDBOpenable": () => (/* binding */ validateIndexedDBOpenable), /* harmony export */ "validateNamespace": () => (/* binding */ validateNamespace) /* harmony export */ }); /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Firebase constants. Some of these (@defines) can be overridden at compile-time. */ const CONSTANTS = { /** * @define {boolean} Whether this is the client Node.js SDK. */ NODE_CLIENT: false, /** * @define {boolean} Whether this is the Admin Node.js SDK. */ NODE_ADMIN: false, /** * Firebase SDK Version */ SDK_VERSION: '${JSCORE_VERSION}' }; /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Throws an error if the provided assertion is falsy */ const assert = function (assertion, message) { if (!assertion) { throw assertionError(message); } }; /** * Returns an Error object suitable for throwing. */ const assertionError = function (message) { return new Error('Firebase Database (' + CONSTANTS.SDK_VERSION + ') INTERNAL ASSERT FAILED: ' + message); }; /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const stringToByteArray$1 = function (str) { // TODO(user): Use native implementations if/when available const out = []; let p = 0; for (let i = 0; i < str.length; i++) { let c = str.charCodeAt(i); if (c < 128) { out[p++] = c; } else if (c < 2048) { out[p++] = (c >> 6) | 192; out[p++] = (c & 63) | 128; } else if ((c & 0xfc00) === 0xd800 && i + 1 < str.length && (str.charCodeAt(i + 1) & 0xfc00) === 0xdc00) { // Surrogate Pair c = 0x10000 + ((c & 0x03ff) << 10) + (str.charCodeAt(++i) & 0x03ff); out[p++] = (c >> 18) | 240; out[p++] = ((c >> 12) & 63) | 128; out[p++] = ((c >> 6) & 63) | 128; out[p++] = (c & 63) | 128; } else { out[p++] = (c >> 12) | 224; out[p++] = ((c >> 6) & 63) | 128; out[p++] = (c & 63) | 128; } } return out; }; /** * Turns an array of numbers into the string given by the concatenation of the * characters to which the numbers correspond. * @param bytes Array of numbers representing characters. * @return Stringification of the array. */ const byteArrayToString = function (bytes) { // TODO(user): Use native implementations if/when available const out = []; let pos = 0, c = 0; while (pos < bytes.length) { const c1 = bytes[pos++]; if (c1 < 128) { out[c++] = String.fromCharCode(c1); } else if (c1 > 191 && c1 < 224) { const c2 = bytes[pos++]; out[c++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63)); } else if (c1 > 239 && c1 < 365) { // Surrogate Pair const c2 = bytes[pos++]; const c3 = bytes[pos++]; const c4 = bytes[pos++]; const u = (((c1 & 7) << 18) | ((c2 & 63) << 12) | ((c3 & 63) << 6) | (c4 & 63)) - 0x10000; out[c++] = String.fromCharCode(0xd800 + (u >> 10)); out[c++] = String.fromCharCode(0xdc00 + (u & 1023)); } else { const c2 = bytes[pos++]; const c3 = bytes[pos++]; out[c++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); } } return out.join(''); }; // We define it as an object literal instead of a class because a class compiled down to es5 can't // be treeshaked. https://github.com/rollup/rollup/issues/1691 // Static lookup maps, lazily populated by init_() const base64 = { /** * Maps bytes to characters. */ byteToCharMap_: null, /** * Maps characters to bytes. */ charToByteMap_: null, /** * Maps bytes to websafe characters. * @private */ byteToCharMapWebSafe_: null, /** * Maps websafe characters to bytes. * @private */ charToByteMapWebSafe_: null, /** * Our default alphabet, shared between * ENCODED_VALS and ENCODED_VALS_WEBSAFE */ ENCODED_VALS_BASE: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 'abcdefghijklmnopqrstuvwxyz' + '0123456789', /** * Our default alphabet. Value 64 (=) is special; it means "nothing." */ get ENCODED_VALS() { return this.ENCODED_VALS_BASE + '+/='; }, /** * Our websafe alphabet. */ get ENCODED_VALS_WEBSAFE() { return this.ENCODED_VALS_BASE + '-_.'; }, /** * Whether this browser supports the atob and btoa functions. This extension * started at Mozilla but is now implemented by many browsers. We use the * ASSUME_* variables to avoid pulling in the full useragent detection library * but still allowing the standard per-browser compilations. * */ HAS_NATIVE_SUPPORT: typeof atob === 'function', /** * Base64-encode an array of bytes. * * @param input An array of bytes (numbers with * value in [0, 255]) to encode. * @param webSafe Boolean indicating we should use the * alternative alphabet. * @return The base64 encoded string. */ encodeByteArray(input, webSafe) { if (!Array.isArray(input)) { throw Error('encodeByteArray takes an array as a parameter'); } this.init_(); const byteToCharMap = webSafe ? this.byteToCharMapWebSafe_ : this.byteToCharMap_; const output = []; for (let i = 0; i < input.length; i += 3) { const byte1 = input[i]; const haveByte2 = i + 1 < input.length; const byte2 = haveByte2 ? input[i + 1] : 0; const haveByte3 = i + 2 < input.length; const byte3 = haveByte3 ? input[i + 2] : 0; const outByte1 = byte1 >> 2; const outByte2 = ((byte1 & 0x03) << 4) | (byte2 >> 4); let outByte3 = ((byte2 & 0x0f) << 2) | (byte3 >> 6); let outByte4 = byte3 & 0x3f; if (!haveByte3) { outByte4 = 64; if (!haveByte2) { outByte3 = 64; } } output.push(byteToCharMap[outByte1], byteToCharMap[outByte2], byteToCharMap[outByte3], byteToCharMap[outByte4]); } return output.join(''); }, /** * Base64-encode a string. * * @param input A string to encode. * @param webSafe If true, we should use the * alternative alphabet. * @return The base64 encoded string. */ encodeString(input, webSafe) { // Shortcut for Mozilla browsers that implement // a native base64 encoder in the form of "btoa/atob" if (this.HAS_NATIVE_SUPPORT && !webSafe) { return btoa(input); } return this.encodeByteArray(stringToByteArray$1(input), webSafe); }, /** * Base64-decode a string. * * @param input to decode. * @param webSafe True if we should use the * alternative alphabet. * @return string representing the decoded value. */ decodeString(input, webSafe) { // Shortcut for Mozilla browsers that implement // a native base64 encoder in the form of "btoa/atob" if (this.HAS_NATIVE_SUPPORT && !webSafe) { return atob(input); } return byteArrayToString(this.decodeStringToByteArray(input, webSafe)); }, /** * Base64-decode a string. * * In base-64 decoding, groups of four characters are converted into three * bytes. If the encoder did not apply padding, the input length may not * be a multiple of 4. * * In this case, the last group will have fewer than 4 characters, and * padding will be inferred. If the group has one or two characters, it decodes * to one byte. If the group has three characters, it decodes to two bytes. * * @param input Input to decode. * @param webSafe True if we should use the web-safe alphabet. * @return bytes representing the decoded value. */ decodeStringToByteArray(input, webSafe) { this.init_(); const charToByteMap = webSafe ? this.charToByteMapWebSafe_ : this.charToByteMap_; const output = []; for (let i = 0; i < input.length;) { const byte1 = charToByteMap[input.charAt(i++)]; const haveByte2 = i < input.length; const byte2 = haveByte2 ? charToByteMap[input.charAt(i)] : 0; ++i; const haveByte3 = i < input.length; const byte3 = haveByte3 ? charToByteMap[input.charAt(i)] : 64; ++i; const haveByte4 = i < input.length; const byte4 = haveByte4 ? charToByteMap[input.charAt(i)] : 64; ++i; if (byte1 == null || byte2 == null || byte3 == null || byte4 == null) { throw new DecodeBase64StringError(); } const outByte1 = (byte1 << 2) | (byte2 >> 4); output.push(outByte1); if (byte3 !== 64) { const outByte2 = ((byte2 << 4) & 0xf0) | (byte3 >> 2); output.push(outByte2); if (byte4 !== 64) { const outByte3 = ((byte3 << 6) & 0xc0) | byte4; output.push(outByte3); } } } return output; }, /** * Lazy static initialization function. Called before * accessing any of the static map variables. * @private */ init_() { if (!this.byteToCharMap_) { this.byteToCharMap_ = {}; this.charToByteMap_ = {}; this.byteToCharMapWebSafe_ = {}; this.charToByteMapWebSafe_ = {}; // We want quick mappings back and forth, so we precompute two maps. for (let i = 0; i < this.ENCODED_VALS.length; i++) { this.byteToCharMap_[i] = this.ENCODED_VALS.charAt(i); this.charToByteMap_[this.byteToCharMap_[i]] = i; this.byteToCharMapWebSafe_[i] = this.ENCODED_VALS_WEBSAFE.charAt(i); this.charToByteMapWebSafe_[this.byteToCharMapWebSafe_[i]] = i; // Be forgiving when decoding and correctly decode both encodings. if (i >= this.ENCODED_VALS_BASE.length) { this.charToByteMap_[this.ENCODED_VALS_WEBSAFE.charAt(i)] = i; this.charToByteMapWebSafe_[this.ENCODED_VALS.charAt(i)] = i; } } } } }; /** * An error encountered while decoding base64 string. */ class DecodeBase64StringError extends Error { constructor() { super(...arguments); this.name = 'DecodeBase64StringError'; } } /** * URL-safe base64 encoding */ const base64Encode = function (str) { const utf8Bytes = stringToByteArray$1(str); return base64.encodeByteArray(utf8Bytes, true); }; /** * URL-safe base64 encoding (without "." padding in the end). * e.g. Used in JSON Web Token (JWT) parts. */ const base64urlEncodeWithoutPadding = function (str) { // Use base64url encoding and remove padding in the end (dot characters). return base64Encode(str).replace(/\./g, ''); }; /** * URL-safe base64 decoding * * NOTE: DO NOT use the global atob() function - it does NOT support the * base64Url variant encoding. * * @param str To be decoded * @return Decoded result, if possible */ const base64Decode = function (str) { try { return base64.decodeString(str, true); } catch (e) { console.error('base64Decode failed: ', e); } return null; }; /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Do a deep-copy of basic JavaScript Objects or Arrays. */ function deepCopy(value) { return deepExtend(undefined, value); } /** * Copy properties from source to target (recursively allows extension * of Objects and Arrays). Scalar values in the target are over-written. * If target is undefined, an object of the appropriate type will be created * (and returned). * * We recursively copy all child properties of plain Objects in the source- so * that namespace- like dictionaries are merged. * * Note that the target can be a function, in which case the properties in * the source Object are copied onto it as static properties of the Function. * * Note: we don't merge __proto__ to prevent prototype pollution */ function deepExtend(target, source) { if (!(source instanceof Object)) { return source; } switch (source.constructor) { case Date: // Treat Dates like scalars; if the target date object had any child // properties - they will be lost! const dateValue = source; return new Date(dateValue.getTime()); case Object: if (target === undefined) { target = {}; } break; case Array: // Always copy the array source and overwrite the target. target = []; break; default: // Not a plain Object - treat it as a scalar. return source; } for (const prop in source) { // use isValidKey to guard against prototype pollution. See https://snyk.io/vuln/SNYK-JS-LODASH-450202 if (!source.hasOwnProperty(prop) || !isValidKey(prop)) { continue; } target[prop] = deepExtend(target[prop], source[prop]); } return target; } function isValidKey(key) { return key !== '__proto__'; } /** * @license * Copyright 2022 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Polyfill for `globalThis` object. * @returns the `globalThis` object for the given environment. * @public */ function getGlobal() { if (typeof self !== 'undefined') { return self; } if (typeof window !== 'undefined') { return window; } if (typeof __webpack_require__.g !== 'undefined') { return __webpack_require__.g; } throw new Error('Unable to locate global object.'); } /** * @license * Copyright 2022 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const getDefaultsFromGlobal = () => getGlobal().__FIREBASE_DEFAULTS__; /** * Attempt to read defaults from a JSON string provided to * process(.)env(.)__FIREBASE_DEFAULTS__ or a JSON file whose path is in * process(.)env(.)__FIREBASE_DEFAULTS_PATH__ * The dots are in parens because certain compilers (Vite?) cannot * handle seeing that variable in comments. * See https://github.com/firebase/firebase-js-sdk/issues/6838 */ const getDefaultsFromEnvVariable = () => { if (typeof process === 'undefined' || typeof process.env === 'undefined') { return; } const defaultsJsonString = process.env.__FIREBASE_DEFAULTS__; if (defaultsJsonString) { return JSON.parse(defaultsJsonString); } }; const getDefaultsFromCookie = () => { if (typeof document === 'undefined') { return; } let match; try { match = document.cookie.match(/__FIREBASE_DEFAULTS__=([^;]+)/); } catch (e) { // Some environments such as Angular Universal SSR have a // `document` object but error on accessing `document.cookie`. return; } const decoded = match && base64Decode(match[1]); return decoded && JSON.parse(decoded); }; /** * Get the __FIREBASE_DEFAULTS__ object. It checks in order: * (1) if such an object exists as a property of `globalThis` * (2) if such an object was provided on a shell environment variable * (3) if such an object exists in a cookie * @public */ const getDefaults = () => { try { return (getDefaultsFromGlobal() || getDefaultsFromEnvVariable() || getDefaultsFromCookie()); } catch (e) { /** * Catch-all for being unable to get __FIREBASE_DEFAULTS__ due * to any environment case we have not accounted for. Log to * info instead of swallowing so we can find these unknown cases * and add paths for them if needed. */ console.info(`Unable to get __FIREBASE_DEFAULTS__ due to: ${e}`); return; } }; /** * Returns emulator host stored in the __FIREBASE_DEFAULTS__ object * for the given product. * @returns a URL host formatted like `127.0.0.1:9999` or `[::1]:4000` if available * @public */ const getDefaultEmulatorHost = (productName) => { var _a, _b; return (_b = (_a = getDefaults()) === null || _a === void 0 ? void 0 : _a.emulatorHosts) === null || _b === void 0 ? void 0 : _b[productName]; }; /** * Returns emulator hostname and port stored in the __FIREBASE_DEFAULTS__ object * for the given product. * @returns a pair of hostname and port like `["::1", 4000]` if available * @public */ const getDefaultEmulatorHostnameAndPort = (productName) => { const host = getDefaultEmulatorHost(productName); if (!host) { return undefined; } const separatorIndex = host.lastIndexOf(':'); // Finding the last since IPv6 addr also has colons. if (separatorIndex <= 0 || separatorIndex + 1 === host.length) { throw new Error(`Invalid host ${host} with no separate hostname and port!`); } // eslint-disable-next-line no-restricted-globals const port = parseInt(host.substring(separatorIndex + 1), 10); if (host[0] === '[') { // Bracket-quoted `[ipv6addr]:port` => return "ipv6addr" (without brackets). return [host.substring(1, separatorIndex - 1), port]; } else { return [host.substring(0, separatorIndex), port]; } }; /** * Returns Firebase app config stored in the __FIREBASE_DEFAULTS__ object. * @public */ const getDefaultAppConfig = () => { var _a; return (_a = getDefaults()) === null || _a === void 0 ? void 0 : _a.config; }; /** * Returns an experimental setting on the __FIREBASE_DEFAULTS__ object (properties * prefixed by "_") * @public */ const getExperimentalSetting = (name) => { var _a; return (_a = getDefaults()) === null || _a === void 0 ? void 0 : _a[`_${name}`]; }; /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class Deferred { constructor() { this.reject = () => { }; this.resolve = () => { }; this.promise = new Promise((resolve, reject) => { this.resolve = resolve; this.reject = reject; }); } /** * Our API internals are not promiseified and cannot because our callback APIs have subtle expectations around * invoking promises inline, which Promises are forbidden to do. This method accepts an optional node-style callback * and returns a node-style callback which will resolve or reject the Deferred's promise. */ wrapCallback(callback) { return (error, value) => { if (error) { this.reject(error); } else { this.resolve(value); } if (typeof callback === 'function') { // Attaching noop handler just in case developer wasn't expecting // promises this.promise.catch(() => { }); // Some of our callbacks don't expect a value and our own tests // assert that the parameter length is 1 if (callback.length === 1) { callback(error); } else { callback(error, value); } } }; } } /** * @license * Copyright 2021 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function createMockUserToken(token, projectId) { if (token.uid) { throw new Error('The "uid" field is no longer supported by mockUserToken. Please use "sub" instead for Firebase Auth User ID.'); } // Unsecured JWTs use "none" as the algorithm. const header = { alg: 'none', type: 'JWT' }; const project = projectId || 'demo-project'; const iat = token.iat || 0; const sub = token.sub || token.user_id; if (!sub) { throw new Error("mockUserToken must contain 'sub' or 'user_id' field!"); } const payload = Object.assign({ // Set all required fields to decent defaults iss: `https://securetoken.google.com/${project}`, aud: project, iat, exp: iat + 3600, auth_time: iat, sub, user_id: sub, firebase: { sign_in_provider: 'custom', identities: {} } }, token); // Unsecured JWTs use the empty string as a signature. const signature = ''; return [ base64urlEncodeWithoutPadding(JSON.stringify(header)), base64urlEncodeWithoutPadding(JSON.stringify(payload)), signature ].join('.'); } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Returns navigator.userAgent string or '' if it's not defined. * @return user agent string */ function getUA() { if (typeof navigator !== 'undefined' && typeof navigator['userAgent'] === 'string') { return navigator['userAgent']; } else { return ''; } } /** * Detect Cordova / PhoneGap / Ionic frameworks on a mobile device. * * Deliberately does not rely on checking `file://` URLs (as this fails PhoneGap * in the Ripple emulator) nor Cordova `onDeviceReady`, which would normally * wait for a callback. */ function isMobileCordova() { return (typeof window !== 'undefined' && // @ts-ignore Setting up an broadly applicable index signature for Window // just to deal with this case would probably be a bad idea. !!(window['cordova'] || window['phonegap'] || window['PhoneGap']) && /ios|iphone|ipod|ipad|android|blackberry|iemobile/i.test(getUA())); } /** * Detect Node.js. * * @return true if Node.js environment is detected or specified. */ // Node detection logic from: https://github.com/iliakan/detect-node/ function isNode() { var _a; const forceEnvironment = (_a = getDefaults()) === null || _a === void 0 ? void 0 : _a.forceEnvironment; if (forceEnvironment === 'node') { return true; } else if (forceEnvironment === 'browser') { return false; } try { return (Object.prototype.toString.call(__webpack_require__.g.process) === '[object process]'); } catch (e) { return false; } } /** * Detect Browser Environment */ function isBrowser() { return typeof self === 'object' && self.self === self; } function isBrowserExtension() { const runtime = typeof chrome === 'object' ? chrome.runtime : typeof browser === 'object' ? browser.runtime : undefined; return typeof runtime === 'object' && runtime.id !== undefined; } /** * Detect React Native. * * @return true if ReactNative environment is detected. */ function isReactNative() { return (typeof navigator === 'object' && navigator['product'] === 'ReactNative'); } /** Detects Electron apps. */ function isElectron() { return getUA().indexOf('Electron/') >= 0; } /** Detects Internet Explorer. */ function isIE() { const ua = getUA(); return ua.indexOf('MSIE ') >= 0 || ua.indexOf('Trident/') >= 0; } /** Detects Universal Windows Platform apps. */ function isUWP() { return getUA().indexOf('MSAppHost/') >= 0; } /** * Detect whether the current SDK build is the Node version. * * @return true if it's the Node SDK build. */ function isNodeSdk() { return CONSTANTS.NODE_CLIENT === true || CONSTANTS.NODE_ADMIN === true; } /** Returns true if we are running in Safari. */ function isSafari() { return (!isNode() && navigator.userAgent.includes('Safari') && !navigator.userAgent.includes('Chrome')); } /** * This method checks if indexedDB is supported by current browser/service worker context * @return true if indexedDB is supported by current browser/service worker context */ function isIndexedDBAvailable() { try { return typeof indexedDB === 'object'; } catch (e) { return false; } } /** * This method validates browser/sw context for indexedDB by opening a dummy indexedDB database and reject * if errors occur during the database open operation. * * @throws exception if current browser/sw context can't run idb.open (ex: Safari iframe, Firefox * private browsing) */ function validateIndexedDBOpenable() { return new Promise((resolve, reject) => { try { let preExist = true; const DB_CHECK_NAME = 'validate-browser-context-for-indexeddb-analytics-module'; const request = self.indexedDB.open(DB_CHECK_NAME); request.onsuccess = () => { request.result.close(); // delete database only when it doesn't pre-exist if (!preExist) { self.indexedDB.deleteDatabase(DB_CHECK_NAME); } resolve(true); }; request.onupgradeneeded = () => { preExist = false; }; request.onerror = () => { var _a; reject(((_a = request.error) === null || _a === void 0 ? void 0 : _a.message) || ''); }; } catch (error) { reject(error); } }); } /** * * This method checks whether cookie is enabled within current browser * @return true if cookie is enabled within current browser */ function areCookiesEnabled() { if (typeof navigator === 'undefined' || !navigator.cookieEnabled) { return false; } return true; } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Standardized Firebase Error. * * Usage: * * // Typescript string literals for type-safe codes * type Err = * 'unknown' | * 'object-not-found' * ; * * // Closure enum for type-safe error codes * // at-enum {string} * var Err = { * UNKNOWN: 'unknown', * OBJECT_NOT_FOUND: 'object-not-found', * } * * let errors: Map = { * 'generic-error': "Unknown error", * 'file-not-found': "Could not find file: {$file}", * }; * * // Type-safe function - must pass a valid error code as param. * let error = new ErrorFactory('service', 'Service', errors); * * ... * throw error.create(Err.GENERIC); * ... * throw error.create(Err.FILE_NOT_FOUND, {'file': fileName}); * ... * // Service: Could not file file: foo.txt (service/file-not-found). * * catch (e) { * assert(e.message === "Could not find file: foo.txt."); * if ((e as FirebaseError)?.code === 'service/file-not-found') { * console.log("Could not read file: " + e['file']); * } * } */ const ERROR_NAME = 'FirebaseError'; // Based on code from: // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Custom_Error_Types class FirebaseError extends Error { constructor( /** The error code for this error. */ code, message, /** Custom data for this error. */ customData) { super(message); this.code = code; this.customData = customData; /** The custom name for all FirebaseErrors. */ this.name = ERROR_NAME; // Fix For ES5 // https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work Object.setPrototypeOf(this, FirebaseError.prototype); // Maintains proper stack trace for where our error was thrown. // Only available on V8. if (Error.captureStackTrace) { Error.captureStackTrace(this, ErrorFactory.prototype.create); } } } class ErrorFactory { constructor(service, serviceName, errors) { this.service = service; this.serviceName = serviceName; this.errors = errors; } create(code, ...data) { const customData = data[0] || {}; const fullCode = `${this.service}/${code}`; const template = this.errors[code]; const message = template ? replaceTemplate(template, customData) : 'Error'; // Service Name: Error message (service/code). const fullMessage = `${this.serviceName}: ${message} (${fullCode}).`; const error = new FirebaseError(fullCode, fullMessage, customData); return error; } } function replaceTemplate(template, data) { return template.replace(PATTERN, (_, key) => { const value = data[key]; return value != null ? String(value) : `<${key}?>`; }); } const PATTERN = /\{\$([^}]+)}/g; /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Evaluates a JSON string into a javascript object. * * @param {string} str A string containing JSON. * @return {*} The javascript object representing the specified JSON. */ function jsonEval(str) { return JSON.parse(str); } /** * Returns JSON representing a javascript object. * @param {*} data Javascript object to be stringified. * @return {string} The JSON contents of the object. */ function stringify(data) { return JSON.stringify(data); } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Decodes a Firebase auth. token into constituent parts. * * Notes: * - May return with invalid / incomplete claims if there's no native base64 decoding support. * - Doesn't check if the token is actually valid. */ const decode = function (token) { let header = {}, claims = {}, data = {}, signature = ''; try { const parts = token.split('.'); header = jsonEval(base64Decode(parts[0]) || ''); claims = jsonEval(base64Decode(parts[1]) || ''); signature = parts[2]; data = claims['d'] || {}; delete claims['d']; } catch (e) { } return { header, claims, data, signature }; }; /** * Decodes a Firebase auth. token and checks the validity of its time-based claims. Will return true if the * token is within the time window authorized by the 'nbf' (not-before) and 'iat' (issued-at) claims. * * Notes: * - May return a false negative if there's no native base64 decoding support. * - Doesn't check if the token is actually valid. */ const isValidTimestamp = function (token) { const claims = decode(token).claims; const now = Math.floor(new Date().getTime() / 1000); let validSince = 0, validUntil = 0; if (typeof claims === 'object') { if (claims.hasOwnProperty('nbf')) { validSince = claims['nbf']; } else if (claims.hasOwnProperty('iat')) { validSince = claims['iat']; } if (claims.hasOwnProperty('exp')) { validUntil = claims['exp']; } else { // token will expire after 24h by default validUntil = validSince + 86400; } } return (!!now && !!validSince && !!validUntil && now >= validSince && now <= validUntil); }; /** * Decodes a Firebase auth. token and returns its issued at time if valid, null otherwise. * * Notes: * - May return null if there's no native base64 decoding support. * - Doesn't check if the token is actually valid. */ const issuedAtTime = function (token) { const claims = decode(token).claims; if (typeof claims === 'object' && claims.hasOwnProperty('iat')) { return claims['iat']; } return null; }; /** * Decodes a Firebase auth. token and checks the validity of its format. Expects a valid issued-at time. * * Notes: * - May return a false negative if there's no native base64 decoding support. * - Doesn't check if the token is actually valid. */ const isValidFormat = function (token) { const decoded = decode(token), claims = decoded.claims; return !!claims && typeof claims === 'object' && claims.hasOwnProperty('iat'); }; /** * Attempts to peer into an auth token and determine if it's an admin auth token by looking at the claims portion. * * Notes: * - May return a false negative if there's no native base64 decoding support. * - Doesn't check if the token is actually valid. */ const isAdmin = function (token) { const claims = decode(token).claims; return typeof claims === 'object' && claims['admin'] === true; }; /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function contains(obj, key) { return Object.prototype.hasOwnProperty.call(obj, key); } function safeGet(obj, key) { if (Object.prototype.hasOwnProperty.call(obj, key)) { return obj[key]; } else { return undefined; } } function isEmpty(obj) { for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { return false; } } return true; } function map(obj, fn, contextObj) { const res = {}; for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { res[key] = fn.call(contextObj, obj[key], key, obj); } } return res; } /** * Deep equal two objects. Support Arrays and Objects. */ function deepEqual(a, b) { if (a === b) { return true; } const aKeys = Object.keys(a); const bKeys = Object.keys(b); for (const k of aKeys) { if (!bKeys.includes(k)) { return false; } const aProp = a[k]; const bProp = b[k]; if (isObject(aProp) && isObject(bProp)) { if (!deepEqual(aProp, bProp)) { return false; } } else if (aProp !== bProp) { return false; } } for (const k of bKeys) { if (!aKeys.includes(k)) { return false; } } return true; } function isObject(thing) { return thing !== null && typeof thing === 'object'; } /** * @license * Copyright 2022 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Rejects if the given promise doesn't resolve in timeInMS milliseconds. * @internal */ function promiseWithTimeout(promise, timeInMS = 2000) { const deferredPromise = new Deferred(); setTimeout(() => deferredPromise.reject('timeout!'), timeInMS); promise.then(deferredPromise.resolve, deferredPromise.reject); return deferredPromise.promise; } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Returns a querystring-formatted string (e.g. &arg=val&arg2=val2) from a * params object (e.g. {arg: 'val', arg2: 'val2'}) * Note: You must prepend it with ? when adding it to a URL. */ function querystring(querystringParams) { const params = []; for (const [key, value] of Object.entries(querystringParams)) { if (Array.isArray(value)) { value.forEach(arrayVal => { params.push(encodeURIComponent(key) + '=' + encodeURIComponent(arrayVal)); }); } else { params.push(encodeURIComponent(key) + '=' + encodeURIComponent(value)); } } return params.length ? '&' + params.join('&') : ''; } /** * Decodes a querystring (e.g. ?arg=val&arg2=val2) into a params object * (e.g. {arg: 'val', arg2: 'val2'}) */ function querystringDecode(querystring) { const obj = {}; const tokens = querystring.replace(/^\?/, '').split('&'); tokens.forEach(token => { if (token) { const [key, value] = token.split('='); obj[decodeURIComponent(key)] = decodeURIComponent(value); } }); return obj; } /** * Extract the query string part of a URL, including the leading question mark (if present). */ function extractQuerystring(url) { const queryStart = url.indexOf('?'); if (!queryStart) { return ''; } const fragmentStart = url.indexOf('#', queryStart); return url.substring(queryStart, fragmentStart > 0 ? fragmentStart : undefined); } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview SHA-1 cryptographic hash. * Variable names follow the notation in FIPS PUB 180-3: * http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf. * * Usage: * var sha1 = new sha1(); * sha1.update(bytes); * var hash = sha1.digest(); * * Performance: * Chrome 23: ~400 Mbit/s * Firefox 16: ~250 Mbit/s * */ /** * SHA-1 cryptographic hash constructor. * * The properties declared here are discussed in the above algorithm document. * @constructor * @final * @struct */ class Sha1 { constructor() { /** * Holds the previous values of accumulated variables a-e in the compress_ * function. * @private */ this.chain_ = []; /** * A buffer holding the partially computed hash result. * @private */ this.buf_ = []; /** * An array of 80 bytes, each a part of the message to be hashed. Referred to * as the message schedule in the docs. * @private */ this.W_ = []; /** * Contains data needed to pad messages less than 64 bytes. * @private */ this.pad_ = []; /** * @private {number} */ this.inbuf_ = 0; /** * @private {number} */ this.total_ = 0; this.blockSize = 512 / 8; this.pad_[0] = 128; for (let i = 1; i < this.blockSize; ++i) { this.pad_[i] = 0; } this.reset(); } reset() { this.chain_[0] = 0x67452301; this.chain_[1] = 0xefcdab89; this.chain_[2] = 0x98badcfe; this.chain_[3] = 0x10325476; this.chain_[4] = 0xc3d2e1f0; this.inbuf_ = 0; this.total_ = 0; } /** * Internal compress helper function. * @param buf Block to compress. * @param offset Offset of the block in the buffer. * @private */ compress_(buf, offset) { if (!offset) { offset = 0; } const W = this.W_; // get 16 big endian words if (typeof buf === 'string') { for (let i = 0; i < 16; i++) { // TODO(user): [bug 8140122] Recent versions of Safari for Mac OS and iOS // have a bug that turns the post-increment ++ operator into pre-increment // during JIT compilation. We have code that depends heavily on SHA-1 for // correctness and which is affected by this bug, so I've removed all uses // of post-increment ++ in which the result value is used. We can revert // this change once the Safari bug // (https://bugs.webkit.org/show_bug.cgi?id=109036) has been fixed and // most clients have been updated. W[i] = (buf.charCodeAt(offset) << 24) | (buf.charCodeAt(offset + 1) << 16) | (buf.charCodeAt(offset + 2) << 8) | buf.charCodeAt(offset + 3); offset += 4; } } else { for (let i = 0; i < 16; i++) { W[i] = (buf[offset] << 24) | (buf[offset + 1] << 16) | (buf[offset + 2] << 8) | buf[offset + 3]; offset += 4; } } // expand to 80 words for (let i = 16; i < 80; i++) { const t = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]; W[i] = ((t << 1) | (t >>> 31)) & 0xffffffff; } let a = this.chain_[0]; let b = this.chain_[1]; let c = this.chain_[2]; let d = this.chain_[3]; let e = this.chain_[4]; let f, k; // TODO(user): Try to unroll this loop to speed up the computation. for (let i = 0; i < 80; i++) { if (i < 40) { if (i < 20) { f = d ^ (b & (c ^ d)); k = 0x5a827999; } else { f = b ^ c ^ d; k = 0x6ed9eba1; } } else { if (i < 60) { f = (b & c) | (d & (b | c)); k = 0x8f1bbcdc; } else { f = b ^ c ^ d; k = 0xca62c1d6; } } const t = (((a << 5) | (a >>> 27)) + f + e + k + W[i]) & 0xffffffff; e = d; d = c; c = ((b << 30) | (b >>> 2)) & 0xffffffff; b = a; a = t; } this.chain_[0] = (this.chain_[0] + a) & 0xffffffff; this.chain_[1] = (this.chain_[1] + b) & 0xffffffff; this.chain_[2] = (this.chain_[2] + c) & 0xffffffff; this.chain_[3] = (this.chain_[3] + d) & 0xffffffff; this.chain_[4] = (this.chain_[4] + e) & 0xffffffff; } update(bytes, length) { // TODO(johnlenz): tighten the function signature and remove this check if (bytes == null) { return; } if (length === undefined) { length = bytes.length; } const lengthMinusBlock = length - this.blockSize; let n = 0; // Using local instead of member variables gives ~5% speedup on Firefox 16. const buf = this.buf_; let inbuf = this.inbuf_; // The outer while loop should execute at most twice. while (n < length) { // When we have no data in the block to top up, we can directly process the // input buffer (assuming it contains sufficient data). This gives ~25% // speedup on Chrome 23 and ~15% speedup on Firefox 16, but requires that // the data is provided in large chunks (or in multiples of 64 bytes). if (inbuf === 0) { while (n <= lengthMinusBlock) { this.compress_(bytes, n); n += this.blockSize; } } if (typeof bytes === 'string') { while (n < length) { buf[inbuf] = bytes.charCodeAt(n); ++inbuf; ++n; if (inbuf === this.blockSize) { this.compress_(buf); inbuf = 0; // Jump to the outer loop so we use the full-block optimization. break; } } } else { while (n < length) { buf[inbuf] = bytes[n]; ++inbuf; ++n; if (inbuf === this.blockSize) { this.compress_(buf); inbuf = 0; // Jump to the outer loop so we use the full-block optimization. break; } } } } this.inbuf_ = inbuf; this.total_ += length; } /** @override */ digest() { const digest = []; let totalBits = this.total_ * 8; // Add pad 0x80 0x00*. if (this.inbuf_ < 56) { this.update(this.pad_, 56 - this.inbuf_); } else { this.update(this.pad_, this.blockSize - (this.inbuf_ - 56)); } // Add # bits. for (let i = this.blockSize - 1; i >= 56; i--) { this.buf_[i] = totalBits & 255; totalBits /= 256; // Don't use bit-shifting here! } this.compress_(this.buf_); let n = 0; for (let i = 0; i < 5; i++) { for (let j = 24; j >= 0; j -= 8) { digest[n] = (this.chain_[i] >> j) & 255; ++n; } } return digest; } } /** * Helper to make a Subscribe function (just like Promise helps make a * Thenable). * * @param executor Function which can make calls to a single Observer * as a proxy. * @param onNoObservers Callback when count of Observers goes to zero. */ function createSubscribe(executor, onNoObservers) { const proxy = new ObserverProxy(executor, onNoObservers); return proxy.subscribe.bind(proxy); } /** * Implement fan-out for any number of Observers attached via a subscribe * function. */ class ObserverProxy { /** * @param executor Function which can make calls to a single Observer * as a proxy. * @param onNoObservers Callback when count of Observers goes to zero. */ constructor(executor, onNoObservers) { this.observers = []; this.unsubscribes = []; this.observerCount = 0; // Micro-task scheduling by calling task.then(). this.task = Promise.resolve(); this.finalized = false; this.onNoObservers = onNoObservers; // Call the executor asynchronously so subscribers that are called // synchronously after the creation of the subscribe function // can still receive the very first value generated in the executor. this.task .then(() => { executor(this); }) .catch(e => { this.error(e); }); } next(value) { this.forEachObserver((observer) => { observer.next(value); }); } error(error) { this.forEachObserver((observer) => { observer.error(error); }); this.close(error); } complete() { this.forEachObserver((observer) => { observer.complete(); }); this.close(); } /** * Subscribe function that can be used to add an Observer to the fan-out list. * * - We require that no event is sent to a subscriber sychronously to their * call to subscribe(). */ subscribe(nextOrObserver, error, complete) { let observer; if (nextOrObserver === undefined && error === undefined && complete === undefined) { throw new Error('Missing Observer.'); } // Assemble an Observer object when passed as callback functions. if (implementsAnyMethods(nextOrObserver, [ 'next', 'error', 'complete' ])) { observer = nextOrObserver; } else { observer = { next: nextOrObserver, error, complete }; } if (observer.next === undefined) { observer.next = noop; } if (observer.error === undefined) { observer.error = noop; } if (observer.complete === undefined) { observer.complete = noop; } const unsub = this.unsubscribeOne.bind(this, this.observers.length); // Attempt to subscribe to a terminated Observable - we // just respond to the Observer with the final error or complete // event. if (this.finalized) { // eslint-disable-next-line @typescript-eslint/no-floating-promises this.task.then(() => { try { if (this.finalError) { observer.error(this.finalError); } else { observer.complete(); } } catch (e) { // nothing } return; }); } this.observers.push(observer); return unsub; } // Unsubscribe is synchronous - we guarantee that no events are sent to // any unsubscribed Observer. unsubscribeOne(i) { if (this.observers === undefined || this.observers[i] === undefined) { return; } delete this.observers[i]; this.observerCount -= 1; if (this.observerCount === 0 && this.onNoObservers !== undefined) { this.onNoObservers(this); } } forEachObserver(fn) { if (this.finalized) { // Already closed by previous event....just eat the additional values. return; } // Since sendOne calls asynchronously - there is no chance that // this.observers will become undefined. for (let i = 0; i < this.observers.length; i++) { this.sendOne(i, fn); } } // Call the Observer via one of it's callback function. We are careful to // confirm that the observe has not been unsubscribed since this asynchronous // function had been queued. sendOne(i, fn) { // Execute the callback asynchronously // eslint-disable-next-line @typescript-eslint/no-floating-promises this.task.then(() => { if (this.observers !== undefined && this.observers[i] !== undefined) { try { fn(this.observers[i]); } catch (e) { // Ignore exceptions raised in Observers or missing methods of an // Observer. // Log error to console. b/31404806 if (typeof console !== 'undefined' && console.error) { console.error(e); } } } }); } close(err) { if (this.finalized) { return; } this.finalized = true; if (err !== undefined) { this.finalError = err; } // Proxy is no longer needed - garbage collect references // eslint-disable-next-line @typescript-eslint/no-floating-promises this.task.then(() => { this.observers = undefined; this.onNoObservers = undefined; }); } } /** Turn synchronous function into one called asynchronously. */ // eslint-disable-next-line @typescript-eslint/ban-types function async(fn, onError) { return (...args) => { Promise.resolve(true) .then(() => { fn(...args); }) .catch((error) => { if (onError) { onError(error); } }); }; } /** * Return true if the object passed in implements any of the named methods. */ function implementsAnyMethods(obj, methods) { if (typeof obj !== 'object' || obj === null) { return false; } for (const method of methods) { if (method in obj && typeof obj[method] === 'function') { return true; } } return false; } function noop() { // do nothing } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Check to make sure the appropriate number of arguments are provided for a public function. * Throws an error if it fails. * * @param fnName The function name * @param minCount The minimum number of arguments to allow for the function call * @param maxCount The maximum number of argument to allow for the function call * @param argCount The actual number of arguments provided. */ const validateArgCount = function (fnName, minCount, maxCount, argCount) { let argError; if (argCount < minCount) { argError = 'at least ' + minCount; } else if (argCount > maxCount) { argError = maxCount === 0 ? 'none' : 'no more than ' + maxCount; } if (argError) { const error = fnName + ' failed: Was called with ' + argCount + (argCount === 1 ? ' argument.' : ' arguments.') + ' Expects ' + argError + '.'; throw new Error(error); } }; /** * Generates a string to prefix an error message about failed argument validation * * @param fnName The function name * @param argName The name of the argument * @return The prefix to add to the error thrown for validation. */ function errorPrefix(fnName, argName) { return `${fnName} failed: ${argName} argument `; } /** * @param fnName * @param argumentNumber * @param namespace * @param optional */ function validateNamespace(fnName, namespace, optional) { if (optional && !namespace) { return; } if (typeof namespace !== 'string') { //TODO: I should do more validation here. We only allow certain chars in namespaces. throw new Error(errorPrefix(fnName, 'namespace') + 'must be a valid firebase namespace.'); } } function validateCallback(fnName, argumentName, // eslint-disable-next-line @typescript-eslint/ban-types callback, optional) { if (optional && !callback) { return; } if (typeof callback !== 'function') { throw new Error(errorPrefix(fnName, argumentName) + 'must be a valid function.'); } } function validateContextObject(fnName, argumentName, context, optional) { if (optional && !context) { return; } if (typeof context !== 'object' || context === null) { throw new Error(errorPrefix(fnName, argumentName) + 'must be a valid context object.'); } } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Code originally came from goog.crypt.stringToUtf8ByteArray, but for some reason they // automatically replaced '\r\n' with '\n', and they didn't handle surrogate pairs, // so it's been modified. // Note that not all Unicode characters appear as single characters in JavaScript strings. // fromCharCode returns the UTF-16 encoding of a character - so some Unicode characters // use 2 characters in Javascript. All 4-byte UTF-8 characters begin with a first // character in the range 0xD800 - 0xDBFF (the first character of a so-called surrogate // pair). // See http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.3 /** * @param {string} str * @return {Array} */ const stringToByteArray = function (str) { const out = []; let p = 0; for (let i = 0; i < str.length; i++) { let c = str.charCodeAt(i); // Is this the lead surrogate in a surrogate pair? if (c >= 0xd800 && c <= 0xdbff) { const high = c - 0xd800; // the high 10 bits. i++; assert(i < str.length, 'Surrogate pair missing trail surrogate.'); const low = str.charCodeAt(i) - 0xdc00; // the low 10 bits. c = 0x10000 + (high << 10) + low; } if (c < 128) { out[p++] = c; } else if (c < 2048) { out[p++] = (c >> 6) | 192; out[p++] = (c & 63) | 128; } else if (c < 65536) { out[p++] = (c >> 12) | 224; out[p++] = ((c >> 6) & 63) | 128; out[p++] = (c & 63) | 128; } else { out[p++] = (c >> 18) | 240; out[p++] = ((c >> 12) & 63) | 128; out[p++] = ((c >> 6) & 63) | 128; out[p++] = (c & 63) | 128; } } return out; }; /** * Calculate length without actually converting; useful for doing cheaper validation. * @param {string} str * @return {number} */ const stringLength = function (str) { let p = 0; for (let i = 0; i < str.length; i++) { const c = str.charCodeAt(i); if (c < 128) { p++; } else if (c < 2048) { p += 2; } else if (c >= 0xd800 && c <= 0xdbff) { // Lead surrogate of a surrogate pair. The pair together will take 4 bytes to represent. p += 4; i++; // skip trail surrogate. } else { p += 3; } } return p; }; /** * @license * Copyright 2022 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Copied from https://stackoverflow.com/a/2117523 * Generates a new uuid. * @public */ const uuidv4 = function () { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { const r = (Math.random() * 16) | 0, v = c === 'x' ? r : (r & 0x3) | 0x8; return v.toString(16); }); }; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * The amount of milliseconds to exponentially increase. */ const DEFAULT_INTERVAL_MILLIS = 1000; /** * The factor to backoff by. * Should be a number greater than 1. */ const DEFAULT_BACKOFF_FACTOR = 2; /** * The maximum milliseconds to increase to. * *

Visible for testing */ const MAX_VALUE_MILLIS = 4 * 60 * 60 * 1000; // Four hours, like iOS and Android. /** * The percentage of backoff time to randomize by. * See * http://go/safe-client-behavior#step-1-determine-the-appropriate-retry-interval-to-handle-spike-traffic * for context. * *

Visible for testing */ const RANDOM_FACTOR = 0.5; /** * Based on the backoff method from * https://github.com/google/closure-library/blob/master/closure/goog/math/exponentialbackoff.js. * Extracted here so we don't need to pass metadata and a stateful ExponentialBackoff object around. */ function calculateBackoffMillis(backoffCount, intervalMillis = DEFAULT_INTERVAL_MILLIS, backoffFactor = DEFAULT_BACKOFF_FACTOR) { // Calculates an exponentially increasing value. // Deviation: calculates value from count and a constant interval, so we only need to save value // and count to restore state. const currBaseValue = intervalMillis * Math.pow(backoffFactor, backoffCount); // A random "fuzz" to avoid waves of retries. // Deviation: randomFactor is required. const randomWait = Math.round( // A fraction of the backoff value to add/subtract. // Deviation: changes multiplication order to improve readability. RANDOM_FACTOR * currBaseValue * // A random float (rounded to int by Math.round above) in the range [-1, 1]. Determines // if we add or subtract. (Math.random() - 0.5) * 2); // Limits backoff to max to avoid effectively permanent backoff. return Math.min(MAX_VALUE_MILLIS, currBaseValue + randomWait); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Provide English ordinal letters after a number */ function ordinal(i) { if (!Number.isFinite(i)) { return `${i}`; } return i + indicator(i); } function indicator(i) { i = Math.abs(i); const cent = i % 100; if (cent >= 10 && cent <= 20) { return 'th'; } const dec = i % 10; if (dec === 1) { return 'st'; } if (dec === 2) { return 'nd'; } if (dec === 3) { return 'rd'; } return 'th'; } /** * @license * Copyright 2021 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function getModularInstance(service) { if (service && service._delegate) { return service._delegate; } else { return service; } } //# sourceMappingURL=index.esm2017.js.map /***/ }), /***/ "./src/config.js": /*!***********************!*\ !*** ./src/config.js ***! \***********************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "API_KEY": () => (/* binding */ API_KEY), /* harmony export */ "APP_NAME": () => (/* binding */ APP_NAME), /* harmony export */ "AVATAR_SIZE": () => (/* binding */ AVATAR_SIZE), /* harmony export */ "BROKEN_IMAGE_SIZE": () => (/* binding */ BROKEN_IMAGE_SIZE), /* harmony export */ "CHANNEL_ACCESS_MODE": () => (/* binding */ CHANNEL_ACCESS_MODE), /* harmony export */ "DEFAULT_HOST": () => (/* binding */ DEFAULT_HOST), /* harmony export */ "DEFAULT_P2P_ACCESS_MODE": () => (/* binding */ DEFAULT_P2P_ACCESS_MODE), /* harmony export */ "EDIT_PREVIEW_LENGTH": () => (/* binding */ EDIT_PREVIEW_LENGTH), /* harmony export */ "FORWARDED_PREVIEW_LENGTH": () => (/* binding */ FORWARDED_PREVIEW_LENGTH), /* harmony export */ "IMAGE_PREVIEW_DIM": () => (/* binding */ IMAGE_PREVIEW_DIM), /* harmony export */ "IMAGE_THUMBNAIL_DIM": () => (/* binding */ IMAGE_THUMBNAIL_DIM), /* harmony export */ "IMMEDIATE_P2P_SUBSCRIPTION": () => (/* binding */ IMMEDIATE_P2P_SUBSCRIPTION), /* harmony export */ "KEYPRESS_DELAY": () => (/* binding */ KEYPRESS_DELAY), /* harmony export */ "KNOWN_HOSTS": () => (/* binding */ KNOWN_HOSTS), /* harmony export */ "LINK_CONTACT_US": () => (/* binding */ LINK_CONTACT_US), /* harmony export */ "LINK_PRIVACY_POLICY": () => (/* binding */ LINK_PRIVACY_POLICY), /* harmony export */ "LINK_TERMS_OF_SERVICE": () => (/* binding */ LINK_TERMS_OF_SERVICE), /* harmony export */ "LOGGING_ENABLED": () => (/* binding */ LOGGING_ENABLED), /* harmony export */ "MAX_AVATAR_BYTES": () => (/* binding */ MAX_AVATAR_BYTES), /* harmony export */ "MAX_DURATION": () => (/* binding */ MAX_DURATION), /* harmony export */ "MAX_EXTERN_ATTACHMENT_SIZE": () => (/* binding */ MAX_EXTERN_ATTACHMENT_SIZE), /* harmony export */ "MAX_IMAGE_DIM": () => (/* binding */ MAX_IMAGE_DIM), /* harmony export */ "MAX_INBAND_ATTACHMENT_SIZE": () => (/* binding */ MAX_INBAND_ATTACHMENT_SIZE), /* harmony export */ "MAX_ONLINE_IN_TOPIC": () => (/* binding */ MAX_ONLINE_IN_TOPIC), /* harmony export */ "MAX_PEER_TITLE_LENGTH": () => (/* binding */ MAX_PEER_TITLE_LENGTH), /* harmony export */ "MAX_TAG_COUNT": () => (/* binding */ MAX_TAG_COUNT), /* harmony export */ "MAX_TAG_LENGTH": () => (/* binding */ MAX_TAG_LENGTH), /* harmony export */ "MAX_TITLE_LENGTH": () => (/* binding */ MAX_TITLE_LENGTH), /* harmony export */ "MAX_TOPIC_DESCRIPTION_LENGTH": () => (/* binding */ MAX_TOPIC_DESCRIPTION_LENGTH), /* harmony export */ "MEDIA_BREAKPOINT": () => (/* binding */ MEDIA_BREAKPOINT), /* harmony export */ "MESSAGES_PAGE": () => (/* binding */ MESSAGES_PAGE), /* harmony export */ "MESSAGE_PREVIEW_LENGTH": () => (/* binding */ MESSAGE_PREVIEW_LENGTH), /* harmony export */ "MIN_DURATION": () => (/* binding */ MIN_DURATION), /* harmony export */ "MIN_TAG_LENGTH": () => (/* binding */ MIN_TAG_LENGTH), /* harmony export */ "NEW_GRP_ACCESS_MODE": () => (/* binding */ NEW_GRP_ACCESS_MODE), /* harmony export */ "NO_ACCESS_MODE": () => (/* binding */ NO_ACCESS_MODE), /* harmony export */ "NO_DIMENSIONS_VIDEO": () => (/* binding */ NO_DIMENSIONS_VIDEO), /* harmony export */ "QUOTED_REPLY_LENGTH": () => (/* binding */ QUOTED_REPLY_LENGTH), /* harmony export */ "READ_DELAY": () => (/* binding */ READ_DELAY), /* harmony export */ "REM_SIZE": () => (/* binding */ REM_SIZE), /* harmony export */ "VIDEO_PREVIEW_DIM": () => (/* binding */ VIDEO_PREVIEW_DIM), /* harmony export */ "VIDEO_THUMBNAIL_WIDTH": () => (/* binding */ VIDEO_THUMBNAIL_WIDTH) /* harmony export */ }); /* harmony import */ var _version_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./version.js */ "./src/version.js"); const APP_NAME = 'TinodeWeb/' + (_version_js__WEBPACK_IMPORTED_MODULE_0__.PACKAGE_VERSION || '0.21'); const API_KEY = 'AQEAAAABAAD_rAp4DJh05a1HAwFT3A6K'; const KNOWN_HOSTS = { hosted: 'web.tinode.co', local: 'localhost:6060' }; const DEFAULT_HOST = KNOWN_HOSTS.hosted; const LOGGING_ENABLED = true; const KEYPRESS_DELAY = 3_000; const READ_DELAY = 1_500; const MIN_TAG_LENGTH = 2; const MAX_TAG_LENGTH = 96; const MAX_TAG_COUNT = 16; const DEFAULT_P2P_ACCESS_MODE = 'JRWPS'; const NEW_GRP_ACCESS_MODE = 'JRWPSAO'; const CHANNEL_ACCESS_MODE = 'JR'; const NO_ACCESS_MODE = 'N'; const MEDIA_BREAKPOINT = 640; const REM_SIZE = 13; const AVATAR_SIZE = 384; const MAX_AVATAR_BYTES = 4096; const BROKEN_IMAGE_SIZE = 32; const NO_DIMENSIONS_VIDEO = 128; const MESSAGES_PAGE = 24; const MAX_INBAND_ATTACHMENT_SIZE = 262_144; const MAX_EXTERN_ATTACHMENT_SIZE = 1 << 23; const MAX_IMAGE_DIM = 1024; const IMAGE_PREVIEW_DIM = 64; const VIDEO_PREVIEW_DIM = 96; const IMAGE_THUMBNAIL_DIM = 36; const VIDEO_THUMBNAIL_WIDTH = 48; const MAX_ONLINE_IN_TOPIC = 4; const MAX_TITLE_LENGTH = 60; const MAX_TOPIC_DESCRIPTION_LENGTH = 360; const MAX_PEER_TITLE_LENGTH = 20; const MESSAGE_PREVIEW_LENGTH = 80; const QUOTED_REPLY_LENGTH = 30; const FORWARDED_PREVIEW_LENGTH = 84; const EDIT_PREVIEW_LENGTH = 48; const MIN_DURATION = 2_000; const MAX_DURATION = 600_000; const LINK_CONTACT_US = 'mailto:support@tinode.co'; const LINK_PRIVACY_POLICY = 'https://tinode.co/privacy.html'; const LINK_TERMS_OF_SERVICE = 'https://tinode.co/terms.html'; const IMMEDIATE_P2P_SUBSCRIPTION = false; /***/ }), /***/ "./src/constants.js": /*!**************************!*\ !*** ./src/constants.js ***! \**************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "CALL_HEAD_STARTED": () => (/* binding */ CALL_HEAD_STARTED), /* harmony export */ "CALL_STATE_INCOMING_RECEIVED": () => (/* binding */ CALL_STATE_INCOMING_RECEIVED), /* harmony export */ "CALL_STATE_IN_PROGRESS": () => (/* binding */ CALL_STATE_IN_PROGRESS), /* harmony export */ "CALL_STATE_NONE": () => (/* binding */ CALL_STATE_NONE), /* harmony export */ "CALL_STATE_OUTGOING_INITATED": () => (/* binding */ CALL_STATE_OUTGOING_INITATED), /* harmony export */ "VC_CAROUSEL_ITEM_GAP": () => (/* binding */ VC_CAROUSEL_ITEM_GAP) /* harmony export */ }); const CALL_STATE_NONE = 0; const CALL_STATE_OUTGOING_INITATED = 1; const CALL_STATE_INCOMING_RECEIVED = 2; const CALL_STATE_IN_PROGRESS = 3; const CALL_HEAD_STARTED = 'started'; const VC_CAROUSEL_ITEM_GAP = 16; /***/ }), /***/ "./src/lib/blob-helpers.js": /*!*********************************!*\ !*** ./src/lib/blob-helpers.js ***! \*********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "MIME_EXTENSIONS": () => (/* binding */ MIME_EXTENSIONS), /* harmony export */ "SUPPORTED_IMAGE_FORMATS": () => (/* binding */ SUPPORTED_IMAGE_FORMATS), /* harmony export */ "base64DecodedLen": () => (/* binding */ base64DecodedLen), /* harmony export */ "base64EncodedLen": () => (/* binding */ base64EncodedLen), /* harmony export */ "base64ReEncode": () => (/* binding */ base64ReEncode), /* harmony export */ "base64ToBlob": () => (/* binding */ base64ToBlob), /* harmony export */ "base64ToIntArray": () => (/* binding */ base64ToIntArray), /* harmony export */ "blobToBase64": () => (/* binding */ blobToBase64), /* harmony export */ "fileNameForMime": () => (/* binding */ fileNameForMime), /* harmony export */ "filePasted": () => (/* binding */ filePasted), /* harmony export */ "fileToBase64": () => (/* binding */ fileToBase64), /* harmony export */ "fitImageSize": () => (/* binding */ fitImageSize), /* harmony export */ "getMimeType": () => (/* binding */ getMimeType), /* harmony export */ "imageCrop": () => (/* binding */ imageCrop), /* harmony export */ "imageScaled": () => (/* binding */ imageScaled), /* harmony export */ "intArrayToBase64": () => (/* binding */ intArrayToBase64), /* harmony export */ "makeImageUrl": () => (/* binding */ makeImageUrl) /* harmony export */ }); const SUPPORTED_IMAGE_FORMATS = ['image/jpeg', 'image/gif', 'image/png', 'image/svg', 'image/svg+xml']; const MIME_EXTENSIONS = ['jpg', 'gif', 'png', 'svg', 'svg']; function makeImageUrl(photo) { if (photo && typeof photo == 'object') { if (photo.ref) { return photo.ref; } if (photo.data && photo.type) { const mime = photo.type.startsWith('image/') ? photo.type : 'image/' + photo.type; return 'data:' + mime + ';base64,' + photo.data; } } return null; } function fitImageSize(width, height, maxWidth, maxHeight, forceSquare) { width = width | 0; height = height | 0; maxWidth = maxWidth | 0; maxHeight = maxHeight | 0; if (width <= 0 || height <= 0 || maxWidth <= 0 || maxHeight <= 0) { return null; } if (forceSquare) { maxWidth = maxHeight = Math.min(maxWidth, maxHeight); } const scale = Math.min(Math.min(width, maxWidth) / width, Math.min(height, maxHeight) / height); const size = { dstWidth: width * scale | 0, dstHeight: height * scale | 0 }; if (forceSquare) { size.dstWidth = size.dstHeight = Math.min(size.dstWidth, size.dstHeight); size.srcWidth = size.srcHeight = Math.min(width, height); size.xoffset = (width - size.srcWidth) / 2 | 0; size.yoffset = (height - size.srcWidth) / 2 | 0; } else { size.xoffset = size.yoffset = 0; size.srcWidth = width; size.srcHeight = height; } return size; } function fileNameForMime(fname, mime) { const idx = SUPPORTED_IMAGE_FORMATS.indexOf(mime); if (idx < 0 || !fname) { return fname; } const ext = MIME_EXTENSIONS[idx]; const at = fname.lastIndexOf('.'); if (at >= 0) { fname = fname.substring(0, at); } return fname + '.' + ext; } function imageScaled(fileOrBlob, maxWidth, maxHeight, maxSize, forceSquare) { return new Promise((resolve, reject) => { const img = new Image(); img.crossOrigin = 'Anonymous'; img.onerror = function (err) { reject(new Error("Image format unrecognized")); }; img.onload = async function () { URL.revokeObjectURL(img.src); const dim = fitImageSize(img.width, img.height, maxWidth, maxHeight, forceSquare); if (!dim) { reject(new Error("Invalid image")); return; } let canvas = document.createElement('canvas'); canvas.width = dim.dstWidth; canvas.height = dim.dstHeight; let ctx = canvas.getContext('2d'); ctx.imageSmoothingEnabled = true; ctx.drawImage(img, dim.xoffset, dim.yoffset, dim.srcWidth, dim.srcHeight, 0, 0, dim.dstWidth, dim.dstHeight); const mime = SUPPORTED_IMAGE_FORMATS.includes(fileOrBlob.type) ? fileOrBlob.type : 'image/jpeg'; let blob = await new Promise(resolve => canvas.toBlob(resolve, mime)); if (!blob) { reject(new Error("Unsupported image format")); return; } while (maxSize > 0 && blob.length > maxSize) { dim.dstWidth = dim.dstWidth * 0.70710678118 | 0; dim.dstHeight = dim.dstHeight * 0.70710678118 | 0; canvas.width = dim.dstWidth; canvas.height = dim.dstHeight; ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(img, dim.xoffset, dim.yoffset, dim.srcWidth, dim.srcHeight, 0, 0, dim.dstWidth, dim.dstHeight); blob = await new Promise(resolve => canvas.toBlob(resolve, mime)); } canvas = null; resolve({ mime: mime, blob: blob, width: dim.dstWidth, height: dim.dstHeight, name: fileNameForMime(fileOrBlob.name, mime) }); }; img.src = URL.createObjectURL(fileOrBlob); }); } function imageCrop(mime, objURL, left, top, width, height, scale) { return new Promise((resolve, reject) => { const img = new Image(); img.crossOrigin = 'Anonymous'; img.onerror = _ => { reject(new Error("Image format unrecognized")); }; img.onload = _ => { URL.revokeObjectURL(img.src); let canvas = document.createElement('canvas'); canvas.width = width * scale; canvas.height = height * scale; let ctx = canvas.getContext('2d'); ctx.imageSmoothingEnabled = true; ctx.drawImage(img, left, top, width, height, 0, 0, canvas.width, canvas.height); mime = SUPPORTED_IMAGE_FORMATS.includes(mime) ? mime : 'image/jpeg'; canvas.toBlob(blob => { canvas = null; if (blob) { resolve({ mime: mime, blob: blob, width: width, height: height }); } else { reject(new Error("Unsupported image format")); } }, mime); }; img.src = objURL; }); } function fileToBase64(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onerror = _ => { reject(reader.error); }; reader.onload = _ => { resolve({ mime: file.type, bits: reader.result.split(',')[1], name: file.name }); }; reader.readAsDataURL(file); }); } function blobToBase64(blob) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onerror = _ => { reject(reader.error); }; reader.onload = _ => { resolve({ mime: blob.type, bits: reader.result.split(',')[1] }); }; reader.readAsDataURL(blob); }); } function filePasted(event, onImageSuccess, onAttachmentSuccess, onError) { const items = (event.clipboardData || event.originalEvent.clipboardData || {}).items; if (!items || !items.length) { return false; } for (let i in items) { const item = items[i]; if (item.kind === 'file') { const file = item.getAsFile(); if (!file) { console.error("Failed to get file object from pasted file item", item.kind, item.type); onError("Failed to get file object from pasted file item"); continue; } if (file.type && file.type.split('/')[0] == 'image') { onImageSuccess(file); } else { onAttachmentSuccess(file); } return true; } } return false; } function getMimeType(header) { const mime = /^data:(image\/[-+a-z0-9.]+);base64/.exec(header); return mime && mime.length > 1 ? mime[1] : null; } function base64EncodedLen(n) { return Math.floor((n + 2) / 3) * 4; } function base64DecodedLen(n) { return Math.floor(n / 4) * 3; } function base64ReEncode(str) { if (str) { str = str.replace(/-/g, '+').replace(/_/g, '/'); try { str = btoa(atob(str)); } catch (err) { console.error("Failed to base64 re-encode string.", err); str = null; } } return str; } function base64ToBlob(str, mime) { if (!str) { return null; } try { const bin = atob(str); const length = bin.length; const buf = new ArrayBuffer(length); const arr = new Uint8Array(buf); for (let i = 0; i < length; i++) { arr[i] = bin.charCodeAt(i); } return new Blob([buf], { type: mime }); } catch (err) { console.error("Failed to convert base64 to blob: ", err); } return null; } function intArrayToBase64(arr) { if (!Array.isArray(arr)) { return null; } try { let bin = ''; new Uint8Array(arr).forEach(b => bin += String.fromCharCode(b)); return window.btoa(bin); } catch (err) {} return null; } function base64ToIntArray(b64) { const arr = []; try { const bin = window.atob(b64); [...bin].forEach(c => { arr.push(c.charCodeAt(0)); }); return arr; } catch (err) {} return null; } /***/ }), /***/ "./src/lib/formatters.js": /*!*******************************!*\ !*** ./src/lib/formatters.js ***! \*******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "fullFormatter": () => (/* binding */ fullFormatter), /* harmony export */ "previewFormatter": () => (/* binding */ previewFormatter), /* harmony export */ "replyFormatter": () => (/* binding */ replyFormatter) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _widgets_audio_player_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/audio-player.jsx */ "./src/widgets/audio-player.jsx"); /* harmony import */ var _widgets_call_message_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../widgets/call-message.jsx */ "./src/widgets/call-message.jsx"); /* harmony import */ var _widgets_call_status_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../widgets/call-status.jsx */ "./src/widgets/call-status.jsx"); /* harmony import */ var _widgets_inline_video_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../widgets/inline-video.jsx */ "./src/widgets/inline-video.jsx"); /* harmony import */ var _widgets_lazy_image_jsx__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../widgets/lazy-image.jsx */ "./src/widgets/lazy-image.jsx"); /* harmony import */ var _widgets_uploading_image_jsx__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../widgets/uploading-image.jsx */ "./src/widgets/uploading-image.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _blob_helpers_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _strformat_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./strformat.js */ "./src/lib/strformat.js"); /* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./utils.js */ "./src/lib/utils.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ drafty_form: { id: "drafty_form", defaultMessage: [{ "type": 0, "value": "Form:" }] }, drafty_attachment: { id: "drafty_attachment", defaultMessage: [{ "type": 0, "value": "Attachment" }] }, drafty_image: { id: "drafty_image", defaultMessage: [{ "type": 0, "value": "Picture" }] }, drafty_video: { id: "drafty_video", defaultMessage: [{ "type": 0, "value": "Video recording" }] }, drafty_unknown: { id: "drafty_unknown", defaultMessage: [{ "type": 0, "value": "Unsupported" }] } }); function fullFormatter(style, data, values, key, stack) { if (stack.includes('QQ')) { return quoteFormatter.call(this, style, data, values, key); } if (!style) { return values; } let el = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.tagName(style); let attr = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attrValue(style, data) || {}; attr.key = key; switch (style) { case 'AU': if (attr.src) { attr.src = this.authorizeURL((0,_utils_js__WEBPACK_IMPORTED_MODULE_12__.sanitizeUrlForMime)(attr.src, 'audio')); attr.duration = data.duration > 0 ? data.duration | 0 : undefined; attr.preview = data.preview; attr.loading = 'lazy'; } el = _widgets_audio_player_jsx__WEBPACK_IMPORTED_MODULE_3__["default"]; values = null; break; case 'BR': values = null; break; case 'EX': break; case 'HL': attr.className = 'highlight'; break; case 'HD': el = null; values = null; break; case 'IM': el = handleImageData.call(this, el, data, attr); values = null; break; case 'BN': attr.onClick = this.onFormButtonClick; let inner = react__WEBPACK_IMPORTED_MODULE_0___default().Children.map(values, child => { return typeof child == 'string' ? child : undefined; }); if (!inner || inner.length == 0) { inner = [attr.name]; } attr['data-title'] = inner.join(''); break; case 'MN': attr.className = 'mention'; if (data) { attr.className += ' ' + (0,_strformat_js__WEBPACK_IMPORTED_MODULE_11__.idToColorClass)(data.val, false, true); } break; case 'FM': attr.className = 'bot-form'; break; case 'RW': break; case 'QQ': attr.className = 'reply-quote'; attr.onClick = this.onQuoteClick; break; case 'VC': el = _widgets_call_message_jsx__WEBPACK_IMPORTED_MODULE_4__["default"]; values = null; if (data) { attr.callState = data.state; attr.incoming = data.incoming; attr.duration = data.duration; attr.vc = data.vc; attr.onCallJoin = this.onCallJoin; } break; case 'VD': el = handleVideoData.call(this, el, data, attr); values = null; break; default: if (!el) { el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); attr = { key: key }; let body = values; if (!Array.isArray(values) || !values.join('').trim()) { body = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { key: "x1", className: "gray" }, this.formatMessage(messages.drafty_unknown))]; } values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { key: "x0", className: "material-icons gray" }, "extension"), ' '].concat(body); } break; } if (!el) { return values; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(el, attr, values); } function handleImageData(el, data, attr) { if (!data) { attr.src = 'img/broken_image.png'; attr.style = { width: _config_js__WEBPACK_IMPORTED_MODULE_9__.IMAGE_THUMBNAIL_DIM + 'px', height: _config_js__WEBPACK_IMPORTED_MODULE_9__.IMAGE_THUMBNAIL_DIM + 'px' }; return el; } attr.className = 'inline-image'; const dim = (0,_blob_helpers_js__WEBPACK_IMPORTED_MODULE_10__.fitImageSize)(data.width, data.height, this.viewportWidth > 0 ? Math.min(this.viewportWidth - _config_js__WEBPACK_IMPORTED_MODULE_9__.REM_SIZE * 6.5, _config_js__WEBPACK_IMPORTED_MODULE_9__.REM_SIZE * 34.5) : _config_js__WEBPACK_IMPORTED_MODULE_9__.REM_SIZE * 34.5, _config_js__WEBPACK_IMPORTED_MODULE_9__.REM_SIZE * 24, false) || { dstWidth: _config_js__WEBPACK_IMPORTED_MODULE_9__.BROKEN_IMAGE_SIZE, dstHeight: _config_js__WEBPACK_IMPORTED_MODULE_9__.BROKEN_IMAGE_SIZE }; attr.style = { width: dim.dstWidth + 'px', height: dim.dstHeight + 'px', minWidth: dim.dstWidth + 'px', minHeight: dim.dstHeight + 'px' }; if (!tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isProcessing(data)) { attr.src = this.authorizeURL((0,_utils_js__WEBPACK_IMPORTED_MODULE_12__.sanitizeUrlForMime)(attr.src, 'image')); attr.alt = data.name; if (attr.src) { if (Math.max(data.width || 0, data.height || 0) > _config_js__WEBPACK_IMPORTED_MODULE_9__.IMAGE_THUMBNAIL_DIM) { attr.onClick = this.onImagePreview; attr.className += ' image-clickable'; } attr.loading = 'lazy'; } else { attr.src = null; } } else { el = _widgets_uploading_image_jsx__WEBPACK_IMPORTED_MODULE_8__["default"]; } return el; } function handleVideoData(el, data, attr) { if (!data) { attr.src = 'img/broken_video.png'; attr.style = { width: _config_js__WEBPACK_IMPORTED_MODULE_9__.IMAGE_THUMBNAIL_DIM + 'px', height: _config_js__WEBPACK_IMPORTED_MODULE_9__.IMAGE_THUMBNAIL_DIM + 'px' }; return el; } attr.className = 'inline-image'; const dim = (0,_blob_helpers_js__WEBPACK_IMPORTED_MODULE_10__.fitImageSize)(data.width, data.height, this.viewportWidth > 0 ? Math.min(this.viewportWidth - _config_js__WEBPACK_IMPORTED_MODULE_9__.REM_SIZE * 6.5, _config_js__WEBPACK_IMPORTED_MODULE_9__.REM_SIZE * 34.5) : _config_js__WEBPACK_IMPORTED_MODULE_9__.REM_SIZE * 34.5, _config_js__WEBPACK_IMPORTED_MODULE_9__.REM_SIZE * 24, false) || { dstWidth: _config_js__WEBPACK_IMPORTED_MODULE_9__.NO_DIMENSIONS_VIDEO, dstHeight: _config_js__WEBPACK_IMPORTED_MODULE_9__.NO_DIMENSIONS_VIDEO }; attr.style = { width: dim.dstWidth + 'px', height: dim.dstHeight + 'px', minWidth: dim.dstWidth + 'px', minHeight: dim.dstHeight + 'px' }; if (!tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isProcessing(data)) { attr.src = this.authorizeURL((0,_utils_js__WEBPACK_IMPORTED_MODULE_12__.sanitizeUrlForMime)(attr.src, 'image')); attr.alt = data.name; if (data.ref || data.val) { attr.onClick = this.onVideoPreview; attr.loading = 'lazy'; } el = _widgets_inline_video_jsx__WEBPACK_IMPORTED_MODULE_6__["default"]; } else { el = _widgets_uploading_image_jsx__WEBPACK_IMPORTED_MODULE_8__["default"]; } return el; } function previewFormatter(style, data, values, key) { if (!style) { return values; } let el = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.tagName(style); const attr = { key: key }; switch (style) { case 'AU': el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { key: "au", className: "material-icons" }, "mic"), ' ', (0,_strformat_js__WEBPACK_IMPORTED_MODULE_11__.secondsToTime)(data.duration / 1000)]; break; case 'BR': el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [' ']; break; case 'HL': attr.className = 'highlight preview'; break; case 'LN': case 'MN': el = 'span'; break; case 'IM': el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { key: "im", className: "material-icons" }, "photo"), ' ', this.formatMessage(messages.drafty_image)]; break; case 'BN': el = 'span'; attr.className = 'flat-button faux'; break; case 'FM': el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { key: "fm", className: "material-icons" }, "dashboard"), this.formatMessage(messages.drafty_form)].concat(' ', values || []); break; case 'RW': el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); break; case 'EX': if (data) { if (data.mime == 'application/json') { return null; } delete data.val; delete data.ref; } el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { key: "ex", className: "material-icons" }, "attachment"), ' ', this.formatMessage(messages.drafty_attachment)]; break; case 'VC': el = _widgets_call_status_jsx__WEBPACK_IMPORTED_MODULE_5__["default"]; if (data) { attr.callState = data.state; attr.incoming = data.incoming; attr.duration = data.duration; } values = null; break; case 'QQ': case 'HD': el = null; values = null; break; case 'VD': el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { key: "im", className: "material-icons" }, "play_circle_outline"), ' ', this.formatMessage(messages.drafty_video)]; break; default: if (!el) { el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { key: "x0", className: "material-icons gray" }, "extension"), ' ', this.formatMessage(messages.drafty_unknown)]; } break; } if (!el) { return values; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(el, attr, values); } ; function inlineImageAttr(attr, data) { attr.style = { width: _config_js__WEBPACK_IMPORTED_MODULE_9__.IMAGE_THUMBNAIL_DIM + 'px', height: _config_js__WEBPACK_IMPORTED_MODULE_9__.IMAGE_THUMBNAIL_DIM + 'px', maxWidth: _config_js__WEBPACK_IMPORTED_MODULE_9__.IMAGE_THUMBNAIL_DIM + 'px', maxHeight: _config_js__WEBPACK_IMPORTED_MODULE_9__.IMAGE_THUMBNAIL_DIM + 'px' }; attr.className = 'inline-image'; attr.alt = this.formatMessage(messages.drafty_image); if (!data) { attr.src = 'img/broken_image.png'; } else { attr.src = attr.src || 'img/broken_image.png'; } attr.title = attr.alt; return attr; } function inlineVideoAttr(attr, data) { const dim = (0,_blob_helpers_js__WEBPACK_IMPORTED_MODULE_10__.fitImageSize)(data.width, data.height, _config_js__WEBPACK_IMPORTED_MODULE_9__.VIDEO_THUMBNAIL_WIDTH, _config_js__WEBPACK_IMPORTED_MODULE_9__.IMAGE_THUMBNAIL_DIM); attr.style = { width: dim.width + 'px', height: dim.height + 'px', maxWidth: _config_js__WEBPACK_IMPORTED_MODULE_9__.VIDEO_THUMBNAIL_WIDTH + 'px', maxHeight: _config_js__WEBPACK_IMPORTED_MODULE_9__.IMAGE_THUMBNAIL_DIM + 'px' }; attr.className = 'inline-image'; attr.alt = this.formatMessage(messages.drafty_video); attr.title = attr.alt; if (!data) { attr.src = 'img/broken_video.png'; } else { attr.src = attr.src || 'img/broken_video.png'; } return attr; } function quoteFormatter(style, data, values, key) { if (['BR', 'EX', 'IM', 'MN', 'VD'].includes(style)) { let el = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.tagName(style); let attr = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attrValue(style, data) || {}; attr.key = key; switch (style) { case 'BR': values = null; break; case 'IM': attr = inlineImageAttr.call(this, attr, data); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement('img', attr, null), ' ', attr.alt]; el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); attr = { key: key }; break; case 'VD': attr = inlineVideoAttr.call(this, attr, data); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement('img', attr, null), ' ', attr.alt]; el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); attr = { key: key }; break; case 'MN': el = 'span'; attr.className = 'mention'; if (data) { attr.className += ' ' + (0,_strformat_js__WEBPACK_IMPORTED_MODULE_11__.idToColorClass)(data.val, false, true); } break; case 'EX': let fname; if (data) { if (data.mime == 'application/json') { return null; } fname = data.name; delete data.val; delete data.ref; } el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment); values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { key: "ex", className: "material-icons" }, "attachment"), (0,_strformat_js__WEBPACK_IMPORTED_MODULE_11__.shortenFileName)(fname, 16) || this.formatMessage(messages.drafty_attachment)]; break; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(el, attr, values); } return previewFormatter.call(this, style, data, values, key); } function quoteImageOrVideo(data, isVideo) { let promise; let bits, ref, mime; if (isVideo) { bits = data.preview; mime = data.premime || 'image/jpeg'; ref = data.preref; } else { bits = data.val; mime = data.mime; ref = data.ref; } if (bits) { const blob = (0,_blob_helpers_js__WEBPACK_IMPORTED_MODULE_10__.base64ToBlob)(bits, mime); if (!blob) { throw new Error("Invalid image"); } promise = Promise.resolve(blob); } else if (ref) { promise = fetch(this.authorizeURL((0,_utils_js__WEBPACK_IMPORTED_MODULE_12__.sanitizeUrlForMime)(ref, 'image'))).then(evt => { if (evt.ok) { return evt.blob(); } else { throw new Error(`Image fetch unsuccessful: ${evt.status} ${evt.statusText}`); } }); } else { throw new Error("Missing image data"); } return promise.then(blob => { return (0,_blob_helpers_js__WEBPACK_IMPORTED_MODULE_10__.imageScaled)(blob, isVideo ? _config_js__WEBPACK_IMPORTED_MODULE_9__.VIDEO_THUMBNAIL_WIDTH : _config_js__WEBPACK_IMPORTED_MODULE_9__.IMAGE_THUMBNAIL_DIM, _config_js__WEBPACK_IMPORTED_MODULE_9__.IMAGE_THUMBNAIL_DIM, -1, !isVideo); }).then(scaled => { if (isVideo) { data.premime = scaled.mime; } else { data.mime = scaled.mime; } data.size = scaled.blob.size; data.width = scaled.width; data.height = scaled.height; delete data.ref; delete data.preref; data.src = URL.createObjectURL(scaled.blob); return (0,_blob_helpers_js__WEBPACK_IMPORTED_MODULE_10__.blobToBase64)(scaled.blob); }).then(b64 => { if (isVideo) { data.preview = b64.bits; } else { data.val = b64.bits; } return data; }).catch(err => { delete data.val; delete data.preview; delete data.src; data.width = _config_js__WEBPACK_IMPORTED_MODULE_9__.IMAGE_THUMBNAIL_DIM; data.height = _config_js__WEBPACK_IMPORTED_MODULE_9__.IMAGE_THUMBNAIL_DIM; throw err; }); } function replyFormatter(style, data, values, key, stack) { if (style == 'IM' || style == 'VD') { const isImage = style == 'IM'; const attr = isImage ? inlineImageAttr.call(this, { key: key }, data) : inlineVideoAttr.call(this, { key: key }, data); let loadedPromise; try { loadedPromise = (0,_utils_js__WEBPACK_IMPORTED_MODULE_12__.cancelablePromise)(quoteImageOrVideo.call(this, data, style == 'VD')); } catch (error) { console.warn("Failed to quote image:", error.message); loadedPromise = (0,_utils_js__WEBPACK_IMPORTED_MODULE_12__.cancelablePromise)(error); } attr.whenDone = loadedPromise; values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_lazy_image_jsx__WEBPACK_IMPORTED_MODULE_7__["default"], attr, null), ' ', attr.alt]; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), { key: key }, values); } else if (style == 'QQ') { if (stack.includes('QQ')) { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement('span', { key: key }, [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { key: "qq", className: "material-icons" }, "format_quote"), ' ']); } const attr = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attrValue('QQ', data) || {}; attr.key = key; attr.className = 'reply-quote'; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.tagName('QQ'), attr, values); } return quoteFormatter.call(this, style, data, values, key); } /***/ }), /***/ "./src/lib/host-name.js": /*!******************************!*\ !*** ./src/lib/host-name.js ***! \******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "detectServerAddress": () => (/* binding */ detectServerAddress), /* harmony export */ "isLocalHost": () => (/* binding */ isLocalHost), /* harmony export */ "isSecureConnection": () => (/* binding */ isSecureConnection) /* harmony export */ }); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); function detectServerAddress() { let host = _config_js__WEBPACK_IMPORTED_MODULE_0__.DEFAULT_HOST; if (typeof window.location == 'object') { if (window.location.protocol == 'file:' || window.location.hostname == 'localhost') { host = _config_js__WEBPACK_IMPORTED_MODULE_0__.KNOWN_HOSTS.local; } else if (window.location.hostname) { host = window.location.hostname + (window.location.port ? ':' + window.location.port : ''); } } return host; } function isSecureConnection() { if (typeof window.location == 'object') { return window.location.protocol == 'https:'; } return false; } function isLocalHost() { if (typeof window.location == 'object') { return window.location.hostname == 'localhost'; } return false; } /***/ }), /***/ "./src/lib/local-storage.js": /*!**********************************!*\ !*** ./src/lib/local-storage.js ***! \**********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ LocalStorageUtil) /* harmony export */ }); class LocalStorageUtil { static setObject(key, value) { localStorage.setItem(key, JSON.stringify(value)); } static getObject(key) { const value = localStorage.getItem(key); return value && JSON.parse(value); } static updateObject(key, value) { const oldVal = this.getObject(key); this.setObject(key, Object.assign(oldVal || {}, value)); } static removeItem(key) { localStorage.removeItem(key); } } /***/ }), /***/ "./src/lib/navigation.js": /*!*******************************!*\ !*** ./src/lib/navigation.js ***! \*******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ HashNavigation) /* harmony export */ }); class HashNavigation { static parseUrlHash(hash) { const parts = hash.split('?', 2); const params = {}; let path = []; if (parts[0]) { path = parts[0].replace('#', '').split('/'); } if (parts[1]) { parts[1].split('&').forEach(arg => { const eq = arg.indexOf('='); if (eq > 0) { params[arg.slice(0, eq)] = decodeURIComponent(arg.slice(eq + 1)); } }); } return { path: path, params: params }; } static navigateTo(url) { window.location.hash = url; } static composeUrlHash(path, params) { let url = path.join('/'); const args = []; for (const key in params) { if (params.hasOwnProperty(key)) { if (params[key] !== undefined) { args.push(key + '=' + encodeURIComponent(params[key])); } } } if (args.length > 0) { url += '?' + args.join('&'); } return url; } static addUrlParam(hash, key, value) { const parsed = HashNavigation.parseUrlHash(hash); parsed.params[key] = value; return HashNavigation.composeUrlHash(parsed.path, parsed.params); } static removeUrlParam(hash, key) { const parsed = HashNavigation.parseUrlHash(hash); delete parsed.params[key]; return HashNavigation.composeUrlHash(parsed.path, parsed.params); } static setUrlSidePanel(hash, sidepanel) { const parsed = HashNavigation.parseUrlHash(hash); parsed.path[0] = sidepanel; return HashNavigation.composeUrlHash(parsed.path, parsed.params); } static setUrlInfoPanel(hash, infopanel) { const parsed = HashNavigation.parseUrlHash(hash); if (infopanel) { parsed.params.info = infopanel; } else { delete parsed.params.info; } return HashNavigation.composeUrlHash(parsed.path, parsed.params); } static setUrlTopic(hash, topic) { const parsed = HashNavigation.parseUrlHash(hash); parsed.path[1] = topic; delete parsed.params.info; return HashNavigation.composeUrlHash(parsed.path, parsed.params); } } /***/ }), /***/ "./src/lib/strformat.js": /*!******************************!*\ !*** ./src/lib/strformat.js ***! \******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "bytesToHumanSize": () => (/* binding */ bytesToHumanSize), /* harmony export */ "flagEmoji": () => (/* binding */ flagEmoji), /* harmony export */ "idToColorClass": () => (/* binding */ idToColorClass), /* harmony export */ "letterTileColorId": () => (/* binding */ letterTileColorId), /* harmony export */ "relativeDateFormat": () => (/* binding */ relativeDateFormat), /* harmony export */ "secondsToTime": () => (/* binding */ secondsToTime), /* harmony export */ "shortDateFormat": () => (/* binding */ shortDateFormat), /* harmony export */ "shortenFileName": () => (/* binding */ shortenFileName) /* harmony export */ }); function shortDateFormat(then, locale) { locale = locale || window.navigator.userLanguage || window.navigator.language; const now = new Date(); if (then.getFullYear() == now.getFullYear()) { if (then.getMonth() == now.getMonth() && then.getDate() == now.getDate()) { return then.toLocaleTimeString(locale, { hour12: false, hour: '2-digit', minute: '2-digit' }); } return then.toLocaleDateString(locale, { hour12: false, month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }); } return then.toLocaleDateString(locale, { year: 'numeric', month: 'short', day: 'numeric' }); } function relativeDateFormat(then, locale) { locale = locale || window.navigator.userLanguage || window.navigator.language; const now = new Date(); const thenDays = Math.floor((then.getTime() - then.getTimezoneOffset() * 60_000) / 86_400_000); const nowDays = Math.floor((now.getTime() - now.getTimezoneOffset() * 60_000) / 86_400_000); const diff = thenDays - nowDays; if (Math.abs(diff) < 2) { return new Intl.RelativeTimeFormat(locale, { numeric: 'auto' }).format(diff, 'day'); } return new Intl.DateTimeFormat(locale).format(then); } function secondsToTime(seconds, fixedMin) { if (typeof seconds != 'number') { return ''; } let min = (Math.floor(seconds / 60) | 0) % 60; let hours = Math.floor(seconds / 3600) | 0; if (fixedMin || hours > 0) { min = min < 10 ? `0${min}` : min; } let sec = (seconds | 0) % 60; sec = sec < 10 ? `0${sec}` : sec; if (hours == 0) { return `${min}:${sec}`; } return `${hours}:${min}:${sec}`; } function bytesToHumanSize(bytes) { if (!bytes || bytes == 0) { return '0 Bytes'; } const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB']; const bucket = Math.min(Math.floor(Math.log2(bytes) / 10) | 0, sizes.length - 1); const count = bytes / Math.pow(1024, bucket); const round = bucket > 0 ? count < 3 ? 2 : count < 30 ? 1 : 0 : 0; return count.toFixed(round) + ' ' + sizes[bucket]; } function shortenFileName(filename, maxLength) { if (typeof filename != 'string') { return filename; } return filename.length > maxLength ? filename.slice(0, maxLength / 2 - 1) + '…' + filename.slice(1 - maxLength / 2) : filename; } function stringToColorHash(value) { let hash = 0; value = '' + value; for (let i = 0; i < value.length; i++) { hash = (hash << 5) - hash + value.charCodeAt(i); hash = hash & hash; } return hash; } function letterTileColorId(userId) { return Math.abs(stringToColorHash(userId)) % 16; } function idToColorClass(id, light, fg) { return (light ? 'lt-' : 'dk-') + (fg ? 'fg-' : 'bg-') + letterTileColorId(id); } function flagEmoji(countryCode) { const codePoints = countryCode.toUpperCase().split('').map(char => 0x1F1A5 + char.charCodeAt()); return String.fromCodePoint(...codePoints); } /***/ }), /***/ "./src/lib/utils.js": /*!**************************!*\ !*** ./src/lib/utils.js ***! \**************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "arrayEqual": () => (/* binding */ arrayEqual), /* harmony export */ "asEmail": () => (/* binding */ asEmail), /* harmony export */ "asPhone": () => (/* binding */ asPhone), /* harmony export */ "cancelablePromise": () => (/* binding */ cancelablePromise), /* harmony export */ "clipStr": () => (/* binding */ clipStr), /* harmony export */ "deliveryMarker": () => (/* binding */ deliveryMarker), /* harmony export */ "isUrlRelative": () => (/* binding */ isUrlRelative), /* harmony export */ "sanitizeUrl": () => (/* binding */ sanitizeUrl), /* harmony export */ "sanitizeUrlForMime": () => (/* binding */ sanitizeUrlForMime), /* harmony export */ "theCard": () => (/* binding */ theCard), /* harmony export */ "updateFavicon": () => (/* binding */ updateFavicon) /* harmony export */ }); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_0__); function updateFavicon(count) { const oldIcon = document.getElementById('shortcut-icon'); const head = document.head || document.getElementsByTagName('head')[0]; const newIcon = document.createElement('link'); newIcon.type = 'image/png'; newIcon.id = 'shortcut-icon'; newIcon.rel = 'shortcut icon'; newIcon.href = 'img/logo32x32' + (count > 0 ? 'a' : '') + '.png'; if (oldIcon) { head.removeChild(oldIcon); } head.appendChild(newIcon); document.title = (count > 0 ? '(' + count + ') ' : '') + 'Tinode'; } function theCard(fn, imageUrl, imageMimeType, note) { let card = null; fn = fn && fn.trim(); note = note && note.trim(); if (fn) { card = { fn: fn }; } if (typeof note == 'string') { card = card || {}; card.note = note ? note : tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.DEL_CHAR; } if (imageUrl) { card = card || {}; let mimeType = imageMimeType; const matches = /^data:(image\/[-a-z0-9+.]+)?(;base64)?,/i.exec(imageUrl); if (matches) { mimeType = matches[1]; card.photo = { data: imageUrl.substring(imageUrl.indexOf(',') + 1), ref: tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.DEL_CHAR }; } else { card.photo = { data: tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.DEL_CHAR, ref: imageUrl }; } card.photo.type = (mimeType || 'image/jpeg').substring('image/'.length); } return card; } function arrayEqual(a, b) { if (a === b) { return true; } if (!Array.isArray(a) || !Array.isArray(b)) { return false; } if (a.length != b.length) { return false; } a.sort(); b.sort(); for (let i = 0, l = a.length; i < l; i++) { if (a[i] !== b[i]) { return false; } } return true; } function asPhone(val) { val = val.trim(); if (/^(?:\+?(\d{1,3}))?[- (.]*(\d{3})[- ).]*(\d{3})[- .]*(\d{2})[- .]*(\d{2})?$/.test(val)) { return val.replace(/[- ().]*/, ''); } return null; } function asEmail(val) { val = val.trim(); if (/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/.test(val)) { return val; } return null; } function isUrlRelative(url) { return url && !/^\s*([a-z][a-z0-9+.-]*:|\/\/)/im.test(url); } function sanitizeUrl(url, allowedSchemes) { if (typeof url != 'string') { return url; } url = url.replace(/[^\x20-\x7E]/gmi, '').trim(); if (!/^([a-z][a-z0-9+.-]*:|\/\/)/i.test(url)) { return url; } if (/^blob:http/.test(url)) { return url; } const schemes = Array.isArray(allowedSchemes) ? allowedSchemes.join('|') : 'http|https'; const re = new RegExp('^((' + schemes + '):|//)', 'i'); if (!re.test(url)) { return null; } return url; } function sanitizeUrlForMime(url, mimeMajor) { if (!url) { return null; } const sanitizedUrl = sanitizeUrl(url); if (sanitizedUrl) { return sanitizedUrl; } const re = new RegExp(`data:${mimeMajor}\/[a-z0-9.-]+;base64,`, 'i'); if (re.test(url.trim())) { return url; } return null; } function deliveryMarker(received) { switch (received) { case tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.MESSAGE_STATUS_SENDING: return { name: 'access_time' }; case tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.MESSAGE_STATUS_FAILED: case tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.MESSAGE_STATUS_FATAL: return { name: 'warning', color: 'danger-color' }; case tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.MESSAGE_STATUS_SENT: return { name: 'done' }; case tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.MESSAGE_STATUS_RECEIVED: return { name: 'done_all' }; case tinode_sdk__WEBPACK_IMPORTED_MODULE_0__.Tinode.MESSAGE_STATUS_READ: return { name: 'done_all', color: 'blue' }; } return null; } function cancelablePromise(promise) { let hasCanceled = false; const wrappedPromise = promise instanceof Error ? Promise.reject(promise) : new Promise((resolve, reject) => { promise.then(result => hasCanceled ? reject({ isCanceled: true }) : resolve(result), error => hasCanceled ? reject({ isCanceled: true }) : reject(error)); }); return { promise: wrappedPromise, cancel() { hasCanceled = true; } }; } ; function clipStr(str, length) { return str && str.substring(0, length); } /***/ }), /***/ "./src/version.js": /*!************************!*\ !*** ./src/version.js ***! \************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "PACKAGE_VERSION": () => (/* binding */ PACKAGE_VERSION) /* harmony export */ }); const PACKAGE_VERSION = "0.23.0-rc1"; /***/ }), /***/ "./src/views/acc-notifications-view.jsx": /*!**********************************************!*\ !*** ./src/views/acc-notifications-view.jsx ***! \**********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ EditAccountView) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/checkbox.jsx */ "./src/widgets/checkbox.jsx"); class EditAccountView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleCheckboxClick = this.handleCheckboxClick.bind(this); } handleCheckboxClick(what, checked) { if (what == 'sound') { this.props.onToggleMessageSounds(checked); } else if (what == 'alert') { this.props.onTogglePushNotifications(checked); } else if (what == 'incognito') { this.props.onToggleIncognitoMode(checked); } } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "scrollable-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { htmlFor: "message-sound" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_message_sound", defaultMessage: [{ "type": 0, "value": "Message sound:" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { name: "sound", id: "message-sound", checked: this.props.messageSounds, onChange: this.handleCheckboxClick })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { htmlFor: "desktop-alerts" }, this.props.desktopAlertsEnabled ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_push_notifications", defaultMessage: [{ "type": 0, "value": "Notification alerts:" }] }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_push_notifications_disabled", defaultMessage: [{ "type": 0, "value": "Notification alerts (requires HTTPS):" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { name: "alert", id: "desktop-alerts", checked: this.props.desktopAlerts, onChange: this.props.desktopAlertsEnabled ? this.handleCheckboxClick : null })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { htmlFor: "incognito-mode" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_incognito_mode", defaultMessage: [{ "type": 0, "value": "Incognito mode:" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { name: "incognito", id: "incognito-mode", checked: this.props.incognitoMode, onChange: this.handleCheckboxClick }))); } } ; /***/ }), /***/ "./src/views/acc-security-view.jsx": /*!*****************************************!*\ !*** ./src/views/acc-security-view.jsx ***! \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/in-place-edit.jsx */ "./src/widgets/in-place-edit.jsx"); /* harmony import */ var _widgets_permissions_editor_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/permissions-editor.jsx */ "./src/widgets/permissions-editor.jsx"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ delete_account: { id: "delete_account", defaultMessage: [{ "type": 0, "value": "Delete account" }] }, delete_account_warning: { id: "delete_account_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to delete your account? It cannot be undone." }] } }); class AccSecurityView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); const me = this.props.tinode.getMeTopic(); let blockedCount = 0; me.contacts(c => { if (c.acs && !c.acs.isJoiner()) { blockedCount++; } }); const defacs = me.getDefaultAccess(); this.state = { auth: defacs ? defacs.auth : null, anon: defacs ? defacs.anon : null, showPermissionEditorFor: undefined, blockedCount: blockedCount }; this.handlePasswordUpdate = this.handlePasswordUpdate.bind(this); this.handleLaunchPermissionsEditor = this.handleLaunchPermissionsEditor.bind(this); this.handleHidePermissionsEditor = this.handleHidePermissionsEditor.bind(this); this.handlePermissionsChanged = this.handlePermissionsChanged.bind(this); this.handleDeleteAccount = this.handleDeleteAccount.bind(this); } handlePasswordUpdate(pwd) { this.setState({ password: pwd }); this.props.onUpdatePassword(pwd); } handleLaunchPermissionsEditor(which) { this.setState({ showPermissionEditorFor: which, editedPermissions: this.state[which] }); } handleHidePermissionsEditor() { this.setState({ showPermissionEditorFor: undefined }); } handlePermissionsChanged(perm) { let defacs = {}; defacs[this.state.showPermissionEditorFor] = perm; this.props.onUpdateAccountDesc('me', undefined, undefined, defacs); let newState = { showPermissionEditorFor: undefined }; newState[this.state.showPermissionEditorFor] = perm; this.setState(newState); } handleDeleteAccount(e) { e.preventDefault(); const { formatMessage } = this.props.intl; this.props.onShowAlert(formatMessage(messages.delete_account), formatMessage(messages.delete_account_warning), _ => this.props.onDeleteAccount(), null, true, null); } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, this.state.showPermissionEditorFor ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_permissions_editor_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { mode: this.state.editedPermissions, skip: "O", onSubmit: this.handlePermissionsChanged, onCancel: this.handleHidePermissionsEditor }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "scrollable-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_password", defaultMessage: [{ "type": 0, "value": "Password" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "password_unchanged_prompt", defaultMessage: [{ "type": 0, "value": "Unchanged" }] }, password_unchanged => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { placeholder: password_unchanged, type: "password", onFinished: this.handlePasswordUpdate })))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "danger flat-button", onClick: e => { e.preventDefault(); this.props.onLogout(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "exit_to_app"), " \xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_logout", defaultMessage: [{ "type": 0, "value": "Logout" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "danger flat-button", onClick: e => { this.handleDeleteAccount(e); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "delete"), " \xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_delete_account", defaultMessage: [{ "type": 0, "value": "Delete account" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_default_access_mode", defaultMessage: [{ "type": 0, "value": "Default access mode:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "quoted" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, "Auth: ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", { className: "clickable", onClick: this.handleLaunchPermissionsEditor.bind(this, 'auth') }, this.state.auth)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, "Anon: ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", { className: "clickable", onClick: this.handleLaunchPermissionsEditor.bind(this, 'anon') }, this.state.anon)))), this.state.blockedCount > 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "block"), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "gray", onClick: e => { e.preventDefault(); this.props.onShowBlocked(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "blocked_contacts_link", defaultMessage: [{ "type": 0, "value": "Blocked contacts (" }, { "type": 1, "value": "count" }, { "type": 0, "value": ")" }], values: { count: this.state.blockedCount } })))) : null)); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(AccSecurityView)); /***/ }), /***/ "./src/views/acc-support-view.jsx": /*!****************************************!*\ !*** ./src/views/acc-support-view.jsx ***! \****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ AccSupportView) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); class AccSupportView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "scrollable-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: _config_js__WEBPACK_IMPORTED_MODULE_3__.LINK_CONTACT_US, className: "flat-button", target: "_blank" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "email"), " \xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "link_contact_us", defaultMessage: [{ "type": 0, "value": "Contact Us" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: _config_js__WEBPACK_IMPORTED_MODULE_3__.LINK_TERMS_OF_SERVICE, className: "flat-button", target: "_blank" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "description"), " \xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "link_terms_of_service", defaultMessage: [{ "type": 0, "value": "Terms of Service" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: _config_js__WEBPACK_IMPORTED_MODULE_3__.LINK_PRIVACY_POLICY, className: "flat-button", target: "_blank" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "policy"), " \xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "link_privacy_policy", defaultMessage: [{ "type": 0, "value": "Privacy Policy" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_client", defaultMessage: [{ "type": 0, "value": "Client:" }] })), _config_js__WEBPACK_IMPORTED_MODULE_3__.APP_NAME), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_sdk", defaultMessage: [{ "type": 0, "value": "SDK:" }] })), tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.getLibrary()), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_server", defaultMessage: [{ "type": 0, "value": "Server:" }] })), this.props.serverVersion), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_server_address", defaultMessage: [{ "type": 0, "value": "Server address:" }] })), this.props.serverAddress))); } } ; /***/ }), /***/ "./src/views/contacts-view.jsx": /*!*************************************!*\ !*** ./src/views/contacts-view.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ ContactsView) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_contact_list_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/contact-list.jsx */ "./src/widgets/contact-list.jsx"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ archived_contacts_title: { id: "archived_contacts", defaultMessage: [{ "type": 0, "value": "Archived contacts (" }, { "type": 1, "value": "count" }, { "type": 0, "value": ")" }] } }); class ContactsView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.handleAction = this.handleAction.bind(this); this.state = ContactsView.deriveStateFromProps(props); } static deriveStateFromProps(props) { const contacts = []; let unreadThreads = 0; let archivedCount = 0; props.chatList.forEach(c => { const blocked = c.acs && !c.acs.isJoiner(); if (blocked && props.blocked) { contacts.push(c); } if (blocked || props.blocked) { return; } if (c.private && c.private.arch) { if (props.archive) { contacts.push(c); } else { archivedCount++; } } else if (!props.archive) { contacts.push(c); unreadThreads += c.unread > 0 ? 1 : 0; } }); contacts.sort((a, b) => { return (b.touched || 0) - (a.touched || 0); }); if (archivedCount > 0) { contacts.push({ action: 'archive', title: messages.archived_contacts_title, values: { count: archivedCount } }); } return { contactList: contacts, unreadThreads: unreadThreads }; } componentDidUpdate(prevProps, prevState) { if (prevProps.chatList != this.props.chatList || prevProps.archive != this.props.archive || prevProps.blocked != this.props.blocked) { const newState = ContactsView.deriveStateFromProps(this.props); this.setState(newState); if (newState.unreadThreads != prevState.unreadThreads) { (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_3__.updateFavicon)(newState.unreadThreads); } } } handleAction(action_ignored) { this.props.onShowArchive(); } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "contacts_not_found", defaultMessage: [{ "type": 0, "value": "You have no chats" }, { "type": 0, "value": "
" }, { "type": 0, "value": "¯∖_(ツ)_/¯" }] }, no_contacts => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_contact_list_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { tinode: this.props.tinode, connected: this.props.connected, contacts: this.state.contactList, emptyListMessage: no_contacts, topicSelected: this.props.topicSelected, myUserId: this.props.myUserId, showOnline: true, showUnread: true, onTopicSelected: this.props.onTopicSelected, showContextMenu: this.props.showContextMenu, onAction: this.handleAction })); } } ; /***/ }), /***/ "./src/views/info-view.jsx": /*!*********************************!*\ !*** ./src/views/info-view.jsx ***! \*********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _widgets_avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/avatar-upload.jsx */ "./src/widgets/avatar-upload.jsx"); /* harmony import */ var _widgets_badge_list_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../widgets/badge-list.jsx */ "./src/widgets/badge-list.jsx"); /* harmony import */ var _widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../widgets/checkbox.jsx */ "./src/widgets/checkbox.jsx"); /* harmony import */ var _widgets_contact_list_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../widgets/contact-list.jsx */ "./src/widgets/contact-list.jsx"); /* harmony import */ var _widgets_error_panel_jsx__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../widgets/error-panel.jsx */ "./src/widgets/error-panel.jsx"); /* harmony import */ var _widgets_group_manager_jsx__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../widgets/group-manager.jsx */ "./src/widgets/group-manager.jsx"); /* harmony import */ var _widgets_menu_cancel_jsx__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../widgets/menu-cancel.jsx */ "./src/widgets/menu-cancel.jsx"); /* harmony import */ var _widgets_permissions_editor_jsx__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../widgets/permissions-editor.jsx */ "./src/widgets/permissions-editor.jsx"); /* harmony import */ var _topic_common_view_jsx__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./topic-common-view.jsx */ "./src/views/topic-common-view.jsx"); /* harmony import */ var _widgets_topic_security_jsx__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../widgets/topic-security.jsx */ "./src/widgets/topic-security.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ info: { id: "panel_title_info", defaultMessage: [{ "type": 0, "value": "Info" }] }, general: { id: "panel_title_general", defaultMessage: [{ "type": 0, "value": "General" }] }, security: { id: "panel_title_security", defaultMessage: [{ "type": 0, "value": "Security" }] }, members: { id: "panel_title_members", defaultMessage: [{ "type": 0, "value": "Members" }] }, crop: { id: "panel_title_crop", defaultMessage: [{ "type": 0, "value": "Drag to Adjust" }] }, perm_want: { id: "requested_permissions", defaultMessage: [{ "type": 0, "value": "Requested" }] }, perm_given: { id: "granted_permissions", defaultMessage: [{ "type": 0, "value": "Granted" }] }, perm_auth: { id: "permissions_authenticated", defaultMessage: [{ "type": 0, "value": "Authenticated" }] }, perm_anon: { id: "permissions_anonymous", defaultMessage: [{ "type": 0, "value": "Anonymous" }] }, perm_user: { id: "permissions_user", defaultMessage: [{ "type": 0, "value": "User's Permissions" }] }, edit_permissions: { id: "menu_item_edit_permissions", defaultMessage: [{ "type": 0, "value": "Edit permissions" }] } }); class InfoView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { topic: null, owner: false, admin: false, sharer: false, deleter: false, muted: false, address: null, groupTopic: undefined, channel: undefined, fullName: undefined, description: undefined, avatar: null, private: null, selectedContact: null, access: null, modeGiven: null, modeWant: null, modeGiven2: null, modeWant2: null, auth: null, anon: null, contactList: [], trustedBadges: [], previousMetaDesc: undefined, previousSubsUpdated: undefined }; this.resetSubs = this.resetSubs.bind(this); this.resetDesc = this.resetDesc.bind(this); this.resetTags = this.resetTags.bind(this); this.onMetaDesc = this.onMetaDesc.bind(this); this.onSubsUpdated = this.onSubsUpdated.bind(this); this.handleImageChanged = this.handleImageChanged.bind(this); this.handleMuted = this.handleMuted.bind(this); this.handleUnarchive = this.handleUnarchive.bind(this); this.handlePermissionsChanged = this.handlePermissionsChanged.bind(this); this.handleLaunchPermissionsEditor = this.handleLaunchPermissionsEditor.bind(this); this.handleShowAddMembers = this.handleShowAddMembers.bind(this); this.handleMemberUpdateRequest = this.handleMemberUpdateRequest.bind(this); this.handleMemberSelected = this.handleMemberSelected.bind(this); this.handleContextMenu = this.handleContextMenu.bind(this); this.handleBackNavigate = this.handleBackNavigate.bind(this); } componentDidUpdate(props) { const topic = this.props.tinode.getTopic(props.topic); if (!topic) { return; } if (this.onMetaDesc != topic.onMetaDesc) { this.previousMetaDesc = topic.onMetaDesc; topic.onMetaDesc = this.onMetaDesc; this.previousSubsUpdated = topic.onSubsUpdated; topic.onSubsUpdated = this.onSubsUpdated; } if (this.state.topic != props.topic) { this.setState({ topic: props.topic }); this.resetDesc(topic, props); this.resetSubs(topic, props); this.resetTags(topic); } } componentWillUnmount() { const topic = this.props.tinode.getTopic(this.props.topic); if (!topic) { return; } this.setState({ topic: null }); topic.onMetaDesc = this.previousMetaDesc; topic.onSubsUpdated = this.previousSubsUpdated; } resetSubs(topic, props) { const newState = { contactList: [] }; if (topic.getType() == 'p2p') { const user2 = topic.subscriber(props.topic); if (user2) { newState.modeGiven2 = user2.acs.getGiven(); newState.modeWant2 = user2.acs.getWant(); } else { newState.modeGiven2 = _config_js__WEBPACK_IMPORTED_MODULE_13__.NO_ACCESS_MODE; newState.modeWant2 = _config_js__WEBPACK_IMPORTED_MODULE_13__.NO_ACCESS_MODE; } } else { topic.subscribers(sub => { newState.contactList.push(sub); }, this); } this.setState(newState); } resetDesc(topic, props) { const defacs = topic.getDefaultAccess() || {}; const acs = topic.getAccessMode(); const badges = []; if (topic.trusted) { for (const [key, val] of Object.entries(topic.trusted)) { if (val) { badges.push(key); } } } this.setState({ owner: acs && acs.isOwner(), admin: acs && acs.isAdmin(), sharer: acs && acs.isSharer(), deleter: acs && acs.isDeleter(), muted: acs && acs.isMuted(), fullName: (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_15__.clipStr)(topic.public && topic.public.fn, _config_js__WEBPACK_IMPORTED_MODULE_13__.MAX_TITLE_LENGTH), description: (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_15__.clipStr)(topic.public && topic.public.note, _config_js__WEBPACK_IMPORTED_MODULE_13__.MAX_TOPIC_DESCRIPTION_LENGTH), avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_14__.makeImageUrl)(topic.public ? topic.public.photo : null), trustedBadges: badges, private: (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_15__.clipStr)(topic.private && topic.private.comment, _config_js__WEBPACK_IMPORTED_MODULE_13__.MAX_TITLE_LENGTH), archived: topic.isArchived(), address: topic.name, groupTopic: topic.isGroupType(), channel: topic.isChannelType() || topic.chan, access: acs ? acs.getMode() : undefined, modeGiven: acs ? acs.getGiven() : undefined, modeWant: acs ? acs.getWant() : undefined, auth: defacs.auth, anon: defacs.anon }); } resetTags(topic) { if (topic.getType() != 'grp') { return; } const acs = topic.getAccessMode(); if (acs && acs.isOwner()) { topic.getMeta(topic.startMetaQuery().withTags().build()); } } onMetaDesc(desc) { const topic = this.props.tinode.getTopic(this.props.topic); if (!topic) { return; } this.resetDesc(topic, this.props); if (this.previousMetaDesc && this.previousMetaDesc != this.onMetaDesc) { this.previousMetaDesc(desc); } } onSubsUpdated(subs) { const topic = this.props.tinode.getTopic(this.props.topic); if (!topic) { return; } this.resetSubs(topic, this.props); if (this.previousSubsUpdated && this.previousSubsUpdated != this.onSubsUpdated) { this.previousSubsUpdated(subs); } } handleImageChanged(mime, img) { this.setState({ avatar: img }); this.props.onTopicDescUpdate(this.props.topic, (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_15__.theCard)(null, img || tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.DEL_CHAR), null); } handleMuted(ignored, checked) { this.setState({ muted: checked }); this.props.onChangePermissions(this.props.topic, checked ? '-P' : '+P'); } handleUnarchive(ignored, ignored2) { this.props.onTopicUnArchive(this.props.topic); } handlePermissionsChanged(which, perm) { switch (which) { case 'auth': this.props.onTopicDescUpdateRequest(this.props.topic, null, null, { auth: perm }); break; case 'anon': this.props.onTopicDescUpdateRequest(this.props.topic, null, null, { anon: perm }); break; case 'mode': case 'want': this.props.onChangePermissions(this.props.topic, perm); break; case 'given': this.props.onChangePermissions(this.props.topic, perm, this.props.topic); break; case 'user': this.props.onChangePermissions(this.props.topic, perm, this.state.userPermissionsEdited); break; } this.handleBackNavigate(); } handleLaunchPermissionsEditor(which, uid) { const { formatMessage } = this.props.intl; let toEdit, toCompare, toSkip, titleEdit, titleCompare, userTitle, userAvatar; switch (which) { case 'mode': toEdit = this.state.access; break; case 'want': toEdit = this.state.modeWant; toCompare = this.state.modeGiven; if (this.state.owner) { toSkip = 'O'; } else { toSkip = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.AccessMode.encode(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.AccessMode.diff('ASDO', this.state.modeGiven)); if (this.state.channel) { toSkip += 'W'; } } titleEdit = formatMessage(messages.perm_want); titleCompare = formatMessage(messages.perm_given); break; case 'given': toEdit = this.state.modeGiven2; toCompare = this.state.modeWant2; toSkip = this.state.groupTopic ? this.state.owner ? '' : 'O' : 'ASDO'; titleEdit = formatMessage(messages.perm_given); titleCompare = formatMessage(messages.perm_want); break; case 'auth': toEdit = this.state.auth; toSkip = 'O'; break; case 'anon': toEdit = this.state.anon; toSkip = 'O'; break; case 'user': { const topic = this.props.tinode.getTopic(this.props.topic); if (!topic) { return; } const user = topic.subscriber(uid); if (!user || !user.acs) { return; } toEdit = user.acs.getGiven(); toCompare = user.acs.getWant(); toSkip = this.state.owner ? '' : 'O'; titleEdit = formatMessage(messages.perm_given); titleCompare = formatMessage(messages.perm_want); if (user.public) { userTitle = user.public.fn; userAvatar = user.public.photo; } break; } default: console.error("Unknown permission editing mode '" + which + "'"); return; } this.setState({ userPermissionsEdited: uid, userPermissionsTitle: userTitle, userPermissionsAvatar: userAvatar, editedPermissions: toEdit, immutablePermissions: toCompare, editedPermissionsTitle: titleEdit, immutablePermissionsTitle: titleCompare, editedPermissionsSkipped: toSkip }); this.props.onNavigate(`perm/${which}`); } handleShowAddMembers(e) { e.preventDefault(); this.props.onInitFind(); this.props.onNavigate('members'); } handleMemberUpdateRequest(members, added, removed) { this.props.onMemberUpdateRequest(this.props.topic, added, removed); this.props.onNavigate('info'); } handleMemberSelected(uid) { this.setState({ selectedContact: uid }); } handleBackNavigate() { const args = (this.props.panel || 'info').split('/'); if (args[0] == 'info') { this.props.onNavigate(null); } else if (args[0] == 'perm') { if (args[1] == 'user') { this.props.onNavigate('info'); } else { this.props.onNavigate('security'); } } else { this.props.onNavigate('info'); } } handleContextMenu(params) { const { formatMessage } = this.props.intl; const topic = this.props.tinode.getTopic(this.props.topic); if (!topic) { return; } const user = topic.subscriber(params.topicName); if (!user || !user.acs) { return; } const isMe = this.props.tinode.isMe(params.topicName); const menuItems = [{ title: formatMessage(messages.edit_permissions), handler: _ => this.handleLaunchPermissionsEditor(isMe ? 'want' : 'user', params.topicName) }]; if (!isMe) { menuItems.push('member_delete'); } menuItems.push(user.acs.isMuted() ? 'member_unmute' : 'member_mute'); if (!isMe) { menuItems.push(user.acs.isJoiner() ? 'member_block' : 'member_unblock'); } this.props.showContextMenu({ topicName: this.props.topic, x: params.x, y: params.y, user: params.topicName }, menuItems); } render() { const args = (this.props.panel || 'info').split('/'); const view = args[0]; args.shift(); const { formatMessage } = this.props.intl; const panelTitle = formatMessage((view == 'perm' ? messages['perm_' + args[0]] : messages[view]) || messages['info']); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "info-view" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "caption-panel", id: "info-caption-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-title", id: "info-title" }, panelTitle), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_menu_cancel_jsx__WEBPACK_IMPORTED_MODULE_9__["default"], { onCancel: this.handleBackNavigate }))), this.props.displayMobile ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_error_panel_jsx__WEBPACK_IMPORTED_MODULE_7__["default"], { level: this.props.errorLevel, text: this.props.errorText, onClearError: this.props.onError }) : null, view == 'members' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_group_manager_jsx__WEBPACK_IMPORTED_MODULE_8__["default"], { tinode: this.props.tinode, members: this.state.contactList, requiredMember: this.props.myUserId, keepInitialMembers: !this.state.admin && !this.state.owner, myUserId: this.props.myUserId, contacts: this.props.searchableContacts, onCancel: this.handleBackNavigate, onSubmit: this.handleMemberUpdateRequest }) : view == 'perm' && args.length > 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_permissions_editor_jsx__WEBPACK_IMPORTED_MODULE_10__["default"], { tinode: this.props.tinode, mode: this.state.editedPermissions, compare: this.state.immutablePermissions, skip: this.state.editedPermissionsSkipped, modeTitle: this.state.editedPermissionsTitle, compareTitle: this.state.immutablePermissionsTitle, userTitle: this.state.userPermissionsTitle, item: this.state.userPermissionsEdited, userAvatar: this.state.userPermissionsAvatar, onSubmit: mode => this.handlePermissionsChanged(args[0], mode), onCancel: this.handleBackNavigate }) : view == 'general' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_topic_common_view_jsx__WEBPACK_IMPORTED_MODULE_11__["default"], { tinode: this.props.tinode, topic: this.props.topic, reqCredMethod: this.props.reqCredMethod, onCredAdd: this.props.onCredAdd, onUpdateTagsRequest: this.props.onTopicTagsUpdateRequest, onCredConfirm: this.props.onCredConfirm, onCredDelete: this.props.onCredDelete, onUpdateTopicDesc: this.props.onTopicDescUpdateRequest, onError: this.props.onError }) : view == 'security' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_topic_security_jsx__WEBPACK_IMPORTED_MODULE_12__["default"], { topic: this.props.topic, owner: this.state.owner, admin: this.state.admin, sharer: this.state.sharer, deleter: this.state.deleter, muted: this.state.muted, groupTopic: this.state.groupTopic, channel: this.state.channel, access: this.state.access, modeGiven: this.state.modeGiven, modeWant: this.state.modeWant, modeGiven2: this.state.modeGiven2, modeWant2: this.state.modeWant2, auth: this.state.auth, anon: this.state.anon, onShowAlert: this.props.onShowAlert, onDeleteMessages: this.props.onDeleteMessages, onLeaveTopic: this.props.onLeaveTopic, onBlockTopic: this.props.onBlockTopic, onReportTopic: this.props.onReportTopic, onLaunchPermissionsEditor: this.handleLaunchPermissionsEditor, onNavigate: this.props.onNavigate }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "info-view-content", className: "scrollable-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "flat-button float-right", onClick: e => { e.preventDefault(); this.props.onNavigate('general'); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "edit"), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_edit", defaultMessage: [{ "type": 0, "value": "Edit" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("center", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, avatar: this.state.avatar, readOnly: true, uid: this.props.topic, title: this.state.fullName })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_topic_name", defaultMessage: [{ "type": 0, "value": "Name" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "large ellipsized" }, this.state.fullName, this.state.channel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { src: "/img/channel.png", className: "channel", alt: "channel" }) : null)), this.state.private ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_private", defaultMessage: [{ "type": 0, "value": "Private comment" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "large ellipsized" }, this.state.private)) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_user_id", defaultMessage: [{ "type": 0, "value": "ID:" }] })), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", null, this.state.address)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_badge_list_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { trustedBadges: this.state.trustedBadges })), this.state.description ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_description", defaultMessage: [{ "type": 0, "value": "Description" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, this.state.description)) : null), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_muting_topic", defaultMessage: [{ "type": 0, "value": "Muted:" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { name: "P", checked: this.state.muted, onChange: this.handleMuted })), this.state.archived ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_unarchive_topic", defaultMessage: [{ "type": 0, "value": "Archived:" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { name: "archived", checked: true, onChange: this.handleUnarchive })) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "flat-button", onClick: e => { e.preventDefault(); this.props.onNavigate('security'); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "security"), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_security", defaultMessage: [{ "type": 0, "value": "Security" }] }))), this.state.groupTopic && this.state.sharer ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_group_members", defaultMessage: [{ "type": 0, "value": "Group members:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "flat-button", onClick: this.handleShowAddMembers }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "person_add"), " \xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_add_members", defaultMessage: [{ "type": 0, "value": "Add members" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "group_has_no_members", defaultMessage: [{ "type": 0, "value": "No members" }] }, no_members => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_contact_list_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], { tinode: this.props.tinode, contacts: this.state.contactList, myUserId: this.props.myUserId, emptyListMessage: no_members, topicSelected: this.state.selectedContact, showOnline: false, showUnread: false, showMode: true, noScroll: true, onTopicSelected: this.handleMemberSelected, showContextMenu: this.state.admin ? this.handleContextMenu : false }))) : null)); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(InfoView)); /***/ }), /***/ "./src/views/login-view.jsx": /*!**********************************!*\ !*** ./src/views/login-view.jsx ***! \**********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ LoginView) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/checkbox.jsx */ "./src/widgets/checkbox.jsx"); /* harmony import */ var _widgets_visible_password_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/visible-password.jsx */ "./src/widgets/visible-password.jsx"); class LoginView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { login: props.login, password: '', hostName: props.serverAddress, saveToken: props.persist }; this.handleLoginChange = this.handleLoginChange.bind(this); this.handlePasswordChange = this.handlePasswordChange.bind(this); this.handleToggleSaveToken = this.handleToggleSaveToken.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleLoginChange(e) { this.setState({ login: e.target.value }); } handlePasswordChange(e) { this.setState({ password: e.target.value }); } handleToggleSaveToken() { this.props.onPersistenceChange(!this.state.saveToken); this.setState({ saveToken: !this.state.saveToken }); } handleSubmit(e) { e.preventDefault(); this.props.onLogin(this.state.login.trim(), this.state.password.trim()); } render() { let submitClasses = 'primary'; if (this.props.disabled) { submitClasses += ' disabled'; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("form", { id: "login-form", onSubmit: this.handleSubmit }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "login_prompt", defaultMessage: [{ "type": 0, "value": "Login" }] }, login_prompt => react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", id: "inputLogin", placeholder: login_prompt, autoComplete: "username", autoCorrect: "off", autoCapitalize: "none", value: this.state.login, onChange: this.handleLoginChange, required: true, autoFocus: true })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "password_prompt", defaultMessage: [{ "type": 0, "value": "Password" }] }, password_prompt => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_visible_password_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { type: "password", id: "inputPassword", placeholder: password_prompt, autoComplete: "current-password", value: this.state.password, onChange: this.handlePasswordChange, required: true })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { id: "save-token", name: "save-token", checked: this.state.saveToken, onChange: this.handleToggleSaveToken }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { htmlFor: "save-token" }, "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "stay_logged_in", defaultMessage: [{ "type": 0, "value": "Stay logged in" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#reset" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "forgot_password_link", defaultMessage: [{ "type": 0, "value": "Forgot password?" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "dialog-buttons" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: submitClasses, type: "submit" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_sign_in", defaultMessage: [{ "type": 0, "value": "Sign in" }] })))); } } ; /***/ }), /***/ "./src/views/logo-view.jsx": /*!*********************************!*\ !*** ./src/views/logo-view.jsx ***! \*********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ LogoView) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); class LogoView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { const version = _config_js__WEBPACK_IMPORTED_MODULE_3__.APP_NAME + ' (' + tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.getLibrary() + ')'; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "dummy-view" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "https://github.com/tinode/chat/" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { id: "logo", alt: "logo", src: "img/logo.svg" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("h2", null, "Tinode Web")), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("p", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_client", defaultMessage: [{ "type": 0, "value": "Client:" }] }), " ", version), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("p", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_server", defaultMessage: [{ "type": 0, "value": "Server:" }] }), " ", this.props.serverVersion, " (", this.props.serverAddress, ")"))); } } ; /***/ }), /***/ "./src/views/messages-view.jsx": /*!*************************************!*\ !*** ./src/views/messages-view.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _widgets_call_panel_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/call-panel.jsx */ "./src/widgets/call-panel.jsx"); /* harmony import */ var _widgets_chat_message_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../widgets/chat-message.jsx */ "./src/widgets/chat-message.jsx"); /* harmony import */ var _widgets_contact_badges_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../widgets/contact-badges.jsx */ "./src/widgets/contact-badges.jsx"); /* harmony import */ var _widgets_doc_preview_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../widgets/doc-preview.jsx */ "./src/widgets/doc-preview.jsx"); /* harmony import */ var _widgets_error_panel_jsx__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../widgets/error-panel.jsx */ "./src/widgets/error-panel.jsx"); /* harmony import */ var _widgets_group_subs_jsx__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../widgets/group-subs.jsx */ "./src/widgets/group-subs.jsx"); /* harmony import */ var _widgets_image_preview_jsx__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../widgets/image-preview.jsx */ "./src/widgets/image-preview.jsx"); /* harmony import */ var _widgets_invitation_jsx__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../widgets/invitation.jsx */ "./src/widgets/invitation.jsx"); /* harmony import */ var _widgets_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../widgets/letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _widgets_load_spinner_jsx__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../widgets/load-spinner.jsx */ "./src/widgets/load-spinner.jsx"); /* harmony import */ var _logo_view_jsx__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./logo-view.jsx */ "./src/views/logo-view.jsx"); /* harmony import */ var _widgets_meta_message_jsx__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../widgets/meta-message.jsx */ "./src/widgets/meta-message.jsx"); /* harmony import */ var _widgets_pinned_messages_jsx__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../widgets/pinned-messages.jsx */ "./src/widgets/pinned-messages.jsx"); /* harmony import */ var _widgets_send_message_jsx__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../widgets/send-message.jsx */ "./src/widgets/send-message.jsx"); /* harmony import */ var _widgets_vc_panel_jsx__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../widgets/vc-panel.jsx */ "./src/widgets/vc-panel.jsx"); /* harmony import */ var _widgets_video_preview_jsx__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../widgets/video-preview.jsx */ "./src/widgets/video-preview.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ../constants.js */ "./src/constants.js"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js"); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); const NOTIFICATION_EXEC_INTERVAL = 300; const SHOW_GO_TO_LAST_DIST = 100; const FETCH_PAGE_TRIGGER = 40; const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ online_now: { id: "online_now", defaultMessage: [{ "type": 0, "value": "online now" }] }, last_seen: { id: "last_seen_timestamp", defaultMessage: [{ "type": 0, "value": "Last seen" }] }, not_found: { id: "title_not_found", defaultMessage: [{ "type": 0, "value": "Not found" }] }, channel: { id: "channel", defaultMessage: [{ "type": 0, "value": "channel" }] }, file_attachment_too_large: { id: "file_attachment_too_large", defaultMessage: [{ "type": 0, "value": "The file size " }, { "type": 1, "value": "size" }, { "type": 0, "value": " exceeds the " }, { "type": 1, "value": "limit" }, { "type": 0, "value": " limit." }] }, invalid_content: { id: "invalid_content", defaultMessage: [{ "type": 0, "value": "invalid content" }] }, editing_message: { id: "editing_message", defaultMessage: [{ "type": 0, "value": "Editing" }] }, drag_file: { id: "drag_file", defaultMessage: [{ "type": 0, "value": "Drag file here" }] } }); function isUnconfirmed(acs) { if (acs) { const ex = acs.getExcessive() || ''; return acs.isJoiner('given') && (ex.includes('R') || ex.includes('W')); } return false; } function isPeerRestricted(acs) { if (acs) { const ms = acs.getMissing() || ''; return acs.isJoiner('want') && (ms.includes('R') || ms.includes('W')); } return false; } function shouldPresentCallPanel(callState) { return callState == _constants_js__WEBPACK_IMPORTED_MODULE_20__.CALL_STATE_OUTGOING_INITATED || callState == _constants_js__WEBPACK_IMPORTED_MODULE_20__.CALL_STATE_IN_PROGRESS; } class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = MessagesView.getDerivedStateFromProps(props, {}); this.componentSetup = this.componentSetup.bind(this); this.leave = this.leave.bind(this); this.sendMessage = this.sendMessage.bind(this); this.retrySend = this.retrySend.bind(this); this.sendImageAttachment = this.sendImageAttachment.bind(this); this.sendVideoAttachment = this.sendVideoAttachment.bind(this); this.sendFileAttachment = this.sendFileAttachment.bind(this); this.sendAudioAttachment = this.sendAudioAttachment.bind(this); this.sendKeyPress = this.sendKeyPress.bind(this); this.subscribe = this.subscribe.bind(this); this.handleScrollReference = this.handleScrollReference.bind(this); this.mountDnDEvents = this.mountDnDEvents.bind(this); this.handleScrollEvent = this.handleScrollEvent.bind(this); this.handleDescChange = this.handleDescChange.bind(this); this.handleSubsUpdated = this.handleSubsUpdated.bind(this); this.handleMessageUpdate = this.handleMessageUpdate.bind(this); this.handleAuxUpdate = this.handleAuxUpdate.bind(this); this.handleAllMessagesReceived = this.handleAllMessagesReceived.bind(this); this.handleInfoReceipt = this.handleInfoReceipt.bind(this); this.handleExpandMedia = this.handleExpandMedia.bind(this); this.handleClosePreview = this.handleClosePreview.bind(this); this.handleFormResponse = this.handleFormResponse.bind(this); this.handleContextClick = this.handleContextClick.bind(this); this.handleShowMessageContextMenu = this.handleShowMessageContextMenu.bind(this); this.handleNewChatAcceptance = this.handleNewChatAcceptance.bind(this); this.handleEnablePeer = this.handleEnablePeer.bind(this); this.handleAttachFile = this.handleAttachFile.bind(this); this.handleAttachImageOrVideo = this.handleAttachImageOrVideo.bind(this); this.handleCancelUpload = this.handleCancelUpload.bind(this); this.postReadNotification = this.postReadNotification.bind(this); this.clearNotificationQueue = this.clearNotificationQueue.bind(this); this.goToLatestMessage = this.goToLatestMessage.bind(this); this.handleFileDrop = this.handleFileDrop.bind(this); this.handlePickReply = this.handlePickReply.bind(this); this.handleEditMessage = this.handleEditMessage.bind(this); this.handleCancelReply = this.handleCancelReply.bind(this); this.handleQuoteClick = this.handleQuoteClick.bind(this); this.handleUnpinMessage = this.handleUnpinMessage.bind(this); this.handleCallHangup = this.handleCallHangup.bind(this); this.isDragEnabled = this.isDragEnabled.bind(this); this.handleDragStart = this.handleDragStart.bind(this); this.handleDragIn = this.handleDragIn.bind(this); this.handleDragOut = this.handleDragOut.bind(this); this.handleDrag = this.handleDrag.bind(this); this.handleDrop = this.handleDrop.bind(this); this.chatMessageRefs = []; this.getOrCreateMessageRef = this.getOrCreateMessageRef.bind(this); this.getVisibleMessageRange = this.getVisibleMessageRange.bind(this); this.dragCounter = 0; this.dndRef = null; this.readNotificationQueue = []; this.readNotificationTimer = null; this.keyPressTimer = null; } getOrCreateMessageRef(seqId) { if (this.chatMessageRefs[seqId]) { return this.chatMessageRefs[seqId]; } const ref = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.chatMessageRefs[seqId] = ref; return ref; } getVisibleMessageRange(holderRect) { let min = Number.MAX_SAFE_INTEGER, max = -1; this.chatMessageRefs.forEach((ref, seq) => { if (ref.current) { const { top, bottom, height } = ref.current.getBoundingClientRect(); const visible = top <= holderRect.top ? holderRect.top - top <= height : bottom - holderRect.bottom <= height; if (visible) { min = Math.min(min, seq); max = Math.max(max, seq); } } }); return max >= min ? { min: min, max: max } : { min: 0, max: 0 }; } componentDidMount() { if (this.messagesScroller) { this.messagesScroller.addEventListener('scroll', this.handleScrollEvent); } this.mountDnDEvents(this.dndRef); this.componentSetup({}, {}); } componentWillUnmount() { if (this.messagesScroller) { this.messagesScroller.removeEventListener('scroll', this.handleScrollEvent); } this.clearNotificationQueue(); if (this.dndRef) { this.dndRef.removeEventListener('dragstart', this.handleDragStart); this.dndRef.removeEventListener('dragenter', this.handleDragIn); this.dndRef.removeEventListener('dragleave', this.handleDragOut); this.dndRef.removeEventListener('dragover', this.handleDrag); this.dndRef.removeEventListener('drop', this.handleDrop); } } componentDidUpdate(prevProps, prevState) { if (this.messagesScroller && (prevState.topic != this.state.topic || prevState.maxSeqId != this.state.maxSeqId || prevState.minSeqId != this.state.minSeqId)) { if (this.state.scrollPosition < SHOW_GO_TO_LAST_DIST) { this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight - this.state.scrollPosition - this.messagesScroller.offsetHeight; } } if (!this.props.applicationVisible) { this.clearNotificationQueue(); } else { this.postReadNotification(0); } this.componentSetup(prevProps, prevState); } componentSetup(prevProps, prevState) { const topic = this.props.tinode ? this.props.tinode.getTopic(this.state.topic) : undefined; if (this.state.topic != prevState.topic) { if (prevState.topic && !tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isNewGroupTopicName(prevState.topic)) { this.leave(prevState.topic); if (prevState.rtcPanel) { this.handleCallHangup(prevState.topic, prevProps.callSeq); } } if (topic) { topic.onData = this.handleMessageUpdate; topic.onAllMessagesReceived = this.handleAllMessagesReceived; topic.onInfo = this.handleInfoReceipt; topic.onMetaDesc = this.handleDescChange; topic.onSubsUpdated = this.handleSubsUpdated; topic.onPres = this.handleSubsUpdated; topic.onAuxUpdated = this.handleAuxUpdate; } } if (topic) { if (this.state.topic != prevState.topic || this.props.myUserId && !prevProps.myUserId) { const newTopic = this.props.newTopicParams && this.props.newTopicParams._topicName == this.props.topic; if (topic.isP2PType() && newTopic && !_config_js__WEBPACK_IMPORTED_MODULE_19__.IMMEDIATE_P2P_SUBSCRIPTION) { topic.getMeta(topic.startMetaQuery().withDesc().build()); } else if (this.props.myUserId) { this.subscribe(topic); } } else if (topic.isSubscribed() && this.state.isReader && !prevState.isReader) { topic.getMeta(topic.startMetaQuery().withLaterData().build()); } } } static getDerivedStateFromProps(nextProps, prevState) { let nextState = {}; if (!nextProps.topic) { nextState = { minSeqId: -1, maxSeqId: -1, latestClearId: -1, onlineSubs: [], topic: null, title: '', avatar: null, isVerified: false, isStaff: false, isDangerous: false, deleted: false, docPreview: null, imagePreview: null, imagePostview: null, videoPreview: null, videoPostview: null, rtcPanel: null, typingIndicator: false, scrollPosition: 0, fetchingMessages: false, peerMessagingDisabled: false, channel: false, reply: null, contentToEdit: null, showGoToLastButton: false, dragging: false, pins: [], selectedPin: 0 }; } else if (nextProps.topic != prevState.topic) { const topic = nextProps.tinode.getTopic(nextProps.topic); nextState = { topic: nextProps.topic, deleted: topic._deleted, docPreview: null, imagePreview: null, imagePostview: null, videoPreview: null, videoPostview: null, rtcPanel: null, typingIndicator: false, scrollPosition: 0, fetchingMessages: false, showGoToLastButton: false, contentToEdit: null, dragging: false, selectedPin: 0 }; if (nextProps.forwardMessage) { nextState.reply = { content: nextProps.forwardMessage.preview, seq: null }; } else { nextState.reply = null; } if (topic) { const subs = []; if (nextProps.connected) { topic.subscribers(sub => { if (sub.online && sub.user != nextProps.myUserId) { subs.push(sub); } }); } Object.assign(nextState, { onlineSubs: subs }); if (topic.public) { Object.assign(nextState, { title: topic.public.fn, avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_21__.makeImageUrl)(topic.public.photo) }); } else { Object.assign(nextState, { title: '', avatar: null }); } const peer = topic.p2pPeerDesc(); if (peer) { Object.assign(nextState, { peerMessagingDisabled: isPeerRestricted(peer.acs) }); } else if (prevState.peerMessagingDisabled) { Object.assign(nextState, { peerMessagingDisabled: false }); } Object.assign(nextState, { minSeqId: topic.minMsgSeq(), maxSeqId: topic.maxMsgSeq(), latestClearId: topic.maxClearId(), channel: topic.isChannelType(), pins: (topic.aux('pins') || []).slice() }); if (nextProps.callTopic == topic.name && shouldPresentCallPanel(nextProps.callState)) { nextState.rtcPanel = nextProps.callTopic; } } else { Object.assign(nextState, { minSeqId: -1, maxSeqId: -1, latestClearId: -1, onlineSubs: [], title: '', avatar: null, peerMessagingDisabled: false, channel: false, pins: [] }); } } else { if (nextProps.callTopic == prevState.topic && !prevState.rtcPanel && shouldPresentCallPanel(nextProps.callState)) { nextState.rtcPanel = nextProps.callTopic; } } if (nextProps.acs) { if (nextProps.acs.isWriter() != prevState.isWriter) { nextState.isWriter = !prevState.isWriter; } if (nextProps.acs.isReader() != prevState.isReader) { nextState.isReader = !prevState.isReader; } if (nextProps.acs.isAdmin() != prevState.isAdmin) { nextState.isAdmin = !prevState.isAdmin; } if (!nextProps.acs.isReader('given') != prevState.readingBlocked) { nextState.readingBlocked = !prevState.readingBlocked; } if (nextProps.acs.isSharer() != prevState.isSharer) { nextState.isSharer = !prevState.isSharer; } } else { if (prevState.isWriter) { nextState.isWriter = false; } if (prevState.isReader) { nextState.isReader = false; } if (prevState.isAdmin) { nextState.isAdmin = false; } if (!prevState.readingBlocked) { prevState.readingBlocked = true; } if (prevState.isSharer) { nextState.isSharer = false; } } if (isUnconfirmed(nextProps.acs) == !prevState.unconformed) { nextState.unconfirmed = !prevState.unconformed; } if (!nextProps.connected && prevState.onlineSubs && prevState.onlineSubs.length > 0) { nextState.onlineSubs = []; } return nextState; } subscribe(topic) { if (topic.isSubscribed() || !this.props.ready) { return; } const newTopic = this.props.newTopicParams && this.props.newTopicParams._topicName == this.props.topic; let getQuery = topic.startMetaQuery().withLaterDesc().withLaterSub().withAux(); if (this.state.isReader || newTopic) { getQuery = getQuery.withLaterData(_config_js__WEBPACK_IMPORTED_MODULE_19__.MESSAGES_PAGE); if (this.state.isReader) { getQuery = getQuery.withLaterDel(); } this.setState({ fetchingMessages: true }); } const setQuery = newTopic ? this.props.newTopicParams : undefined; topic.subscribe(getQuery.build(), setQuery).then(ctrl => { if (ctrl.code == 303) { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_22__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_22__["default"].setUrlTopic('', ctrl.params.topic)); return; } if (this.state.topic != ctrl.topic) { this.setState({ topic: ctrl.topic }); } if (this.state.deleted) { this.setState({ deleted: false }); } this.props.onNewTopicCreated(this.props.topic, ctrl.topic); let discard = []; topic.queuedMessages(pub => { if (pub._sending) { return; } if (pub._fatal || pub.head && pub.head.webrtc) { discard.push(pub.seq); return; } if (topic.isSubscribed()) { this.retrySend(pub); } }); if (discard.length > 0) { topic.delMessagesList(discard, true); } }).catch(err => { console.error("Failed subscription to", this.state.topic, err); this.props.onError(err.message, 'err'); const blankState = MessagesView.getDerivedStateFromProps({}, {}); blankState.title = this.props.intl.formatMessage(messages.not_found); this.setState(blankState); }); } leave(oldTopicName) { if (!oldTopicName || !this.props.tinode.isTopicCached(oldTopicName)) { return; } const oldTopic = this.props.tinode.getTopic(oldTopicName); if (oldTopic && oldTopic.isSubscribed()) { oldTopic.leave(false).catch(_ => {}).finally(_ => { this.setState({ fetchingMessages: false }); oldTopic.onData = undefined; oldTopic.onAllMessagesReceived = undefined; oldTopic.onInfo = undefined; oldTopic.onMetaDesc = undefined; oldTopic.onSubsUpdated = undefined; oldTopic.onPres = undefined; oldTopic.onAuxUpdated = undefined; }); } } handleScrollReference(node) { if (node) { node.addEventListener('scroll', this.handleScrollEvent); this.messagesScroller = node; this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight - this.state.scrollPosition - this.messagesScroller.offsetHeight; } } handleScrollEvent(event) { const pos = event.target.scrollHeight - event.target.scrollTop - event.target.offsetHeight; this.setState({ scrollPosition: pos, showGoToLastButton: pos > SHOW_GO_TO_LAST_DIST && pos < this.state.scrollPosition }); if (this.state.fetchingMessages) { return; } if (event.target.scrollTop <= FETCH_PAGE_TRIGGER) { const topic = this.props.tinode.getTopic(this.state.topic); if (topic && topic.isSubscribed()) { const { min, max } = this.getVisibleMessageRange(event.target.getBoundingClientRect()); const gaps = topic.msgHasMoreMessages(min, max, false); if (gaps.length > 0) { this.setState({ fetchingMessages: true }, _ => { topic.getMessagesPage(_config_js__WEBPACK_IMPORTED_MODULE_19__.MESSAGES_PAGE, gaps, min, max).catch(err => this.props.onError(err.message, 'err')).finally(_ => this.setState({ fetchingMessages: false })); }); } } } } mountDnDEvents(dnd) { if (dnd) { dnd.addEventListener('dragstart', this.handleDragStart); dnd.addEventListener('dragenter', this.handleDragIn); dnd.addEventListener('dragleave', this.handleDragOut); dnd.addEventListener('dragover', this.handleDrag); dnd.addEventListener('drop', this.handleDrop); this.dndRef = dnd; } } goToLatestMessage() { this.setState({ scrollPosition: 0 }); if (this.messagesScroller) { this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight - this.messagesScroller.offsetHeight; } } handleDescChange(desc) { if (desc.public) { this.setState({ title: desc.public.fn, avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_21__.makeImageUrl)(desc.public.photo) }); } else { this.setState({ title: '', avatar: null }); } if (desc.acs) { this.setState({ isWriter: desc.acs.isWriter(), isReader: desc.acs.isReader(), isAdmin: desc.acs.isAdmin(), readingBlocked: !desc.acs.isReader('given'), unconfirmed: isUnconfirmed(desc.acs) }); } } postReadNotification(seq) { if (!this.props.applicationVisible) { return; } if (!this.readNotificationTimer) { this.readNotificationTimer = setInterval(_ => { if (this.readNotificationQueue.length == 0) { clearInterval(this.readNotificationTimer); this.readNotificationTimer = null; return; } let seq = -1; while (this.readNotificationQueue.length > 0) { const n = this.readNotificationQueue[0]; if (n.topicName != this.state.topic) { this.readNotificationQueue.shift(); continue; } const now = new Date(); if (n.sendAt <= now) { this.readNotificationQueue.shift(); seq = Math.max(seq, n.seq); } else { break; } } if (seq >= 0) { const topic = this.props.tinode.getTopic(this.state.topic); if (topic) { topic.noteRead(seq); } } }, NOTIFICATION_EXEC_INTERVAL); } const now = new Date(); this.readNotificationQueue.push({ topicName: this.state.topic, seq: seq, sendAt: now.setMilliseconds(now.getMilliseconds() + _config_js__WEBPACK_IMPORTED_MODULE_19__.READ_DELAY) }); } clearNotificationQueue() { this.readNotificationQueue = []; if (this.readNotificationTimer) { clearInterval(this.readNotificationTimer); this.readNotificationTimer = null; } } handleSubsUpdated() { if (this.state.topic) { const subs = []; const topic = this.props.tinode.getTopic(this.state.topic); topic.subscribers(sub => { if (sub.online && sub.user != this.props.myUserId) { subs.push(sub); } }); const newState = { onlineSubs: subs }; const peer = topic.p2pPeerDesc(); if (peer) { Object.assign(newState, { peerMessagingDisabled: isPeerRestricted(peer.acs) }); } else if (this.state.peerMessagingDisabled) { Object.assign(newState, { peerMessagingDisabled: false }); } this.setState(newState); } } handleMessageUpdate(msg) { if (!this.state.topic) { return; } const topic = this.props.tinode.getTopic(this.state.topic); if (!msg) { this.setState({ latestClearId: topic.maxClearId() }); return; } clearTimeout(this.keyPressTimer); this.setState({ maxSeqId: topic.maxMsgSeq(), minSeqId: topic.minMsgSeq(), typingIndicator: false }, _ => { if (topic.isNewMessage(msg.seq)) { if (this.state.scrollPosition > SHOW_GO_TO_LAST_DIST) { this.setState({ showGoToLastButton: true }); } else { this.goToLatestMessage(); } } else { if (this.messagesScroller) { this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight - this.state.scrollPosition - this.messagesScroller.offsetHeight; } } }); const status = topic.msgStatus(msg, true); if (status >= tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_SENT && msg.from != this.props.myUserId) { this.postReadNotification(msg.seq); } } handleAllMessagesReceived(count) { this.setState({ fetchingMessages: false }); if (count > 0) { this.postReadNotification(0); } const topic = this.props.tinode.getTopic(this.state.topic); topic.getPinnedMessages(); } handleAuxUpdate(aux) { const pins = (aux['pins'] || []).slice(); let selectedPin = this.state.selectedPin; if (pins.length > this.state.pins.length) { selectedPin = 0; } else if (selectedPin >= pins.length) { selectedPin = Math.max(0, pins.length - 1); } this.setState({ pins: pins, selectedPin: selectedPin }); } handleInfoReceipt(info) { switch (info.what) { case 'kp': { clearTimeout(this.keyPressTimer); this.keyPressTimer = setTimeout(_ => this.setState({ typingIndicator: false }), _config_js__WEBPACK_IMPORTED_MODULE_19__.KEYPRESS_DELAY + 1000); if (!this.state.typingIndicator) { this.setState({ typingIndicator: true }); } break; } case 'read': case 'recv': this.forceUpdate(); break; default: console.info("Other change in topic: ", info.what); } } handleExpandMedia(content) { if (!content) { return; } if (content.video) { this.setState({ videoPostview: content }); } else { this.setState({ imagePostview: content }); } } handleClosePreview() { if (this.state.imagePreview && this.state.imagePreview.url) { URL.revokeObjectURL(this.state.imagePreview.url); } if (this.state.videoPreview && this.state.videoPreview.url) { URL.revokeObjectURL(this.state.videoPreview.url); } this.setState({ imagePostview: null, imagePreview: null, docPreview: null, videoPreview: null, videoPostview: null }); } handleFormResponse(action, text, data) { if (action == 'pub') { this.sendMessage(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attachJSON(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.parse(text), data)); } else if (action == 'url') { const url = new URL(data.ref); const params = url.searchParams; for (let key in data.resp) { if (data.resp.hasOwnProperty(key)) { params.set(key, data.resp[key]); } } ['name', 'seq'].forEach(key => { if (data[key]) { params.set(key, data[key]); } }); params.set('uid', this.props.myUserId); params.set('topic', this.state.topic); url.search = params; window.open(url, '_blank'); } else { console.info("Unknown action in form", action); } } handleContextClick(e) { e.preventDefault(); e.stopPropagation(); this.props.showContextMenu({ topicName: this.state.topic, y: e.pageY, x: e.pageX }); } handleShowMessageContextMenu(params, messageSpecificMenuItems) { if (params.userFrom == 'chan') { params.userFrom = this.state.topic; params.userName = this.state.title; } params.topicName = this.state.topic; const menuItems = messageSpecificMenuItems || []; const topic = this.props.tinode.getTopic(params.topicName); if (topic) { if (!topic.isChannelType()) { menuItems.push('message_delete'); } const acs = topic.getAccessMode(); if (acs && acs.isDeleter()) { menuItems.push('message_delete_hard'); } } this.props.showContextMenu(params, menuItems); } handleNewChatAcceptance(action) { this.props.onNewChat(this.state.topic, action); } handleEnablePeer(e) { e.preventDefault(); this.props.onChangePermissions(this.state.topic, _config_js__WEBPACK_IMPORTED_MODULE_19__.DEFAULT_P2P_ACCESS_MODE, this.state.topic); } sendKeyPress(audio) { const topic = this.props.tinode.getTopic(this.state.topic); if (topic.isSubscribed()) { if (audio) { topic.noteRecording(true); } else { topic.noteKeyPress(); } } } sendMessage(msg, uploadCompletionPromise, uploader) { let head; if (this.props.forwardMessage) { msg = this.props.forwardMessage.msg; head = this.props.forwardMessage.head; this.handleCancelReply(); } else if (this.state.reply) { if (this.state.reply.editing) { if (msg == this.state.contentToEdit) { this.handleCancelReply(); return; } head = { replace: ':' + this.state.reply.seq }; } else if (this.state.reply.content) { head = { reply: '' + this.state.reply.seq }; if (typeof msg == 'string') { msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.parse(msg); } msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.append(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.sanitizeEntities(this.state.reply.content), msg); } this.handleCancelReply(); } this.props.sendMessage(msg, uploadCompletionPromise, uploader, head); } retrySend(pub) { this.props.sendMessage(pub.content, undefined, undefined, pub.head).then(_ => { const topic = this.props.tinode.getTopic(this.state.topic); topic.delMessagesList([pub.seq], true); }); } sendFileAttachment(file) { const maxInbandAttachmentSize = this.props.tinode.getServerParam('maxMessageSize', _config_js__WEBPACK_IMPORTED_MODULE_19__.MAX_INBAND_ATTACHMENT_SIZE) * 0.75 - 1024 | 0; if (file.size > maxInbandAttachmentSize) { const uploader = this.props.tinode.getLargeFileHelper(); if (!uploader) { this.props.onError(this.props.intl.formatMessage(messages.cannot_initiate_upload)); return; } const uploadCompletionPromise = uploader.upload(file); const msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attachFile(null, { mime: file.type, filename: file.name, size: file.size, urlPromise: uploadCompletionPromise }); this.sendMessage(msg, uploadCompletionPromise, uploader); } else { (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_21__.fileToBase64)(file).then(b64 => this.sendMessage(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attachFile(null, { mime: b64.mime, data: b64.bits, filename: b64.name, size: file.size }))).catch(err => this.props.onError(err.message, 'err')); } } handleAttachFile(file) { const maxExternAttachmentSize = this.props.tinode.getServerParam('maxFileUploadSize', _config_js__WEBPACK_IMPORTED_MODULE_19__.MAX_EXTERN_ATTACHMENT_SIZE); if (file.size > maxExternAttachmentSize) { this.props.onError(this.props.intl.formatMessage(messages.file_attachment_too_large, { size: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_23__.bytesToHumanSize)(file.size), limit: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_23__.bytesToHumanSize)(maxExternAttachmentSize) }), 'err'); } else { this.setState({ docPreview: { file: file, name: file.name, size: file.size, type: file.type } }); } } handleCallHangup(topic, seq) { this.props.onVideoCallClosed(); this.setState({ rtcPanel: null }); this.props.onCallHangup(topic, seq); } sendImageAttachment(caption, blob) { const mime = this.state.imagePreview.mime; const width = this.state.imagePreview.width; const height = this.state.imagePreview.height; const fname = this.state.imagePreview.filename; const maxInbandAttachmentSize = this.props.tinode.getServerParam('maxMessageSize', _config_js__WEBPACK_IMPORTED_MODULE_19__.MAX_INBAND_ATTACHMENT_SIZE) * 0.75 - 1024 | 0; if (blob.size > maxInbandAttachmentSize) { const uploader = this.props.tinode.getLargeFileHelper(); if (!uploader) { this.props.onError(this.props.intl.formatMessage(messages.cannot_initiate_upload)); return; } const uploadCompletionPromise = uploader.upload(blob); (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_21__.imageScaled)(blob, _config_js__WEBPACK_IMPORTED_MODULE_19__.IMAGE_PREVIEW_DIM, _config_js__WEBPACK_IMPORTED_MODULE_19__.IMAGE_PREVIEW_DIM, -1, false).then(scaled => (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_21__.blobToBase64)(scaled.blob)).then(b64 => { let msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.insertImage(null, 0, { mime: mime, _tempPreview: b64.bits, bits: b64.bits, width: width, height: height, filename: fname, size: blob.size, urlPromise: uploadCompletionPromise }); if (caption) { msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.appendLineBreak(msg); msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.append(msg, tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.parse(caption)); } this.sendMessage(msg, uploadCompletionPromise, uploader); }).catch(err => this.props.onError(err, 'err')); return; } (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_21__.blobToBase64)(blob).then(b64 => { let msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.insertImage(null, 0, { mime: b64.mime, bits: b64.bits, width: width, height: height, filename: fname, size: blob.size }); if (caption) { msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.appendLineBreak(msg); msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.append(msg, tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.parse(caption)); } this.sendMessage(msg); }); } sendVideoAttachment(caption, videoBlob, previewBlob, params) { const width = params.width; const height = params.height; const maxInbandAttachmentSize = this.props.tinode.getServerParam('maxMessageSize', _config_js__WEBPACK_IMPORTED_MODULE_19__.MAX_INBAND_ATTACHMENT_SIZE) * 0.75 - 1024 | 0; const uploads = []; let uploader; if (videoBlob.size + previewBlob.size > maxInbandAttachmentSize) { uploader = this.props.tinode.getLargeFileHelper(); if (!uploader) { this.props.onError(this.props.intl.formatMessage(messages.cannot_initiate_upload)); return; } uploads[0] = videoBlob.size > maxInbandAttachmentSize * 0.675 ? uploader.upload(videoBlob) : null; uploads[1] = previewBlob.size > maxInbandAttachmentSize * 0.275 ? uploader.upload(previewBlob) : null; } if (uploads.length == 0) { Promise.all([(0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_21__.blobToBase64)(videoBlob), (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_21__.blobToBase64)(previewBlob)]).then(b64s => { const [v64, i64] = b64s; let msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.insertVideo(null, 0, { mime: v64.mime, bits: v64.bits, preview: i64.bits, premime: i64.mime, width: width, height: height, duration: params.duration, filename: params.name, size: videoBlob.size }); if (caption) { msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.appendLineBreak(msg); msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.append(msg, tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.parse(caption)); } this.sendMessage(msg); }); return; } const uploadCompletionPromise = Promise.all(uploads); const b64conv = []; b64conv[0] = uploads[0] ? null : (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_21__.blobToBase64)(videoBlob); b64conv[1] = uploads[1] ? null : (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_21__.imageScaled)(previewBlob, _config_js__WEBPACK_IMPORTED_MODULE_19__.MAX_IMAGE_DIM, _config_js__WEBPACK_IMPORTED_MODULE_19__.MAX_IMAGE_DIM, -1, false).then(scaled => (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_21__.blobToBase64)(scaled.blob)); b64conv[2] = (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_21__.imageScaled)(previewBlob, _config_js__WEBPACK_IMPORTED_MODULE_19__.VIDEO_PREVIEW_DIM, _config_js__WEBPACK_IMPORTED_MODULE_19__.VIDEO_PREVIEW_DIM, -1, false).then(scaled => (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_21__.blobToBase64)(scaled.blob)); Promise.all(b64conv).then(b64s => { const [video, img, preview] = b64s; let msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.insertVideo(null, 0, { mime: params.mime, bits: video ? video.bits : null, _tempPreview: preview.bits, preview: img ? img.bits : preview.bits, premime: img ? img.mime : preview.mime, width: width, height: height, duration: params.duration, filename: params.name, size: videoBlob.size, urlPromise: uploadCompletionPromise }); if (caption) { msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.appendLineBreak(msg); msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.append(msg, tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.parse(caption)); } this.sendMessage(msg, uploadCompletionPromise, uploader); }).catch(err => this.props.onError(err.message, 'err')); } handleAttachImageOrVideo(file) { const maxExternAttachmentSize = this.props.tinode.getServerParam('maxFileUploadSize', _config_js__WEBPACK_IMPORTED_MODULE_19__.MAX_EXTERN_ATTACHMENT_SIZE); if (file.type.startsWith('video/')) { this.setState({ videoPreview: { url: URL.createObjectURL(file), blob: file, filename: file.name, size: file.size, mime: file.type } }); return; } (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_21__.imageScaled)(file, _config_js__WEBPACK_IMPORTED_MODULE_19__.MAX_IMAGE_DIM, _config_js__WEBPACK_IMPORTED_MODULE_19__.MAX_IMAGE_DIM, maxExternAttachmentSize, false).then(scaled => { this.setState({ imagePreview: { url: URL.createObjectURL(scaled.blob), blob: scaled.blob, filename: scaled.name, width: scaled.width, height: scaled.height, size: scaled.blob.size, mime: scaled.mime } }); }).catch(err => { this.props.onError(err.message, 'err'); }); } handleFileDrop(files) { if (!files || files.length == 0) { return; } const file = files[0]; if (file.type && file.type.startsWith('image/')) { this.handleAttachImageOrVideo(file); } else { this.handleAttachFile(file); } } sendAudioAttachment(url, preview, duration) { fetch(url).then(result => result.blob()).then(blob => { const maxInbandAttachmentSize = this.props.tinode.getServerParam('maxMessageSize', _config_js__WEBPACK_IMPORTED_MODULE_19__.MAX_INBAND_ATTACHMENT_SIZE) * 0.75 - 1024; if (blob.size > maxInbandAttachmentSize) { const uploader = this.props.tinode.getLargeFileHelper(); if (!uploader) { this.props.onError(this.props.intl.formatMessage(messages.cannot_initiate_upload)); return; } const uploadCompletionPromise = uploader.upload(blob); const msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.appendAudio(null, { mime: blob.type, size: blob.size, duration: duration, preview: preview, urlPromise: uploadCompletionPromise }); this.sendMessage(msg, uploadCompletionPromise, uploader); } else { (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_21__.blobToBase64)(blob).then(b64 => { this.sendMessage(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.appendAudio(null, { mime: b64.mime, bits: b64.bits, size: blob.size, duration: duration, preview: preview })); }); } }).catch(err => { this.props.onError(err.message, 'err'); }); ; } handleCancelUpload(seq, uploader) { const topic = this.props.tinode.getTopic(this.state.topic); const found = topic.findMessage(seq); if (found) { found._cancelled = true; } uploader.cancel(); } handlePickReply(seq, content, senderId, senderName) { if (!seq || !content) { this.setState({ reply: null }); return; } content = typeof content == 'string' ? tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.init(content) : content; if (tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isValid(content)) { content = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.replyContent(content, _config_js__WEBPACK_IMPORTED_MODULE_19__.QUOTED_REPLY_LENGTH); } else { content = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.append(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.init('\u26A0 '), tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.wrapInto(this.props.intl.formatMessage(messages.invalid_content), 'EM')); } this.setState({ reply: { content: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.quote(senderName, senderId, content), seq: seq } }); this.props.onCancelForwardMessage(); } handleEditMessage(seq, content) { if (!seq || !content) { this.setState({ reply: null }); return; } content = typeof content == 'string' ? tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.init(content) : content; const editable = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.toMarkdown(content); if (tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isValid(content)) { content = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.replyContent(content, _config_js__WEBPACK_IMPORTED_MODULE_19__.EDIT_PREVIEW_LENGTH); } else { content = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.append(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.init('\u26A0 '), tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.wrapInto(this.props.intl.formatMessage(messages.invalid_content), 'EM')); } this.setState({ reply: { content: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.quote(this.props.intl.formatMessage(messages.editing_message), null, content), seq: seq, editing: true }, contentToEdit: editable }); this.props.onCancelForwardMessage(); } handleCancelReply() { this.setState({ reply: null, contentToEdit: null }); this.props.onCancelForwardMessage(); } handleQuoteClick(replyToSeq) { const ref = this.getOrCreateMessageRef(replyToSeq); if (ref && ref.current) { ref.current.scrollIntoView({ block: "center", behavior: "smooth" }); ref.current.classList.add('flash'); setTimeout(_ => { ref.current.classList.remove('flash'); }, 1000); } else { console.error("Unresolved message ref", replyToSeq); } } handleUnpinMessage(seq) { const topic = this.props.tinode.getTopic(this.state.topic); topic.pinMessage(seq, false); } isDragEnabled() { return this.state.isWriter && !this.state.unconfirmed && !this.props.forwardMessage && !this.state.peerMessagingDisabled; } handleDragStart(e) { e.preventDefault(); e.stopPropagation(); e.dataTransfer.clearData(); } handleDragIn(e) { e.preventDefault(); e.stopPropagation(); this.dragCounter++; if (e.dataTransfer.items && e.dataTransfer.items.length > 0) { this.setState({ dragging: true }); } } handleDragOut(e) { e.preventDefault(); e.stopPropagation(); this.dragCounter--; if (this.dragCounter <= 0) { this.setState({ dragging: false }); } } handleDrag(e) { e.preventDefault(); e.stopPropagation(); } handleDrop(e) { e.preventDefault(); e.stopPropagation(); this.setState({ dragging: false }); if (this.isDragEnabled() && e.dataTransfer.files && e.dataTransfer.files.length > 0) { this.handleFileDrop(e.dataTransfer.files); this.dragCounter = 0; } } render() { const { formatMessage } = this.props.intl; let component; if (!this.state.topic) { component = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_logo_view_jsx__WEBPACK_IMPORTED_MODULE_13__["default"], { serverVersion: this.props.serverVersion, serverAddress: this.props.serverAddress }); } else { let component2; if (this.state.imagePreview) { component2 = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_image_preview_jsx__WEBPACK_IMPORTED_MODULE_9__["default"], { content: this.state.imagePreview, tinode: this.props.tinode, reply: this.state.reply, onCancelReply: this.handleCancelReply, onClose: this.handleClosePreview, onSendMessage: this.sendImageAttachment }); } else if (this.state.videoPreview) { component2 = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_video_preview_jsx__WEBPACK_IMPORTED_MODULE_18__["default"], { content: this.state.videoPreview, tinode: this.props.tinode, reply: this.state.reply, onError: this.props.onError, onCancelReply: this.handleCancelReply, onClose: this.handleClosePreview, onSendMessage: this.sendVideoAttachment }); } else if (this.state.imagePostview) { component2 = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_image_preview_jsx__WEBPACK_IMPORTED_MODULE_9__["default"], { content: this.state.imagePostview, onClose: this.handleClosePreview }); } else if (this.state.videoPostview) { component2 = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_video_preview_jsx__WEBPACK_IMPORTED_MODULE_18__["default"], { content: this.state.videoPostview, tinode: this.props.tinode, onError: this.props.onError, onClose: this.handleClosePreview }); } else if (this.state.docPreview) { component2 = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_doc_preview_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], { content: this.state.docPreview, tinode: this.props.tinode, reply: this.state.reply, onCancelReply: this.handleCancelReply, onClose: this.handleClosePreview, onSendMessage: this.sendFileAttachment }); } else if (this.state.rtcPanel) { if (tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isP2PTopicName(this.state.rtcPanel)) { component2 = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_call_panel_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { topic: this.state.topic, seq: this.props.callSeq, callState: this.props.callState, callAudioOnly: this.props.callAudioOnly, tinode: this.props.tinode, title: this.state.title, avatar: this.state.avatar || true, onError: this.props.onError, onHangup: this.handleCallHangup, onInvite: this.props.onCallInvite, onSendOffer: this.props.onCallSendOffer, onIceCandidate: this.props.onCallIceCandidate, onSendAnswer: this.props.onCallSendAnswer }); } else { component2 = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_vc_panel_jsx__WEBPACK_IMPORTED_MODULE_17__["default"], { topic: this.state.topic, seq: this.props.callSeq, callState: this.props.callState, callAudioOnly: this.props.callAudioOnly, tinode: this.props.tinode, title: this.state.title, avatar: this.state.avatar || true, myUid: this.props.myUserId, onError: this.props.onError, onHangup: this.handleCallHangup, onCreateCall: this.props.onCallInvite, onJoin: this.props.onVCJoin }); } } else { const topic = this.props.tinode.getTopic(this.state.topic); const isChannel = topic.isChannelType(); const groupTopic = topic.isGroupType() && !isChannel; const icon_badges = []; if (topic.trusted) { if (topic.trusted.verified) { icon_badges.push({ icon: 'verified', color: 'badge-inv' }); } if (topic.trusted.staff) { icon_badges.push({ icon: 'staff', color: 'badge-inv' }); } if (topic.trusted.danger) { icon_badges.push({ icon: 'dangerous', color: 'badge-inv' }); } } const pinnedMessages = []; this.state.pins.forEach(seq => pinnedMessages.push(topic.latestMsgVersion(seq) || topic.findMessage(seq))); const messageNodes = []; let previousFrom = null; let prevDate = null; let chatBoxClass = null; topic.messages((msg, prev, next, i) => { let nextFrom = next ? next.from || 'chan' : null; let sequence = 'single'; let thisFrom = msg.from || 'chan'; if (thisFrom == previousFrom) { if (thisFrom == nextFrom) { sequence = 'middle'; } else { sequence = 'last'; } } else if (thisFrom == nextFrom) { sequence = 'first'; } previousFrom = thisFrom; const isReply = !(thisFrom == this.props.myUserId); const deliveryStatus = topic.msgStatus(msg, true); let userFrom = thisFrom, userName, userAvatar; const user = topic.userDesc(thisFrom); if (user && user.public) { userName = user.public.fn; userAvatar = (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_21__.makeImageUrl)(user.public.photo); } chatBoxClass = groupTopic ? 'chat-box group' : 'chat-box'; const ref = this.getOrCreateMessageRef(msg.seq); let replyToSeq = msg.head ? parseInt(msg.head.reply) : null; if (!replyToSeq || isNaN(replyToSeq)) { replyToSeq = null; } if (msg.hi) { messageNodes.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_meta_message_jsx__WEBPACK_IMPORTED_MODULE_14__["default"], { deleted: true, key: msg.seq })); } else { const thisDate = new Date(msg.ts); if (!prevDate || prevDate.toDateString() != thisDate.toDateString()) { messageNodes.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_meta_message_jsx__WEBPACK_IMPORTED_MODULE_14__["default"], { date: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_23__.relativeDateFormat)(msg.ts), locale: this.props.intl.locale, key: 'date-' + msg.seq })); prevDate = thisDate; } messageNodes.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_chat_message_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { tinode: this.props.tinode, topic: this.state.topic, content: msg.content, mimeType: msg.head && msg.head.mime, replyToSeq: replyToSeq, edited: msg.head && !msg.head.webrtc && msg.head.replace, timestamp: msg.ts, response: isReply, seq: msg.seq, isGroup: groupTopic, isChan: this.state.channel, userFrom: userFrom, userName: userName, userAvatar: userAvatar, sequence: sequence, received: deliveryStatus, uploader: msg._uploader, userIsWriter: this.state.isWriter, userIsAdmin: this.state.isAdmin, pinned: this.state.pins.includes(msg.seq), viewportWidth: this.props.viewportWidth, showContextMenu: this.handleShowMessageContextMenu, onExpandMedia: this.handleExpandMedia, onFormResponse: this.handleFormResponse, onCancelUpload: this.handleCancelUpload, pickReply: this.handlePickReply, editMessage: this.handleEditMessage, onQuoteClick: this.handleQuoteClick, onAcceptCall: this.props.onAcceptCall, onError: this.props.onError, ref: ref, key: msg.seq })); } }); let lastSeen = null; if (isChannel) { lastSeen = formatMessage(messages.channel); } else { const cont = this.props.tinode.getMeTopic().getContact(this.state.topic); if (cont && tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isP2PTopicName(cont.topic)) { if (cont.online) { lastSeen = formatMessage(messages.online_now); } else if (cont.seen) { lastSeen = formatMessage(messages.last_seen) + ": " + (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_23__.shortDateFormat)(cont.seen.when, this.props.intl.locale); } } } const avatar = this.state.avatar || true; const online = this.state.deleted ? null : this.props.online ? 'online' + (this.state.typingIndicator ? ' typing' : '') : 'offline'; const titleClass = 'panel-title' + (this.state.deleted ? ' deleted' : ''); let messagesComponent = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "messages-container" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: 'action-button' + (this.state.showGoToLastButton ? '' : ' hidden'), onClick: this.goToLatestMessage }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "arrow_downward")), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "messages-panel", ref: this.handleScrollReference }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("ul", { id: "scroller", className: chatBoxClass }, messageNodes)), !this.state.isReader ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "write-only-background" }, this.state.readingBlocked ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "write-only-note" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "messages_not_readable", defaultMessage: [{ "type": 0, "value": "no access to messages" }] })) : null) : null), this.state.peerMessagingDisabled && !this.state.unconfirmed ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "peer-messaging-disabled-note" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons secondary" }, "block"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "peers_messaging_disabled", defaultMessage: [{ "type": 0, "value": "Peer's messaging is disabled." }] }), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleEnablePeer }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "enable_peers_messaging", defaultMessage: [{ "type": 0, "value": "Enable" }] })), ".") : null, this.state.unconfirmed ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_invitation_jsx__WEBPACK_IMPORTED_MODULE_10__["default"], { onAction: this.handleNewChatAcceptance }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_send_message_jsx__WEBPACK_IMPORTED_MODULE_16__["default"], { tinode: this.props.tinode, topicName: this.state.topic, noInput: !!this.props.forwardMessage, disabled: !this.state.isWriter || this.state.deleted, reply: this.state.reply, initMessage: this.state.contentToEdit, onKeyPress: this.sendKeyPress, onRecordingProgress: this.sendKeyPress, onSendMessage: this.sendMessage, onAttachFile: this.props.forwardMessage ? null : this.handleAttachFile, onAttachImage: this.props.forwardMessage ? null : this.handleAttachImageOrVideo, onAttachAudio: this.props.forwardMessage ? null : this.sendAudioAttachment, onError: this.props.onError, onQuoteClick: this.handleQuoteClick, onCancelReply: this.handleCancelReply })); component2 = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "topic-caption-panel", className: "caption-panel" }, this.props.displayMobile ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", id: "hide-message-view", onClick: e => { e.preventDefault(); this.props.onHideMessagesView(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "arrow_back")) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "avatar-box" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_11__["default"], { tinode: this.props.tinode, avatar: avatar, topic: this.state.topic, title: this.state.title, deleted: this.state.deleted }), !isChannel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: online }) : null), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "topic-title-group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "topic-title", className: titleClass }, this.state.title || react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "unnamed_topic", defaultMessage: [{ "type": 0, "value": "Unnamed" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_contact_badges_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { badges: icon_badges })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "topic-last-seen" }, lastSeen)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { style: { marginLeft: 'auto' } }), !this.props.displayMobile ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_pinned_messages_jsx__WEBPACK_IMPORTED_MODULE_15__["default"], { tinode: this.props.tinode, messages: pinnedMessages, selected: this.state.selectedPin, isAdmin: this.state.isAdmin, setSelected: index => this.setState({ selectedPin: index }), onSelected: this.handleQuoteClick, onCancel: this.handleUnpinMessage }) : null, groupTopic ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_group_subs_jsx__WEBPACK_IMPORTED_MODULE_8__["default"], { tinode: this.props.tinode, subscribers: this.state.onlineSubs }) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleContextClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "more_vert")))), this.props.displayMobile ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_pinned_messages_jsx__WEBPACK_IMPORTED_MODULE_15__["default"], { tinode: this.props.tinode, messages: pinnedMessages, selected: this.state.selectedPin, isAdmin: this.state.isAdmin, setSelected: index => this.setState({ selectedPin: index }), onSelected: this.handleQuoteClick, onCancel: this.handleUnpinMessage }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_error_panel_jsx__WEBPACK_IMPORTED_MODULE_7__["default"], { level: this.props.errorLevel, text: this.props.errorText, onClearError: this.props.onError })) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_load_spinner_jsx__WEBPACK_IMPORTED_MODULE_12__["default"], { show: this.state.fetchingMessages }), messagesComponent, this.state.dragging && this.isDragEnabled() ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "drag-n-drop" }, formatMessage(messages.drag_file)) : null); } component = react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "topic-view", ref: this.mountDnDEvents }, component2); } return component; } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(MessagesView)); /***/ }), /***/ "./src/views/new-topic-view.jsx": /*!**************************************!*\ !*** ./src/views/new-topic-view.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _widgets_contact_list_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/contact-list.jsx */ "./src/widgets/contact-list.jsx"); /* harmony import */ var _widgets_new_topic_by_id_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../widgets/new-topic-by-id.jsx */ "./src/widgets/new-topic-by-id.jsx"); /* harmony import */ var _widgets_new_topic_group_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../widgets/new-topic-group.jsx */ "./src/widgets/new-topic-group.jsx"); /* harmony import */ var _widgets_search_contacts_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../widgets/search-contacts.jsx */ "./src/widgets/search-contacts.jsx"); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ search_for_contacts: { id: "search_for_contacts", defaultMessage: [{ "type": 0, "value": "Use search to find contacts" }] }, search_no_results: { id: "search_no_results", defaultMessage: [{ "type": 0, "value": "Search returned no results" }] }, search_placeholder: { id: "search_placeholder", defaultMessage: [{ "type": 0, "value": "List like alice@example.com, +17025550003..." }] } }); class NewTopicView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { tabSelected: 'find', searchQuery: null }; this.handleTabClick = this.handleTabClick.bind(this); this.handleSearchContacts = this.handleSearchContacts.bind(this); this.handleSearchResultSelected = this.handleSearchResultSelected.bind(this); this.handleNewGroupSubmit = this.handleNewGroupSubmit.bind(this); this.handleGroupByID = this.handleGroupByID.bind(this); } componentDidMount() { this.props.onInitFind(); } handleTabClick(e) { e.preventDefault(); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].addUrlParam(window.location.hash, 'tab', e.currentTarget.dataset.id)); this.setState({ tabSelected: e.currentTarget.dataset.id }); } handleSearchContacts(query) { this.props.onSearchContacts(query); this.setState({ searchQuery: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isNullValue(query) ? null : query }); } handleSearchResultSelected(topicName) { if (this.state.tabSelected == 'find') { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].removeUrlParam(window.location.hash, 'tab')); this.props.onCreateTopic(topicName); } } handleNewGroupSubmit(name, description, dataUrl, priv, tags, isChannel) { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].removeUrlParam(window.location.hash, 'tab')); this.props.onCreateTopic(undefined, { public: (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_8__.theCard)(name, dataUrl, null, description), private: priv, tags: tags }, isChannel); } handleGroupByID(topicName) { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].removeUrlParam(window.location.hash, 'tab')); this.props.onCreateTopic(topicName); } render() { const { formatMessage } = this.props.intl; const no_contacts_placeholder = formatMessage(this.state.searchQuery ? messages.search_no_results : messages.search_for_contacts); const search_placeholder = formatMessage(messages.search_placeholder); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "flex-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("ul", { className: "tabbar" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { className: this.state.tabSelected === "find" ? "active" : null }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", "data-id": "find", onClick: this.handleTabClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "tabtitle_find_user", defaultMessage: [{ "type": 0, "value": "find" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { className: this.state.tabSelected === "grp" ? "active" : null }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", "data-id": "grp", onClick: this.handleTabClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "tabtitle_new_group", defaultMessage: [{ "type": 0, "value": "new group" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { className: this.state.tabSelected === "byid" ? "active" : null }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", "data-id": "byid", onClick: this.handleTabClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "tabtitle_group_by_id", defaultMessage: [{ "type": 0, "value": "by id" }] })))), this.state.tabSelected === 'grp' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_new_topic_group_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { tinode: this.props.tinode, onSubmit: this.handleNewGroupSubmit, onError: this.props.onError }) : this.state.tabSelected === 'byid' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_new_topic_by_id_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { onSubmit: this.handleGroupByID, onError: this.props.onError }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "flex-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_search_contacts_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], { placeholder: search_placeholder, onSearchContacts: this.handleSearchContacts }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_contact_list_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, contacts: this.props.searchResults, myUserId: this.props.myUserId, emptyListMessage: no_contacts_placeholder, showOnline: false, showUnread: false, showContextMenu: false, onTopicSelected: this.handleSearchResultSelected }))); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(NewTopicView)); /***/ }), /***/ "./src/views/settings-view.jsx": /*!*************************************!*\ !*** ./src/views/settings-view.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ SettingsView) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/checkbox.jsx */ "./src/widgets/checkbox.jsx"); /* harmony import */ var _widgets_host_selector_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/host-selector.jsx */ "./src/widgets/host-selector.jsx"); class SettingsView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { transport: props.transport || 'def', serverAddress: props.serverAddress, secureConnection: props.secureConnection }; this.handleSubmit = this.handleSubmit.bind(this); this.handleTransportSelected = this.handleTransportSelected.bind(this); this.handleServerAddressChange = this.handleServerAddressChange.bind(this); this.handleToggleSecure = this.handleToggleSecure.bind(this); } handleSubmit(e) { e.preventDefault(); this.props.onUpdate({ transport: this.state.transport, serverAddress: this.state.serverAddress, secureConnection: this.state.secureConnection }); } handleTransportSelected(e) { this.setState({ transport: e.currentTarget.value }); } handleServerAddressChange(name) { this.setState({ serverAddress: name }); } handleToggleSecure(e) { this.setState({ secureConnection: !this.state.secureConnection }); } render() { const names = { def: "default", ws: "websocket", lp: "long polling" }; const transportOptions = []; ['def', 'ws', 'lp'].forEach(item => { const id = 'transport-' + item; const name = names[item]; transportOptions.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { key: item }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "radio", id: id, name: "transport-select", value: item, checked: this.state.transport === item, onChange: this.handleTransportSelected }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { htmlFor: id }, name))); }); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("form", { id: "settings-form", className: "panel-form", onSubmit: this.handleSubmit }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_server_to_use", defaultMessage: [{ "type": 0, "value": "Server to use:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_host_selector_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { serverAddress: this.state.serverAddress, onServerAddressChange: this.handleServerAddressChange }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { id: "secure-connection", name: "secure-connection", checked: this.state.secureConnection, className: "quoted", onChange: this.handleToggleSecure }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { htmlFor: "secure-connection" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_use_secure_connection", defaultMessage: [{ "type": 0, "value": "Use secure connection" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_wire_transport", defaultMessage: [{ "type": 0, "value": "Wire transport:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("ul", { className: "quoted" }, transportOptions)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "dialog-buttons" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { type: "submit", className: "primary" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_update", defaultMessage: [{ "type": 0, "value": "Update" }] })))); } } ; /***/ }), /***/ "./src/views/sidepanel-view.jsx": /*!**************************************!*\ !*** ./src/views/sidepanel-view.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_error_panel_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/error-panel.jsx */ "./src/widgets/error-panel.jsx"); /* harmony import */ var _widgets_load_spinner_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/load-spinner.jsx */ "./src/widgets/load-spinner.jsx"); /* harmony import */ var _widgets_side_navbar_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../widgets/side-navbar.jsx */ "./src/widgets/side-navbar.jsx"); /* harmony import */ var _topic_common_view_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./topic-common-view.jsx */ "./src/views/topic-common-view.jsx"); /* harmony import */ var _contacts_view_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./contacts-view.jsx */ "./src/views/contacts-view.jsx"); /* harmony import */ var _acc_notifications_view_jsx__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./acc-notifications-view.jsx */ "./src/views/acc-notifications-view.jsx"); /* harmony import */ var _acc_security_view_jsx__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./acc-security-view.jsx */ "./src/views/acc-security-view.jsx"); /* harmony import */ var _acc_support_view_jsx__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./acc-support-view.jsx */ "./src/views/acc-support-view.jsx"); /* harmony import */ var _login_view_jsx__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./login-view.jsx */ "./src/views/login-view.jsx"); /* harmony import */ var _new_topic_view_jsx__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./new-topic-view.jsx */ "./src/views/new-topic-view.jsx"); /* harmony import */ var _settings_view_jsx__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./settings-view.jsx */ "./src/views/settings-view.jsx"); /* harmony import */ var _validation_view_jsx__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./validation-view.jsx */ "./src/views/validation-view.jsx"); const AccountSettingsView = react__WEBPACK_IMPORTED_MODULE_0___default().lazy(_ => Promise.all(/*! import() */[__webpack_require__.e("vendors-node_modules_libphonenumber-js_examples_mobile_json_js-node_modules_libphonenumber-js-7e28c7"), __webpack_require__.e("src_views_account-settings-view_jsx")]).then(__webpack_require__.bind(__webpack_require__, /*! ./account-settings-view.jsx */ "./src/views/account-settings-view.jsx"))); const CreateAccountView = react__WEBPACK_IMPORTED_MODULE_0___default().lazy(_ => Promise.all(/*! import() */[__webpack_require__.e("vendors-node_modules_libphonenumber-js_examples_mobile_json_js-node_modules_libphonenumber-js-7e28c7"), __webpack_require__.e("src_views_create-account-view_jsx")]).then(__webpack_require__.bind(__webpack_require__, /*! ./create-account-view.jsx */ "./src/views/create-account-view.jsx"))); const PasswordResetView = react__WEBPACK_IMPORTED_MODULE_0___default().lazy(_ => Promise.all(/*! import() */[__webpack_require__.e("vendors-node_modules_libphonenumber-js_examples_mobile_json_js-node_modules_libphonenumber-js-7e28c7"), __webpack_require__.e("src_views_password-reset-view_jsx")]).then(__webpack_require__.bind(__webpack_require__, /*! ./password-reset-view.jsx */ "./src/views/password-reset-view.jsx"))); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ login: { id: "sidepanel_title_login", defaultMessage: [{ "type": 0, "value": "Sign In" }] }, register: { id: "sidepanel_title_register", defaultMessage: [{ "type": 0, "value": "Create Account" }] }, settings: { id: "sidepanel_title_settings", defaultMessage: [{ "type": 0, "value": "Settings" }] }, edit: { id: "sidepanel_title_account_settings", defaultMessage: [{ "type": 0, "value": "Account Settings" }] }, general: { id: "panel_title_general", defaultMessage: [{ "type": 0, "value": "General" }] }, security: { id: "panel_title_security", defaultMessage: [{ "type": 0, "value": "Security" }] }, crop: { id: "panel_title_crop", defaultMessage: [{ "type": 0, "value": "Drag to Adjust" }] }, notif: { id: "sidepanel_title_acc_notifications", defaultMessage: [{ "type": 0, "value": "Notifications" }] }, support: { id: "sidepanel_title_acc_support", defaultMessage: [{ "type": 0, "value": "Support" }] }, newtpk: { id: "sidepanel_title_newtpk", defaultMessage: [{ "type": 0, "value": "Start New Chat" }] }, cred: { id: "sidepanel_title_cred", defaultMessage: [{ "type": 0, "value": "Confirm Credentials" }] }, reset: { id: "sidepanel_title_reset", defaultMessage: [{ "type": 0, "value": "Reset Password" }] }, archive: { id: "sidepanel_title_archive", defaultMessage: [{ "type": 0, "value": "Archived Chats" }] }, blocked: { id: "sidepanel_title_blocked", defaultMessage: [{ "type": 0, "value": "Blocked Chats" }] } }); class SidepanelView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleNewTopic = this.handleNewTopic.bind(this); } handleNewTopic() { this.props.onNavigate('newtpk'); } render() { const { formatMessage } = this.props.intl; const view = this.props.state || (this.props.myUserId ? 'contacts' : 'login'); let title, avatar, badges; if (view == 'contacts') { title = this.props.title; avatar = this.props.avatar ? this.props.avatar : true; badges = this.props.trustedBadges; } else { title = formatMessage(messages[view]); avatar = false; badges = null; } let onCancel; if (['login', 'contacts'].indexOf(view) == -1) { onCancel = this.props.onCancel; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "sidepanel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_side_navbar_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { state: view, title: title, avatar: avatar, tinode: this.props.tinode, trustedBadges: badges, myUserId: this.props.myUserId, onSignUp: this.props.onSignUp, onSettings: this.props.onSettings, onNewTopic: this.handleNewTopic, onCancel: onCancel }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_error_panel_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { level: this.props.errorLevel, text: this.props.errorText, action: this.props.errorAction, actionText: this.props.errorActionText, onClearError: this.props.onError }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_load_spinner_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { show: this.props.loadSpinnerVisible }), view === 'login' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_login_view_jsx__WEBPACK_IMPORTED_MODULE_10__["default"], { login: this.props.login, disabled: this.props.loginDisabled, persist: this.props.persist, onLogin: this.props.onLoginRequest, onPersistenceChange: this.props.onPersistenceChange }) : view === 'register' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, { fallback: react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "loading_note", defaultMessage: [{ "type": 0, "value": "Loading..." }] })) }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(CreateAccountView, { tinode: this.props.tinode, reqCredMethod: this.props.reqCredMethod, onShowCountrySelector: this.props.onShowCountrySelector, onCreateAccount: this.props.onCreateAccount, onCancel: this.props.onCancel, onError: this.props.onError })) : view === 'settings' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_settings_view_jsx__WEBPACK_IMPORTED_MODULE_12__["default"], { transport: this.props.transport, serverAddress: this.props.serverAddress, secureConnection: this.props.secureConnection, onCancel: this.props.onCancel, onUpdate: this.props.onGlobalSettings }) : view === 'edit' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, { fallback: react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "loading_note", defaultMessage: [{ "type": 0, "value": "Loading..." }] })) }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(AccountSettingsView, { tinode: this.props.tinode, myUserId: this.props.myUserId, trustedBadges: this.props.trustedBadges, reqCredMethod: this.props.reqCredMethod, onShowCountrySelector: this.props.onShowCountrySelector, onNavigate: this.props.onNavigate, onCredAdd: this.props.onCredAdd, onCredDelete: this.props.onCredDelete, onCredConfirm: this.props.onCredConfirm, onError: this.props.onError })) : view === 'general' || view === 'crop' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_topic_common_view_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { topic: "me", tinode: this.props.tinode, myUserId: this.props.myUserId, reqCredMethod: this.props.reqCredMethod, onUpdateTopicDesc: this.props.onUpdateAccountDesc, onUpdateTagsRequest: this.props.onUpdateAccountTags, onError: this.props.onError }) : view === 'notif' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_acc_notifications_view_jsx__WEBPACK_IMPORTED_MODULE_7__["default"], { messageSounds: this.props.messageSounds, desktopAlerts: this.props.desktopAlerts, desktopAlertsEnabled: this.props.desktopAlertsEnabled, incognitoMode: this.props.incognitoMode, onTogglePushNotifications: this.props.onTogglePushNotifications, onToggleMessageSounds: this.props.onToggleMessageSounds, onToggleIncognitoMode: this.props.onToggleIncognitoMode }) : view === 'security' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_acc_security_view_jsx__WEBPACK_IMPORTED_MODULE_8__["default"], { tinode: this.props.tinode, onUpdateAccountDesc: this.props.onUpdateAccountDesc, onUpdatePassword: this.props.onUpdatePassword, onLogout: this.props.onLogout, onDeleteAccount: this.props.onDeleteAccount, onShowAlert: this.props.onShowAlert, onShowBlocked: this.props.onShowBlocked }) : view === 'support' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_acc_support_view_jsx__WEBPACK_IMPORTED_MODULE_9__["default"], { serverAddress: this.props.serverAddress, serverVersion: this.props.serverVersion }) : view === 'contacts' || view == 'archive' || view == 'blocked' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_contacts_view_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], { tinode: this.props.tinode, myUserId: this.props.myUserId, connected: this.props.connected, topicSelected: this.props.topicSelected, archive: view == 'archive', blocked: view == 'blocked', chatList: this.props.chatList, showContextMenu: this.props.showContextMenu, onTopicSelected: this.props.onTopicSelected, onShowArchive: this.props.onShowArchive }) : view === 'newtpk' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_new_topic_view_jsx__WEBPACK_IMPORTED_MODULE_11__["default"], { tinode: this.props.tinode, searchResults: this.props.searchResults, onInitFind: this.props.onInitFind, onSearchContacts: this.props.onSearchContacts, onCreateTopic: this.props.onCreateTopic, onError: this.props.onError }) : view === 'cred' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_validation_view_jsx__WEBPACK_IMPORTED_MODULE_13__["default"], { credCode: this.props.credCode, credMethod: this.props.credMethod, credToken: this.props.credToken, onSubmit: this.props.onValidateCredentials, onCancel: this.props.onCancel }) : view === 'reset' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, { fallback: react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "loading_note", defaultMessage: [{ "type": 0, "value": "Loading..." }] })) }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(PasswordResetView, { tinode: this.props.tinode, reqCredMethod: this.props.reqCredMethod, onShowCountrySelector: this.props.onShowCountrySelector, onRequest: this.props.onPasswordResetRequest, onReset: this.props.onResetPassword, onCancel: this.props.onCancel, onError: this.props.onError })) : null); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(SidepanelView)); /***/ }), /***/ "./src/views/tinode-web.jsx": /*!**********************************!*\ !*** ./src/views/tinode-web.jsx ***! \**********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var firebase_app__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! firebase/app */ "./node_modules/firebase/app/dist/esm/index.esm.js"); /* harmony import */ var firebase_messaging__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! firebase/messaging */ "./node_modules/firebase/messaging/dist/esm/index.esm.js"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_4__); /* harmony import */ var _widgets_alert_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../widgets/alert.jsx */ "./src/widgets/alert.jsx"); /* harmony import */ var _widgets_context_menu_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../widgets/context-menu.jsx */ "./src/widgets/context-menu.jsx"); /* harmony import */ var _widgets_forward_dialog_jsx__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../widgets/forward-dialog.jsx */ "./src/widgets/forward-dialog.jsx"); /* harmony import */ var _widgets_call_incoming_jsx__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../widgets/call-incoming.jsx */ "./src/widgets/call-incoming.jsx"); /* harmony import */ var _info_view_jsx__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./info-view.jsx */ "./src/views/info-view.jsx"); /* harmony import */ var _messages_view_jsx__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./messages-view.jsx */ "./src/views/messages-view.jsx"); /* harmony import */ var _sidepanel_view_jsx__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./sidepanel-view.jsx */ "./src/views/sidepanel-view.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../constants.js */ "./src/constants.js"); /* harmony import */ var _version_js__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../version.js */ "./src/version.js"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_host_name_js__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../lib/host-name.js */ "./src/lib/host-name.js"); /* harmony import */ var _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../lib/local-storage.js */ "./src/lib/local-storage.js"); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js"); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); const PhoneCountrySelector = react__WEBPACK_IMPORTED_MODULE_0___default().lazy(_ => __webpack_require__.e(/*! import() */ "src_widgets_phone-country-selector_jsx").then(__webpack_require__.bind(__webpack_require__, /*! ../widgets/phone-country-selector.jsx */ "./src/widgets/phone-country-selector.jsx"))); const POP_SOUND = new Audio('audio/msg.m4a'); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ reconnect_countdown: { id: "reconnect_countdown", defaultMessage: [{ "type": 0, "value": "Disconnected. Reconnecting in " }, { "type": 1, "value": "seconds" }, { "type": 0, "value": "…" }] }, reconnect_now: { id: "reconnect_now", defaultMessage: [{ "type": 0, "value": "Try now" }] }, push_init_failed: { id: "push_init_failed", defaultMessage: [{ "type": 0, "value": "Failed to initialize push notifications" }] }, invalid_security_token: { id: "invalid_security_token", defaultMessage: [{ "type": 0, "value": "Invalid security token" }] }, no_connection: { id: "no_connection", defaultMessage: [{ "type": 0, "value": "No connection" }] }, code_doesnot_match: { id: "code_doesnot_match", defaultMessage: [{ "type": 0, "value": "Code does not match" }] }, menu_item_info: { id: "menu_item_info", defaultMessage: [{ "type": 0, "value": "Info" }] }, menu_item_audio_call: { id: "menu_item_audio_call", defaultMessage: [{ "type": 0, "value": "Call" }] }, menu_item_video_call: { id: "menu_item_video_call", defaultMessage: [{ "type": 0, "value": "Video call" }] }, cred_confirmed_successfully: { id: "cred_confirmed_successfully", defaultMessage: [{ "type": 0, "value": "Confirmed successfully" }] } }); class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.selfRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.state = this.getBlankState(); this.handleResize = this.handleResize.bind(this); this.handleHashRoute = this.handleHashRoute.bind(this); this.handleOnline = this.handleOnline.bind(this); this.checkForAppUpdate = this.checkForAppUpdate.bind(this); this.handleVisibilityEvent = this.handleVisibilityEvent.bind(this); this.handleError = this.handleError.bind(this); this.handleLoginRequest = this.handleLoginRequest.bind(this); this.handlePersistenceChange = this.handlePersistenceChange.bind(this); this.handleConnected = this.handleConnected.bind(this); this.handleAutoreconnectIteration = this.handleAutoreconnectIteration.bind(this); this.doLogin = this.doLogin.bind(this); this.handleLoginSuccessful = this.handleLoginSuccessful.bind(this); this.handleDisconnect = this.handleDisconnect.bind(this); this.tnMeMetaDesc = this.tnMeMetaDesc.bind(this); this.tnMeContactUpdate = this.tnMeContactUpdate.bind(this); this.tnMeSubsUpdated = this.tnMeSubsUpdated.bind(this); this.resetContactList = this.resetContactList.bind(this); this.tnInitFind = this.tnInitFind.bind(this); this.tnFndSubsUpdated = this.tnFndSubsUpdated.bind(this); this.handleSearchContacts = this.handleSearchContacts.bind(this); this.handleTopicSelected = this.handleTopicSelected.bind(this); this.handleHideMessagesView = this.handleHideMessagesView.bind(this); this.handleSendMessage = this.handleSendMessage.bind(this); this.handleNewChatInvitation = this.handleNewChatInvitation.bind(this); this.handleNewAccount = this.handleNewAccount.bind(this); this.handleNewAccountRequest = this.handleNewAccountRequest.bind(this); this.handleUpdatePasswordRequest = this.handleUpdatePasswordRequest.bind(this); this.handleUpdateAccountTagsRequest = this.handleUpdateAccountTagsRequest.bind(this); this.handleToggleIncognitoMode = this.handleToggleIncognitoMode.bind(this); this.handleSettings = this.handleSettings.bind(this); this.handleGlobalSettings = this.handleGlobalSettings.bind(this); this.handleShowArchive = this.handleShowArchive.bind(this); this.handleShowBlocked = this.handleShowBlocked.bind(this); this.handleToggleMessageSounds = this.handleToggleMessageSounds.bind(this); this.handleCredAdd = this.handleCredAdd.bind(this); this.handleCredDelete = this.handleCredDelete.bind(this); this.handleCredConfirm = this.handleCredConfirm.bind(this); this.initFCMessaging = this.initFCMessaging.bind(this); this.toggleFCMToken = this.toggleFCMToken.bind(this); this.handlePushMessage = this.handlePushMessage.bind(this); this.handleSidepanelCancel = this.handleSidepanelCancel.bind(this); this.handleStartTopicRequest = this.handleStartTopicRequest.bind(this); this.handleNewTopicCreated = this.handleNewTopicCreated.bind(this); this.handleTopicUpdateRequest = this.handleTopicUpdateRequest.bind(this); this.handleUnarchive = this.handleUnarchive.bind(this); this.handleChangePermissions = this.handleChangePermissions.bind(this); this.handleTagsUpdateRequest = this.handleTagsUpdateRequest.bind(this); this.handleLogout = this.handleLogout.bind(this); this.handleDeleteAccount = this.handleDeleteAccount.bind(this); this.handleDeleteTopicRequest = this.handleDeleteTopicRequest.bind(this); this.handleDeleteMessagesRequest = this.handleDeleteMessagesRequest.bind(this); this.handleLeaveUnsubRequest = this.handleLeaveUnsubRequest.bind(this); this.handleBlockTopicRequest = this.handleBlockTopicRequest.bind(this); this.handleReportTopic = this.handleReportTopic.bind(this); this.handleShowContextMenu = this.handleShowContextMenu.bind(this); this.defaultTopicContextMenu = this.defaultTopicContextMenu.bind(this); this.handleHideContextMenu = this.handleHideContextMenu.bind(this); this.handleShowAlert = this.handleShowAlert.bind(this); this.handleShowInfoView = this.handleShowInfoView.bind(this); this.handleMemberUpdateRequest = this.handleMemberUpdateRequest.bind(this); this.handleValidateCredentialsRequest = this.handleValidateCredentialsRequest.bind(this); this.handlePasswordResetRequest = this.handlePasswordResetRequest.bind(this); this.handleResetPassword = this.handleResetPassword.bind(this); this.handleContextMenuAction = this.handleContextMenuAction.bind(this); this.handleShowCountrySelector = this.handleShowCountrySelector.bind(this); this.handleShowForwardDialog = this.handleShowForwardDialog.bind(this); this.handleHideForwardDialog = this.handleHideForwardDialog.bind(this); this.handleStartVideoCall = this.handleStartVideoCall.bind(this); this.handleStartAudioCall = this.handleStartAudioCall.bind(this); this.handleInfoMessage = this.handleInfoMessage.bind(this); this.handleDataMessage = this.handleDataMessage.bind(this); this.handleCallClose = this.handleCallClose.bind(this); this.handleCallInvite = this.handleCallInvite.bind(this); this.handleCallRinging = this.handleCallRinging.bind(this); this.handleCallHangup = this.handleCallHangup.bind(this); this.handleCallSendOffer = this.handleCallSendOffer.bind(this); this.handleCallIceCandidate = this.handleCallIceCandidate.bind(this); this.handleCallSendAnswer = this.handleCallSendAnswer.bind(this); this.handleVCCallJoin = this.handleVCCallJoin.bind(this); this.handleCallAccept = this.handleCallAccept.bind(this); this.sendMessageToTopic = this.sendMessageToTopic.bind(this); this.callTimeoutTimer = null; } getBlankState() { const settings = _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('settings') || {}; const persist = !!_lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('keep-logged-in'); return { connected: false, ready: false, autoLogin: false, transport: settings.transport || null, serverAddress: settings.serverAddress || (0,_lib_host_name_js__WEBPACK_IMPORTED_MODULE_16__.detectServerAddress)(), secureConnection: settings.secureConnection === undefined ? (0,_lib_host_name_js__WEBPACK_IMPORTED_MODULE_16__.isSecureConnection)() : settings.secureConnection, serverVersion: "no connection", messageSounds: !settings.messageSoundsOff, incognitoMode: false, desktopAlerts: persist && !!settings.desktopAlerts, desktopAlertsEnabled: ((0,_lib_host_name_js__WEBPACK_IMPORTED_MODULE_16__.isSecureConnection)() || (0,_lib_host_name_js__WEBPACK_IMPORTED_MODULE_16__.isLocalHost)()) && typeof firebase_app__WEBPACK_IMPORTED_MODULE_2__.initializeApp != 'undefined' && typeof navigator != 'undefined' && typeof FIREBASE_INIT != 'undefined', firebaseToken: persist ? _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('firebase-token') : null, applicationVisible: !document.hidden, errorText: '', errorLevel: null, errorAction: undefined, errorActionText: null, sidePanelSelected: 'login', sidePanelTitle: null, sidePanelAvatar: null, myTrustedBadges: [], loadSpinnerVisible: false, login: '', password: '', persist: persist, myUserId: null, liveConnection: navigator.onLine, topicSelected: '', topicSelectedOnline: false, topicSelectedAcs: null, newTopicParams: null, loginDisabled: false, displayMobile: window.innerWidth <= _config_js__WEBPACK_IMPORTED_MODULE_12__.MEDIA_BREAKPOINT, infoPanel: undefined, mobilePanel: 'sidepanel', callTopic: undefined, callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_NONE, callAudioOnly: undefined, callShouldStart: false, contextMenuVisible: false, contextMenuBounds: null, contextMenuClickAt: null, contextMenuParams: null, contextMenuItems: [], forwardDialogVisible: false, forwardMessage: null, alertVisible: false, alertParams: {}, chatList: [], searchResults: [], searchableContacts: [], reqCredMethod: undefined, credMethod: undefined, credCode: undefined, credToken: undefined, requestedTopic: undefined }; } componentDidMount() { window.addEventListener('resize', this.handleResize); this.handleOnlineOn = _ => { this.handleOnline(true); }; window.addEventListener('online', this.handleOnlineOn); this.handleOnlineOff = _ => { this.handleOnline(false); }; window.addEventListener('offline', this.handleOnlineOff); window.addEventListener('hashchange', this.handleHashRoute); if (typeof BroadcastChannel == 'function') { const serviceWorkerChannel = new BroadcastChannel('tinode-sw'); serviceWorkerChannel.addEventListener('message', this.handlePushMessage); } else { console.warn("Your browser does not support BroadcastChannel. Some features will not be available"); } document.addEventListener('visibilitychange', this.handleVisibilityEvent); this.setState({ viewportWidth: document.documentElement.clientWidth, viewportHeight: document.documentElement.clientHeight }); new Promise((resolve, reject) => { this.tinode = TinodeWeb.tnSetup(this.state.serverAddress, (0,_lib_host_name_js__WEBPACK_IMPORTED_MODULE_16__.isSecureConnection)(), this.state.transport, this.props.intl.locale, this.state.persist, resolve); this.tinode.onConnect = this.handleConnected; this.tinode.onDisconnect = this.handleDisconnect; this.tinode.onAutoreconnectIteration = this.handleAutoreconnectIteration; this.tinode.onInfoMessage = this.handleInfoMessage; this.tinode.onDataMessage = this.handleDataMessage; }).then(_ => { if (this.state.desktopAlertsEnabled) { this.initFCMessaging().catch(_ => {}); } this.resetContactList(); const token = this.state.persist ? _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('auth-token') : undefined; if (token) { this.setState({ autoLogin: true }); token.expires = new Date(token.expires); this.tinode.setAuthToken(token); this.tinode.connect().catch(err => { this.handleError(err.message, 'err'); }); } this.readTimer = null; this.readTimerCallback = null; const parsedNav = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].parseUrlHash(window.location.hash); if (!['cred', 'reset', 'register'].includes(parsedNav.path[0])) { this.setState({ requestedTopic: parsedNav.path[1] }); const path = parsedNav.params && parsedNav.params.cred_done ? _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].addUrlParam('', 'cred_done', parsedNav.params.cred_done) : ''; _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(path); } else { this.handleHashRoute(); } }); } componentWillUnmount() { window.removeEventListener('resize', this.handleResize); window.removeEventListener('hashchange', this.handleHashRoute); window.removeEventListener('online', this.handleOnlineOn); window.removeEventListener('offline', this.handleOnlineOff); document.removeEventListener('visibilitychange', this.handleVisibilityEvent); } static tnSetup(serverAddress, secureConnection, transport, locale, persistentCache, onSetupCompleted) { const tinode = new tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode({ appName: _config_js__WEBPACK_IMPORTED_MODULE_12__.APP_NAME, host: serverAddress, apiKey: _config_js__WEBPACK_IMPORTED_MODULE_12__.API_KEY, transport: transport, secure: secureConnection, persist: persistentCache }, onSetupCompleted); tinode.setHumanLanguage(locale); tinode.enableLogging(_config_js__WEBPACK_IMPORTED_MODULE_12__.LOGGING_ENABLED, true); return tinode; } handlePushMessage(payload) { this.tinode.oobNotification(payload.data || {}); } initFCMessaging() { const { formatMessage, locale } = this.props.intl; const onError = (msg, err) => { console.error(msg, err); this.handleError(formatMessage(messages.push_init_failed), 'err'); this.setState({ firebaseToken: null }); _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { desktopAlerts: false }); }; try { this.fcm = (0,firebase_messaging__WEBPACK_IMPORTED_MODULE_3__.getMessaging)((0,firebase_app__WEBPACK_IMPORTED_MODULE_2__.initializeApp)(FIREBASE_INIT, _config_js__WEBPACK_IMPORTED_MODULE_12__.APP_NAME)); return navigator.serviceWorker.getRegistration('/service-worker.js').then(reg => { return reg || navigator.serviceWorker.register('/service-worker.js').then(reg => { this.checkForAppUpdate(reg); return reg; }); }).then(reg => { (reg.active || reg.installing).postMessage(JSON.stringify({ locale: locale, version: _version_js__WEBPACK_IMPORTED_MODULE_14__.PACKAGE_VERSION })); return TinodeWeb.requestFCMToken(this.fcm, reg); }).then(token => { const persist = _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('keep-logged-in'); if (token != this.state.firebaseToken) { this.tinode.setDeviceToken(token); if (persist) { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].setObject('firebase-token', token); } } this.setState({ firebaseToken: token, desktopAlerts: true }); if (persist) { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { desktopAlerts: true }); } (0,firebase_messaging__WEBPACK_IMPORTED_MODULE_3__.onMessage)(this.fcm, payload => { this.handlePushMessage(payload); }); }).catch(err => { onError(err); throw err; }); } catch (err) { onError(err); return Promise.reject(err); } } static requestFCMToken(fcm, sw) { return (0,firebase_messaging__WEBPACK_IMPORTED_MODULE_3__.getToken)(fcm, { serviceWorkerRegistration: sw, vapidKey: FIREBASE_INIT.messagingVapidKey }).then(token => { if (token) { return token; } else if (typeof Notification != 'undefined') { return Notification.requestPermission().then(permission => { if (permission === 'granted') { return (0,firebase_messaging__WEBPACK_IMPORTED_MODULE_3__.getToken)(fcm, { serviceWorkerRegistration: reg, vapidKey: FIREBASE_INIT.messagingVapidKey }).then(token => { if (token) { return token; } else { throw new Error("Failed to initialize notifications"); } }); } else { throw new Error("No permission to send notifications: " + permission); } }); } throw new Error("Notifications are not supported"); }); } handleResize() { const mobile = document.documentElement.clientWidth <= _config_js__WEBPACK_IMPORTED_MODULE_12__.MEDIA_BREAKPOINT; this.setState({ viewportWidth: document.documentElement.clientWidth, viewportHeight: document.documentElement.clientHeight }); if (this.state.displayMobile != mobile) { this.setState({ displayMobile: mobile }); } } checkForAppUpdate(reg) { reg.onupdatefound = _ => { const installingWorker = reg.installing; installingWorker.onstatechange = _ => { if (installingWorker.state == 'installed' && navigator.serviceWorker.controller) { const msg = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "update_available", defaultMessage: [{ "type": 0, "value": "Update available." }] }), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "reload_update", defaultMessage: [{ "type": 0, "value": "Reload" }] })), "."); this.handleError(msg, 'info'); } }; }; } handleHashRoute() { const hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].parseUrlHash(window.location.hash); const newState = { infoPanel: hash.params.info, newTopicTabSelected: hash.params.tab }; if (hash.path && hash.path.length > 0) { if (['register', 'settings', 'edit', 'notif', 'security', 'support', 'general', 'crop', 'cred', 'reset', 'newtpk', 'archive', 'blocked', 'contacts', ''].includes(hash.path[0])) { newState.sidePanelSelected = hash.path[0]; } else { console.warn("Unknown sidepanel view", hash.path[0]); } let topicName = hash.path[1] || null; if (topicName != this.state.topicSelected) { if (!tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.topicType(topicName)) { topicName = null; newState.mobilePanel = 'sidepanel'; } else { newState.mobilePanel = 'topic-view'; } Object.assign(newState, { topicSelected: topicName, topicSelectedAcs: this.tinode.getTopicAccessMode(topicName) }); } } else { Object.assign(newState, { sidePanelSelected: '', topicSelected: null }); } if (hash.params.method) { newState.credMethod = hash.params.method; } if (hash.params.code) { newState.credCode = hash.params.code; } if (hash.params.token) { newState.credToken = hash.params.token; } if (hash.params.cred_done) { Object.assign(newState, TinodeWeb.stateForError(this.props.intl.formatMessage(messages.cred_confirmed_successfully), 'info')); } this.setState(newState); } handleOnline(online) { if (online) { this.handleError(); clearInterval(this.reconnectCountdown); this.tinode.reconnect(); } else { this.handleError(this.props.intl.formatMessage(messages.no_connection), 'warn'); } this.setState({ liveConnection: online }); } handleVisibilityEvent() { this.setState({ applicationVisible: !document.hidden }); } static stateForError(err, level, action, actionText) { return { errorText: err, errorLevel: level, errorAction: action, errorActionText: actionText, callShouldStart: false }; } handleError(err, level, action, actionText) { this.setState(TinodeWeb.stateForError(err, level, action, actionText)); } handleLoginRequest(login, password) { this.setState({ loginDisabled: true, login: login, password: password, loadSpinnerVisible: true, autoLogin: true }); this.handleError('', null); if (this.tinode.isConnected()) { this.doLogin(login, password, null, { meth: this.state.credMethod, resp: this.state.credCode }); } else { this.tinode.connect().catch(err => { this.setState({ loginDisabled: false, autoLogin: false, loadSpinnerVisible: false }); this.handleError(err.message, 'err'); }); } if (this.state.desktopAlertsEnabled && !this.state.firebaseToken) { this.initFCMessaging(); } } handlePersistenceChange(persist) { if (persist) { this.tinode.initStorage().then(_ => { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].setObject('keep-logged-in', true); this.setState({ persist: true }); }); } else { this.tinode.clearStorage().then(_ => { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].setObject('keep-logged-in', false); this.setState({ persist: false }); }); } } handleConnected() { clearInterval(this.reconnectCountdown); this.handleError(); const params = this.tinode.getServerInfo(); this.setState({ serverVersion: params.ver + ' ' + (params.build ? params.build : 'none'), reqCredMethod: ((params.reqCred || {}).auth || [])[0] || 'email' }); if (this.state.autoLogin) { this.doLogin(this.state.login, this.state.password, null, { meth: this.state.credMethod, resp: this.state.credCode }); } } handleAutoreconnectIteration(sec, prom) { clearInterval(this.reconnectCountdown); if (sec < 0) { this.handleError(); return; } if (prom) { prom.then(_ => { this.handleError(); }).catch(err => { this.handleError(err.message, 'err'); }); return; } const { formatMessage } = this.props.intl; let count = sec / 1000; count = count | count; this.reconnectCountdown = setInterval(_ => { if (count < -10) { clearInterval(this.reconnectCountdown); this.tinode.reconnect(); return; } const fmtTime = count > 99 ? (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_19__.secondsToTime)(count) : count; this.handleError(formatMessage(messages.reconnect_countdown, { seconds: fmtTime }), 'warn', _ => { clearInterval(this.reconnectCountdown); this.tinode.reconnect(); }, formatMessage(messages.reconnect_now)); count -= 1; }, 1000); } handleDisconnect(err) { this.setState({ connected: false, ready: false, topicSelectedOnline: false, errorText: err && err.message ? err.message : "Disconnected", errorLevel: err && err.message ? 'err' : 'warn', loginDisabled: false, contextMenuVisible: false, forwardDialogVisible: false, serverVersion: "no connection" }); } doLogin(login, password, tmpToken, cred) { if (this.tinode.isAuthenticated()) { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(''); return; } let token = tmpToken || (this.tinode.getAuthToken() || {}).token; if (!(login && password) && !token) { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(''); this.setState({ loginDisabled: false }); return; } cred = tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.credential(cred); let connectionPromise = this.tinode.isConnected() ? Promise.resolve() : this.tinode.connect(); let loginPromise; if (login && password) { token = null; this.setState({ password: null }); loginPromise = connectionPromise.then(_ => this.tinode.loginBasic(login, password, cred)); } else { loginPromise = connectionPromise.then(_ => this.tinode.loginToken(token, cred)); } loginPromise.then(ctrl => { if (ctrl.code >= 300 && ctrl.text === 'validate credentials') { this.setState({ loadSpinnerVisible: false }); if (cred) { this.handleError(this.props.intl.formatMessage(messages.code_doesnot_match), 'warn'); } TinodeWeb.navigateToCredentialsView(ctrl.params); } else { this.handleLoginSuccessful(); } }).catch(err => { const autoLogin = err.code >= 500; this.setState({ loginDisabled: false, credMethod: undefined, credCode: undefined, loadSpinnerVisible: false, autoLogin: autoLogin }); this.handleError(err.message, 'err'); console.warn("Login failed", err); if (!autoLogin) { if (token) { this.handleLogout(); } _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(''); } }); } static navigateToCredentialsView(params) { const parsed = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].parseUrlHash(window.location.hash); parsed.path[0] = 'cred'; parsed.params['method'] = params.cred[0]; parsed.params['token'] = params.token; parsed.params['code'] = params.code; _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].composeUrlHash(parsed.path, parsed.params)); } handleLoginSuccessful() { this.handleError(); if (_lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('keep-logged-in')) { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].setObject('auth-token', this.tinode.getAuthToken()); } const goToTopic = this.state.requestedTopic; const me = this.tinode.getMeTopic(); me.onMetaDesc = this.tnMeMetaDesc; me.onContactUpdate = this.tnMeContactUpdate; me.onSubsUpdated = this.tnMeSubsUpdated; this.setState({ connected: true, credMethod: undefined, credCode: undefined, credToken: undefined, myUserId: this.tinode.getCurrentUserID(), autoLogin: true, requestedTopic: undefined }); me.subscribe(me.startMetaQuery().withLaterSub().withDesc().withTags().withCred().build()).catch(err => { this.tinode.disconnect(); localStorage.removeItem('auth-token'); this.handleError(err.message, 'err'); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(''); }).finally(_ => { this.setState({ loadSpinnerVisible: false }); }); let urlHash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlSidePanel(window.location.hash, 'contacts'); if (goToTopic) { urlHash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlTopic(urlHash, goToTopic); } _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(urlHash); } tnMeMetaDesc(desc) { if (desc) { if (desc.public) { this.setState({ sidePanelTitle: desc.public.fn, sidePanelAvatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_15__.makeImageUrl)(desc.public.photo) }); } if (desc.trusted) { const badges = []; for (const [key, val] of Object.entries(desc.trusted)) { if (val) { badges.push(key); } } this.setState({ myTrustedBadges: badges }); } if (desc.acs) { this.setState({ incognitoMode: !desc.acs.isPresencer() }); } } } tnMeContactUpdate(what, cont) { if (what == 'on' || what == 'off') { this.resetContactList(); if (this.state.topicSelected == cont.topic) { this.setState({ topicSelectedOnline: what == 'on' }); } } else if (what == 'read') { this.resetContactList(); } else if (what == 'msg' && cont) { const topic = this.tinode.getTopic(cont.topic); const archived = topic && topic.isArchived(); if (cont.unread > 0 && this.state.messageSounds && !archived) { if (document.hidden || this.state.topicSelected != cont.topic) { POP_SOUND.play().catch(_ => {}); } } this.resetContactList(); } else if (what == 'recv') {} else if (what == 'gone' || what == 'unsub') { if (this.state.topicSelected == cont.topic) { this.handleTopicSelected(null); } this.resetContactList(); } else if (what == 'acs') { if (this.state.topicSelected == cont.topic) { this.setState({ topicSelectedAcs: cont.acs }); } } else if (what == 'del') {} else if (what == 'upd' || what == 'call') {} else { console.info("Unsupported (yet) presence update:", what, "in", (cont || {}).topic); } } tnMeSubsUpdated(unused) { this.resetContactList(); } static prepareSearchableContacts(chatList, foundContacts) { const merged = {}; for (const c of chatList) { if (tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isP2PTopicName(c.topic)) { merged[c.topic] = { user: c.topic, updated: c.updated, public: c.public, private: c.private, acs: c.acs }; } } for (const c of foundContacts) { if (!merged[c.user]) { merged[c.user] = c; } } return Object.values(merged); } resetContactList() { const newState = { chatList: [] }; if (!this.state.ready) { newState.ready = true; } this.tinode.getMeTopic().contacts(c => { if (!c.topic && !c.user) { c.topic = c.name; } newState.chatList.push(c); if (this.state.topicSelected == c.topic) { newState.topicSelectedOnline = c.online; newState.topicSelectedAcs = c.acs; } }); const past = new Date(0); newState.chatList.sort((a, b) => { return (a.touched || past).getTime() - (b.touched || past).getTime(); }); newState.searchableContacts = TinodeWeb.prepareSearchableContacts(newState.chatList, this.state.searchResults); this.setState(newState); } tnInitFind() { const fnd = this.tinode.getFndTopic(); fnd.onSubsUpdated = this.tnFndSubsUpdated; if (fnd.isSubscribed()) { this.tnFndSubsUpdated(); } else { fnd.subscribe(fnd.startMetaQuery().withSub().build()).catch(err => { this.handleError(err.message, 'err'); }); } } tnFndSubsUpdated() { const foundContacts = []; this.tinode.getFndTopic().contacts(s => { foundContacts.push(s); }); this.setState({ searchResults: foundContacts, searchableContacts: TinodeWeb.prepareSearchableContacts(this.state.chatList, foundContacts) }); } handleSearchContacts(query) { const fnd = this.tinode.getFndTopic(); fnd.setMeta({ desc: { public: query } }).then(_ => fnd.getMeta(fnd.startMetaQuery().withSub().build())).catch(err => this.handleError(err.message, 'err')); } handleTopicSelected(topicName) { if (this.state.newTopicParams && this.state.newTopicParams._topicName != topicName) { this.setState({ newTopicParams: null }); } if (topicName) { this.setState({ errorText: '', errorLevel: null, mobilePanel: 'topic-view', infoPanel: undefined }); if (this.state.topicSelected != topicName) { this.setState({ topicSelectedOnline: this.tinode.isTopicOnline(topicName), topicSelectedAcs: this.tinode.getTopicAccessMode(topicName), forwardMessage: null }); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlTopic('', topicName)); } } else { this.setState({ topicSelected: null, errorText: '', errorLevel: null, mobilePanel: 'sidepanel', topicSelectedOnline: false, topicSelectedAcs: null, infoPanel: undefined, forwardMessage: null }); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlTopic('', null)); } } handleHideMessagesView() { this.setState({ mobilePanel: 'sidepanel' }); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlTopic(window.location.hash, null)); } handleSendMessage(msg, uploadCompletionPromise, uploader, head) { const topic = this.tinode.getTopic(this.state.topicSelected); return this.sendMessageToTopic(topic, msg, uploadCompletionPromise, uploader, head); } sendMessageToTopic(topic, msg, uploadCompletionPromise, uploader, head) { msg = topic.createMessage(msg, false); msg._uploader = uploader; if (head) { msg.head = Object.assign(msg.head || {}, head); } const completion = []; if (uploadCompletionPromise) { completion.push(uploadCompletionPromise); } if (!topic.isSubscribed()) { const subscribePromise = topic.subscribe().then(_ => { let calls = []; topic.queuedMessages(pub => { if (pub._sending || pub.seq == msg.seq) { return; } if (pub.head && pub.head.webrtc) { calls.push(pub.seq); return; } if (topic.isSubscribed()) { topic.publishMessage(pub); } }); if (calls.length > 0) { topic.delMessagesList(calls, true); } }); completion.push(subscribePromise); } return topic.publishDraft(msg, Promise.all(completion)).then(ctrl => { if (topic.isArchived()) { topic.archive(false); } return ctrl; }).catch(err => this.handleError(err.message, 'err')); } handleNewChatInvitation(topicName, action) { const topic = this.tinode.getTopic(topicName); let response = null; switch (action) { case 'accept': const mode = topic.getAccessMode().getGiven(); response = topic.setMeta({ sub: { mode: mode } }); if (topic.isP2PType()) { response = response.then(_ => topic.setMeta({ sub: { user: topicName, mode: mode } })); } break; case 'delete': response = topic.delTopic(true); break; case 'block': const am = topic.getAccessMode().updateWant('-JP').getWant(); response = topic.setMeta({ sub: { mode: am } }).then(_ => this.handleTopicSelected(null)); break; default: console.warn("Unknown invitation action", '"' + action + '""'); } if (response != null) { response.catch(err => this.handleError(err.message, 'err')); } } handleNewAccount() { this.handleError(); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlSidePanel(window.location.hash, 'register')); } handleNewAccountRequest(login_, password_, public_, cred_, tags_) { this.handleError(); this.tinode.connect(this.state.serverAddress).then(_ => { let attachments; if (public_ && public_.photo && public_.photo.ref) { attachments = [public_.photo.ref]; } return this.tinode.createAccountBasic(login_, password_, { public: public_, tags: tags_, cred: tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.credential(cred_), attachments: attachments }); }).then(ctrl => { if (ctrl.code >= 300 && ctrl.text == 'validate credentials') { TinodeWeb.navigateToCredentialsView(ctrl.params); } else { this.handleLoginSuccessful(this); } }).catch(err => { this.handleError(err.message, 'err'); }); } handleToggleIncognitoMode(on) { this.setState({ incognitoMode: null }); const me = this.tinode.getMeTopic(); const am = me.getAccessMode().updateWant(on ? '-P' : '+P').getWant(); me.setMeta({ sub: { mode: am } }).catch(err => { this.setState({ incognitoMode: !on }); this.handleError(err.message, 'err'); }); } handleUpdateAccountTagsRequest(_, tags) { this.tinode.getMeTopic().setMeta({ tags: tags }).catch(err => this.handleError(err.message, 'err')); } handleSettings() { this.handleError(); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlSidePanel(window.location.hash, this.state.myUserId ? 'edit' : 'settings')); } handleGlobalSettings(settings) { const serverAddress = settings.serverAddress || this.state.serverAddress; const transport = settings.transport || this.state.transport; const secureConnection = settings.secureConnection === undefined ? this.state.secureConnection : settings.secureConnection; if (this.tinode) { this.tinode.clearStorage(); this.tinode.onDisconnect = undefined; this.tinode.disconnect(); } this.tinode = TinodeWeb.tnSetup(serverAddress, secureConnection, transport, this.props.intl.locale, _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('keep-logged-in')); this.tinode.onConnect = this.handleConnected; this.tinode.onDisconnect = this.handleDisconnect; this.tinode.onAutoreconnectIteration = this.handleAutoreconnectIteration; this.tinode.onInfoMessage = this.handleInfoMessage; this.tinode.onDataMessage = this.handleDataMessage; this.setState({ serverAddress: serverAddress, transport: transport, secureConnection: secureConnection }); _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].setObject('settings', { serverAddress: serverAddress, transport: transport, secureConnection: secureConnection }); _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlSidePanel(window.location.hash, '')); } handleShowArchive() { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlSidePanel(window.location.hash, this.state.myUserId ? 'archive' : '')); } handleShowBlocked() { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlSidePanel(window.location.hash, this.state.myUserId ? 'blocked' : '')); } toggleFCMToken(enabled) { if (enabled) { this.setState({ desktopAlerts: null }); if (!this.state.firebaseToken) { this.initFCMessaging(); } else { this.setState({ desktopAlerts: true }); if (_lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('keep-logged-in')) { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { desktopAlerts: true }); } } } else if (this.state.firebaseToken && this.fcm) { (0,firebase_messaging__WEBPACK_IMPORTED_MODULE_3__.deleteToken)(this.fcm).catch(err => { console.error("Unable to delete token.", err); }).finally(_ => { _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { desktopAlerts: false }); localStorage.removeItem('firebase-token'); this.setState({ desktopAlerts: false, firebaseToken: null }); this.tinode.setDeviceToken(null); }); } else { this.setState({ desktopAlerts: false, firebaseToken: null }); _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { desktopAlerts: false }); } } handleToggleMessageSounds(enabled) { this.setState({ messageSounds: enabled }); _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].updateObject('settings', { messageSoundsOff: !enabled }); } handleCredAdd(method, value) { const me = this.tinode.getMeTopic(); me.setMeta({ cred: { meth: method, val: value } }).catch(err => this.handleError(err.message, 'err')); } handleCredDelete(method, value) { const me = this.tinode.getMeTopic(); me.delCredential(method, value).catch(err => this.handleError(err.message, 'err')); } handleCredConfirm(method, response) { TinodeWeb.navigateToCredentialsView({ cred: [method], code: response }); } handleSidepanelCancel() { const parsed = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].parseUrlHash(window.location.hash); let path = ''; if (['security', 'support', 'general', 'notif'].includes(parsed.path[0])) { path = 'edit'; } else if ('crop' == parsed.path[0]) { path = 'general'; } else if ('blocked' == parsed.path[0]) { path = 'security'; } else if (this.state.myUserId) { path = 'contacts'; } parsed.path[0] = path; if (parsed.params) { delete parsed.params.code; delete parsed.params.method; delete parsed.params.tab; delete parsed.params.scheme; delete parsed.params.token; } _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].composeUrlHash(parsed.path, parsed.params)); this.setState({ errorText: '', errorLevel: null }); } basicNavigator(hash) { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlSidePanel(window.location.hash, hash)); } infoNavigator(hash) { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlInfoPanel(window.location.hash, hash)); } handleStartTopicRequest(topicName, newTopicParams, isChannel) { if (topicName && this.tinode.isTopicCached(topicName)) { this.handleTopicSelected(topicName); return; } const params = {}; if (tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isP2PTopicName(topicName)) { params.sub = { mode: _config_js__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_P2P_ACCESS_MODE }; params.desc = { defacs: { auth: _config_js__WEBPACK_IMPORTED_MODULE_12__.DEFAULT_P2P_ACCESS_MODE } }; } else { topicName = topicName || this.tinode.newGroupTopicName(isChannel); if (newTopicParams) { params.desc = { public: newTopicParams.public, private: { comment: newTopicParams.private } }; params.tags = newTopicParams.tags; } } params._topicName = topicName; this.setState({ newTopicParams: params }, _ => { this.handleTopicSelected(topicName); }); } handleNewTopicCreated(oldName, newName) { let nextState = {}; if (this.state.callShouldStart) { nextState = { callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_IN_PROGRESS, callShouldStart: false }; } if (this.state.topicSelected == oldName && oldName != newName) { nextState.topicSelected = newName; } this.setState(nextState, _ => { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlTopic('', newName)); }); } handleTopicUpdateRequest(topicName, pub, priv, defacs) { this.handleError(); const topic = this.tinode.getTopic(topicName); if (topic) { const params = {}; let attachments; if (pub) { if (pub.photo) { if (pub.photo.ref && pub.photo.ref != tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.DEL_CHAR) { attachments = [pub.photo.ref]; } else if (!pub.photo.data || pub.photo.data == tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.DEL_CHAR) { pub.photo = tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.DEL_CHAR; } } params.public = pub; } if (typeof priv == 'string') { params.private = priv === tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.DEL_CHAR ? tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.DEL_CHAR : { comment: priv }; } if (defacs) { params.defacs = defacs; } topic.setMeta({ desc: params, attachments: attachments }).catch(err => this.handleError(err.message, 'err')); } } handleUnarchive(topicName) { const topic = this.tinode.getTopic(topicName); if (topic) { topic.archive(false).catch(err => this.handleError(err.message, 'err')); } } handleUpdatePasswordRequest(password) { this.handleError(); if (password) { this.tinode.updateAccountBasic(null, this.tinode.getCurrentLogin(), password).catch(err => this.handleError(err.message, 'err')); } } handleChangePermissions(topicName, mode, uid) { const topic = this.tinode.getTopic(topicName); if (topic) { const am = topic.getAccessMode(); if (uid) { am.updateGiven(mode); mode = am.getGiven(); } else { am.updateWant(mode); mode = am.getWant(); } topic.setMeta({ sub: { user: uid, mode: mode } }).catch(err => this.handleError(err.message, 'err')); } } handleTagsUpdateRequest(topicName, tags) { const topic = this.tinode.getTopic(topicName); if (topic) { topic.setMeta({ tags: tags }).catch(err => this.handleError(err.message, 'err')); } } handleLogout() { (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_20__.updateFavicon)(0); localStorage.removeItem('auth-token'); localStorage.removeItem('firebase-token'); localStorage.removeItem('settings'); if (this.state.firebaseToken) { (0,firebase_messaging__WEBPACK_IMPORTED_MODULE_3__.deleteToken)(this.fcm); } clearInterval(this.reconnectCountdown); let cleared; if (this.tinode) { cleared = this.tinode.clearStorage(); this.tinode.onDisconnect = undefined; this.tinode.disconnect(); } else { cleared = Promose.resolve(); } this.setState(this.getBlankState()); cleared.then(_ => { this.tinode = TinodeWeb.tnSetup(this.state.serverAddress, (0,_lib_host_name_js__WEBPACK_IMPORTED_MODULE_16__.isSecureConnection)(), this.state.transport, this.props.intl.locale, _lib_local_storage_js__WEBPACK_IMPORTED_MODULE_17__["default"].getObject('keep-logged-in'), _ => { this.tinode.onConnect = this.handleConnected; this.tinode.onDisconnect = this.handleDisconnect; this.tinode.onAutoreconnectIteration = this.handleAutoreconnectIteration; this.tinode.onInfoMessage = this.handleInfoMessage; this.tinode.onDataMessage = this.handleDataMessage; _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(''); }); }); } handleDeleteAccount() { this.tinode.delCurrentUser(true).then(_ => { this.handleLogout(); }); } handleDeleteTopicRequest(topicName) { const topic = this.tinode.getTopic(topicName); if (!topic) { return; } topic.delTopic(true).then(_ => { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlTopic(window.location.hash, '')); }).catch(err => { this.handleError(err.message, 'err'); }); } handleDeleteMessagesRequest(topicName) { const topic = this.tinode.getTopic(topicName); if (!topic) { return; } topic.delMessagesAll(true).catch(err => this.handleError(err.message, 'err')); } handleLeaveUnsubRequest(topicName) { const topic = this.tinode.getTopic(topicName); if (!topic) { return; } topic.leave(true).then(_ => { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlTopic(window.location.hash, '')); }).catch(err => { this.handleError(err.message, 'err'); }); } handleBlockTopicRequest(topicName) { const topic = this.tinode.getTopic(topicName); if (!topic) { return; } topic.updateMode(null, '-JP').then(_ => { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlTopic(window.location.hash, '')); }).catch(err => this.handleError(err.message, 'err')); } handleReportTopic(topicName) { const topic = this.tinode.getTopic(topicName); if (!topic) { return; } this.tinode.report('report', topicName); topic.updateMode(null, '-JP').then(_ => { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlTopic(window.location.hash, '')); }).catch(err => this.handleError(err.message, 'err')); } handleShowContextMenu(params, menuItems) { this.setState({ contextMenuVisible: true, contextMenuClickAt: { x: params.x, y: params.y }, contextMenuParams: params, contextMenuItems: menuItems || this.defaultTopicContextMenu(params.topicName), contextMenuBounds: this.selfRef.current.getBoundingClientRect() }); } handleShowForwardDialog(params) { if (this.state.sidePanelSelected == 'newtpk') { this.handleSidepanelCancel(); } const header = '➦ ' + params.userName; const content = typeof params.content == 'string' ? tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.init(params.content) : tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.forwardedContent(params.content); const preview = tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.preview(content, _config_js__WEBPACK_IMPORTED_MODULE_12__.FORWARDED_PREVIEW_LENGTH, true); const msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.append(tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.appendLineBreak(tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.mention(header, params.userFrom)), content); const msgPreview = tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.quote(header, params.userFrom, preview); const head = { forwarded: params.topicName + ':' + params.seq }; this.setState({ forwardDialogVisible: true, forwardMessage: { head: head, msg: msg, preview: msgPreview } }); } defaultTopicContextMenu(topicName) { const topic = this.tinode.getTopic(topicName); if (topic._deleted) { return ['topic_delete']; } let muted = false, blocked = false, self_blocked = false, subscribed = false, deleter = false, archived = false, webrtc = false, writer = false; if (topic) { subscribed = topic.isSubscribed(); archived = topic.isArchived(); const acs = topic.getAccessMode(); if (acs) { muted = acs.isMuted(); blocked = !acs.isJoiner(); self_blocked = !acs.isJoiner('want'); deleter = acs.isDeleter(); writer = acs.isWriter(); } } webrtc = writer && !!this.tinode.getServerParam('iceServers'); const mediaServerAvailable = !!this.tinode.getServerParam('vcEndpoint'); return [subscribed ? { title: this.props.intl.formatMessage(messages.menu_item_info), handler: this.handleShowInfoView } : null, subscribed && tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isP2PTopicName(topicName) && webrtc ? { title: this.props.intl.formatMessage(messages.menu_item_audio_call), handler: this.handleStartAudioCall } : null, subscribed && webrtc ? { title: this.props.intl.formatMessage(messages.menu_item_video_call), disabled: tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isGroupTopicName(topicName) && !mediaServerAvailable, handler: this.handleStartVideoCall } : null, subscribed ? 'messages_clear' : null, subscribed && deleter ? 'messages_clear_hard' : null, muted ? blocked ? null : 'topic_unmute' : 'topic_mute', self_blocked ? 'topic_unblock' : 'topic_block', archived ? 'topic_restore' : 'topic_archive', 'topic_delete']; } handleHideContextMenu() { this.setState({ contextMenuVisible: false, contextMenuClickAt: null, contextMenuParams: null, contextMenuBounds: null }); } handleHideForwardDialog(keepForwardedMessage) { this.setState({ forwardDialogVisible: false, forwardMessage: keepForwardedMessage ? this.state.forwardMessage : null }); } handleContextMenuAction(action, promise, params) { if (action == 'topic_archive') { if (promise && params.topicName && params.topicName == this.state.topicSelected) { promise.then(_ => { this.handleTopicSelected(null); }); } } else if (action == 'menu_item_forward') { this.handleShowForwardDialog(params); } } handleShowAlert(title, content, onConfirm, confirmText, onReject, rejectText) { this.setState({ alertVisible: true, alertParams: { title: title, content: content, onConfirm: onConfirm, confirm: confirmText, onReject: onReject, reject: rejectText } }); } handleShowInfoView() { _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].addUrlParam(window.location.hash, 'info', 'info')); this.setState({ infoPanel: 'info' }); } handleMemberUpdateRequest(topicName, added, removed) { if (!topicName) { return; } const topic = this.tinode.getTopic(topicName); if (!topic) { return; } if (added && added.length > 0) { added.forEach(uid => { topic.invite(uid, null).catch(err => this.handleError(err.message, 'err')); }); } if (removed && removed.length > 0) { removed.forEach(uid => { topic.delSubscription(uid).catch(err => this.handleError(err.message, 'err')); }); } } handleValidateCredentialsRequest(cred, code, token) { if (this.tinode.isAuthenticated()) { this.tinode.getMeTopic().setMeta({ cred: { meth: cred, resp: code } }).then(_ => _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlSidePanel(window.location.hash, 'contacts'))).catch(err => this.handleError(err.message, 'err')); } else { this.setState({ credMethod: cred, credCode: code, credToken: token }); this.doLogin(null, null, token, { meth: cred, resp: code }); } } handlePasswordResetRequest(method, value) { return this.tinode.connect().then(_ => this.tinode.requestResetAuthSecret('basic', method, value)).catch(err => { this.handleError(err.message, 'err'); }); } handleResetPassword(newPassword, tempAuth) { const secret = (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_15__.base64ReEncode)(tempAuth.secret); if (!secret || !tempAuth.scheme) { this.handleError(this.props.intl.formatMessage(messages.invalid_security_token), 'err'); } else { this.tinode.connect().then(_ => this.tinode.updateAccountBasic(null, null, newPassword, { scheme: tempAuth.scheme, secret: secret })).then(_ => _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo('')).catch(err => { this.handleError(err.message, 'err'); }); } } handleShowCountrySelector(code, dial, selectedCallback) { this.handleShowAlert("Select country", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, { fallback: react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "loading_note", defaultMessage: [{ "type": 0, "value": "Loading..." }] })) }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(PhoneCountrySelector, { selected: code, onSubmit: (c, d) => { this.setState({ alertVisible: false }); selectedCallback(c, d); } })), null, null, _ => {}, "Cancel"); } handleStartVideoCall() { this.setState({ callTopic: this.state.topicSelected, callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_OUTGOING_INITATED, callAudioOnly: false }); } handleStartAudioCall() { this.setState({ callTopic: this.state.topicSelected, callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_OUTGOING_INITATED, callAudioOnly: true }); } handleCallInvite(callTopic, callSeq, callState, audioOnly) { switch (callState) { case _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_OUTGOING_INITATED: const head = { webrtc: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_HEAD_STARTED, aonly: !!audioOnly }; const msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Drafty.videoCall(audioOnly); if (tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isGroupTopicName(callTopic)) { head.vc = true; } return this.handleSendMessage(msg, undefined, undefined, head).then(ctrl => { if (ctrl.code < 200 || ctrl.code >= 300 || !ctrl.params || !ctrl.params.seq) { this.handleCallClose(); return ctrl; } this.setState({ callSeq: ctrl.params['seq'] }); return ctrl; }); break; case _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_IN_PROGRESS: const topic = this.tinode.getTopic(callTopic); if (!topic) { return; } topic.videoCall('accept', callSeq); break; } } handleCallRinging(callTopic, callSeq) { const topic = this.tinode.getTopic(callTopic); if (!topic) { return; } topic.videoCall('ringing', callSeq); } handleCallHangup(callTopic, callSeq) { const topic = this.tinode.getTopic(callTopic); if (!topic) { return; } topic.videoCall('hang-up', callSeq); } handleCallSendOffer(callTopic, callSeq, sdp) { const topic = this.tinode.getTopic(callTopic); if (!topic) { return; } topic.videoCall('offer', callSeq, sdp); } handleCallIceCandidate(callTopic, callSeq, candidate) { const topic = this.tinode.getTopic(callTopic); if (!topic) { return; } topic.videoCall('ice-candidate', callSeq, candidate); } handleCallSendAnswer(callTopic, callSeq, sdp) { const topic = this.tinode.getTopic(callTopic); if (!topic) { return; } topic.videoCall('answer', callSeq, sdp); } handleVCCallJoin(callTopic, callSeq) { const topic = this.tinode.getTopic(callTopic); if (!topic) { return; } topic.videoCall('vc-join', callSeq); } handleCallClose() { if (this.callTimeoutTimer) { clearTimeout(this.callTimeoutTimer); } this.setState({ callTopic: undefined, callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_NONE, callAudioOnly: undefined }); } handleCallAccept(topicName, setCallTopic, callSeq) { const topic = this.tinode.getTopic(topicName); if (!topic) { return; } if (topic.isSubscribed()) { this.handleTopicSelected(setCallTopic ? topicName : this.state.callTopic); const upd = { callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_IN_PROGRESS }; if (setCallTopic) { upd.callTopic = topicName; upd.callSeq = callSeq; } this.setState(upd); } else { this.setState({ callShouldStart: true }, _ => this.handleTopicSelected(this.state.callTopic)); } } handleInfoMessage(info) { if (info.what != 'call') { return; } switch (info.event) { case 'accept': if (tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isMeTopicName(info.topic) && this.tinode.isMe(info.from)) { this.setState({ callTopic: null, callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_NONE, callSeq: null, callAudioOnly: undefined }); return; } if (info.topic == this.state.callTopic) { this.setState({ callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_IN_PROGRESS }); } break; case 'hang-up': this.handleCallClose(); break; } } handleDataMessage(data) { if (data.head && data.head.webrtc && data.head.webrtc == _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_HEAD_STARTED && tinode_sdk__WEBPACK_IMPORTED_MODULE_4__.Tinode.isP2PTopicName(data.topic)) { const topic = this.tinode.getTopic(data.topic); if (topic) { const msg = topic.latestMsgVersion(data.seq) || data; if (msg.head && msg.head.webrtc && msg.head.webrtc == _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_HEAD_STARTED) { if (data.from != this.state.myUserId) { if (this.state.callState == _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_NONE) { this.setState({ callTopic: data.topic, callState: _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_INCOMING_RECEIVED, callSeq: data.seq, callAudioOnly: !!msg.head.aonly }); } else { this.handleCallHangup(data.topic, data.seq); } } } } else { console.warn("Received vc data message from unknown topic", data.topic); } } } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "app-container", ref: this.selfRef }, this.state.contextMenuVisible ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_context_menu_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], { tinode: this.tinode, bounds: this.state.contextMenuBounds, clickAt: this.state.contextMenuClickAt, params: this.state.contextMenuParams, items: this.state.contextMenuItems, hide: this.handleHideContextMenu, onShowAlert: this.handleShowAlert, onAction: this.handleContextMenuAction, onTopicRemoved: topicName => { if (topicName == this.state.topicSelected) { this.handleTopicSelected(null); } }, onError: this.handleError }) : null, this.state.forwardDialogVisible ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_forward_dialog_jsx__WEBPACK_IMPORTED_MODULE_7__["default"], { tinode: this.tinode, contacts: this.state.chatList, topicSelected: this.state.topicSelected, myUserId: this.state.myUserId, hide: this.handleHideForwardDialog, onInitFind: this.tnInitFind, searchResults: this.state.searchResults, onSearchContacts: this.handleSearchContacts, onTopicSelected: this.handleStartTopicRequest }) : null, this.state.callTopic && this.state.callState == _constants_js__WEBPACK_IMPORTED_MODULE_13__.CALL_STATE_INCOMING_RECEIVED ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_call_incoming_jsx__WEBPACK_IMPORTED_MODULE_8__["default"], { tinode: this.tinode, topic: this.state.callTopic, seq: this.state.callSeq, callState: this.state.callState, audioOnly: this.state.callAudioOnly, onClose: this.handleCallClose, onRinging: this.handleCallRinging, onAcceptCall: this.handleCallAccept, onReject: this.handleCallHangup }) : null, this.state.alertVisible ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_alert_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { title: this.state.alertParams.title, content: this.state.alertParams.content, onReject: this.state.alertParams.onReject ? _ => this.setState({ alertVisible: false }) : null, reject: this.state.alertParams.reject, onConfirm: this.state.alertParams.onConfirm ? _ => { this.setState({ alertVisible: false }); this.state.alertParams.onConfirm(); } : null, confirm: this.state.alertParams.confirm }) : null, !this.state.displayMobile || this.state.mobilePanel == 'sidepanel' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_sidepanel_view_jsx__WEBPACK_IMPORTED_MODULE_11__["default"], { tinode: this.tinode, connected: this.state.connected, displayMobile: this.state.displayMobile, state: this.state.sidePanelSelected, title: this.state.sidePanelTitle, avatar: this.state.sidePanelAvatar, trustedBadges: this.state.myTrustedBadges, login: this.state.login, persist: this.state.persist, myUserId: this.state.myUserId, loginDisabled: this.state.loginDisabled, loadSpinnerVisible: this.state.loadSpinnerVisible, errorText: this.state.errorText, errorLevel: this.state.errorLevel, errorAction: this.state.errorAction, errorActionText: this.state.errorActionText, topicSelected: this.state.topicSelected, chatList: this.state.chatList, credMethod: this.state.credMethod, credCode: this.state.credCode, credToken: this.state.credToken, transport: this.state.transport, messageSounds: this.state.messageSounds, desktopAlerts: this.state.desktopAlerts, desktopAlertsEnabled: this.state.desktopAlertsEnabled, incognitoMode: this.state.incognitoMode, serverAddress: this.state.serverAddress, secureConnection: this.state.secureConnection, serverVersion: this.state.serverVersion, reqCredMethod: this.state.reqCredMethod, onGlobalSettings: this.handleGlobalSettings, onSignUp: this.handleNewAccount, onSettings: this.handleSettings, onNavigate: this.basicNavigator, onLoginRequest: this.handleLoginRequest, onPersistenceChange: this.handlePersistenceChange, onCreateAccount: this.handleNewAccountRequest, onUpdateAccountDesc: this.handleTopicUpdateRequest, onUpdatePassword: this.handleUpdatePasswordRequest, onUpdateAccountTags: this.handleUpdateAccountTagsRequest, onTogglePushNotifications: this.toggleFCMToken, onToggleMessageSounds: this.handleToggleMessageSounds, onToggleIncognitoMode: this.handleToggleIncognitoMode, onCredAdd: this.handleCredAdd, onCredDelete: this.handleCredDelete, onCredConfirm: this.handleCredConfirm, onTopicSelected: this.handleTopicSelected, onCreateTopic: this.handleStartTopicRequest, onLogout: this.handleLogout, onDeleteAccount: this.handleDeleteAccount, onShowAlert: this.handleShowAlert, onCancel: this.handleSidepanelCancel, onError: this.handleError, onValidateCredentials: this.handleValidateCredentialsRequest, onPasswordResetRequest: this.handlePasswordResetRequest, onResetPassword: this.handleResetPassword, onShowArchive: this.handleShowArchive, onShowBlocked: this.handleShowBlocked, onShowCountrySelector: this.handleShowCountrySelector, onInitFind: this.tnInitFind, searchResults: this.state.searchResults, onSearchContacts: this.handleSearchContacts, showContextMenu: this.handleShowContextMenu }) : null, !this.state.displayMobile || this.state.mobilePanel == 'topic-view' && !this.state.infoPanel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_messages_view_jsx__WEBPACK_IMPORTED_MODULE_10__["default"], { tinode: this.tinode, connected: this.state.connected, ready: this.state.ready, online: this.state.topicSelectedOnline, acs: this.state.topicSelectedAcs, displayMobile: this.state.displayMobile, viewportWidth: this.state.viewportWidth, viewportHeight: this.state.viewportHeight, topic: this.state.topicSelected, myUserId: this.state.myUserId, myUserName: this.state.sidePanelTitle, serverVersion: this.state.serverVersion, serverAddress: this.state.serverAddress, applicationVisible: this.state.applicationVisible, forwardMessage: this.state.forwardMessage, onCancelForwardMessage: this.handleHideForwardDialog, callTopic: this.state.callTopic, callSeq: this.state.callSeq, callState: this.state.callState, callAudioOnly: this.state.callAudioOnly, onCallHangup: this.handleCallHangup, onAcceptCall: this.handleCallAccept, onCallInvite: this.handleCallInvite, onCallSendOffer: this.handleCallSendOffer, onCallIceCandidate: this.handleCallIceCandidate, onCallSendAnswer: this.handleCallSendAnswer, onVCJoin: this.handleVCCallJoin, errorText: this.state.errorText, errorLevel: this.state.errorLevel, errorAction: this.state.errorAction, errorActionText: this.state.errorActionText, newTopicParams: this.state.newTopicParams, onHideMessagesView: this.handleHideMessagesView, onError: this.handleError, onNewTopicCreated: this.handleNewTopicCreated, showContextMenu: this.handleShowContextMenu, onChangePermissions: this.handleChangePermissions, onNewChat: this.handleNewChatInvitation, sendMessage: this.handleSendMessage, onVideoCallClosed: this.handleCallClose }) : null, this.state.infoPanel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_info_view_jsx__WEBPACK_IMPORTED_MODULE_9__["default"], { tinode: this.tinode, connected: this.state.connected, displayMobile: this.state.displayMobile, topic: this.state.topicSelected, searchableContacts: this.state.searchableContacts, myUserId: this.state.myUserId, panel: this.state.infoPanel, errorText: this.state.errorText, errorLevel: this.state.errorLevel, errorAction: this.state.errorAction, errorActionText: this.state.errorActionText, onNavigate: this.infoNavigator, onTopicDescUpdateRequest: this.handleTopicUpdateRequest, onShowAlert: this.handleShowAlert, onChangePermissions: this.handleChangePermissions, onMemberUpdateRequest: this.handleMemberUpdateRequest, onDeleteTopic: this.handleDeleteTopicRequest, onDeleteMessages: this.handleDeleteMessagesRequest, onLeaveTopic: this.handleLeaveUnsubRequest, onBlockTopic: this.handleBlockTopicRequest, onReportTopic: this.handleReportTopic, onAddMember: this.handleManageGroupMembers, onTopicTagsUpdateRequest: this.handleTagsUpdateRequest, onTopicUnArchive: this.handleUnarchive, onInitFind: this.tnInitFind, onError: this.handleError, showContextMenu: this.handleShowContextMenu }) : null); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(TinodeWeb)); /***/ }), /***/ "./src/views/topic-common-view.jsx": /*!*****************************************!*\ !*** ./src/views/topic-common-view.jsx ***! \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ TopicCommonView) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _widgets_topic_desc_edit_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../widgets/topic-desc-edit.jsx */ "./src/widgets/topic-desc-edit.jsx"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); class TopicCommonView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); const topic = this.props.tinode.getTopic(this.props.topic); const acs = topic.getAccessMode(); this.state = { tags: [] }; this.previousTagsUpdated = undefined; this.onTagsUpdated = this.onTagsUpdated.bind(this); this.handleTagsUpdated = this.handleTagsUpdated.bind(this); } componentDidUpdate(props) { const topic = this.props.tinode.getTopic(props.topic); if (!topic) { return; } if (topic.onTagsUpdated != this.onTagsUpdated) { if (topic.getType() == 'grp') { this.previousTagsUpdated = topic.onTagsUpdated; topic.onTagsUpdated = this.onTagsUpdated; } else { this.previousTagsUpdated = undefined; } } if (this.state.topic != props.topic) { this.setState({ topic: props.topic }); } } componentWillUnmount() { const topic = this.props.tinode.getTopic(this.props.topic); topic.onTagsUpdated = this.previousTagsUpdated; } onTagsUpdated(tags) { this.setState({ tags: tags }); if (this.previousTagsUpdated && this.previousTagsUpdated != this.onTagsUpdated) { this.previousTagsUpdated(tags); } } handleTagsUpdated(tags) { if (!(0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_2__.arrayEqual)(this.state.tags.slice(0), tags.slice(0))) { this.props.onUpdateTagsRequest(this.props.topic, tags); } } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "scrollable-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_topic_desc_edit_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { tinode: this.props.tinode, topic: this.props.topic, onUpdateTopicDesc: this.props.onUpdateTopicDesc, onUpdateTags: this.handleTagsUpdated, onError: this.props.onError })); } } ; /***/ }), /***/ "./src/views/validation-view.jsx": /*!***************************************!*\ !*** ./src/views/validation-view.jsx ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ phone: { id: "phone_dative", defaultMessage: [{ "type": 0, "value": "phone" }] }, email: { id: "email_dative", defaultMessage: [{ "type": 0, "value": "email" }] } }); class ValidationView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { code: props.credCode || '', codeReceived: props.credCode }; this.handleCodeChange = this.handleCodeChange.bind(this); this.handleKeyPress = this.handleKeyPress.bind(this); this.handleSubmit = this.handleSubmit.bind(this); this.handleCancel = this.handleCancel.bind(this); } static getDerivedStateFromProps(nextProps, prevState) { if (nextProps.credCode != prevState.codeReceived) { return { code: nextProps.credCode || '', codeReceived: nextProps.credCode }; } return prevState; } componentDidMount() { if (this.props.credCode) { this.props.onSubmit(this.props.credMethod, this.props.credCode, this.props.credToken); } } componentDidUpdate(prevProps, prevState) { if (this.state.codeReceived && this.state.code && this.state.code != prevState.code) { this.props.onSubmit(this.props.credMethod, this.state.code, this.props.credToken); } } handleCodeChange(e) { this.setState({ code: e.target.value.replace(/[^\d]/g, '') }); } handleKeyPress(e) { if (e.key === 'Enter') { this.handleSubmit(e); } else if (e.key == 'Escape') { this.handleCancel(e); } } handleSubmit(e) { e.preventDefault(); if (this.state.code && this.state.code.trim()) { this.props.onSubmit(this.props.credMethod, this.state.code.trim(), this.props.credToken); } } handleCancel(e) { e.preventDefault(); this.props.onCancel(); } render() { const { formatMessage } = this.props.intl; const methods = { 'email': formatMessage(messages.email), 'tel': formatMessage(messages.phone) }; const method = methods[this.props.credMethod] || this.props.credMethod; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small gray", htmlFor: "enter-confirmation-code" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "enter_confirmation_code_prompt", defaultMessage: [{ "type": 0, "value": "Confirmation code" }], values: { method: method } }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "numeric_confirmation_code_prompt", defaultMessage: [{ "type": 0, "value": "Numbers only" }] }, numbers_only => react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", id: "enter-confirmation-code", placeholder: numbers_only, value: this.state.code, onChange: this.handleCodeChange, onKeyDown: this.handleKeyPress, required: true }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "dialog-buttons" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "secondary", onClick: this.handleCancel }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_cancel", defaultMessage: [{ "type": 0, "value": "Cancel" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "primary", onClick: this.handleSubmit }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_confirm", defaultMessage: [{ "type": 0, "value": "Confirm" }] })))); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(ValidationView)); /***/ }), /***/ "./src/widgets/alert.jsx": /*!*******************************!*\ !*** ./src/widgets/alert.jsx ***! \*******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ Alert) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); class Alert extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "alert-container" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "alert" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "title" }, this.props.title), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "content" }, this.props.content), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "dialog-buttons" }, this.props.onReject ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "outline", onClick: this.props.onReject }, this.props.reject || react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_cancel", defaultMessage: [{ "type": 0, "value": "Cancel" }] })) : null, this.props.onConfirm ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "primary", onClick: this.props.onConfirm }, this.props.confirm || react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_ok", defaultMessage: [{ "type": 0, "value": "OK" }] })) : null))); } } ; /***/ }), /***/ "./src/widgets/attachment.jsx": /*!************************************!*\ !*** ./src/widgets/attachment.jsx ***! \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ Attachment) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _file_progress_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./file-progress.jsx */ "./src/widgets/file-progress.jsx"); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); class Attachment extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { downloader: null, progress: 0 }; this.downloadFile = this.downloadFile.bind(this); this.handleCancel = this.handleCancel.bind(this); } downloadFile(url, filename, mimetype) { if (!url) { this.props.onError("Invalid download URL '" + url + "'"); return; } const downloader = this.props.tinode.getLargeFileHelper(); this.setState({ downloader: downloader }); downloader.download(url, filename, mimetype, loaded => this.setState({ progress: loaded / this.props.size }), err => this.props.onError(err, 'err')).then(_ => this.setState({ downloader: null, progress: 0 })).catch(err => { if (err) { this.props.onError("Error downloading file: " + err.message, 'err'); } this.setState({ downloader: null, progress: 0 }); }); } handleCancel() { if (this.props.uploading) { this.props.onCancelUpload(); } else if (this.state.downloader) { this.state.downloader.cancel(); } } render() { let filename = this.props.filename || 'file_attachment'; if (filename.length > 36) { filename = filename.substr(0, 16) + '...' + filename.substr(-16); } let size = this.props.size > 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "small gray" }, "(", (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_3__.bytesToHumanSize)(this.props.size), ")") : null; let url, helperFunc; if (!this.props.uploading && !this.state.downloader && (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_4__.isUrlRelative)(this.props.downloadUrl)) { url = '#'; helperFunc = e => { e.preventDefault(); this.downloadFile(this.props.downloadUrl, this.props.filename, this.props.mimetype); }; } else { url = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_4__.sanitizeUrl)(this.props.downloadUrl); helperFunc = null; } const downloadWidget = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "file_download"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "save_attachment", defaultMessage: [{ "type": 0, "value": "save" }] })); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "attachment" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons big gray" }, "insert_drive_file")), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "flex-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, filename, " ", size), this.props.uploading || this.state.downloader ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_file_progress_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { progress: this.props.uploading ? this.props.progress : this.state.progress, onCancel: this.handleCancel }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, url ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: url, download: this.props.filename, onClick: helperFunc }, downloadWidget) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "light-gray" }, downloadWidget)))); } } ; /***/ }), /***/ "./src/widgets/audio-player.jsx": /*!**************************************!*\ !*** ./src/widgets/audio-player.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _lib_strformat__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/strformat */ "./src/lib/strformat.js"); /* harmony import */ var _lib_blob_helpers__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/blob-helpers */ "./src/lib/blob-helpers.js"); const CANVAS_UPSCALING = 2.0; const LINE_WIDTH = 3 * CANVAS_UPSCALING; const SPACING = 2 * CANVAS_UPSCALING; const BAR_COLOR = '#888A'; const BAR_COLOR_DARK = '#666C'; const THUMB_COLOR = '#444E'; const MIN_PREVIEW_LENGTH = 16; const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ icon_title_play: { id: "icon_title_play", defaultMessage: [{ "type": 0, "value": "Play recording" }] } }); class AudioPlayer extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); let preview = (0,_lib_blob_helpers__WEBPACK_IMPORTED_MODULE_3__.base64ToIntArray)(this.props.preview); if (!Array.isArray(preview) || preview.length < MIN_PREVIEW_LENGTH) { preview = null; } this.state = { canPlay: false, playing: false, currentTime: '0:00', duration: this.props.duration > 0 ? (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_2__.secondsToTime)(this.props.duration / 1000) : '-:--', longMin: this.props.duration >= 600000, preview: preview }; this.initAudio = this.initAudio.bind(this); this.initCanvas = this.initCanvas.bind(this); this.resampleBars = this.resampleBars.bind(this); this.visualize = this.visualize.bind(this); this.handlePlay = this.handlePlay.bind(this); this.handleSeek = this.handleSeek.bind(this); this.handleError = this.handleError.bind(this); this.audioPlayer = null; this.viewBuffer = []; this.canvasRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); } componentDidMount() { if (this.props.src) { this.initAudio(); } this.initCanvas(); } componentWillUnmount() { if (this.audioPlayer) { this.audioPlayer.onloadedmetadata = null; this.audioPlayer.ontimeupdate = null; this.audioPlayer.onended = null; this.audioPlayer.pause(); this.audioPlayer = null; } } componentDidUpdate(prevProps) { if (this.props.src != prevProps.src) { this.initAudio(); } if (this.props.preview != prevProps.preview) { let preview = (0,_lib_blob_helpers__WEBPACK_IMPORTED_MODULE_3__.base64ToIntArray)(this.props.preview); if (!Array.isArray(preview) || preview.length < MIN_PREVIEW_LENGTH) { preview = null; } this.setState({ preview: preview }, this.initCanvas); } } initAudio() { this.audioPlayer = new Audio(this.props.src); this.audioPlayer.onloadedmetadata = _ => this.setState({ canPlay: true }); this.audioPlayer.ontimeupdate = _ => this.setState({ currentTime: (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_2__.secondsToTime)(this.audioPlayer.currentTime, this.state.longMin) }); this.audioPlayer.onended = _ => { this.audioPlayer.currentTime = 0; this.setState({ playing: false, currentTime: (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_2__.secondsToTime)(0, this.state.longMin) }); }; } initCanvas() { this.canvasRef.current.width = this.canvasRef.current.offsetWidth * CANVAS_UPSCALING; this.canvasRef.current.height = this.canvasRef.current.offsetHeight * CANVAS_UPSCALING; this.canvasContext = this.canvasRef.current.getContext('2d'); this.canvasContext.lineCap = 'round'; this.viewBuffer = this.resampleBars(this.state.preview); this.visualize(); } visualize() { if (!this.canvasRef.current) { return; } const width = this.effectiveWidth; const height = this.canvasRef.current.height; this.canvasContext.lineWidth = LINE_WIDTH; const drawFrame = _ => { if (!this.canvasRef.current || !this.audioPlayer) { return; } this.canvasContext.clearRect(0, 0, this.canvasRef.current.width, height); if (this.viewBuffer) { if (this.state.playing) { window.requestAnimationFrame(drawFrame); } const thumbAt = this.props.duration ? Math.max(0, Math.min(this.audioPlayer.currentTime * 1000 / this.props.duration, 1)) * (width - LINE_WIDTH * 2) : -1; this.canvasContext.beginPath(); this.canvasContext.strokeStyle = BAR_COLOR_DARK; for (let i = 0; i < this.viewBuffer.length; i++) { let x = 1 + i * (LINE_WIDTH + SPACING) + LINE_WIDTH * 0.5; let y = Math.max(this.viewBuffer[i] * height * 0.9, 1); const color = x < thumbAt ? BAR_COLOR_DARK : BAR_COLOR; if (this.canvasContext.strokeStyle != color) { this.canvasContext.stroke(); this.canvasContext.beginPath(); this.canvasContext.strokeStyle = color; } this.canvasContext.moveTo(x, (height - y) * 0.5); this.canvasContext.lineTo(x, (height + y) * 0.5); } this.canvasContext.stroke(); if (this.props.duration) { this.canvasContext.beginPath(); this.canvasContext.arc(thumbAt + LINE_WIDTH * 2, height * 0.5, LINE_WIDTH * 2, 0, 2 * Math.PI); this.canvasContext.fillStyle = THUMB_COLOR; this.canvasContext.fill(); } } }; drawFrame(); } resampleBars(original) { const dstCount = (this.canvasRef.current.width - SPACING) / (LINE_WIDTH + SPACING) | 0; this.effectiveWidth = dstCount * (LINE_WIDTH + SPACING) + SPACING; if (!Array.isArray(original) || original.length == 0) { return Array.apply(null, Array(dstCount)).map(_ => 0.01); } const factor = original.length / dstCount; let amps = []; let maxAmp = -1; for (let i = 0; i < dstCount; i++) { let lo = i * factor | 0; let hi = (i + 1) * factor | 0; if (hi == lo) { amps[i] = original[lo]; } else { let amp = 0.0; for (let j = lo; j < hi; j++) { amp += original[j]; } amps[i] = Math.max(0, amp / (hi - lo)); } maxAmp = Math.max(amps[i], maxAmp); } if (maxAmp > 0) { return amps.map(a => a / maxAmp); } return Array.apply(null, Array(dstCount)).map(_ => 0.01); } handlePlay(e) { e.preventDefault(); if (!this.state.canPlay) { return; } if (this.state.playing) { this.audioPlayer.pause(); this.setState({ playing: false }); } else if (this.audioPlayer.readyState >= 2) { this.audioPlayer.play(); this.setState({ playing: true }, this.visualize); } } handleError(err) { console.error(err); } handleSeek(e) { e.preventDefault(); if (e.target && this.props.duration) { const rect = e.target.getBoundingClientRect(); const offset = (e.clientX - rect.left) / this.effectiveWidth * CANVAS_UPSCALING; this.audioPlayer.currentTime = this.props.duration * offset / 1000; this.setState({ currentTime: (0,_lib_strformat__WEBPACK_IMPORTED_MODULE_2__.secondsToTime)(this.audioPlayer.currentTime, this.state.longMin) }); if (!this.state.playing) { this.visualize(); } } } render() { const playClass = 'material-icons' + (this.props.short ? '' : ' large') + (this.state.canPlay ? '' : ' disabled'); const play = react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handlePlay, title: this.props.intl.formatMessage(messages.icon_title_play) }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: playClass }, this.state.playing ? 'pause_circle' : this.state.canPlay ? 'play_circle' : 'not_interested')); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "audio-player" }, this.props.short ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("canvas", { className: "playback", ref: this.canvasRef, onClick: this.handleSeek }), play) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, play, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("canvas", { className: "playback", ref: this.canvasRef, onClick: this.handleSeek }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "timer" }, this.state.currentTime, "/", this.state.duration)))); } } /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(AudioPlayer)); /***/ }), /***/ "./src/widgets/avatar-crop.jsx": /*!*************************************!*\ !*** ./src/widgets/avatar-crop.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ AvatarCrop) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _cropper_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./cropper.jsx */ "./src/widgets/cropper.jsx"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); class AvatarCrop extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { top: 0, left: 0, width: 0, height: 0, scale: 1 }; this.handleSubmit = this.handleSubmit.bind(this); this.handleChange = this.handleChange.bind(this); } handleChange(left, top, width, height, scale) { this.setState({ left: left, top: top, width: width, height: height, scale: scale }); } handleSubmit() { (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_3__.imageCrop)(this.props.mime, this.props.avatar, this.state.left, this.state.top, this.state.width, this.state.height, this.state.scale).then(img => { this.props.onSubmit(img.mime, img.blob, img.width, img.height); }).catch(err => { this.props.onError(err); }); } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_cropper_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { source: this.props.avatar, onChange: this.handleChange })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "dialog-buttons" }, this.props.onCancel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "secondary", onClick: this.props.onCancel }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_cancel", defaultMessage: [{ "type": 0, "value": "Cancel" }] })) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "primary", onClick: this.handleSubmit }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_ok", defaultMessage: [{ "type": 0, "value": "OK" }] })))); } } ; /***/ }), /***/ "./src/widgets/avatar-upload.jsx": /*!***************************************!*\ !*** ./src/widgets/avatar-upload.jsx ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ AvatarUpload) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _load_spinner_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./load-spinner.jsx */ "./src/widgets/load-spinner.jsx"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); class AvatarUpload extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { source: props.avatar }; this.handleFileReceived = this.handleFileReceived.bind(this); } componentDidUpdate(prevProps) { if (this.props.avatar != prevProps.avatar) { this.setState({ source: this.props.avatar }); } } handleFileReceived(e) { const image = e.target.files[0]; this.props.onImageUpdated(image.type, URL.createObjectURL(image), image.name); e.target.value = ''; } render() { const randId = 'file-input-avatar-' + ('' + Math.random()).substring(0, 4); const className = 'avatar-upload' + (this.props.readOnly ? ' read-only' : ''); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: className }, this.props.readOnly || !this.state.source ? null : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "clear-avatar", onClick: e => { e.preventDefault(); this.props.onImageUpdated(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "clear")), this.state.source ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { src: this.props.tinode.authorizeURL((0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_3__.sanitizeUrlForMime)(this.state.source, 'image')), className: "preview" }) : this.props.readOnly && this.props.uid ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "avatar-box" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { tinode: this.props.tinode, avatar: true, topic: this.props.uid, title: this.props.title })) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "blank" }, _config_js__WEBPACK_IMPORTED_MODULE_4__.AVATAR_SIZE, "\xD7", _config_js__WEBPACK_IMPORTED_MODULE_4__.AVATAR_SIZE), this.props.readOnly ? null : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "file", id: randId, className: "inputfile hidden", accept: "image/*", onChange: this.handleFileReceived }), this.props.readOnly ? null : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { htmlFor: randId, className: "round" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "file_upload")), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_load_spinner_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { show: this.props.uploading, large: true, clear: true, centered: true })); } } ; /***/ }), /***/ "./src/widgets/badge-list.jsx": /*!************************************!*\ !*** ./src/widgets/badge-list.jsx ***! \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); const icon_mapping = { 'staff': 'verified_user' }; const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ badge_verified: { id: "badge_verified", defaultMessage: [{ "type": 0, "value": "Verified/official" }] }, badge_staff: { id: "badge_staff", defaultMessage: [{ "type": 0, "value": "Staff-managed" }] }, badge_danger: { id: "badge_danger", defaultMessage: [{ "type": 0, "value": "Untrustworthy" }] } }); class BadgeList extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { const { formatMessage } = this.props.intl; let badges = null; if (this.props.trustedBadges && this.props.trustedBadges.length > 0) { badges = []; this.props.trustedBadges.forEach(b => { const comment = this.props.short ? null : formatMessage(messages['badge_' + b]); const style = 'material-icons ' + b + '-color'; badges.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "trusted-badge", key: b }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: style }, icon_mapping[b] || b), " ", comment)); }); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, badges); } return null; } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(BadgeList)); /***/ }), /***/ "./src/widgets/button-back.jsx": /*!*************************************!*\ !*** ./src/widgets/button-back.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ ButtonBack) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); class ButtonBack extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onBack(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "arrow_back")); } } /***/ }), /***/ "./src/widgets/call-incoming.jsx": /*!***************************************!*\ !*** ./src/widgets/call-incoming.jsx ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ CallIncoming) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _badge_list_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./badge-list.jsx */ "./src/widgets/badge-list.jsx"); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../constants.js */ "./src/constants.js"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); const RING_SOUND = new Audio('audio/call-in.m4a'); class CallIncoming extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { topic: null, fullName: undefined, avatar: null, trustedBadges: [], previousMetaDesc: undefined }; this.resetDesc = this.resetDesc.bind(this); this.onMetaDesc = this.onMetaDesc.bind(this); this.handleRejectCall = this.handleRejectCall.bind(this); this.handleAcceptCall = this.handleAcceptCall.bind(this); this.ringTimer = null; } componentDidMount() { const topic = this.props.tinode.getTopic(this.props.topic); if (!topic) { return; } this.resetDesc(topic); if (this.props.callState == _constants_js__WEBPACK_IMPORTED_MODULE_4__.CALL_STATE_INCOMING_RECEIVED) { RING_SOUND.play().catch(_ => {}); this.ringTimer = setInterval(_ => { RING_SOUND.play().catch(_ => {}); }, 2000); this.props.onRinging(this.props.topic, this.props.seq); } } componentDidUpdate(props) { const topic = this.props.tinode.getTopic(props.topic); if (!topic) { return; } if (this.onMetaDesc != topic.onMetaDesc) { this.previousMetaDesc = topic.onMetaDesc; topic.onMetaDesc = this.onMetaDesc; } if (this.state.topic != props.topic) { this.setState({ topic: props.topic }); this.resetDesc(topic, props); } } componentWillUnmount() { if (this.ringTimer != null) { clearInterval(this.ringTimer); RING_SOUND.pause(); } const topic = this.props.tinode.getTopic(this.props.topic); if (!topic) { return; } this.setState({ topic: null }); topic.onMetaDesc = this.previousMetaDesc; } resetDesc(topic) { const badges = []; if (topic.trusted) { for (const [key, val] of Object.entries(topic.trusted)) { if (val) { badges.push(key); } } } this.setState({ fullName: (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_6__.clipStr)(topic.public ? topic.public.fn : undefined, _config_js__WEBPACK_IMPORTED_MODULE_3__.MAX_TITLE_LENGTH), avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_5__.makeImageUrl)(topic.public ? topic.public.photo : null), trustedBadges: badges }); } onMetaDesc(desc) { const topic = this.props.tinode.getTopic(this.props.topic); if (!topic) { return; } this.resetDesc(topic); if (this.previousMetaDesc && this.previousMetaDesc != this.onMetaDesc) { this.previousMetaDesc(desc); } } handleAcceptCall() { this.props.onAcceptCall(this.props.topic); } handleRejectCall() { this.props.onReject(this.props.topic, this.props.seq); this.props.onClose(); } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "alert-container" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "incoming-call" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "caller-card incoming pulse" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "avatar-box" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { tinode: this.props.tinode, avatar: this.state.avatar || true, topic: this.props.topic, title: this.state.fullName })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "caller-name" }, (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_6__.clipStr)(this.state.fullName, _config_js__WEBPACK_IMPORTED_MODULE_3__.MAX_PEER_TITLE_LENGTH), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_badge_list_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { short: true, trustedBadges: this.state.trustedBadges }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "controls" }, this.props.callState == _constants_js__WEBPACK_IMPORTED_MODULE_4__.CALL_STATE_INCOMING_RECEIVED ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "danger", onClick: this.handleRejectCall }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "call_end")), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "positive", onClick: this.handleAcceptCall }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "call"))) : null))); } } ; /***/ }), /***/ "./src/widgets/call-message.jsx": /*!**************************************!*\ !*** ./src/widgets/call-message.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ CallMessage) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); class CallMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { const bigIcon = this.props.vc ? 'video_call' : 'call'; const isCallDropped = ['busy', 'declined', 'disconnected', 'missed'].includes(this.props.callState); const successClass = 'material-icons medium ' + (isCallDropped ? 'red' : 'green'); const callIcon = this.props.incoming ? isCallDropped ? 'call_missed' : 'call_received' : isCallDropped ? 'call_missed_outgoing' : 'call_made'; const title = this.props.vc ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "calls_conference", defaultMessage: [{ "type": 0, "value": "Conference call" }] }) : this.props.incoming ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "calls_incoming", defaultMessage: [{ "type": 0, "value": "Incoming call" }] }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "calls_outgoing", defaultMessage: [{ "type": 0, "value": "Outgoing call" }] }); let duration; if (isCallDropped) { switch (this.props.callState) { case 'busy': duration = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_busy", defaultMessage: [{ "type": 0, "value": "busy" }] }); break; case 'declined': duration = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_declined", defaultMessage: [{ "type": 0, "value": "declined" }] }); break; case 'missed': duration = this.props.incoming ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_missed", defaultMessage: [{ "type": 0, "value": "missed" }] }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_cancelled", defaultMessage: [{ "type": 0, "value": "cancelled" }] }); break; default: duration = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_disconnected", defaultMessage: [{ "type": 0, "value": "disconnected" }] }); break; } } else { duration = react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_2__.secondsToTime)(this.props.duration / 1000)); } const allowJoin = this.props.vc && this.props.callState == 'started'; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "call-message" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons big gray" }, bigIcon)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "flex-column narrow" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, title), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "duration" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: successClass }, callIcon), " ", duration), allowJoin ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { onClick: this.props.onCallJoin }, "Join") : null)); } } /***/ }), /***/ "./src/widgets/call-panel.jsx": /*!************************************!*\ !*** ./src/widgets/call-panel.jsx ***! \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../constants.js */ "./src/constants.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); const RING_SOUND = new Audio('audio/call-out.m4a'); RING_SOUND.loop = true; const CALL_ENDED_SOUND = new Audio('audio/call-end.m4a'); CALL_ENDED_SOUND.loop = true; const DIALING_SOUND = new Audio('audio/dialing.m4a'); const VIDEO_MUTED_EVENT = 'video:muted'; const VIDEO_UNMUTED_EVENT = 'video:unmuted'; const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ already_in_call: { id: "already_in_call", defaultMessage: [{ "type": 0, "value": "You already in an ongoing call!" }] } }); class CallPanel extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { localStream: undefined, remoteStream: undefined, pc: undefined, dataChannel: undefined, previousOnInfo: undefined, waitingForPeer: false, callInitialSetupComplete: false, audioOnly: props.callAudioOnly, videoToggleInProgress: false, remoteVideoLive: false }; this.localStreamConstraints = { audio: true, video: !props.callAudioOnly }; this.isOutgoingCall = props.callState == _constants_js__WEBPACK_IMPORTED_MODULE_4__.CALL_STATE_OUTGOING_INITATED; this.localRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.remoteRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.remoteIceCandidatesCache = []; this.onInfo = this.onInfo.bind(this); this.start = this.start.bind(this); this.stop = this.stop.bind(this); this.createPeerConnection = this.createPeerConnection.bind(this); this.canSendOffer = this.canSendOffer.bind(this); this.drainRemoteIceCandidatesCache = this.drainRemoteIceCandidatesCache.bind(this); this.handleNegotiationNeededEvent = this.handleNegotiationNeededEvent.bind(this); this.handleICECandidateEvent = this.handleICECandidateEvent.bind(this); this.handleNewICECandidateMsg = this.handleNewICECandidateMsg.bind(this); this.handleICEConnectionStateChangeEvent = this.handleICEConnectionStateChangeEvent.bind(this); this.handleSignalingStateChangeEvent = this.handleSignalingStateChangeEvent.bind(this); this.handleICEGatheringStateChangeEvent = this.handleICEGatheringStateChangeEvent.bind(this); this.handleIceCandidateErrorEvent = this.handleIceCandidateErrorEvent.bind(this); this.handleTrackEvent = this.handleTrackEvent.bind(this); this.handleVideoOfferMsg = this.handleVideoOfferMsg.bind(this); this.handleVideoAnswerMsg = this.handleVideoAnswerMsg.bind(this); this.handleNewICECandidateMsg = this.handleNewICECandidateMsg.bind(this); this.reportError = this.reportError.bind(this); this.handleGetUserMediaError = this.handleGetUserMediaError.bind(this); this.stopTracks = this.stopTracks.bind(this); this.disconnectMedia = this.disconnectMedia.bind(this); this.handleCloseClick = this.handleCloseClick.bind(this); this.handleToggleCameraClick = this.handleToggleCameraClick.bind(this); this.handleToggleMicClick = this.handleToggleMicClick.bind(this); this.handleRemoteHangup = this.handleRemoteHangup.bind(this); this.handleVideoCallAccepted = this.handleVideoCallAccepted.bind(this); this.muteVideo = this.muteVideo.bind(this); this.unmuteVideo = this.unmuteVideo.bind(this); this.emptyVideoTrack = this.emptyVideoTrack.bind(this); this.handleDataChannelEvent = this.handleDataChannelEvent.bind(this); this.handleDataChannelError = this.handleDataChannelError.bind(this); this.handleDataChannelMessage = this.handleDataChannelMessage.bind(this); this.handleDataChannelOpen = this.handleDataChannelOpen.bind(this); this.handleDataChannelClose = this.handleDataChannelClose.bind(this); } componentDidMount() { const topic = this.props.tinode.getTopic(this.props.topic); this.previousOnInfo = topic.onInfo; topic.onInfo = this.onInfo; if ((this.props.callState == _constants_js__WEBPACK_IMPORTED_MODULE_4__.CALL_STATE_OUTGOING_INITATED || this.props.callState == _constants_js__WEBPACK_IMPORTED_MODULE_4__.CALL_STATE_IN_PROGRESS) && this.localRef.current) { this.start(); } } componentWillUnmount() { const topic = this.props.tinode.getTopic(this.props.topic); topic.onInfo = this.previousOnInfo; this.stop(); } handleVideoCallAccepted(info) { RING_SOUND.pause(); const pc = this.createPeerConnection(true); const stream = this.state.localStream; stream.getTracks().forEach(track => { pc.addTrack(track, stream); if (track.kind == 'video' && this.state.audioOnly) { track.enabled = false; track.stop(); stream.removeTrack(track); } }); } onInfo(info) { if (info.what != 'call') { return; } switch (info.event) { case 'accept': this.handleVideoCallAccepted(info); break; case 'answer': this.handleVideoAnswerMsg(info); break; case 'ice-candidate': this.handleNewICECandidateMsg(info); break; case 'hang-up': this.handleRemoteHangup(info); break; case 'offer': this.handleVideoOfferMsg(info); break; case 'ringing': RING_SOUND.play().catch(_ => {}); break; default: console.warn("Unknown call event", info.event); break; } } emptyVideoTrack() { const width = 640; const height = 480; const canvas = Object.assign(document.createElement("canvas"), { width, height }); canvas.getContext('2d').fillRect(0, 0, width, height); const stream = canvas.captureStream(0); return Object.assign(stream.getVideoTracks()[0], { enabled: false }); } start() { if (this.state.localStream) { this.props.onError(this.props.intl.formatMessage(messages.already_in_call), 'info'); return; } if (this.props.callState == _constants_js__WEBPACK_IMPORTED_MODULE_4__.CALL_STATE_IN_PROGRESS) { this.props.onInvite(this.props.topic, this.props.seq, _constants_js__WEBPACK_IMPORTED_MODULE_4__.CALL_STATE_IN_PROGRESS, this.props.callAudioOnly); return; } navigator.mediaDevices.getUserMedia(this.localStreamConstraints).then(stream => { if (!this.localStreamConstraints.video) { stream.addTrack(this.emptyVideoTrack()); } this.setState({ localStream: stream, waitingForPeer: true }); this.localRef.current.srcObject = stream; DIALING_SOUND.play(); this.props.onInvite(this.props.topic, this.props.seq, this.props.callState, this.props.callAudioOnly); }).catch(this.handleGetUserMediaError); } stop() { CALL_ENDED_SOUND.pause(); CALL_ENDED_SOUND.currentTime = 0; RING_SOUND.pause(); RING_SOUND.currentTime = 0; this.stopTracks(this.state.localStream); this.stopTracks(this.state.remoteStream); this.disconnectMedia(this.localRef.current); this.disconnectMedia(this.remoteRef.current); if (this.state.pc) { this.state.pc.ontrack = null; this.state.pc.onremovetrack = null; this.state.pc.onremovestream = null; this.state.pc.onicecandidate = null; this.state.pc.oniceconnectionstatechange = null; this.state.pc.onsignalingstatechange = null; this.state.pc.onicegatheringstatechange = null; this.state.pc.onnegotiationneeded = null; this.state.pc.onicecandidateerror = null; this.state.pc.ondatachannel = null; if (this.state.dataChannel && (this.state.dataChannel.readyState == 'open' || this.state.dataChannel.readyState == 'connecting')) { this.state.dataChannel.close(); } this.state.pc.close(); } this.setState({ pc: null, waitingForPeer: false }); } disconnectMedia(el) { if (!el) { return; } el.srcObject = null; el.src = ''; } stopTracks(stream) { if (!stream) { return; } let tracks = stream.getTracks(); if (tracks) { tracks.forEach(track => { track.stop(); track.enabled = false; }); } } handleDataChannelError(error) { console.error('data channel error', error); } handleDataChannelMessage(event) { switch (event.data) { case VIDEO_MUTED_EVENT: this.setState({ remoteVideoLive: false }, _ => { this.remoteRef.current.srcObject = this.state.remoteStream; }); break; case VIDEO_UNMUTED_EVENT: this.setState({ remoteVideoLive: true }, _ => { this.remoteRef.current.srcObject = this.state.remoteStream; }); break; default: break; } } handleDataChannelOpen(event) { if (!this.state.audioOnly) { event.target.send(VIDEO_UNMUTED_EVENT); } } handleDataChannelClose(event) { console.log('close data channel:', event); } handleDataChannelEvent(event) { console.log('data channel event:', event); const channel = event.channel; channel.onerror = this.handleDataChannelError; channel.onmessage = this.handleDataChannelMessage; channel.onopen = this.handleDataChannelOpen; channel.onclose = this.handleDataChannelClose; this.setState({ dataChannel: channel }); } createPeerConnection(withDataChannel) { const iceServers = this.props.tinode.getServerParam('iceServers', null); const pc = iceServers ? new RTCPeerConnection({ iceServers: iceServers }) : new RTCPeerConnection(); pc.onicecandidate = this.handleICECandidateEvent; pc.oniceconnectionstatechange = this.handleICEConnectionStateChangeEvent; pc.onicegatheringstatechange = this.handleICEGatheringStateChangeEvent; pc.onsignalingstatechange = this.handleSignalingStateChangeEvent; pc.onnegotiationneeded = this.handleNegotiationNeededEvent; pc.onicecandidateerror = this.handleIceCandidateErrorEvent; pc.ontrack = this.handleTrackEvent; pc.ondatachannel = this.handleDataChannelEvent; let stateUpdate = { pc: pc, waitingForPeer: false }; if (withDataChannel) { const channel = pc.createDataChannel("events", { ordered: true }); channel.onerror = this.handleDataChannelError; channel.onmessage = this.handleDataChannelMessage; channel.onopen = this.handleDataChannelOpen; channel.onclose = this.handleDataChannelClose; stateUpdate.dataChannel = channel; } this.setState(stateUpdate); return pc; } handleVideoAnswerMsg(info) { const desc = new RTCSessionDescription(info.payload); this.state.pc.setRemoteDescription(desc).then(_ => { this.setState({ callInitialSetupComplete: true }, _ => this.drainRemoteIceCandidatesCache()); }).catch(err => this.reportError(err)); } reportError(err) { this.props.onError(err.message, 'err'); } canSendOffer() { return this.isOutgoingCall || this.state.callInitialSetupComplete; } handleNegotiationNeededEvent(event) { const pc = event.target; if (!this.canSendOffer()) { return; } pc.createOffer().then(offer => { return pc.setLocalDescription(offer); }).then(_ => { this.props.onSendOffer(this.props.topic, this.props.seq, pc.localDescription.toJSON()); }).catch(err => this.reportError(err)); } handleIceCandidateErrorEvent(event) { console.warn("ICE candidate error:", event); } handleICECandidateEvent(event) { if (event.candidate) { this.props.onIceCandidate(this.props.topic, this.props.seq, event.candidate.toJSON()); } } handleNewICECandidateMsg(info) { const candidate = new RTCIceCandidate(info.payload); if (this.state.callInitialSetupComplete) { this.state.pc.addIceCandidate(candidate).catch(err => { if (candidate.candidate) { this.reportError(err); } console.warn("Error adding new ice candidate", candidate, err); }); } else { this.remoteIceCandidatesCache.push(candidate); } } drainRemoteIceCandidatesCache() { this.remoteIceCandidatesCache.forEach(candidate => { this.state.pc.addIceCandidate(candidate).catch(err => { if (candidate.candidate) { this.reportError(err); } console.warn("Error adding cached ice candidate", candidate, err); }); }); this.remoteIceCandidatesCache = []; } handleICEConnectionStateChangeEvent(event) { switch (event.target.iceConnectionState) { case 'closed': case 'failed': this.handleCloseClick(); break; } } handleSignalingStateChangeEvent(event) { if (event.target.signalingState == 'closed') { this.handleCloseClick(); } } handleICEGatheringStateChangeEvent(event) {} handleTrackEvent(event) { this.remoteRef.current.srcObject = event.streams[0]; this.setState({ remoteStream: event.streams[0] }); } handleGetUserMediaError(e) { console.error("Error opening camera and/or microphone", e); switch (e.name) { case 'NotFoundError': this.reportError(e); break; case 'SecurityError': case 'PermissionDeniedError': break; default: this.reportError(e); break; } this.handleCloseClick(); } handleVideoOfferMsg(info) { let localStream = null; const pc = this.state.pc ? this.state.pc : this.createPeerConnection(false); const desc = new RTCSessionDescription(info.payload); pc.setRemoteDescription(desc).then(_ => { return navigator.mediaDevices.getUserMedia(this.localStreamConstraints); }).then(stream => { let dummyVideo; if (!this.localStreamConstraints.video) { dummyVideo = this.emptyVideoTrack(); stream.addTrack(dummyVideo); } localStream = stream; this.localRef.current.srcObject = stream; this.setState({ localStream: stream }); localStream.getTracks().forEach(track => { pc.addTrack(track, localStream); }); if (dummyVideo) { dummyVideo.enabled = false; dummyVideo.stop(); stream.removeTrack(dummyVideo); } }).then(_ => { return pc.createAnswer(); }).then(answer => { return pc.setLocalDescription(answer); }).then(_ => { this.props.onSendAnswer(this.props.topic, this.props.seq, pc.localDescription.toJSON()); this.setState({ callInitialSetupComplete: true }, _ => this.drainRemoteIceCandidatesCache()); }).catch(this.handleGetUserMediaError); } handleRemoteHangup() { if (!this.state.waitingForPeer) { this.handleCloseClick(); } else { this.setState({ waitingForPeer: false }); RING_SOUND.pause(); RING_SOUND.currentTime = 0; CALL_ENDED_SOUND.loop = true; CALL_ENDED_SOUND.play().catch(_ => {}); setTimeout(_ => { this.handleCloseClick(); }, 2000); } } handleCloseClick() { this.stop(); this.props.onHangup(this.props.topic, this.props.seq); } muteVideo() { if (!this.state.pc || !this.state.dataChannel) { return; } const stream = this.state.localStream; const t = stream.getVideoTracks()[0]; t.enabled = false; t.stop(); stream.removeTrack(t); this.state.dataChannel.send(VIDEO_MUTED_EVENT); this.setState({ videoToggleInProgress: false }); } unmuteVideo() { if (!this.state.pc || !this.state.dataChannel) { return; } navigator.mediaDevices.getUserMedia({ video: true }).then(stream => { this.localRef.current.srcObject = null; const sender = this.state.pc.getSenders().find(s => s.track.kind == 'video'); const track = stream.getVideoTracks()[0]; stream.removeTrack(track); this.state.localStream.addTrack(track); return sender.replaceTrack(track); }).then(_ => { this.localRef.current.srcObject = this.state.localStream; this.state.dataChannel.send(VIDEO_UNMUTED_EVENT); }).catch(err => this.handleGetUserMediaError(err)).finally(_ => { this.setState({ videoToggleInProgress: false }); }); } handleToggleCameraClick() { if (this.state.videoToggleInProgress) { return; } const tracks = this.state.localStream.getVideoTracks(); this.setState({ videoToggleInProgress: true }, _ => { if (tracks && tracks.length > 0 && tracks[0].enabled && tracks[0].readyState == 'live') { this.muteVideo(); } else { this.unmuteVideo(); } this.setState({ audioOnly: !this.state.audioOnly }); }); } handleToggleMicClick() { const stream = this.state.localStream; const t = stream.getAudioTracks()[0]; t.enabled = !t.enabled; this.forceUpdate(); } render() { const audioTracks = this.state.localStream && this.state.localStream.getAudioTracks(); const videoTracks = !this.state.audioOnly && this.state.localStream && this.state.localStream.getVideoTracks(); const disabled = !this.state.pc || !this.state.dataChannel || !(audioTracks && audioTracks[0]); const audioIcon = audioTracks && audioTracks[0] && audioTracks[0].enabled ? 'mic' : 'mic_off'; const videoIcon = videoTracks && videoTracks[0] && videoTracks[0].enabled && videoTracks[0].readyState == 'live' ? 'videocam' : 'videocam_off'; const peerTitle = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_5__.clipStr)(this.props.title, _config_js__WEBPACK_IMPORTED_MODULE_3__.MAX_PEER_TITLE_LENGTH); const pulseAnimation = this.state.waitingForPeer ? ' pulse' : ''; let remoteActive = false; if (this.remoteRef.current && this.remoteRef.current.srcObject && this.state.remoteVideoLive) { const rstream = this.remoteRef.current.srcObject; if (rstream.getVideoTracks().length > 0) { const t = rstream.getVideoTracks()[0]; remoteActive = t.enabled && t.readyState == 'live'; } } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "video-container" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "video-container-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "call-party self", disabled: this.state.audioOnly }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("video", { ref: this.localRef, autoPlay: true, muted: true, playsInline: true }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "caller-name inactive" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "calls_you_label", defaultMessage: [{ "type": 0, "value": "You" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "call-party peer", disabled: !remoteActive }, remoteActive ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("video", { ref: this.remoteRef, autoPlay: true, playsInline: true }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "caller-name inactive" }, peerTitle)) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("audio", { ref: this.remoteRef, autoPlay: true }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: `caller-card${pulseAnimation}` }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "avatar-box" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { tinode: this.props.tinode, avatar: this.props.avatar, topic: this.props.topic, title: this.props.title })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "caller-name" }, peerTitle))))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "controls" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "danger", onClick: this.handleCloseClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "call_end")), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "secondary", onClick: this.handleToggleCameraClick, disabled: disabled }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, videoIcon)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "secondary", onClick: this.handleToggleMicClick, disabled: disabled }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, audioIcon))))); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(CallPanel)); /***/ }), /***/ "./src/widgets/call-status.jsx": /*!*************************************!*\ !*** ./src/widgets/call-status.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ CallStatus) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); class CallStatus extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { const isCallDropped = ['busy', 'declined', 'disconnected', 'missed'].includes(this.props.callState); const icon2 = this.props.incoming ? isCallDropped ? 'call_missed' : 'call_received' : isCallDropped ? 'call_missed_outgoing' : 'call_made'; let duration; if (isCallDropped) { switch (this.props.callState) { case 'busy': duration = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_busy", defaultMessage: [{ "type": 0, "value": "busy" }] }); break; case 'declined': duration = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_declined", defaultMessage: [{ "type": 0, "value": "declined" }] }); break; case 'missed': duration = this.props.incoming ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_missed", defaultMessage: [{ "type": 0, "value": "missed" }] }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_cancelled", defaultMessage: [{ "type": 0, "value": "cancelled" }] }); break; default: duration = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_disconnected", defaultMessage: [{ "type": 0, "value": "disconnected" }] }); break; } } else if (['accepted', 'started'].includes(this.props.callState) && !this.props.duration) { duration = react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "call_in_progress", defaultMessage: [{ "type": 0, "value": "in progress" }] }); } else { duration = react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_2__.secondsToTime)(this.props.duration / 1000)); } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "composed-material" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "call"), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons second" }, icon2)), " ", duration); } } ; /***/ }), /***/ "./src/widgets/chat-message.jsx": /*!**************************************!*\ !*** ./src/widgets/chat-message.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _attachment_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./attachment.jsx */ "./src/widgets/attachment.jsx"); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _received_marker_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./received-marker.jsx */ "./src/widgets/received-marker.jsx"); /* harmony import */ var _lib_formatters_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lib/formatters.js */ "./src/lib/formatters.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); function _extends() { _extends = Object.assign ? Object.assign.bind() : 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; }; return _extends.apply(this, arguments); } class BaseChatMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { progress: 0 }; if (props.uploader) { props.uploader.onProgress = this.handleProgress.bind(this); } this.handleExpandImage = this.handleExpandImage.bind(this); this.handlePlayVideo = this.handlePlayVideo.bind(this); this.handleFormButtonClick = this.handleFormButtonClick.bind(this); this.handleContextClick = this.handleContextClick.bind(this); this.handleCancelUpload = this.handleCancelUpload.bind(this); this.handleQuoteClick = this.handleQuoteClick.bind(this); this.handleCallJoin = this.handleCallJoin.bind(this); this.formatterContext = { formatMessage: props.intl.formatMessage.bind(props.intl), viewportWidth: props.viewportWidth, authorizeURL: props.tinode.authorizeURL.bind(props.tinode), onImagePreview: this.handleExpandImage, onVideoPreview: this.handlePlayVideo, onFormButtonClick: this.handleFormButtonClick, onQuoteClick: this.handleQuoteClick, onCallJoin: this.handleCallJoin }; } handleExpandImage(e) { e.preventDefault(); this.props.onExpandMedia({ url: e.target.src, filename: e.target.dataset.name, width: e.target.dataset.width, height: e.target.dataset.height, size: e.target.dataset.size, type: e.target.dataset.mime }); } handlePlayVideo(e) { e.preventDefault(); this.props.onExpandMedia({ video: true, url: e.target.dataset.src, preview: e.target.src, filename: e.target.dataset.name, width: e.target.dataset.width, height: e.target.dataset.height, duration: e.target.dataset.duration, size: e.target.dataset.size, type: e.target.dataset.mime }); } handleFormButtonClick(e) { e.preventDefault(); const data = { seq: this.props.seq }; data.resp = {}; if (e.target.dataset.name) { data.resp[e.target.dataset.name] = e.target.dataset.val ? e.target.dataset.val : e.target.dataset.val === undefined ? 1 : '' + e.target.dataset.val; } if (e.target.dataset.act == 'url') { data.ref = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_7__.sanitizeUrl)(e.target.dataset.ref) || 'about:blank'; } const text = e.target.dataset.title || 'unknown'; this.props.onFormResponse(e.target.dataset.act, text, data); } handleContextClick(e) { e.preventDefault(); e.stopPropagation(); const menuItems = []; if (this.props.received == tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_FAILED) { menuItems.push('menu_item_send_retry'); } if (this.props.received > tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_FATAL) { if (this.props.userIsWriter) { menuItems.push('menu_item_reply'); if (!this.props.response) { let immutable = false; tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.entities(this.props.content, (_0, _1, tp) => { immutable = ['AU', 'EX', 'FM', 'IM', 'VC', 'VD'].includes(tp); return immutable; }); if (!immutable) { tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.styles(this.props.content, tp => { immutable = ['QQ'].includes(tp); return immutable; }); } if (!immutable) { menuItems.push('menu_item_edit'); } } } if (this.props.userIsAdmin) { menuItems.push(this.props.pinned ? 'menu_item_unpin' : 'menu_item_pin'); } } menuItems.push('menu_item_forward'); this.props.showContextMenu({ seq: this.props.seq, replace: this.props.edited ? parseInt(this.props.edited.split(':')[1]) : 0, content: this.props.content, userFrom: this.props.userFrom, userName: this.props.userName, y: e.pageY, x: e.pageX, pickReply: this.props.pickReply, editMessage: this.props.editMessage }, menuItems); } handleProgress(ratio) { this.setState({ progress: ratio }); } handleCancelUpload() { this.props.onCancelUpload(this.props.seq, this.props.uploader); } handleQuoteClick(e) { e.preventDefault(); e.stopPropagation(); const replyToSeq = this.props.replyToSeq; if (replyToSeq) { this.props.onQuoteClick(replyToSeq); } } handleCallJoin() { this.props.onAcceptCall(this.props.topic, true, this.props.seq); } render() { const sideClass = this.props.sequence + ' ' + (this.props.response ? 'left' : 'right'); const bubbleClass = this.props.sequence == 'single' || this.props.sequence == 'last' ? 'bubble tip' : 'bubble'; const avatar = this.props.userAvatar || true; const fullDisplay = this.props.isGroup && this.props.response && (this.props.sequence == 'single' || this.props.sequence == 'last'); let content = this.props.content; const attachments = []; if (this.props.mimeType == tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.getContentType() && tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isValid(content)) { tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attachments(content, (att, i) => { if (att.mime == 'application/json') { return; } attachments.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_attachment_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, downloadUrl: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.getDownloadUrl(att), filename: att.name, uploading: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isProcessing(att), mimetype: att.mime, size: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.getEntitySize(att), progress: this.state.progress, onCancelUpload: this.handleCancelUpload, onError: this.props.onError, key: i })); }, this); const tree = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.format(content, _lib_formatters_js__WEBPACK_IMPORTED_MODULE_6__.fullFormatter, this.formatterContext); content = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, tree); } else if (typeof content != 'string') { content = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons gray" }, "warning_amber"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "gray" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "invalid_content", defaultMessage: [{ "type": 0, "value": "invalid content" }] }))); } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { ref: this.props.innerRef, className: sideClass }, this.props.isGroup && this.props.response ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "avatar-box" }, fullDisplay ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { tinode: this.props.tinode, topic: this.props.userFrom, title: this.props.userName, avatar: avatar }) : null) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: bubbleClass }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "content-meta" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "message-content" }, content, attachments), this.props.timestamp ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_received_marker_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { edited: this.props.edited, timestamp: this.props.timestamp, received: this.props.received }) : null), this.props.showContextMenu ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "menuTrigger" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleContextClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "expand_more"))) : null), fullDisplay ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "author" }, this.props.userName || react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "user_not_found", defaultMessage: [{ "type": 0, "value": "Not found" }] }))) : null)); } } ; const IntlChatMessage = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(BaseChatMessage); const ChatMessage = react__WEBPACK_IMPORTED_MODULE_0___default().forwardRef((props, ref) => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(IntlChatMessage, _extends({ innerRef: ref }, props))); /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (ChatMessage); /***/ }), /***/ "./src/widgets/checkbox.jsx": /*!**********************************!*\ !*** ./src/widgets/checkbox.jsx ***! \**********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ CheckBox) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); class CheckBox extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); } handleChange() { this.props.onChange(this.props.name, !this.props.checked); } render() { let classList = ['material-icons']; let iconName; if (Array.isArray(this.props.className)) { classList.push(...this.props.className); } else if (this.props.className) { classList.push(this.props.className); } if (this.props.onChange) { if (this.props.checked) { classList.push('blue', 'clickable'); iconName = 'check_box'; } else if (this.props.checked === false) { classList.push('blue', 'clickable'); iconName = 'check_box_outline_blank'; } else { classList.push('lt-blue'); iconName = 'indeterminate_check_box'; } } else { if (this.props.checked) { iconName = 'check_box'; } else { iconName = 'check_box_outline_blank'; } } let attrs = { className: classList.join(' '), id: this.props.id }; if (this.props.onChange) { attrs.onClick = this.handleChange; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement('i', attrs, iconName); } } /***/ }), /***/ "./src/widgets/chip-input.jsx": /*!************************************!*\ !*** ./src/widgets/chip-input.jsx ***! \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ ChipInput) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _chip_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./chip.jsx */ "./src/widgets/chip.jsx"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); class ChipInput extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = ChipInput.deriveStateFromProps(props); this.state.input = ''; this.state.focused = false; this.handleTextInput = this.handleTextInput.bind(this); this.removeChipAt = this.removeChipAt.bind(this); this.handleChipCancel = this.handleChipCancel.bind(this); this.handleFocusGained = this.handleFocusGained.bind(this); this.handleFocusLost = this.handleFocusLost.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); } static deriveStateFromProps(props) { return { placeholder: props.chips ? '' : props.prompt, sortedChips: ChipInput.sortChips(props.chips, props.staticMembers), chipIndex: ChipInput.indexChips(props.chips) }; } componentDidUpdate(prevProps, prevState) { if (prevProps.chips != this.props.chips || prevProps.staticMembers != this.props.staticMembers || prevProps.prompt != this.props.prompt) { this.setState(ChipInput.deriveStateFromProps(this.props)); } if (!prevState || this.props.chips.length > prevState.sortedChips.length) { this.setState({ input: '' }); } } static indexChips(chips) { const index = {}; let count = 0; chips.forEach(item => { index[item.user] = count; count++; }); return index; } static sortChips(chips, keep) { const required = []; const normal = []; chips.forEach(item => { if (keep && keep.includes(item.user)) { required.push(item); } else { normal.push(item); } }); return required.concat(normal); } handleTextInput(e) { this.setState({ input: e.target.value }); if (this.props.filterFunc) { this.props.filterFunc(e.target.value); } } removeChipAt(idx) { const removed = this.state.sortedChips[idx]; this.props.onChipRemoved(removed.user, this.state.chipIndex[removed.user]); } handleChipCancel(item, idx) { this.removeChipAt(idx); } handleFocusGained() { this.setState({ focused: true }); } handleFocusLost() { this.setState({ focused: false }); if (this.props.onFocusLost) { this.props.onFocusLost(this.state.input); } } handleKeyDown(e) { if (e.key === 'Backspace') { if (this.state.input.length == 0 && this.state.sortedChips.length > 0) { const at = this.state.sortedChips.length - 1; if (this.state.sortedChips[at].user !== this.props.staticMembers) { this.removeChipAt(at); } } } else if (e.key === 'Enter') { if (this.props.onEnter) { this.props.onEnter(this.state.input); } } else if (e.key === 'Escape') { if (this.props.onCancel) { this.props.onCancel(); } } } render() { const chips = []; let count = 0; const staticMembers = this.props.staticMembers || []; this.state.sortedChips.forEach(item => { chips.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_chip_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { tinode: this.props.tinode, onCancel: this.handleChipCancel, avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_2__.makeImageUrl)(item.public ? item.public.photo : null), title: item.public ? item.public.fn : undefined, noAvatar: this.props.avatarDisabled, topic: item.user, required: staticMembers.includes(item.user), invalid: item.invalid, index: count, key: item.user })); count++; }); const className = "chip-input" + (this.state.focused ? ' focused' : ''); const autoFocus = !(this.props.tabIndex > 0); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: className }, chips, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", placeholder: this.state.placeholder, onChange: this.handleTextInput, onFocus: this.handleFocusGained, onBlur: this.handleFocusLost, onKeyDown: this.handleKeyDown, value: this.state.input, tabIndex: this.props.tabIndex, autoFocus: autoFocus })); } } ; /***/ }), /***/ "./src/widgets/chip.jsx": /*!******************************!*\ !*** ./src/widgets/chip.jsx ***! \******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ Chip) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); class Chip extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleCancel = this.handleCancel.bind(this); } handleCancel(e) { e.preventDefault(); this.props.onCancel(this.props.topic, this.props.index); } render() { const title = this.props.title || this.props.topic; const className = this.props.invalid ? 'chip invalid' : 'chip'; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: className }, this.props.noAvatar ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "spacer" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "avatar-box" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { tinode: this.props.tinode, avatar: this.props.avatar || true, topic: this.props.topic, title: this.props.title })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, title), this.props.onCancel && !this.props.required ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleCancel }, "\xD7") : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "spacer" })); } } ; /***/ }), /***/ "./src/widgets/contact-action.jsx": /*!****************************************!*\ !*** ./src/widgets/contact-action.jsx ***! \****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); class ContactAction extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); } handleClick(e) { e.preventDefault(); e.stopPropagation(); this.props.onAction(this.props.action); } render() { const { formatMessage } = this.props.intl; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { onClick: this.handleClick, className: "action" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "action-text" }, formatMessage(this.props.title, this.props.values))); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(ContactAction)); /***/ }), /***/ "./src/widgets/contact-badges.jsx": /*!****************************************!*\ !*** ./src/widgets/contact-badges.jsx ***! \****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ ContactBadges) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); const icon_mapping = { 'muted': 'notifications_off', 'banned': 'block', 'staff': 'verified_user' }; class ContactBadges extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { let badges = null; if (this.props.badges && this.props.badges.length > 0) { badges = []; this.props.badges.forEach(b => { const color = b.color ? ' ' + b.color : ''; if (b.icon) { badges.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: 'material-icons as-badge' + color, key: b.key || b.icon }, icon_mapping[b.icon] || b.icon)); } else { badges.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: 'badge' + color, key: b.key || b.name }, b.name)); } }); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, badges); } return null; } } ; /***/ }), /***/ "./src/widgets/contact-list.jsx": /*!**************************************!*\ !*** ./src/widgets/contact-list.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _contact_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./contact.jsx */ "./src/widgets/contact.jsx"); /* harmony import */ var _contact_action_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./contact-action.jsx */ "./src/widgets/contact-action.jsx"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ badge_you: { id: "badge_you", defaultMessage: [{ "type": 0, "value": "you" }] }, badge_owner: { id: "badge_owner", defaultMessage: [{ "type": 0, "value": "owner" }] } }); class ContactList extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { render() { const { formatMessage } = this.props.intl; const showCheckmark = Array.isArray(this.props.topicSelected); const contactNodes = []; let contactsCount = 0; if (this.props.contacts && this.props.contacts.length > 0) { this.props.contacts.forEach(c => { if (c.action) { contactNodes.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_contact_action_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { title: c.title, action: c.action, values: c.values, key: c.action, onAction: this.props.onAction })); } else { const key = this.props.showMode ? c.user : c.topic || c.user; if (this.props.filterFunc && this.props.filter) { const filterOn = [key]; if (c.private && c.private.comment) { filterOn.push(('' + c.private.comment).toLowerCase()); } if (c.public && c.public.fn) { filterOn.push(('' + c.public.fn).toLowerCase()); } if (!this.props.filterFunc(this.props.filter, filterOn)) { return; } } const isChannel = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isChannelTopicName(key); const isGroup = !isChannel && tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isGroupTopicName(key); const selected = showCheckmark ? this.props.topicSelected.indexOf(key) > -1 : this.props.topicSelected === key; const badges = []; if (this.props.showMode) { if (key == this.props.myUserId) { badges.push({ name: formatMessage(messages.badge_you), color: 'green' }); } if (c.acs && c.acs.isOwner()) { badges.push({ name: formatMessage(messages.badge_owner), color: 'blue' }); } } const comment = Array.isArray(c.private) ? c.private.join(',') : c.private ? c.private.comment : null; let preview; let forwarded; let previewIsResponse; let deliveryStatus; if (!this.props.showMode && c.latestMessage) { const msg = c.latestMessage(); if (msg) { forwarded = msg.head ? msg.head.forwarded : null; deliveryStatus = msg._status || c.msgStatus(msg, true); previewIsResponse = msg.from != this.props.myUserId; if (msg.content) { preview = typeof msg.content == 'string' ? msg.content.substr(0, _config_js__WEBPACK_IMPORTED_MODULE_6__.MESSAGE_PREVIEW_LENGTH) : tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.preview(msg.content, _config_js__WEBPACK_IMPORTED_MODULE_6__.MESSAGE_PREVIEW_LENGTH); } } } contactNodes.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_contact_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, title: c.public ? c.public.fn : null, avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_5__.makeImageUrl)(c.public ? c.public.photo : null), comment: comment, preview: preview, previewIsResponse: previewIsResponse, forwarded: forwarded, received: deliveryStatus, unread: this.props.showUnread ? c.unread : 0, now: c.online && this.props.connected, acs: c.acs, showMode: this.props.showMode, badges: badges, showCheckmark: showCheckmark, selected: selected, showOnline: this.props.showOnline && !isChannel, isChannel: isChannel, isGroup: isGroup, showContextMenu: this.props.showContextMenu, isVerified: c.trusted && c.trusted.verified, isStaff: c.trusted && c.trusted.staff, isDangerous: c.trusted && c.trusted.danger, deleted: c._deleted, onSelected: this.props.onTopicSelected, item: key, index: contactNodes.length, key: key })); contactsCount++; } }, this); } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: this.props.noScroll ? null : "scrollable-panel" }, contactsCount == 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "center-medium-text", dangerouslySetInnerHTML: { __html: this.props.emptyListMessage } }) : null, contactNodes.length > 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("ul", { className: "contact-box" }, contactNodes) : null); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(ContactList)); /***/ }), /***/ "./src/widgets/contact.jsx": /*!*********************************!*\ !*** ./src/widgets/contact.jsx ***! \*********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _contact_badges_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./contact-badges.jsx */ "./src/widgets/contact-badges.jsx"); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _unread_badge_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./unread-badge.jsx */ "./src/widgets/unread-badge.jsx"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_5__); /* harmony import */ var _lib_formatters_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lib/formatters.js */ "./src/lib/formatters.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); class Contact extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); this.handleContextClick = this.handleContextClick.bind(this); } handleClick(e) { e.preventDefault(); e.stopPropagation(); if (this.props.onSelected) { this.props.onSelected(this.props.item, this.props.index); } } handleContextClick(e) { e.preventDefault(); e.stopPropagation(); this.props.showContextMenu({ topicName: this.props.item, y: e.pageY, x: e.pageX }); } render() { let title = this.props.title; if (!title) { title = react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "unnamed_topic", defaultMessage: [{ "type": 0, "value": "Unnamed" }] })); } else if (title.length > 30) { title = title.substring(0, 28) + '…'; } const online = this.props.now ? 'online' : 'offline'; const avatar = this.props.avatar ? this.props.avatar : true; const badges = this.props.badges ? this.props.badges.slice() : []; const icon_badges = []; if (this.props.isVerified) { icon_badges.push({ icon: 'verified', color: 'verified-color' }); } if (this.props.isStaff) { icon_badges.push({ icon: 'staff', color: 'staff-color' }); } if (this.props.isDangerous) { icon_badges.push({ icon: 'dangerous', color: 'danger-color' }); } if (this.props.acs) { if (this.props.showMode) { badges.push({ name: this.props.acs.getMode(), key: 'mode' }); } if (this.props.acs.isMuted()) { icon_badges.push({ icon: 'muted' }); } if (!this.props.acs.isJoiner()) { icon_badges.push({ icon: 'banned' }); } } let preview; if (typeof this.props.preview == 'string') { preview = this.props.preview; } else if (tinode_sdk__WEBPACK_IMPORTED_MODULE_5__.Drafty.isValid(this.props.preview)) { preview = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, tinode_sdk__WEBPACK_IMPORTED_MODULE_5__.Drafty.format(this.props.preview, _lib_formatters_js__WEBPACK_IMPORTED_MODULE_6__.previewFormatter, { formatMessage: this.props.intl.formatMessage, previewIsResponse: this.props.previewIsResponse })); } else if (this.props.preview) { preview = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons gray" }, "warning_amber"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "gray" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "invalid_content", defaultMessage: [{ "type": 0, "value": "invalid content" }] }))); } const icon = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_7__.deliveryMarker)(this.props.received); const marker = icon ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: 'material-icons small space-right' + (icon.color ? ' ' + icon.color : '') }, icon.name) : null; const titleClass = 'contact-title' + (this.props.deleted ? ' deleted' : ''); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { className: !this.props.showCheckmark && this.props.selected ? 'selected' : null, onClick: this.handleClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "avatar-box" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, avatar: avatar, title: this.props.title, topic: this.props.item, deleted: this.props.deleted }), this.props.deleted ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "deleted material-icons" }, "cancel") : this.props.showOnline ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: online }) : this.props.showCheckmark && this.props.selected ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "checkmark material-icons" }, "check_circle") : null), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "text-box" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: titleClass }, title), this.props.isGroup ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons as-badge" }, "group") : null, this.props.isChannel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { src: "/img/channel.png", className: "channel", alt: "channel" }) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_contact_badges_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { badges: icon_badges }), !this.props.deleted ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_unread_badge_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { count: this.props.unread }) : null), this.props.showMode ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_contact_badges_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { badges: badges })) : this.props.small ? null : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "contact-comment" }, marker, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, preview || this.props.comment || '\u00A0'))), this.props.showContextMenu ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "menuTrigger" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleContextClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "expand_more"))) : null); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(Contact)); /***/ }), /***/ "./src/widgets/context-menu.jsx": /*!**************************************!*\ !*** ./src/widgets/context-menu.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ info: { id: "menu_item_info", defaultMessage: [{ "type": 0, "value": "Info" }] }, clear_messages: { id: "menu_item_clear_messages", defaultMessage: [{ "type": 0, "value": "Clear messages" }] }, clear_for_all: { id: "menu_item_clear_messages_for_all", defaultMessage: [{ "type": 0, "value": "Clear for All" }] }, delete: { id: "menu_item_delete", defaultMessage: [{ "type": 0, "value": "Delete" }] }, delete_for_all: { id: "menu_item_delete_for_all", defaultMessage: [{ "type": 0, "value": "Delete for All" }] }, send_retry: { id: "menu_item_send_retry", defaultMessage: [{ "type": 0, "value": "Retry" }] }, mute: { id: "menu_item_mute", defaultMessage: [{ "type": 0, "value": "Mute" }] }, unmute: { id: "menu_item_unmute", defaultMessage: [{ "type": 0, "value": "Unmute" }] }, reply: { id: "menu_item_reply", defaultMessage: [{ "type": 0, "value": "Reply" }] }, forward: { id: "menu_item_forward", defaultMessage: [{ "type": 0, "value": "Forward" }] }, edit: { id: "menu_item_edit", defaultMessage: [{ "type": 0, "value": "Edit" }] }, topic_delete: { id: "menu_item_delete_topic", defaultMessage: [{ "type": 0, "value": "Delete" }] }, topic_delete_warning: { id: "topic_delete_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to delete this conversation? It cannot be undone." }] }, delete_messages_warning: { id: "delete_messages_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to delete all messages for everyone? It cannot be undone." }] }, unblock: { id: "menu_item_unblock", defaultMessage: [{ "type": 0, "value": "Unblock" }] }, block: { id: "menu_item_block", defaultMessage: [{ "type": 0, "value": "Block" }] }, topic_block_warning: { id: "topic_block_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to block this conversation?" }] }, member_delete: { id: "menu_item_member_delete", defaultMessage: [{ "type": 0, "value": "Remove" }] }, archive: { id: "menu_item_archive_topic", defaultMessage: [{ "type": 0, "value": "Archive" }] }, unarchive: { id: "menu_item_restore_topic", defaultMessage: [{ "type": 0, "value": "Restore" }] }, edit_permissions: { id: "menu_item_edit_permissions", defaultMessage: [{ "type": 0, "value": "Edit permissions" }] }, clear_messages_warning: { id: "clear_messages_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to clear all messages? It cannot be undone." }] }, pin_message: { id: "pin_message", defaultMessage: [{ "type": 0, "value": "Pin" }] }, unpin_message: { id: "unpin_message", defaultMessage: [{ "type": 0, "value": "Unpin" }] } }); class ContextMenu extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.selfRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); const { formatMessage } = props.intl; this.handlePageClick = this.handlePageClick.bind(this); this.handleEscapeKey = this.handleEscapeKey.bind(this); this.handleClick = this.handleClick.bind(this); this.MenuItems = { 'topic_info': { id: 'topic_info', title: formatMessage(messages.info), handler: null }, 'messages_clear': { id: 'messages_clear', title: formatMessage(messages.clear_messages), handler: (params, errorHandler) => { return props.onShowAlert(formatMessage(messages.clear_messages), formatMessage(messages.clear_messages_warning), _ => { this.deleteMessages(true, false, params, errorHandler); }, null, true, null); } }, 'messages_clear_hard': { id: 'messages_clear_hard', title: formatMessage(messages.clear_for_all), handler: (params, errorHandler) => { return props.onShowAlert(formatMessage(messages.clear_for_all), formatMessage(messages.delete_messages_warning), _ => { return this.deleteMessages(true, true, params, errorHandler); }, null, true, null); } }, 'message_delete': { id: 'message_delete', title: formatMessage(messages.delete), handler: (params, errorHandler) => { return this.deleteMessages(false, false, params, errorHandler); } }, 'message_delete_hard': { id: 'message_delete_hard', title: formatMessage(messages.delete_for_all), handler: (params, errorHandler) => { return this.deleteMessages(false, true, params, errorHandler); } }, 'menu_item_send_retry': { id: 'menu_item_send_retry', title: formatMessage(messages.send_retry), handler: (params, errorHandler) => { return this.retryMessage(params, errorHandler); } }, 'menu_item_reply': { id: 'menu_item_reply', title: formatMessage(messages.reply), handler: (params, errorHandler) => { return this.replyToMessage(params, errorHandler); } }, 'menu_item_forward': { id: 'menu_item_forward', title: formatMessage(messages.forward), handler: _ => {} }, 'menu_item_edit': { id: 'menu_item_edit', title: formatMessage(messages.edit), handler: (params, errorHandler) => { return this.editMessage(params, errorHandler); } }, 'menu_item_pin': { id: 'menu_item_pin', title: formatMessage(messages.pin_message), handler: (params, errorHandler) => { return this.pinMessage(true, params, errorHandler); } }, 'menu_item_unpin': { id: 'menu_item_unpin', title: formatMessage(messages.unpin_message), handler: (params, errorHandler) => { return this.pinMessage(false, params, errorHandler); } }, 'topic_unmute': { id: 'topic_unmute', title: formatMessage(messages.unmute), handler: this.topicPermissionSetter.bind(this, '+P') }, 'topic_mute': { id: 'topic_mute', title: formatMessage(messages.mute), handler: this.topicPermissionSetter.bind(this, '-P') }, 'topic_unblock': { id: 'topic_unblock', title: formatMessage(messages.unblock), handler: this.topicPermissionSetter.bind(this, '+JP') }, 'topic_block': { id: 'topic_block', title: formatMessage(messages.block), handler: (params, errorHandler) => { return props.onShowAlert(formatMessage(messages.block), formatMessage(messages.topic_block_warning), _ => this.topicPermissionSetter('-JP', params, errorHandler).then(ctrl => { this.props.onTopicRemoved(params.topicName); return ctrl; }), null, true, null); } }, 'topic_delete': { id: 'topic_delete', title: formatMessage(messages.topic_delete), handler: (params, errorHandler) => { return props.onShowAlert(formatMessage(messages.topic_delete), formatMessage(messages.topic_delete_warning), _ => { const topic = this.props.tinode.getTopic(params.topicName); if (!topic) { console.warn("Topic not found: ", params.topicName); return; } return topic.delTopic(true).catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); }, null, true, null); } }, 'topic_archive': { id: 'topic_archive', title: formatMessage(messages.archive), handler: (params, errorHandler) => { const topic = this.props.tinode.getTopic(params.topicName); if (!topic) { console.warn("Topic not found: ", params.topicName); return; } return topic.archive(true).catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); } }, 'topic_restore': { id: 'topic_restore', title: formatMessage(messages.unarchive), handler: (params, errorHandler) => { const topic = this.props.tinode.getTopic(params.topicName); if (!topic) { console.warn("Topic not found: ", params.topicName); return; } return topic.archive(false).catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); } }, 'permissions': { id: 'permissions', title: formatMessage(messages.edit_permissions), handler: null }, 'member_delete': { id: 'member_delete', title: formatMessage(messages.member_delete), handler: (params, errorHandler) => { const topic = this.props.tinode.getTopic(params.topicName); if (!topic || !params.user) { console.warn("Topic or user not found: '" + params.topicName + "', '" + params.user + "'"); return; } return topic.delSubscription(params.user).catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); } }, 'member_mute': { id: 'member_mute', title: formatMessage(messages.mute), handler: this.topicPermissionSetter.bind(this, '-P') }, 'member_unmute': { id: 'member_unmute', title: formatMessage(messages.unmute), handler: this.topicPermissionSetter.bind(this, '+P') }, 'member_block': { id: 'member_block', title: formatMessage(messages.block), handler: this.topicPermissionSetter.bind(this, '-JP') }, 'member_unblock': { id: 'member_unblock', title: formatMessage(messages.unblock), handler: this.topicPermissionSetter.bind(this, '+JP') } }; } componentDidMount() { document.addEventListener('mousedown', this.handlePageClick, false); document.addEventListener('keyup', this.handleEscapeKey, false); } componentWillUnmount() { document.removeEventListener('mousedown', this.handlePageClick, false); document.removeEventListener('keyup', this.handleEscapeKey, false); } handlePageClick(e) { if (this.selfRef.current.contains(e.target)) { return; } e.preventDefault(); e.stopPropagation(); this.props.hide(); } handleEscapeKey(e) { if (e.keyCode === 27) { this.props.hide(); } } handleClick(e) { e.preventDefault(); e.stopPropagation(); this.props.hide(); let item = this.props.items[e.currentTarget.dataset.id]; if (typeof item == 'string') { item = this.MenuItems[item]; } if (!item) { console.error("Invalid menu item ID", e.currentTarget.dataset.id); } else { this.props.onAction(item.id, item.handler(this.props.params, this.props.onError), this.props.params); } } deleteMessages(all, hard, params, errorHandler) { const topic = this.props.tinode.getTopic(params.topicName); if (!topic) { console.warn("Topic not found: ", params.topicName); return; } if (!all && topic.cancelSend(params.seq)) { return; } const promise = all ? topic.delMessagesAll(hard) : params.replace > 0 ? topic.delMessagesEdits(params.replace, hard) : topic.delMessagesList([params.seq], hard); return promise.catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); } retryMessage(params, errorHandler) { const topic = this.props.tinode.getTopic(params.topicName); if (!topic || !topic.flushMessage(params.seq)) { return; } const msg = topic.createMessage(params.content, false); return topic.publishDraft(msg).catch(err => { if (errorHandler) { errorHandler(err.message, 'err'); } }); } pinMessage(pin, params, errorHandler) { const topic = this.props.tinode.getTopic(params.topicName); if (!topic) { return; } topic.pinMessage(params.seq, pin).catch(err => errorHandler ? errorHandler(err.message, 'err') : null); } topicPermissionSetter(mode, params, errorHandler) { const topic = this.props.tinode.getTopic(params.topicName); if (!topic) { console.warn("Topic not found", params.topicName); return; } let result = topic.updateMode(params.user, mode); if (errorHandler) { result = result.catch(err => errorHandler(err.message, 'err')); } return result; } replyToMessage(params, errorHandler) { params.pickReply(params.seq, params.content, params.userFrom, params.userName, errorHandler); } editMessage(params, errorHandler) { params.editMessage(params.replace || params.seq, params.content, errorHandler); } render() { const menu = []; let count = 0; this.props.items.forEach(item => { if (typeof item == 'string') { item = this.MenuItems[item]; } if (item && item.title) { const className = item.disabled ? 'disabled' : undefined; menu.push(item.title == '-' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { className: "separator", key: count }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { className: className, onClick: this.handleClick, "data-id": count, key: count }, item.title)); } count++; }); const hSize = 12 * _config_js__WEBPACK_IMPORTED_MODULE_2__.REM_SIZE; const vSize = _config_js__WEBPACK_IMPORTED_MODULE_2__.REM_SIZE * (0.7 + menu.length * 2.5); const left = this.props.bounds.right - this.props.clickAt.x < hSize ? this.props.clickAt.x - this.props.bounds.left - hSize : this.props.clickAt.x - this.props.bounds.left; const top = this.props.bounds.bottom - this.props.clickAt.y < vSize ? this.props.clickAt.y - this.props.bounds.top - vSize : this.props.clickAt.y - this.props.bounds.top; const position = { left: left + 'px', top: top + 'px' }; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("ul", { className: "menu", style: position, ref: this.selfRef }, menu); } } /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(ContextMenu)); /***/ }), /***/ "./src/widgets/cropper.jsx": /*!*********************************!*\ !*** ./src/widgets/cropper.jsx ***! \*********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ Cropper) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); const DEFAULT_MAX_ZOOM = 2.5; class Cropper extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { panX: 0, panY: 0, originX: 0, originY: 0, zoom: 1, minZoom: 0, maxZoom: DEFAULT_MAX_ZOOM }; this.overlay = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.cutout = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.preview = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.boundingBox = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.imageWidth = 0; this.imageHeight = 0; this.mouseX = 0; this.mouseY = 0; this.prevDistance = 0; this.cutoutRect = {}; this.bBoxRect = {}; this.originX = 0; this.originY = 0; this.initScaling = this.initScaling.bind(this); this.onZoom = this.onZoom.bind(this); this.handleZoom = this.handleZoom.bind(this); this.mouseDown = this.mouseDown.bind(this); this.mouseUp = this.mouseUp.bind(this); this.mouseMove = this.mouseMove.bind(this); this.mouseTouch = this.mouseTouch.bind(this); this.positionAll = this.positionAll.bind(this); this.translate = this.translate.bind(this); } componentDidMount() { this.overlay.current.addEventListener('mousedown', this.mouseDown, { passive: true }); this.overlay.current.addEventListener('touchstart', this.mouseDown, { passive: true }); this.bBoxRect = this.boundingBox.current.getBoundingClientRect(); this.originX = this.bBoxRect.width / 2; this.originY = this.bBoxRect.height / 2; this.cutoutRect = this.cutout.current.getBoundingClientRect(); } componentWillUnmount() { this.overlay.current.removeEventListener('mousedown', this.mouseDown); this.overlay.current.removeEventListener('touchstart', this.mouseDown); } positionAll(panX, panY, zoom) { this.setState({ panX: panX, panY: panY, zoom: zoom, originX: this.originX - panX, originY: this.originY - panY }); const left = (this.originX - panX) * zoom - this.originX; const top = (this.originY - panY) * zoom - this.originY; this.props.onChange((left + this.cutoutRect.left - this.bBoxRect.left) / zoom, (top + this.cutoutRect.top - this.bBoxRect.top) / zoom, this.cutoutRect.width / zoom, this.cutoutRect.height / zoom, zoom); } static checkBound(currPan, img, cutout, delta) { let nextDiff = Math.min(0, cutout[0] - img[0] - delta, img[1] - cutout[1] + delta); if (nextDiff == 0) { currPan += delta; } else if (Math.min(0, cutout[0] - img[0], img[1] - cutout[1]) < nextDiff) { currPan += delta; } return currPan; } initScaling() { const imgRect = this.preview.current.getBoundingClientRect(); this.imageWidth = imgRect.width; this.imageHeight = imgRect.height; const minZoom = Math.max(this.cutoutRect.width / imgRect.width, this.cutoutRect.height / imgRect.height); this.setState({ minZoom: minZoom, maxZoom: Math.max(DEFAULT_MAX_ZOOM, minZoom + 1) }); const zoom = Math.max(this.bBoxRect.width / imgRect.width, this.bBoxRect.height / imgRect.height); const panX = this.cutoutRect.left - this.bBoxRect.left - (imgRect.width - this.cutoutRect.width) / 2; const panY = this.cutoutRect.top - this.bBoxRect.top - (imgRect.height - this.cutoutRect.height) / 2; this.positionAll(panX, panY, zoom); } onZoom(e) { this.handleZoom(e.target.value); } handleZoom(zoom) { let panX = this.state.panX; let panY = this.state.panY; const imgLeft = this.originX - (this.originX - panX) * zoom; const imgRight = imgLeft + this.imageWidth * zoom; const coLeft = this.cutoutRect.left - this.bBoxRect.left; const coRight = coLeft + this.cutoutRect.width; if (coLeft < imgLeft) { panX -= imgLeft - coLeft; } else if (coRight > imgRight) { panX += coRight - imgRight; } const imgTop = this.originY - (this.originY - panY) * zoom; const imgBottom = imgTop + this.imageHeight * zoom; const coTop = this.cutoutRect.top - this.bBoxRect.top; const coBottom = coTop + this.cutoutRect.height; if (coTop < imgTop) { panY -= imgTop - coTop; } else if (coBottom > imgBottom) { panY += coBottom - imgBottom; } this.positionAll(panX, panY, zoom); } mouseDown(e) { if (e.touches) { this.mouseX = e.touches[0].pageX; this.mouseY = e.touches[0].pageY; } else { this.mouseX = e.pageX; this.mouseY = e.pageY; } window.addEventListener('mousemove', this.mouseMove, { passive: false }); window.addEventListener('touchmove', this.mouseTouch, { passive: false }); window.addEventListener('mouseup', this.mouseUp, { passive: true }); window.addEventListener('touchend', this.mouseUp, { passive: true }); document.body.style['userSelect'] = 'none'; } translate(pageX, pageY) { const dX = pageX - this.mouseX; const dY = pageY - this.mouseY; this.mouseX = pageX; this.mouseY = pageY; const imgRect = this.preview.current.getBoundingClientRect(); let panX = Cropper.checkBound(this.state.panX, [imgRect.left, imgRect.right], [this.cutoutRect.left, this.cutoutRect.right], dX); let panY = Cropper.checkBound(this.state.panY, [imgRect.top, imgRect.bottom], [this.cutoutRect.top, this.cutoutRect.bottom], dY); this.positionAll(panX, panY, this.state.zoom); } mouseMove(e) { e.preventDefault(); this.translate(e.pageX, e.pageY); } mouseTouch(e) { e.preventDefault(); if (e.touches.length == 1) { this.translate(e.touches[0].pageX, e.touches[0].pageY); return; } const [touch0, touch1] = e.touches; const distance = Math.sqrt((touch0.pageX - touch1.pageX) * (touch0.pageX - touch1.pageX) + (touch0.pageY - touch1.pageY) * (touch0.pageY - touch1.pageY)); if (!this.prevDistance) { this.prevDistance = distance / this.state.zoom; } let scale = distance / this.prevDistance; this.handleZoom(Math.max(this.minZoom, Math.min(this.maxZoom, scale))); } mouseUp(e) { window.removeEventListener('mousemove', this.mouseMove); window.removeEventListener('touchmove', this.mouseTouch); window.removeEventListener('mouseup', this.mouseUp); window.removeEventListener('touchend', this.mouseUp); document.body.style['userSelect'] = ''; this.positionAll(this.state.panX, this.state.panY, this.state.zoom); } render() { const t3d = `translate3d(${this.state.panX}px, ${this.state.panY}px, 0) scale(${this.state.zoom})`; const orig = `${this.state.originX}px ${this.state.originY}px`; const overlay = { top: `${this.originY - this.state.originY * this.state.zoom}px`, left: `${this.originX - this.state.originX * this.state.zoom}px`, width: `${this.imageWidth * this.state.zoom}px`, height: `${this.imageHeight * this.state.zoom}px` }; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "cropper" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "bounding-box", ref: this.boundingBox }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { src: this.props.source, className: "preview", alt: "", style: { transform: t3d, transformOrigin: orig }, ref: this.preview, onLoad: this.initScaling }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "cutout circle", ref: this.cutout }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "overlay", style: overlay, ref: this.overlay })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "zoom-wrapper" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "range", className: "zoomer", step: "0.001", min: this.state.minZoom, max: this.state.maxZoom, value: this.state.zoom, onChange: this.onZoom }))); } } /***/ }), /***/ "./src/widgets/doc-preview.jsx": /*!*************************************!*\ !*** ./src/widgets/doc-preview.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ DocPreview) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _widgets_send_message_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../widgets/send-message.jsx */ "./src/widgets/send-message.jsx"); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); function iconFromMime(mime) { const mimeToIcon = { default: 'insert_drive_file', image: 'image', text: 'description', video: 'theaters' }; return mimeToIcon[mime] || mimeToIcon[(mime || '').split('/')[0]] || mimeToIcon['default']; } class DocPreview extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleSendDoc = this.handleSendDoc.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); } componentDidMount() { document.addEventListener('keydown', this.handleKeyDown); } componentWillUnmount() { document.removeEventListener('keydown', this.handleKeyDown); } handleKeyDown(e) { e.preventDefault(); if (e.key === 'Escape') { this.props.onClose(); } } handleSendDoc(caption) { this.props.onClose(); this.props.onSendMessage(this.props.content.file); } render() { if (!this.props.content) { return null; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "image-preview" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "image-preview-caption-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, this.props.content.name), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onClose(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons gray" }, "close"))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "image-preview-container" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "flex-column narrow" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons gray" }, iconFromMime(this.props.content.type)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("b", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_file_name", defaultMessage: [{ "type": 0, "value": "File name:" }] })), " ", (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_3__.shortenFileName)(this.props.content.name, 24) || '-'), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("b", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_content_type", defaultMessage: [{ "type": 0, "value": "Content type:" }] })), " ", this.props.content.type || 'application/octet-stream'), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("b", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_size", defaultMessage: [{ "type": 0, "value": "Size:" }] })), " ", (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_3__.bytesToHumanSize)(this.props.content.size)))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_send_message_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { noInput: true, tinode: this.props.tinode, reply: this.props.reply, onCancelReply: this.props.onCancelReply, onSendMessage: this.handleSendDoc, onError: this.props.onError })); } } ; /***/ }), /***/ "./src/widgets/error-panel.jsx": /*!*************************************!*\ !*** ./src/widgets/error-panel.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ ErrorPanel) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _menu_cancel_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./menu-cancel.jsx */ "./src/widgets/menu-cancel.jsx"); class ErrorPanel extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { show: false }; this.hide = this.hide.bind(this); } componentDidUpdate(prevProps) { if (prevProps.level !== this.props.level) { this.setState({ show: !!this.props.level }); } } hide() { this.setState({ show: false }); if (this.props.onClearError) { this.props.onClearError(); } } render() { const icons = { err: 'error', warn: 'warning', info: 'info' }; const level = icons[this.props.level] || ''; const className = 'info-box ' + level; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: className }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "icon" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, level)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, this.props.text, this.props.action ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, "\xA0 ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", style: { whiteSpace: 'nowrap' }, onClick: e => { e.preventDefault(); this.props.action(); } }, this.props.actionText)) : null), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "cancel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_menu_cancel_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { onCancel: this.hide }))); } } ; /***/ }), /***/ "./src/widgets/file-progress.jsx": /*!***************************************!*\ !*** ./src/widgets/file-progress.jsx ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ FileProgress) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); class FileProgress extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "uploader" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { style: { width: this.props.progress * 100 + "%" } })), this.props.progress < 0.999 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onCancel(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "close"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "action_cancel", defaultMessage: [{ "type": 0, "value": "cancel" }] })) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "upload_finishing", defaultMessage: [{ "type": 0, "value": "finishing..." }] })); } } /***/ }), /***/ "./src/widgets/forward-dialog.jsx": /*!****************************************!*\ !*** ./src/widgets/forward-dialog.jsx ***! \****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ ForwardDialog) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _contact_list_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./contact-list.jsx */ "./src/widgets/contact-list.jsx"); /* harmony import */ var _search_contacts_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./search-contacts.jsx */ "./src/widgets/search-contacts.jsx"); class ForwardDialog extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { query: null }; this.handleEscapeKey = this.handleEscapeKey.bind(this); this.handleClose = this.handleClose.bind(this); this.handleSearchContacts = this.handleSearchContacts.bind(this); this.handleContactSelected = this.handleContactSelected.bind(this); } componentDidMount() { this.props.onInitFind(); } handleEscapeKey(e) { if (e.keyCode === 27) { this.props.hide(false); } } handleClose(e) { e.preventDefault(); this.props.hide(false); } handleSearchContacts(query) { this.setState({ query: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isNullValue(query) ? null : query }); this.props.onSearchContacts(query); } handleContactSelected(uid) { this.props.onTopicSelected(uid); this.props.hide(true); } render() { let contacts = this.state.query != null ? this.props.searchResults : this.props.contacts; contacts = contacts.filter(c => { return c.name != this.props.topicSelected && c.acs.isJoiner() && c.acs.isWriter(); }); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "alert-container" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "forward-dialog" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "title with-control" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "forward_to", defaultMessage: [{ "type": 0, "value": "Forward to" }], desription: "Title of the contact selector dialog when forwarding a message" })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleClose }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "close")))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "forward_to_search_placeholder", defaultMessage: [{ "type": 0, "value": "Search contacts" }] }, search_placeholder => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_search_contacts_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { placeholder: search_placeholder, onSearchContacts: this.handleSearchContacts })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "search_no_results", defaultMessage: [{ "type": 0, "value": "Search returned no results" }] }, not_found_placeholder => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_contact_list_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, contacts: contacts, myUserId: this.props.myUserId, emptyListMessage: not_found_placeholder, showOnline: false, showUnread: false, showContextMenu: false, onTopicSelected: this.handleContactSelected })))); } } /***/ }), /***/ "./src/widgets/group-manager.jsx": /*!***************************************!*\ !*** ./src/widgets/group-manager.jsx ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _chip_input_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./chip-input.jsx */ "./src/widgets/chip-input.jsx"); /* harmony import */ var _contact_list_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./contact-list.jsx */ "./src/widgets/contact-list.jsx"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ no_contacts: { id: "no_contacts", defaultMessage: [{ "type": 0, "value": "You have no contacts :-(" }] }, contacts_not_found_short: { id: "contacts_not_found_short", defaultMessage: [{ "type": 0, "value": "No contacts match '" }, { "type": 1, "value": "query" }, { "type": 0, "value": "'" }] } }); class GroupManager extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { members: props.members, index: GroupManager.indexMembers(props.members), staticMembers: GroupManager.staticMembers(props.members, props.keepInitialMembers, props.requiredMember), contactFilter: '', noContactsMessage: props.intl.formatMessage(messages.no_contacts), selectedContacts: GroupManager.selectedContacts(props.members) }; this.handleContactSelected = this.handleContactSelected.bind(this); this.handleMemberRemoved = this.handleMemberRemoved.bind(this); this.handleContactFilter = this.handleContactFilter.bind(this); this.handleSubmit = this.handleSubmit.bind(this); this.handleCancel = this.handleCancel.bind(this); } static indexMembers(members) { let index = {}; members.forEach(m => { index[m.user] = { delta: 0, present: true }; }); return index; } static staticMembers(members, keepInitial, requiredMember) { let stat = []; members.forEach(m => { if (keepInitial || m.user == requiredMember) { stat.push(m.user); } }); return stat; } static selectedContacts(members) { let sel = []; members.forEach(m => { sel.push(m.user); }); return sel; } handleContactSelected(userId, index) { let status = this.state.index[userId]; if (status) { if (status.present) { return; } status.delta += 1; status.present = true; } else { status = { delta: 1, present: true }; } let m = this.state.members.slice(); m.push(this.props.contacts[index]); const sel = GroupManager.selectedContacts(m); const i = this.state.index; i[userId] = status; this.setState({ members: m, index: i, selectedContacts: sel }); } handleMemberRemoved(userId, index) { const status = this.state.index[userId]; if (!status || !status.present) { return; } status.present = false; status.delta -= 1; let m = this.state.members.slice(); m.splice(index, 1); const sel = GroupManager.selectedContacts(m); const i = this.state.index; i[userId] = status; this.setState({ members: m, index: i, selectedContacts: sel }); } handleContactFilter(val) { const { formatMessage } = this.props.intl; const msg = !val ? formatMessage(messages.no_contacts) : formatMessage(messages.contacts_not_found_short, { query: val }); this.setState({ contactFilter: val, noContactsMessage: msg }); } static doContactFiltering(filter, values) { if (filter) { for (let i = 0; i < values.length; i++) { if (values[i].indexOf(filter) >= 0) { return true; } } return false; } return true; } handleSubmit() { const members = []; const added = []; const removed = []; const keys = Object.keys(this.state.index); keys.forEach(k => { if (this.state.index[k].present) { members.push(k); } if (this.state.index[k].delta > 0) { added.push(k); } else if (this.state.index[k].delta < 0) { removed.push(k); } }); this.props.onSubmit(members, added, removed); } handleCancel() { this.props.onCancel(); } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "group-manager" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "title_group_members", defaultMessage: [{ "type": 0, "value": "Group Members" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_chip_input_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { tinode: this.props.tinode, chips: this.state.members, staticMembers: this.state.staticMembers, prompt: "add members", filterFunc: this.handleContactFilter, onChipRemoved: this.handleMemberRemoved })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "title_all_contacts", defaultMessage: [{ "type": 0, "value": "All Contacts" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_contact_list_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, contacts: this.props.contacts, myUserId: this.props.myUserId, topicSelected: this.state.selectedContacts, filter: this.state.contactFilter, filterFunc: GroupManager.doContactFiltering, emptyListMessage: this.state.noContactsMessage, showOnline: false, showUnread: false, onTopicSelected: this.handleContactSelected }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "group-manager-buttons", className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "secondary", onClick: this.handleCancel }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_cancel", defaultMessage: [{ "type": 0, "value": "Cancel" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "primary", onClick: this.handleSubmit }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_ok", defaultMessage: [{ "type": 0, "value": "OK" }] })))); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(GroupManager)); /***/ }), /***/ "./src/widgets/group-subs.jsx": /*!************************************!*\ !*** ./src/widgets/group-subs.jsx ***! \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ GroupSubs) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); class GroupSubs extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); } render() { const usersOnline = []; const totalCount = (this.props.subscribers || []).length; const countToShow = Math.min(_config_js__WEBPACK_IMPORTED_MODULE_2__.MAX_ONLINE_IN_TOPIC, totalCount); (this.props.subscribers || []).some(sub => { usersOnline.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "avatar-box", key: sub.user }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, topic: sub.user, avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__.makeImageUrl)(sub.public ? sub.public.photo : null) || true, title: sub.public ? sub.public.fn : null }))); return usersOnline.length == countToShow; }); if (usersOnline.length == 0) { return null; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "topic-users" }, usersOnline, " ", totalCount > countToShow ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "more_online_members", defaultMessage: [{ "type": 0, "value": "+" }, { "type": 1, "value": "overflow" }, { "type": 0, "value": " more" }], values: { overflow: totalCount - countToShow } })) : null); } } ; /***/ }), /***/ "./src/widgets/host-selector.jsx": /*!***************************************!*\ !*** ./src/widgets/host-selector.jsx ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ HostSelector) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); class HostSelector extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { hostName: props.serverAddress, changed: false }; this.handleHostNameChange = this.handleHostNameChange.bind(this); this.handleEditingFinished = this.handleEditingFinished.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); } handleHostNameChange(e) { this.setState({ hostName: e.target.value, changed: true }); } handleEditingFinished() { if (this.state.changed) { this.setState({ changed: false }); this.props.onServerAddressChange(this.state.hostName.trim()); } } handleKeyDown(e) { if (e.key == 'Enter') { this.handleEditingFinished(); } } render() { const hostOptions = []; for (let key in _config_js__WEBPACK_IMPORTED_MODULE_1__.KNOWN_HOSTS) { let item = _config_js__WEBPACK_IMPORTED_MODULE_1__.KNOWN_HOSTS[key]; hostOptions.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("option", { key: item, value: item })); } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "search", id: "host-name", placeholder: this.props.hostName, list: "known-hosts", className: "quoted", value: this.state.hostName, onChange: this.handleHostNameChange, onBlur: this.handleEditingFinished, onKeyDown: this.handleKeyDown, required: true }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("datalist", { id: "known-hosts" }, hostOptions)); } } /***/ }), /***/ "./src/widgets/image-preview.jsx": /*!***************************************!*\ !*** ./src/widgets/image-preview.jsx ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ ImagePreview) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _send_message_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./send-message.jsx */ "./src/widgets/send-message.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); class ImagePreview extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { width: 0, height: 0 }; this.handleSendImage = this.handleSendImage.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); } componentDidMount() { document.addEventListener('keydown', this.handleKeyDown); } componentWillUnmount() { document.removeEventListener('keydown', this.handleKeyDown); } handleKeyDown(e) { if (this.props.onSendMessage) { return; } e.preventDefault(); if (e.key === 'Escape') { this.props.onClose(); } } assignWidth(node) { if (node && !this.state.width) { const bounds = node.getBoundingClientRect(); this.setState({ width: bounds.width | 0, height: bounds.height | 0 }); } } handleSendImage(caption) { this.props.onClose(); this.props.onSendMessage(caption, this.props.content.blob); } render() { if (!this.props.content) { return null; } const dim = (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__.fitImageSize)(this.props.content.width, this.props.content.height, this.state.width, this.state.height, false); const size = dim ? { width: dim.dstWidth + 'px', height: dim.dstHeight + 'px' } : this.props.content.width > this.props.content.height ? { width: '100%' } : { height: '100%' }; size.maxWidth = '100%'; size.maxHeight = '100%'; const maxlength = Math.max((this.state.width / _config_js__WEBPACK_IMPORTED_MODULE_3__.REM_SIZE / 1.5 | 0) - 2, 12); const fname = (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_5__.shortenFileName)(this.props.content.filename, maxlength) || '-'; const width = this.props.content.width || '-'; const height = this.props.content.height || '-'; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "image-preview" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "image-preview-caption-panel" }, this.props.onSendMessage ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, fname) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: this.props.content.url, download: this.props.content.filename }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "file_download"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "download_action", defaultMessage: [{ "type": 0, "value": "download" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onClose(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons gray" }, "close"))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "image-preview-container", ref: node => this.assignWidth(node) }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { src: this.props.content.url, style: size, className: "image-preview", alt: this.props.content.filename })), this.props.onSendMessage ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_send_message_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { messagePrompt: "add_image_caption", acceptBlank: true, tinode: this.props.tinode, reply: this.props.reply, onCancelReply: this.props.onCancelReply, onSendMessage: this.handleSendImage, onError: this.props.onError }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "image-preview-footer" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("b", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_file_name", defaultMessage: [{ "type": 0, "value": "File name:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { title: this.props.content.filename }, fname))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("b", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_content_type", defaultMessage: [{ "type": 0, "value": "Content type:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, this.props.content.type)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("b", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_size", defaultMessage: [{ "type": 0, "value": "Size:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, width, " \xD7 ", height, " px; ", (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_5__.bytesToHumanSize)(this.props.content.size))))); } } ; /***/ }), /***/ "./src/widgets/in-place-edit.jsx": /*!***************************************!*\ !*** ./src/widgets/in-place-edit.jsx ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ InPlaceEdit) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _visible_password_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./visible-password.jsx */ "./src/widgets/visible-password.jsx"); class InPlaceEdit extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.selfRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.state = { active: props.active, initialValue: props.value || '', value: props.value || '' }; this.handeTextChange = this.handeTextChange.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); this.handleStartEditing = this.handleStartEditing.bind(this); this.handleEditingFinished = this.handleEditingFinished.bind(this); this.handlePasswordFinished = this.handlePasswordFinished.bind(this); } componentDidUpdate(prevProps, prevState) { const newValue = this.props.value || ''; if (prevState.initialValue != newValue && !prevState.active) { this.setState({ initialValue: newValue, value: newValue }); } } handeTextChange(e) { this.setState({ value: e.target.value || '' }); } handleKeyDown(e) { if (e.keyCode === 27) { this.setState({ value: this.props.value, active: false }); } else if (e.keyCode === 13) { this.handleEditingFinished(e); } } handleStartEditing() { if (!this.props.readOnly) { this.setState({ active: true }, _ => { if (this.selfRef.current) { this.selfRef.current.focus(); } }); } } handleEditingFinished(event) { const value = this.state.value.trim(); if (this.props.required && (!event.target.checkValidity() || !value)) { this.setState({ value: this.props.value, active: false }); return; } this.setState({ active: false }); if ((value || this.props.value) && value !== this.props.value) { this.props.onFinished(value); } } handlePasswordFinished(value) { this.setState({ active: false }); if (value && value !== this.props.value) { this.props.onFinished(value); } } render() { if (!this.state.active) { let spanText = this.props.type == 'password' ? '••••••••' : this.state.value; let spanClass = 'in-place-edit' + (this.props.readOnly ? ' disabled' : ''); if (!spanText) { spanText = this.props.placeholder; spanClass += ' placeholder'; } if (!this.props.multiline || this.props.multiline == 1) { spanClass += ' short'; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: spanClass, onClick: this.handleStartEditing }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, spanText)); } let element; const attr = {}; if (this.props.type == 'password') { element = _visible_password_jsx__WEBPACK_IMPORTED_MODULE_1__["default"]; attr.onFinished = this.handlePasswordFinished; } else { if (this.props.multiline > 1) { element = 'textarea'; attr.rows = this.props.multiline; attr.className = 'inplace-edit'; } else { element = 'input'; attr.type = this.props.type || 'text'; } attr.value = this.state.value; attr.ref = this.selfRef; attr.onChange = this.handeTextChange; attr.onKeyDown = this.handleKeyDown; attr.onBlur = this.handleEditingFinished; } attr.placeholder = this.props.placeholder; attr.required = this.props.required ? 'required' : ''; attr.autoComplete = this.props.autoComplete; attr.autoFocus = true; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(element, attr, null); } } ; /***/ }), /***/ "./src/widgets/inline-video.jsx": /*!**************************************!*\ !*** ./src/widgets/inline-video.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ InlineVideo) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); class InlineVideo extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.videoRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.handleClick = this.handleClick.bind(this); } handleClick(e) { if (this.props.onClick) { this.props.onClick(e); } } render() { const duration = (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_1__.secondsToTime)(this.props['data-duration'] / 1000); const className = 'inline-video' + (this.props.onClick ? ' image-clickable' : ''); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: className }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement('img', this.props), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "play-control" }, this.props.onClick ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons white bigger" }, "play_arrow") : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { src: "img/broken_video.png", style: { filter: 'invert(100%)' }, width: "36", height: "36" })), duration ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "duration" }, duration) : null); } } ; /***/ }), /***/ "./src/widgets/invitation.jsx": /*!************************************!*\ !*** ./src/widgets/invitation.jsx ***! \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ Invitation) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); class Invitation extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleButtonAction = this.handleButtonAction.bind(this); } handleButtonAction(evt, data) { evt.preventDefault(); this.props.onAction(data); } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "accept-invite-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "title" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "chat_invitation", defaultMessage: [{ "type": 0, "value": "You are invited to start a new chat. What would you like to do?" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "footer" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "primary", onClick: event => { this.handleButtonAction(event, "accept"); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "chat_invitation_accept", defaultMessage: [{ "type": 0, "value": "Accept" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "secondary", onClick: event => { this.handleButtonAction(event, "delete"); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "chat_invitation_ignore", defaultMessage: [{ "type": 0, "value": "Ignore" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "secondary", onClick: event => { this.handleButtonAction(event, "block"); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "chat_invitation_block", defaultMessage: [{ "type": 0, "value": "Block" }] })))); } } ; /***/ }), /***/ "./src/widgets/lazy-image.jsx": /*!************************************!*\ !*** ./src/widgets/lazy-image.jsx ***! \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ LazyImage) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); class LazyImage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { src: this.props.isvideo ? 'img/blankvid.png' : 'img/blankimg.png', style: Object.assign({ padding: '4px' }, this.props.style), className: this.props.className, alt: this.props.alt, onClick: this.props.onClick }; } componentDidMount() { this.props.whenDone.promise.then(data => this.setState({ src: data.src, style: { ...this.state.style, padding: 0 } })).catch(_ => this.setState({ src: this.props.isvideo ? 'img/broken_video.png' : 'img/broken_image.png' })); } componentWillUnmount() { this.props.whenDone.cancel(); } componentDidUpdate(prevProps) { if (prevProps.whenDone != this.props.whenDone) { this.setState({ src: this.props.isvideo ? 'img/blankvid.png' : 'img/blankimg.png', style: { ...this.state.style, padding: '4px' } }); this.props.whenDone.promise.then(data => this.setState({ src: data.src, style: { ...this.state.style, padding: 0 } })).catch(_ => this.setState({ src: this.props.isvideo ? 'img/broken_video.png' : 'img/broken_image.png' })); } } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement('img', this.state); } } ; /***/ }), /***/ "./src/widgets/letter-tile.jsx": /*!*************************************!*\ !*** ./src/widgets/letter-tile.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ LetterTile) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); class LetterTile extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { let avatar; if (this.props.avatar === true) { const isGroup = tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Tinode.isGroupTopicName(this.props.topic); const iconColor = (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_2__.idToColorClass)(this.props.topic, isGroup); if (this.props.topic && this.props.title && this.props.title.trim()) { const letter = this.props.title.trim().charAt(0); const className = 'lettertile ' + iconColor + (this.props.deleted ? ' disabled' : ''); avatar = react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: className }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, letter)); } else { const className = 'material-icons ' + iconColor + (this.props.deleted ? ' disabled' : ''); avatar = isGroup ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: className }, "group") : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: className }, "person"); } } else if (this.props.avatar) { const url = this.props.tinode.authorizeURL((0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_3__.sanitizeUrlForMime)(this.props.avatar, 'image')); const className = 'avatar' + (this.props.deleted ? ' deleted' : ''); avatar = react__WEBPACK_IMPORTED_MODULE_0___default().createElement("img", { className: className, alt: "avatar", src: url, onError: e => { e.target.onerror = null; e.target.src = "../img/broken_image.png"; } }); } else { avatar = null; } return avatar; } } /***/ }), /***/ "./src/widgets/load-spinner.jsx": /*!**************************************!*\ !*** ./src/widgets/load-spinner.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ LoadSpinner) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); class LoadSpinner extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { const className = 'load-spinner-box' + (this.props.large ? ' large' : '') + (this.props.clear ? ' clear' : '') + (this.props.centered ? ' centered' : ''); return this.props.show ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: className }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "loader-spinner" })) : null; } } /***/ }), /***/ "./src/widgets/menu-cancel.jsx": /*!*************************************!*\ !*** ./src/widgets/menu-cancel.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ MenuCancel) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); class MenuCancel extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onCancel(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "close")); } } /***/ }), /***/ "./src/widgets/menu-contacts.jsx": /*!***************************************!*\ !*** ./src/widgets/menu-contacts.jsx ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ MenuContacts) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); class MenuContacts extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onNewTopic(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "chat")), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onSettings(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "settings"))); } } ; /***/ }), /***/ "./src/widgets/menu-start.jsx": /*!************************************!*\ !*** ./src/widgets/menu-start.jsx ***! \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ MenuStart) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); class MenuStart extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onSignUp(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "person_add")), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onSettings(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "settings"))); } } ; /***/ }), /***/ "./src/widgets/meta-message.jsx": /*!**************************************!*\ !*** ./src/widgets/meta-message.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ MetaMessage) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); class MetaMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); } render() { let content = null; let bubbleClass = 'bubble'; if (this.props.date) { content = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, this.props.date); bubbleClass += ' date'; } if (!content) { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, null); } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("li", { className: "meta" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: bubbleClass }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "message-content" }, content))); } } ; /***/ }), /***/ "./src/widgets/new-topic-by-id.jsx": /*!*****************************************!*\ !*** ./src/widgets/new-topic-by-id.jsx ***! \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ invalid_id: { id: "error_invalid_id", defaultMessage: [{ "type": 0, "value": "Invalid ID" }] } }); class NewTopicById extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { groupId: '' }; this.handleChange = this.handleChange.bind(this); this.handleKeyPress = this.handleKeyPress.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(e) { this.setState({ groupId: e.target.value }); } handleKeyPress(e) { if (e.key === 'Enter') { this.handleSubmit(e); } } handleSubmit(e) { e.preventDefault(); if (this.state.groupId) { const name = this.state.groupId.trim(); const prefix = name.substr(0, 3); if (name.length > 3 && ['usr', 'grp', 'chn'].includes(prefix)) { this.props.onSubmit(name); } else { this.props.onError(this.props.intl.formatMessage(messages.invalid_id), 'err'); } } } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "group_user_id_prompt", defaultMessage: [{ "type": 0, "value": "Group or User ID" }] }, prompt => react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", placeholder: prompt, value: this.state.groupId, onChange: this.handleChange, onKeyPress: this.handleKeyPress, required: true, autoFocus: true }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "dialog-buttons" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "primary", onClick: this.handleSubmit }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_subscribe", defaultMessage: [{ "type": 0, "value": "Subscribe" }] })))); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(NewTopicById)); /***/ }), /***/ "./src/widgets/new-topic-group.jsx": /*!*****************************************!*\ !*** ./src/widgets/new-topic-group.jsx ***! \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ NewTopicGroup) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _avatar_crop_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./avatar-crop.jsx */ "./src/widgets/avatar-crop.jsx"); /* harmony import */ var _avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./avatar-upload.jsx */ "./src/widgets/avatar-upload.jsx"); /* harmony import */ var _checkbox_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./checkbox.jsx */ "./src/widgets/checkbox.jsx"); /* harmony import */ var _tag_manager_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./tag-manager.jsx */ "./src/widgets/tag-manager.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); class NewTopicGroup extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.fullName = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.state = { fullName: '', private: '', description: '', imageUrl: null, tags: [], isChannel: false, newAvatar: null, newAvatarMime: null }; this.handleFieldEdit = this.handleFieldEdit.bind(this); this.handleImageChanged = this.handleImageChanged.bind(this); this.handleAvatarCropped = this.handleAvatarCropped.bind(this); this.handleAvatarCropCancel = this.handleAvatarCropCancel.bind(this); this.uploadAvatar = this.uploadAvatar.bind(this); this.handleTagsChanged = this.handleTagsChanged.bind(this); this.handleChannelToggle = this.handleChannelToggle.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } componentDidMount() {} handleFieldEdit(name, e) { this.setState({ [name]: e.target.value || '' }); } handleImageChanged(mime, img) { this.setState({ newAvatar: img, newAvatarMime: mime }); } handleAvatarCropped(mime, blob, width, height) { const url = blob ? URL.createObjectURL(blob) : null; this.setState({ imageUrl: url, newAvatar: null, newAvatarMime: null }); if (blob) { this.uploadAvatar(mime, blob, width, height); } } handleAvatarCropCancel() { this.setState({ newAvatar: null, newAvatarMime: null }); } uploadAvatar(mime, blob, width, height) { const readyToUpload = image => { let { mime, blob } = image; if (blob.size > _config_js__WEBPACK_IMPORTED_MODULE_6__.MAX_AVATAR_BYTES) { const uploader = this.props.tinode.getLargeFileHelper(); uploader.upload(blob).then(url => this.setState({ imageUrl: url })).catch(err => this.props.onError(err.message, 'err')); } else { (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_7__.blobToBase64)(blob).then(b64 => this.setState({ imageUrl: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_7__.makeImageUrl)({ data: b64.bits, type: mime }) })); } }; if (width > _config_js__WEBPACK_IMPORTED_MODULE_6__.AVATAR_SIZE || height > _config_js__WEBPACK_IMPORTED_MODULE_6__.AVATAR_SIZE || width != height) { (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_7__.imageScaled)(blob, _config_js__WEBPACK_IMPORTED_MODULE_6__.AVATAR_SIZE, _config_js__WEBPACK_IMPORTED_MODULE_6__.AVATAR_SIZE, _config_js__WEBPACK_IMPORTED_MODULE_6__.MAX_EXTERN_ATTACHMENT_SIZE, true).then(scaled => readyToUpload(scaled)).catch(err => this.props.onError(err.message, 'err')); } else { readyToUpload({ mime: mime, blob: blob, width: width, height: height }); } } handleTagsChanged(tags) { this.setState({ tags: tags }); } handleChannelToggle() { this.setState({ isChannel: !this.state.isChannel }); } handleSubmit(e) { e.preventDefault(); const fn = this.state.fullName.trim().substring(0, _config_js__WEBPACK_IMPORTED_MODULE_6__.MAX_TITLE_LENGTH); const comment = this.state.private.trim().substring(0, _config_js__WEBPACK_IMPORTED_MODULE_6__.MAX_TITLE_LENGTH); const description = this.state.description.trim().substring(0, _config_js__WEBPACK_IMPORTED_MODULE_6__.MAX_TOPIC_DESCRIPTION_LENGTH); if (fn) { this.props.onSubmit(fn, description, this.state.imageUrl, comment, this.state.tags, this.state.isChannel); } } render() { if (this.state.newAvatar) { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_avatar_crop_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { avatar: this.state.newAvatar, mime: this.state.newAvatarMime, onSubmit: this.handleAvatarCropped, onCancel: this.handleAvatarCropCancel, onError: this.props.onError }); } let submitClasses = 'primary'; if (this.props.disabled) { submitClasses += ' disabled'; } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("form", { className: "panel-form", onSubmit: this.handleSubmit }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("center", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, avatar: this.state.imageUrl, onError: this.props.onError, onImageUpdated: this.handleImageChanged })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small", htmlFor: "new-topic-fn" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_topic_name", defaultMessage: [{ "type": 0, "value": "Name" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "topic_name_editing_placeholder", defaultMessage: [{ "type": 0, "value": "Freeform name of the group" }] }, placeholder => react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", id: "new-topic-fn", placeholder: placeholder, ref: this.fullName, value: this.state.fullName, onChange: this.handleFieldEdit.bind(this, 'fullName'), autoFocus: true, required: true, tabIndex: 0 }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small", htmlFor: "new-topic-priv" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_private", defaultMessage: [{ "type": 0, "value": "Private comment" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "private_editing_placeholder", defaultMessage: [{ "type": 0, "value": "Visible to you only" }] }, placeholder => react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", id: "new-topic-priv", placeholder: placeholder, value: this.state.private, onChange: this.handleFieldEdit.bind(this, 'private'), tabIndex: 1 }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small", htmlFor: "new-topic-desc" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_description", defaultMessage: [{ "type": 0, "value": "Description" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "description_editing_placeholder", defaultMessage: [{ "type": 0, "value": "Description (optional)" }] }, placeholder => react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", id: "new-topic-desc", placeholder: placeholder, value: this.state.description, onChange: this.handleFieldEdit.bind(this, 'description'), tabIndex: 2 })))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_checkbox_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { checked: this.state.isChannel, tabIndex: 3, onChange: this.handleChannelToggle }), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { onClick: this.handleChannelToggle }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "channel_prompt", defaultMessage: [{ "type": 0, "value": "This is a channel" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "title_tag_manager", defaultMessage: [{ "type": 0, "value": "Tags (search & discovery)" }] }, title => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_tag_manager_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { tinode: this.props.tinode, tags: this.state.tags, activated: true, onTagsChanged: this.handleTagsChanged, tabIndex: 4, title: title })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "dialog-buttons" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: submitClasses }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_create", defaultMessage: [{ "type": 0, "value": "Create" }] })))); } } ; /***/ }), /***/ "./src/widgets/permissions-editor.jsx": /*!********************************************!*\ !*** ./src/widgets/permissions-editor.jsx ***! \********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./checkbox.jsx */ "./src/widgets/checkbox.jsx"); /* harmony import */ var _contact_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./contact.jsx */ "./src/widgets/contact.jsx"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ joiner: { id: "permission_join", defaultMessage: [{ "type": 0, "value": "Join (" }, { "type": 1, "value": "val" }, { "type": 0, "value": ")" }] }, reader: { id: "permission_read", defaultMessage: [{ "type": 0, "value": "Read (" }, { "type": 1, "value": "val" }, { "type": 0, "value": ")" }] }, writer: { id: "permission_write", defaultMessage: [{ "type": 0, "value": "Write (" }, { "type": 1, "value": "val" }, { "type": 0, "value": ")" }] }, preser: { id: "permission_pres", defaultMessage: [{ "type": 0, "value": "Get notified (" }, { "type": 1, "value": "val" }, { "type": 0, "value": ")" }] }, approver: { id: "permission_admin", defaultMessage: [{ "type": 0, "value": "Approve (" }, { "type": 1, "value": "val" }, { "type": 0, "value": ")" }] }, sharer: { id: "permission_share", defaultMessage: [{ "type": 0, "value": "Share (" }, { "type": 1, "value": "val" }, { "type": 0, "value": ")" }] }, deleter: { id: "permission_delete", defaultMessage: [{ "type": 0, "value": "Delete (" }, { "type": 1, "value": "val" }, { "type": 0, "value": ")" }] }, owner: { id: "permission_owner", defaultMessage: [{ "type": 0, "value": "Owner (" }, { "type": 1, "value": "val" }, { "type": 0, "value": ")" }] } }); class PermissionsEditor extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { mode: (props.mode || '').replace('N', '') }; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); this.handleCancel = this.handleCancel.bind(this); } handleChange(val) { let mode = this.state.mode; const idx = mode.indexOf(val); if (idx == -1) { mode += val; } else { mode = mode.replace(val, ''); } this.setState({ mode: mode }); } handleSubmit() { const mode = (this.state.mode || 'N').split('').sort().join(''); const before = (this.props.mode || 'N').split('').sort().join(''); if (mode !== before) { this.props.onSubmit(mode); } else { this.props.onCancel(); } } handleCancel() { this.props.onCancel(); } render() { const { formatMessage } = this.props.intl; const all = 'JRWPASDO'; const names = { 'J': formatMessage(messages.joiner, { val: 'J' }), 'R': formatMessage(messages.reader, { val: 'R' }), 'W': formatMessage(messages.writer, { val: 'W' }), 'P': formatMessage(messages.preser, { val: 'P' }), 'A': formatMessage(messages.approver, { val: 'A' }), 'S': formatMessage(messages.sharer, { val: 'S' }), 'D': formatMessage(messages.deleter, { val: 'D' }), 'O': formatMessage(messages.owner, { val: 'O' }) }; let skip = this.props.skip || ''; let mode = this.state.mode; let compare = (this.props.compare || '').replace('N', ''); let items = []; for (let i = 0; i < all.length; i++) { let c = all.charAt(i); if (skip.indexOf(c) >= 0 && mode.indexOf(c) < 0) { continue; } items.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tr", { key: c }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", null, names[c]), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", { className: "checkbox" }, skip.indexOf(c) < 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { name: c, checked: mode.indexOf(c) >= 0, onChange: this.handleChange }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { name: c, checked: mode.indexOf(c) >= 0 })), this.props.compare ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", { className: "checkbox" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_checkbox_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { name: c, checked: compare.indexOf(c) >= 0 })) : null)); } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, this.props.userTitle ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("ul", { className: "contact-box small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_contact_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, item: this.props.item, title: this.props.userTitle, small: true, avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__.makeImageUrl)(this.props.userAvatar ? this.props.userAvatar : null) })) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "title_permissions", defaultMessage: [{ "type": 0, "value": "Permissions" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("table", { className: "permission-editor" }, this.props.compare ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("thead", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tr", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("th", null), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("th", null, this.props.modeTitle), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("th", null, this.props.compareTitle))) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tbody", null, items)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("br", null), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "dialog-buttons" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "outline", onClick: this.handleCancel }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_cancel", defaultMessage: [{ "type": 0, "value": "Cancel" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "primary", onClick: this.handleSubmit }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_ok", defaultMessage: [{ "type": 0, "value": "OK" }] })))); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(PermissionsEditor)); /***/ }), /***/ "./src/widgets/pinned-messages.jsx": /*!*****************************************!*\ !*** ./src/widgets/pinned-messages.jsx ***! \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _lib_formatters_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/formatters.js */ "./src/lib/formatters.js"); class PinnedMessages extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.getSelectedIndex = this.getSelectedIndex.bind(this); this.handleCancel = this.handleCancel.bind(this); this.handleSelected = this.handleSelected.bind(this); this.handleMoveNext = this.handleMoveNext.bind(this); this.handleMovePrev = this.handleMovePrev.bind(this); } getSelectedIndex() { const list = this.props.messages || []; return list.length - this.props.selected - 1; } handleCancel(e) { e.preventDefault(); this.props.onCancel(this.props.messages[this.getSelectedIndex()].seq); } handleSelected(e) { e.preventDefault(); this.props.onSelected(this.props.messages[this.getSelectedIndex()].seq); } handleMoveNext(e) { e.preventDefault(); e.stopPropagation(); const idx = Math.max(this.props.selected - 1, 0); if (idx != this.props.selected) { this.props.setSelected(idx); } } handleMovePrev(e) { e.preventDefault(); e.stopPropagation(); const idx = Math.min(this.props.selected + 1, (this.props.messages || []).length - 1); if (idx != this.props.selected) { this.props.setSelected(idx); } } render() { const selected = this.getSelectedIndex(); let shown = (this.props.messages || [])[selected]; shown = shown ? tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.format(shown.content, _lib_formatters_js__WEBPACK_IMPORTED_MODULE_3__.previewFormatter, { formatMessage: this.props.intl.formatMessage.bind(this.props.intl), authorizeURL: this.props.tinode.authorizeURL.bind(this.props.tinode) }) : null; const dots = []; this.props.messages.forEach(_ => { const cn = dots.length == selected ? 'adot' : 'dot'; dots.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { key: dots.length, className: cn })); }); return shown ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "pinned-wrapper" }, this.props.isAdmin ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "cancel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleCancel }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons gray" }, "close"))) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons gray" }, "push_pin")), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "pinned-scroll" }, dots), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "pinned", onClick: this.handleSelected }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("p", null, shown)), selected > 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "menuTrigger upper" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleMovePrev }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "expand_less"))) : null, this.props.selected > 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "menuTrigger lower" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleMoveNext }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "expand_more"))) : null) : null; } } /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(PinnedMessages)); /***/ }), /***/ "./src/widgets/received-marker.jsx": /*!*****************************************!*\ !*** ./src/widgets/received-marker.jsx ***! \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ message_sending: { id: "message_sending", defaultMessage: [{ "type": 0, "value": "sending..." }] }, message_sending_failed: { id: "message_sending_failed", defaultMessage: [{ "type": 0, "value": "failed" }] }, message_edited_marker: { id: "message_edited_marker", defaultMessage: [{ "type": 0, "value": ", edited" }] } }); class ReceivedMarker extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { const { formatMessage } = this.props.intl; let timestamp; if (this.props.received <= tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_SENDING) { timestamp = formatMessage(messages.message_sending); } else if (this.props.received == tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_FAILED || this.props.received == tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_FATAL) { timestamp = formatMessage(messages.message_sending_failed); } else { timestamp = this.props.timestamp.toLocaleTimeString(this.props.intl.locale, { timeStyle: 'short' }); } const icon = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_3__.deliveryMarker)(this.props.received); const marker = icon ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: 'material-icons small ' + icon.color }, icon.name) : null; const edited = this.props.edited ? formatMessage(messages.message_edited_marker) : null; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "timestamp" }, timestamp, edited, '\u00a0', marker); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(ReceivedMarker)); /***/ }), /***/ "./src/widgets/search-contacts.jsx": /*!*****************************************!*\ !*** ./src/widgets/search-contacts.jsx ***! \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ SearchContacts) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_1__); class SearchContacts extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { edited: false, search: '' }; this.handleSearchChange = this.handleSearchChange.bind(this); this.handleSearch = this.handleSearch.bind(this); this.handleClear = this.handleClear.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); } componentWillUnmount() { if (this.state.edited) { this.setState({ search: '', edited: false }); this.props.onSearchContacts(tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Tinode.DEL_CHAR); } } handleSearchChange(e) { this.setState({ search: e.target.value }); } handleSearch(e) { e.preventDefault(); const query = this.state.search.trim(); this.setState({ edited: query.length > 0 }); this.props.onSearchContacts(query.length > 0 ? query : tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Tinode.DEL_CHAR); } handleClear(e) { e.preventDefault(); if (this.state.edited) { this.props.onSearchContacts(tinode_sdk__WEBPACK_IMPORTED_MODULE_1__.Tinode.DEL_CHAR); } this.setState({ search: '', edited: false }); } handleKeyDown(e) { if (e.key === 'Enter') { this.handleSearch(e); } else if (e.key === 'Escape') { this.handleClear(); } } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons search" }, "search"), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { className: "search", type: "text", placeholder: this.props.placeholder, value: this.state.search, onChange: this.handleSearchChange, onKeyDown: this.handleKeyDown, required: true, autoFocus: true }), this.state.search ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleClear }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "highlight_off")) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "\xA0")))); } } ; /***/ }), /***/ "./src/widgets/send-message.jsx": /*!**************************************!*\ !*** ./src/widgets/send-message.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_formatters_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/formatters.js */ "./src/lib/formatters.js"); const AudioRecorder = react__WEBPACK_IMPORTED_MODULE_0___default().lazy(_ => Promise.all(/*! import() */[__webpack_require__.e("vendors-node_modules_webm-duration-fix_lib_index_js"), __webpack_require__.e("src_widgets_audio-recorder_jsx")]).then(__webpack_require__.bind(__webpack_require__, /*! ./audio-recorder.jsx */ "./src/widgets/audio-recorder.jsx"))); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ messaging_disabled: { id: "messaging_disabled_prompt", defaultMessage: [{ "type": 0, "value": "Messaging disabled" }] }, type_new_message: { id: "new_message_prompt", defaultMessage: [{ "type": 0, "value": "New message" }] }, add_image_caption: { id: "image_caption_prompt", defaultMessage: [{ "type": 0, "value": "Image caption" }] }, file_attachment_too_large: { id: "file_attachment_too_large", defaultMessage: [{ "type": 0, "value": "The file size " }, { "type": 1, "value": "size" }, { "type": 0, "value": " exceeds the " }, { "type": 1, "value": "limit" }, { "type": 0, "value": " limit." }] }, cannot_initiate_upload: { id: "cannot_initiate_file_upload", defaultMessage: [{ "type": 0, "value": "Cannot initiate file upload." }] }, icon_title_record_voice: { id: "icon_title_record_voice", defaultMessage: [{ "type": 0, "value": "Record voice message" }] }, icon_title_attach_file: { id: "icon_title_attach_file", defaultMessage: [{ "type": 0, "value": "Attach file" }] }, icon_title_add_image: { id: "icon_title_add_image", defaultMessage: [{ "type": 0, "value": "Add image" }] }, icon_title_send: { id: "icon_title_send", defaultMessage: [{ "type": 0, "value": "Send message" }] } }); class SendMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { quote: null, message: '', audioRec: false, audioAvailable: !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) }; this.keypressTimestamp = 0; this.handlePasteEvent = this.handlePasteEvent.bind(this); this.handleAttachImage = this.handleAttachImage.bind(this); this.handleAttachFile = this.handleAttachFile.bind(this); this.handleAttachAudio = this.handleAttachAudio.bind(this); this.handleSend = this.handleSend.bind(this); this.handleKeyPress = this.handleKeyPress.bind(this); this.handleMessageTyping = this.handleMessageTyping.bind(this); this.handleDropAttach = this.handleDropAttach.bind(this); this.handleQuoteClick = this.handleQuoteClick.bind(this); this.formatReply = this.formatReply.bind(this); } componentDidMount() { if (this.messageEditArea) { this.messageEditArea.addEventListener('paste', this.handlePasteEvent, false); if (window.getComputedStyle(this.messageEditArea).getPropertyValue('transition-property') == 'all') { this.messageEditArea.focus(); } } this.setState({ quote: this.formatReply() }); } componentWillUnmount() { if (this.messageEditArea) { this.messageEditArea.removeEventListener('paste', this.handlePasteEvent, false); } } componentDidUpdate(prevProps) { if (this.messageEditArea) { if (window.getComputedStyle(this.messageEditArea).getPropertyValue('transition-property') == 'all') { this.messageEditArea.focus(); } this.messageEditArea.style.height = '0px'; this.messageEditArea.style.height = this.messageEditArea.scrollHeight + 'px'; } if (prevProps.topicName != this.props.topicName) { this.setState({ message: this.props.initMessage || '', audioRec: false, quote: null }); } else if (prevProps.initMessage != this.props.initMessage) { const msg = this.props.initMessage || ''; this.setState({ message: msg }, _ => { this.messageEditArea.scrollTop = this.messageEditArea.scrollHeight; this.messageEditArea.setSelectionRange(msg.length, msg.length); }); } if (prevProps.reply != this.props.reply) { this.setState({ quote: this.formatReply() }); } } formatReply() { return this.props.reply ? tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.format(this.props.reply.content, _lib_formatters_js__WEBPACK_IMPORTED_MODULE_5__.replyFormatter, { formatMessage: this.props.intl.formatMessage.bind(this.props.intl), authorizeURL: this.props.tinode.authorizeURL.bind(this.props.tinode) }) : null; } handlePasteEvent(e) { if (this.props.disabled) { return; } if ((0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__.filePasted)(e, file => { this.props.onAttachImage(file); }, file => { this.props.onAttachFile(file); }, this.props.onError)) { e.preventDefault(); } } handleAttachImage(e) { if (e.target.files && e.target.files.length > 0) { this.props.onAttachImage(e.target.files[0]); } e.target.value = ''; } handleAttachFile(e) { if (e.target.files && e.target.files.length > 0) { this.props.onAttachFile(e.target.files[0]); } e.target.value = ''; } handleDropAttach(files) { if (files && files.length > 0) { this.props.onAttachFile(files[0]); } } handleAttachAudio(url, preview, duration) { this.setState({ audioRec: false }); this.props.onAttachAudio(url, preview, duration); } handleSend(e) { e.preventDefault(); const message = this.state.message.trim(); if (message || this.props.acceptBlank || this.props.noInput) { this.props.onSendMessage(message); this.setState({ message: '' }); } } handleKeyPress(e) { if (this.state.audioRec) { e.preventDefault(); e.stopPropagation(); return; } if (e.key === 'Enter') { if (!e.shiftKey) { e.preventDefault(); e.stopPropagation(); this.handleSend(e); } } } handleMessageTyping(e) { this.setState({ message: e.target.value }); if (this.props.onKeyPress) { const now = new Date().getTime(); if (now - this.keypressTimestamp > _config_js__WEBPACK_IMPORTED_MODULE_3__.KEYPRESS_DELAY) { this.props.onKeyPress(); this.keypressTimestamp = now; } } } handleQuoteClick(e) { e.preventDefault(); e.stopPropagation(); if (this.props.reply && this.props.onQuoteClick) { const replyToSeq = this.props.reply.seq; this.props.onQuoteClick(replyToSeq); } } render() { const { formatMessage } = this.props.intl; const prompt = this.props.disabled ? formatMessage(messages.messaging_disabled) : this.props.messagePrompt ? formatMessage(messages[this.props.messagePrompt]) : formatMessage(messages.type_new_message); const sendIcon = this.props.reply && this.props.reply.editing ? 'check_circle' : 'send'; const quote = this.state.quote ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "reply-quote-preview" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "cancel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onCancelReply(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons gray" }, "close"))), this.state.quote) : null; const audioEnabled = this.state.audioAvailable && this.props.onAttachAudio; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "send-message-wrapper" }, !this.props.noInput ? quote : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "send-message-panel" }, !this.props.disabled ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, this.props.onAttachFile && !this.state.audioRec ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.attachImage.click(); }, title: formatMessage(messages.icon_title_add_image) }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons secondary" }, "photo")), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.attachFile.click(); }, title: formatMessage(messages.icon_title_attach_file) }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons secondary" }, "attach_file"))) : null, this.props.noInput ? quote || react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr thin" }) : this.state.audioRec ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, { fallback: react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "loading_note", defaultMessage: [{ "type": 0, "value": "Loading..." }] })) }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(AudioRecorder, { onRecordingProgress: _ => this.props.onKeyPress(true), onDeleted: _ => this.setState({ audioRec: false }), onFinished: this.handleAttachAudio })) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("textarea", { id: "send-message-input", placeholder: prompt, value: this.state.message, onChange: this.handleMessageTyping, onKeyDown: this.handleKeyPress, ref: ref => { this.messageEditArea = ref; } }), this.state.message || !audioEnabled ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: this.handleSend, title: formatMessage(messages.icon_title_send) }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, sendIcon)) : !this.state.audioRec ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.setState({ audioRec: true }); }, title: formatMessage(messages.icon_title_record_voice) }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "mic")) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "file", ref: ref => { this.attachFile = ref; }, onChange: this.handleAttachFile, style: { display: 'none' } }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "file", ref: ref => { this.attachImage = ref; }, accept: "image/*, video/*", onChange: this.handleAttachImage, style: { display: 'none' } })) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "writing-disabled" }, prompt))); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(SendMessage)); /***/ }), /***/ "./src/widgets/side-navbar.jsx": /*!*************************************!*\ !*** ./src/widgets/side-navbar.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ SideNavbar) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _button_back_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./button-back.jsx */ "./src/widgets/button-back.jsx"); /* harmony import */ var _contact_badges_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./contact-badges.jsx */ "./src/widgets/contact-badges.jsx"); /* harmony import */ var _menu_contacts_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./menu-contacts.jsx */ "./src/widgets/menu-contacts.jsx"); /* harmony import */ var _menu_start_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./menu-start.jsx */ "./src/widgets/menu-start.jsx"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); class SideNavbar extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { const icon_badges = []; if (this.props.trustedBadges) { this.props.trustedBadges.forEach(b => { icon_badges.push({ icon: b, color: 'badge-inv' }); }); } let avatar = null; if (this.props.tinode) { avatar = this.props.tinode.authorizeURL((0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_6__.sanitizeUrlForMime)(this.props.avatar, 'image')); } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "side-caption-panel", className: "caption-panel" }, this.props.onCancel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_button_back_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { onBack: this.props.onCancel }) : null, avatar ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "self-avatar", className: "avatar-box" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { tinode: this.props.tinode, avatar: avatar, topic: this.props.myUserId, title: this.props.title })) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "sidepanel-title", className: "panel-title" }, this.props.title, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_contact_badges_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { badges: icon_badges })), this.props.state === 'login' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_menu_start_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { onSignUp: this.props.onSignUp, onSettings: this.props.onSettings }) : this.props.state === 'contacts' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_menu_contacts_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { onNewTopic: this.props.onNewTopic, onSettings: this.props.onSettings }) : null); } } ; /***/ }), /***/ "./src/widgets/tag-manager.jsx": /*!*************************************!*\ !*** ./src/widgets/tag-manager.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ TagManager) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _chip_input_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./chip-input.jsx */ "./src/widgets/chip-input.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); class TagManager extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.state = { tags: this.props.tags || [], tagInput: '', activated: this.props.activated }; this.handleTagInput = this.handleTagInput.bind(this); this.handleAddTag = this.handleAddTag.bind(this); this.handleRemoveTag = this.handleRemoveTag.bind(this); this.handleSubmit = this.handleSubmit.bind(this); this.handleCancel = this.handleCancel.bind(this); } static getDerivedStateFromProps(nextProps, prevState) { const tags = nextProps.tags || []; if (!(0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_4__.arrayEqual)(tags, prevState.tags) && !prevState.activated) { return { tags: tags }; } return null; } handleTagInput(text) { this.setState({ tagInput: text }); if (text.length > 0) { const last = text[text.length - 1]; if (text[0] == '"') { if (text.length > 1 && last == '"') { this.handleAddTag(text.substring(1, text.length - 1)); } } else if (last == ',' || last == ' ' || last == ';' || last == '"') { this.handleAddTag(text.substring(0, text.length - 1).trim()); } } } handleAddTag(tag) { const maxTagCount = this.props.tinode.getServerParam('maxTagCount', _config_js__WEBPACK_IMPORTED_MODULE_3__.MAX_TAG_COUNT); if (tag.length > 0 && this.state.tags.length < maxTagCount) { const tags = this.state.tags.slice(0); tags.push(tag); this.setState({ tags: tags, tagInput: '' }); if (this.props.onTagsChanged) { this.props.onTagsChanged(tags); } return tags; } return this.state.tags; } handleRemoveTag(tag, index) { const tags = this.state.tags.slice(0); tags.splice(index, 1); this.setState({ tags: tags }); if (this.props.onTagsChanged) { this.props.onTagsChanged(tags); } } handleSubmit() { this.props.onSubmit(this.handleAddTag(this.state.tagInput.trim())); this.setState({ activated: false, tags: this.props.tags || [] }); } handleCancel() { this.setState({ activated: false, tagInput: '', tags: this.props.tags || [] }); if (this.props.onCancel) { this.props.onCancel(); } } render() { const minTagLength = this.props.tinode.getServerParam('minTagLength', _config_js__WEBPACK_IMPORTED_MODULE_3__.MIN_TAG_LENGTH); const maxTagLength = this.props.tinode.getServerParam('maxTagLength', _config_js__WEBPACK_IMPORTED_MODULE_3__.MAX_TAG_LENGTH); let tags = []; if (this.state.activated) { this.state.tags.forEach(tag => { tags.push({ user: tag, invalid: tag.length < minTagLength || tag.length > maxTagLength }); }); } else { this.state.tags.forEach(tag => { tags.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "badge", key: tags.length }, tag)); }); if (tags.length == 0) { tags = react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "tags_not_found", defaultMessage: [{ "type": 0, "value": "No tags defined. Add some." }] })); } } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, this.props.title)), this.state.activated ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "tags_editor_no_tags", defaultMessage: [{ "type": 0, "value": "Add some tags" }] }, add_tags_prompt => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_chip_input_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { tinode: this.props.tinode, chips: tags, avatarDisabled: true, prompt: add_tags_prompt, tabIndex: this.props.tabIndex, onEnter: this.handleAddTag, onFocusLost: this.handleAddTag, onCancel: this.handleCancel, onChipRemoved: this.handleRemoveTag, filterFunc: this.handleTagInput })), this.props.onSubmit || this.props.onCancel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "tag-manager-buttons", className: "dialog-buttons panel-form-row" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "outline", onClick: this.handleCancel }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_cancel", defaultMessage: [{ "type": 0, "value": "Cancel" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "primary", onClick: this.handleSubmit }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "button_ok", defaultMessage: [{ "type": 0, "value": "OK" }] }))) : null) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "quoted" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "flat-button", onClick: e => { e.preventDefault(); this.setState({ activated: true }); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "edit"), " \xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "title_manage_tags", defaultMessage: [{ "type": 0, "value": "Manage" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, tags))); } } ; /***/ }), /***/ "./src/widgets/topic-desc-edit.jsx": /*!*****************************************!*\ !*** ./src/widgets/topic-desc-edit.jsx ***! \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ TopicDescEdit) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk"); /* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _avatar_crop_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./avatar-crop.jsx */ "./src/widgets/avatar-crop.jsx"); /* harmony import */ var _avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./avatar-upload.jsx */ "./src/widgets/avatar-upload.jsx"); /* harmony import */ var _in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./in-place-edit.jsx */ "./src/widgets/in-place-edit.jsx"); /* harmony import */ var _tag_manager_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./tag-manager.jsx */ "./src/widgets/tag-manager.jsx"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); class TopicDescEdit extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); const topic = this.props.tinode.getTopic(this.props.topic); const acs = topic.getAccessMode(); this.state = { isMe: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isMeTopicName(this.props.topic), owner: acs && acs.isOwner(), fullName: topic.public ? topic.public.fn : undefined, private: topic.private ? topic.private.comment : null, description: topic.public ? topic.public.note : undefined, avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_8__.makeImageUrl)(topic.public ? topic.public.photo : null), tags: topic.tags() || [], newAvatar: null, newAvatarMime: null }; this.previousOnTags = null; this.tnNewTags = this.tnNewTags.bind(this); this.handleFullNameUpdate = this.handleFullNameUpdate.bind(this); this.handleImageUpdated = this.handleImageUpdated.bind(this); this.handleAvatarCropped = this.handleAvatarCropped.bind(this); this.handleAvatarCropCancel = this.handleAvatarCropCancel.bind(this); this.uploadAvatar = this.uploadAvatar.bind(this); this.handlePrivateUpdate = this.handlePrivateUpdate.bind(this); this.handleDescriptionUpdate = this.handleDescriptionUpdate.bind(this); this.handleTagsUpdated = this.handleTagsUpdated.bind(this); } componentDidMount() { const topic = this.props.tinode.getTopic(this.props.topic); this.previousOnTags = topic.onTagsUpdated; topic.onTagsUpdated = this.tnNewTags; } componentWillUnmount() { const topic = this.props.tinode.getTopic(this.props.topic); topic.onTagsUpdated = this.previousOnTags; } tnNewTags(tags) { this.setState({ tags: tags }); } handleFullNameUpdate(fn) { fn = fn.trim().substring(0, _config_js__WEBPACK_IMPORTED_MODULE_7__.MAX_TITLE_LENGTH); if (fn && this.state.fullName !== fn) { this.setState({ fullName: fn }); this.props.onUpdateTopicDesc(this.props.topic, (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_9__.theCard)(fn, null)); } } handlePrivateUpdate(comment) { comment = comment.trim().substring(0, _config_js__WEBPACK_IMPORTED_MODULE_7__.MAX_TITLE_LENGTH); if (this.state.private !== comment) { this.setState({ private: comment }); this.props.onUpdateTopicDesc(this.props.topic, null, comment || tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.DEL_CHAR); } } handleDescriptionUpdate(desc) { desc = desc.trim().substring(0, _config_js__WEBPACK_IMPORTED_MODULE_7__.MAX_TOPIC_DESCRIPTION_LENGTH); if (desc) { this.setState({ description: desc }); this.props.onUpdateTopicDesc(this.props.topic, (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_9__.theCard)(null, null, null, desc)); } } handleImageUpdated(mime, img) { this.setState({ newAvatar: img, newAvatarMime: mime }); if (!img) { this.setState({ avatar: null }); this.props.onUpdateTopicDesc(this.props.topic, (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_9__.theCard)(null, tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.DEL_CHAR)); } } handleAvatarCropped(mime, blob, width, height) { const url = blob ? URL.createObjectURL(blob) : null; this.setState({ avatar: url, newAvatar: null, newAvatarMime: null }); if (blob) { this.uploadAvatar(mime, blob, width, height); } } uploadAvatar(mime, blob, width, height) { const readyToUpload = image => { let { mime, blob } = image; if (blob.size > _config_js__WEBPACK_IMPORTED_MODULE_7__.MAX_AVATAR_BYTES) { const uploader = this.props.tinode.getLargeFileHelper(); uploader.upload(blob).then(url => this.props.onUpdateTopicDesc(this.props.topic, (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_9__.theCard)(null, url))).catch(err => this.props.onError(err.message, 'err')); } else { (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_8__.blobToBase64)(blob).then(b64 => { const du = (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_8__.makeImageUrl)({ data: b64.bits, type: mime }); this.setState({ source: du }); this.props.onUpdateTopicDesc(this.props.topic, (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_9__.theCard)(null, du)); }); } }; if (width > _config_js__WEBPACK_IMPORTED_MODULE_7__.AVATAR_SIZE || height > _config_js__WEBPACK_IMPORTED_MODULE_7__.AVATAR_SIZE || width != height) { (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_8__.imageScaled)(blob, _config_js__WEBPACK_IMPORTED_MODULE_7__.AVATAR_SIZE, _config_js__WEBPACK_IMPORTED_MODULE_7__.AVATAR_SIZE, _config_js__WEBPACK_IMPORTED_MODULE_7__.MAX_EXTERN_ATTACHMENT_SIZE, true).then(scaled => readyToUpload(scaled)).catch(err => this.props.onError(err.message, 'err')); } else { readyToUpload({ mime: mime, blob: blob, width: width, height: height }); } } handleAvatarCropCancel() { this.setState({ newAvatar: null, newAvatarMime: null }); } handleTagsUpdated(tags) { if ((0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_9__.arrayEqual)(this.state.tags.slice(0), tags.slice(0))) { return; } this.props.onUpdateTags(tags); } render() { if (this.state.newAvatar) { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_avatar_crop_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { avatar: this.state.newAvatar, mime: this.state.newAvatarMime, onSubmit: this.handleAvatarCropped, onCancel: this.handleAvatarCropCancel, onError: this.props.onError }); } const editable = this.state.isMe || this.state.owner; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("center", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_avatar_upload_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { tinode: this.props.tinode, avatar: this.state.avatar, readOnly: !editable, uid: this.props.topic, title: this.state.fullName, onImageUpdated: this.handleImageUpdated, onError: this.props.onError })), this.state.isMe ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_your_name", defaultMessage: [{ "type": 0, "value": "Your name" }] })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "full_name_prompt", defaultMessage: [{ "type": 0, "value": "Full name, e.g. John Doe" }] }, full_name_placeholder => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { placeholder: full_name_placeholder, value: this.state.fullName, required: true, onFinished: this.handleFullNameUpdate })))) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_topic_name", defaultMessage: [{ "type": 0, "value": "Name" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "topic_name_editing_placeholder", defaultMessage: [{ "type": 0, "value": "Freeform name of the group" }] }, group_name_placeholder => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { placeholder: group_name_placeholder, readOnly: !editable, value: this.state.fullName, required: true, onFinished: this.handleFullNameUpdate })))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_private", defaultMessage: [{ "type": 0, "value": "Private comment" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "private_editing_placeholder", defaultMessage: [{ "type": 0, "value": "Visible to you only" }] }, private_placeholder => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { placeholder: private_placeholder, value: this.state.private, onFinished: this.handlePrivateUpdate }))))), editable || this.state.description ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_description", defaultMessage: [{ "type": 0, "value": "Description" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "description_editing_placeholder", defaultMessage: [{ "type": 0, "value": "Description (optional)" }] }, private_placeholder => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_in_place_edit_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], { placeholder: private_placeholder, readOnly: !editable, value: this.state.description, multiline: 2, onFinished: this.handleDescriptionUpdate })))) : null), editable ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "title_tag_manager", defaultMessage: [{ "type": 0, "value": "Tags (search & discovery)" }] }, title_tag_manager => react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_tag_manager_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], { tinode: this.props.tinode, title: title_tag_manager, activated: false, tags: this.state.tags, onSubmit: this.handleTagsUpdated }))) : null); } } ; /***/ }), /***/ "./src/widgets/topic-security.jsx": /*!****************************************!*\ !*** ./src/widgets/topic-security.jsx ***! \****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ clear_messages: { id: "action_clear_messages", defaultMessage: [{ "type": 0, "value": "Clear Messages" }] }, clear_messages_warning: { id: "clear_messages_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to clear all messages? It cannot be undone." }] }, delete_messages: { id: "action_delete_messages", defaultMessage: [{ "type": 0, "value": "Clear Messages for All" }] }, delete_messages_warning: { id: "delete_messages_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to delete all messages for everyone? It cannot be undone." }] }, topic_delete: { id: "topic_delete", defaultMessage: [{ "type": 0, "value": "Delete Conversation" }] }, topic_delete_warning: { id: "topic_delete_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to delete this conversation? It cannot be undone." }] }, leave_chat: { id: "action_leave_chat", defaultMessage: [{ "type": 0, "value": "Leave Conversation" }] }, leave_chat_warning: { id: "leave_chat_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to leave this conversation?" }] }, block_contact: { id: "action_block_contact", defaultMessage: [{ "type": 0, "value": "Block Contact" }] }, block_contact_warning: { id: "block_contact_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to block this contact?" }] }, report_chat: { id: "action_report_chat", defaultMessage: [{ "type": 0, "value": "Report Conversation" }] }, report_chat_warning: { id: "report_chat_warning", defaultMessage: [{ "type": 0, "value": "Are you sure you want to block and report this conversation?" }] }, other_user: { id: "label_other_user", defaultMessage: [{ "type": 0, "value": "Other" }] } }); class TopicSecurity extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.handleDeleteTopic = this.handleDeleteTopic.bind(this); this.handleDeleteMessages = this.handleDeleteMessages.bind(this); this.handleLeave = this.handleLeave.bind(this); this.handleBlock = this.handleBlock.bind(this); this.handleReport = this.handleReport.bind(this); } handleDeleteTopic(e) { e.preventDefault(); const { formatMessage } = this.props.intl; this.props.onShowAlert(formatMessage(messages.topic_delete), formatMessage(messages.topic_delete_warning), _ => this.props.onDeleteTopic(this.props.topic), null, true, null); } handleDeleteMessages(e) { e.preventDefault(); const { formatMessage } = this.props.intl; this.props.onShowAlert(formatMessage(this.props.deleter ? messages.delete_messages : messages.clear_messages), formatMessage(this.props.deleter ? messages.delete_messages_warning : messages.clear_messages_warning), _ => this.props.onDeleteMessages(this.props.topic), null, true, null); } handleLeave(e) { e.preventDefault(); const { formatMessage } = this.props.intl; this.props.onShowAlert(formatMessage(messages.leave_chat), formatMessage(messages.leave_chat_warning), _ => this.props.onLeaveTopic(this.props.topic), null, true, null); } handleBlock(e) { e.preventDefault(); const { formatMessage } = this.props.intl; this.props.onShowAlert(formatMessage(messages.block_contact), formatMessage(messages.block_contact_warning), _ => this.props.onBlockTopic(this.props.topic), null, true, null); } handleReport(e) { e.preventDefault(); const { formatMessage } = this.props.intl; this.props.onShowAlert(formatMessage(messages.report_chat), formatMessage(messages.report_chat_warning), _ => { this.props.onReportTopic(this.props.topic); }, null, true, null); } render() { const { formatMessage } = this.props.intl; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "scrollable-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, !this.props.channel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "flat-button", onClick: this.handleDeleteMessages }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "delete_outline"), " \xA0", formatMessage(this.props.deleter ? messages.delete_messages : messages.clear_messages)) : null, this.props.owner ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "danger flat-button", onClick: this.handleDeleteTopic }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "delete"), " \xA0", formatMessage(messages.topic_delete)) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "danger flat-button", onClick: this.handleLeave }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "exit_to_app"), " \xA0", formatMessage(messages.leave_chat)), !this.props.groupTopic ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "danger flat-button", onClick: this.handleBlock }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "block"), " \xA0", formatMessage(messages.block_contact)) : null, !this.props.owner ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", className: "danger flat-button", onClick: this.handleReport }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "report"), " \xA0", formatMessage(messages.report_chat)) : null), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "hr" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "panel-form-column" }, this.props.groupTopic ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_your_permissions", defaultMessage: [{ "type": 0, "value": "Your permissions:" }] })), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", { className: "clickable", onClick: e => { e.preventDefault(); this.props.onLaunchPermissionsEditor('want'); } }, this.props.access)), !this.props.channel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_default_access_mode", defaultMessage: [{ "type": 0, "value": "Default access mode:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "quoted" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, "Auth: ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", { className: this.props.owner ? 'clickable' : null, onClick: e => { e.preventDefault(); if (this.props.owner) { this.props.onLaunchPermissionsEditor('auth'); } } }, this.props.auth)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, "Anon: ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", { className: this.props.owner ? 'clickable' : null, onClick: e => { e.preventDefault(); if (this.props.owner) { this.props.onLaunchPermissionsEditor('anon'); } } }, this.props.anon)))) : null) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "group" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "small" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_permissions", defaultMessage: [{ "type": 0, "value": "Permissions:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "quoted" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_you", defaultMessage: [{ "type": 0, "value": "You:" }] }), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", { className: "clickable", onClick: e => { e.preventDefault(); this.props.onLaunchPermissionsEditor('want'); } }, this.props.access)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, this.props.fullName ? this.props.fullName : formatMessage(messages.other_user), ": \xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", { className: "clickable", onClick: e => { e.preventDefault(); this.props.onLaunchPermissionsEditor('given'); } }, this.props.modeGiven2)))))); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(TopicSecurity)); /***/ }), /***/ "./src/widgets/unread-badge.jsx": /*!**************************************!*\ !*** ./src/widgets/unread-badge.jsx ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ UnreadBadge) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); class UnreadBadge extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { render() { return this.props.count > 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "unread" }, this.props.count > 9 ? "9+" : this.props.count) : null; } } ; /***/ }), /***/ "./src/widgets/uploading-image.jsx": /*!*****************************************!*\ !*** ./src/widgets/uploading-image.jsx ***! \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ UploadingImage) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _file_progress_jsx__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./file-progress.jsx */ "./src/widgets/file-progress.jsx"); class UploadingImage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "inline-image" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement('img', this.props), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "rounded-container" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_file_progress_jsx__WEBPACK_IMPORTED_MODULE_1__["default"], { progress: this.props.progress, onCancel: this.props.onCancelUpload }))); } } ; /***/ }), /***/ "./src/widgets/vc-carousel-item.jsx": /*!******************************************!*\ !*** ./src/widgets/vc-carousel-item.jsx ***! \******************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ VCCarouselItem) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var livekit_client__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! livekit-client */ "../../../go/src/github.com/livekit/client-sdk-js/dist/livekit-client.esm.mjs"); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); class VCCarouselItem extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { videoRef: undefined, audioRef: undefined }; this.handleVideoRefChange = this.handleVideoRefChange.bind(this); this.handleAudioRefChange = this.handleAudioRefChange.bind(this); } componentDidUpdate(prevProps) { if (this.state.videoRef && !this.state.videoRef.srcObject && this.props.cameraPub && this.props.cameraPub.videoTrack) { this.props.cameraPub.videoTrack.attach(this.state.videoRef); } if (this.state.audioRef && !this.state.audioRef.srcObject && this.props.micPub && this.props.micPub.audioTrack) { this.props.micPub.audioTrack.attach(this.state.audioRef); } } handleVideoRefChange(node) { if (!node) { return; } this.setState({ videoRef: node }); const cameraPub = this.props.cameraPub; const cameraEnabled = cameraPub && cameraPub.isSubscribed && !cameraPub.isMuted; if (cameraEnabled && cameraPub.videoTrack) { cameraPub.videoTrack.attach(node); } } handleAudioRefChange(node) { if (!node) { return; } this.setState({ audioRef: node }); const micPub = this.props.micPub; const micEnabled = micPub && micPub.isSubscribed && !micPub.isMuted; if (micEnabled && this.state.audioTrack) { this.state.audioTrack.attach(node); } } render() { let classes = 'call-party carousel-item'; if (this.props.isSpeaking) { classes += ' call-party-speaking'; } const micPub = this.props.micPub; const cameraPub = this.props.cameraPub; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: classes }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("video", { ref: this.handleVideoRefChange }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("audio", { ref: this.handleAudioRefChange }), micPub && micPub.isMuted ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons muted" }, "mic_off") : null, cameraPub && cameraPub.isMuted ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "avatar-box carousel-item" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { tinode: this.props.tinode, avatar: this.props.photo, topic: this.props.identity, title: this.props.name }))) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "caller-name inactive" }, this.props.name))); } } /***/ }), /***/ "./src/widgets/vc-carousel.jsx": /*!*************************************!*\ !*** ./src/widgets/vc-carousel.jsx ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ VCCarousel) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var livekit_client__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! livekit-client */ "../../../go/src/github.com/livekit/client-sdk-js/dist/livekit-client.esm.mjs"); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _vc_carousel_item_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./vc-carousel-item.jsx */ "./src/widgets/vc-carousel-item.jsx"); /* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../constants.js */ "./src/constants.js"); class VCCarousel extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) { constructor(props) { super(props); this.handlePrevClick = this.handlePrevClick.bind(this); this.handleNextClick = this.handleNextClick.bind(this); this.carouselRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.contentRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.prevRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.nextRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); } handlePrevClick() { const gap = _constants_js__WEBPACK_IMPORTED_MODULE_4__.VC_CAROUSEL_ITEM_GAP; const width = this.carouselRef.current.offsetWidth; this.carouselRef.current.scrollBy(-(width + gap), 0); if (this.carouselRef.current.scrollLeft - width - gap <= 0) { this.prevRef.current.style.display = 'none'; } if (!this.contentRef.current.scrollWidth - width - gap <= this.carouselRef.current.scrollLeft + width) { this.nextRef.current.style.display = 'flex'; } } handleNextClick() { const gap = _constants_js__WEBPACK_IMPORTED_MODULE_4__.VC_CAROUSEL_ITEM_GAP; const width = this.carouselRef.current.offsetWidth; this.carouselRef.current.scrollBy(width + gap, 0); if (this.carouselRef.current.scrollWidth !== 0) { this.prevRef.current.style.display = 'flex'; } if (this.contentRef.current.scrollWidth - width - gap <= this.carouselRef.current.scrollLeft + width) { this.nextRef.current.style.display = 'none'; } } render() { let peers = []; if (this.props.participants) { Object.entries(this.props.participants).forEach((_ref, i) => { let [identity, party] = _ref; const participant = party.participant; const cameraPub = participant.getTrack(livekit_client__WEBPACK_IMPORTED_MODULE_1__.Track.Source.Camera); const micPub = participant.getTrack(livekit_client__WEBPACK_IMPORTED_MODULE_1__.Track.Source.Microphone); peers.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_vc_carousel_item_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, isSpeaking: participant.isSpeaking, cameraPub: cameraPub ? cameraPub : null, micPub: micPub ? micPub : null, name: party.name, identity: identity, photo: party.photo, key: i })); }); } return react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "carousel-wrapper" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "carousel", ref: this.carouselRef }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "carousel-content", ref: this.contentRef }, peers)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { id: "carousel-prev", ref: this.prevRef, onClick: this.handlePrevClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("path", { fill: "none", d: "M0 0h24v24H0V0z" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("path", { d: "M15.61 7.41L14.2 6l-6 6 6 6 1.41-1.41L11.03 12l4.58-4.59z" }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { id: "carousel-next", ref: this.nextRef, onClick: this.handleNextClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("path", { fill: "none", d: "M0 0h24v24H0V0z" }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("path", { d: "M10.02 6L8.61 7.41 13.19 12l-4.58 4.59L10.02 18l6-6-6-6z" }))))); } } /***/ }), /***/ "./src/widgets/vc-panel.jsx": /*!**********************************!*\ !*** ./src/widgets/vc-panel.jsx ***! \**********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var livekit_client__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! livekit-client */ "../../../go/src/github.com/livekit/client-sdk-js/dist/livekit-client.esm.mjs"); /* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx"); /* harmony import */ var _vc_carousel_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./vc-carousel.jsx */ "./src/widgets/vc-carousel.jsx"); /* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js"); /* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../config.js */ "./src/config.js"); /* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../constants.js */ "./src/constants.js"); /* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js"); class VCPanel extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.state = { room: undefined, participants: {}, activeSpeaker: undefined, previousOnInfo: undefined }; this.isOutgoingCall = props.callState == _constants_js__WEBPACK_IMPORTED_MODULE_7__.CALL_STATE_OUTGOING_INITATED; const topic = this.props.tinode.getTopic(this.props.topic); this.isBroadcast = topic && topic.chan; this.localRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.remoteRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.onInfo = this.onInfo.bind(this); this.start = this.start.bind(this); this.stop = this.stop.bind(this); this.reportError = this.reportError.bind(this); this.handleCloseClick = this.handleCloseClick.bind(this); this.handleToggleCameraClick = this.handleToggleCameraClick.bind(this); this.handleToggleMicClick = this.handleToggleMicClick.bind(this); this.handleRemoteHangup = this.handleRemoteHangup.bind(this); this.handleTrackSubscribed = this.handleTrackSubscribed.bind(this); this.handleTrackUnsubscribed = this.handleTrackUnsubscribed.bind(this); this.handleActiveSpeakerChange = this.handleActiveSpeakerChange.bind(this); this.handleDisconnect = this.handleDisconnect.bind(this); this.handleLocalTrackUnpublished = this.handleLocalTrackUnpublished.bind(this); this.handleLocalTrackPublished = this.handleLocalTrackPublished.bind(this); this.handleParticipantConnected = this.handleParticipantConnected.bind(this); this.handleParticipantDisconnected = this.handleParticipantDisconnected.bind(this); this.handleData = this.handleData.bind(this); this.handleDevicesChanged = this.handleDevicesChanged.bind(this); this.startRoom = this.startRoom.bind(this); this.participants = {}; } componentDidMount() { const topic = this.props.tinode.getTopic(this.props.topic); this.previousOnInfo = topic.onInfo; topic.onInfo = this.onInfo; this.start(); } componentWillUnmount() { const topic = this.props.tinode.getTopic(this.props.topic); topic.onInfo = this.previousOnInfo; this.stop(); } onInfo(info) { if (info.what != 'call') { return; } switch (info.event) { case 'vc-token': const ts = info.payload; this.setState({ token: ts.token }); this.startRoom(ts.token); break; case 'hang-up': this.handleRemoteHangup(info); break; default: console.warn("Unknown call event", info.event); break; } } handleParticipantConnected(participant) { if (!participant) return; if (participant instanceof livekit_client__WEBPACK_IMPORTED_MODULE_2__.RemoteParticipant) { participant.on(livekit_client__WEBPACK_IMPORTED_MODULE_2__.ParticipantEvent.TrackMuted, pub => { console.log('track was muted', pub.trackSid, participant.identity); this.forceUpdate(); }).on(livekit_client__WEBPACK_IMPORTED_MODULE_2__.ParticipantEvent.TrackUnmuted, pub => { console.log('track was unmuted', pub.trackSid, participant.identity); this.forceUpdate(); }).on(livekit_client__WEBPACK_IMPORTED_MODULE_2__.ParticipantEvent.IsSpeakingChanged, _ => { this.forceUpdate(); }).on(livekit_client__WEBPACK_IMPORTED_MODULE_2__.ParticipantEvent.ConnectionQualityChanged, _ => { this.forceUpdate(); }); const me = this.props.tinode.getMeTopic(); const c = me.getContact(participant.identity); const name = c && c.public && c.public.fn ? c.public.fn : participant.identity; const photo = (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_5__.makeImageUrl)(c && c.public ? c.public.photo : null); const p = { name: name, photo: photo, participant: participant }; this.participants[participant.identity] = p; console.log('participant connected', this.participants); this.setState({ participants: this.participants }, _ => { this.forceUpdate(); }); } } handleParticipantDisconnected(participant) { console.log('Deleting participant ', participant.identity); delete this.participants[participant.identity]; this.setState({ participants: this.participants }); } handleData(msg, participant) { console.log('Data message ', msg, participant); } handleTrackSubscribed(track, publication, participant) { if (participant instanceof livekit_client__WEBPACK_IMPORTED_MODULE_2__.RemoteParticipant) { if (this.remoteRef.current && !(this.remoteRef.current.src != '' || this.remoteRef.srcObject)) { track.attach(this.remoteRef.current); } } this.forceUpdate(); } handleTrackUnsubscribed(track, publication, participant) { console.log('handleTrackUnsubscribed', track); track.detach(); this.forceUpdate(); } handleLocalTrackPublished(pub) { console.log('Local track published', pub); const track = pub.track; if (track instanceof livekit_client__WEBPACK_IMPORTED_MODULE_2__.LocalVideoTrack && this.localRef.current) { const elem = this.localRef.current; track.attach(elem); elem.style.transform = 'scale(-1, 1)'; } } handleLocalTrackUnpublished(pub) { const track = pub.track; console.log('handleLocalTrackUnpublished', track); track.detach(); this.forceUpdate(); } handleActiveSpeakerChange(speakers) { console.log('handleActiveSpeakerChange', speakers); speakers.forEach(s => { if (s.isSpeaking) { console.log('Speaking participant ', s); const elem = this.remoteRef.current; const me = this.props.tinode.getMeTopic(); const c = me.getContact(s.identity); const name = c && c.public && c.public.fn ? c.public.fn : undefined; this.setState({ activeSpeaker: name }); const cameraPub = s.getTrack(livekit_client__WEBPACK_IMPORTED_MODULE_2__.Track.Source.Camera); const cameraEnabled = cameraPub && cameraPub.isSubscribed && !cameraPub.isMuted; if (cameraEnabled && cameraPub.videoTrack) { cameraPub.videoTrack.attach(elem); } } }); } handleDevicesChanged() { console.log('devices changed'); } handleDisconnect() { console.log('disconnected from room'); this.handleCloseClick(); } startRoom(token) { const roomOpts = { adaptiveStream: true, dynacast: true, publishDefaults: { simulcast: true, videoSimulcastLayers: [livekit_client__WEBPACK_IMPORTED_MODULE_2__.VideoPresets.h90, livekit_client__WEBPACK_IMPORTED_MODULE_2__.VideoPresets.h216], videoCodec: 'vp8' }, videoCaptureDefaults: { resolution: livekit_client__WEBPACK_IMPORTED_MODULE_2__.VideoPresets.h720.resolution } }; const connectOpts = { autoSubscribe: true }; const room = new livekit_client__WEBPACK_IMPORTED_MODULE_2__.Room(roomOpts); this.setState({ room: room }); const startTime = Date.now(); const topic = this.props.tinode.getTopic(this.props.topic); const shouldPublish = this.isOutgoingCall || !this.isBroadcast; room.on(livekit_client__WEBPACK_IMPORTED_MODULE_2__.RoomEvent.ParticipantConnected, this.handleParticipantConnected).on(livekit_client__WEBPACK_IMPORTED_MODULE_2__.RoomEvent.ParticipantDisconnected, this.handleParticipantDisconnected).on(livekit_client__WEBPACK_IMPORTED_MODULE_2__.RoomEvent.DataReceived, this.handleData).on(livekit_client__WEBPACK_IMPORTED_MODULE_2__.RoomEvent.TrackSubscribed, this.handleTrackSubscribed).on(livekit_client__WEBPACK_IMPORTED_MODULE_2__.RoomEvent.TrackUnsubscribed, this.handleTrackUnsubscribed).on(livekit_client__WEBPACK_IMPORTED_MODULE_2__.RoomEvent.ActiveSpeakersChanged, this.handleActiveSpeakerChange).on(livekit_client__WEBPACK_IMPORTED_MODULE_2__.RoomEvent.Disconnected, this.handleDisconnect).on(livekit_client__WEBPACK_IMPORTED_MODULE_2__.RoomEvent.LocalTrackUnpublished, this.handleLocalTrackUnpublished).on(livekit_client__WEBPACK_IMPORTED_MODULE_2__.RoomEvent.LocalTrackPublished, this.handleLocalTrackPublished).on(livekit_client__WEBPACK_IMPORTED_MODULE_2__.RoomEvent.RoomMetadataChanged, metadata => { console.log('VC room new metadata ', metadata); }).on(livekit_client__WEBPACK_IMPORTED_MODULE_2__.RoomEvent.MediaDevicesChanged, this.handleDevicesChanged).on(livekit_client__WEBPACK_IMPORTED_MODULE_2__.RoomEvent.AudioPlaybackStatusChanged, e => { console.log('Audio playback status change: ', e); }).on(livekit_client__WEBPACK_IMPORTED_MODULE_2__.RoomEvent.MediaDevicesError, e => { const failure = livekit_client__WEBPACK_IMPORTED_MODULE_2__.MediaDeviceFailure.getFailure(e); this.reportError(failure); }).on(livekit_client__WEBPACK_IMPORTED_MODULE_2__.RoomEvent.ConnectionQualityChanged, (quality, participant) => { const id = participant ? participant.identity : 'nil'; console.log('Connection quality changed', id, ' -> ', quality); }).on(livekit_client__WEBPACK_IMPORTED_MODULE_2__.RoomEvent.SignalConnected, _ => { const signalConnectionTime = Date.now() - startTime; console.log(`signal connection established in ${signalConnectionTime}ms`); if (shouldPublish) { room.localParticipant.enableCameraAndMicrophone(); console.log(`tracks published in ${Date.now() - startTime}ms`); } }); const vcEndpoint = this.props.tinode.getServerParam('vcEndpoint', null); room.connect(vcEndpoint, token, connectOpts).then(_ => { console.log('Connected to VC room', room.name, '. Access token', token); room.participants.forEach(participant => { this.handleParticipantConnected(participant); }); this.handleParticipantConnected(room.localParticipant); }); } start() { if (this.state.localStream) { this.props.onError(this.props.intl.formatMessage(messages.already_in_call), 'info'); return; } if (this.isOutgoingCall) { this.props.onCreateCall(this.props.topic, this.props.seq, this.props.callState, this.props.callAudioOnly).then(ctrl => { const token = ctrl.params.token; const seq = ctrl.params.seq; this.setState({ callSeq: seq, token: token }); this.startRoom(token); }); } else { this.props.onJoin(this.props.topic, this.props.seq); } } stop() { if (this.state.room) { this.state.room.disconnect(); } } reportError(err) { this.props.onError(err.message, 'err'); } handleRemoteHangup() { this.handleCloseClick(); } handleCloseClick() { this.stop(); this.props.onHangup(this.props.topic, this.props.seq); } handleToggleCameraClick() { if (!this.state.room) return; const enabled = this.state.room.localParticipant.isCameraEnabled; this.state.room.localParticipant.setCameraEnabled(!enabled).then(_ => this.forceUpdate()); this.forceUpdate(); } handleToggleMicClick() { if (!this.state.room) return; const enabled = this.state.room.localParticipant.isMicrophoneEnabled; this.state.room.localParticipant.setMicrophoneEnabled(!enabled).then(_ => this.forceUpdate()); this.forceUpdate(); } render() { const isPublishing = this.isOutgoingCall || !this.isBroadcast; const disabled = !isPublishing || !this.state.room || !this.state.room.localParticipant; const audioIcon = !disabled && this.state.room.localParticipant.isMicrophoneEnabled ? 'mic' : 'mic_off'; const videoIcon = !disabled && this.state.room.localParticipant.isCameraEnabled ? 'videocam' : 'videocam_off'; const peerTitle = this.state.activeSpeaker ? this.state.activeSpeaker : (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_8__.clipStr)(this.props.title, _config_js__WEBPACK_IMPORTED_MODULE_6__.MAX_PEER_TITLE_LENGTH); const remoteActive = this.remoteRef.current && (this.remoteRef.current.src || this.remoteRef.current.srcObject); return react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "video-container" }, !this.isBroadcast && Object.keys(this.state.participants).length > 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_vc_carousel_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], { tinode: this.props.tinode, participants: this.state.participants }) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "video-container-panel" }, isPublishing ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "call-party self", disabled: this.state.audioOnly }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("video", { ref: this.localRef, autoPlay: true, muted: true, playsInline: true }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "caller-name inactive" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "calls_you_label", defaultMessage: [{ "type": 0, "value": "You" }] }))) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "call-party peer", disabled: !remoteActive }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("video", { ref: this.remoteRef, autoPlay: true, playsInline: true }), remoteActive ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "caller-name inactive" }, peerTitle)) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "caller-card" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "avatar-box" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], { tinode: this.props.tinode, avatar: this.props.avatar, topic: this.props.topic, title: this.props.title })), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "caller-name" }, peerTitle))))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "controls" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "danger", onClick: this.handleCloseClick }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, "call_end")), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "secondary", onClick: this.handleToggleCameraClick, disabled: disabled }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, videoIcon)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "secondary", onClick: this.handleToggleMicClick, disabled: disabled }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons" }, audioIcon))))); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(VCPanel)); /***/ }), /***/ "./src/widgets/video-preview.jsx": /*!***************************************!*\ !*** ./src/widgets/video-preview.jsx ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _send_message_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./send-message.jsx */ "./src/widgets/send-message.jsx"); /* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js"); const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({ unrecognized_video_format: { id: "unrecognized_video_format", defaultMessage: [{ "type": 0, "value": "Format of this video is not recognized" }] } }); class VideoPreview extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.videoRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.handleSendVideo = this.handleSendVideo.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); } componentDidMount() { document.addEventListener('keydown', this.handleKeyDown); } componentWillUnmount() { document.removeEventListener('keydown', this.handleKeyDown); } handleKeyDown(e) { if (this.props.onSendMessage) { return; } e.preventDefault(); if (e.key === 'Escape') { this.props.onClose(); } } handleSendVideo(caption) { this.props.onClose(); const params = { width: this.videoRef.current.videoWidth, height: this.videoRef.current.videoHeight, duration: this.videoRef.current.duration * 1000 | 0, mime: this.props.content.mime, name: this.props.content.filename }; if (params.width == 0 || params.height == 0) { this.props.onError(this.props.intl.formatMessage(messages.unrecognized_video_format), 'err'); return; } const canvas = document.createElement('canvas'); canvas.width = params.width; canvas.height = params.height; const ctx = canvas.getContext('2d'); ctx.drawImage(this.videoRef.current, 0, 0, canvas.width, canvas.height); ctx.canvas.toBlob(preview => this.props.onSendMessage(caption, this.props.content.blob, preview, params), 'image/jpeg', 0.75); } render() { if (!this.props.content) { return null; } const width = this.props.content.width || '-'; const height = this.props.content.height || '-'; const controlist = this.props.onSendMessage ? 'nodownload' : ''; const autoPlay = !this.props.onSendMessage; return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "image-preview" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "image-preview-caption-panel" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, this.props.content.filename), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", { href: "#", onClick: e => { e.preventDefault(); this.props.onClose(); } }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons gray" }, "close"))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "image-preview-container" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("video", { className: "image-preview", controls: true, controlsList: controlist, disablePictureInPicture: true, ref: this.videoRef, autoPlay: autoPlay, src: this.props.tinode.authorizeURL(this.props.content.url), poster: this.props.content.preview, alt: this.props.content.filename })), this.props.onSendMessage ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_send_message_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], { messagePrompt: "add_image_caption", acceptBlank: true, tinode: this.props.tinode, reply: this.props.reply, onCancelReply: this.props.onCancelReply, onSendMessage: this.handleSendVideo, onError: this.props.onError }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { id: "image-preview-footer" }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("b", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_file_name", defaultMessage: [{ "type": 0, "value": "File name:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { title: this.props.content.filename }, this.props.content.filename))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("b", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_content_type", defaultMessage: [{ "type": 0, "value": "Content type:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, this.props.content.type)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("b", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, { id: "label_size", defaultMessage: [{ "type": 0, "value": "Size:" }] }))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, width, " \xD7 ", height, " px; ", (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_3__.bytesToHumanSize)(this.props.content.size))))); } } ; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(VideoPreview)); /***/ }), /***/ "./src/widgets/visible-password.jsx": /*!******************************************!*\ !*** ./src/widgets/visible-password.jsx ***! \******************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (/* binding */ VisiblePassword) /* harmony export */ }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); class VisiblePassword extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) { constructor(props) { super(props); this.inputRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef(); this.state = { value: this.props.value || '', visible: false }; this.handleVisibility = this.handleVisibility.bind(this); this.handeTextChange = this.handeTextChange.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); this.handleEditingFinished = this.handleEditingFinished.bind(this); } componentDidMount() { if (this.props.autoFocus) { this.inputRef.current.focus(); } } handeTextChange(e) { this.setState({ value: e.target.value }); if (this.props.onChange) { this.props.onChange(e); } } handleVisibility(e) { e.preventDefault(); this.setState({ visible: !this.state.visible }); } handleKeyDown(e) { if (e.keyCode == 27) { this.setState({ value: this.props.value || '', visible: false }); if (this.props.onFinished) { this.props.onFinished(); } } else if (e.keyCode == 13) { this.handleEditingFinished(); } } handleEditingFinished(e) { if (e) { let currentTarget = e.currentTarget; setTimeout(_ => { if (!currentTarget.contains(document.activeElement)) { if (this.props.onFinished) { this.props.onFinished(this.state.value); } } }, 0); } else if (this.props.onFinished) { this.props.onFinished(this.state.value.trim()); } } render() { return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { tabIndex: "-1", className: "group-focus", onBlur: this.handleEditingFinished }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { className: "with-visibility", type: this.state.visible ? 'text' : 'password', value: this.state.value, placeholder: this.props.placeholder, required: this.props.required ? 'required' : '', autoFocus: this.props.autoFocus ? 'autoFocus' : '', autoComplete: this.props.autoComplete, onChange: this.handeTextChange, onKeyDown: this.handleKeyDown, ref: this.inputRef }), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { onClick: this.handleVisibility }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", { className: "material-icons clickable light-gray" }, this.state.visible ? 'visibility' : 'visibility_off'))); } } /***/ }), /***/ "./node_modules/react-dom/client.js": /*!******************************************!*\ !*** ./node_modules/react-dom/client.js ***! \******************************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { var m = __webpack_require__(/*! react-dom */ "react-dom"); if (false) {} else { var i = m.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; exports.createRoot = function(c, o) { i.usingClientEntryPoint = true; try { return m.createRoot(c, o); } finally { i.usingClientEntryPoint = false; } }; exports.hydrateRoot = function(c, h, o) { i.usingClientEntryPoint = true; try { return m.hydrateRoot(c, h, o); } finally { i.usingClientEntryPoint = false; } }; } /***/ }), /***/ "react": /*!************************!*\ !*** external "React" ***! \************************/ /***/ ((module) => { module.exports = React; /***/ }), /***/ "react-dom": /*!***************************!*\ !*** external "ReactDOM" ***! \***************************/ /***/ ((module) => { module.exports = ReactDOM; /***/ }), /***/ "react-intl": /*!****************************!*\ !*** external "ReactIntl" ***! \****************************/ /***/ ((module) => { module.exports = ReactIntl; /***/ }), /***/ "tinode-sdk": /*!*************************!*\ !*** external "tinode" ***! \*************************/ /***/ ((module) => { module.exports = tinode; /***/ }), /***/ "../../../go/src/github.com/livekit/client-sdk-js/dist/livekit-client.esm.mjs": /*!************************************************************************************!*\ !*** ../../../go/src/github.com/livekit/client-sdk-js/dist/livekit-client.esm.mjs ***! \************************************************************************************/ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "AudioPresets": () => (/* binding */ AudioPresets), /* harmony export */ "ConnectionCheck": () => (/* binding */ ConnectionCheck), /* harmony export */ "ConnectionError": () => (/* binding */ ConnectionError), /* harmony export */ "ConnectionQuality": () => (/* binding */ ConnectionQuality), /* harmony export */ "ConnectionState": () => (/* binding */ ConnectionState), /* harmony export */ "CriticalTimers": () => (/* binding */ CriticalTimers), /* harmony export */ "DataPacket_Kind": () => (/* binding */ DataPacket_Kind), /* harmony export */ "DefaultReconnectPolicy": () => (/* binding */ DefaultReconnectPolicy), /* harmony export */ "DeviceUnsupportedError": () => (/* binding */ DeviceUnsupportedError), /* harmony export */ "DisconnectReason": () => (/* binding */ DisconnectReason), /* harmony export */ "EngineEvent": () => (/* binding */ EngineEvent), /* harmony export */ "LivekitError": () => (/* binding */ LivekitError), /* harmony export */ "LocalAudioTrack": () => (/* binding */ LocalAudioTrack), /* harmony export */ "LocalParticipant": () => (/* binding */ LocalParticipant), /* harmony export */ "LocalTrack": () => (/* binding */ LocalTrack), /* harmony export */ "LocalTrackPublication": () => (/* binding */ LocalTrackPublication), /* harmony export */ "LocalVideoTrack": () => (/* binding */ LocalVideoTrack), /* harmony export */ "LogLevel": () => (/* binding */ LogLevel), /* harmony export */ "MediaDeviceFailure": () => (/* binding */ MediaDeviceFailure), /* harmony export */ "NegotiationError": () => (/* binding */ NegotiationError), /* harmony export */ "Participant": () => (/* binding */ Participant), /* harmony export */ "ParticipantEvent": () => (/* binding */ ParticipantEvent), /* harmony export */ "PublishDataError": () => (/* binding */ PublishDataError), /* harmony export */ "RemoteAudioTrack": () => (/* binding */ RemoteAudioTrack), /* harmony export */ "RemoteParticipant": () => (/* binding */ RemoteParticipant), /* harmony export */ "RemoteTrack": () => (/* binding */ RemoteTrack), /* harmony export */ "RemoteTrackPublication": () => (/* binding */ RemoteTrackPublication), /* harmony export */ "RemoteVideoTrack": () => (/* binding */ RemoteVideoTrack), /* harmony export */ "Room": () => (/* binding */ Room), /* harmony export */ "RoomEvent": () => (/* binding */ RoomEvent), /* harmony export */ "RoomState": () => (/* binding */ RoomState), /* harmony export */ "ScreenSharePresets": () => (/* binding */ ScreenSharePresets), /* harmony export */ "Track": () => (/* binding */ Track), /* harmony export */ "TrackEvent": () => (/* binding */ TrackEvent), /* harmony export */ "TrackInvalidError": () => (/* binding */ TrackInvalidError), /* harmony export */ "TrackPublication": () => (/* binding */ TrackPublication), /* harmony export */ "UnexpectedConnectionState": () => (/* binding */ UnexpectedConnectionState), /* harmony export */ "UnsupportedServer": () => (/* binding */ UnsupportedServer), /* harmony export */ "VideoPreset": () => (/* binding */ VideoPreset), /* harmony export */ "VideoPresets": () => (/* binding */ VideoPresets), /* harmony export */ "VideoPresets43": () => (/* binding */ VideoPresets43), /* harmony export */ "VideoQuality": () => (/* binding */ VideoQuality), /* harmony export */ "attachToElement": () => (/* binding */ attachToElement), /* harmony export */ "createAudioAnalyser": () => (/* binding */ createAudioAnalyser), /* harmony export */ "createLocalAudioTrack": () => (/* binding */ createLocalAudioTrack), /* harmony export */ "createLocalScreenTracks": () => (/* binding */ createLocalScreenTracks), /* harmony export */ "createLocalTracks": () => (/* binding */ createLocalTracks), /* harmony export */ "createLocalVideoTrack": () => (/* binding */ createLocalVideoTrack), /* harmony export */ "detachTrack": () => (/* binding */ detachTrack), /* harmony export */ "getEmptyAudioStreamTrack": () => (/* binding */ getEmptyAudioStreamTrack), /* harmony export */ "getEmptyVideoStreamTrack": () => (/* binding */ getEmptyVideoStreamTrack), /* harmony export */ "isBackupCodec": () => (/* binding */ isBackupCodec), /* harmony export */ "isBrowserSupported": () => (/* binding */ isBrowserSupported), /* harmony export */ "protocolVersion": () => (/* binding */ protocolVersion), /* harmony export */ "setLogExtension": () => (/* binding */ setLogExtension), /* harmony export */ "setLogLevel": () => (/* binding */ setLogLevel), /* harmony export */ "supportsAV1": () => (/* binding */ supportsAV1), /* harmony export */ "supportsAdaptiveStream": () => (/* binding */ supportsAdaptiveStream), /* harmony export */ "supportsDynacast": () => (/* binding */ supportsDynacast), /* harmony export */ "version": () => (/* binding */ version) /* harmony export */ }); function _mergeNamespaces(n, m) { m.forEach(function (e) { e && typeof e !== 'string' && !Array.isArray(e) && Object.keys(e).forEach(function (k) { if (k !== 'default' && !(k in n)) { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); }); return Object.freeze(n); } var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; function getDefaultExportFromCjs (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } var loglevelExports = {}; var loglevel = { get exports(){ return loglevelExports; }, set exports(v){ loglevelExports = v; }, }; /* * loglevel - https://github.com/pimterry/loglevel * * Copyright (c) 2013 Tim Perry * Licensed under the MIT license. */ (function (module) { (function (root, definition) { if (module.exports) { module.exports = definition(); } else { root.log = definition(); } })(commonjsGlobal, function () { // Slightly dubious tricks to cut down minimized file size var noop = function () {}; var undefinedType = "undefined"; var isIE = typeof window !== undefinedType && typeof window.navigator !== undefinedType && /Trident\/|MSIE /.test(window.navigator.userAgent); var logMethods = ["trace", "debug", "info", "warn", "error"]; // Cross-browser bind equivalent that works at least back to IE6 function bindMethod(obj, methodName) { var method = obj[methodName]; if (typeof method.bind === 'function') { return method.bind(obj); } else { try { return Function.prototype.bind.call(method, obj); } catch (e) { // Missing bind shim or IE8 + Modernizr, fallback to wrapping return function () { return Function.prototype.apply.apply(method, [obj, arguments]); }; } } } // Trace() doesn't print the message in IE, so for that case we need to wrap it function traceForIE() { if (console.log) { if (console.log.apply) { console.log.apply(console, arguments); } else { // In old IE, native console methods themselves don't have apply(). Function.prototype.apply.apply(console.log, [console, arguments]); } } if (console.trace) console.trace(); } // Build the best logging method possible for this env // Wherever possible we want to bind, not wrap, to preserve stack traces function realMethod(methodName) { if (methodName === 'debug') { methodName = 'log'; } if (typeof console === undefinedType) { return false; // No method possible, for now - fixed later by enableLoggingWhenConsoleArrives } else if (methodName === 'trace' && isIE) { return traceForIE; } else if (console[methodName] !== undefined) { return bindMethod(console, methodName); } else if (console.log !== undefined) { return bindMethod(console, 'log'); } else { return noop; } } // These private functions always need `this` to be set properly function replaceLoggingMethods(level, loggerName) { /*jshint validthis:true */ for (var i = 0; i < logMethods.length; i++) { var methodName = logMethods[i]; this[methodName] = i < level ? noop : this.methodFactory(methodName, level, loggerName); } // Define log.log as an alias for log.debug this.log = this.debug; } // In old IE versions, the console isn't present until you first open it. // We build realMethod() replacements here that regenerate logging methods function enableLoggingWhenConsoleArrives(methodName, level, loggerName) { return function () { if (typeof console !== undefinedType) { replaceLoggingMethods.call(this, level, loggerName); this[methodName].apply(this, arguments); } }; } // By default, we use closely bound real methods wherever possible, and // otherwise we wait for a console to appear, and then try again. function defaultMethodFactory(methodName, level, loggerName) { /*jshint validthis:true */ return realMethod(methodName) || enableLoggingWhenConsoleArrives.apply(this, arguments); } function Logger(name, defaultLevel, factory) { var self = this; var currentLevel; defaultLevel = defaultLevel == null ? "WARN" : defaultLevel; var storageKey = "loglevel"; if (typeof name === "string") { storageKey += ":" + name; } else if (typeof name === "symbol") { storageKey = undefined; } function persistLevelIfPossible(levelNum) { var levelName = (logMethods[levelNum] || 'silent').toUpperCase(); if (typeof window === undefinedType || !storageKey) return; // Use localStorage if available try { window.localStorage[storageKey] = levelName; return; } catch (ignore) {} // Use session cookie as fallback try { window.document.cookie = encodeURIComponent(storageKey) + "=" + levelName + ";"; } catch (ignore) {} } function getPersistedLevel() { var storedLevel; if (typeof window === undefinedType || !storageKey) return; try { storedLevel = window.localStorage[storageKey]; } catch (ignore) {} // Fallback to cookies if local storage gives us nothing if (typeof storedLevel === undefinedType) { try { var cookie = window.document.cookie; var location = cookie.indexOf(encodeURIComponent(storageKey) + "="); if (location !== -1) { storedLevel = /^([^;]+)/.exec(cookie.slice(location))[1]; } } catch (ignore) {} } // If the stored level is not valid, treat it as if nothing was stored. if (self.levels[storedLevel] === undefined) { storedLevel = undefined; } return storedLevel; } function clearPersistedLevel() { if (typeof window === undefinedType || !storageKey) return; // Use localStorage if available try { window.localStorage.removeItem(storageKey); return; } catch (ignore) {} // Use session cookie as fallback try { window.document.cookie = encodeURIComponent(storageKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC"; } catch (ignore) {} } /* * * Public logger API - see https://github.com/pimterry/loglevel for details * */ self.name = name; self.levels = { "TRACE": 0, "DEBUG": 1, "INFO": 2, "WARN": 3, "ERROR": 4, "SILENT": 5 }; self.methodFactory = factory || defaultMethodFactory; self.getLevel = function () { return currentLevel; }; self.setLevel = function (level, persist) { if (typeof level === "string" && self.levels[level.toUpperCase()] !== undefined) { level = self.levels[level.toUpperCase()]; } if (typeof level === "number" && level >= 0 && level <= self.levels.SILENT) { currentLevel = level; if (persist !== false) { // defaults to true persistLevelIfPossible(level); } replaceLoggingMethods.call(self, level, name); if (typeof console === undefinedType && level < self.levels.SILENT) { return "No console available for logging"; } } else { throw "log.setLevel() called with invalid level: " + level; } }; self.setDefaultLevel = function (level) { defaultLevel = level; if (!getPersistedLevel()) { self.setLevel(level, false); } }; self.resetLevel = function () { self.setLevel(defaultLevel, false); clearPersistedLevel(); }; self.enableAll = function (persist) { self.setLevel(self.levels.TRACE, persist); }; self.disableAll = function (persist) { self.setLevel(self.levels.SILENT, persist); }; // Initialize with the right level var initialLevel = getPersistedLevel(); if (initialLevel == null) { initialLevel = defaultLevel; } self.setLevel(initialLevel, false); } /* * * Top-level API * */ var defaultLogger = new Logger(); var _loggersByName = {}; defaultLogger.getLogger = function getLogger(name) { if (typeof name !== "symbol" && typeof name !== "string" || name === "") { throw new TypeError("You must supply a name when creating a logger."); } var logger = _loggersByName[name]; if (!logger) { logger = _loggersByName[name] = new Logger(name, defaultLogger.getLevel(), defaultLogger.methodFactory); } return logger; }; // Grab the current global log variable in case of overwrite var _log = typeof window !== undefinedType ? window.log : undefined; defaultLogger.noConflict = function () { if (typeof window !== undefinedType && window.log === defaultLogger) { window.log = _log; } return defaultLogger; }; defaultLogger.getLoggers = function getLoggers() { return _loggersByName; }; // ES6 default export, for compatibility defaultLogger['default'] = defaultLogger; return defaultLogger; }); })(loglevel); var LogLevel; (function (LogLevel) { LogLevel[LogLevel["trace"] = 0] = "trace"; LogLevel[LogLevel["debug"] = 1] = "debug"; LogLevel[LogLevel["info"] = 2] = "info"; LogLevel[LogLevel["warn"] = 3] = "warn"; LogLevel[LogLevel["error"] = 4] = "error"; LogLevel[LogLevel["silent"] = 5] = "silent"; })(LogLevel || (LogLevel = {})); const livekitLogger = loglevelExports.getLogger('livekit'); livekitLogger.setLevel(LogLevel.info); function setLogLevel(level) { livekitLogger.setLevel(level); } /** * use this to hook into the logging function to allow sending internal livekit logs to third party services * if set, the browser logs will lose their stacktrace information (see https://github.com/pimterry/loglevel#writing-plugins) */ function setLogExtension(extension) { const originalFactory = livekitLogger.methodFactory; livekitLogger.methodFactory = (methodName, logLevel, loggerName) => { const rawMethod = originalFactory(methodName, logLevel, loggerName); const configLevel = livekitLogger.getLevel(); const needLog = logLevel >= configLevel && logLevel < LogLevel.silent; return (msg, context) => { if (context) rawMethod(msg, context);else rawMethod(msg); if (needLog) { extension(logLevel, msg, context); } }; }; livekitLogger.setLevel(livekitLogger.getLevel()); // Be sure to call setLevel method in order to apply plugin } /** * @license * Copyright 2009 The Closure Library Authors * Copyright 2020 Daniel Wirtz / The long.js Authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * SPDX-License-Identifier: Apache-2.0 */ // WebAssembly optimizations to do native i64 multiplication and divide var wasm = null; try { wasm = new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 13, 2, 96, 0, 1, 127, 96, 4, 127, 127, 127, 127, 1, 127, 3, 7, 6, 0, 1, 1, 1, 1, 1, 6, 6, 1, 127, 1, 65, 0, 11, 7, 50, 6, 3, 109, 117, 108, 0, 1, 5, 100, 105, 118, 95, 115, 0, 2, 5, 100, 105, 118, 95, 117, 0, 3, 5, 114, 101, 109, 95, 115, 0, 4, 5, 114, 101, 109, 95, 117, 0, 5, 8, 103, 101, 116, 95, 104, 105, 103, 104, 0, 0, 10, 191, 1, 6, 4, 0, 35, 0, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 126, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 127, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 128, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 129, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 130, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11])), {}).exports; } catch (e) { // no wasm support :( } /** * Constructs a 64 bit two's-complement integer, given its low and high 32 bit values as *signed* integers. * See the from* functions below for more convenient ways of constructing Longs. * @exports Long * @class A Long class for representing a 64 bit two's-complement integer value. * @param {number} low The low (signed) 32 bits of the long * @param {number} high The high (signed) 32 bits of the long * @param {boolean=} unsigned Whether unsigned or not, defaults to signed * @constructor */ function Long(low, high, unsigned) { /** * The low 32 bits as a signed value. * @type {number} */ this.low = low | 0; /** * The high 32 bits as a signed value. * @type {number} */ this.high = high | 0; /** * Whether unsigned or not. * @type {boolean} */ this.unsigned = !!unsigned; } // The internal representation of a long is the two given signed, 32-bit values. // We use 32-bit pieces because these are the size of integers on which // Javascript performs bit-operations. For operations like addition and // multiplication, we split each number into 16 bit pieces, which can easily be // multiplied within Javascript's floating-point representation without overflow // or change in sign. // // In the algorithms below, we frequently reduce the negative case to the // positive case by negating the input(s) and then post-processing the result. // Note that we must ALWAYS check specially whether those values are MIN_VALUE // (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as // a positive number, it overflows back into a negative). Not handling this // case would often result in infinite recursion. // // Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the from* // methods on which they depend. /** * An indicator used to reliably determine if an object is a Long or not. * @type {boolean} * @const * @private */ Long.prototype.__isLong__; Object.defineProperty(Long.prototype, "__isLong__", { value: true }); /** * @function * @param {*} obj Object * @returns {boolean} * @inner */ function isLong(obj) { return (obj && obj["__isLong__"]) === true; } /** * @function * @param {*} value number * @returns {number} * @inner */ function ctz32(value) { var c = Math.clz32(value & -value); return value ? 31 - c : c; } /** * Tests if the specified object is a Long. * @function * @param {*} obj Object * @returns {boolean} */ Long.isLong = isLong; /** * A cache of the Long representations of small integer values. * @type {!Object} * @inner */ var INT_CACHE = {}; /** * A cache of the Long representations of small unsigned integer values. * @type {!Object} * @inner */ var UINT_CACHE = {}; /** * @param {number} value * @param {boolean=} unsigned * @returns {!Long} * @inner */ function fromInt(value, unsigned) { var obj, cachedObj, cache; if (unsigned) { value >>>= 0; if (cache = 0 <= value && value < 256) { cachedObj = UINT_CACHE[value]; if (cachedObj) return cachedObj; } obj = fromBits(value, 0, true); if (cache) UINT_CACHE[value] = obj; return obj; } else { value |= 0; if (cache = -128 <= value && value < 128) { cachedObj = INT_CACHE[value]; if (cachedObj) return cachedObj; } obj = fromBits(value, value < 0 ? -1 : 0, false); if (cache) INT_CACHE[value] = obj; return obj; } } /** * Returns a Long representing the given 32 bit integer value. * @function * @param {number} value The 32 bit integer in question * @param {boolean=} unsigned Whether unsigned or not, defaults to signed * @returns {!Long} The corresponding Long value */ Long.fromInt = fromInt; /** * @param {number} value * @param {boolean=} unsigned * @returns {!Long} * @inner */ function fromNumber(value, unsigned) { if (isNaN(value)) return unsigned ? UZERO : ZERO; if (unsigned) { if (value < 0) return UZERO; if (value >= TWO_PWR_64_DBL) return MAX_UNSIGNED_VALUE; } else { if (value <= -TWO_PWR_63_DBL) return MIN_VALUE; if (value + 1 >= TWO_PWR_63_DBL) return MAX_VALUE; } if (value < 0) return fromNumber(-value, unsigned).neg(); return fromBits(value % TWO_PWR_32_DBL | 0, value / TWO_PWR_32_DBL | 0, unsigned); } /** * Returns a Long representing the given value, provided that it is a finite number. Otherwise, zero is returned. * @function * @param {number} value The number in question * @param {boolean=} unsigned Whether unsigned or not, defaults to signed * @returns {!Long} The corresponding Long value */ Long.fromNumber = fromNumber; /** * @param {number} lowBits * @param {number} highBits * @param {boolean=} unsigned * @returns {!Long} * @inner */ function fromBits(lowBits, highBits, unsigned) { return new Long(lowBits, highBits, unsigned); } /** * Returns a Long representing the 64 bit integer that comes by concatenating the given low and high bits. Each is * assumed to use 32 bits. * @function * @param {number} lowBits The low 32 bits * @param {number} highBits The high 32 bits * @param {boolean=} unsigned Whether unsigned or not, defaults to signed * @returns {!Long} The corresponding Long value */ Long.fromBits = fromBits; /** * @function * @param {number} base * @param {number} exponent * @returns {number} * @inner */ var pow_dbl = Math.pow; // Used 4 times (4*8 to 15+4) /** * @param {string} str * @param {(boolean|number)=} unsigned * @param {number=} radix * @returns {!Long} * @inner */ function fromString(str, unsigned, radix) { if (str.length === 0) throw Error('empty string'); if (typeof unsigned === 'number') { // For goog.math.long compatibility radix = unsigned; unsigned = false; } else { unsigned = !!unsigned; } if (str === "NaN" || str === "Infinity" || str === "+Infinity" || str === "-Infinity") return unsigned ? UZERO : ZERO; radix = radix || 10; if (radix < 2 || 36 < radix) throw RangeError('radix'); var p; if ((p = str.indexOf('-')) > 0) throw Error('interior hyphen');else if (p === 0) { return fromString(str.substring(1), unsigned, radix).neg(); } // Do several (8) digits each time through the loop, so as to // minimize the calls to the very expensive emulated div. var radixToPower = fromNumber(pow_dbl(radix, 8)); var result = ZERO; for (var i = 0; i < str.length; i += 8) { var size = Math.min(8, str.length - i), value = parseInt(str.substring(i, i + size), radix); if (size < 8) { var power = fromNumber(pow_dbl(radix, size)); result = result.mul(power).add(fromNumber(value)); } else { result = result.mul(radixToPower); result = result.add(fromNumber(value)); } } result.unsigned = unsigned; return result; } /** * Returns a Long representation of the given string, written using the specified radix. * @function * @param {string} str The textual representation of the Long * @param {(boolean|number)=} unsigned Whether unsigned or not, defaults to signed * @param {number=} radix The radix in which the text is written (2-36), defaults to 10 * @returns {!Long} The corresponding Long value */ Long.fromString = fromString; /** * @function * @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val * @param {boolean=} unsigned * @returns {!Long} * @inner */ function fromValue(val, unsigned) { if (typeof val === 'number') return fromNumber(val, unsigned); if (typeof val === 'string') return fromString(val, unsigned); // Throws for non-objects, converts non-instanceof Long: return fromBits(val.low, val.high, typeof unsigned === 'boolean' ? unsigned : val.unsigned); } /** * Converts the specified value to a Long using the appropriate from* function for its type. * @function * @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val Value * @param {boolean=} unsigned Whether unsigned or not, defaults to signed * @returns {!Long} */ Long.fromValue = fromValue; // NOTE: the compiler should inline these constant values below and then remove these variables, so there should be // no runtime penalty for these. /** * @type {number} * @const * @inner */ var TWO_PWR_16_DBL = 1 << 16; /** * @type {number} * @const * @inner */ var TWO_PWR_24_DBL = 1 << 24; /** * @type {number} * @const * @inner */ var TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL; /** * @type {number} * @const * @inner */ var TWO_PWR_64_DBL = TWO_PWR_32_DBL * TWO_PWR_32_DBL; /** * @type {number} * @const * @inner */ var TWO_PWR_63_DBL = TWO_PWR_64_DBL / 2; /** * @type {!Long} * @const * @inner */ var TWO_PWR_24 = fromInt(TWO_PWR_24_DBL); /** * @type {!Long} * @inner */ var ZERO = fromInt(0); /** * Signed zero. * @type {!Long} */ Long.ZERO = ZERO; /** * @type {!Long} * @inner */ var UZERO = fromInt(0, true); /** * Unsigned zero. * @type {!Long} */ Long.UZERO = UZERO; /** * @type {!Long} * @inner */ var ONE = fromInt(1); /** * Signed one. * @type {!Long} */ Long.ONE = ONE; /** * @type {!Long} * @inner */ var UONE = fromInt(1, true); /** * Unsigned one. * @type {!Long} */ Long.UONE = UONE; /** * @type {!Long} * @inner */ var NEG_ONE = fromInt(-1); /** * Signed negative one. * @type {!Long} */ Long.NEG_ONE = NEG_ONE; /** * @type {!Long} * @inner */ var MAX_VALUE = fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0, false); /** * Maximum signed value. * @type {!Long} */ Long.MAX_VALUE = MAX_VALUE; /** * @type {!Long} * @inner */ var MAX_UNSIGNED_VALUE = fromBits(0xFFFFFFFF | 0, 0xFFFFFFFF | 0, true); /** * Maximum unsigned value. * @type {!Long} */ Long.MAX_UNSIGNED_VALUE = MAX_UNSIGNED_VALUE; /** * @type {!Long} * @inner */ var MIN_VALUE = fromBits(0, 0x80000000 | 0, false); /** * Minimum signed value. * @type {!Long} */ Long.MIN_VALUE = MIN_VALUE; /** * @alias Long.prototype * @inner */ var LongPrototype = Long.prototype; /** * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer. * @this {!Long} * @returns {number} */ LongPrototype.toInt = function toInt() { return this.unsigned ? this.low >>> 0 : this.low; }; /** * Converts the Long to a the nearest floating-point representation of this value (double, 53 bit mantissa). * @this {!Long} * @returns {number} */ LongPrototype.toNumber = function toNumber() { if (this.unsigned) return (this.high >>> 0) * TWO_PWR_32_DBL + (this.low >>> 0); return this.high * TWO_PWR_32_DBL + (this.low >>> 0); }; /** * Converts the Long to a string written in the specified radix. * @this {!Long} * @param {number=} radix Radix (2-36), defaults to 10 * @returns {string} * @override * @throws {RangeError} If `radix` is out of range */ LongPrototype.toString = function toString(radix) { radix = radix || 10; if (radix < 2 || 36 < radix) throw RangeError('radix'); if (this.isZero()) return '0'; if (this.isNegative()) { // Unsigned Longs are never negative if (this.eq(MIN_VALUE)) { // We need to change the Long value before it can be negated, so we remove // the bottom-most digit in this base and then recurse to do the rest. var radixLong = fromNumber(radix), div = this.div(radixLong), rem1 = div.mul(radixLong).sub(this); return div.toString(radix) + rem1.toInt().toString(radix); } else return '-' + this.neg().toString(radix); } // Do several (6) digits each time through the loop, so as to // minimize the calls to the very expensive emulated div. var radixToPower = fromNumber(pow_dbl(radix, 6), this.unsigned), rem = this; var result = ''; while (true) { var remDiv = rem.div(radixToPower), intval = rem.sub(remDiv.mul(radixToPower)).toInt() >>> 0, digits = intval.toString(radix); rem = remDiv; if (rem.isZero()) return digits + result;else { while (digits.length < 6) digits = '0' + digits; result = '' + digits + result; } } }; /** * Gets the high 32 bits as a signed integer. * @this {!Long} * @returns {number} Signed high bits */ LongPrototype.getHighBits = function getHighBits() { return this.high; }; /** * Gets the high 32 bits as an unsigned integer. * @this {!Long} * @returns {number} Unsigned high bits */ LongPrototype.getHighBitsUnsigned = function getHighBitsUnsigned() { return this.high >>> 0; }; /** * Gets the low 32 bits as a signed integer. * @this {!Long} * @returns {number} Signed low bits */ LongPrototype.getLowBits = function getLowBits() { return this.low; }; /** * Gets the low 32 bits as an unsigned integer. * @this {!Long} * @returns {number} Unsigned low bits */ LongPrototype.getLowBitsUnsigned = function getLowBitsUnsigned() { return this.low >>> 0; }; /** * Gets the number of bits needed to represent the absolute value of this Long. * @this {!Long} * @returns {number} */ LongPrototype.getNumBitsAbs = function getNumBitsAbs() { if (this.isNegative()) // Unsigned Longs are never negative return this.eq(MIN_VALUE) ? 64 : this.neg().getNumBitsAbs(); var val = this.high != 0 ? this.high : this.low; for (var bit = 31; bit > 0; bit--) if ((val & 1 << bit) != 0) break; return this.high != 0 ? bit + 33 : bit + 1; }; /** * Tests if this Long's value equals zero. * @this {!Long} * @returns {boolean} */ LongPrototype.isZero = function isZero() { return this.high === 0 && this.low === 0; }; /** * Tests if this Long's value equals zero. This is an alias of {@link Long#isZero}. * @returns {boolean} */ LongPrototype.eqz = LongPrototype.isZero; /** * Tests if this Long's value is negative. * @this {!Long} * @returns {boolean} */ LongPrototype.isNegative = function isNegative() { return !this.unsigned && this.high < 0; }; /** * Tests if this Long's value is positive or zero. * @this {!Long} * @returns {boolean} */ LongPrototype.isPositive = function isPositive() { return this.unsigned || this.high >= 0; }; /** * Tests if this Long's value is odd. * @this {!Long} * @returns {boolean} */ LongPrototype.isOdd = function isOdd() { return (this.low & 1) === 1; }; /** * Tests if this Long's value is even. * @this {!Long} * @returns {boolean} */ LongPrototype.isEven = function isEven() { return (this.low & 1) === 0; }; /** * Tests if this Long's value equals the specified's. * @this {!Long} * @param {!Long|number|string} other Other value * @returns {boolean} */ LongPrototype.equals = function equals(other) { if (!isLong(other)) other = fromValue(other); if (this.unsigned !== other.unsigned && this.high >>> 31 === 1 && other.high >>> 31 === 1) return false; return this.high === other.high && this.low === other.low; }; /** * Tests if this Long's value equals the specified's. This is an alias of {@link Long#equals}. * @function * @param {!Long|number|string} other Other value * @returns {boolean} */ LongPrototype.eq = LongPrototype.equals; /** * Tests if this Long's value differs from the specified's. * @this {!Long} * @param {!Long|number|string} other Other value * @returns {boolean} */ LongPrototype.notEquals = function notEquals(other) { return !this.eq( /* validates */other); }; /** * Tests if this Long's value differs from the specified's. This is an alias of {@link Long#notEquals}. * @function * @param {!Long|number|string} other Other value * @returns {boolean} */ LongPrototype.neq = LongPrototype.notEquals; /** * Tests if this Long's value differs from the specified's. This is an alias of {@link Long#notEquals}. * @function * @param {!Long|number|string} other Other value * @returns {boolean} */ LongPrototype.ne = LongPrototype.notEquals; /** * Tests if this Long's value is less than the specified's. * @this {!Long} * @param {!Long|number|string} other Other value * @returns {boolean} */ LongPrototype.lessThan = function lessThan(other) { return this.comp( /* validates */other) < 0; }; /** * Tests if this Long's value is less than the specified's. This is an alias of {@link Long#lessThan}. * @function * @param {!Long|number|string} other Other value * @returns {boolean} */ LongPrototype.lt = LongPrototype.lessThan; /** * Tests if this Long's value is less than or equal the specified's. * @this {!Long} * @param {!Long|number|string} other Other value * @returns {boolean} */ LongPrototype.lessThanOrEqual = function lessThanOrEqual(other) { return this.comp( /* validates */other) <= 0; }; /** * Tests if this Long's value is less than or equal the specified's. This is an alias of {@link Long#lessThanOrEqual}. * @function * @param {!Long|number|string} other Other value * @returns {boolean} */ LongPrototype.lte = LongPrototype.lessThanOrEqual; /** * Tests if this Long's value is less than or equal the specified's. This is an alias of {@link Long#lessThanOrEqual}. * @function * @param {!Long|number|string} other Other value * @returns {boolean} */ LongPrototype.le = LongPrototype.lessThanOrEqual; /** * Tests if this Long's value is greater than the specified's. * @this {!Long} * @param {!Long|number|string} other Other value * @returns {boolean} */ LongPrototype.greaterThan = function greaterThan(other) { return this.comp( /* validates */other) > 0; }; /** * Tests if this Long's value is greater than the specified's. This is an alias of {@link Long#greaterThan}. * @function * @param {!Long|number|string} other Other value * @returns {boolean} */ LongPrototype.gt = LongPrototype.greaterThan; /** * Tests if this Long's value is greater than or equal the specified's. * @this {!Long} * @param {!Long|number|string} other Other value * @returns {boolean} */ LongPrototype.greaterThanOrEqual = function greaterThanOrEqual(other) { return this.comp( /* validates */other) >= 0; }; /** * Tests if this Long's value is greater than or equal the specified's. This is an alias of {@link Long#greaterThanOrEqual}. * @function * @param {!Long|number|string} other Other value * @returns {boolean} */ LongPrototype.gte = LongPrototype.greaterThanOrEqual; /** * Tests if this Long's value is greater than or equal the specified's. This is an alias of {@link Long#greaterThanOrEqual}. * @function * @param {!Long|number|string} other Other value * @returns {boolean} */ LongPrototype.ge = LongPrototype.greaterThanOrEqual; /** * Compares this Long's value with the specified's. * @this {!Long} * @param {!Long|number|string} other Other value * @returns {number} 0 if they are the same, 1 if the this is greater and -1 * if the given one is greater */ LongPrototype.compare = function compare(other) { if (!isLong(other)) other = fromValue(other); if (this.eq(other)) return 0; var thisNeg = this.isNegative(), otherNeg = other.isNegative(); if (thisNeg && !otherNeg) return -1; if (!thisNeg && otherNeg) return 1; // At this point the sign bits are the same if (!this.unsigned) return this.sub(other).isNegative() ? -1 : 1; // Both are positive if at least one is unsigned return other.high >>> 0 > this.high >>> 0 || other.high === this.high && other.low >>> 0 > this.low >>> 0 ? -1 : 1; }; /** * Compares this Long's value with the specified's. This is an alias of {@link Long#compare}. * @function * @param {!Long|number|string} other Other value * @returns {number} 0 if they are the same, 1 if the this is greater and -1 * if the given one is greater */ LongPrototype.comp = LongPrototype.compare; /** * Negates this Long's value. * @this {!Long} * @returns {!Long} Negated Long */ LongPrototype.negate = function negate() { if (!this.unsigned && this.eq(MIN_VALUE)) return MIN_VALUE; return this.not().add(ONE); }; /** * Negates this Long's value. This is an alias of {@link Long#negate}. * @function * @returns {!Long} Negated Long */ LongPrototype.neg = LongPrototype.negate; /** * Returns the sum of this and the specified Long. * @this {!Long} * @param {!Long|number|string} addend Addend * @returns {!Long} Sum */ LongPrototype.add = function add(addend) { if (!isLong(addend)) addend = fromValue(addend); // Divide each number into 4 chunks of 16 bits, and then sum the chunks. var a48 = this.high >>> 16; var a32 = this.high & 0xFFFF; var a16 = this.low >>> 16; var a00 = this.low & 0xFFFF; var b48 = addend.high >>> 16; var b32 = addend.high & 0xFFFF; var b16 = addend.low >>> 16; var b00 = addend.low & 0xFFFF; var c48 = 0, c32 = 0, c16 = 0, c00 = 0; c00 += a00 + b00; c16 += c00 >>> 16; c00 &= 0xFFFF; c16 += a16 + b16; c32 += c16 >>> 16; c16 &= 0xFFFF; c32 += a32 + b32; c48 += c32 >>> 16; c32 &= 0xFFFF; c48 += a48 + b48; c48 &= 0xFFFF; return fromBits(c16 << 16 | c00, c48 << 16 | c32, this.unsigned); }; /** * Returns the difference of this and the specified Long. * @this {!Long} * @param {!Long|number|string} subtrahend Subtrahend * @returns {!Long} Difference */ LongPrototype.subtract = function subtract(subtrahend) { if (!isLong(subtrahend)) subtrahend = fromValue(subtrahend); return this.add(subtrahend.neg()); }; /** * Returns the difference of this and the specified Long. This is an alias of {@link Long#subtract}. * @function * @param {!Long|number|string} subtrahend Subtrahend * @returns {!Long} Difference */ LongPrototype.sub = LongPrototype.subtract; /** * Returns the product of this and the specified Long. * @this {!Long} * @param {!Long|number|string} multiplier Multiplier * @returns {!Long} Product */ LongPrototype.multiply = function multiply(multiplier) { if (this.isZero()) return this; if (!isLong(multiplier)) multiplier = fromValue(multiplier); // use wasm support if present if (wasm) { var low = wasm["mul"](this.low, this.high, multiplier.low, multiplier.high); return fromBits(low, wasm["get_high"](), this.unsigned); } if (multiplier.isZero()) return this.unsigned ? UZERO : ZERO; if (this.eq(MIN_VALUE)) return multiplier.isOdd() ? MIN_VALUE : ZERO; if (multiplier.eq(MIN_VALUE)) return this.isOdd() ? MIN_VALUE : ZERO; if (this.isNegative()) { if (multiplier.isNegative()) return this.neg().mul(multiplier.neg());else return this.neg().mul(multiplier).neg(); } else if (multiplier.isNegative()) return this.mul(multiplier.neg()).neg(); // If both longs are small, use float multiplication if (this.lt(TWO_PWR_24) && multiplier.lt(TWO_PWR_24)) return fromNumber(this.toNumber() * multiplier.toNumber(), this.unsigned); // Divide each long into 4 chunks of 16 bits, and then add up 4x4 products. // We can skip products that would overflow. var a48 = this.high >>> 16; var a32 = this.high & 0xFFFF; var a16 = this.low >>> 16; var a00 = this.low & 0xFFFF; var b48 = multiplier.high >>> 16; var b32 = multiplier.high & 0xFFFF; var b16 = multiplier.low >>> 16; var b00 = multiplier.low & 0xFFFF; var c48 = 0, c32 = 0, c16 = 0, c00 = 0; c00 += a00 * b00; c16 += c00 >>> 16; c00 &= 0xFFFF; c16 += a16 * b00; c32 += c16 >>> 16; c16 &= 0xFFFF; c16 += a00 * b16; c32 += c16 >>> 16; c16 &= 0xFFFF; c32 += a32 * b00; c48 += c32 >>> 16; c32 &= 0xFFFF; c32 += a16 * b16; c48 += c32 >>> 16; c32 &= 0xFFFF; c32 += a00 * b32; c48 += c32 >>> 16; c32 &= 0xFFFF; c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48; c48 &= 0xFFFF; return fromBits(c16 << 16 | c00, c48 << 16 | c32, this.unsigned); }; /** * Returns the product of this and the specified Long. This is an alias of {@link Long#multiply}. * @function * @param {!Long|number|string} multiplier Multiplier * @returns {!Long} Product */ LongPrototype.mul = LongPrototype.multiply; /** * Returns this Long divided by the specified. The result is signed if this Long is signed or * unsigned if this Long is unsigned. * @this {!Long} * @param {!Long|number|string} divisor Divisor * @returns {!Long} Quotient */ LongPrototype.divide = function divide(divisor) { if (!isLong(divisor)) divisor = fromValue(divisor); if (divisor.isZero()) throw Error('division by zero'); // use wasm support if present if (wasm) { // guard against signed division overflow: the largest // negative number / -1 would be 1 larger than the largest // positive number, due to two's complement. if (!this.unsigned && this.high === -0x80000000 && divisor.low === -1 && divisor.high === -1) { // be consistent with non-wasm code path return this; } var low = (this.unsigned ? wasm["div_u"] : wasm["div_s"])(this.low, this.high, divisor.low, divisor.high); return fromBits(low, wasm["get_high"](), this.unsigned); } if (this.isZero()) return this.unsigned ? UZERO : ZERO; var approx, rem, res; if (!this.unsigned) { // This section is only relevant for signed longs and is derived from the // closure library as a whole. if (this.eq(MIN_VALUE)) { if (divisor.eq(ONE) || divisor.eq(NEG_ONE)) return MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE else if (divisor.eq(MIN_VALUE)) return ONE;else { // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|. var halfThis = this.shr(1); approx = halfThis.div(divisor).shl(1); if (approx.eq(ZERO)) { return divisor.isNegative() ? ONE : NEG_ONE; } else { rem = this.sub(divisor.mul(approx)); res = approx.add(rem.div(divisor)); return res; } } } else if (divisor.eq(MIN_VALUE)) return this.unsigned ? UZERO : ZERO; if (this.isNegative()) { if (divisor.isNegative()) return this.neg().div(divisor.neg()); return this.neg().div(divisor).neg(); } else if (divisor.isNegative()) return this.div(divisor.neg()).neg(); res = ZERO; } else { // The algorithm below has not been made for unsigned longs. It's therefore // required to take special care of the MSB prior to running it. if (!divisor.unsigned) divisor = divisor.toUnsigned(); if (divisor.gt(this)) return UZERO; if (divisor.gt(this.shru(1))) // 15 >>> 1 = 7 ; with divisor = 8 ; true return UONE; res = UZERO; } // Repeat the following until the remainder is less than other: find a // floating-point that approximates remainder / other *from below*, add this // into the result, and subtract it from the remainder. It is critical that // the approximate value is less than or equal to the real value so that the // remainder never becomes negative. rem = this; while (rem.gte(divisor)) { // Approximate the result of division. This may be a little greater or // smaller than the actual value. approx = Math.max(1, Math.floor(rem.toNumber() / divisor.toNumber())); // We will tweak the approximate result by changing it in the 48-th digit or // the smallest non-fractional digit, whichever is larger. var log2 = Math.ceil(Math.log(approx) / Math.LN2), delta = log2 <= 48 ? 1 : pow_dbl(2, log2 - 48), // Decrease the approximation until it is smaller than the remainder. Note // that if it is too large, the product overflows and is negative. approxRes = fromNumber(approx), approxRem = approxRes.mul(divisor); while (approxRem.isNegative() || approxRem.gt(rem)) { approx -= delta; approxRes = fromNumber(approx, this.unsigned); approxRem = approxRes.mul(divisor); } // We know the answer can't be zero... and actually, zero would cause // infinite recursion since we would make no progress. if (approxRes.isZero()) approxRes = ONE; res = res.add(approxRes); rem = rem.sub(approxRem); } return res; }; /** * Returns this Long divided by the specified. This is an alias of {@link Long#divide}. * @function * @param {!Long|number|string} divisor Divisor * @returns {!Long} Quotient */ LongPrototype.div = LongPrototype.divide; /** * Returns this Long modulo the specified. * @this {!Long} * @param {!Long|number|string} divisor Divisor * @returns {!Long} Remainder */ LongPrototype.modulo = function modulo(divisor) { if (!isLong(divisor)) divisor = fromValue(divisor); // use wasm support if present if (wasm) { var low = (this.unsigned ? wasm["rem_u"] : wasm["rem_s"])(this.low, this.high, divisor.low, divisor.high); return fromBits(low, wasm["get_high"](), this.unsigned); } return this.sub(this.div(divisor).mul(divisor)); }; /** * Returns this Long modulo the specified. This is an alias of {@link Long#modulo}. * @function * @param {!Long|number|string} divisor Divisor * @returns {!Long} Remainder */ LongPrototype.mod = LongPrototype.modulo; /** * Returns this Long modulo the specified. This is an alias of {@link Long#modulo}. * @function * @param {!Long|number|string} divisor Divisor * @returns {!Long} Remainder */ LongPrototype.rem = LongPrototype.modulo; /** * Returns the bitwise NOT of this Long. * @this {!Long} * @returns {!Long} */ LongPrototype.not = function not() { return fromBits(~this.low, ~this.high, this.unsigned); }; /** * Returns count leading zeros of this Long. * @this {!Long} * @returns {!number} */ LongPrototype.countLeadingZeros = function countLeadingZeros() { return this.high ? Math.clz32(this.high) : Math.clz32(this.low) + 32; }; /** * Returns count leading zeros. This is an alias of {@link Long#countLeadingZeros}. * @function * @param {!Long} * @returns {!number} */ LongPrototype.clz = LongPrototype.countLeadingZeros; /** * Returns count trailing zeros of this Long. * @this {!Long} * @returns {!number} */ LongPrototype.countTrailingZeros = function countTrailingZeros() { return this.low ? ctz32(this.low) : ctz32(this.high) + 32; }; /** * Returns count trailing zeros. This is an alias of {@link Long#countTrailingZeros}. * @function * @param {!Long} * @returns {!number} */ LongPrototype.ctz = LongPrototype.countTrailingZeros; /** * Returns the bitwise AND of this Long and the specified. * @this {!Long} * @param {!Long|number|string} other Other Long * @returns {!Long} */ LongPrototype.and = function and(other) { if (!isLong(other)) other = fromValue(other); return fromBits(this.low & other.low, this.high & other.high, this.unsigned); }; /** * Returns the bitwise OR of this Long and the specified. * @this {!Long} * @param {!Long|number|string} other Other Long * @returns {!Long} */ LongPrototype.or = function or(other) { if (!isLong(other)) other = fromValue(other); return fromBits(this.low | other.low, this.high | other.high, this.unsigned); }; /** * Returns the bitwise XOR of this Long and the given one. * @this {!Long} * @param {!Long|number|string} other Other Long * @returns {!Long} */ LongPrototype.xor = function xor(other) { if (!isLong(other)) other = fromValue(other); return fromBits(this.low ^ other.low, this.high ^ other.high, this.unsigned); }; /** * Returns this Long with bits shifted to the left by the given amount. * @this {!Long} * @param {number|!Long} numBits Number of bits * @returns {!Long} Shifted Long */ LongPrototype.shiftLeft = function shiftLeft(numBits) { if (isLong(numBits)) numBits = numBits.toInt(); if ((numBits &= 63) === 0) return this;else if (numBits < 32) return fromBits(this.low << numBits, this.high << numBits | this.low >>> 32 - numBits, this.unsigned);else return fromBits(0, this.low << numBits - 32, this.unsigned); }; /** * Returns this Long with bits shifted to the left by the given amount. This is an alias of {@link Long#shiftLeft}. * @function * @param {number|!Long} numBits Number of bits * @returns {!Long} Shifted Long */ LongPrototype.shl = LongPrototype.shiftLeft; /** * Returns this Long with bits arithmetically shifted to the right by the given amount. * @this {!Long} * @param {number|!Long} numBits Number of bits * @returns {!Long} Shifted Long */ LongPrototype.shiftRight = function shiftRight(numBits) { if (isLong(numBits)) numBits = numBits.toInt(); if ((numBits &= 63) === 0) return this;else if (numBits < 32) return fromBits(this.low >>> numBits | this.high << 32 - numBits, this.high >> numBits, this.unsigned);else return fromBits(this.high >> numBits - 32, this.high >= 0 ? 0 : -1, this.unsigned); }; /** * Returns this Long with bits arithmetically shifted to the right by the given amount. This is an alias of {@link Long#shiftRight}. * @function * @param {number|!Long} numBits Number of bits * @returns {!Long} Shifted Long */ LongPrototype.shr = LongPrototype.shiftRight; /** * Returns this Long with bits logically shifted to the right by the given amount. * @this {!Long} * @param {number|!Long} numBits Number of bits * @returns {!Long} Shifted Long */ LongPrototype.shiftRightUnsigned = function shiftRightUnsigned(numBits) { if (isLong(numBits)) numBits = numBits.toInt(); if ((numBits &= 63) === 0) return this; if (numBits < 32) return fromBits(this.low >>> numBits | this.high << 32 - numBits, this.high >>> numBits, this.unsigned); if (numBits === 32) return fromBits(this.high, 0, this.unsigned); return fromBits(this.high >>> numBits - 32, 0, this.unsigned); }; /** * Returns this Long with bits logically shifted to the right by the given amount. This is an alias of {@link Long#shiftRightUnsigned}. * @function * @param {number|!Long} numBits Number of bits * @returns {!Long} Shifted Long */ LongPrototype.shru = LongPrototype.shiftRightUnsigned; /** * Returns this Long with bits logically shifted to the right by the given amount. This is an alias of {@link Long#shiftRightUnsigned}. * @function * @param {number|!Long} numBits Number of bits * @returns {!Long} Shifted Long */ LongPrototype.shr_u = LongPrototype.shiftRightUnsigned; /** * Returns this Long with bits rotated to the left by the given amount. * @this {!Long} * @param {number|!Long} numBits Number of bits * @returns {!Long} Rotated Long */ LongPrototype.rotateLeft = function rotateLeft(numBits) { var b; if (isLong(numBits)) numBits = numBits.toInt(); if ((numBits &= 63) === 0) return this; if (numBits === 32) return fromBits(this.high, this.low, this.unsigned); if (numBits < 32) { b = 32 - numBits; return fromBits(this.low << numBits | this.high >>> b, this.high << numBits | this.low >>> b, this.unsigned); } numBits -= 32; b = 32 - numBits; return fromBits(this.high << numBits | this.low >>> b, this.low << numBits | this.high >>> b, this.unsigned); }; /** * Returns this Long with bits rotated to the left by the given amount. This is an alias of {@link Long#rotateLeft}. * @function * @param {number|!Long} numBits Number of bits * @returns {!Long} Rotated Long */ LongPrototype.rotl = LongPrototype.rotateLeft; /** * Returns this Long with bits rotated to the right by the given amount. * @this {!Long} * @param {number|!Long} numBits Number of bits * @returns {!Long} Rotated Long */ LongPrototype.rotateRight = function rotateRight(numBits) { var b; if (isLong(numBits)) numBits = numBits.toInt(); if ((numBits &= 63) === 0) return this; if (numBits === 32) return fromBits(this.high, this.low, this.unsigned); if (numBits < 32) { b = 32 - numBits; return fromBits(this.high << b | this.low >>> numBits, this.low << b | this.high >>> numBits, this.unsigned); } numBits -= 32; b = 32 - numBits; return fromBits(this.low << b | this.high >>> numBits, this.high << b | this.low >>> numBits, this.unsigned); }; /** * Returns this Long with bits rotated to the right by the given amount. This is an alias of {@link Long#rotateRight}. * @function * @param {number|!Long} numBits Number of bits * @returns {!Long} Rotated Long */ LongPrototype.rotr = LongPrototype.rotateRight; /** * Converts this Long to signed. * @this {!Long} * @returns {!Long} Signed long */ LongPrototype.toSigned = function toSigned() { if (!this.unsigned) return this; return fromBits(this.low, this.high, false); }; /** * Converts this Long to unsigned. * @this {!Long} * @returns {!Long} Unsigned long */ LongPrototype.toUnsigned = function toUnsigned() { if (this.unsigned) return this; return fromBits(this.low, this.high, true); }; /** * Converts this Long to its byte representation. * @param {boolean=} le Whether little or big endian, defaults to big endian * @this {!Long} * @returns {!Array.} Byte representation */ LongPrototype.toBytes = function toBytes(le) { return le ? this.toBytesLE() : this.toBytesBE(); }; /** * Converts this Long to its little endian byte representation. * @this {!Long} * @returns {!Array.} Little endian byte representation */ LongPrototype.toBytesLE = function toBytesLE() { var hi = this.high, lo = this.low; return [lo & 0xff, lo >>> 8 & 0xff, lo >>> 16 & 0xff, lo >>> 24, hi & 0xff, hi >>> 8 & 0xff, hi >>> 16 & 0xff, hi >>> 24]; }; /** * Converts this Long to its big endian byte representation. * @this {!Long} * @returns {!Array.} Big endian byte representation */ LongPrototype.toBytesBE = function toBytesBE() { var hi = this.high, lo = this.low; return [hi >>> 24, hi >>> 16 & 0xff, hi >>> 8 & 0xff, hi & 0xff, lo >>> 24, lo >>> 16 & 0xff, lo >>> 8 & 0xff, lo & 0xff]; }; /** * Creates a Long from its byte representation. * @param {!Array.} bytes Byte representation * @param {boolean=} unsigned Whether unsigned or not, defaults to signed * @param {boolean=} le Whether little or big endian, defaults to big endian * @returns {Long} The corresponding Long value */ Long.fromBytes = function fromBytes(bytes, unsigned, le) { return le ? Long.fromBytesLE(bytes, unsigned) : Long.fromBytesBE(bytes, unsigned); }; /** * Creates a Long from its little endian byte representation. * @param {!Array.} bytes Little endian byte representation * @param {boolean=} unsigned Whether unsigned or not, defaults to signed * @returns {Long} The corresponding Long value */ Long.fromBytesLE = function fromBytesLE(bytes, unsigned) { return new Long(bytes[0] | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24, bytes[4] | bytes[5] << 8 | bytes[6] << 16 | bytes[7] << 24, unsigned); }; /** * Creates a Long from its big endian byte representation. * @param {!Array.} bytes Big endian byte representation * @param {boolean=} unsigned Whether unsigned or not, defaults to signed * @returns {Long} The corresponding Long value */ Long.fromBytesBE = function fromBytesBE(bytes, unsigned) { return new Long(bytes[4] << 24 | bytes[5] << 16 | bytes[6] << 8 | bytes[7], bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3], unsigned); }; var minimalExports = {}; var minimal$1 = { get exports(){ return minimalExports; }, set exports(v){ minimalExports = v; }, }; var indexMinimal = {}; var minimal = {}; var aspromise = asPromise; /** * Callback as used by {@link util.asPromise}. * @typedef asPromiseCallback * @type {function} * @param {Error|null} error Error, if any * @param {...*} params Additional arguments * @returns {undefined} */ /** * Returns a promise from a node-style callback function. * @memberof util * @param {asPromiseCallback} fn Function to call * @param {*} ctx Function context * @param {...*} params Function arguments * @returns {Promise<*>} Promisified function */ function asPromise(fn, ctx /*, varargs */) { var params = new Array(arguments.length - 1), offset = 0, index = 2, pending = true; while (index < arguments.length) params[offset++] = arguments[index++]; return new Promise(function executor(resolve, reject) { params[offset] = function callback(err /*, varargs */) { if (pending) { pending = false; if (err) reject(err);else { var params = new Array(arguments.length - 1), offset = 0; while (offset < params.length) params[offset++] = arguments[offset]; resolve.apply(null, params); } } }; try { fn.apply(ctx || null, params); } catch (err) { if (pending) { pending = false; reject(err); } } }); } var base64$1 = {}; (function (exports) { /** * A minimal base64 implementation for number arrays. * @memberof util * @namespace */ var base64 = exports; /** * Calculates the byte length of a base64 encoded string. * @param {string} string Base64 encoded string * @returns {number} Byte length */ base64.length = function length(string) { var p = string.length; if (!p) return 0; var n = 0; while (--p % 4 > 1 && string.charAt(p) === "=") ++n; return Math.ceil(string.length * 3) / 4 - n; }; // Base64 encoding table var b64 = new Array(64); // Base64 decoding table var s64 = new Array(123); // 65..90, 97..122, 48..57, 43, 47 for (var i = 0; i < 64;) s64[b64[i] = i < 26 ? i + 65 : i < 52 ? i + 71 : i < 62 ? i - 4 : i - 59 | 43] = i++; /** * Encodes a buffer to a base64 encoded string. * @param {Uint8Array} buffer Source buffer * @param {number} start Source start * @param {number} end Source end * @returns {string} Base64 encoded string */ base64.encode = function encode(buffer, start, end) { var parts = null, chunk = []; var i = 0, // output index j = 0, // goto index t; // temporary while (start < end) { var b = buffer[start++]; switch (j) { case 0: chunk[i++] = b64[b >> 2]; t = (b & 3) << 4; j = 1; break; case 1: chunk[i++] = b64[t | b >> 4]; t = (b & 15) << 2; j = 2; break; case 2: chunk[i++] = b64[t | b >> 6]; chunk[i++] = b64[b & 63]; j = 0; break; } if (i > 8191) { (parts || (parts = [])).push(String.fromCharCode.apply(String, chunk)); i = 0; } } if (j) { chunk[i++] = b64[t]; chunk[i++] = 61; if (j === 1) chunk[i++] = 61; } if (parts) { if (i) parts.push(String.fromCharCode.apply(String, chunk.slice(0, i))); return parts.join(""); } return String.fromCharCode.apply(String, chunk.slice(0, i)); }; var invalidEncoding = "invalid encoding"; /** * Decodes a base64 encoded string to a buffer. * @param {string} string Source string * @param {Uint8Array} buffer Destination buffer * @param {number} offset Destination offset * @returns {number} Number of bytes written * @throws {Error} If encoding is invalid */ base64.decode = function decode(string, buffer, offset) { var start = offset; var j = 0, // goto index t; // temporary for (var i = 0; i < string.length;) { var c = string.charCodeAt(i++); if (c === 61 && j > 1) break; if ((c = s64[c]) === undefined) throw Error(invalidEncoding); switch (j) { case 0: t = c; j = 1; break; case 1: buffer[offset++] = t << 2 | (c & 48) >> 4; t = c; j = 2; break; case 2: buffer[offset++] = (t & 15) << 4 | (c & 60) >> 2; t = c; j = 3; break; case 3: buffer[offset++] = (t & 3) << 6 | c; j = 0; break; } } if (j === 1) throw Error(invalidEncoding); return offset - start; }; /** * Tests if the specified string appears to be base64 encoded. * @param {string} string String to test * @returns {boolean} `true` if probably base64 encoded, otherwise false */ base64.test = function test(string) { return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(string); }; })(base64$1); var eventemitter = EventEmitter$1; /** * Constructs a new event emitter instance. * @classdesc A minimal event emitter. * @memberof util * @constructor */ function EventEmitter$1() { /** * Registered listeners. * @type {Object.} * @private */ this._listeners = {}; } /** * Registers an event listener. * @param {string} evt Event name * @param {function} fn Listener * @param {*} [ctx] Listener context * @returns {util.EventEmitter} `this` */ EventEmitter$1.prototype.on = function on(evt, fn, ctx) { (this._listeners[evt] || (this._listeners[evt] = [])).push({ fn: fn, ctx: ctx || this }); return this; }; /** * Removes an event listener or any matching listeners if arguments are omitted. * @param {string} [evt] Event name. Removes all listeners if omitted. * @param {function} [fn] Listener to remove. Removes all listeners of `evt` if omitted. * @returns {util.EventEmitter} `this` */ EventEmitter$1.prototype.off = function off(evt, fn) { if (evt === undefined) this._listeners = {};else { if (fn === undefined) this._listeners[evt] = [];else { var listeners = this._listeners[evt]; for (var i = 0; i < listeners.length;) if (listeners[i].fn === fn) listeners.splice(i, 1);else ++i; } } return this; }; /** * Emits an event by calling its listeners with the specified arguments. * @param {string} evt Event name * @param {...*} args Arguments * @returns {util.EventEmitter} `this` */ EventEmitter$1.prototype.emit = function emit(evt) { var listeners = this._listeners[evt]; if (listeners) { var args = [], i = 1; for (; i < arguments.length;) args.push(arguments[i++]); for (i = 0; i < listeners.length;) listeners[i].fn.apply(listeners[i++].ctx, args); } return this; }; var float = factory(factory); /** * Reads / writes floats / doubles from / to buffers. * @name util.float * @namespace */ /** * Writes a 32 bit float to a buffer using little endian byte order. * @name util.float.writeFloatLE * @function * @param {number} val Value to write * @param {Uint8Array} buf Target buffer * @param {number} pos Target buffer offset * @returns {undefined} */ /** * Writes a 32 bit float to a buffer using big endian byte order. * @name util.float.writeFloatBE * @function * @param {number} val Value to write * @param {Uint8Array} buf Target buffer * @param {number} pos Target buffer offset * @returns {undefined} */ /** * Reads a 32 bit float from a buffer using little endian byte order. * @name util.float.readFloatLE * @function * @param {Uint8Array} buf Source buffer * @param {number} pos Source buffer offset * @returns {number} Value read */ /** * Reads a 32 bit float from a buffer using big endian byte order. * @name util.float.readFloatBE * @function * @param {Uint8Array} buf Source buffer * @param {number} pos Source buffer offset * @returns {number} Value read */ /** * Writes a 64 bit double to a buffer using little endian byte order. * @name util.float.writeDoubleLE * @function * @param {number} val Value to write * @param {Uint8Array} buf Target buffer * @param {number} pos Target buffer offset * @returns {undefined} */ /** * Writes a 64 bit double to a buffer using big endian byte order. * @name util.float.writeDoubleBE * @function * @param {number} val Value to write * @param {Uint8Array} buf Target buffer * @param {number} pos Target buffer offset * @returns {undefined} */ /** * Reads a 64 bit double from a buffer using little endian byte order. * @name util.float.readDoubleLE * @function * @param {Uint8Array} buf Source buffer * @param {number} pos Source buffer offset * @returns {number} Value read */ /** * Reads a 64 bit double from a buffer using big endian byte order. * @name util.float.readDoubleBE * @function * @param {Uint8Array} buf Source buffer * @param {number} pos Source buffer offset * @returns {number} Value read */ // Factory function for the purpose of node-based testing in modified global environments function factory(exports) { // float: typed array if (typeof Float32Array !== "undefined") (function () { var f32 = new Float32Array([-0]), f8b = new Uint8Array(f32.buffer), le = f8b[3] === 128; function writeFloat_f32_cpy(val, buf, pos) { f32[0] = val; buf[pos] = f8b[0]; buf[pos + 1] = f8b[1]; buf[pos + 2] = f8b[2]; buf[pos + 3] = f8b[3]; } function writeFloat_f32_rev(val, buf, pos) { f32[0] = val; buf[pos] = f8b[3]; buf[pos + 1] = f8b[2]; buf[pos + 2] = f8b[1]; buf[pos + 3] = f8b[0]; } /* istanbul ignore next */ exports.writeFloatLE = le ? writeFloat_f32_cpy : writeFloat_f32_rev; /* istanbul ignore next */ exports.writeFloatBE = le ? writeFloat_f32_rev : writeFloat_f32_cpy; function readFloat_f32_cpy(buf, pos) { f8b[0] = buf[pos]; f8b[1] = buf[pos + 1]; f8b[2] = buf[pos + 2]; f8b[3] = buf[pos + 3]; return f32[0]; } function readFloat_f32_rev(buf, pos) { f8b[3] = buf[pos]; f8b[2] = buf[pos + 1]; f8b[1] = buf[pos + 2]; f8b[0] = buf[pos + 3]; return f32[0]; } /* istanbul ignore next */ exports.readFloatLE = le ? readFloat_f32_cpy : readFloat_f32_rev; /* istanbul ignore next */ exports.readFloatBE = le ? readFloat_f32_rev : readFloat_f32_cpy; // float: ieee754 })();else (function () { function writeFloat_ieee754(writeUint, val, buf, pos) { var sign = val < 0 ? 1 : 0; if (sign) val = -val; if (val === 0) writeUint(1 / val > 0 ? /* positive */0 : /* negative 0 */2147483648, buf, pos);else if (isNaN(val)) writeUint(2143289344, buf, pos);else if (val > 3.4028234663852886e+38) // +-Infinity writeUint((sign << 31 | 2139095040) >>> 0, buf, pos);else if (val < 1.1754943508222875e-38) // denormal writeUint((sign << 31 | Math.round(val / 1.401298464324817e-45)) >>> 0, buf, pos);else { var exponent = Math.floor(Math.log(val) / Math.LN2), mantissa = Math.round(val * Math.pow(2, -exponent) * 8388608) & 8388607; writeUint((sign << 31 | exponent + 127 << 23 | mantissa) >>> 0, buf, pos); } } exports.writeFloatLE = writeFloat_ieee754.bind(null, writeUintLE); exports.writeFloatBE = writeFloat_ieee754.bind(null, writeUintBE); function readFloat_ieee754(readUint, buf, pos) { var uint = readUint(buf, pos), sign = (uint >> 31) * 2 + 1, exponent = uint >>> 23 & 255, mantissa = uint & 8388607; return exponent === 255 ? mantissa ? NaN : sign * Infinity : exponent === 0 // denormal ? sign * 1.401298464324817e-45 * mantissa : sign * Math.pow(2, exponent - 150) * (mantissa + 8388608); } exports.readFloatLE = readFloat_ieee754.bind(null, readUintLE); exports.readFloatBE = readFloat_ieee754.bind(null, readUintBE); })(); // double: typed array if (typeof Float64Array !== "undefined") (function () { var f64 = new Float64Array([-0]), f8b = new Uint8Array(f64.buffer), le = f8b[7] === 128; function writeDouble_f64_cpy(val, buf, pos) { f64[0] = val; buf[pos] = f8b[0]; buf[pos + 1] = f8b[1]; buf[pos + 2] = f8b[2]; buf[pos + 3] = f8b[3]; buf[pos + 4] = f8b[4]; buf[pos + 5] = f8b[5]; buf[pos + 6] = f8b[6]; buf[pos + 7] = f8b[7]; } function writeDouble_f64_rev(val, buf, pos) { f64[0] = val; buf[pos] = f8b[7]; buf[pos + 1] = f8b[6]; buf[pos + 2] = f8b[5]; buf[pos + 3] = f8b[4]; buf[pos + 4] = f8b[3]; buf[pos + 5] = f8b[2]; buf[pos + 6] = f8b[1]; buf[pos + 7] = f8b[0]; } /* istanbul ignore next */ exports.writeDoubleLE = le ? writeDouble_f64_cpy : writeDouble_f64_rev; /* istanbul ignore next */ exports.writeDoubleBE = le ? writeDouble_f64_rev : writeDouble_f64_cpy; function readDouble_f64_cpy(buf, pos) { f8b[0] = buf[pos]; f8b[1] = buf[pos + 1]; f8b[2] = buf[pos + 2]; f8b[3] = buf[pos + 3]; f8b[4] = buf[pos + 4]; f8b[5] = buf[pos + 5]; f8b[6] = buf[pos + 6]; f8b[7] = buf[pos + 7]; return f64[0]; } function readDouble_f64_rev(buf, pos) { f8b[7] = buf[pos]; f8b[6] = buf[pos + 1]; f8b[5] = buf[pos + 2]; f8b[4] = buf[pos + 3]; f8b[3] = buf[pos + 4]; f8b[2] = buf[pos + 5]; f8b[1] = buf[pos + 6]; f8b[0] = buf[pos + 7]; return f64[0]; } /* istanbul ignore next */ exports.readDoubleLE = le ? readDouble_f64_cpy : readDouble_f64_rev; /* istanbul ignore next */ exports.readDoubleBE = le ? readDouble_f64_rev : readDouble_f64_cpy; // double: ieee754 })();else (function () { function writeDouble_ieee754(writeUint, off0, off1, val, buf, pos) { var sign = val < 0 ? 1 : 0; if (sign) val = -val; if (val === 0) { writeUint(0, buf, pos + off0); writeUint(1 / val > 0 ? /* positive */0 : /* negative 0 */2147483648, buf, pos + off1); } else if (isNaN(val)) { writeUint(0, buf, pos + off0); writeUint(2146959360, buf, pos + off1); } else if (val > 1.7976931348623157e+308) { // +-Infinity writeUint(0, buf, pos + off0); writeUint((sign << 31 | 2146435072) >>> 0, buf, pos + off1); } else { var mantissa; if (val < 2.2250738585072014e-308) { // denormal mantissa = val / 5e-324; writeUint(mantissa >>> 0, buf, pos + off0); writeUint((sign << 31 | mantissa / 4294967296) >>> 0, buf, pos + off1); } else { var exponent = Math.floor(Math.log(val) / Math.LN2); if (exponent === 1024) exponent = 1023; mantissa = val * Math.pow(2, -exponent); writeUint(mantissa * 4503599627370496 >>> 0, buf, pos + off0); writeUint((sign << 31 | exponent + 1023 << 20 | mantissa * 1048576 & 1048575) >>> 0, buf, pos + off1); } } } exports.writeDoubleLE = writeDouble_ieee754.bind(null, writeUintLE, 0, 4); exports.writeDoubleBE = writeDouble_ieee754.bind(null, writeUintBE, 4, 0); function readDouble_ieee754(readUint, off0, off1, buf, pos) { var lo = readUint(buf, pos + off0), hi = readUint(buf, pos + off1); var sign = (hi >> 31) * 2 + 1, exponent = hi >>> 20 & 2047, mantissa = 4294967296 * (hi & 1048575) + lo; return exponent === 2047 ? mantissa ? NaN : sign * Infinity : exponent === 0 // denormal ? sign * 5e-324 * mantissa : sign * Math.pow(2, exponent - 1075) * (mantissa + 4503599627370496); } exports.readDoubleLE = readDouble_ieee754.bind(null, readUintLE, 0, 4); exports.readDoubleBE = readDouble_ieee754.bind(null, readUintBE, 4, 0); })(); return exports; } // uint helpers function writeUintLE(val, buf, pos) { buf[pos] = val & 255; buf[pos + 1] = val >>> 8 & 255; buf[pos + 2] = val >>> 16 & 255; buf[pos + 3] = val >>> 24; } function writeUintBE(val, buf, pos) { buf[pos] = val >>> 24; buf[pos + 1] = val >>> 16 & 255; buf[pos + 2] = val >>> 8 & 255; buf[pos + 3] = val & 255; } function readUintLE(buf, pos) { return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16 | buf[pos + 3] << 24) >>> 0; } function readUintBE(buf, pos) { return (buf[pos] << 24 | buf[pos + 1] << 16 | buf[pos + 2] << 8 | buf[pos + 3]) >>> 0; } var inquire_1 = inquire; /** * Requires a module only if available. * @memberof util * @param {string} moduleName Module to require * @returns {?Object} Required module if available and not empty, otherwise `null` */ function inquire(moduleName) { try { var mod = undefined; // eslint-disable-line no-eval if (mod && (mod.length || Object.keys(mod).length)) return mod; } catch (e) {} // eslint-disable-line no-empty return null; } var utf8$2 = {}; (function (exports) { /** * A minimal UTF8 implementation for number arrays. * @memberof util * @namespace */ var utf8 = exports; /** * Calculates the UTF8 byte length of a string. * @param {string} string String * @returns {number} Byte length */ utf8.length = function utf8_length(string) { var len = 0, c = 0; for (var i = 0; i < string.length; ++i) { c = string.charCodeAt(i); if (c < 128) len += 1;else if (c < 2048) len += 2;else if ((c & 0xFC00) === 0xD800 && (string.charCodeAt(i + 1) & 0xFC00) === 0xDC00) { ++i; len += 4; } else len += 3; } return len; }; /** * Reads UTF8 bytes as a string. * @param {Uint8Array} buffer Source buffer * @param {number} start Source start * @param {number} end Source end * @returns {string} String read */ utf8.read = function utf8_read(buffer, start, end) { var len = end - start; if (len < 1) return ""; var parts = null, chunk = [], i = 0, // char offset t; // temporary while (start < end) { t = buffer[start++]; if (t < 128) chunk[i++] = t;else if (t > 191 && t < 224) chunk[i++] = (t & 31) << 6 | buffer[start++] & 63;else if (t > 239 && t < 365) { t = ((t & 7) << 18 | (buffer[start++] & 63) << 12 | (buffer[start++] & 63) << 6 | buffer[start++] & 63) - 0x10000; chunk[i++] = 0xD800 + (t >> 10); chunk[i++] = 0xDC00 + (t & 1023); } else chunk[i++] = (t & 15) << 12 | (buffer[start++] & 63) << 6 | buffer[start++] & 63; if (i > 8191) { (parts || (parts = [])).push(String.fromCharCode.apply(String, chunk)); i = 0; } } if (parts) { if (i) parts.push(String.fromCharCode.apply(String, chunk.slice(0, i))); return parts.join(""); } return String.fromCharCode.apply(String, chunk.slice(0, i)); }; /** * Writes a string as UTF8 bytes. * @param {string} string Source string * @param {Uint8Array} buffer Destination buffer * @param {number} offset Destination offset * @returns {number} Bytes written */ utf8.write = function utf8_write(string, buffer, offset) { var start = offset, c1, // character 1 c2; // character 2 for (var i = 0; i < string.length; ++i) { c1 = string.charCodeAt(i); if (c1 < 128) { buffer[offset++] = c1; } else if (c1 < 2048) { buffer[offset++] = c1 >> 6 | 192; buffer[offset++] = c1 & 63 | 128; } else if ((c1 & 0xFC00) === 0xD800 && ((c2 = string.charCodeAt(i + 1)) & 0xFC00) === 0xDC00) { c1 = 0x10000 + ((c1 & 0x03FF) << 10) + (c2 & 0x03FF); ++i; buffer[offset++] = c1 >> 18 | 240; buffer[offset++] = c1 >> 12 & 63 | 128; buffer[offset++] = c1 >> 6 & 63 | 128; buffer[offset++] = c1 & 63 | 128; } else { buffer[offset++] = c1 >> 12 | 224; buffer[offset++] = c1 >> 6 & 63 | 128; buffer[offset++] = c1 & 63 | 128; } } return offset - start; }; })(utf8$2); var pool_1 = pool; /** * An allocator as used by {@link util.pool}. * @typedef PoolAllocator * @type {function} * @param {number} size Buffer size * @returns {Uint8Array} Buffer */ /** * A slicer as used by {@link util.pool}. * @typedef PoolSlicer * @type {function} * @param {number} start Start offset * @param {number} end End offset * @returns {Uint8Array} Buffer slice * @this {Uint8Array} */ /** * A general purpose buffer pool. * @memberof util * @function * @param {PoolAllocator} alloc Allocator * @param {PoolSlicer} slice Slicer * @param {number} [size=8192] Slab size * @returns {PoolAllocator} Pooled allocator */ function pool(alloc, slice, size) { var SIZE = size || 8192; var MAX = SIZE >>> 1; var slab = null; var offset = SIZE; return function pool_alloc(size) { if (size < 1 || size > MAX) return alloc(size); if (offset + size > SIZE) { slab = alloc(SIZE); offset = 0; } var buf = slice.call(slab, offset, offset += size); if (offset & 7) // align to 32 bit offset = (offset | 7) + 1; return buf; }; } var longbits; var hasRequiredLongbits; function requireLongbits() { if (hasRequiredLongbits) return longbits; hasRequiredLongbits = 1; longbits = LongBits; var util = requireMinimal(); /** * Constructs new long bits. * @classdesc Helper class for working with the low and high bits of a 64 bit value. * @memberof util * @constructor * @param {number} lo Low 32 bits, unsigned * @param {number} hi High 32 bits, unsigned */ function LongBits(lo, hi) { // note that the casts below are theoretically unnecessary as of today, but older statically // generated converter code might still call the ctor with signed 32bits. kept for compat. /** * Low bits. * @type {number} */ this.lo = lo >>> 0; /** * High bits. * @type {number} */ this.hi = hi >>> 0; } /** * Zero bits. * @memberof util.LongBits * @type {util.LongBits} */ var zero = LongBits.zero = new LongBits(0, 0); zero.toNumber = function () { return 0; }; zero.zzEncode = zero.zzDecode = function () { return this; }; zero.length = function () { return 1; }; /** * Zero hash. * @memberof util.LongBits * @type {string} */ var zeroHash = LongBits.zeroHash = "\0\0\0\0\0\0\0\0"; /** * Constructs new long bits from the specified number. * @param {number} value Value * @returns {util.LongBits} Instance */ LongBits.fromNumber = function fromNumber(value) { if (value === 0) return zero; var sign = value < 0; if (sign) value = -value; var lo = value >>> 0, hi = (value - lo) / 4294967296 >>> 0; if (sign) { hi = ~hi >>> 0; lo = ~lo >>> 0; if (++lo > 4294967295) { lo = 0; if (++hi > 4294967295) hi = 0; } } return new LongBits(lo, hi); }; /** * Constructs new long bits from a number, long or string. * @param {Long|number|string} value Value * @returns {util.LongBits} Instance */ LongBits.from = function from(value) { if (typeof value === "number") return LongBits.fromNumber(value); if (util.isString(value)) { /* istanbul ignore else */ if (util.Long) value = util.Long.fromString(value);else return LongBits.fromNumber(parseInt(value, 10)); } return value.low || value.high ? new LongBits(value.low >>> 0, value.high >>> 0) : zero; }; /** * Converts this long bits to a possibly unsafe JavaScript number. * @param {boolean} [unsigned=false] Whether unsigned or not * @returns {number} Possibly unsafe number */ LongBits.prototype.toNumber = function toNumber(unsigned) { if (!unsigned && this.hi >>> 31) { var lo = ~this.lo + 1 >>> 0, hi = ~this.hi >>> 0; if (!lo) hi = hi + 1 >>> 0; return -(lo + hi * 4294967296); } return this.lo + this.hi * 4294967296; }; /** * Converts this long bits to a long. * @param {boolean} [unsigned=false] Whether unsigned or not * @returns {Long} Long */ LongBits.prototype.toLong = function toLong(unsigned) { return util.Long ? new util.Long(this.lo | 0, this.hi | 0, Boolean(unsigned)) /* istanbul ignore next */ : { low: this.lo | 0, high: this.hi | 0, unsigned: Boolean(unsigned) }; }; var charCodeAt = String.prototype.charCodeAt; /** * Constructs new long bits from the specified 8 characters long hash. * @param {string} hash Hash * @returns {util.LongBits} Bits */ LongBits.fromHash = function fromHash(hash) { if (hash === zeroHash) return zero; return new LongBits((charCodeAt.call(hash, 0) | charCodeAt.call(hash, 1) << 8 | charCodeAt.call(hash, 2) << 16 | charCodeAt.call(hash, 3) << 24) >>> 0, (charCodeAt.call(hash, 4) | charCodeAt.call(hash, 5) << 8 | charCodeAt.call(hash, 6) << 16 | charCodeAt.call(hash, 7) << 24) >>> 0); }; /** * Converts this long bits to a 8 characters long hash. * @returns {string} Hash */ LongBits.prototype.toHash = function toHash() { return String.fromCharCode(this.lo & 255, this.lo >>> 8 & 255, this.lo >>> 16 & 255, this.lo >>> 24, this.hi & 255, this.hi >>> 8 & 255, this.hi >>> 16 & 255, this.hi >>> 24); }; /** * Zig-zag encodes this long bits. * @returns {util.LongBits} `this` */ LongBits.prototype.zzEncode = function zzEncode() { var mask = this.hi >> 31; this.hi = ((this.hi << 1 | this.lo >>> 31) ^ mask) >>> 0; this.lo = (this.lo << 1 ^ mask) >>> 0; return this; }; /** * Zig-zag decodes this long bits. * @returns {util.LongBits} `this` */ LongBits.prototype.zzDecode = function zzDecode() { var mask = -(this.lo & 1); this.lo = ((this.lo >>> 1 | this.hi << 31) ^ mask) >>> 0; this.hi = (this.hi >>> 1 ^ mask) >>> 0; return this; }; /** * Calculates the length of this longbits when encoded as a varint. * @returns {number} Length */ LongBits.prototype.length = function length() { var part0 = this.lo, part1 = (this.lo >>> 28 | this.hi << 4) >>> 0, part2 = this.hi >>> 24; return part2 === 0 ? part1 === 0 ? part0 < 16384 ? part0 < 128 ? 1 : 2 : part0 < 2097152 ? 3 : 4 : part1 < 16384 ? part1 < 128 ? 5 : 6 : part1 < 2097152 ? 7 : 8 : part2 < 128 ? 9 : 10; }; return longbits; } var hasRequiredMinimal; function requireMinimal() { if (hasRequiredMinimal) return minimal; hasRequiredMinimal = 1; (function (exports) { var util = exports; // used to return a Promise where callback is omitted util.asPromise = aspromise; // converts to / from base64 encoded strings util.base64 = base64$1; // base class of rpc.Service util.EventEmitter = eventemitter; // float handling accross browsers util.float = float; // requires modules optionally and hides the call from bundlers util.inquire = inquire_1; // converts to / from utf8 encoded strings util.utf8 = utf8$2; // provides a node-like buffer pool in the browser util.pool = pool_1; // utility to work with the low and high bits of a 64 bit value util.LongBits = requireLongbits(); /** * Whether running within node or not. * @memberof util * @type {boolean} */ util.isNode = Boolean(typeof commonjsGlobal !== "undefined" && commonjsGlobal && commonjsGlobal.process && commonjsGlobal.process.versions && commonjsGlobal.process.versions.node); /** * Global object reference. * @memberof util * @type {Object} */ util.global = util.isNode && commonjsGlobal || typeof window !== "undefined" && window || typeof self !== "undefined" && self || commonjsGlobal; // eslint-disable-line no-invalid-this /** * An immuable empty array. * @memberof util * @type {Array.<*>} * @const */ util.emptyArray = Object.freeze ? Object.freeze([]) : /* istanbul ignore next */[]; // used on prototypes /** * An immutable empty object. * @type {Object} * @const */ util.emptyObject = Object.freeze ? Object.freeze({}) : /* istanbul ignore next */{}; // used on prototypes /** * Tests if the specified value is an integer. * @function * @param {*} value Value to test * @returns {boolean} `true` if the value is an integer */ util.isInteger = Number.isInteger || /* istanbul ignore next */function isInteger(value) { return typeof value === "number" && isFinite(value) && Math.floor(value) === value; }; /** * Tests if the specified value is a string. * @param {*} value Value to test * @returns {boolean} `true` if the value is a string */ util.isString = function isString(value) { return typeof value === "string" || value instanceof String; }; /** * Tests if the specified value is a non-null object. * @param {*} value Value to test * @returns {boolean} `true` if the value is a non-null object */ util.isObject = function isObject(value) { return value && typeof value === "object"; }; /** * Checks if a property on a message is considered to be present. * This is an alias of {@link util.isSet}. * @function * @param {Object} obj Plain object or message instance * @param {string} prop Property name * @returns {boolean} `true` if considered to be present, otherwise `false` */ util.isset = /** * Checks if a property on a message is considered to be present. * @param {Object} obj Plain object or message instance * @param {string} prop Property name * @returns {boolean} `true` if considered to be present, otherwise `false` */ util.isSet = function isSet(obj, prop) { var value = obj[prop]; if (value != null && obj.hasOwnProperty(prop)) // eslint-disable-line eqeqeq, no-prototype-builtins return typeof value !== "object" || (Array.isArray(value) ? value.length : Object.keys(value).length) > 0; return false; }; /** * Any compatible Buffer instance. * This is a minimal stand-alone definition of a Buffer instance. The actual type is that exported by node's typings. * @interface Buffer * @extends Uint8Array */ /** * Node's Buffer class if available. * @type {Constructor} */ util.Buffer = function () { try { var Buffer = util.inquire("buffer").Buffer; // refuse to use non-node buffers if not explicitly assigned (perf reasons): return Buffer.prototype.utf8Write ? Buffer : /* istanbul ignore next */null; } catch (e) { /* istanbul ignore next */ return null; } }(); // Internal alias of or polyfull for Buffer.from. util._Buffer_from = null; // Internal alias of or polyfill for Buffer.allocUnsafe. util._Buffer_allocUnsafe = null; /** * Creates a new buffer of whatever type supported by the environment. * @param {number|number[]} [sizeOrArray=0] Buffer size or number array * @returns {Uint8Array|Buffer} Buffer */ util.newBuffer = function newBuffer(sizeOrArray) { /* istanbul ignore next */ return typeof sizeOrArray === "number" ? util.Buffer ? util._Buffer_allocUnsafe(sizeOrArray) : new util.Array(sizeOrArray) : util.Buffer ? util._Buffer_from(sizeOrArray) : typeof Uint8Array === "undefined" ? sizeOrArray : new Uint8Array(sizeOrArray); }; /** * Array implementation used in the browser. `Uint8Array` if supported, otherwise `Array`. * @type {Constructor} */ util.Array = typeof Uint8Array !== "undefined" ? Uint8Array /* istanbul ignore next */ : Array; /** * Any compatible Long instance. * This is a minimal stand-alone definition of a Long instance. The actual type is that exported by long.js. * @interface Long * @property {number} low Low bits * @property {number} high High bits * @property {boolean} unsigned Whether unsigned or not */ /** * Long.js's Long class if available. * @type {Constructor} */ util.Long = /* istanbul ignore next */util.global.dcodeIO && /* istanbul ignore next */util.global.dcodeIO.Long || /* istanbul ignore next */util.global.Long || util.inquire("long"); /** * Regular expression used to verify 2 bit (`bool`) map keys. * @type {RegExp} * @const */ util.key2Re = /^true|false|0|1$/; /** * Regular expression used to verify 32 bit (`int32` etc.) map keys. * @type {RegExp} * @const */ util.key32Re = /^-?(?:0|[1-9][0-9]*)$/; /** * Regular expression used to verify 64 bit (`int64` etc.) map keys. * @type {RegExp} * @const */ util.key64Re = /^(?:[\\x00-\\xff]{8}|-?(?:0|[1-9][0-9]*))$/; /** * Converts a number or long to an 8 characters long hash string. * @param {Long|number} value Value to convert * @returns {string} Hash */ util.longToHash = function longToHash(value) { return value ? util.LongBits.from(value).toHash() : util.LongBits.zeroHash; }; /** * Converts an 8 characters long hash string to a long or number. * @param {string} hash Hash * @param {boolean} [unsigned=false] Whether unsigned or not * @returns {Long|number} Original value */ util.longFromHash = function longFromHash(hash, unsigned) { var bits = util.LongBits.fromHash(hash); if (util.Long) return util.Long.fromBits(bits.lo, bits.hi, unsigned); return bits.toNumber(Boolean(unsigned)); }; /** * Merges the properties of the source object into the destination object. * @memberof util * @param {Object.} dst Destination object * @param {Object.} src Source object * @param {boolean} [ifNotSet=false] Merges only if the key is not already set * @returns {Object.} Destination object */ function merge(dst, src, ifNotSet) { // used by converters for (var keys = Object.keys(src), i = 0; i < keys.length; ++i) if (dst[keys[i]] === undefined || !ifNotSet) dst[keys[i]] = src[keys[i]]; return dst; } util.merge = merge; /** * Converts the first character of a string to lower case. * @param {string} str String to convert * @returns {string} Converted string */ util.lcFirst = function lcFirst(str) { return str.charAt(0).toLowerCase() + str.substring(1); }; /** * Creates a custom error constructor. * @memberof util * @param {string} name Error name * @returns {Constructor} Custom error constructor */ function newError(name) { function CustomError(message, properties) { if (!(this instanceof CustomError)) return new CustomError(message, properties); // Error.call(this, message); // ^ just returns a new error instance because the ctor can be called as a function Object.defineProperty(this, "message", { get: function () { return message; } }); /* istanbul ignore next */ if (Error.captureStackTrace) // node Error.captureStackTrace(this, CustomError);else Object.defineProperty(this, "stack", { value: new Error().stack || "" }); if (properties) merge(this, properties); } CustomError.prototype = Object.create(Error.prototype, { constructor: { value: CustomError, writable: true, enumerable: false, configurable: true }, name: { get() { return name; }, set: undefined, enumerable: false, // configurable: false would accurately preserve the behavior of // the original, but I'm guessing that was not intentional. // For an actual error subclass, this property would // be configurable. configurable: true }, toString: { value() { return this.name + ": " + this.message; }, writable: true, enumerable: false, configurable: true } }); return CustomError; } util.newError = newError; /** * Constructs a new protocol error. * @classdesc Error subclass indicating a protocol specifc error. * @memberof util * @extends Error * @template T extends Message * @constructor * @param {string} message Error message * @param {Object.} [properties] Additional properties * @example * try { * MyMessage.decode(someBuffer); // throws if required fields are missing * } catch (e) { * if (e instanceof ProtocolError && e.instance) * console.log("decoded so far: " + JSON.stringify(e.instance)); * } */ util.ProtocolError = newError("ProtocolError"); /** * So far decoded message instance. * @name util.ProtocolError#instance * @type {Message} */ /** * A OneOf getter as returned by {@link util.oneOfGetter}. * @typedef OneOfGetter * @type {function} * @returns {string|undefined} Set field name, if any */ /** * Builds a getter for a oneof's present field name. * @param {string[]} fieldNames Field names * @returns {OneOfGetter} Unbound getter */ util.oneOfGetter = function getOneOf(fieldNames) { var fieldMap = {}; for (var i = 0; i < fieldNames.length; ++i) fieldMap[fieldNames[i]] = 1; /** * @returns {string|undefined} Set field name, if any * @this Object * @ignore */ return function () { // eslint-disable-line consistent-return for (var keys = Object.keys(this), i = keys.length - 1; i > -1; --i) if (fieldMap[keys[i]] === 1 && this[keys[i]] !== undefined && this[keys[i]] !== null) return keys[i]; }; }; /** * A OneOf setter as returned by {@link util.oneOfSetter}. * @typedef OneOfSetter * @type {function} * @param {string|undefined} value Field name * @returns {undefined} */ /** * Builds a setter for a oneof's present field name. * @param {string[]} fieldNames Field names * @returns {OneOfSetter} Unbound setter */ util.oneOfSetter = function setOneOf(fieldNames) { /** * @param {string} name Field name * @returns {undefined} * @this Object * @ignore */ return function (name) { for (var i = 0; i < fieldNames.length; ++i) if (fieldNames[i] !== name) delete this[fieldNames[i]]; }; }; /** * Default conversion options used for {@link Message#toJSON} implementations. * * These options are close to proto3's JSON mapping with the exception that internal types like Any are handled just like messages. More precisely: * * - Longs become strings * - Enums become string keys * - Bytes become base64 encoded strings * - (Sub-)Messages become plain objects * - Maps become plain objects with all string keys * - Repeated fields become arrays * - NaN and Infinity for float and double fields become strings * * @type {IConversionOptions} * @see https://developers.google.com/protocol-buffers/docs/proto3?hl=en#json */ util.toJSONOptions = { longs: String, enums: String, bytes: String, json: true }; // Sets up buffer utility according to the environment (called in index-minimal) util._configure = function () { var Buffer = util.Buffer; /* istanbul ignore if */ if (!Buffer) { util._Buffer_from = util._Buffer_allocUnsafe = null; return; } // because node 4.x buffers are incompatible & immutable // see: https://github.com/dcodeIO/protobuf.js/pull/665 util._Buffer_from = Buffer.from !== Uint8Array.from && Buffer.from || /* istanbul ignore next */ function Buffer_from(value, encoding) { return new Buffer(value, encoding); }; util._Buffer_allocUnsafe = Buffer.allocUnsafe || /* istanbul ignore next */ function Buffer_allocUnsafe(size) { return new Buffer(size); }; }; })(minimal); return minimal; } var writer$2 = Writer$1; var util$4 = requireMinimal(); var BufferWriter$1; // cyclic var LongBits$1 = util$4.LongBits, base64 = util$4.base64, utf8$1 = util$4.utf8; /** * Constructs a new writer operation instance. * @classdesc Scheduled writer operation. * @constructor * @param {function(*, Uint8Array, number)} fn Function to call * @param {number} len Value byte length * @param {*} val Value to write * @ignore */ function Op(fn, len, val) { /** * Function to call. * @type {function(Uint8Array, number, *)} */ this.fn = fn; /** * Value byte length. * @type {number} */ this.len = len; /** * Next operation. * @type {Writer.Op|undefined} */ this.next = undefined; /** * Value to write. * @type {*} */ this.val = val; // type varies } /* istanbul ignore next */ function noop() {} // eslint-disable-line no-empty-function /** * Constructs a new writer state instance. * @classdesc Copied writer state. * @memberof Writer * @constructor * @param {Writer} writer Writer to copy state from * @ignore */ function State(writer) { /** * Current head. * @type {Writer.Op} */ this.head = writer.head; /** * Current tail. * @type {Writer.Op} */ this.tail = writer.tail; /** * Current buffer length. * @type {number} */ this.len = writer.len; /** * Next state. * @type {State|null} */ this.next = writer.states; } /** * Constructs a new writer instance. * @classdesc Wire format writer using `Uint8Array` if available, otherwise `Array`. * @constructor */ function Writer$1() { /** * Current length. * @type {number} */ this.len = 0; /** * Operations head. * @type {Object} */ this.head = new Op(noop, 0, 0); /** * Operations tail * @type {Object} */ this.tail = this.head; /** * Linked forked states. * @type {Object|null} */ this.states = null; // When a value is written, the writer calculates its byte length and puts it into a linked // list of operations to perform when finish() is called. This both allows us to allocate // buffers of the exact required size and reduces the amount of work we have to do compared // to first calculating over objects and then encoding over objects. In our case, the encoding // part is just a linked list walk calling operations with already prepared values. } var create$1 = function create() { return util$4.Buffer ? function create_buffer_setup() { return (Writer$1.create = function create_buffer() { return new BufferWriter$1(); })(); } /* istanbul ignore next */ : function create_array() { return new Writer$1(); }; }; /** * Creates a new writer. * @function * @returns {BufferWriter|Writer} A {@link BufferWriter} when Buffers are supported, otherwise a {@link Writer} */ Writer$1.create = create$1(); /** * Allocates a buffer of the specified size. * @param {number} size Buffer size * @returns {Uint8Array} Buffer */ Writer$1.alloc = function alloc(size) { return new util$4.Array(size); }; // Use Uint8Array buffer pool in the browser, just like node does with buffers /* istanbul ignore else */ if (util$4.Array !== Array) Writer$1.alloc = util$4.pool(Writer$1.alloc, util$4.Array.prototype.subarray); /** * Pushes a new operation to the queue. * @param {function(Uint8Array, number, *)} fn Function to call * @param {number} len Value byte length * @param {number} val Value to write * @returns {Writer} `this` * @private */ Writer$1.prototype._push = function push(fn, len, val) { this.tail = this.tail.next = new Op(fn, len, val); this.len += len; return this; }; function writeByte(val, buf, pos) { buf[pos] = val & 255; } function writeVarint32(val, buf, pos) { while (val > 127) { buf[pos++] = val & 127 | 128; val >>>= 7; } buf[pos] = val; } /** * Constructs a new varint writer operation instance. * @classdesc Scheduled varint writer operation. * @extends Op * @constructor * @param {number} len Value byte length * @param {number} val Value to write * @ignore */ function VarintOp(len, val) { this.len = len; this.next = undefined; this.val = val; } VarintOp.prototype = Object.create(Op.prototype); VarintOp.prototype.fn = writeVarint32; /** * Writes an unsigned 32 bit value as a varint. * @param {number} value Value to write * @returns {Writer} `this` */ Writer$1.prototype.uint32 = function write_uint32(value) { // here, the call to this.push has been inlined and a varint specific Op subclass is used. // uint32 is by far the most frequently used operation and benefits significantly from this. this.len += (this.tail = this.tail.next = new VarintOp((value = value >>> 0) < 128 ? 1 : value < 16384 ? 2 : value < 2097152 ? 3 : value < 268435456 ? 4 : 5, value)).len; return this; }; /** * Writes a signed 32 bit value as a varint. * @function * @param {number} value Value to write * @returns {Writer} `this` */ Writer$1.prototype.int32 = function write_int32(value) { return value < 0 ? this._push(writeVarint64, 10, LongBits$1.fromNumber(value)) // 10 bytes per spec : this.uint32(value); }; /** * Writes a 32 bit value as a varint, zig-zag encoded. * @param {number} value Value to write * @returns {Writer} `this` */ Writer$1.prototype.sint32 = function write_sint32(value) { return this.uint32((value << 1 ^ value >> 31) >>> 0); }; function writeVarint64(val, buf, pos) { while (val.hi) { buf[pos++] = val.lo & 127 | 128; val.lo = (val.lo >>> 7 | val.hi << 25) >>> 0; val.hi >>>= 7; } while (val.lo > 127) { buf[pos++] = val.lo & 127 | 128; val.lo = val.lo >>> 7; } buf[pos++] = val.lo; } /** * Writes an unsigned 64 bit value as a varint. * @param {Long|number|string} value Value to write * @returns {Writer} `this` * @throws {TypeError} If `value` is a string and no long library is present. */ Writer$1.prototype.uint64 = function write_uint64(value) { var bits = LongBits$1.from(value); return this._push(writeVarint64, bits.length(), bits); }; /** * Writes a signed 64 bit value as a varint. * @function * @param {Long|number|string} value Value to write * @returns {Writer} `this` * @throws {TypeError} If `value` is a string and no long library is present. */ Writer$1.prototype.int64 = Writer$1.prototype.uint64; /** * Writes a signed 64 bit value as a varint, zig-zag encoded. * @param {Long|number|string} value Value to write * @returns {Writer} `this` * @throws {TypeError} If `value` is a string and no long library is present. */ Writer$1.prototype.sint64 = function write_sint64(value) { var bits = LongBits$1.from(value).zzEncode(); return this._push(writeVarint64, bits.length(), bits); }; /** * Writes a boolish value as a varint. * @param {boolean} value Value to write * @returns {Writer} `this` */ Writer$1.prototype.bool = function write_bool(value) { return this._push(writeByte, 1, value ? 1 : 0); }; function writeFixed32(val, buf, pos) { buf[pos] = val & 255; buf[pos + 1] = val >>> 8 & 255; buf[pos + 2] = val >>> 16 & 255; buf[pos + 3] = val >>> 24; } /** * Writes an unsigned 32 bit value as fixed 32 bits. * @param {number} value Value to write * @returns {Writer} `this` */ Writer$1.prototype.fixed32 = function write_fixed32(value) { return this._push(writeFixed32, 4, value >>> 0); }; /** * Writes a signed 32 bit value as fixed 32 bits. * @function * @param {number} value Value to write * @returns {Writer} `this` */ Writer$1.prototype.sfixed32 = Writer$1.prototype.fixed32; /** * Writes an unsigned 64 bit value as fixed 64 bits. * @param {Long|number|string} value Value to write * @returns {Writer} `this` * @throws {TypeError} If `value` is a string and no long library is present. */ Writer$1.prototype.fixed64 = function write_fixed64(value) { var bits = LongBits$1.from(value); return this._push(writeFixed32, 4, bits.lo)._push(writeFixed32, 4, bits.hi); }; /** * Writes a signed 64 bit value as fixed 64 bits. * @function * @param {Long|number|string} value Value to write * @returns {Writer} `this` * @throws {TypeError} If `value` is a string and no long library is present. */ Writer$1.prototype.sfixed64 = Writer$1.prototype.fixed64; /** * Writes a float (32 bit). * @function * @param {number} value Value to write * @returns {Writer} `this` */ Writer$1.prototype.float = function write_float(value) { return this._push(util$4.float.writeFloatLE, 4, value); }; /** * Writes a double (64 bit float). * @function * @param {number} value Value to write * @returns {Writer} `this` */ Writer$1.prototype.double = function write_double(value) { return this._push(util$4.float.writeDoubleLE, 8, value); }; var writeBytes = util$4.Array.prototype.set ? function writeBytes_set(val, buf, pos) { buf.set(val, pos); // also works for plain array values } /* istanbul ignore next */ : function writeBytes_for(val, buf, pos) { for (var i = 0; i < val.length; ++i) buf[pos + i] = val[i]; }; /** * Writes a sequence of bytes. * @param {Uint8Array|string} value Buffer or base64 encoded string to write * @returns {Writer} `this` */ Writer$1.prototype.bytes = function write_bytes(value) { var len = value.length >>> 0; if (!len) return this._push(writeByte, 1, 0); if (util$4.isString(value)) { var buf = Writer$1.alloc(len = base64.length(value)); base64.decode(value, buf, 0); value = buf; } return this.uint32(len)._push(writeBytes, len, value); }; /** * Writes a string. * @param {string} value Value to write * @returns {Writer} `this` */ Writer$1.prototype.string = function write_string(value) { var len = utf8$1.length(value); return len ? this.uint32(len)._push(utf8$1.write, len, value) : this._push(writeByte, 1, 0); }; /** * Forks this writer's state by pushing it to a stack. * Calling {@link Writer#reset|reset} or {@link Writer#ldelim|ldelim} resets the writer to the previous state. * @returns {Writer} `this` */ Writer$1.prototype.fork = function fork() { this.states = new State(this); this.head = this.tail = new Op(noop, 0, 0); this.len = 0; return this; }; /** * Resets this instance to the last state. * @returns {Writer} `this` */ Writer$1.prototype.reset = function reset() { if (this.states) { this.head = this.states.head; this.tail = this.states.tail; this.len = this.states.len; this.states = this.states.next; } else { this.head = this.tail = new Op(noop, 0, 0); this.len = 0; } return this; }; /** * Resets to the last state and appends the fork state's current write length as a varint followed by its operations. * @returns {Writer} `this` */ Writer$1.prototype.ldelim = function ldelim() { var head = this.head, tail = this.tail, len = this.len; this.reset().uint32(len); if (len) { this.tail.next = head.next; // skip noop this.tail = tail; this.len += len; } return this; }; /** * Finishes the write operation. * @returns {Uint8Array} Finished buffer */ Writer$1.prototype.finish = function finish() { var head = this.head.next, // skip noop buf = this.constructor.alloc(this.len), pos = 0; while (head) { head.fn(head.val, buf, pos); pos += head.len; head = head.next; } // this.head = this.tail = null; return buf; }; Writer$1._configure = function (BufferWriter_) { BufferWriter$1 = BufferWriter_; Writer$1.create = create$1(); BufferWriter$1._configure(); }; var writer_buffer = BufferWriter; // extends Writer var Writer = writer$2; (BufferWriter.prototype = Object.create(Writer.prototype)).constructor = BufferWriter; var util$3 = requireMinimal(); /** * Constructs a new buffer writer instance. * @classdesc Wire format writer using node buffers. * @extends Writer * @constructor */ function BufferWriter() { Writer.call(this); } BufferWriter._configure = function () { /** * Allocates a buffer of the specified size. * @function * @param {number} size Buffer size * @returns {Buffer} Buffer */ BufferWriter.alloc = util$3._Buffer_allocUnsafe; BufferWriter.writeBytesBuffer = util$3.Buffer && util$3.Buffer.prototype instanceof Uint8Array && util$3.Buffer.prototype.set.name === "set" ? function writeBytesBuffer_set(val, buf, pos) { buf.set(val, pos); // faster than copy (requires node >= 4 where Buffers extend Uint8Array and set is properly inherited) // also works for plain array values } /* istanbul ignore next */ : function writeBytesBuffer_copy(val, buf, pos) { if (val.copy) // Buffer values val.copy(buf, pos, 0, val.length);else for (var i = 0; i < val.length;) // plain array values buf[pos++] = val[i++]; }; }; /** * @override */ BufferWriter.prototype.bytes = function write_bytes_buffer(value) { if (util$3.isString(value)) value = util$3._Buffer_from(value, "base64"); var len = value.length >>> 0; this.uint32(len); if (len) this._push(BufferWriter.writeBytesBuffer, len, value); return this; }; function writeStringBuffer(val, buf, pos) { if (val.length < 40) // plain js is faster for short strings (probably due to redundant assertions) util$3.utf8.write(val, buf, pos);else if (buf.utf8Write) buf.utf8Write(val, pos);else buf.write(val, pos); } /** * @override */ BufferWriter.prototype.string = function write_string_buffer(value) { var len = util$3.Buffer.byteLength(value); this.uint32(len); if (len) this._push(writeStringBuffer, len, value); return this; }; /** * Finishes the write operation. * @name BufferWriter#finish * @function * @returns {Buffer} Finished buffer */ BufferWriter._configure(); var reader = Reader$1; var util$2 = requireMinimal(); var BufferReader$1; // cyclic var LongBits = util$2.LongBits, utf8 = util$2.utf8; /* istanbul ignore next */ function indexOutOfRange(reader, writeLength) { return RangeError("index out of range: " + reader.pos + " + " + (writeLength || 1) + " > " + reader.len); } /** * Constructs a new reader instance using the specified buffer. * @classdesc Wire format reader using `Uint8Array` if available, otherwise `Array`. * @constructor * @param {Uint8Array} buffer Buffer to read from */ function Reader$1(buffer) { /** * Read buffer. * @type {Uint8Array} */ this.buf = buffer; /** * Read buffer position. * @type {number} */ this.pos = 0; /** * Read buffer length. * @type {number} */ this.len = buffer.length; } var create_array = typeof Uint8Array !== "undefined" ? function create_typed_array(buffer) { if (buffer instanceof Uint8Array || Array.isArray(buffer)) return new Reader$1(buffer); throw Error("illegal buffer"); } /* istanbul ignore next */ : function create_array(buffer) { if (Array.isArray(buffer)) return new Reader$1(buffer); throw Error("illegal buffer"); }; var create = function create() { return util$2.Buffer ? function create_buffer_setup(buffer) { return (Reader$1.create = function create_buffer(buffer) { return util$2.Buffer.isBuffer(buffer) ? new BufferReader$1(buffer) /* istanbul ignore next */ : create_array(buffer); })(buffer); } /* istanbul ignore next */ : create_array; }; /** * Creates a new reader using the specified buffer. * @function * @param {Uint8Array|Buffer} buffer Buffer to read from * @returns {Reader|BufferReader} A {@link BufferReader} if `buffer` is a Buffer, otherwise a {@link Reader} * @throws {Error} If `buffer` is not a valid buffer */ Reader$1.create = create(); Reader$1.prototype._slice = util$2.Array.prototype.subarray || /* istanbul ignore next */util$2.Array.prototype.slice; /** * Reads a varint as an unsigned 32 bit value. * @function * @returns {number} Value read */ Reader$1.prototype.uint32 = function read_uint32_setup() { var value = 4294967295; // optimizer type-hint, tends to deopt otherwise (?!) return function read_uint32() { value = (this.buf[this.pos] & 127) >>> 0; if (this.buf[this.pos++] < 128) return value; value = (value | (this.buf[this.pos] & 127) << 7) >>> 0; if (this.buf[this.pos++] < 128) return value; value = (value | (this.buf[this.pos] & 127) << 14) >>> 0; if (this.buf[this.pos++] < 128) return value; value = (value | (this.buf[this.pos] & 127) << 21) >>> 0; if (this.buf[this.pos++] < 128) return value; value = (value | (this.buf[this.pos] & 15) << 28) >>> 0; if (this.buf[this.pos++] < 128) return value; /* istanbul ignore if */ if ((this.pos += 5) > this.len) { this.pos = this.len; throw indexOutOfRange(this, 10); } return value; }; }(); /** * Reads a varint as a signed 32 bit value. * @returns {number} Value read */ Reader$1.prototype.int32 = function read_int32() { return this.uint32() | 0; }; /** * Reads a zig-zag encoded varint as a signed 32 bit value. * @returns {number} Value read */ Reader$1.prototype.sint32 = function read_sint32() { var value = this.uint32(); return value >>> 1 ^ -(value & 1) | 0; }; /* eslint-disable no-invalid-this */ function readLongVarint() { // tends to deopt with local vars for octet etc. var bits = new LongBits(0, 0); var i = 0; if (this.len - this.pos > 4) { // fast route (lo) for (; i < 4; ++i) { // 1st..4th bits.lo = (bits.lo | (this.buf[this.pos] & 127) << i * 7) >>> 0; if (this.buf[this.pos++] < 128) return bits; } // 5th bits.lo = (bits.lo | (this.buf[this.pos] & 127) << 28) >>> 0; bits.hi = (bits.hi | (this.buf[this.pos] & 127) >> 4) >>> 0; if (this.buf[this.pos++] < 128) return bits; i = 0; } else { for (; i < 3; ++i) { /* istanbul ignore if */ if (this.pos >= this.len) throw indexOutOfRange(this); // 1st..3th bits.lo = (bits.lo | (this.buf[this.pos] & 127) << i * 7) >>> 0; if (this.buf[this.pos++] < 128) return bits; } // 4th bits.lo = (bits.lo | (this.buf[this.pos++] & 127) << i * 7) >>> 0; return bits; } if (this.len - this.pos > 4) { // fast route (hi) for (; i < 5; ++i) { // 6th..10th bits.hi = (bits.hi | (this.buf[this.pos] & 127) << i * 7 + 3) >>> 0; if (this.buf[this.pos++] < 128) return bits; } } else { for (; i < 5; ++i) { /* istanbul ignore if */ if (this.pos >= this.len) throw indexOutOfRange(this); // 6th..10th bits.hi = (bits.hi | (this.buf[this.pos] & 127) << i * 7 + 3) >>> 0; if (this.buf[this.pos++] < 128) return bits; } } /* istanbul ignore next */ throw Error("invalid varint encoding"); } /* eslint-enable no-invalid-this */ /** * Reads a varint as a signed 64 bit value. * @name Reader#int64 * @function * @returns {Long} Value read */ /** * Reads a varint as an unsigned 64 bit value. * @name Reader#uint64 * @function * @returns {Long} Value read */ /** * Reads a zig-zag encoded varint as a signed 64 bit value. * @name Reader#sint64 * @function * @returns {Long} Value read */ /** * Reads a varint as a boolean. * @returns {boolean} Value read */ Reader$1.prototype.bool = function read_bool() { return this.uint32() !== 0; }; function readFixed32_end(buf, end) { // note that this uses `end`, not `pos` return (buf[end - 4] | buf[end - 3] << 8 | buf[end - 2] << 16 | buf[end - 1] << 24) >>> 0; } /** * Reads fixed 32 bits as an unsigned 32 bit integer. * @returns {number} Value read */ Reader$1.prototype.fixed32 = function read_fixed32() { /* istanbul ignore if */ if (this.pos + 4 > this.len) throw indexOutOfRange(this, 4); return readFixed32_end(this.buf, this.pos += 4); }; /** * Reads fixed 32 bits as a signed 32 bit integer. * @returns {number} Value read */ Reader$1.prototype.sfixed32 = function read_sfixed32() { /* istanbul ignore if */ if (this.pos + 4 > this.len) throw indexOutOfRange(this, 4); return readFixed32_end(this.buf, this.pos += 4) | 0; }; /* eslint-disable no-invalid-this */ function readFixed64( /* this: Reader */ ) { /* istanbul ignore if */ if (this.pos + 8 > this.len) throw indexOutOfRange(this, 8); return new LongBits(readFixed32_end(this.buf, this.pos += 4), readFixed32_end(this.buf, this.pos += 4)); } /* eslint-enable no-invalid-this */ /** * Reads fixed 64 bits. * @name Reader#fixed64 * @function * @returns {Long} Value read */ /** * Reads zig-zag encoded fixed 64 bits. * @name Reader#sfixed64 * @function * @returns {Long} Value read */ /** * Reads a float (32 bit) as a number. * @function * @returns {number} Value read */ Reader$1.prototype.float = function read_float() { /* istanbul ignore if */ if (this.pos + 4 > this.len) throw indexOutOfRange(this, 4); var value = util$2.float.readFloatLE(this.buf, this.pos); this.pos += 4; return value; }; /** * Reads a double (64 bit float) as a number. * @function * @returns {number} Value read */ Reader$1.prototype.double = function read_double() { /* istanbul ignore if */ if (this.pos + 8 > this.len) throw indexOutOfRange(this, 4); var value = util$2.float.readDoubleLE(this.buf, this.pos); this.pos += 8; return value; }; /** * Reads a sequence of bytes preceeded by its length as a varint. * @returns {Uint8Array} Value read */ Reader$1.prototype.bytes = function read_bytes() { var length = this.uint32(), start = this.pos, end = this.pos + length; /* istanbul ignore if */ if (end > this.len) throw indexOutOfRange(this, length); this.pos += length; if (Array.isArray(this.buf)) // plain array return this.buf.slice(start, end); return start === end // fix for IE 10/Win8 and others' subarray returning array of size 1 ? new this.buf.constructor(0) : this._slice.call(this.buf, start, end); }; /** * Reads a string preceeded by its byte length as a varint. * @returns {string} Value read */ Reader$1.prototype.string = function read_string() { var bytes = this.bytes(); return utf8.read(bytes, 0, bytes.length); }; /** * Skips the specified number of bytes if specified, otherwise skips a varint. * @param {number} [length] Length if known, otherwise a varint is assumed * @returns {Reader} `this` */ Reader$1.prototype.skip = function skip(length) { if (typeof length === "number") { /* istanbul ignore if */ if (this.pos + length > this.len) throw indexOutOfRange(this, length); this.pos += length; } else { do { /* istanbul ignore if */ if (this.pos >= this.len) throw indexOutOfRange(this); } while (this.buf[this.pos++] & 128); } return this; }; /** * Skips the next element of the specified wire type. * @param {number} wireType Wire type received * @returns {Reader} `this` */ Reader$1.prototype.skipType = function (wireType) { switch (wireType) { case 0: this.skip(); break; case 1: this.skip(8); break; case 2: this.skip(this.uint32()); break; case 3: while ((wireType = this.uint32() & 7) !== 4) { this.skipType(wireType); } break; case 5: this.skip(4); break; /* istanbul ignore next */ default: throw Error("invalid wire type " + wireType + " at offset " + this.pos); } return this; }; Reader$1._configure = function (BufferReader_) { BufferReader$1 = BufferReader_; Reader$1.create = create(); BufferReader$1._configure(); var fn = util$2.Long ? "toLong" : /* istanbul ignore next */"toNumber"; util$2.merge(Reader$1.prototype, { int64: function read_int64() { return readLongVarint.call(this)[fn](false); }, uint64: function read_uint64() { return readLongVarint.call(this)[fn](true); }, sint64: function read_sint64() { return readLongVarint.call(this).zzDecode()[fn](false); }, fixed64: function read_fixed64() { return readFixed64.call(this)[fn](true); }, sfixed64: function read_sfixed64() { return readFixed64.call(this)[fn](false); } }); }; var reader_buffer = BufferReader; // extends Reader var Reader = reader; (BufferReader.prototype = Object.create(Reader.prototype)).constructor = BufferReader; var util$1 = requireMinimal(); /** * Constructs a new buffer reader instance. * @classdesc Wire format reader using node buffers. * @extends Reader * @constructor * @param {Buffer} buffer Buffer to read from */ function BufferReader(buffer) { Reader.call(this, buffer); /** * Read buffer. * @name BufferReader#buf * @type {Buffer} */ } BufferReader._configure = function () { /* istanbul ignore else */ if (util$1.Buffer) BufferReader.prototype._slice = util$1.Buffer.prototype.slice; }; /** * @override */ BufferReader.prototype.string = function read_string_buffer() { var len = this.uint32(); // modifies pos return this.buf.utf8Slice ? this.buf.utf8Slice(this.pos, this.pos = Math.min(this.pos + len, this.len)) : this.buf.toString("utf-8", this.pos, this.pos = Math.min(this.pos + len, this.len)); }; /** * Reads a sequence of bytes preceeded by its length as a varint. * @name BufferReader#bytes * @function * @returns {Buffer} Value read */ BufferReader._configure(); var rpc = {}; var service = Service; var util = requireMinimal(); // Extends EventEmitter (Service.prototype = Object.create(util.EventEmitter.prototype)).constructor = Service; /** * A service method callback as used by {@link rpc.ServiceMethod|ServiceMethod}. * * Differs from {@link RPCImplCallback} in that it is an actual callback of a service method which may not return `response = null`. * @typedef rpc.ServiceMethodCallback * @template TRes extends Message * @type {function} * @param {Error|null} error Error, if any * @param {TRes} [response] Response message * @returns {undefined} */ /** * A service method part of a {@link rpc.Service} as created by {@link Service.create}. * @typedef rpc.ServiceMethod * @template TReq extends Message * @template TRes extends Message * @type {function} * @param {TReq|Properties} request Request message or plain object * @param {rpc.ServiceMethodCallback} [callback] Node-style callback called with the error, if any, and the response message * @returns {Promise>} Promise if `callback` has been omitted, otherwise `undefined` */ /** * Constructs a new RPC service instance. * @classdesc An RPC service as returned by {@link Service#create}. * @exports rpc.Service * @extends util.EventEmitter * @constructor * @param {RPCImpl} rpcImpl RPC implementation * @param {boolean} [requestDelimited=false] Whether requests are length-delimited * @param {boolean} [responseDelimited=false] Whether responses are length-delimited */ function Service(rpcImpl, requestDelimited, responseDelimited) { if (typeof rpcImpl !== "function") throw TypeError("rpcImpl must be a function"); util.EventEmitter.call(this); /** * RPC implementation. Becomes `null` once the service is ended. * @type {RPCImpl|null} */ this.rpcImpl = rpcImpl; /** * Whether requests are length-delimited. * @type {boolean} */ this.requestDelimited = Boolean(requestDelimited); /** * Whether responses are length-delimited. * @type {boolean} */ this.responseDelimited = Boolean(responseDelimited); } /** * Calls a service method through {@link rpc.Service#rpcImpl|rpcImpl}. * @param {Method|rpc.ServiceMethod} method Reflected or static method * @param {Constructor} requestCtor Request constructor * @param {Constructor} responseCtor Response constructor * @param {TReq|Properties} request Request message or plain object * @param {rpc.ServiceMethodCallback} callback Service callback * @returns {undefined} * @template TReq extends Message * @template TRes extends Message */ Service.prototype.rpcCall = function rpcCall(method, requestCtor, responseCtor, request, callback) { if (!request) throw TypeError("request must be specified"); var self = this; if (!callback) return util.asPromise(rpcCall, self, method, requestCtor, responseCtor, request); if (!self.rpcImpl) { setTimeout(function () { callback(Error("already ended")); }, 0); return undefined; } try { return self.rpcImpl(method, requestCtor[self.requestDelimited ? "encodeDelimited" : "encode"](request).finish(), function rpcCallback(err, response) { if (err) { self.emit("error", err, method); return callback(err); } if (response === null) { self.end( /* endedByRPC */true); return undefined; } if (!(response instanceof responseCtor)) { try { response = responseCtor[self.responseDelimited ? "decodeDelimited" : "decode"](response); } catch (err) { self.emit("error", err, method); return callback(err); } } self.emit("data", response, method); return callback(null, response); }); } catch (err) { self.emit("error", err, method); setTimeout(function () { callback(err); }, 0); return undefined; } }; /** * Ends this service and emits the `end` event. * @param {boolean} [endedByRPC=false] Whether the service has been ended by the RPC implementation. * @returns {rpc.Service} `this` */ Service.prototype.end = function end(endedByRPC) { if (this.rpcImpl) { if (!endedByRPC) // signal end to rpcImpl this.rpcImpl(null, null, null); this.rpcImpl = null; this.emit("end").off(); } return this; }; (function (exports) { /** * Streaming RPC helpers. * @namespace */ var rpc = exports; /** * RPC implementation passed to {@link Service#create} performing a service request on network level, i.e. by utilizing http requests or websockets. * @typedef RPCImpl * @type {function} * @param {Method|rpc.ServiceMethod,Message<{}>>} method Reflected or static method being called * @param {Uint8Array} requestData Request data * @param {RPCImplCallback} callback Callback function * @returns {undefined} * @example * function rpcImpl(method, requestData, callback) { * if (protobuf.util.lcFirst(method.name) !== "myMethod") // compatible with static code * throw Error("no such method"); * asynchronouslyObtainAResponse(requestData, function(err, responseData) { * callback(err, responseData); * }); * } */ /** * Node-style callback as used by {@link RPCImpl}. * @typedef RPCImplCallback * @type {function} * @param {Error|null} error Error, if any, otherwise `null` * @param {Uint8Array|null} [response] Response data or `null` to signal end of stream, if there hasn't been an error * @returns {undefined} */ rpc.Service = service; })(rpc); var roots = {}; (function (exports) { var protobuf = exports; /** * Build type, one of `"full"`, `"light"` or `"minimal"`. * @name build * @type {string} * @const */ protobuf.build = "minimal"; // Serialization protobuf.Writer = writer$2; protobuf.BufferWriter = writer_buffer; protobuf.Reader = reader; protobuf.BufferReader = reader_buffer; // Utility protobuf.util = requireMinimal(); protobuf.rpc = rpc; protobuf.roots = roots; protobuf.configure = configure; /* istanbul ignore next */ /** * Reconfigures the library according to the environment. * @returns {undefined} */ function configure() { protobuf.util._configure(); protobuf.Writer._configure(protobuf.BufferWriter); protobuf.Reader._configure(protobuf.BufferReader); } // Set up buffer utility according to the environment configure(); })(indexMinimal); (function (module) { module.exports = indexMinimal; })(minimal$1); var _m0 = /*@__PURE__*/getDefaultExportFromCjs(minimalExports); /* eslint-disable */ (() => { if (typeof globalThis !== "undefined") { return globalThis; } if (typeof self !== "undefined") { return self; } if (typeof window !== "undefined") { return window; } if (typeof global !== "undefined") { return global; } throw "Unable to locate global object"; })(); if (_m0.util.Long !== Long) { _m0.util.Long = Long; _m0.configure(); } /* eslint-disable */ var TrackType; (function (TrackType) { TrackType[TrackType["AUDIO"] = 0] = "AUDIO"; TrackType[TrackType["VIDEO"] = 1] = "VIDEO"; TrackType[TrackType["DATA"] = 2] = "DATA"; TrackType[TrackType["UNRECOGNIZED"] = -1] = "UNRECOGNIZED"; })(TrackType || (TrackType = {})); function trackTypeFromJSON(object) { switch (object) { case 0: case "AUDIO": return TrackType.AUDIO; case 1: case "VIDEO": return TrackType.VIDEO; case 2: case "DATA": return TrackType.DATA; case -1: case "UNRECOGNIZED": default: return TrackType.UNRECOGNIZED; } } function trackTypeToJSON(object) { switch (object) { case TrackType.AUDIO: return "AUDIO"; case TrackType.VIDEO: return "VIDEO"; case TrackType.DATA: return "DATA"; case TrackType.UNRECOGNIZED: default: return "UNRECOGNIZED"; } } var TrackSource; (function (TrackSource) { TrackSource[TrackSource["UNKNOWN"] = 0] = "UNKNOWN"; TrackSource[TrackSource["CAMERA"] = 1] = "CAMERA"; TrackSource[TrackSource["MICROPHONE"] = 2] = "MICROPHONE"; TrackSource[TrackSource["SCREEN_SHARE"] = 3] = "SCREEN_SHARE"; TrackSource[TrackSource["SCREEN_SHARE_AUDIO"] = 4] = "SCREEN_SHARE_AUDIO"; TrackSource[TrackSource["UNRECOGNIZED"] = -1] = "UNRECOGNIZED"; })(TrackSource || (TrackSource = {})); function trackSourceFromJSON(object) { switch (object) { case 0: case "UNKNOWN": return TrackSource.UNKNOWN; case 1: case "CAMERA": return TrackSource.CAMERA; case 2: case "MICROPHONE": return TrackSource.MICROPHONE; case 3: case "SCREEN_SHARE": return TrackSource.SCREEN_SHARE; case 4: case "SCREEN_SHARE_AUDIO": return TrackSource.SCREEN_SHARE_AUDIO; case -1: case "UNRECOGNIZED": default: return TrackSource.UNRECOGNIZED; } } function trackSourceToJSON(object) { switch (object) { case TrackSource.UNKNOWN: return "UNKNOWN"; case TrackSource.CAMERA: return "CAMERA"; case TrackSource.MICROPHONE: return "MICROPHONE"; case TrackSource.SCREEN_SHARE: return "SCREEN_SHARE"; case TrackSource.SCREEN_SHARE_AUDIO: return "SCREEN_SHARE_AUDIO"; case TrackSource.UNRECOGNIZED: default: return "UNRECOGNIZED"; } } var VideoQuality; (function (VideoQuality) { VideoQuality[VideoQuality["LOW"] = 0] = "LOW"; VideoQuality[VideoQuality["MEDIUM"] = 1] = "MEDIUM"; VideoQuality[VideoQuality["HIGH"] = 2] = "HIGH"; VideoQuality[VideoQuality["OFF"] = 3] = "OFF"; VideoQuality[VideoQuality["UNRECOGNIZED"] = -1] = "UNRECOGNIZED"; })(VideoQuality || (VideoQuality = {})); function videoQualityFromJSON(object) { switch (object) { case 0: case "LOW": return VideoQuality.LOW; case 1: case "MEDIUM": return VideoQuality.MEDIUM; case 2: case "HIGH": return VideoQuality.HIGH; case 3: case "OFF": return VideoQuality.OFF; case -1: case "UNRECOGNIZED": default: return VideoQuality.UNRECOGNIZED; } } function videoQualityToJSON(object) { switch (object) { case VideoQuality.LOW: return "LOW"; case VideoQuality.MEDIUM: return "MEDIUM"; case VideoQuality.HIGH: return "HIGH"; case VideoQuality.OFF: return "OFF"; case VideoQuality.UNRECOGNIZED: default: return "UNRECOGNIZED"; } } var ConnectionQuality$1; (function (ConnectionQuality) { ConnectionQuality[ConnectionQuality["POOR"] = 0] = "POOR"; ConnectionQuality[ConnectionQuality["GOOD"] = 1] = "GOOD"; ConnectionQuality[ConnectionQuality["EXCELLENT"] = 2] = "EXCELLENT"; ConnectionQuality[ConnectionQuality["UNRECOGNIZED"] = -1] = "UNRECOGNIZED"; })(ConnectionQuality$1 || (ConnectionQuality$1 = {})); function connectionQualityFromJSON(object) { switch (object) { case 0: case "POOR": return ConnectionQuality$1.POOR; case 1: case "GOOD": return ConnectionQuality$1.GOOD; case 2: case "EXCELLENT": return ConnectionQuality$1.EXCELLENT; case -1: case "UNRECOGNIZED": default: return ConnectionQuality$1.UNRECOGNIZED; } } function connectionQualityToJSON(object) { switch (object) { case ConnectionQuality$1.POOR: return "POOR"; case ConnectionQuality$1.GOOD: return "GOOD"; case ConnectionQuality$1.EXCELLENT: return "EXCELLENT"; case ConnectionQuality$1.UNRECOGNIZED: default: return "UNRECOGNIZED"; } } var ClientConfigSetting; (function (ClientConfigSetting) { ClientConfigSetting[ClientConfigSetting["UNSET"] = 0] = "UNSET"; ClientConfigSetting[ClientConfigSetting["DISABLED"] = 1] = "DISABLED"; ClientConfigSetting[ClientConfigSetting["ENABLED"] = 2] = "ENABLED"; ClientConfigSetting[ClientConfigSetting["UNRECOGNIZED"] = -1] = "UNRECOGNIZED"; })(ClientConfigSetting || (ClientConfigSetting = {})); function clientConfigSettingFromJSON(object) { switch (object) { case 0: case "UNSET": return ClientConfigSetting.UNSET; case 1: case "DISABLED": return ClientConfigSetting.DISABLED; case 2: case "ENABLED": return ClientConfigSetting.ENABLED; case -1: case "UNRECOGNIZED": default: return ClientConfigSetting.UNRECOGNIZED; } } function clientConfigSettingToJSON(object) { switch (object) { case ClientConfigSetting.UNSET: return "UNSET"; case ClientConfigSetting.DISABLED: return "DISABLED"; case ClientConfigSetting.ENABLED: return "ENABLED"; case ClientConfigSetting.UNRECOGNIZED: default: return "UNRECOGNIZED"; } } var DisconnectReason; (function (DisconnectReason) { DisconnectReason[DisconnectReason["UNKNOWN_REASON"] = 0] = "UNKNOWN_REASON"; DisconnectReason[DisconnectReason["CLIENT_INITIATED"] = 1] = "CLIENT_INITIATED"; DisconnectReason[DisconnectReason["DUPLICATE_IDENTITY"] = 2] = "DUPLICATE_IDENTITY"; DisconnectReason[DisconnectReason["SERVER_SHUTDOWN"] = 3] = "SERVER_SHUTDOWN"; DisconnectReason[DisconnectReason["PARTICIPANT_REMOVED"] = 4] = "PARTICIPANT_REMOVED"; DisconnectReason[DisconnectReason["ROOM_DELETED"] = 5] = "ROOM_DELETED"; DisconnectReason[DisconnectReason["STATE_MISMATCH"] = 6] = "STATE_MISMATCH"; DisconnectReason[DisconnectReason["JOIN_FAILURE"] = 7] = "JOIN_FAILURE"; DisconnectReason[DisconnectReason["UNRECOGNIZED"] = -1] = "UNRECOGNIZED"; })(DisconnectReason || (DisconnectReason = {})); function disconnectReasonFromJSON(object) { switch (object) { case 0: case "UNKNOWN_REASON": return DisconnectReason.UNKNOWN_REASON; case 1: case "CLIENT_INITIATED": return DisconnectReason.CLIENT_INITIATED; case 2: case "DUPLICATE_IDENTITY": return DisconnectReason.DUPLICATE_IDENTITY; case 3: case "SERVER_SHUTDOWN": return DisconnectReason.SERVER_SHUTDOWN; case 4: case "PARTICIPANT_REMOVED": return DisconnectReason.PARTICIPANT_REMOVED; case 5: case "ROOM_DELETED": return DisconnectReason.ROOM_DELETED; case 6: case "STATE_MISMATCH": return DisconnectReason.STATE_MISMATCH; case 7: case "JOIN_FAILURE": return DisconnectReason.JOIN_FAILURE; case -1: case "UNRECOGNIZED": default: return DisconnectReason.UNRECOGNIZED; } } function disconnectReasonToJSON(object) { switch (object) { case DisconnectReason.UNKNOWN_REASON: return "UNKNOWN_REASON"; case DisconnectReason.CLIENT_INITIATED: return "CLIENT_INITIATED"; case DisconnectReason.DUPLICATE_IDENTITY: return "DUPLICATE_IDENTITY"; case DisconnectReason.SERVER_SHUTDOWN: return "SERVER_SHUTDOWN"; case DisconnectReason.PARTICIPANT_REMOVED: return "PARTICIPANT_REMOVED"; case DisconnectReason.ROOM_DELETED: return "ROOM_DELETED"; case DisconnectReason.STATE_MISMATCH: return "STATE_MISMATCH"; case DisconnectReason.JOIN_FAILURE: return "JOIN_FAILURE"; case DisconnectReason.UNRECOGNIZED: default: return "UNRECOGNIZED"; } } var ReconnectReason; (function (ReconnectReason) { ReconnectReason[ReconnectReason["RR_UNKOWN"] = 0] = "RR_UNKOWN"; ReconnectReason[ReconnectReason["RR_SIGNAL_DISCONNECTED"] = 1] = "RR_SIGNAL_DISCONNECTED"; ReconnectReason[ReconnectReason["RR_PUBLISHER_FAILED"] = 2] = "RR_PUBLISHER_FAILED"; ReconnectReason[ReconnectReason["RR_SUBSCRIBER_FAILED"] = 3] = "RR_SUBSCRIBER_FAILED"; ReconnectReason[ReconnectReason["RR_SWITCH_CANDIDATE"] = 4] = "RR_SWITCH_CANDIDATE"; ReconnectReason[ReconnectReason["UNRECOGNIZED"] = -1] = "UNRECOGNIZED"; })(ReconnectReason || (ReconnectReason = {})); var ParticipantInfo_State; (function (ParticipantInfo_State) { /** JOINING - websocket' connected, but not offered yet */ ParticipantInfo_State[ParticipantInfo_State["JOINING"] = 0] = "JOINING"; /** JOINED - server received client offer */ ParticipantInfo_State[ParticipantInfo_State["JOINED"] = 1] = "JOINED"; /** ACTIVE - ICE connectivity established */ ParticipantInfo_State[ParticipantInfo_State["ACTIVE"] = 2] = "ACTIVE"; /** DISCONNECTED - WS disconnected */ ParticipantInfo_State[ParticipantInfo_State["DISCONNECTED"] = 3] = "DISCONNECTED"; ParticipantInfo_State[ParticipantInfo_State["UNRECOGNIZED"] = -1] = "UNRECOGNIZED"; })(ParticipantInfo_State || (ParticipantInfo_State = {})); function participantInfo_StateFromJSON(object) { switch (object) { case 0: case "JOINING": return ParticipantInfo_State.JOINING; case 1: case "JOINED": return ParticipantInfo_State.JOINED; case 2: case "ACTIVE": return ParticipantInfo_State.ACTIVE; case 3: case "DISCONNECTED": return ParticipantInfo_State.DISCONNECTED; case -1: case "UNRECOGNIZED": default: return ParticipantInfo_State.UNRECOGNIZED; } } function participantInfo_StateToJSON(object) { switch (object) { case ParticipantInfo_State.JOINING: return "JOINING"; case ParticipantInfo_State.JOINED: return "JOINED"; case ParticipantInfo_State.ACTIVE: return "ACTIVE"; case ParticipantInfo_State.DISCONNECTED: return "DISCONNECTED"; case ParticipantInfo_State.UNRECOGNIZED: default: return "UNRECOGNIZED"; } } var Encryption_Type; (function (Encryption_Type) { Encryption_Type[Encryption_Type["NONE"] = 0] = "NONE"; Encryption_Type[Encryption_Type["GCM"] = 1] = "GCM"; Encryption_Type[Encryption_Type["CUSTOM"] = 2] = "CUSTOM"; Encryption_Type[Encryption_Type["UNRECOGNIZED"] = -1] = "UNRECOGNIZED"; })(Encryption_Type || (Encryption_Type = {})); function encryption_TypeFromJSON(object) { switch (object) { case 0: case "NONE": return Encryption_Type.NONE; case 1: case "GCM": return Encryption_Type.GCM; case 2: case "CUSTOM": return Encryption_Type.CUSTOM; case -1: case "UNRECOGNIZED": default: return Encryption_Type.UNRECOGNIZED; } } function encryption_TypeToJSON(object) { switch (object) { case Encryption_Type.NONE: return "NONE"; case Encryption_Type.GCM: return "GCM"; case Encryption_Type.CUSTOM: return "CUSTOM"; case Encryption_Type.UNRECOGNIZED: default: return "UNRECOGNIZED"; } } var DataPacket_Kind; (function (DataPacket_Kind) { DataPacket_Kind[DataPacket_Kind["RELIABLE"] = 0] = "RELIABLE"; DataPacket_Kind[DataPacket_Kind["LOSSY"] = 1] = "LOSSY"; DataPacket_Kind[DataPacket_Kind["UNRECOGNIZED"] = -1] = "UNRECOGNIZED"; })(DataPacket_Kind || (DataPacket_Kind = {})); function dataPacket_KindFromJSON(object) { switch (object) { case 0: case "RELIABLE": return DataPacket_Kind.RELIABLE; case 1: case "LOSSY": return DataPacket_Kind.LOSSY; case -1: case "UNRECOGNIZED": default: return DataPacket_Kind.UNRECOGNIZED; } } function dataPacket_KindToJSON(object) { switch (object) { case DataPacket_Kind.RELIABLE: return "RELIABLE"; case DataPacket_Kind.LOSSY: return "LOSSY"; case DataPacket_Kind.UNRECOGNIZED: default: return "UNRECOGNIZED"; } } var ServerInfo_Edition; (function (ServerInfo_Edition) { ServerInfo_Edition[ServerInfo_Edition["Standard"] = 0] = "Standard"; ServerInfo_Edition[ServerInfo_Edition["Cloud"] = 1] = "Cloud"; ServerInfo_Edition[ServerInfo_Edition["UNRECOGNIZED"] = -1] = "UNRECOGNIZED"; })(ServerInfo_Edition || (ServerInfo_Edition = {})); function serverInfo_EditionFromJSON(object) { switch (object) { case 0: case "Standard": return ServerInfo_Edition.Standard; case 1: case "Cloud": return ServerInfo_Edition.Cloud; case -1: case "UNRECOGNIZED": default: return ServerInfo_Edition.UNRECOGNIZED; } } function serverInfo_EditionToJSON(object) { switch (object) { case ServerInfo_Edition.Standard: return "Standard"; case ServerInfo_Edition.Cloud: return "Cloud"; case ServerInfo_Edition.UNRECOGNIZED: default: return "UNRECOGNIZED"; } } var ClientInfo_SDK; (function (ClientInfo_SDK) { ClientInfo_SDK[ClientInfo_SDK["UNKNOWN"] = 0] = "UNKNOWN"; ClientInfo_SDK[ClientInfo_SDK["JS"] = 1] = "JS"; ClientInfo_SDK[ClientInfo_SDK["SWIFT"] = 2] = "SWIFT"; ClientInfo_SDK[ClientInfo_SDK["ANDROID"] = 3] = "ANDROID"; ClientInfo_SDK[ClientInfo_SDK["FLUTTER"] = 4] = "FLUTTER"; ClientInfo_SDK[ClientInfo_SDK["GO"] = 5] = "GO"; ClientInfo_SDK[ClientInfo_SDK["UNITY"] = 6] = "UNITY"; ClientInfo_SDK[ClientInfo_SDK["UNRECOGNIZED"] = -1] = "UNRECOGNIZED"; })(ClientInfo_SDK || (ClientInfo_SDK = {})); function clientInfo_SDKFromJSON(object) { switch (object) { case 0: case "UNKNOWN": return ClientInfo_SDK.UNKNOWN; case 1: case "JS": return ClientInfo_SDK.JS; case 2: case "SWIFT": return ClientInfo_SDK.SWIFT; case 3: case "ANDROID": return ClientInfo_SDK.ANDROID; case 4: case "FLUTTER": return ClientInfo_SDK.FLUTTER; case 5: case "GO": return ClientInfo_SDK.GO; case 6: case "UNITY": return ClientInfo_SDK.UNITY; case -1: case "UNRECOGNIZED": default: return ClientInfo_SDK.UNRECOGNIZED; } } function clientInfo_SDKToJSON(object) { switch (object) { case ClientInfo_SDK.UNKNOWN: return "UNKNOWN"; case ClientInfo_SDK.JS: return "JS"; case ClientInfo_SDK.SWIFT: return "SWIFT"; case ClientInfo_SDK.ANDROID: return "ANDROID"; case ClientInfo_SDK.FLUTTER: return "FLUTTER"; case ClientInfo_SDK.GO: return "GO"; case ClientInfo_SDK.UNITY: return "UNITY"; case ClientInfo_SDK.UNRECOGNIZED: default: return "UNRECOGNIZED"; } } function createBaseRoom() { return { sid: "", name: "", emptyTimeout: 0, maxParticipants: 0, creationTime: 0, turnPassword: "", enabledCodecs: [], metadata: "", numParticipants: 0, activeRecording: false }; } const Room$1 = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.sid !== "") { writer.uint32(10).string(message.sid); } if (message.name !== "") { writer.uint32(18).string(message.name); } if (message.emptyTimeout !== 0) { writer.uint32(24).uint32(message.emptyTimeout); } if (message.maxParticipants !== 0) { writer.uint32(32).uint32(message.maxParticipants); } if (message.creationTime !== 0) { writer.uint32(40).int64(message.creationTime); } if (message.turnPassword !== "") { writer.uint32(50).string(message.turnPassword); } for (const v of message.enabledCodecs) { Codec.encode(v, writer.uint32(58).fork()).ldelim(); } if (message.metadata !== "") { writer.uint32(66).string(message.metadata); } if (message.numParticipants !== 0) { writer.uint32(72).uint32(message.numParticipants); } if (message.activeRecording === true) { writer.uint32(80).bool(message.activeRecording); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseRoom(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.sid = reader.string(); break; case 2: message.name = reader.string(); break; case 3: message.emptyTimeout = reader.uint32(); break; case 4: message.maxParticipants = reader.uint32(); break; case 5: message.creationTime = longToNumber$1(reader.int64()); break; case 6: message.turnPassword = reader.string(); break; case 7: message.enabledCodecs.push(Codec.decode(reader, reader.uint32())); break; case 8: message.metadata = reader.string(); break; case 9: message.numParticipants = reader.uint32(); break; case 10: message.activeRecording = reader.bool(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { sid: isSet$1(object.sid) ? String(object.sid) : "", name: isSet$1(object.name) ? String(object.name) : "", emptyTimeout: isSet$1(object.emptyTimeout) ? Number(object.emptyTimeout) : 0, maxParticipants: isSet$1(object.maxParticipants) ? Number(object.maxParticipants) : 0, creationTime: isSet$1(object.creationTime) ? Number(object.creationTime) : 0, turnPassword: isSet$1(object.turnPassword) ? String(object.turnPassword) : "", enabledCodecs: Array.isArray(object === null || object === void 0 ? void 0 : object.enabledCodecs) ? object.enabledCodecs.map(e => Codec.fromJSON(e)) : [], metadata: isSet$1(object.metadata) ? String(object.metadata) : "", numParticipants: isSet$1(object.numParticipants) ? Number(object.numParticipants) : 0, activeRecording: isSet$1(object.activeRecording) ? Boolean(object.activeRecording) : false }; }, toJSON(message) { const obj = {}; message.sid !== undefined && (obj.sid = message.sid); message.name !== undefined && (obj.name = message.name); message.emptyTimeout !== undefined && (obj.emptyTimeout = Math.round(message.emptyTimeout)); message.maxParticipants !== undefined && (obj.maxParticipants = Math.round(message.maxParticipants)); message.creationTime !== undefined && (obj.creationTime = Math.round(message.creationTime)); message.turnPassword !== undefined && (obj.turnPassword = message.turnPassword); if (message.enabledCodecs) { obj.enabledCodecs = message.enabledCodecs.map(e => e ? Codec.toJSON(e) : undefined); } else { obj.enabledCodecs = []; } message.metadata !== undefined && (obj.metadata = message.metadata); message.numParticipants !== undefined && (obj.numParticipants = Math.round(message.numParticipants)); message.activeRecording !== undefined && (obj.activeRecording = message.activeRecording); return obj; }, create(base) { return Room$1.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; const message = createBaseRoom(); message.sid = (_a = object.sid) !== null && _a !== void 0 ? _a : ""; message.name = (_b = object.name) !== null && _b !== void 0 ? _b : ""; message.emptyTimeout = (_c = object.emptyTimeout) !== null && _c !== void 0 ? _c : 0; message.maxParticipants = (_d = object.maxParticipants) !== null && _d !== void 0 ? _d : 0; message.creationTime = (_e = object.creationTime) !== null && _e !== void 0 ? _e : 0; message.turnPassword = (_f = object.turnPassword) !== null && _f !== void 0 ? _f : ""; message.enabledCodecs = ((_g = object.enabledCodecs) === null || _g === void 0 ? void 0 : _g.map(e => Codec.fromPartial(e))) || []; message.metadata = (_h = object.metadata) !== null && _h !== void 0 ? _h : ""; message.numParticipants = (_j = object.numParticipants) !== null && _j !== void 0 ? _j : 0; message.activeRecording = (_k = object.activeRecording) !== null && _k !== void 0 ? _k : false; return message; } }; function createBaseCodec() { return { mime: "", fmtpLine: "" }; } const Codec = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.mime !== "") { writer.uint32(10).string(message.mime); } if (message.fmtpLine !== "") { writer.uint32(18).string(message.fmtpLine); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseCodec(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.mime = reader.string(); break; case 2: message.fmtpLine = reader.string(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { mime: isSet$1(object.mime) ? String(object.mime) : "", fmtpLine: isSet$1(object.fmtpLine) ? String(object.fmtpLine) : "" }; }, toJSON(message) { const obj = {}; message.mime !== undefined && (obj.mime = message.mime); message.fmtpLine !== undefined && (obj.fmtpLine = message.fmtpLine); return obj; }, create(base) { return Codec.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b; const message = createBaseCodec(); message.mime = (_a = object.mime) !== null && _a !== void 0 ? _a : ""; message.fmtpLine = (_b = object.fmtpLine) !== null && _b !== void 0 ? _b : ""; return message; } }; function createBaseParticipantPermission() { return { canSubscribe: false, canPublish: false, canPublishData: false, canPublishSources: [], hidden: false, recorder: false }; } const ParticipantPermission = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.canSubscribe === true) { writer.uint32(8).bool(message.canSubscribe); } if (message.canPublish === true) { writer.uint32(16).bool(message.canPublish); } if (message.canPublishData === true) { writer.uint32(24).bool(message.canPublishData); } writer.uint32(74).fork(); for (const v of message.canPublishSources) { writer.int32(v); } writer.ldelim(); if (message.hidden === true) { writer.uint32(56).bool(message.hidden); } if (message.recorder === true) { writer.uint32(64).bool(message.recorder); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseParticipantPermission(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.canSubscribe = reader.bool(); break; case 2: message.canPublish = reader.bool(); break; case 3: message.canPublishData = reader.bool(); break; case 9: if ((tag & 7) === 2) { const end2 = reader.uint32() + reader.pos; while (reader.pos < end2) { message.canPublishSources.push(reader.int32()); } } else { message.canPublishSources.push(reader.int32()); } break; case 7: message.hidden = reader.bool(); break; case 8: message.recorder = reader.bool(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { canSubscribe: isSet$1(object.canSubscribe) ? Boolean(object.canSubscribe) : false, canPublish: isSet$1(object.canPublish) ? Boolean(object.canPublish) : false, canPublishData: isSet$1(object.canPublishData) ? Boolean(object.canPublishData) : false, canPublishSources: Array.isArray(object === null || object === void 0 ? void 0 : object.canPublishSources) ? object.canPublishSources.map(e => trackSourceFromJSON(e)) : [], hidden: isSet$1(object.hidden) ? Boolean(object.hidden) : false, recorder: isSet$1(object.recorder) ? Boolean(object.recorder) : false }; }, toJSON(message) { const obj = {}; message.canSubscribe !== undefined && (obj.canSubscribe = message.canSubscribe); message.canPublish !== undefined && (obj.canPublish = message.canPublish); message.canPublishData !== undefined && (obj.canPublishData = message.canPublishData); if (message.canPublishSources) { obj.canPublishSources = message.canPublishSources.map(e => trackSourceToJSON(e)); } else { obj.canPublishSources = []; } message.hidden !== undefined && (obj.hidden = message.hidden); message.recorder !== undefined && (obj.recorder = message.recorder); return obj; }, create(base) { return ParticipantPermission.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c, _d, _e, _f; const message = createBaseParticipantPermission(); message.canSubscribe = (_a = object.canSubscribe) !== null && _a !== void 0 ? _a : false; message.canPublish = (_b = object.canPublish) !== null && _b !== void 0 ? _b : false; message.canPublishData = (_c = object.canPublishData) !== null && _c !== void 0 ? _c : false; message.canPublishSources = ((_d = object.canPublishSources) === null || _d === void 0 ? void 0 : _d.map(e => e)) || []; message.hidden = (_e = object.hidden) !== null && _e !== void 0 ? _e : false; message.recorder = (_f = object.recorder) !== null && _f !== void 0 ? _f : false; return message; } }; function createBaseParticipantInfo() { return { sid: "", identity: "", state: 0, tracks: [], metadata: "", joinedAt: 0, name: "", version: 0, permission: undefined, region: "", isPublisher: false }; } const ParticipantInfo = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.sid !== "") { writer.uint32(10).string(message.sid); } if (message.identity !== "") { writer.uint32(18).string(message.identity); } if (message.state !== 0) { writer.uint32(24).int32(message.state); } for (const v of message.tracks) { TrackInfo.encode(v, writer.uint32(34).fork()).ldelim(); } if (message.metadata !== "") { writer.uint32(42).string(message.metadata); } if (message.joinedAt !== 0) { writer.uint32(48).int64(message.joinedAt); } if (message.name !== "") { writer.uint32(74).string(message.name); } if (message.version !== 0) { writer.uint32(80).uint32(message.version); } if (message.permission !== undefined) { ParticipantPermission.encode(message.permission, writer.uint32(90).fork()).ldelim(); } if (message.region !== "") { writer.uint32(98).string(message.region); } if (message.isPublisher === true) { writer.uint32(104).bool(message.isPublisher); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseParticipantInfo(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.sid = reader.string(); break; case 2: message.identity = reader.string(); break; case 3: message.state = reader.int32(); break; case 4: message.tracks.push(TrackInfo.decode(reader, reader.uint32())); break; case 5: message.metadata = reader.string(); break; case 6: message.joinedAt = longToNumber$1(reader.int64()); break; case 9: message.name = reader.string(); break; case 10: message.version = reader.uint32(); break; case 11: message.permission = ParticipantPermission.decode(reader, reader.uint32()); break; case 12: message.region = reader.string(); break; case 13: message.isPublisher = reader.bool(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { sid: isSet$1(object.sid) ? String(object.sid) : "", identity: isSet$1(object.identity) ? String(object.identity) : "", state: isSet$1(object.state) ? participantInfo_StateFromJSON(object.state) : 0, tracks: Array.isArray(object === null || object === void 0 ? void 0 : object.tracks) ? object.tracks.map(e => TrackInfo.fromJSON(e)) : [], metadata: isSet$1(object.metadata) ? String(object.metadata) : "", joinedAt: isSet$1(object.joinedAt) ? Number(object.joinedAt) : 0, name: isSet$1(object.name) ? String(object.name) : "", version: isSet$1(object.version) ? Number(object.version) : 0, permission: isSet$1(object.permission) ? ParticipantPermission.fromJSON(object.permission) : undefined, region: isSet$1(object.region) ? String(object.region) : "", isPublisher: isSet$1(object.isPublisher) ? Boolean(object.isPublisher) : false }; }, toJSON(message) { const obj = {}; message.sid !== undefined && (obj.sid = message.sid); message.identity !== undefined && (obj.identity = message.identity); message.state !== undefined && (obj.state = participantInfo_StateToJSON(message.state)); if (message.tracks) { obj.tracks = message.tracks.map(e => e ? TrackInfo.toJSON(e) : undefined); } else { obj.tracks = []; } message.metadata !== undefined && (obj.metadata = message.metadata); message.joinedAt !== undefined && (obj.joinedAt = Math.round(message.joinedAt)); message.name !== undefined && (obj.name = message.name); message.version !== undefined && (obj.version = Math.round(message.version)); message.permission !== undefined && (obj.permission = message.permission ? ParticipantPermission.toJSON(message.permission) : undefined); message.region !== undefined && (obj.region = message.region); message.isPublisher !== undefined && (obj.isPublisher = message.isPublisher); return obj; }, create(base) { return ParticipantInfo.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; const message = createBaseParticipantInfo(); message.sid = (_a = object.sid) !== null && _a !== void 0 ? _a : ""; message.identity = (_b = object.identity) !== null && _b !== void 0 ? _b : ""; message.state = (_c = object.state) !== null && _c !== void 0 ? _c : 0; message.tracks = ((_d = object.tracks) === null || _d === void 0 ? void 0 : _d.map(e => TrackInfo.fromPartial(e))) || []; message.metadata = (_e = object.metadata) !== null && _e !== void 0 ? _e : ""; message.joinedAt = (_f = object.joinedAt) !== null && _f !== void 0 ? _f : 0; message.name = (_g = object.name) !== null && _g !== void 0 ? _g : ""; message.version = (_h = object.version) !== null && _h !== void 0 ? _h : 0; message.permission = object.permission !== undefined && object.permission !== null ? ParticipantPermission.fromPartial(object.permission) : undefined; message.region = (_j = object.region) !== null && _j !== void 0 ? _j : ""; message.isPublisher = (_k = object.isPublisher) !== null && _k !== void 0 ? _k : false; return message; } }; function createBaseSimulcastCodecInfo() { return { mimeType: "", mid: "", cid: "", layers: [] }; } const SimulcastCodecInfo = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.mimeType !== "") { writer.uint32(10).string(message.mimeType); } if (message.mid !== "") { writer.uint32(18).string(message.mid); } if (message.cid !== "") { writer.uint32(26).string(message.cid); } for (const v of message.layers) { VideoLayer.encode(v, writer.uint32(34).fork()).ldelim(); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseSimulcastCodecInfo(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.mimeType = reader.string(); break; case 2: message.mid = reader.string(); break; case 3: message.cid = reader.string(); break; case 4: message.layers.push(VideoLayer.decode(reader, reader.uint32())); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { mimeType: isSet$1(object.mimeType) ? String(object.mimeType) : "", mid: isSet$1(object.mid) ? String(object.mid) : "", cid: isSet$1(object.cid) ? String(object.cid) : "", layers: Array.isArray(object === null || object === void 0 ? void 0 : object.layers) ? object.layers.map(e => VideoLayer.fromJSON(e)) : [] }; }, toJSON(message) { const obj = {}; message.mimeType !== undefined && (obj.mimeType = message.mimeType); message.mid !== undefined && (obj.mid = message.mid); message.cid !== undefined && (obj.cid = message.cid); if (message.layers) { obj.layers = message.layers.map(e => e ? VideoLayer.toJSON(e) : undefined); } else { obj.layers = []; } return obj; }, create(base) { return SimulcastCodecInfo.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c, _d; const message = createBaseSimulcastCodecInfo(); message.mimeType = (_a = object.mimeType) !== null && _a !== void 0 ? _a : ""; message.mid = (_b = object.mid) !== null && _b !== void 0 ? _b : ""; message.cid = (_c = object.cid) !== null && _c !== void 0 ? _c : ""; message.layers = ((_d = object.layers) === null || _d === void 0 ? void 0 : _d.map(e => VideoLayer.fromPartial(e))) || []; return message; } }; function createBaseTrackInfo() { return { sid: "", type: 0, name: "", muted: false, width: 0, height: 0, simulcast: false, disableDtx: false, source: 0, layers: [], mimeType: "", mid: "", codecs: [], stereo: false, disableRed: false, encryption: 0 }; } const TrackInfo = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.sid !== "") { writer.uint32(10).string(message.sid); } if (message.type !== 0) { writer.uint32(16).int32(message.type); } if (message.name !== "") { writer.uint32(26).string(message.name); } if (message.muted === true) { writer.uint32(32).bool(message.muted); } if (message.width !== 0) { writer.uint32(40).uint32(message.width); } if (message.height !== 0) { writer.uint32(48).uint32(message.height); } if (message.simulcast === true) { writer.uint32(56).bool(message.simulcast); } if (message.disableDtx === true) { writer.uint32(64).bool(message.disableDtx); } if (message.source !== 0) { writer.uint32(72).int32(message.source); } for (const v of message.layers) { VideoLayer.encode(v, writer.uint32(82).fork()).ldelim(); } if (message.mimeType !== "") { writer.uint32(90).string(message.mimeType); } if (message.mid !== "") { writer.uint32(98).string(message.mid); } for (const v of message.codecs) { SimulcastCodecInfo.encode(v, writer.uint32(106).fork()).ldelim(); } if (message.stereo === true) { writer.uint32(112).bool(message.stereo); } if (message.disableRed === true) { writer.uint32(120).bool(message.disableRed); } if (message.encryption !== 0) { writer.uint32(128).int32(message.encryption); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseTrackInfo(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.sid = reader.string(); break; case 2: message.type = reader.int32(); break; case 3: message.name = reader.string(); break; case 4: message.muted = reader.bool(); break; case 5: message.width = reader.uint32(); break; case 6: message.height = reader.uint32(); break; case 7: message.simulcast = reader.bool(); break; case 8: message.disableDtx = reader.bool(); break; case 9: message.source = reader.int32(); break; case 10: message.layers.push(VideoLayer.decode(reader, reader.uint32())); break; case 11: message.mimeType = reader.string(); break; case 12: message.mid = reader.string(); break; case 13: message.codecs.push(SimulcastCodecInfo.decode(reader, reader.uint32())); break; case 14: message.stereo = reader.bool(); break; case 15: message.disableRed = reader.bool(); break; case 16: message.encryption = reader.int32(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { sid: isSet$1(object.sid) ? String(object.sid) : "", type: isSet$1(object.type) ? trackTypeFromJSON(object.type) : 0, name: isSet$1(object.name) ? String(object.name) : "", muted: isSet$1(object.muted) ? Boolean(object.muted) : false, width: isSet$1(object.width) ? Number(object.width) : 0, height: isSet$1(object.height) ? Number(object.height) : 0, simulcast: isSet$1(object.simulcast) ? Boolean(object.simulcast) : false, disableDtx: isSet$1(object.disableDtx) ? Boolean(object.disableDtx) : false, source: isSet$1(object.source) ? trackSourceFromJSON(object.source) : 0, layers: Array.isArray(object === null || object === void 0 ? void 0 : object.layers) ? object.layers.map(e => VideoLayer.fromJSON(e)) : [], mimeType: isSet$1(object.mimeType) ? String(object.mimeType) : "", mid: isSet$1(object.mid) ? String(object.mid) : "", codecs: Array.isArray(object === null || object === void 0 ? void 0 : object.codecs) ? object.codecs.map(e => SimulcastCodecInfo.fromJSON(e)) : [], stereo: isSet$1(object.stereo) ? Boolean(object.stereo) : false, disableRed: isSet$1(object.disableRed) ? Boolean(object.disableRed) : false, encryption: isSet$1(object.encryption) ? encryption_TypeFromJSON(object.encryption) : 0 }; }, toJSON(message) { const obj = {}; message.sid !== undefined && (obj.sid = message.sid); message.type !== undefined && (obj.type = trackTypeToJSON(message.type)); message.name !== undefined && (obj.name = message.name); message.muted !== undefined && (obj.muted = message.muted); message.width !== undefined && (obj.width = Math.round(message.width)); message.height !== undefined && (obj.height = Math.round(message.height)); message.simulcast !== undefined && (obj.simulcast = message.simulcast); message.disableDtx !== undefined && (obj.disableDtx = message.disableDtx); message.source !== undefined && (obj.source = trackSourceToJSON(message.source)); if (message.layers) { obj.layers = message.layers.map(e => e ? VideoLayer.toJSON(e) : undefined); } else { obj.layers = []; } message.mimeType !== undefined && (obj.mimeType = message.mimeType); message.mid !== undefined && (obj.mid = message.mid); if (message.codecs) { obj.codecs = message.codecs.map(e => e ? SimulcastCodecInfo.toJSON(e) : undefined); } else { obj.codecs = []; } message.stereo !== undefined && (obj.stereo = message.stereo); message.disableRed !== undefined && (obj.disableRed = message.disableRed); message.encryption !== undefined && (obj.encryption = encryption_TypeToJSON(message.encryption)); return obj; }, create(base) { return TrackInfo.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r; const message = createBaseTrackInfo(); message.sid = (_a = object.sid) !== null && _a !== void 0 ? _a : ""; message.type = (_b = object.type) !== null && _b !== void 0 ? _b : 0; message.name = (_c = object.name) !== null && _c !== void 0 ? _c : ""; message.muted = (_d = object.muted) !== null && _d !== void 0 ? _d : false; message.width = (_e = object.width) !== null && _e !== void 0 ? _e : 0; message.height = (_f = object.height) !== null && _f !== void 0 ? _f : 0; message.simulcast = (_g = object.simulcast) !== null && _g !== void 0 ? _g : false; message.disableDtx = (_h = object.disableDtx) !== null && _h !== void 0 ? _h : false; message.source = (_j = object.source) !== null && _j !== void 0 ? _j : 0; message.layers = ((_k = object.layers) === null || _k === void 0 ? void 0 : _k.map(e => VideoLayer.fromPartial(e))) || []; message.mimeType = (_l = object.mimeType) !== null && _l !== void 0 ? _l : ""; message.mid = (_m = object.mid) !== null && _m !== void 0 ? _m : ""; message.codecs = ((_o = object.codecs) === null || _o === void 0 ? void 0 : _o.map(e => SimulcastCodecInfo.fromPartial(e))) || []; message.stereo = (_p = object.stereo) !== null && _p !== void 0 ? _p : false; message.disableRed = (_q = object.disableRed) !== null && _q !== void 0 ? _q : false; message.encryption = (_r = object.encryption) !== null && _r !== void 0 ? _r : 0; return message; } }; function createBaseVideoLayer() { return { quality: 0, width: 0, height: 0, bitrate: 0, ssrc: 0 }; } const VideoLayer = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.quality !== 0) { writer.uint32(8).int32(message.quality); } if (message.width !== 0) { writer.uint32(16).uint32(message.width); } if (message.height !== 0) { writer.uint32(24).uint32(message.height); } if (message.bitrate !== 0) { writer.uint32(32).uint32(message.bitrate); } if (message.ssrc !== 0) { writer.uint32(40).uint32(message.ssrc); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseVideoLayer(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.quality = reader.int32(); break; case 2: message.width = reader.uint32(); break; case 3: message.height = reader.uint32(); break; case 4: message.bitrate = reader.uint32(); break; case 5: message.ssrc = reader.uint32(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { quality: isSet$1(object.quality) ? videoQualityFromJSON(object.quality) : 0, width: isSet$1(object.width) ? Number(object.width) : 0, height: isSet$1(object.height) ? Number(object.height) : 0, bitrate: isSet$1(object.bitrate) ? Number(object.bitrate) : 0, ssrc: isSet$1(object.ssrc) ? Number(object.ssrc) : 0 }; }, toJSON(message) { const obj = {}; message.quality !== undefined && (obj.quality = videoQualityToJSON(message.quality)); message.width !== undefined && (obj.width = Math.round(message.width)); message.height !== undefined && (obj.height = Math.round(message.height)); message.bitrate !== undefined && (obj.bitrate = Math.round(message.bitrate)); message.ssrc !== undefined && (obj.ssrc = Math.round(message.ssrc)); return obj; }, create(base) { return VideoLayer.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c, _d, _e; const message = createBaseVideoLayer(); message.quality = (_a = object.quality) !== null && _a !== void 0 ? _a : 0; message.width = (_b = object.width) !== null && _b !== void 0 ? _b : 0; message.height = (_c = object.height) !== null && _c !== void 0 ? _c : 0; message.bitrate = (_d = object.bitrate) !== null && _d !== void 0 ? _d : 0; message.ssrc = (_e = object.ssrc) !== null && _e !== void 0 ? _e : 0; return message; } }; function createBaseDataPacket() { return { kind: 0, value: undefined }; } const DataPacket = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); var _a; if (message.kind !== 0) { writer.uint32(8).int32(message.kind); } switch ((_a = message.value) === null || _a === void 0 ? void 0 : _a.$case) { case "user": UserPacket.encode(message.value.user, writer.uint32(18).fork()).ldelim(); break; case "speaker": ActiveSpeakerUpdate.encode(message.value.speaker, writer.uint32(26).fork()).ldelim(); break; } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseDataPacket(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.kind = reader.int32(); break; case 2: message.value = { $case: "user", user: UserPacket.decode(reader, reader.uint32()) }; break; case 3: message.value = { $case: "speaker", speaker: ActiveSpeakerUpdate.decode(reader, reader.uint32()) }; break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { kind: isSet$1(object.kind) ? dataPacket_KindFromJSON(object.kind) : 0, value: isSet$1(object.user) ? { $case: "user", user: UserPacket.fromJSON(object.user) } : isSet$1(object.speaker) ? { $case: "speaker", speaker: ActiveSpeakerUpdate.fromJSON(object.speaker) } : undefined }; }, toJSON(message) { var _a, _b, _c, _d, _e, _f; const obj = {}; message.kind !== undefined && (obj.kind = dataPacket_KindToJSON(message.kind)); ((_a = message.value) === null || _a === void 0 ? void 0 : _a.$case) === "user" && (obj.user = ((_b = message.value) === null || _b === void 0 ? void 0 : _b.user) ? UserPacket.toJSON((_c = message.value) === null || _c === void 0 ? void 0 : _c.user) : undefined); ((_d = message.value) === null || _d === void 0 ? void 0 : _d.$case) === "speaker" && (obj.speaker = ((_e = message.value) === null || _e === void 0 ? void 0 : _e.speaker) ? ActiveSpeakerUpdate.toJSON((_f = message.value) === null || _f === void 0 ? void 0 : _f.speaker) : undefined); return obj; }, create(base) { return DataPacket.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c, _d, _e, _f, _g; const message = createBaseDataPacket(); message.kind = (_a = object.kind) !== null && _a !== void 0 ? _a : 0; if (((_b = object.value) === null || _b === void 0 ? void 0 : _b.$case) === "user" && ((_c = object.value) === null || _c === void 0 ? void 0 : _c.user) !== undefined && ((_d = object.value) === null || _d === void 0 ? void 0 : _d.user) !== null) { message.value = { $case: "user", user: UserPacket.fromPartial(object.value.user) }; } if (((_e = object.value) === null || _e === void 0 ? void 0 : _e.$case) === "speaker" && ((_f = object.value) === null || _f === void 0 ? void 0 : _f.speaker) !== undefined && ((_g = object.value) === null || _g === void 0 ? void 0 : _g.speaker) !== null) { message.value = { $case: "speaker", speaker: ActiveSpeakerUpdate.fromPartial(object.value.speaker) }; } return message; } }; function createBaseActiveSpeakerUpdate() { return { speakers: [] }; } const ActiveSpeakerUpdate = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); for (const v of message.speakers) { SpeakerInfo.encode(v, writer.uint32(10).fork()).ldelim(); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseActiveSpeakerUpdate(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.speakers.push(SpeakerInfo.decode(reader, reader.uint32())); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { speakers: Array.isArray(object === null || object === void 0 ? void 0 : object.speakers) ? object.speakers.map(e => SpeakerInfo.fromJSON(e)) : [] }; }, toJSON(message) { const obj = {}; if (message.speakers) { obj.speakers = message.speakers.map(e => e ? SpeakerInfo.toJSON(e) : undefined); } else { obj.speakers = []; } return obj; }, create(base) { return ActiveSpeakerUpdate.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a; const message = createBaseActiveSpeakerUpdate(); message.speakers = ((_a = object.speakers) === null || _a === void 0 ? void 0 : _a.map(e => SpeakerInfo.fromPartial(e))) || []; return message; } }; function createBaseSpeakerInfo() { return { sid: "", level: 0, active: false }; } const SpeakerInfo = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.sid !== "") { writer.uint32(10).string(message.sid); } if (message.level !== 0) { writer.uint32(21).float(message.level); } if (message.active === true) { writer.uint32(24).bool(message.active); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseSpeakerInfo(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.sid = reader.string(); break; case 2: message.level = reader.float(); break; case 3: message.active = reader.bool(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { sid: isSet$1(object.sid) ? String(object.sid) : "", level: isSet$1(object.level) ? Number(object.level) : 0, active: isSet$1(object.active) ? Boolean(object.active) : false }; }, toJSON(message) { const obj = {}; message.sid !== undefined && (obj.sid = message.sid); message.level !== undefined && (obj.level = message.level); message.active !== undefined && (obj.active = message.active); return obj; }, create(base) { return SpeakerInfo.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c; const message = createBaseSpeakerInfo(); message.sid = (_a = object.sid) !== null && _a !== void 0 ? _a : ""; message.level = (_b = object.level) !== null && _b !== void 0 ? _b : 0; message.active = (_c = object.active) !== null && _c !== void 0 ? _c : false; return message; } }; function createBaseUserPacket() { return { participantSid: "", payload: new Uint8Array(), destinationSids: [], topic: undefined }; } const UserPacket = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.participantSid !== "") { writer.uint32(10).string(message.participantSid); } if (message.payload.length !== 0) { writer.uint32(18).bytes(message.payload); } for (const v of message.destinationSids) { writer.uint32(26).string(v); } if (message.topic !== undefined) { writer.uint32(34).string(message.topic); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseUserPacket(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.participantSid = reader.string(); break; case 2: message.payload = reader.bytes(); break; case 3: message.destinationSids.push(reader.string()); break; case 4: message.topic = reader.string(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { participantSid: isSet$1(object.participantSid) ? String(object.participantSid) : "", payload: isSet$1(object.payload) ? bytesFromBase64(object.payload) : new Uint8Array(), destinationSids: Array.isArray(object === null || object === void 0 ? void 0 : object.destinationSids) ? object.destinationSids.map(e => String(e)) : [], topic: isSet$1(object.topic) ? String(object.topic) : undefined }; }, toJSON(message) { const obj = {}; message.participantSid !== undefined && (obj.participantSid = message.participantSid); message.payload !== undefined && (obj.payload = base64FromBytes(message.payload !== undefined ? message.payload : new Uint8Array())); if (message.destinationSids) { obj.destinationSids = message.destinationSids.map(e => e); } else { obj.destinationSids = []; } message.topic !== undefined && (obj.topic = message.topic); return obj; }, create(base) { return UserPacket.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c, _d; const message = createBaseUserPacket(); message.participantSid = (_a = object.participantSid) !== null && _a !== void 0 ? _a : ""; message.payload = (_b = object.payload) !== null && _b !== void 0 ? _b : new Uint8Array(); message.destinationSids = ((_c = object.destinationSids) === null || _c === void 0 ? void 0 : _c.map(e => e)) || []; message.topic = (_d = object.topic) !== null && _d !== void 0 ? _d : undefined; return message; } }; function createBaseParticipantTracks() { return { participantSid: "", trackSids: [] }; } const ParticipantTracks = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.participantSid !== "") { writer.uint32(10).string(message.participantSid); } for (const v of message.trackSids) { writer.uint32(18).string(v); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseParticipantTracks(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.participantSid = reader.string(); break; case 2: message.trackSids.push(reader.string()); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { participantSid: isSet$1(object.participantSid) ? String(object.participantSid) : "", trackSids: Array.isArray(object === null || object === void 0 ? void 0 : object.trackSids) ? object.trackSids.map(e => String(e)) : [] }; }, toJSON(message) { const obj = {}; message.participantSid !== undefined && (obj.participantSid = message.participantSid); if (message.trackSids) { obj.trackSids = message.trackSids.map(e => e); } else { obj.trackSids = []; } return obj; }, create(base) { return ParticipantTracks.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b; const message = createBaseParticipantTracks(); message.participantSid = (_a = object.participantSid) !== null && _a !== void 0 ? _a : ""; message.trackSids = ((_b = object.trackSids) === null || _b === void 0 ? void 0 : _b.map(e => e)) || []; return message; } }; function createBaseServerInfo() { return { edition: 0, version: "", protocol: 0, region: "", nodeId: "", debugInfo: "" }; } const ServerInfo = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.edition !== 0) { writer.uint32(8).int32(message.edition); } if (message.version !== "") { writer.uint32(18).string(message.version); } if (message.protocol !== 0) { writer.uint32(24).int32(message.protocol); } if (message.region !== "") { writer.uint32(34).string(message.region); } if (message.nodeId !== "") { writer.uint32(42).string(message.nodeId); } if (message.debugInfo !== "") { writer.uint32(50).string(message.debugInfo); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseServerInfo(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.edition = reader.int32(); break; case 2: message.version = reader.string(); break; case 3: message.protocol = reader.int32(); break; case 4: message.region = reader.string(); break; case 5: message.nodeId = reader.string(); break; case 6: message.debugInfo = reader.string(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { edition: isSet$1(object.edition) ? serverInfo_EditionFromJSON(object.edition) : 0, version: isSet$1(object.version) ? String(object.version) : "", protocol: isSet$1(object.protocol) ? Number(object.protocol) : 0, region: isSet$1(object.region) ? String(object.region) : "", nodeId: isSet$1(object.nodeId) ? String(object.nodeId) : "", debugInfo: isSet$1(object.debugInfo) ? String(object.debugInfo) : "" }; }, toJSON(message) { const obj = {}; message.edition !== undefined && (obj.edition = serverInfo_EditionToJSON(message.edition)); message.version !== undefined && (obj.version = message.version); message.protocol !== undefined && (obj.protocol = Math.round(message.protocol)); message.region !== undefined && (obj.region = message.region); message.nodeId !== undefined && (obj.nodeId = message.nodeId); message.debugInfo !== undefined && (obj.debugInfo = message.debugInfo); return obj; }, create(base) { return ServerInfo.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c, _d, _e, _f; const message = createBaseServerInfo(); message.edition = (_a = object.edition) !== null && _a !== void 0 ? _a : 0; message.version = (_b = object.version) !== null && _b !== void 0 ? _b : ""; message.protocol = (_c = object.protocol) !== null && _c !== void 0 ? _c : 0; message.region = (_d = object.region) !== null && _d !== void 0 ? _d : ""; message.nodeId = (_e = object.nodeId) !== null && _e !== void 0 ? _e : ""; message.debugInfo = (_f = object.debugInfo) !== null && _f !== void 0 ? _f : ""; return message; } }; function createBaseClientInfo() { return { sdk: 0, version: "", protocol: 0, os: "", osVersion: "", deviceModel: "", browser: "", browserVersion: "", address: "", network: "" }; } const ClientInfo = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.sdk !== 0) { writer.uint32(8).int32(message.sdk); } if (message.version !== "") { writer.uint32(18).string(message.version); } if (message.protocol !== 0) { writer.uint32(24).int32(message.protocol); } if (message.os !== "") { writer.uint32(34).string(message.os); } if (message.osVersion !== "") { writer.uint32(42).string(message.osVersion); } if (message.deviceModel !== "") { writer.uint32(50).string(message.deviceModel); } if (message.browser !== "") { writer.uint32(58).string(message.browser); } if (message.browserVersion !== "") { writer.uint32(66).string(message.browserVersion); } if (message.address !== "") { writer.uint32(74).string(message.address); } if (message.network !== "") { writer.uint32(82).string(message.network); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseClientInfo(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.sdk = reader.int32(); break; case 2: message.version = reader.string(); break; case 3: message.protocol = reader.int32(); break; case 4: message.os = reader.string(); break; case 5: message.osVersion = reader.string(); break; case 6: message.deviceModel = reader.string(); break; case 7: message.browser = reader.string(); break; case 8: message.browserVersion = reader.string(); break; case 9: message.address = reader.string(); break; case 10: message.network = reader.string(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { sdk: isSet$1(object.sdk) ? clientInfo_SDKFromJSON(object.sdk) : 0, version: isSet$1(object.version) ? String(object.version) : "", protocol: isSet$1(object.protocol) ? Number(object.protocol) : 0, os: isSet$1(object.os) ? String(object.os) : "", osVersion: isSet$1(object.osVersion) ? String(object.osVersion) : "", deviceModel: isSet$1(object.deviceModel) ? String(object.deviceModel) : "", browser: isSet$1(object.browser) ? String(object.browser) : "", browserVersion: isSet$1(object.browserVersion) ? String(object.browserVersion) : "", address: isSet$1(object.address) ? String(object.address) : "", network: isSet$1(object.network) ? String(object.network) : "" }; }, toJSON(message) { const obj = {}; message.sdk !== undefined && (obj.sdk = clientInfo_SDKToJSON(message.sdk)); message.version !== undefined && (obj.version = message.version); message.protocol !== undefined && (obj.protocol = Math.round(message.protocol)); message.os !== undefined && (obj.os = message.os); message.osVersion !== undefined && (obj.osVersion = message.osVersion); message.deviceModel !== undefined && (obj.deviceModel = message.deviceModel); message.browser !== undefined && (obj.browser = message.browser); message.browserVersion !== undefined && (obj.browserVersion = message.browserVersion); message.address !== undefined && (obj.address = message.address); message.network !== undefined && (obj.network = message.network); return obj; }, create(base) { return ClientInfo.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; const message = createBaseClientInfo(); message.sdk = (_a = object.sdk) !== null && _a !== void 0 ? _a : 0; message.version = (_b = object.version) !== null && _b !== void 0 ? _b : ""; message.protocol = (_c = object.protocol) !== null && _c !== void 0 ? _c : 0; message.os = (_d = object.os) !== null && _d !== void 0 ? _d : ""; message.osVersion = (_e = object.osVersion) !== null && _e !== void 0 ? _e : ""; message.deviceModel = (_f = object.deviceModel) !== null && _f !== void 0 ? _f : ""; message.browser = (_g = object.browser) !== null && _g !== void 0 ? _g : ""; message.browserVersion = (_h = object.browserVersion) !== null && _h !== void 0 ? _h : ""; message.address = (_j = object.address) !== null && _j !== void 0 ? _j : ""; message.network = (_k = object.network) !== null && _k !== void 0 ? _k : ""; return message; } }; function createBaseClientConfiguration() { return { video: undefined, screen: undefined, resumeConnection: 0, disabledCodecs: undefined, forceRelay: 0 }; } const ClientConfiguration = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.video !== undefined) { VideoConfiguration.encode(message.video, writer.uint32(10).fork()).ldelim(); } if (message.screen !== undefined) { VideoConfiguration.encode(message.screen, writer.uint32(18).fork()).ldelim(); } if (message.resumeConnection !== 0) { writer.uint32(24).int32(message.resumeConnection); } if (message.disabledCodecs !== undefined) { DisabledCodecs.encode(message.disabledCodecs, writer.uint32(34).fork()).ldelim(); } if (message.forceRelay !== 0) { writer.uint32(40).int32(message.forceRelay); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseClientConfiguration(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.video = VideoConfiguration.decode(reader, reader.uint32()); break; case 2: message.screen = VideoConfiguration.decode(reader, reader.uint32()); break; case 3: message.resumeConnection = reader.int32(); break; case 4: message.disabledCodecs = DisabledCodecs.decode(reader, reader.uint32()); break; case 5: message.forceRelay = reader.int32(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { video: isSet$1(object.video) ? VideoConfiguration.fromJSON(object.video) : undefined, screen: isSet$1(object.screen) ? VideoConfiguration.fromJSON(object.screen) : undefined, resumeConnection: isSet$1(object.resumeConnection) ? clientConfigSettingFromJSON(object.resumeConnection) : 0, disabledCodecs: isSet$1(object.disabledCodecs) ? DisabledCodecs.fromJSON(object.disabledCodecs) : undefined, forceRelay: isSet$1(object.forceRelay) ? clientConfigSettingFromJSON(object.forceRelay) : 0 }; }, toJSON(message) { const obj = {}; message.video !== undefined && (obj.video = message.video ? VideoConfiguration.toJSON(message.video) : undefined); message.screen !== undefined && (obj.screen = message.screen ? VideoConfiguration.toJSON(message.screen) : undefined); message.resumeConnection !== undefined && (obj.resumeConnection = clientConfigSettingToJSON(message.resumeConnection)); message.disabledCodecs !== undefined && (obj.disabledCodecs = message.disabledCodecs ? DisabledCodecs.toJSON(message.disabledCodecs) : undefined); message.forceRelay !== undefined && (obj.forceRelay = clientConfigSettingToJSON(message.forceRelay)); return obj; }, create(base) { return ClientConfiguration.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b; const message = createBaseClientConfiguration(); message.video = object.video !== undefined && object.video !== null ? VideoConfiguration.fromPartial(object.video) : undefined; message.screen = object.screen !== undefined && object.screen !== null ? VideoConfiguration.fromPartial(object.screen) : undefined; message.resumeConnection = (_a = object.resumeConnection) !== null && _a !== void 0 ? _a : 0; message.disabledCodecs = object.disabledCodecs !== undefined && object.disabledCodecs !== null ? DisabledCodecs.fromPartial(object.disabledCodecs) : undefined; message.forceRelay = (_b = object.forceRelay) !== null && _b !== void 0 ? _b : 0; return message; } }; function createBaseVideoConfiguration() { return { hardwareEncoder: 0 }; } const VideoConfiguration = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.hardwareEncoder !== 0) { writer.uint32(8).int32(message.hardwareEncoder); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseVideoConfiguration(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.hardwareEncoder = reader.int32(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { hardwareEncoder: isSet$1(object.hardwareEncoder) ? clientConfigSettingFromJSON(object.hardwareEncoder) : 0 }; }, toJSON(message) { const obj = {}; message.hardwareEncoder !== undefined && (obj.hardwareEncoder = clientConfigSettingToJSON(message.hardwareEncoder)); return obj; }, create(base) { return VideoConfiguration.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a; const message = createBaseVideoConfiguration(); message.hardwareEncoder = (_a = object.hardwareEncoder) !== null && _a !== void 0 ? _a : 0; return message; } }; function createBaseDisabledCodecs() { return { codecs: [] }; } const DisabledCodecs = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); for (const v of message.codecs) { Codec.encode(v, writer.uint32(10).fork()).ldelim(); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseDisabledCodecs(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.codecs.push(Codec.decode(reader, reader.uint32())); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { codecs: Array.isArray(object === null || object === void 0 ? void 0 : object.codecs) ? object.codecs.map(e => Codec.fromJSON(e)) : [] }; }, toJSON(message) { const obj = {}; if (message.codecs) { obj.codecs = message.codecs.map(e => e ? Codec.toJSON(e) : undefined); } else { obj.codecs = []; } return obj; }, create(base) { return DisabledCodecs.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a; const message = createBaseDisabledCodecs(); message.codecs = ((_a = object.codecs) === null || _a === void 0 ? void 0 : _a.map(e => Codec.fromPartial(e))) || []; return message; } }; var tsProtoGlobalThis$1 = (() => { if (typeof globalThis !== "undefined") { return globalThis; } if (typeof self !== "undefined") { return self; } if (typeof window !== "undefined") { return window; } if (typeof global !== "undefined") { return global; } throw "Unable to locate global object"; })(); function bytesFromBase64(b64) { if (tsProtoGlobalThis$1.Buffer) { return Uint8Array.from(tsProtoGlobalThis$1.Buffer.from(b64, "base64")); } else { const bin = tsProtoGlobalThis$1.atob(b64); const arr = new Uint8Array(bin.length); for (let i = 0; i < bin.length; ++i) { arr[i] = bin.charCodeAt(i); } return arr; } } function base64FromBytes(arr) { if (tsProtoGlobalThis$1.Buffer) { return tsProtoGlobalThis$1.Buffer.from(arr).toString("base64"); } else { const bin = []; arr.forEach(byte => { bin.push(String.fromCharCode(byte)); }); return tsProtoGlobalThis$1.btoa(bin.join("")); } } function longToNumber$1(long) { if (long.gt(Number.MAX_SAFE_INTEGER)) { throw new tsProtoGlobalThis$1.Error("Value is larger than Number.MAX_SAFE_INTEGER"); } return long.toNumber(); } if (_m0.util.Long !== Long) { _m0.util.Long = Long; _m0.configure(); } function isSet$1(value) { return value !== null && value !== undefined; } const maxRetryDelay = 7000; const DEFAULT_RETRY_DELAYS_IN_MS = [0, 300, 2 * 2 * 300, 3 * 3 * 300, 4 * 4 * 300, maxRetryDelay, maxRetryDelay, maxRetryDelay, maxRetryDelay, maxRetryDelay]; class DefaultReconnectPolicy { constructor(retryDelays) { this._retryDelays = retryDelays !== undefined ? [...retryDelays] : DEFAULT_RETRY_DELAYS_IN_MS; } nextRetryDelayInMs(context) { if (context.retryCount >= this._retryDelays.length) return null; const retryDelay = this._retryDelays[context.retryCount]; if (context.retryCount <= 1) return retryDelay; return retryDelay + Math.random() * 1000; } } function _asyncIterator(iterable) { var method, async, sync, retry = 2; for ("undefined" != typeof Symbol && (async = Symbol.asyncIterator, sync = Symbol.iterator); retry--;) { if (async && null != (method = iterable[async])) return method.call(iterable); if (sync && null != (method = iterable[sync])) return new AsyncFromSyncIterator(method.call(iterable)); async = "@@asyncIterator", sync = "@@iterator"; } throw new TypeError("Object is not async iterable"); } function AsyncFromSyncIterator(s) { function AsyncFromSyncIteratorContinuation(r) { if (Object(r) !== r) return Promise.reject(new TypeError(r + " is not an object.")); var done = r.done; return Promise.resolve(r.value).then(function (value) { return { value: value, done: done }; }); } return AsyncFromSyncIterator = function (s) { this.s = s, this.n = s.next; }, AsyncFromSyncIterator.prototype = { s: null, n: null, next: function () { return AsyncFromSyncIteratorContinuation(this.n.apply(this.s, arguments)); }, return: function (value) { var ret = this.s.return; return void 0 === ret ? Promise.resolve({ value: value, done: !0 }) : AsyncFromSyncIteratorContinuation(ret.apply(this.s, arguments)); }, throw: function (value) { var thr = this.s.return; return void 0 === thr ? Promise.reject(value) : AsyncFromSyncIteratorContinuation(thr.apply(this.s, arguments)); } }, new AsyncFromSyncIterator(s); } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); } /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. */ let logDisabled_ = true; let deprecationWarnings_ = true; /** * Extract browser version out of the provided user agent string. * * @param {!string} uastring userAgent string. * @param {!string} expr Regular expression used as match criteria. * @param {!number} pos position in the version string to be returned. * @return {!number} browser version. */ function extractVersion(uastring, expr, pos) { const match = uastring.match(expr); return match && match.length >= pos && parseInt(match[pos], 10); } // Wraps the peerconnection event eventNameToWrap in a function // which returns the modified event object (or false to prevent // the event). function wrapPeerConnectionEvent(window, eventNameToWrap, wrapper) { if (!window.RTCPeerConnection) { return; } const proto = window.RTCPeerConnection.prototype; const nativeAddEventListener = proto.addEventListener; proto.addEventListener = function (nativeEventName, cb) { if (nativeEventName !== eventNameToWrap) { return nativeAddEventListener.apply(this, arguments); } const wrappedCallback = e => { const modifiedEvent = wrapper(e); if (modifiedEvent) { if (cb.handleEvent) { cb.handleEvent(modifiedEvent); } else { cb(modifiedEvent); } } }; this._eventMap = this._eventMap || {}; if (!this._eventMap[eventNameToWrap]) { this._eventMap[eventNameToWrap] = new Map(); } this._eventMap[eventNameToWrap].set(cb, wrappedCallback); return nativeAddEventListener.apply(this, [nativeEventName, wrappedCallback]); }; const nativeRemoveEventListener = proto.removeEventListener; proto.removeEventListener = function (nativeEventName, cb) { if (nativeEventName !== eventNameToWrap || !this._eventMap || !this._eventMap[eventNameToWrap]) { return nativeRemoveEventListener.apply(this, arguments); } if (!this._eventMap[eventNameToWrap].has(cb)) { return nativeRemoveEventListener.apply(this, arguments); } const unwrappedCb = this._eventMap[eventNameToWrap].get(cb); this._eventMap[eventNameToWrap].delete(cb); if (this._eventMap[eventNameToWrap].size === 0) { delete this._eventMap[eventNameToWrap]; } if (Object.keys(this._eventMap).length === 0) { delete this._eventMap; } return nativeRemoveEventListener.apply(this, [nativeEventName, unwrappedCb]); }; Object.defineProperty(proto, 'on' + eventNameToWrap, { get() { return this['_on' + eventNameToWrap]; }, set(cb) { if (this['_on' + eventNameToWrap]) { this.removeEventListener(eventNameToWrap, this['_on' + eventNameToWrap]); delete this['_on' + eventNameToWrap]; } if (cb) { this.addEventListener(eventNameToWrap, this['_on' + eventNameToWrap] = cb); } }, enumerable: true, configurable: true }); } function disableLog(bool) { if (typeof bool !== 'boolean') { return new Error('Argument type: ' + typeof bool + '. Please use a boolean.'); } logDisabled_ = bool; return bool ? 'adapter.js logging disabled' : 'adapter.js logging enabled'; } /** * Disable or enable deprecation warnings * @param {!boolean} bool set to true to disable warnings. */ function disableWarnings(bool) { if (typeof bool !== 'boolean') { return new Error('Argument type: ' + typeof bool + '. Please use a boolean.'); } deprecationWarnings_ = !bool; return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled'); } function log() { if (typeof window === 'object') { if (logDisabled_) { return; } if (typeof console !== 'undefined' && typeof console.log === 'function') { console.log.apply(console, arguments); } } } /** * Shows a deprecation warning suggesting the modern and spec-compatible API. */ function deprecated(oldMethod, newMethod) { if (!deprecationWarnings_) { return; } console.warn(oldMethod + ' is deprecated, please use ' + newMethod + ' instead.'); } /** * Browser detector. * * @return {object} result containing browser and version * properties. */ function detectBrowser(window) { // Returned result object. const result = { browser: null, version: null }; // Fail early if it's not a browser if (typeof window === 'undefined' || !window.navigator) { result.browser = 'Not a browser.'; return result; } const { navigator } = window; if (navigator.mozGetUserMedia) { // Firefox. result.browser = 'firefox'; result.version = extractVersion(navigator.userAgent, /Firefox\/(\d+)\./, 1); } else if (navigator.webkitGetUserMedia || window.isSecureContext === false && window.webkitRTCPeerConnection && !window.RTCIceGatherer) { // Chrome, Chromium, Webview, Opera. // Version matches Chrome/WebRTC version. // Chrome 74 removed webkitGetUserMedia on http as well so we need the // more complicated fallback to webkitRTCPeerConnection. result.browser = 'chrome'; result.version = extractVersion(navigator.userAgent, /Chrom(e|ium)\/(\d+)\./, 2); } else if (window.RTCPeerConnection && navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) { // Safari. result.browser = 'safari'; result.version = extractVersion(navigator.userAgent, /AppleWebKit\/(\d+)\./, 1); result.supportsUnifiedPlan = window.RTCRtpTransceiver && 'currentDirection' in window.RTCRtpTransceiver.prototype; } else { // Default fallthrough: not supported. result.browser = 'Not a supported browser.'; return result; } return result; } /** * Checks if something is an object. * * @param {*} val The something you want to check. * @return true if val is an object, false otherwise. */ function isObject(val) { return Object.prototype.toString.call(val) === '[object Object]'; } /** * Remove all empty objects and undefined values * from a nested object -- an enhanced and vanilla version * of Lodash's `compact`. */ function compactObject(data) { if (!isObject(data)) { return data; } return Object.keys(data).reduce(function (accumulator, key) { const isObj = isObject(data[key]); const value = isObj ? compactObject(data[key]) : data[key]; const isEmptyObject = isObj && !Object.keys(value).length; if (value === undefined || isEmptyObject) { return accumulator; } return Object.assign(accumulator, { [key]: value }); }, {}); } /* iterates the stats graph recursively. */ function walkStats(stats, base, resultSet) { if (!base || resultSet.has(base.id)) { return; } resultSet.set(base.id, base); Object.keys(base).forEach(name => { if (name.endsWith('Id')) { walkStats(stats, stats.get(base[name]), resultSet); } else if (name.endsWith('Ids')) { base[name].forEach(id => { walkStats(stats, stats.get(id), resultSet); }); } }); } /* filter getStats for a sender/receiver track. */ function filterStats(result, track, outbound) { const streamStatsType = outbound ? 'outbound-rtp' : 'inbound-rtp'; const filteredResult = new Map(); if (track === null) { return filteredResult; } const trackStats = []; result.forEach(value => { if (value.type === 'track' && value.trackIdentifier === track.id) { trackStats.push(value); } }); trackStats.forEach(trackStat => { result.forEach(stats => { if (stats.type === streamStatsType && stats.trackId === trackStat.id) { walkStats(result, stats, filteredResult); } }); }); return filteredResult; } /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. */ const logging = log; function shimGetUserMedia$2(window, browserDetails) { const navigator = window && window.navigator; if (!navigator.mediaDevices) { return; } const constraintsToChrome_ = function (c) { if (typeof c !== 'object' || c.mandatory || c.optional) { return c; } const cc = {}; Object.keys(c).forEach(key => { if (key === 'require' || key === 'advanced' || key === 'mediaSource') { return; } const r = typeof c[key] === 'object' ? c[key] : { ideal: c[key] }; if (r.exact !== undefined && typeof r.exact === 'number') { r.min = r.max = r.exact; } const oldname_ = function (prefix, name) { if (prefix) { return prefix + name.charAt(0).toUpperCase() + name.slice(1); } return name === 'deviceId' ? 'sourceId' : name; }; if (r.ideal !== undefined) { cc.optional = cc.optional || []; let oc = {}; if (typeof r.ideal === 'number') { oc[oldname_('min', key)] = r.ideal; cc.optional.push(oc); oc = {}; oc[oldname_('max', key)] = r.ideal; cc.optional.push(oc); } else { oc[oldname_('', key)] = r.ideal; cc.optional.push(oc); } } if (r.exact !== undefined && typeof r.exact !== 'number') { cc.mandatory = cc.mandatory || {}; cc.mandatory[oldname_('', key)] = r.exact; } else { ['min', 'max'].forEach(mix => { if (r[mix] !== undefined) { cc.mandatory = cc.mandatory || {}; cc.mandatory[oldname_(mix, key)] = r[mix]; } }); } }); if (c.advanced) { cc.optional = (cc.optional || []).concat(c.advanced); } return cc; }; const shimConstraints_ = function (constraints, func) { if (browserDetails.version >= 61) { return func(constraints); } constraints = JSON.parse(JSON.stringify(constraints)); if (constraints && typeof constraints.audio === 'object') { const remap = function (obj, a, b) { if (a in obj && !(b in obj)) { obj[b] = obj[a]; delete obj[a]; } }; constraints = JSON.parse(JSON.stringify(constraints)); remap(constraints.audio, 'autoGainControl', 'googAutoGainControl'); remap(constraints.audio, 'noiseSuppression', 'googNoiseSuppression'); constraints.audio = constraintsToChrome_(constraints.audio); } if (constraints && typeof constraints.video === 'object') { // Shim facingMode for mobile & surface pro. let face = constraints.video.facingMode; face = face && (typeof face === 'object' ? face : { ideal: face }); const getSupportedFacingModeLies = browserDetails.version < 66; if (face && (face.exact === 'user' || face.exact === 'environment' || face.ideal === 'user' || face.ideal === 'environment') && !(navigator.mediaDevices.getSupportedConstraints && navigator.mediaDevices.getSupportedConstraints().facingMode && !getSupportedFacingModeLies)) { delete constraints.video.facingMode; let matches; if (face.exact === 'environment' || face.ideal === 'environment') { matches = ['back', 'rear']; } else if (face.exact === 'user' || face.ideal === 'user') { matches = ['front']; } if (matches) { // Look for matches in label, or use last cam for back (typical). return navigator.mediaDevices.enumerateDevices().then(devices => { devices = devices.filter(d => d.kind === 'videoinput'); let dev = devices.find(d => matches.some(match => d.label.toLowerCase().includes(match))); if (!dev && devices.length && matches.includes('back')) { dev = devices[devices.length - 1]; // more likely the back cam } if (dev) { constraints.video.deviceId = face.exact ? { exact: dev.deviceId } : { ideal: dev.deviceId }; } constraints.video = constraintsToChrome_(constraints.video); logging('chrome: ' + JSON.stringify(constraints)); return func(constraints); }); } } constraints.video = constraintsToChrome_(constraints.video); } logging('chrome: ' + JSON.stringify(constraints)); return func(constraints); }; const shimError_ = function (e) { if (browserDetails.version >= 64) { return e; } return { name: { PermissionDeniedError: 'NotAllowedError', PermissionDismissedError: 'NotAllowedError', InvalidStateError: 'NotAllowedError', DevicesNotFoundError: 'NotFoundError', ConstraintNotSatisfiedError: 'OverconstrainedError', TrackStartError: 'NotReadableError', MediaDeviceFailedDueToShutdown: 'NotAllowedError', MediaDeviceKillSwitchOn: 'NotAllowedError', TabCaptureError: 'AbortError', ScreenCaptureError: 'AbortError', DeviceCaptureError: 'AbortError' }[e.name] || e.name, message: e.message, constraint: e.constraint || e.constraintName, toString() { return this.name + (this.message && ': ') + this.message; } }; }; const getUserMedia_ = function (constraints, onSuccess, onError) { shimConstraints_(constraints, c => { navigator.webkitGetUserMedia(c, onSuccess, e => { if (onError) { onError(shimError_(e)); } }); }); }; navigator.getUserMedia = getUserMedia_.bind(navigator); // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia // function which returns a Promise, it does not accept spec-style // constraints. if (navigator.mediaDevices.getUserMedia) { const origGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices); navigator.mediaDevices.getUserMedia = function (cs) { return shimConstraints_(cs, c => origGetUserMedia(c).then(stream => { if (c.audio && !stream.getAudioTracks().length || c.video && !stream.getVideoTracks().length) { stream.getTracks().forEach(track => { track.stop(); }); throw new DOMException('', 'NotFoundError'); } return stream; }, e => Promise.reject(shimError_(e)))); }; } } /* * Copyright (c) 2018 The adapter.js project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. */ function shimGetDisplayMedia$1(window, getSourceId) { if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) { return; } if (!window.navigator.mediaDevices) { return; } // getSourceId is a function that returns a promise resolving with // the sourceId of the screen/window/tab to be shared. if (typeof getSourceId !== 'function') { console.error('shimGetDisplayMedia: getSourceId argument is not ' + 'a function'); return; } window.navigator.mediaDevices.getDisplayMedia = function getDisplayMedia(constraints) { return getSourceId(constraints).then(sourceId => { const widthSpecified = constraints.video && constraints.video.width; const heightSpecified = constraints.video && constraints.video.height; const frameRateSpecified = constraints.video && constraints.video.frameRate; constraints.video = { mandatory: { chromeMediaSource: 'desktop', chromeMediaSourceId: sourceId, maxFrameRate: frameRateSpecified || 3 } }; if (widthSpecified) { constraints.video.mandatory.maxWidth = widthSpecified; } if (heightSpecified) { constraints.video.mandatory.maxHeight = heightSpecified; } return window.navigator.mediaDevices.getUserMedia(constraints); }); }; } /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. */ function shimMediaStream(window) { window.MediaStream = window.MediaStream || window.webkitMediaStream; } function shimOnTrack$1(window) { if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in window.RTCPeerConnection.prototype)) { Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { get() { return this._ontrack; }, set(f) { if (this._ontrack) { this.removeEventListener('track', this._ontrack); } this.addEventListener('track', this._ontrack = f); }, enumerable: true, configurable: true }); const origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() { if (!this._ontrackpoly) { this._ontrackpoly = e => { // onaddstream does not fire when a track is added to an existing // stream. But stream.onaddtrack is implemented so we use that. e.stream.addEventListener('addtrack', te => { let receiver; if (window.RTCPeerConnection.prototype.getReceivers) { receiver = this.getReceivers().find(r => r.track && r.track.id === te.track.id); } else { receiver = { track: te.track }; } const event = new Event('track'); event.track = te.track; event.receiver = receiver; event.transceiver = { receiver }; event.streams = [e.stream]; this.dispatchEvent(event); }); e.stream.getTracks().forEach(track => { let receiver; if (window.RTCPeerConnection.prototype.getReceivers) { receiver = this.getReceivers().find(r => r.track && r.track.id === track.id); } else { receiver = { track }; } const event = new Event('track'); event.track = track; event.receiver = receiver; event.transceiver = { receiver }; event.streams = [e.stream]; this.dispatchEvent(event); }); }; this.addEventListener('addstream', this._ontrackpoly); } return origSetRemoteDescription.apply(this, arguments); }; } else { // even if RTCRtpTransceiver is in window, it is only used and // emitted in unified-plan. Unfortunately this means we need // to unconditionally wrap the event. wrapPeerConnectionEvent(window, 'track', e => { if (!e.transceiver) { Object.defineProperty(e, 'transceiver', { value: { receiver: e.receiver } }); } return e; }); } } function shimGetSendersWithDtmf(window) { // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack. if (typeof window === 'object' && window.RTCPeerConnection && !('getSenders' in window.RTCPeerConnection.prototype) && 'createDTMFSender' in window.RTCPeerConnection.prototype) { const shimSenderWithDtmf = function (pc, track) { return { track, get dtmf() { if (this._dtmf === undefined) { if (track.kind === 'audio') { this._dtmf = pc.createDTMFSender(track); } else { this._dtmf = null; } } return this._dtmf; }, _pc: pc }; }; // augment addTrack when getSenders is not available. if (!window.RTCPeerConnection.prototype.getSenders) { window.RTCPeerConnection.prototype.getSenders = function getSenders() { this._senders = this._senders || []; return this._senders.slice(); // return a copy of the internal state. }; const origAddTrack = window.RTCPeerConnection.prototype.addTrack; window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) { let sender = origAddTrack.apply(this, arguments); if (!sender) { sender = shimSenderWithDtmf(this, track); this._senders.push(sender); } return sender; }; const origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) { origRemoveTrack.apply(this, arguments); const idx = this._senders.indexOf(sender); if (idx !== -1) { this._senders.splice(idx, 1); } }; } const origAddStream = window.RTCPeerConnection.prototype.addStream; window.RTCPeerConnection.prototype.addStream = function addStream(stream) { this._senders = this._senders || []; origAddStream.apply(this, [stream]); stream.getTracks().forEach(track => { this._senders.push(shimSenderWithDtmf(this, track)); }); }; const origRemoveStream = window.RTCPeerConnection.prototype.removeStream; window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { this._senders = this._senders || []; origRemoveStream.apply(this, [stream]); stream.getTracks().forEach(track => { const sender = this._senders.find(s => s.track === track); if (sender) { // remove sender this._senders.splice(this._senders.indexOf(sender), 1); } }); }; } else if (typeof window === 'object' && window.RTCPeerConnection && 'getSenders' in window.RTCPeerConnection.prototype && 'createDTMFSender' in window.RTCPeerConnection.prototype && window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { const origGetSenders = window.RTCPeerConnection.prototype.getSenders; window.RTCPeerConnection.prototype.getSenders = function getSenders() { const senders = origGetSenders.apply(this, []); senders.forEach(sender => sender._pc = this); return senders; }; Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { get() { if (this._dtmf === undefined) { if (this.track.kind === 'audio') { this._dtmf = this._pc.createDTMFSender(this.track); } else { this._dtmf = null; } } return this._dtmf; } }); } } function shimGetStats(window) { if (!window.RTCPeerConnection) { return; } const origGetStats = window.RTCPeerConnection.prototype.getStats; window.RTCPeerConnection.prototype.getStats = function getStats() { const [selector, onSucc, onErr] = arguments; // If selector is a function then we are in the old style stats so just // pass back the original getStats format to avoid breaking old users. if (arguments.length > 0 && typeof selector === 'function') { return origGetStats.apply(this, arguments); } // When spec-style getStats is supported, return those when called with // either no arguments or the selector argument is null. if (origGetStats.length === 0 && (arguments.length === 0 || typeof selector !== 'function')) { return origGetStats.apply(this, []); } const fixChromeStats_ = function (response) { const standardReport = {}; const reports = response.result(); reports.forEach(report => { const standardStats = { id: report.id, timestamp: report.timestamp, type: { localcandidate: 'local-candidate', remotecandidate: 'remote-candidate' }[report.type] || report.type }; report.names().forEach(name => { standardStats[name] = report.stat(name); }); standardReport[standardStats.id] = standardStats; }); return standardReport; }; // shim getStats with maplike support const makeMapStats = function (stats) { return new Map(Object.keys(stats).map(key => [key, stats[key]])); }; if (arguments.length >= 2) { const successCallbackWrapper_ = function (response) { onSucc(makeMapStats(fixChromeStats_(response))); }; return origGetStats.apply(this, [successCallbackWrapper_, selector]); } // promise-support return new Promise((resolve, reject) => { origGetStats.apply(this, [function (response) { resolve(makeMapStats(fixChromeStats_(response))); }, reject]); }).then(onSucc, onErr); }; } function shimSenderReceiverGetStats(window) { if (!(typeof window === 'object' && window.RTCPeerConnection && window.RTCRtpSender && window.RTCRtpReceiver)) { return; } // shim sender stats. if (!('getStats' in window.RTCRtpSender.prototype)) { const origGetSenders = window.RTCPeerConnection.prototype.getSenders; if (origGetSenders) { window.RTCPeerConnection.prototype.getSenders = function getSenders() { const senders = origGetSenders.apply(this, []); senders.forEach(sender => sender._pc = this); return senders; }; } const origAddTrack = window.RTCPeerConnection.prototype.addTrack; if (origAddTrack) { window.RTCPeerConnection.prototype.addTrack = function addTrack() { const sender = origAddTrack.apply(this, arguments); sender._pc = this; return sender; }; } window.RTCRtpSender.prototype.getStats = function getStats() { const sender = this; return this._pc.getStats().then(result => /* Note: this will include stats of all senders that * send a track with the same id as sender.track as * it is not possible to identify the RTCRtpSender. */ filterStats(result, sender.track, true)); }; } // shim receiver stats. if (!('getStats' in window.RTCRtpReceiver.prototype)) { const origGetReceivers = window.RTCPeerConnection.prototype.getReceivers; if (origGetReceivers) { window.RTCPeerConnection.prototype.getReceivers = function getReceivers() { const receivers = origGetReceivers.apply(this, []); receivers.forEach(receiver => receiver._pc = this); return receivers; }; } wrapPeerConnectionEvent(window, 'track', e => { e.receiver._pc = e.srcElement; return e; }); window.RTCRtpReceiver.prototype.getStats = function getStats() { const receiver = this; return this._pc.getStats().then(result => filterStats(result, receiver.track, false)); }; } if (!('getStats' in window.RTCRtpSender.prototype && 'getStats' in window.RTCRtpReceiver.prototype)) { return; } // shim RTCPeerConnection.getStats(track). const origGetStats = window.RTCPeerConnection.prototype.getStats; window.RTCPeerConnection.prototype.getStats = function getStats() { if (arguments.length > 0 && arguments[0] instanceof window.MediaStreamTrack) { const track = arguments[0]; let sender; let receiver; let err; this.getSenders().forEach(s => { if (s.track === track) { if (sender) { err = true; } else { sender = s; } } }); this.getReceivers().forEach(r => { if (r.track === track) { if (receiver) { err = true; } else { receiver = r; } } return r.track === track; }); if (err || sender && receiver) { return Promise.reject(new DOMException('There are more than one sender or receiver for the track.', 'InvalidAccessError')); } else if (sender) { return sender.getStats(); } else if (receiver) { return receiver.getStats(); } return Promise.reject(new DOMException('There is no sender or receiver for the track.', 'InvalidAccessError')); } return origGetStats.apply(this, arguments); }; } function shimAddTrackRemoveTrackWithNative(window) { // shim addTrack/removeTrack with native variants in order to make // the interactions with legacy getLocalStreams behave as in other browsers. // Keeps a mapping stream.id => [stream, rtpsenders...] window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() { this._shimmedLocalStreams = this._shimmedLocalStreams || {}; return Object.keys(this._shimmedLocalStreams).map(streamId => this._shimmedLocalStreams[streamId][0]); }; const origAddTrack = window.RTCPeerConnection.prototype.addTrack; window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) { if (!stream) { return origAddTrack.apply(this, arguments); } this._shimmedLocalStreams = this._shimmedLocalStreams || {}; const sender = origAddTrack.apply(this, arguments); if (!this._shimmedLocalStreams[stream.id]) { this._shimmedLocalStreams[stream.id] = [stream, sender]; } else if (this._shimmedLocalStreams[stream.id].indexOf(sender) === -1) { this._shimmedLocalStreams[stream.id].push(sender); } return sender; }; const origAddStream = window.RTCPeerConnection.prototype.addStream; window.RTCPeerConnection.prototype.addStream = function addStream(stream) { this._shimmedLocalStreams = this._shimmedLocalStreams || {}; stream.getTracks().forEach(track => { const alreadyExists = this.getSenders().find(s => s.track === track); if (alreadyExists) { throw new DOMException('Track already exists.', 'InvalidAccessError'); } }); const existingSenders = this.getSenders(); origAddStream.apply(this, arguments); const newSenders = this.getSenders().filter(newSender => existingSenders.indexOf(newSender) === -1); this._shimmedLocalStreams[stream.id] = [stream].concat(newSenders); }; const origRemoveStream = window.RTCPeerConnection.prototype.removeStream; window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { this._shimmedLocalStreams = this._shimmedLocalStreams || {}; delete this._shimmedLocalStreams[stream.id]; return origRemoveStream.apply(this, arguments); }; const origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) { this._shimmedLocalStreams = this._shimmedLocalStreams || {}; if (sender) { Object.keys(this._shimmedLocalStreams).forEach(streamId => { const idx = this._shimmedLocalStreams[streamId].indexOf(sender); if (idx !== -1) { this._shimmedLocalStreams[streamId].splice(idx, 1); } if (this._shimmedLocalStreams[streamId].length === 1) { delete this._shimmedLocalStreams[streamId]; } }); } return origRemoveTrack.apply(this, arguments); }; } function shimAddTrackRemoveTrack(window, browserDetails) { if (!window.RTCPeerConnection) { return; } // shim addTrack and removeTrack. if (window.RTCPeerConnection.prototype.addTrack && browserDetails.version >= 65) { return shimAddTrackRemoveTrackWithNative(window); } // also shim pc.getLocalStreams when addTrack is shimmed // to return the original streams. const origGetLocalStreams = window.RTCPeerConnection.prototype.getLocalStreams; window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() { const nativeStreams = origGetLocalStreams.apply(this); this._reverseStreams = this._reverseStreams || {}; return nativeStreams.map(stream => this._reverseStreams[stream.id]); }; const origAddStream = window.RTCPeerConnection.prototype.addStream; window.RTCPeerConnection.prototype.addStream = function addStream(stream) { this._streams = this._streams || {}; this._reverseStreams = this._reverseStreams || {}; stream.getTracks().forEach(track => { const alreadyExists = this.getSenders().find(s => s.track === track); if (alreadyExists) { throw new DOMException('Track already exists.', 'InvalidAccessError'); } }); // Add identity mapping for consistency with addTrack. // Unless this is being used with a stream from addTrack. if (!this._reverseStreams[stream.id]) { const newStream = new window.MediaStream(stream.getTracks()); this._streams[stream.id] = newStream; this._reverseStreams[newStream.id] = stream; stream = newStream; } origAddStream.apply(this, [stream]); }; const origRemoveStream = window.RTCPeerConnection.prototype.removeStream; window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { this._streams = this._streams || {}; this._reverseStreams = this._reverseStreams || {}; origRemoveStream.apply(this, [this._streams[stream.id] || stream]); delete this._reverseStreams[this._streams[stream.id] ? this._streams[stream.id].id : stream.id]; delete this._streams[stream.id]; }; window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) { if (this.signalingState === 'closed') { throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.', 'InvalidStateError'); } const streams = [].slice.call(arguments, 1); if (streams.length !== 1 || !streams[0].getTracks().find(t => t === track)) { // this is not fully correct but all we can manage without // [[associated MediaStreams]] internal slot. throw new DOMException('The adapter.js addTrack polyfill only supports a single ' + ' stream which is associated with the specified track.', 'NotSupportedError'); } const alreadyExists = this.getSenders().find(s => s.track === track); if (alreadyExists) { throw new DOMException('Track already exists.', 'InvalidAccessError'); } this._streams = this._streams || {}; this._reverseStreams = this._reverseStreams || {}; const oldStream = this._streams[stream.id]; if (oldStream) { // this is using odd Chrome behaviour, use with caution: // https://bugs.chromium.org/p/webrtc/issues/detail?id=7815 // Note: we rely on the high-level addTrack/dtmf shim to // create the sender with a dtmf sender. oldStream.addTrack(track); // Trigger ONN async. Promise.resolve().then(() => { this.dispatchEvent(new Event('negotiationneeded')); }); } else { const newStream = new window.MediaStream([track]); this._streams[stream.id] = newStream; this._reverseStreams[newStream.id] = stream; this.addStream(newStream); } return this.getSenders().find(s => s.track === track); }; // replace the internal stream id with the external one and // vice versa. function replaceInternalStreamId(pc, description) { let sdp = description.sdp; Object.keys(pc._reverseStreams || []).forEach(internalId => { const externalStream = pc._reverseStreams[internalId]; const internalStream = pc._streams[externalStream.id]; sdp = sdp.replace(new RegExp(internalStream.id, 'g'), externalStream.id); }); return new RTCSessionDescription({ type: description.type, sdp }); } function replaceExternalStreamId(pc, description) { let sdp = description.sdp; Object.keys(pc._reverseStreams || []).forEach(internalId => { const externalStream = pc._reverseStreams[internalId]; const internalStream = pc._streams[externalStream.id]; sdp = sdp.replace(new RegExp(externalStream.id, 'g'), internalStream.id); }); return new RTCSessionDescription({ type: description.type, sdp }); } ['createOffer', 'createAnswer'].forEach(function (method) { const nativeMethod = window.RTCPeerConnection.prototype[method]; const methodObj = { [method]() { const args = arguments; const isLegacyCall = arguments.length && typeof arguments[0] === 'function'; if (isLegacyCall) { return nativeMethod.apply(this, [description => { const desc = replaceInternalStreamId(this, description); args[0].apply(null, [desc]); }, err => { if (args[1]) { args[1].apply(null, err); } }, arguments[2]]); } return nativeMethod.apply(this, arguments).then(description => replaceInternalStreamId(this, description)); } }; window.RTCPeerConnection.prototype[method] = methodObj[method]; }); const origSetLocalDescription = window.RTCPeerConnection.prototype.setLocalDescription; window.RTCPeerConnection.prototype.setLocalDescription = function setLocalDescription() { if (!arguments.length || !arguments[0].type) { return origSetLocalDescription.apply(this, arguments); } arguments[0] = replaceExternalStreamId(this, arguments[0]); return origSetLocalDescription.apply(this, arguments); }; // TODO: mangle getStats: https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamstats-streamidentifier const origLocalDescription = Object.getOwnPropertyDescriptor(window.RTCPeerConnection.prototype, 'localDescription'); Object.defineProperty(window.RTCPeerConnection.prototype, 'localDescription', { get() { const description = origLocalDescription.get.apply(this); if (description.type === '') { return description; } return replaceInternalStreamId(this, description); } }); window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) { if (this.signalingState === 'closed') { throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.', 'InvalidStateError'); } // We can not yet check for sender instanceof RTCRtpSender // since we shim RTPSender. So we check if sender._pc is set. if (!sender._pc) { throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack ' + 'does not implement interface RTCRtpSender.', 'TypeError'); } const isLocal = sender._pc === this; if (!isLocal) { throw new DOMException('Sender was not created by this connection.', 'InvalidAccessError'); } // Search for the native stream the senders track belongs to. this._streams = this._streams || {}; let stream; Object.keys(this._streams).forEach(streamid => { const hasTrack = this._streams[streamid].getTracks().find(track => sender.track === track); if (hasTrack) { stream = this._streams[streamid]; } }); if (stream) { if (stream.getTracks().length === 1) { // if this is the last track of the stream, remove the stream. This // takes care of any shimmed _senders. this.removeStream(this._reverseStreams[stream.id]); } else { // relying on the same odd chrome behaviour as above. stream.removeTrack(sender.track); } this.dispatchEvent(new Event('negotiationneeded')); } }; } function shimPeerConnection$1(window, browserDetails) { if (!window.RTCPeerConnection && window.webkitRTCPeerConnection) { // very basic support for old versions. window.RTCPeerConnection = window.webkitRTCPeerConnection; } if (!window.RTCPeerConnection) { return; } // shim implicit creation of RTCSessionDescription/RTCIceCandidate if (browserDetails.version < 53) { ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'].forEach(function (method) { const nativeMethod = window.RTCPeerConnection.prototype[method]; const methodObj = { [method]() { arguments[0] = new (method === 'addIceCandidate' ? window.RTCIceCandidate : window.RTCSessionDescription)(arguments[0]); return nativeMethod.apply(this, arguments); } }; window.RTCPeerConnection.prototype[method] = methodObj[method]; }); } } // Attempt to fix ONN in plan-b mode. function fixNegotiationNeeded(window, browserDetails) { wrapPeerConnectionEvent(window, 'negotiationneeded', e => { const pc = e.target; if (browserDetails.version < 72 || pc.getConfiguration && pc.getConfiguration().sdpSemantics === 'plan-b') { if (pc.signalingState !== 'stable') { return; } } return e; }); } var chromeShim = /*#__PURE__*/Object.freeze({ __proto__: null, fixNegotiationNeeded: fixNegotiationNeeded, shimAddTrackRemoveTrack: shimAddTrackRemoveTrack, shimAddTrackRemoveTrackWithNative: shimAddTrackRemoveTrackWithNative, shimGetDisplayMedia: shimGetDisplayMedia$1, shimGetSendersWithDtmf: shimGetSendersWithDtmf, shimGetStats: shimGetStats, shimGetUserMedia: shimGetUserMedia$2, shimMediaStream: shimMediaStream, shimOnTrack: shimOnTrack$1, shimPeerConnection: shimPeerConnection$1, shimSenderReceiverGetStats: shimSenderReceiverGetStats }); /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. */ function shimGetUserMedia$1(window, browserDetails) { const navigator = window && window.navigator; const MediaStreamTrack = window && window.MediaStreamTrack; navigator.getUserMedia = function (constraints, onSuccess, onError) { // Replace Firefox 44+'s deprecation warning with unprefixed version. deprecated('navigator.getUserMedia', 'navigator.mediaDevices.getUserMedia'); navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError); }; if (!(browserDetails.version > 55 && 'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) { const remap = function (obj, a, b) { if (a in obj && !(b in obj)) { obj[b] = obj[a]; delete obj[a]; } }; const nativeGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices); navigator.mediaDevices.getUserMedia = function (c) { if (typeof c === 'object' && typeof c.audio === 'object') { c = JSON.parse(JSON.stringify(c)); remap(c.audio, 'autoGainControl', 'mozAutoGainControl'); remap(c.audio, 'noiseSuppression', 'mozNoiseSuppression'); } return nativeGetUserMedia(c); }; if (MediaStreamTrack && MediaStreamTrack.prototype.getSettings) { const nativeGetSettings = MediaStreamTrack.prototype.getSettings; MediaStreamTrack.prototype.getSettings = function () { const obj = nativeGetSettings.apply(this, arguments); remap(obj, 'mozAutoGainControl', 'autoGainControl'); remap(obj, 'mozNoiseSuppression', 'noiseSuppression'); return obj; }; } if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) { const nativeApplyConstraints = MediaStreamTrack.prototype.applyConstraints; MediaStreamTrack.prototype.applyConstraints = function (c) { if (this.kind === 'audio' && typeof c === 'object') { c = JSON.parse(JSON.stringify(c)); remap(c, 'autoGainControl', 'mozAutoGainControl'); remap(c, 'noiseSuppression', 'mozNoiseSuppression'); } return nativeApplyConstraints.apply(this, [c]); }; } } } /* * Copyright (c) 2018 The adapter.js project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. */ function shimGetDisplayMedia(window, preferredMediaSource) { if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) { return; } if (!window.navigator.mediaDevices) { return; } window.navigator.mediaDevices.getDisplayMedia = function getDisplayMedia(constraints) { if (!(constraints && constraints.video)) { const err = new DOMException('getDisplayMedia without video ' + 'constraints is undefined'); err.name = 'NotFoundError'; // from https://heycam.github.io/webidl/#idl-DOMException-error-names err.code = 8; return Promise.reject(err); } if (constraints.video === true) { constraints.video = { mediaSource: preferredMediaSource }; } else { constraints.video.mediaSource = preferredMediaSource; } return window.navigator.mediaDevices.getUserMedia(constraints); }; } /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. */ function shimOnTrack(window) { if (typeof window === 'object' && window.RTCTrackEvent && 'receiver' in window.RTCTrackEvent.prototype && !('transceiver' in window.RTCTrackEvent.prototype)) { Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { get() { return { receiver: this.receiver }; } }); } } function shimPeerConnection(window, browserDetails) { if (typeof window !== 'object' || !(window.RTCPeerConnection || window.mozRTCPeerConnection)) { return; // probably media.peerconnection.enabled=false in about:config } if (!window.RTCPeerConnection && window.mozRTCPeerConnection) { // very basic support for old versions. window.RTCPeerConnection = window.mozRTCPeerConnection; } if (browserDetails.version < 53) { // shim away need for obsolete RTCIceCandidate/RTCSessionDescription. ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'].forEach(function (method) { const nativeMethod = window.RTCPeerConnection.prototype[method]; const methodObj = { [method]() { arguments[0] = new (method === 'addIceCandidate' ? window.RTCIceCandidate : window.RTCSessionDescription)(arguments[0]); return nativeMethod.apply(this, arguments); } }; window.RTCPeerConnection.prototype[method] = methodObj[method]; }); } const modernStatsTypes = { inboundrtp: 'inbound-rtp', outboundrtp: 'outbound-rtp', candidatepair: 'candidate-pair', localcandidate: 'local-candidate', remotecandidate: 'remote-candidate' }; const nativeGetStats = window.RTCPeerConnection.prototype.getStats; window.RTCPeerConnection.prototype.getStats = function getStats() { const [selector, onSucc, onErr] = arguments; return nativeGetStats.apply(this, [selector || null]).then(stats => { if (browserDetails.version < 53 && !onSucc) { // Shim only promise getStats with spec-hyphens in type names // Leave callback version alone; misc old uses of forEach before Map try { stats.forEach(stat => { stat.type = modernStatsTypes[stat.type] || stat.type; }); } catch (e) { if (e.name !== 'TypeError') { throw e; } // Avoid TypeError: "type" is read-only, in old versions. 34-43ish stats.forEach((stat, i) => { stats.set(i, Object.assign({}, stat, { type: modernStatsTypes[stat.type] || stat.type })); }); } } return stats; }).then(onSucc, onErr); }; } function shimSenderGetStats(window) { if (!(typeof window === 'object' && window.RTCPeerConnection && window.RTCRtpSender)) { return; } if (window.RTCRtpSender && 'getStats' in window.RTCRtpSender.prototype) { return; } const origGetSenders = window.RTCPeerConnection.prototype.getSenders; if (origGetSenders) { window.RTCPeerConnection.prototype.getSenders = function getSenders() { const senders = origGetSenders.apply(this, []); senders.forEach(sender => sender._pc = this); return senders; }; } const origAddTrack = window.RTCPeerConnection.prototype.addTrack; if (origAddTrack) { window.RTCPeerConnection.prototype.addTrack = function addTrack() { const sender = origAddTrack.apply(this, arguments); sender._pc = this; return sender; }; } window.RTCRtpSender.prototype.getStats = function getStats() { return this.track ? this._pc.getStats(this.track) : Promise.resolve(new Map()); }; } function shimReceiverGetStats(window) { if (!(typeof window === 'object' && window.RTCPeerConnection && window.RTCRtpSender)) { return; } if (window.RTCRtpSender && 'getStats' in window.RTCRtpReceiver.prototype) { return; } const origGetReceivers = window.RTCPeerConnection.prototype.getReceivers; if (origGetReceivers) { window.RTCPeerConnection.prototype.getReceivers = function getReceivers() { const receivers = origGetReceivers.apply(this, []); receivers.forEach(receiver => receiver._pc = this); return receivers; }; } wrapPeerConnectionEvent(window, 'track', e => { e.receiver._pc = e.srcElement; return e; }); window.RTCRtpReceiver.prototype.getStats = function getStats() { return this._pc.getStats(this.track); }; } function shimRemoveStream(window) { if (!window.RTCPeerConnection || 'removeStream' in window.RTCPeerConnection.prototype) { return; } window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { deprecated('removeStream', 'removeTrack'); this.getSenders().forEach(sender => { if (sender.track && stream.getTracks().includes(sender.track)) { this.removeTrack(sender); } }); }; } function shimRTCDataChannel(window) { // rename DataChannel to RTCDataChannel (native fix in FF60): // https://bugzilla.mozilla.org/show_bug.cgi?id=1173851 if (window.DataChannel && !window.RTCDataChannel) { window.RTCDataChannel = window.DataChannel; } } function shimAddTransceiver(window) { // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647 // Firefox ignores the init sendEncodings options passed to addTransceiver // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918 if (!(typeof window === 'object' && window.RTCPeerConnection)) { return; } const origAddTransceiver = window.RTCPeerConnection.prototype.addTransceiver; if (origAddTransceiver) { window.RTCPeerConnection.prototype.addTransceiver = function addTransceiver() { this.setParametersPromises = []; const initParameters = arguments[1]; const shouldPerformCheck = initParameters && 'sendEncodings' in initParameters; if (shouldPerformCheck) { // If sendEncodings params are provided, validate grammar initParameters.sendEncodings.forEach(encodingParam => { if ('rid' in encodingParam) { const ridRegex = /^[a-z0-9]{0,16}$/i; if (!ridRegex.test(encodingParam.rid)) { throw new TypeError('Invalid RID value provided.'); } } if ('scaleResolutionDownBy' in encodingParam) { if (!(parseFloat(encodingParam.scaleResolutionDownBy) >= 1.0)) { throw new RangeError('scale_resolution_down_by must be >= 1.0'); } } if ('maxFramerate' in encodingParam) { if (!(parseFloat(encodingParam.maxFramerate) >= 0)) { throw new RangeError('max_framerate must be >= 0.0'); } } }); } const transceiver = origAddTransceiver.apply(this, arguments); if (shouldPerformCheck) { // Check if the init options were applied. If not we do this in an // asynchronous way and save the promise reference in a global object. // This is an ugly hack, but at the same time is way more robust than // checking the sender parameters before and after the createOffer // Also note that after the createoffer we are not 100% sure that // the params were asynchronously applied so we might miss the // opportunity to recreate offer. const { sender } = transceiver; const params = sender.getParameters(); if (!('encodings' in params) || // Avoid being fooled by patched getParameters() below. params.encodings.length === 1 && Object.keys(params.encodings[0]).length === 0) { params.encodings = initParameters.sendEncodings; sender.sendEncodings = initParameters.sendEncodings; this.setParametersPromises.push(sender.setParameters(params).then(() => { delete sender.sendEncodings; }).catch(() => { delete sender.sendEncodings; })); } } return transceiver; }; } } function shimGetParameters(window) { if (!(typeof window === 'object' && window.RTCRtpSender)) { return; } const origGetParameters = window.RTCRtpSender.prototype.getParameters; if (origGetParameters) { window.RTCRtpSender.prototype.getParameters = function getParameters() { const params = origGetParameters.apply(this, arguments); if (!('encodings' in params)) { params.encodings = [].concat(this.sendEncodings || [{}]); } return params; }; } } function shimCreateOffer(window) { // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647 // Firefox ignores the init sendEncodings options passed to addTransceiver // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918 if (!(typeof window === 'object' && window.RTCPeerConnection)) { return; } const origCreateOffer = window.RTCPeerConnection.prototype.createOffer; window.RTCPeerConnection.prototype.createOffer = function createOffer() { if (this.setParametersPromises && this.setParametersPromises.length) { return Promise.all(this.setParametersPromises).then(() => { return origCreateOffer.apply(this, arguments); }).finally(() => { this.setParametersPromises = []; }); } return origCreateOffer.apply(this, arguments); }; } function shimCreateAnswer(window) { // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647 // Firefox ignores the init sendEncodings options passed to addTransceiver // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918 if (!(typeof window === 'object' && window.RTCPeerConnection)) { return; } const origCreateAnswer = window.RTCPeerConnection.prototype.createAnswer; window.RTCPeerConnection.prototype.createAnswer = function createAnswer() { if (this.setParametersPromises && this.setParametersPromises.length) { return Promise.all(this.setParametersPromises).then(() => { return origCreateAnswer.apply(this, arguments); }).finally(() => { this.setParametersPromises = []; }); } return origCreateAnswer.apply(this, arguments); }; } var firefoxShim = /*#__PURE__*/Object.freeze({ __proto__: null, shimAddTransceiver: shimAddTransceiver, shimCreateAnswer: shimCreateAnswer, shimCreateOffer: shimCreateOffer, shimGetDisplayMedia: shimGetDisplayMedia, shimGetParameters: shimGetParameters, shimGetUserMedia: shimGetUserMedia$1, shimOnTrack: shimOnTrack, shimPeerConnection: shimPeerConnection, shimRTCDataChannel: shimRTCDataChannel, shimReceiverGetStats: shimReceiverGetStats, shimRemoveStream: shimRemoveStream, shimSenderGetStats: shimSenderGetStats }); /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. */ function shimLocalStreamsAPI(window) { if (typeof window !== 'object' || !window.RTCPeerConnection) { return; } if (!('getLocalStreams' in window.RTCPeerConnection.prototype)) { window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() { if (!this._localStreams) { this._localStreams = []; } return this._localStreams; }; } if (!('addStream' in window.RTCPeerConnection.prototype)) { const _addTrack = window.RTCPeerConnection.prototype.addTrack; window.RTCPeerConnection.prototype.addStream = function addStream(stream) { if (!this._localStreams) { this._localStreams = []; } if (!this._localStreams.includes(stream)) { this._localStreams.push(stream); } // Try to emulate Chrome's behaviour of adding in audio-video order. // Safari orders by track id. stream.getAudioTracks().forEach(track => _addTrack.call(this, track, stream)); stream.getVideoTracks().forEach(track => _addTrack.call(this, track, stream)); }; window.RTCPeerConnection.prototype.addTrack = function addTrack(track) { for (var _len = arguments.length, streams = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { streams[_key - 1] = arguments[_key]; } if (streams) { streams.forEach(stream => { if (!this._localStreams) { this._localStreams = [stream]; } else if (!this._localStreams.includes(stream)) { this._localStreams.push(stream); } }); } return _addTrack.apply(this, arguments); }; } if (!('removeStream' in window.RTCPeerConnection.prototype)) { window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { if (!this._localStreams) { this._localStreams = []; } const index = this._localStreams.indexOf(stream); if (index === -1) { return; } this._localStreams.splice(index, 1); const tracks = stream.getTracks(); this.getSenders().forEach(sender => { if (tracks.includes(sender.track)) { this.removeTrack(sender); } }); }; } } function shimRemoteStreamsAPI(window) { if (typeof window !== 'object' || !window.RTCPeerConnection) { return; } if (!('getRemoteStreams' in window.RTCPeerConnection.prototype)) { window.RTCPeerConnection.prototype.getRemoteStreams = function getRemoteStreams() { return this._remoteStreams ? this._remoteStreams : []; }; } if (!('onaddstream' in window.RTCPeerConnection.prototype)) { Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', { get() { return this._onaddstream; }, set(f) { if (this._onaddstream) { this.removeEventListener('addstream', this._onaddstream); this.removeEventListener('track', this._onaddstreampoly); } this.addEventListener('addstream', this._onaddstream = f); this.addEventListener('track', this._onaddstreampoly = e => { e.streams.forEach(stream => { if (!this._remoteStreams) { this._remoteStreams = []; } if (this._remoteStreams.includes(stream)) { return; } this._remoteStreams.push(stream); const event = new Event('addstream'); event.stream = stream; this.dispatchEvent(event); }); }); } }); const origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() { const pc = this; if (!this._onaddstreampoly) { this.addEventListener('track', this._onaddstreampoly = function (e) { e.streams.forEach(stream => { if (!pc._remoteStreams) { pc._remoteStreams = []; } if (pc._remoteStreams.indexOf(stream) >= 0) { return; } pc._remoteStreams.push(stream); const event = new Event('addstream'); event.stream = stream; pc.dispatchEvent(event); }); }); } return origSetRemoteDescription.apply(pc, arguments); }; } } function shimCallbacksAPI(window) { if (typeof window !== 'object' || !window.RTCPeerConnection) { return; } const prototype = window.RTCPeerConnection.prototype; const origCreateOffer = prototype.createOffer; const origCreateAnswer = prototype.createAnswer; const setLocalDescription = prototype.setLocalDescription; const setRemoteDescription = prototype.setRemoteDescription; const addIceCandidate = prototype.addIceCandidate; prototype.createOffer = function createOffer(successCallback, failureCallback) { const options = arguments.length >= 2 ? arguments[2] : arguments[0]; const promise = origCreateOffer.apply(this, [options]); if (!failureCallback) { return promise; } promise.then(successCallback, failureCallback); return Promise.resolve(); }; prototype.createAnswer = function createAnswer(successCallback, failureCallback) { const options = arguments.length >= 2 ? arguments[2] : arguments[0]; const promise = origCreateAnswer.apply(this, [options]); if (!failureCallback) { return promise; } promise.then(successCallback, failureCallback); return Promise.resolve(); }; let withCallback = function (description, successCallback, failureCallback) { const promise = setLocalDescription.apply(this, [description]); if (!failureCallback) { return promise; } promise.then(successCallback, failureCallback); return Promise.resolve(); }; prototype.setLocalDescription = withCallback; withCallback = function (description, successCallback, failureCallback) { const promise = setRemoteDescription.apply(this, [description]); if (!failureCallback) { return promise; } promise.then(successCallback, failureCallback); return Promise.resolve(); }; prototype.setRemoteDescription = withCallback; withCallback = function (candidate, successCallback, failureCallback) { const promise = addIceCandidate.apply(this, [candidate]); if (!failureCallback) { return promise; } promise.then(successCallback, failureCallback); return Promise.resolve(); }; prototype.addIceCandidate = withCallback; } function shimGetUserMedia(window) { const navigator = window && window.navigator; if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { // shim not needed in Safari 12.1 const mediaDevices = navigator.mediaDevices; const _getUserMedia = mediaDevices.getUserMedia.bind(mediaDevices); navigator.mediaDevices.getUserMedia = constraints => { return _getUserMedia(shimConstraints(constraints)); }; } if (!navigator.getUserMedia && navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { navigator.getUserMedia = function getUserMedia(constraints, cb, errcb) { navigator.mediaDevices.getUserMedia(constraints).then(cb, errcb); }.bind(navigator); } } function shimConstraints(constraints) { if (constraints && constraints.video !== undefined) { return Object.assign({}, constraints, { video: compactObject(constraints.video) }); } return constraints; } function shimRTCIceServerUrls(window) { if (!window.RTCPeerConnection) { return; } // migrate from non-spec RTCIceServer.url to RTCIceServer.urls const OrigPeerConnection = window.RTCPeerConnection; window.RTCPeerConnection = function RTCPeerConnection(pcConfig, pcConstraints) { if (pcConfig && pcConfig.iceServers) { const newIceServers = []; for (let i = 0; i < pcConfig.iceServers.length; i++) { let server = pcConfig.iceServers[i]; if (!server.hasOwnProperty('urls') && server.hasOwnProperty('url')) { deprecated('RTCIceServer.url', 'RTCIceServer.urls'); server = JSON.parse(JSON.stringify(server)); server.urls = server.url; delete server.url; newIceServers.push(server); } else { newIceServers.push(pcConfig.iceServers[i]); } } pcConfig.iceServers = newIceServers; } return new OrigPeerConnection(pcConfig, pcConstraints); }; window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; // wrap static methods. Currently just generateCertificate. if ('generateCertificate' in OrigPeerConnection) { Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { get() { return OrigPeerConnection.generateCertificate; } }); } } function shimTrackEventTransceiver(window) { // Add event.transceiver member over deprecated event.receiver if (typeof window === 'object' && window.RTCTrackEvent && 'receiver' in window.RTCTrackEvent.prototype && !('transceiver' in window.RTCTrackEvent.prototype)) { Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { get() { return { receiver: this.receiver }; } }); } } function shimCreateOfferLegacy(window) { const origCreateOffer = window.RTCPeerConnection.prototype.createOffer; window.RTCPeerConnection.prototype.createOffer = function createOffer(offerOptions) { if (offerOptions) { if (typeof offerOptions.offerToReceiveAudio !== 'undefined') { // support bit values offerOptions.offerToReceiveAudio = !!offerOptions.offerToReceiveAudio; } const audioTransceiver = this.getTransceivers().find(transceiver => transceiver.receiver.track.kind === 'audio'); if (offerOptions.offerToReceiveAudio === false && audioTransceiver) { if (audioTransceiver.direction === 'sendrecv') { if (audioTransceiver.setDirection) { audioTransceiver.setDirection('sendonly'); } else { audioTransceiver.direction = 'sendonly'; } } else if (audioTransceiver.direction === 'recvonly') { if (audioTransceiver.setDirection) { audioTransceiver.setDirection('inactive'); } else { audioTransceiver.direction = 'inactive'; } } } else if (offerOptions.offerToReceiveAudio === true && !audioTransceiver) { this.addTransceiver('audio', { direction: 'recvonly' }); } if (typeof offerOptions.offerToReceiveVideo !== 'undefined') { // support bit values offerOptions.offerToReceiveVideo = !!offerOptions.offerToReceiveVideo; } const videoTransceiver = this.getTransceivers().find(transceiver => transceiver.receiver.track.kind === 'video'); if (offerOptions.offerToReceiveVideo === false && videoTransceiver) { if (videoTransceiver.direction === 'sendrecv') { if (videoTransceiver.setDirection) { videoTransceiver.setDirection('sendonly'); } else { videoTransceiver.direction = 'sendonly'; } } else if (videoTransceiver.direction === 'recvonly') { if (videoTransceiver.setDirection) { videoTransceiver.setDirection('inactive'); } else { videoTransceiver.direction = 'inactive'; } } } else if (offerOptions.offerToReceiveVideo === true && !videoTransceiver) { this.addTransceiver('video', { direction: 'recvonly' }); } } return origCreateOffer.apply(this, arguments); }; } function shimAudioContext(window) { if (typeof window !== 'object' || window.AudioContext) { return; } window.AudioContext = window.webkitAudioContext; } var safariShim = /*#__PURE__*/Object.freeze({ __proto__: null, shimAudioContext: shimAudioContext, shimCallbacksAPI: shimCallbacksAPI, shimConstraints: shimConstraints, shimCreateOfferLegacy: shimCreateOfferLegacy, shimGetUserMedia: shimGetUserMedia, shimLocalStreamsAPI: shimLocalStreamsAPI, shimRTCIceServerUrls: shimRTCIceServerUrls, shimRemoteStreamsAPI: shimRemoteStreamsAPI, shimTrackEventTransceiver: shimTrackEventTransceiver }); var sdpExports = {}; var sdp$1 = { get exports(){ return sdpExports; }, set exports(v){ sdpExports = v; }, }; /* eslint-env node */ (function (module) { // SDP helpers. const SDPUtils = {}; // Generate an alphanumeric identifier for cname or mids. // TODO: use UUIDs instead? https://gist.github.com/jed/982883 SDPUtils.generateIdentifier = function () { return Math.random().toString(36).substr(2, 10); }; // The RTCP CNAME used by all peerconnections from the same JS. SDPUtils.localCName = SDPUtils.generateIdentifier(); // Splits SDP into lines, dealing with both CRLF and LF. SDPUtils.splitLines = function (blob) { return blob.trim().split('\n').map(line => line.trim()); }; // Splits SDP into sessionpart and mediasections. Ensures CRLF. SDPUtils.splitSections = function (blob) { const parts = blob.split('\nm='); return parts.map((part, index) => (index > 0 ? 'm=' + part : part).trim() + '\r\n'); }; // Returns the session description. SDPUtils.getDescription = function (blob) { const sections = SDPUtils.splitSections(blob); return sections && sections[0]; }; // Returns the individual media sections. SDPUtils.getMediaSections = function (blob) { const sections = SDPUtils.splitSections(blob); sections.shift(); return sections; }; // Returns lines that start with a certain prefix. SDPUtils.matchPrefix = function (blob, prefix) { return SDPUtils.splitLines(blob).filter(line => line.indexOf(prefix) === 0); }; // Parses an ICE candidate line. Sample input: // candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8 // rport 55996" // Input can be prefixed with a=. SDPUtils.parseCandidate = function (line) { let parts; // Parse both variants. if (line.indexOf('a=candidate:') === 0) { parts = line.substring(12).split(' '); } else { parts = line.substring(10).split(' '); } const candidate = { foundation: parts[0], component: { 1: 'rtp', 2: 'rtcp' }[parts[1]] || parts[1], protocol: parts[2].toLowerCase(), priority: parseInt(parts[3], 10), ip: parts[4], address: parts[4], // address is an alias for ip. port: parseInt(parts[5], 10), // skip parts[6] == 'typ' type: parts[7] }; for (let i = 8; i < parts.length; i += 2) { switch (parts[i]) { case 'raddr': candidate.relatedAddress = parts[i + 1]; break; case 'rport': candidate.relatedPort = parseInt(parts[i + 1], 10); break; case 'tcptype': candidate.tcpType = parts[i + 1]; break; case 'ufrag': candidate.ufrag = parts[i + 1]; // for backward compatibility. candidate.usernameFragment = parts[i + 1]; break; default: // extension handling, in particular ufrag. Don't overwrite. if (candidate[parts[i]] === undefined) { candidate[parts[i]] = parts[i + 1]; } break; } } return candidate; }; // Translates a candidate object into SDP candidate attribute. // This does not include the a= prefix! SDPUtils.writeCandidate = function (candidate) { const sdp = []; sdp.push(candidate.foundation); const component = candidate.component; if (component === 'rtp') { sdp.push(1); } else if (component === 'rtcp') { sdp.push(2); } else { sdp.push(component); } sdp.push(candidate.protocol.toUpperCase()); sdp.push(candidate.priority); sdp.push(candidate.address || candidate.ip); sdp.push(candidate.port); const type = candidate.type; sdp.push('typ'); sdp.push(type); if (type !== 'host' && candidate.relatedAddress && candidate.relatedPort) { sdp.push('raddr'); sdp.push(candidate.relatedAddress); sdp.push('rport'); sdp.push(candidate.relatedPort); } if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') { sdp.push('tcptype'); sdp.push(candidate.tcpType); } if (candidate.usernameFragment || candidate.ufrag) { sdp.push('ufrag'); sdp.push(candidate.usernameFragment || candidate.ufrag); } return 'candidate:' + sdp.join(' '); }; // Parses an ice-options line, returns an array of option tags. // Sample input: // a=ice-options:foo bar SDPUtils.parseIceOptions = function (line) { return line.substr(14).split(' '); }; // Parses a rtpmap line, returns RTCRtpCoddecParameters. Sample input: // a=rtpmap:111 opus/48000/2 SDPUtils.parseRtpMap = function (line) { let parts = line.substr(9).split(' '); const parsed = { payloadType: parseInt(parts.shift(), 10) // was: id }; parts = parts[0].split('/'); parsed.name = parts[0]; parsed.clockRate = parseInt(parts[1], 10); // was: clockrate parsed.channels = parts.length === 3 ? parseInt(parts[2], 10) : 1; // legacy alias, got renamed back to channels in ORTC. parsed.numChannels = parsed.channels; return parsed; }; // Generates a rtpmap line from RTCRtpCodecCapability or // RTCRtpCodecParameters. SDPUtils.writeRtpMap = function (codec) { let pt = codec.payloadType; if (codec.preferredPayloadType !== undefined) { pt = codec.preferredPayloadType; } const channels = codec.channels || codec.numChannels || 1; return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate + (channels !== 1 ? '/' + channels : '') + '\r\n'; }; // Parses a extmap line (headerextension from RFC 5285). Sample input: // a=extmap:2 urn:ietf:params:rtp-hdrext:toffset // a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset SDPUtils.parseExtmap = function (line) { const parts = line.substr(9).split(' '); return { id: parseInt(parts[0], 10), direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv', uri: parts[1] }; }; // Generates an extmap line from RTCRtpHeaderExtensionParameters or // RTCRtpHeaderExtension. SDPUtils.writeExtmap = function (headerExtension) { return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) + (headerExtension.direction && headerExtension.direction !== 'sendrecv' ? '/' + headerExtension.direction : '') + ' ' + headerExtension.uri + '\r\n'; }; // Parses a fmtp line, returns dictionary. Sample input: // a=fmtp:96 vbr=on;cng=on // Also deals with vbr=on; cng=on SDPUtils.parseFmtp = function (line) { const parsed = {}; let kv; const parts = line.substr(line.indexOf(' ') + 1).split(';'); for (let j = 0; j < parts.length; j++) { kv = parts[j].trim().split('='); parsed[kv[0].trim()] = kv[1]; } return parsed; }; // Generates a fmtp line from RTCRtpCodecCapability or RTCRtpCodecParameters. SDPUtils.writeFmtp = function (codec) { let line = ''; let pt = codec.payloadType; if (codec.preferredPayloadType !== undefined) { pt = codec.preferredPayloadType; } if (codec.parameters && Object.keys(codec.parameters).length) { const params = []; Object.keys(codec.parameters).forEach(param => { if (codec.parameters[param] !== undefined) { params.push(param + '=' + codec.parameters[param]); } else { params.push(param); } }); line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n'; } return line; }; // Parses a rtcp-fb line, returns RTCPRtcpFeedback object. Sample input: // a=rtcp-fb:98 nack rpsi SDPUtils.parseRtcpFb = function (line) { const parts = line.substr(line.indexOf(' ') + 1).split(' '); return { type: parts.shift(), parameter: parts.join(' ') }; }; // Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters. SDPUtils.writeRtcpFb = function (codec) { let lines = ''; let pt = codec.payloadType; if (codec.preferredPayloadType !== undefined) { pt = codec.preferredPayloadType; } if (codec.rtcpFeedback && codec.rtcpFeedback.length) { // FIXME: special handling for trr-int? codec.rtcpFeedback.forEach(fb => { lines += 'a=rtcp-fb:' + pt + ' ' + fb.type + (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') + '\r\n'; }); } return lines; }; // Parses a RFC 5576 ssrc media attribute. Sample input: // a=ssrc:3735928559 cname:something SDPUtils.parseSsrcMedia = function (line) { const sp = line.indexOf(' '); const parts = { ssrc: parseInt(line.substr(7, sp - 7), 10) }; const colon = line.indexOf(':', sp); if (colon > -1) { parts.attribute = line.substr(sp + 1, colon - sp - 1); parts.value = line.substr(colon + 1); } else { parts.attribute = line.substr(sp + 1); } return parts; }; // Parse a ssrc-group line (see RFC 5576). Sample input: // a=ssrc-group:semantics 12 34 SDPUtils.parseSsrcGroup = function (line) { const parts = line.substr(13).split(' '); return { semantics: parts.shift(), ssrcs: parts.map(ssrc => parseInt(ssrc, 10)) }; }; // Extracts the MID (RFC 5888) from a media section. // Returns the MID or undefined if no mid line was found. SDPUtils.getMid = function (mediaSection) { const mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0]; if (mid) { return mid.substr(6); } }; // Parses a fingerprint line for DTLS-SRTP. SDPUtils.parseFingerprint = function (line) { const parts = line.substr(14).split(' '); return { algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge. value: parts[1].toUpperCase() // the definition is upper-case in RFC 4572. }; }; // Extracts DTLS parameters from SDP media section or sessionpart. // FIXME: for consistency with other functions this should only // get the fingerprint line as input. See also getIceParameters. SDPUtils.getDtlsParameters = function (mediaSection, sessionpart) { const lines = SDPUtils.matchPrefix(mediaSection + sessionpart, 'a=fingerprint:'); // Note: a=setup line is ignored since we use the 'auto' role in Edge. return { role: 'auto', fingerprints: lines.map(SDPUtils.parseFingerprint) }; }; // Serializes DTLS parameters to SDP. SDPUtils.writeDtlsParameters = function (params, setupType) { let sdp = 'a=setup:' + setupType + '\r\n'; params.fingerprints.forEach(fp => { sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n'; }); return sdp; }; // Parses a=crypto lines into // https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#dictionary-rtcsrtpsdesparameters-members SDPUtils.parseCryptoLine = function (line) { const parts = line.substr(9).split(' '); return { tag: parseInt(parts[0], 10), cryptoSuite: parts[1], keyParams: parts[2], sessionParams: parts.slice(3) }; }; SDPUtils.writeCryptoLine = function (parameters) { return 'a=crypto:' + parameters.tag + ' ' + parameters.cryptoSuite + ' ' + (typeof parameters.keyParams === 'object' ? SDPUtils.writeCryptoKeyParams(parameters.keyParams) : parameters.keyParams) + (parameters.sessionParams ? ' ' + parameters.sessionParams.join(' ') : '') + '\r\n'; }; // Parses the crypto key parameters into // https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#rtcsrtpkeyparam* SDPUtils.parseCryptoKeyParams = function (keyParams) { if (keyParams.indexOf('inline:') !== 0) { return null; } const parts = keyParams.substr(7).split('|'); return { keyMethod: 'inline', keySalt: parts[0], lifeTime: parts[1], mkiValue: parts[2] ? parts[2].split(':')[0] : undefined, mkiLength: parts[2] ? parts[2].split(':')[1] : undefined }; }; SDPUtils.writeCryptoKeyParams = function (keyParams) { return keyParams.keyMethod + ':' + keyParams.keySalt + (keyParams.lifeTime ? '|' + keyParams.lifeTime : '') + (keyParams.mkiValue && keyParams.mkiLength ? '|' + keyParams.mkiValue + ':' + keyParams.mkiLength : ''); }; // Extracts all SDES parameters. SDPUtils.getCryptoParameters = function (mediaSection, sessionpart) { const lines = SDPUtils.matchPrefix(mediaSection + sessionpart, 'a=crypto:'); return lines.map(SDPUtils.parseCryptoLine); }; // Parses ICE information from SDP media section or sessionpart. // FIXME: for consistency with other functions this should only // get the ice-ufrag and ice-pwd lines as input. SDPUtils.getIceParameters = function (mediaSection, sessionpart) { const ufrag = SDPUtils.matchPrefix(mediaSection + sessionpart, 'a=ice-ufrag:')[0]; const pwd = SDPUtils.matchPrefix(mediaSection + sessionpart, 'a=ice-pwd:')[0]; if (!(ufrag && pwd)) { return null; } return { usernameFragment: ufrag.substr(12), password: pwd.substr(10) }; }; // Serializes ICE parameters to SDP. SDPUtils.writeIceParameters = function (params) { let sdp = 'a=ice-ufrag:' + params.usernameFragment + '\r\n' + 'a=ice-pwd:' + params.password + '\r\n'; if (params.iceLite) { sdp += 'a=ice-lite\r\n'; } return sdp; }; // Parses the SDP media section and returns RTCRtpParameters. SDPUtils.parseRtpParameters = function (mediaSection) { const description = { codecs: [], headerExtensions: [], fecMechanisms: [], rtcp: [] }; const lines = SDPUtils.splitLines(mediaSection); const mline = lines[0].split(' '); for (let i = 3; i < mline.length; i++) { // find all codecs from mline[3..] const pt = mline[i]; const rtpmapline = SDPUtils.matchPrefix(mediaSection, 'a=rtpmap:' + pt + ' ')[0]; if (rtpmapline) { const codec = SDPUtils.parseRtpMap(rtpmapline); const fmtps = SDPUtils.matchPrefix(mediaSection, 'a=fmtp:' + pt + ' '); // Only the first a=fmtp: is considered. codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {}; codec.rtcpFeedback = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-fb:' + pt + ' ').map(SDPUtils.parseRtcpFb); description.codecs.push(codec); // parse FEC mechanisms from rtpmap lines. switch (codec.name.toUpperCase()) { case 'RED': case 'ULPFEC': description.fecMechanisms.push(codec.name.toUpperCase()); break; } } } SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(line => { description.headerExtensions.push(SDPUtils.parseExtmap(line)); }); // FIXME: parse rtcp. return description; }; // Generates parts of the SDP media section describing the capabilities / // parameters. SDPUtils.writeRtpDescription = function (kind, caps) { let sdp = ''; // Build the mline. sdp += 'm=' + kind + ' '; sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs. sdp += ' UDP/TLS/RTP/SAVPF '; sdp += caps.codecs.map(codec => { if (codec.preferredPayloadType !== undefined) { return codec.preferredPayloadType; } return codec.payloadType; }).join(' ') + '\r\n'; sdp += 'c=IN IP4 0.0.0.0\r\n'; sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n'; // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb. caps.codecs.forEach(codec => { sdp += SDPUtils.writeRtpMap(codec); sdp += SDPUtils.writeFmtp(codec); sdp += SDPUtils.writeRtcpFb(codec); }); let maxptime = 0; caps.codecs.forEach(codec => { if (codec.maxptime > maxptime) { maxptime = codec.maxptime; } }); if (maxptime > 0) { sdp += 'a=maxptime:' + maxptime + '\r\n'; } if (caps.headerExtensions) { caps.headerExtensions.forEach(extension => { sdp += SDPUtils.writeExtmap(extension); }); } // FIXME: write fecMechanisms. return sdp; }; // Parses the SDP media section and returns an array of // RTCRtpEncodingParameters. SDPUtils.parseRtpEncodingParameters = function (mediaSection) { const encodingParameters = []; const description = SDPUtils.parseRtpParameters(mediaSection); const hasRed = description.fecMechanisms.indexOf('RED') !== -1; const hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1; // filter a=ssrc:... cname:, ignore PlanB-msid const ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:').map(line => SDPUtils.parseSsrcMedia(line)).filter(parts => parts.attribute === 'cname'); const primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc; let secondarySsrc; const flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID').map(line => { const parts = line.substr(17).split(' '); return parts.map(part => parseInt(part, 10)); }); if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) { secondarySsrc = flows[0][1]; } description.codecs.forEach(codec => { if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) { let encParam = { ssrc: primarySsrc, codecPayloadType: parseInt(codec.parameters.apt, 10) }; if (primarySsrc && secondarySsrc) { encParam.rtx = { ssrc: secondarySsrc }; } encodingParameters.push(encParam); if (hasRed) { encParam = JSON.parse(JSON.stringify(encParam)); encParam.fec = { ssrc: primarySsrc, mechanism: hasUlpfec ? 'red+ulpfec' : 'red' }; encodingParameters.push(encParam); } } }); if (encodingParameters.length === 0 && primarySsrc) { encodingParameters.push({ ssrc: primarySsrc }); } // we support both b=AS and b=TIAS but interpret AS as TIAS. let bandwidth = SDPUtils.matchPrefix(mediaSection, 'b='); if (bandwidth.length) { if (bandwidth[0].indexOf('b=TIAS:') === 0) { bandwidth = parseInt(bandwidth[0].substr(7), 10); } else if (bandwidth[0].indexOf('b=AS:') === 0) { // use formula from JSEP to convert b=AS to TIAS value. bandwidth = parseInt(bandwidth[0].substr(5), 10) * 1000 * 0.95 - 50 * 40 * 8; } else { bandwidth = undefined; } encodingParameters.forEach(params => { params.maxBitrate = bandwidth; }); } return encodingParameters; }; // parses http://draft.ortc.org/#rtcrtcpparameters* SDPUtils.parseRtcpParameters = function (mediaSection) { const rtcpParameters = {}; // Gets the first SSRC. Note that with RTX there might be multiple // SSRCs. const remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:').map(line => SDPUtils.parseSsrcMedia(line)).filter(obj => obj.attribute === 'cname')[0]; if (remoteSsrc) { rtcpParameters.cname = remoteSsrc.value; rtcpParameters.ssrc = remoteSsrc.ssrc; } // Edge uses the compound attribute instead of reducedSize // compound is !reducedSize const rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize'); rtcpParameters.reducedSize = rsize.length > 0; rtcpParameters.compound = rsize.length === 0; // parses the rtcp-mux attrіbute. // Note that Edge does not support unmuxed RTCP. const mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux'); rtcpParameters.mux = mux.length > 0; return rtcpParameters; }; SDPUtils.writeRtcpParameters = function (rtcpParameters) { let sdp = ''; if (rtcpParameters.reducedSize) { sdp += 'a=rtcp-rsize\r\n'; } if (rtcpParameters.mux) { sdp += 'a=rtcp-mux\r\n'; } if (rtcpParameters.ssrc !== undefined && rtcpParameters.cname) { sdp += 'a=ssrc:' + rtcpParameters.ssrc + ' cname:' + rtcpParameters.cname + '\r\n'; } return sdp; }; // parses either a=msid: or a=ssrc:... msid lines and returns // the id of the MediaStream and MediaStreamTrack. SDPUtils.parseMsid = function (mediaSection) { let parts; const spec = SDPUtils.matchPrefix(mediaSection, 'a=msid:'); if (spec.length === 1) { parts = spec[0].substr(7).split(' '); return { stream: parts[0], track: parts[1] }; } const planB = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:').map(line => SDPUtils.parseSsrcMedia(line)).filter(msidParts => msidParts.attribute === 'msid'); if (planB.length > 0) { parts = planB[0].value.split(' '); return { stream: parts[0], track: parts[1] }; } }; // SCTP // parses draft-ietf-mmusic-sctp-sdp-26 first and falls back // to draft-ietf-mmusic-sctp-sdp-05 SDPUtils.parseSctpDescription = function (mediaSection) { const mline = SDPUtils.parseMLine(mediaSection); const maxSizeLine = SDPUtils.matchPrefix(mediaSection, 'a=max-message-size:'); let maxMessageSize; if (maxSizeLine.length > 0) { maxMessageSize = parseInt(maxSizeLine[0].substr(19), 10); } if (isNaN(maxMessageSize)) { maxMessageSize = 65536; } const sctpPort = SDPUtils.matchPrefix(mediaSection, 'a=sctp-port:'); if (sctpPort.length > 0) { return { port: parseInt(sctpPort[0].substr(12), 10), protocol: mline.fmt, maxMessageSize }; } const sctpMapLines = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:'); if (sctpMapLines.length > 0) { const parts = sctpMapLines[0].substr(10).split(' '); return { port: parseInt(parts[0], 10), protocol: parts[1], maxMessageSize }; } }; // SCTP // outputs the draft-ietf-mmusic-sctp-sdp-26 version that all browsers // support by now receiving in this format, unless we originally parsed // as the draft-ietf-mmusic-sctp-sdp-05 format (indicated by the m-line // protocol of DTLS/SCTP -- without UDP/ or TCP/) SDPUtils.writeSctpDescription = function (media, sctp) { let output = []; if (media.protocol !== 'DTLS/SCTP') { output = ['m=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.protocol + '\r\n', 'c=IN IP4 0.0.0.0\r\n', 'a=sctp-port:' + sctp.port + '\r\n']; } else { output = ['m=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.port + '\r\n', 'c=IN IP4 0.0.0.0\r\n', 'a=sctpmap:' + sctp.port + ' ' + sctp.protocol + ' 65535\r\n']; } if (sctp.maxMessageSize !== undefined) { output.push('a=max-message-size:' + sctp.maxMessageSize + '\r\n'); } return output.join(''); }; // Generate a session ID for SDP. // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1 // recommends using a cryptographically random +ve 64-bit value // but right now this should be acceptable and within the right range SDPUtils.generateSessionId = function () { return Math.random().toString().substr(2, 21); }; // Write boiler plate for start of SDP // sessId argument is optional - if not supplied it will // be generated randomly // sessVersion is optional and defaults to 2 // sessUser is optional and defaults to 'thisisadapterortc' SDPUtils.writeSessionBoilerplate = function (sessId, sessVer, sessUser) { let sessionId; const version = sessVer !== undefined ? sessVer : 2; if (sessId) { sessionId = sessId; } else { sessionId = SDPUtils.generateSessionId(); } const user = sessUser || 'thisisadapterortc'; // FIXME: sess-id should be an NTP timestamp. return 'v=0\r\n' + 'o=' + user + ' ' + sessionId + ' ' + version + ' IN IP4 127.0.0.1\r\n' + 's=-\r\n' + 't=0 0\r\n'; }; // Gets the direction from the mediaSection or the sessionpart. SDPUtils.getDirection = function (mediaSection, sessionpart) { // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv. const lines = SDPUtils.splitLines(mediaSection); for (let i = 0; i < lines.length; i++) { switch (lines[i]) { case 'a=sendrecv': case 'a=sendonly': case 'a=recvonly': case 'a=inactive': return lines[i].substr(2); // FIXME: What should happen here? } } if (sessionpart) { return SDPUtils.getDirection(sessionpart); } return 'sendrecv'; }; SDPUtils.getKind = function (mediaSection) { const lines = SDPUtils.splitLines(mediaSection); const mline = lines[0].split(' '); return mline[0].substr(2); }; SDPUtils.isRejected = function (mediaSection) { return mediaSection.split(' ', 2)[1] === '0'; }; SDPUtils.parseMLine = function (mediaSection) { const lines = SDPUtils.splitLines(mediaSection); const parts = lines[0].substr(2).split(' '); return { kind: parts[0], port: parseInt(parts[1], 10), protocol: parts[2], fmt: parts.slice(3).join(' ') }; }; SDPUtils.parseOLine = function (mediaSection) { const line = SDPUtils.matchPrefix(mediaSection, 'o=')[0]; const parts = line.substr(2).split(' '); return { username: parts[0], sessionId: parts[1], sessionVersion: parseInt(parts[2], 10), netType: parts[3], addressType: parts[4], address: parts[5] }; }; // a very naive interpretation of a valid SDP. SDPUtils.isValidSDP = function (blob) { if (typeof blob !== 'string' || blob.length === 0) { return false; } const lines = SDPUtils.splitLines(blob); for (let i = 0; i < lines.length; i++) { if (lines[i].length < 2 || lines[i].charAt(1) !== '=') { return false; } // TODO: check the modifier a bit more. } return true; }; // Expose public methods. { module.exports = SDPUtils; } })(sdp$1); var SDPUtils = sdpExports; var sdp = /*#__PURE__*/_mergeNamespaces({ __proto__: null, default: SDPUtils }, [sdpExports]); /* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. */ function shimRTCIceCandidate(window) { // foundation is arbitrarily chosen as an indicator for full support for // https://w3c.github.io/webrtc-pc/#rtcicecandidate-interface if (!window.RTCIceCandidate || window.RTCIceCandidate && 'foundation' in window.RTCIceCandidate.prototype) { return; } const NativeRTCIceCandidate = window.RTCIceCandidate; window.RTCIceCandidate = function RTCIceCandidate(args) { // Remove the a= which shouldn't be part of the candidate string. if (typeof args === 'object' && args.candidate && args.candidate.indexOf('a=') === 0) { args = JSON.parse(JSON.stringify(args)); args.candidate = args.candidate.substr(2); } if (args.candidate && args.candidate.length) { // Augment the native candidate with the parsed fields. const nativeCandidate = new NativeRTCIceCandidate(args); const parsedCandidate = SDPUtils.parseCandidate(args.candidate); const augmentedCandidate = Object.assign(nativeCandidate, parsedCandidate); // Add a serializer that does not serialize the extra attributes. augmentedCandidate.toJSON = function toJSON() { return { candidate: augmentedCandidate.candidate, sdpMid: augmentedCandidate.sdpMid, sdpMLineIndex: augmentedCandidate.sdpMLineIndex, usernameFragment: augmentedCandidate.usernameFragment }; }; return augmentedCandidate; } return new NativeRTCIceCandidate(args); }; window.RTCIceCandidate.prototype = NativeRTCIceCandidate.prototype; // Hook up the augmented candidate in onicecandidate and // addEventListener('icecandidate', ...) wrapPeerConnectionEvent(window, 'icecandidate', e => { if (e.candidate) { Object.defineProperty(e, 'candidate', { value: new window.RTCIceCandidate(e.candidate), writable: 'false' }); } return e; }); } function shimMaxMessageSize(window, browserDetails) { if (!window.RTCPeerConnection) { return; } if (!('sctp' in window.RTCPeerConnection.prototype)) { Object.defineProperty(window.RTCPeerConnection.prototype, 'sctp', { get() { return typeof this._sctp === 'undefined' ? null : this._sctp; } }); } const sctpInDescription = function (description) { if (!description || !description.sdp) { return false; } const sections = SDPUtils.splitSections(description.sdp); sections.shift(); return sections.some(mediaSection => { const mLine = SDPUtils.parseMLine(mediaSection); return mLine && mLine.kind === 'application' && mLine.protocol.indexOf('SCTP') !== -1; }); }; const getRemoteFirefoxVersion = function (description) { // TODO: Is there a better solution for detecting Firefox? const match = description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/); if (match === null || match.length < 2) { return -1; } const version = parseInt(match[1], 10); // Test for NaN (yes, this is ugly) return version !== version ? -1 : version; }; const getCanSendMaxMessageSize = function (remoteIsFirefox) { // Every implementation we know can send at least 64 KiB. // Note: Although Chrome is technically able to send up to 256 KiB, the // data does not reach the other peer reliably. // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=8419 let canSendMaxMessageSize = 65536; if (browserDetails.browser === 'firefox') { if (browserDetails.version < 57) { if (remoteIsFirefox === -1) { // FF < 57 will send in 16 KiB chunks using the deprecated PPID // fragmentation. canSendMaxMessageSize = 16384; } else { // However, other FF (and RAWRTC) can reassemble PPID-fragmented // messages. Thus, supporting ~2 GiB when sending. canSendMaxMessageSize = 2147483637; } } else if (browserDetails.version < 60) { // Currently, all FF >= 57 will reset the remote maximum message size // to the default value when a data channel is created at a later // stage. :( // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 canSendMaxMessageSize = browserDetails.version === 57 ? 65535 : 65536; } else { // FF >= 60 supports sending ~2 GiB canSendMaxMessageSize = 2147483637; } } return canSendMaxMessageSize; }; const getMaxMessageSize = function (description, remoteIsFirefox) { // Note: 65536 bytes is the default value from the SDP spec. Also, // every implementation we know supports receiving 65536 bytes. let maxMessageSize = 65536; // FF 57 has a slightly incorrect default remote max message size, so // we need to adjust it here to avoid a failure when sending. // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1425697 if (browserDetails.browser === 'firefox' && browserDetails.version === 57) { maxMessageSize = 65535; } const match = SDPUtils.matchPrefix(description.sdp, 'a=max-message-size:'); if (match.length > 0) { maxMessageSize = parseInt(match[0].substr(19), 10); } else if (browserDetails.browser === 'firefox' && remoteIsFirefox !== -1) { // If the maximum message size is not present in the remote SDP and // both local and remote are Firefox, the remote peer can receive // ~2 GiB. maxMessageSize = 2147483637; } return maxMessageSize; }; const origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() { this._sctp = null; // Chrome decided to not expose .sctp in plan-b mode. // As usual, adapter.js has to do an 'ugly worakaround' // to cover up the mess. if (browserDetails.browser === 'chrome' && browserDetails.version >= 76) { const { sdpSemantics } = this.getConfiguration(); if (sdpSemantics === 'plan-b') { Object.defineProperty(this, 'sctp', { get() { return typeof this._sctp === 'undefined' ? null : this._sctp; }, enumerable: true, configurable: true }); } } if (sctpInDescription(arguments[0])) { // Check if the remote is FF. const isFirefox = getRemoteFirefoxVersion(arguments[0]); // Get the maximum message size the local peer is capable of sending const canSendMMS = getCanSendMaxMessageSize(isFirefox); // Get the maximum message size of the remote peer. const remoteMMS = getMaxMessageSize(arguments[0], isFirefox); // Determine final maximum message size let maxMessageSize; if (canSendMMS === 0 && remoteMMS === 0) { maxMessageSize = Number.POSITIVE_INFINITY; } else if (canSendMMS === 0 || remoteMMS === 0) { maxMessageSize = Math.max(canSendMMS, remoteMMS); } else { maxMessageSize = Math.min(canSendMMS, remoteMMS); } // Create a dummy RTCSctpTransport object and the 'maxMessageSize' // attribute. const sctp = {}; Object.defineProperty(sctp, 'maxMessageSize', { get() { return maxMessageSize; } }); this._sctp = sctp; } return origSetRemoteDescription.apply(this, arguments); }; } function shimSendThrowTypeError(window) { if (!(window.RTCPeerConnection && 'createDataChannel' in window.RTCPeerConnection.prototype)) { return; } // Note: Although Firefox >= 57 has a native implementation, the maximum // message size can be reset for all data channels at a later stage. // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 function wrapDcSend(dc, pc) { const origDataChannelSend = dc.send; dc.send = function send() { const data = arguments[0]; const length = data.length || data.size || data.byteLength; if (dc.readyState === 'open' && pc.sctp && length > pc.sctp.maxMessageSize) { throw new TypeError('Message too large (can send a maximum of ' + pc.sctp.maxMessageSize + ' bytes)'); } return origDataChannelSend.apply(dc, arguments); }; } const origCreateDataChannel = window.RTCPeerConnection.prototype.createDataChannel; window.RTCPeerConnection.prototype.createDataChannel = function createDataChannel() { const dataChannel = origCreateDataChannel.apply(this, arguments); wrapDcSend(dataChannel, this); return dataChannel; }; wrapPeerConnectionEvent(window, 'datachannel', e => { wrapDcSend(e.channel, e.target); return e; }); } /* shims RTCConnectionState by pretending it is the same as iceConnectionState. * See https://bugs.chromium.org/p/webrtc/issues/detail?id=6145#c12 * for why this is a valid hack in Chrome. In Firefox it is slightly incorrect * since DTLS failures would be hidden. See * https://bugzilla.mozilla.org/show_bug.cgi?id=1265827 * for the Firefox tracking bug. */ function shimConnectionState(window) { if (!window.RTCPeerConnection || 'connectionState' in window.RTCPeerConnection.prototype) { return; } const proto = window.RTCPeerConnection.prototype; Object.defineProperty(proto, 'connectionState', { get() { return { completed: 'connected', checking: 'connecting' }[this.iceConnectionState] || this.iceConnectionState; }, enumerable: true, configurable: true }); Object.defineProperty(proto, 'onconnectionstatechange', { get() { return this._onconnectionstatechange || null; }, set(cb) { if (this._onconnectionstatechange) { this.removeEventListener('connectionstatechange', this._onconnectionstatechange); delete this._onconnectionstatechange; } if (cb) { this.addEventListener('connectionstatechange', this._onconnectionstatechange = cb); } }, enumerable: true, configurable: true }); ['setLocalDescription', 'setRemoteDescription'].forEach(method => { const origMethod = proto[method]; proto[method] = function () { if (!this._connectionstatechangepoly) { this._connectionstatechangepoly = e => { const pc = e.target; if (pc._lastConnectionState !== pc.connectionState) { pc._lastConnectionState = pc.connectionState; const newEvent = new Event('connectionstatechange', e); pc.dispatchEvent(newEvent); } return e; }; this.addEventListener('iceconnectionstatechange', this._connectionstatechangepoly); } return origMethod.apply(this, arguments); }; }); } function removeExtmapAllowMixed(window, browserDetails) { /* remove a=extmap-allow-mixed for webrtc.org < M71 */ if (!window.RTCPeerConnection) { return; } if (browserDetails.browser === 'chrome' && browserDetails.version >= 71) { return; } if (browserDetails.browser === 'safari' && browserDetails.version >= 605) { return; } const nativeSRD = window.RTCPeerConnection.prototype.setRemoteDescription; window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription(desc) { if (desc && desc.sdp && desc.sdp.indexOf('\na=extmap-allow-mixed') !== -1) { const sdp = desc.sdp.split('\n').filter(line => { return line.trim() !== 'a=extmap-allow-mixed'; }).join('\n'); // Safari enforces read-only-ness of RTCSessionDescription fields. if (window.RTCSessionDescription && desc instanceof window.RTCSessionDescription) { arguments[0] = new window.RTCSessionDescription({ type: desc.type, sdp }); } else { desc.sdp = sdp; } } return nativeSRD.apply(this, arguments); }; } function shimAddIceCandidateNullOrEmpty(window, browserDetails) { // Support for addIceCandidate(null or undefined) // as well as addIceCandidate({candidate: "", ...}) // https://bugs.chromium.org/p/chromium/issues/detail?id=978582 // Note: must be called before other polyfills which change the signature. if (!(window.RTCPeerConnection && window.RTCPeerConnection.prototype)) { return; } const nativeAddIceCandidate = window.RTCPeerConnection.prototype.addIceCandidate; if (!nativeAddIceCandidate || nativeAddIceCandidate.length === 0) { return; } window.RTCPeerConnection.prototype.addIceCandidate = function addIceCandidate() { if (!arguments[0]) { if (arguments[1]) { arguments[1].apply(null); } return Promise.resolve(); } // Firefox 68+ emits and processes {candidate: "", ...}, ignore // in older versions. // Native support for ignoring exists for Chrome M77+. // Safari ignores as well, exact version unknown but works in the same // version that also ignores addIceCandidate(null). if ((browserDetails.browser === 'chrome' && browserDetails.version < 78 || browserDetails.browser === 'firefox' && browserDetails.version < 68 || browserDetails.browser === 'safari') && arguments[0] && arguments[0].candidate === '') { return Promise.resolve(); } return nativeAddIceCandidate.apply(this, arguments); }; } // Note: Make sure to call this ahead of APIs that modify // setLocalDescription.length function shimParameterlessSetLocalDescription(window, browserDetails) { if (!(window.RTCPeerConnection && window.RTCPeerConnection.prototype)) { return; } const nativeSetLocalDescription = window.RTCPeerConnection.prototype.setLocalDescription; if (!nativeSetLocalDescription || nativeSetLocalDescription.length === 0) { return; } window.RTCPeerConnection.prototype.setLocalDescription = function setLocalDescription() { let desc = arguments[0] || {}; if (typeof desc !== 'object' || desc.type && desc.sdp) { return nativeSetLocalDescription.apply(this, arguments); } // The remaining steps should technically happen when SLD comes off the // RTCPeerConnection's operations chain (not ahead of going on it), but // this is too difficult to shim. Instead, this shim only covers the // common case where the operations chain is empty. This is imperfect, but // should cover many cases. Rationale: Even if we can't reduce the glare // window to zero on imperfect implementations, there's value in tapping // into the perfect negotiation pattern that several browsers support. desc = { type: desc.type, sdp: desc.sdp }; if (!desc.type) { switch (this.signalingState) { case 'stable': case 'have-local-offer': case 'have-remote-pranswer': desc.type = 'offer'; break; default: desc.type = 'answer'; break; } } if (desc.sdp || desc.type !== 'offer' && desc.type !== 'answer') { return nativeSetLocalDescription.apply(this, [desc]); } const func = desc.type === 'offer' ? this.createOffer : this.createAnswer; return func.apply(this).then(d => nativeSetLocalDescription.apply(this, [d])); }; } var commonShim = /*#__PURE__*/Object.freeze({ __proto__: null, removeExtmapAllowMixed: removeExtmapAllowMixed, shimAddIceCandidateNullOrEmpty: shimAddIceCandidateNullOrEmpty, shimConnectionState: shimConnectionState, shimMaxMessageSize: shimMaxMessageSize, shimParameterlessSetLocalDescription: shimParameterlessSetLocalDescription, shimRTCIceCandidate: shimRTCIceCandidate, shimSendThrowTypeError: shimSendThrowTypeError }); /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. */ // Shimming starts here. function adapterFactory() { let { window } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { shimChrome: true, shimFirefox: true, shimSafari: true }; // Utils. const logging = log; const browserDetails = detectBrowser(window); const adapter = { browserDetails, commonShim, extractVersion: extractVersion, disableLog: disableLog, disableWarnings: disableWarnings, // Expose sdp as a convenience. For production apps include directly. sdp }; // Shim browser if found. switch (browserDetails.browser) { case 'chrome': if (!chromeShim || !shimPeerConnection$1 || !options.shimChrome) { logging('Chrome shim is not included in this adapter release.'); return adapter; } if (browserDetails.version === null) { logging('Chrome shim can not determine version, not shimming.'); return adapter; } logging('adapter.js shimming chrome.'); // Export to the adapter global object visible in the browser. adapter.browserShim = chromeShim; // Must be called before shimPeerConnection. shimAddIceCandidateNullOrEmpty(window, browserDetails); shimParameterlessSetLocalDescription(window); shimGetUserMedia$2(window, browserDetails); shimMediaStream(window); shimPeerConnection$1(window, browserDetails); shimOnTrack$1(window); shimAddTrackRemoveTrack(window, browserDetails); shimGetSendersWithDtmf(window); shimGetStats(window); shimSenderReceiverGetStats(window); fixNegotiationNeeded(window, browserDetails); shimRTCIceCandidate(window); shimConnectionState(window); shimMaxMessageSize(window, browserDetails); shimSendThrowTypeError(window); removeExtmapAllowMixed(window, browserDetails); break; case 'firefox': if (!firefoxShim || !shimPeerConnection || !options.shimFirefox) { logging('Firefox shim is not included in this adapter release.'); return adapter; } logging('adapter.js shimming firefox.'); // Export to the adapter global object visible in the browser. adapter.browserShim = firefoxShim; // Must be called before shimPeerConnection. shimAddIceCandidateNullOrEmpty(window, browserDetails); shimParameterlessSetLocalDescription(window); shimGetUserMedia$1(window, browserDetails); shimPeerConnection(window, browserDetails); shimOnTrack(window); shimRemoveStream(window); shimSenderGetStats(window); shimReceiverGetStats(window); shimRTCDataChannel(window); shimAddTransceiver(window); shimGetParameters(window); shimCreateOffer(window); shimCreateAnswer(window); shimRTCIceCandidate(window); shimConnectionState(window); shimMaxMessageSize(window, browserDetails); shimSendThrowTypeError(window); break; case 'safari': if (!safariShim || !options.shimSafari) { logging('Safari shim is not included in this adapter release.'); return adapter; } logging('adapter.js shimming safari.'); // Export to the adapter global object visible in the browser. adapter.browserShim = safariShim; // Must be called before shimCallbackAPI. shimAddIceCandidateNullOrEmpty(window, browserDetails); shimParameterlessSetLocalDescription(window); shimRTCIceServerUrls(window); shimCreateOfferLegacy(window); shimCallbacksAPI(window); shimLocalStreamsAPI(window); shimRemoteStreamsAPI(window); shimTrackEventTransceiver(window); shimGetUserMedia(window); shimAudioContext(window); shimRTCIceCandidate(window); shimMaxMessageSize(window, browserDetails); shimSendThrowTypeError(window); removeExtmapAllowMixed(window, browserDetails); break; default: logging('Unsupported browser!'); break; } return adapter; } /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. */ adapterFactory({ window: typeof window === 'undefined' ? undefined : window }); /* eslint-disable */ var SignalTarget; (function (SignalTarget) { SignalTarget[SignalTarget["PUBLISHER"] = 0] = "PUBLISHER"; SignalTarget[SignalTarget["SUBSCRIBER"] = 1] = "SUBSCRIBER"; SignalTarget[SignalTarget["UNRECOGNIZED"] = -1] = "UNRECOGNIZED"; })(SignalTarget || (SignalTarget = {})); function signalTargetFromJSON(object) { switch (object) { case 0: case "PUBLISHER": return SignalTarget.PUBLISHER; case 1: case "SUBSCRIBER": return SignalTarget.SUBSCRIBER; case -1: case "UNRECOGNIZED": default: return SignalTarget.UNRECOGNIZED; } } function signalTargetToJSON(object) { switch (object) { case SignalTarget.PUBLISHER: return "PUBLISHER"; case SignalTarget.SUBSCRIBER: return "SUBSCRIBER"; case SignalTarget.UNRECOGNIZED: default: return "UNRECOGNIZED"; } } var StreamState; (function (StreamState) { StreamState[StreamState["ACTIVE"] = 0] = "ACTIVE"; StreamState[StreamState["PAUSED"] = 1] = "PAUSED"; StreamState[StreamState["UNRECOGNIZED"] = -1] = "UNRECOGNIZED"; })(StreamState || (StreamState = {})); function streamStateFromJSON(object) { switch (object) { case 0: case "ACTIVE": return StreamState.ACTIVE; case 1: case "PAUSED": return StreamState.PAUSED; case -1: case "UNRECOGNIZED": default: return StreamState.UNRECOGNIZED; } } function streamStateToJSON(object) { switch (object) { case StreamState.ACTIVE: return "ACTIVE"; case StreamState.PAUSED: return "PAUSED"; case StreamState.UNRECOGNIZED: default: return "UNRECOGNIZED"; } } var CandidateProtocol; (function (CandidateProtocol) { CandidateProtocol[CandidateProtocol["UDP"] = 0] = "UDP"; CandidateProtocol[CandidateProtocol["TCP"] = 1] = "TCP"; CandidateProtocol[CandidateProtocol["TLS"] = 2] = "TLS"; CandidateProtocol[CandidateProtocol["UNRECOGNIZED"] = -1] = "UNRECOGNIZED"; })(CandidateProtocol || (CandidateProtocol = {})); function candidateProtocolFromJSON(object) { switch (object) { case 0: case "UDP": return CandidateProtocol.UDP; case 1: case "TCP": return CandidateProtocol.TCP; case 2: case "TLS": return CandidateProtocol.TLS; case -1: case "UNRECOGNIZED": default: return CandidateProtocol.UNRECOGNIZED; } } function candidateProtocolToJSON(object) { switch (object) { case CandidateProtocol.UDP: return "UDP"; case CandidateProtocol.TCP: return "TCP"; case CandidateProtocol.TLS: return "TLS"; case CandidateProtocol.UNRECOGNIZED: default: return "UNRECOGNIZED"; } } function createBaseSignalRequest() { return { message: undefined }; } const SignalRequest = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); var _a; switch ((_a = message.message) === null || _a === void 0 ? void 0 : _a.$case) { case "offer": SessionDescription.encode(message.message.offer, writer.uint32(10).fork()).ldelim(); break; case "answer": SessionDescription.encode(message.message.answer, writer.uint32(18).fork()).ldelim(); break; case "trickle": TrickleRequest.encode(message.message.trickle, writer.uint32(26).fork()).ldelim(); break; case "addTrack": AddTrackRequest.encode(message.message.addTrack, writer.uint32(34).fork()).ldelim(); break; case "mute": MuteTrackRequest.encode(message.message.mute, writer.uint32(42).fork()).ldelim(); break; case "subscription": UpdateSubscription.encode(message.message.subscription, writer.uint32(50).fork()).ldelim(); break; case "trackSetting": UpdateTrackSettings.encode(message.message.trackSetting, writer.uint32(58).fork()).ldelim(); break; case "leave": LeaveRequest.encode(message.message.leave, writer.uint32(66).fork()).ldelim(); break; case "updateLayers": UpdateVideoLayers.encode(message.message.updateLayers, writer.uint32(82).fork()).ldelim(); break; case "subscriptionPermission": SubscriptionPermission.encode(message.message.subscriptionPermission, writer.uint32(90).fork()).ldelim(); break; case "syncState": SyncState.encode(message.message.syncState, writer.uint32(98).fork()).ldelim(); break; case "simulate": SimulateScenario.encode(message.message.simulate, writer.uint32(106).fork()).ldelim(); break; case "ping": writer.uint32(112).int64(message.message.ping); break; case "updateMetadata": UpdateParticipantMetadata.encode(message.message.updateMetadata, writer.uint32(122).fork()).ldelim(); break; case "pingReq": Ping.encode(message.message.pingReq, writer.uint32(130).fork()).ldelim(); break; } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseSignalRequest(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.message = { $case: "offer", offer: SessionDescription.decode(reader, reader.uint32()) }; break; case 2: message.message = { $case: "answer", answer: SessionDescription.decode(reader, reader.uint32()) }; break; case 3: message.message = { $case: "trickle", trickle: TrickleRequest.decode(reader, reader.uint32()) }; break; case 4: message.message = { $case: "addTrack", addTrack: AddTrackRequest.decode(reader, reader.uint32()) }; break; case 5: message.message = { $case: "mute", mute: MuteTrackRequest.decode(reader, reader.uint32()) }; break; case 6: message.message = { $case: "subscription", subscription: UpdateSubscription.decode(reader, reader.uint32()) }; break; case 7: message.message = { $case: "trackSetting", trackSetting: UpdateTrackSettings.decode(reader, reader.uint32()) }; break; case 8: message.message = { $case: "leave", leave: LeaveRequest.decode(reader, reader.uint32()) }; break; case 10: message.message = { $case: "updateLayers", updateLayers: UpdateVideoLayers.decode(reader, reader.uint32()) }; break; case 11: message.message = { $case: "subscriptionPermission", subscriptionPermission: SubscriptionPermission.decode(reader, reader.uint32()) }; break; case 12: message.message = { $case: "syncState", syncState: SyncState.decode(reader, reader.uint32()) }; break; case 13: message.message = { $case: "simulate", simulate: SimulateScenario.decode(reader, reader.uint32()) }; break; case 14: message.message = { $case: "ping", ping: longToNumber(reader.int64()) }; break; case 15: message.message = { $case: "updateMetadata", updateMetadata: UpdateParticipantMetadata.decode(reader, reader.uint32()) }; break; case 16: message.message = { $case: "pingReq", pingReq: Ping.decode(reader, reader.uint32()) }; break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { message: isSet(object.offer) ? { $case: "offer", offer: SessionDescription.fromJSON(object.offer) } : isSet(object.answer) ? { $case: "answer", answer: SessionDescription.fromJSON(object.answer) } : isSet(object.trickle) ? { $case: "trickle", trickle: TrickleRequest.fromJSON(object.trickle) } : isSet(object.addTrack) ? { $case: "addTrack", addTrack: AddTrackRequest.fromJSON(object.addTrack) } : isSet(object.mute) ? { $case: "mute", mute: MuteTrackRequest.fromJSON(object.mute) } : isSet(object.subscription) ? { $case: "subscription", subscription: UpdateSubscription.fromJSON(object.subscription) } : isSet(object.trackSetting) ? { $case: "trackSetting", trackSetting: UpdateTrackSettings.fromJSON(object.trackSetting) } : isSet(object.leave) ? { $case: "leave", leave: LeaveRequest.fromJSON(object.leave) } : isSet(object.updateLayers) ? { $case: "updateLayers", updateLayers: UpdateVideoLayers.fromJSON(object.updateLayers) } : isSet(object.subscriptionPermission) ? { $case: "subscriptionPermission", subscriptionPermission: SubscriptionPermission.fromJSON(object.subscriptionPermission) } : isSet(object.syncState) ? { $case: "syncState", syncState: SyncState.fromJSON(object.syncState) } : isSet(object.simulate) ? { $case: "simulate", simulate: SimulateScenario.fromJSON(object.simulate) } : isSet(object.ping) ? { $case: "ping", ping: Number(object.ping) } : isSet(object.updateMetadata) ? { $case: "updateMetadata", updateMetadata: UpdateParticipantMetadata.fromJSON(object.updateMetadata) } : isSet(object.pingReq) ? { $case: "pingReq", pingReq: Ping.fromJSON(object.pingReq) } : undefined }; }, toJSON(message) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19; const obj = {}; ((_a = message.message) === null || _a === void 0 ? void 0 : _a.$case) === "offer" && (obj.offer = ((_b = message.message) === null || _b === void 0 ? void 0 : _b.offer) ? SessionDescription.toJSON((_c = message.message) === null || _c === void 0 ? void 0 : _c.offer) : undefined); ((_d = message.message) === null || _d === void 0 ? void 0 : _d.$case) === "answer" && (obj.answer = ((_e = message.message) === null || _e === void 0 ? void 0 : _e.answer) ? SessionDescription.toJSON((_f = message.message) === null || _f === void 0 ? void 0 : _f.answer) : undefined); ((_g = message.message) === null || _g === void 0 ? void 0 : _g.$case) === "trickle" && (obj.trickle = ((_h = message.message) === null || _h === void 0 ? void 0 : _h.trickle) ? TrickleRequest.toJSON((_j = message.message) === null || _j === void 0 ? void 0 : _j.trickle) : undefined); ((_k = message.message) === null || _k === void 0 ? void 0 : _k.$case) === "addTrack" && (obj.addTrack = ((_l = message.message) === null || _l === void 0 ? void 0 : _l.addTrack) ? AddTrackRequest.toJSON((_m = message.message) === null || _m === void 0 ? void 0 : _m.addTrack) : undefined); ((_o = message.message) === null || _o === void 0 ? void 0 : _o.$case) === "mute" && (obj.mute = ((_p = message.message) === null || _p === void 0 ? void 0 : _p.mute) ? MuteTrackRequest.toJSON((_q = message.message) === null || _q === void 0 ? void 0 : _q.mute) : undefined); ((_r = message.message) === null || _r === void 0 ? void 0 : _r.$case) === "subscription" && (obj.subscription = ((_s = message.message) === null || _s === void 0 ? void 0 : _s.subscription) ? UpdateSubscription.toJSON((_t = message.message) === null || _t === void 0 ? void 0 : _t.subscription) : undefined); ((_u = message.message) === null || _u === void 0 ? void 0 : _u.$case) === "trackSetting" && (obj.trackSetting = ((_v = message.message) === null || _v === void 0 ? void 0 : _v.trackSetting) ? UpdateTrackSettings.toJSON((_w = message.message) === null || _w === void 0 ? void 0 : _w.trackSetting) : undefined); ((_x = message.message) === null || _x === void 0 ? void 0 : _x.$case) === "leave" && (obj.leave = ((_y = message.message) === null || _y === void 0 ? void 0 : _y.leave) ? LeaveRequest.toJSON((_z = message.message) === null || _z === void 0 ? void 0 : _z.leave) : undefined); ((_0 = message.message) === null || _0 === void 0 ? void 0 : _0.$case) === "updateLayers" && (obj.updateLayers = ((_1 = message.message) === null || _1 === void 0 ? void 0 : _1.updateLayers) ? UpdateVideoLayers.toJSON((_2 = message.message) === null || _2 === void 0 ? void 0 : _2.updateLayers) : undefined); ((_3 = message.message) === null || _3 === void 0 ? void 0 : _3.$case) === "subscriptionPermission" && (obj.subscriptionPermission = ((_4 = message.message) === null || _4 === void 0 ? void 0 : _4.subscriptionPermission) ? SubscriptionPermission.toJSON((_5 = message.message) === null || _5 === void 0 ? void 0 : _5.subscriptionPermission) : undefined); ((_6 = message.message) === null || _6 === void 0 ? void 0 : _6.$case) === "syncState" && (obj.syncState = ((_7 = message.message) === null || _7 === void 0 ? void 0 : _7.syncState) ? SyncState.toJSON((_8 = message.message) === null || _8 === void 0 ? void 0 : _8.syncState) : undefined); ((_9 = message.message) === null || _9 === void 0 ? void 0 : _9.$case) === "simulate" && (obj.simulate = ((_10 = message.message) === null || _10 === void 0 ? void 0 : _10.simulate) ? SimulateScenario.toJSON((_11 = message.message) === null || _11 === void 0 ? void 0 : _11.simulate) : undefined); ((_12 = message.message) === null || _12 === void 0 ? void 0 : _12.$case) === "ping" && (obj.ping = Math.round((_13 = message.message) === null || _13 === void 0 ? void 0 : _13.ping)); ((_14 = message.message) === null || _14 === void 0 ? void 0 : _14.$case) === "updateMetadata" && (obj.updateMetadata = ((_15 = message.message) === null || _15 === void 0 ? void 0 : _15.updateMetadata) ? UpdateParticipantMetadata.toJSON((_16 = message.message) === null || _16 === void 0 ? void 0 : _16.updateMetadata) : undefined); ((_17 = message.message) === null || _17 === void 0 ? void 0 : _17.$case) === "pingReq" && (obj.pingReq = ((_18 = message.message) === null || _18 === void 0 ? void 0 : _18.pingReq) ? Ping.toJSON((_19 = message.message) === null || _19 === void 0 ? void 0 : _19.pingReq) : undefined); return obj; }, create(base) { return SignalRequest.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20; const message = createBaseSignalRequest(); if (((_a = object.message) === null || _a === void 0 ? void 0 : _a.$case) === "offer" && ((_b = object.message) === null || _b === void 0 ? void 0 : _b.offer) !== undefined && ((_c = object.message) === null || _c === void 0 ? void 0 : _c.offer) !== null) { message.message = { $case: "offer", offer: SessionDescription.fromPartial(object.message.offer) }; } if (((_d = object.message) === null || _d === void 0 ? void 0 : _d.$case) === "answer" && ((_e = object.message) === null || _e === void 0 ? void 0 : _e.answer) !== undefined && ((_f = object.message) === null || _f === void 0 ? void 0 : _f.answer) !== null) { message.message = { $case: "answer", answer: SessionDescription.fromPartial(object.message.answer) }; } if (((_g = object.message) === null || _g === void 0 ? void 0 : _g.$case) === "trickle" && ((_h = object.message) === null || _h === void 0 ? void 0 : _h.trickle) !== undefined && ((_j = object.message) === null || _j === void 0 ? void 0 : _j.trickle) !== null) { message.message = { $case: "trickle", trickle: TrickleRequest.fromPartial(object.message.trickle) }; } if (((_k = object.message) === null || _k === void 0 ? void 0 : _k.$case) === "addTrack" && ((_l = object.message) === null || _l === void 0 ? void 0 : _l.addTrack) !== undefined && ((_m = object.message) === null || _m === void 0 ? void 0 : _m.addTrack) !== null) { message.message = { $case: "addTrack", addTrack: AddTrackRequest.fromPartial(object.message.addTrack) }; } if (((_o = object.message) === null || _o === void 0 ? void 0 : _o.$case) === "mute" && ((_p = object.message) === null || _p === void 0 ? void 0 : _p.mute) !== undefined && ((_q = object.message) === null || _q === void 0 ? void 0 : _q.mute) !== null) { message.message = { $case: "mute", mute: MuteTrackRequest.fromPartial(object.message.mute) }; } if (((_r = object.message) === null || _r === void 0 ? void 0 : _r.$case) === "subscription" && ((_s = object.message) === null || _s === void 0 ? void 0 : _s.subscription) !== undefined && ((_t = object.message) === null || _t === void 0 ? void 0 : _t.subscription) !== null) { message.message = { $case: "subscription", subscription: UpdateSubscription.fromPartial(object.message.subscription) }; } if (((_u = object.message) === null || _u === void 0 ? void 0 : _u.$case) === "trackSetting" && ((_v = object.message) === null || _v === void 0 ? void 0 : _v.trackSetting) !== undefined && ((_w = object.message) === null || _w === void 0 ? void 0 : _w.trackSetting) !== null) { message.message = { $case: "trackSetting", trackSetting: UpdateTrackSettings.fromPartial(object.message.trackSetting) }; } if (((_x = object.message) === null || _x === void 0 ? void 0 : _x.$case) === "leave" && ((_y = object.message) === null || _y === void 0 ? void 0 : _y.leave) !== undefined && ((_z = object.message) === null || _z === void 0 ? void 0 : _z.leave) !== null) { message.message = { $case: "leave", leave: LeaveRequest.fromPartial(object.message.leave) }; } if (((_0 = object.message) === null || _0 === void 0 ? void 0 : _0.$case) === "updateLayers" && ((_1 = object.message) === null || _1 === void 0 ? void 0 : _1.updateLayers) !== undefined && ((_2 = object.message) === null || _2 === void 0 ? void 0 : _2.updateLayers) !== null) { message.message = { $case: "updateLayers", updateLayers: UpdateVideoLayers.fromPartial(object.message.updateLayers) }; } if (((_3 = object.message) === null || _3 === void 0 ? void 0 : _3.$case) === "subscriptionPermission" && ((_4 = object.message) === null || _4 === void 0 ? void 0 : _4.subscriptionPermission) !== undefined && ((_5 = object.message) === null || _5 === void 0 ? void 0 : _5.subscriptionPermission) !== null) { message.message = { $case: "subscriptionPermission", subscriptionPermission: SubscriptionPermission.fromPartial(object.message.subscriptionPermission) }; } if (((_6 = object.message) === null || _6 === void 0 ? void 0 : _6.$case) === "syncState" && ((_7 = object.message) === null || _7 === void 0 ? void 0 : _7.syncState) !== undefined && ((_8 = object.message) === null || _8 === void 0 ? void 0 : _8.syncState) !== null) { message.message = { $case: "syncState", syncState: SyncState.fromPartial(object.message.syncState) }; } if (((_9 = object.message) === null || _9 === void 0 ? void 0 : _9.$case) === "simulate" && ((_10 = object.message) === null || _10 === void 0 ? void 0 : _10.simulate) !== undefined && ((_11 = object.message) === null || _11 === void 0 ? void 0 : _11.simulate) !== null) { message.message = { $case: "simulate", simulate: SimulateScenario.fromPartial(object.message.simulate) }; } if (((_12 = object.message) === null || _12 === void 0 ? void 0 : _12.$case) === "ping" && ((_13 = object.message) === null || _13 === void 0 ? void 0 : _13.ping) !== undefined && ((_14 = object.message) === null || _14 === void 0 ? void 0 : _14.ping) !== null) { message.message = { $case: "ping", ping: object.message.ping }; } if (((_15 = object.message) === null || _15 === void 0 ? void 0 : _15.$case) === "updateMetadata" && ((_16 = object.message) === null || _16 === void 0 ? void 0 : _16.updateMetadata) !== undefined && ((_17 = object.message) === null || _17 === void 0 ? void 0 : _17.updateMetadata) !== null) { message.message = { $case: "updateMetadata", updateMetadata: UpdateParticipantMetadata.fromPartial(object.message.updateMetadata) }; } if (((_18 = object.message) === null || _18 === void 0 ? void 0 : _18.$case) === "pingReq" && ((_19 = object.message) === null || _19 === void 0 ? void 0 : _19.pingReq) !== undefined && ((_20 = object.message) === null || _20 === void 0 ? void 0 : _20.pingReq) !== null) { message.message = { $case: "pingReq", pingReq: Ping.fromPartial(object.message.pingReq) }; } return message; } }; function createBaseSignalResponse() { return { message: undefined }; } const SignalResponse = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); var _a; switch ((_a = message.message) === null || _a === void 0 ? void 0 : _a.$case) { case "join": JoinResponse.encode(message.message.join, writer.uint32(10).fork()).ldelim(); break; case "answer": SessionDescription.encode(message.message.answer, writer.uint32(18).fork()).ldelim(); break; case "offer": SessionDescription.encode(message.message.offer, writer.uint32(26).fork()).ldelim(); break; case "trickle": TrickleRequest.encode(message.message.trickle, writer.uint32(34).fork()).ldelim(); break; case "update": ParticipantUpdate.encode(message.message.update, writer.uint32(42).fork()).ldelim(); break; case "trackPublished": TrackPublishedResponse.encode(message.message.trackPublished, writer.uint32(50).fork()).ldelim(); break; case "leave": LeaveRequest.encode(message.message.leave, writer.uint32(66).fork()).ldelim(); break; case "mute": MuteTrackRequest.encode(message.message.mute, writer.uint32(74).fork()).ldelim(); break; case "speakersChanged": SpeakersChanged.encode(message.message.speakersChanged, writer.uint32(82).fork()).ldelim(); break; case "roomUpdate": RoomUpdate.encode(message.message.roomUpdate, writer.uint32(90).fork()).ldelim(); break; case "connectionQuality": ConnectionQualityUpdate.encode(message.message.connectionQuality, writer.uint32(98).fork()).ldelim(); break; case "streamStateUpdate": StreamStateUpdate.encode(message.message.streamStateUpdate, writer.uint32(106).fork()).ldelim(); break; case "subscribedQualityUpdate": SubscribedQualityUpdate.encode(message.message.subscribedQualityUpdate, writer.uint32(114).fork()).ldelim(); break; case "subscriptionPermissionUpdate": SubscriptionPermissionUpdate.encode(message.message.subscriptionPermissionUpdate, writer.uint32(122).fork()).ldelim(); break; case "refreshToken": writer.uint32(130).string(message.message.refreshToken); break; case "trackUnpublished": TrackUnpublishedResponse.encode(message.message.trackUnpublished, writer.uint32(138).fork()).ldelim(); break; case "pong": writer.uint32(144).int64(message.message.pong); break; case "reconnect": ReconnectResponse.encode(message.message.reconnect, writer.uint32(154).fork()).ldelim(); break; case "pongResp": Pong.encode(message.message.pongResp, writer.uint32(162).fork()).ldelim(); break; } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseSignalResponse(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.message = { $case: "join", join: JoinResponse.decode(reader, reader.uint32()) }; break; case 2: message.message = { $case: "answer", answer: SessionDescription.decode(reader, reader.uint32()) }; break; case 3: message.message = { $case: "offer", offer: SessionDescription.decode(reader, reader.uint32()) }; break; case 4: message.message = { $case: "trickle", trickle: TrickleRequest.decode(reader, reader.uint32()) }; break; case 5: message.message = { $case: "update", update: ParticipantUpdate.decode(reader, reader.uint32()) }; break; case 6: message.message = { $case: "trackPublished", trackPublished: TrackPublishedResponse.decode(reader, reader.uint32()) }; break; case 8: message.message = { $case: "leave", leave: LeaveRequest.decode(reader, reader.uint32()) }; break; case 9: message.message = { $case: "mute", mute: MuteTrackRequest.decode(reader, reader.uint32()) }; break; case 10: message.message = { $case: "speakersChanged", speakersChanged: SpeakersChanged.decode(reader, reader.uint32()) }; break; case 11: message.message = { $case: "roomUpdate", roomUpdate: RoomUpdate.decode(reader, reader.uint32()) }; break; case 12: message.message = { $case: "connectionQuality", connectionQuality: ConnectionQualityUpdate.decode(reader, reader.uint32()) }; break; case 13: message.message = { $case: "streamStateUpdate", streamStateUpdate: StreamStateUpdate.decode(reader, reader.uint32()) }; break; case 14: message.message = { $case: "subscribedQualityUpdate", subscribedQualityUpdate: SubscribedQualityUpdate.decode(reader, reader.uint32()) }; break; case 15: message.message = { $case: "subscriptionPermissionUpdate", subscriptionPermissionUpdate: SubscriptionPermissionUpdate.decode(reader, reader.uint32()) }; break; case 16: message.message = { $case: "refreshToken", refreshToken: reader.string() }; break; case 17: message.message = { $case: "trackUnpublished", trackUnpublished: TrackUnpublishedResponse.decode(reader, reader.uint32()) }; break; case 18: message.message = { $case: "pong", pong: longToNumber(reader.int64()) }; break; case 19: message.message = { $case: "reconnect", reconnect: ReconnectResponse.decode(reader, reader.uint32()) }; break; case 20: message.message = { $case: "pongResp", pongResp: Pong.decode(reader, reader.uint32()) }; break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { message: isSet(object.join) ? { $case: "join", join: JoinResponse.fromJSON(object.join) } : isSet(object.answer) ? { $case: "answer", answer: SessionDescription.fromJSON(object.answer) } : isSet(object.offer) ? { $case: "offer", offer: SessionDescription.fromJSON(object.offer) } : isSet(object.trickle) ? { $case: "trickle", trickle: TrickleRequest.fromJSON(object.trickle) } : isSet(object.update) ? { $case: "update", update: ParticipantUpdate.fromJSON(object.update) } : isSet(object.trackPublished) ? { $case: "trackPublished", trackPublished: TrackPublishedResponse.fromJSON(object.trackPublished) } : isSet(object.leave) ? { $case: "leave", leave: LeaveRequest.fromJSON(object.leave) } : isSet(object.mute) ? { $case: "mute", mute: MuteTrackRequest.fromJSON(object.mute) } : isSet(object.speakersChanged) ? { $case: "speakersChanged", speakersChanged: SpeakersChanged.fromJSON(object.speakersChanged) } : isSet(object.roomUpdate) ? { $case: "roomUpdate", roomUpdate: RoomUpdate.fromJSON(object.roomUpdate) } : isSet(object.connectionQuality) ? { $case: "connectionQuality", connectionQuality: ConnectionQualityUpdate.fromJSON(object.connectionQuality) } : isSet(object.streamStateUpdate) ? { $case: "streamStateUpdate", streamStateUpdate: StreamStateUpdate.fromJSON(object.streamStateUpdate) } : isSet(object.subscribedQualityUpdate) ? { $case: "subscribedQualityUpdate", subscribedQualityUpdate: SubscribedQualityUpdate.fromJSON(object.subscribedQualityUpdate) } : isSet(object.subscriptionPermissionUpdate) ? { $case: "subscriptionPermissionUpdate", subscriptionPermissionUpdate: SubscriptionPermissionUpdate.fromJSON(object.subscriptionPermissionUpdate) } : isSet(object.refreshToken) ? { $case: "refreshToken", refreshToken: String(object.refreshToken) } : isSet(object.trackUnpublished) ? { $case: "trackUnpublished", trackUnpublished: TrackUnpublishedResponse.fromJSON(object.trackUnpublished) } : isSet(object.pong) ? { $case: "pong", pong: Number(object.pong) } : isSet(object.reconnect) ? { $case: "reconnect", reconnect: ReconnectResponse.fromJSON(object.reconnect) } : isSet(object.pongResp) ? { $case: "pongResp", pongResp: Pong.fromJSON(object.pongResp) } : undefined }; }, toJSON(message) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30; const obj = {}; ((_a = message.message) === null || _a === void 0 ? void 0 : _a.$case) === "join" && (obj.join = ((_b = message.message) === null || _b === void 0 ? void 0 : _b.join) ? JoinResponse.toJSON((_c = message.message) === null || _c === void 0 ? void 0 : _c.join) : undefined); ((_d = message.message) === null || _d === void 0 ? void 0 : _d.$case) === "answer" && (obj.answer = ((_e = message.message) === null || _e === void 0 ? void 0 : _e.answer) ? SessionDescription.toJSON((_f = message.message) === null || _f === void 0 ? void 0 : _f.answer) : undefined); ((_g = message.message) === null || _g === void 0 ? void 0 : _g.$case) === "offer" && (obj.offer = ((_h = message.message) === null || _h === void 0 ? void 0 : _h.offer) ? SessionDescription.toJSON((_j = message.message) === null || _j === void 0 ? void 0 : _j.offer) : undefined); ((_k = message.message) === null || _k === void 0 ? void 0 : _k.$case) === "trickle" && (obj.trickle = ((_l = message.message) === null || _l === void 0 ? void 0 : _l.trickle) ? TrickleRequest.toJSON((_m = message.message) === null || _m === void 0 ? void 0 : _m.trickle) : undefined); ((_o = message.message) === null || _o === void 0 ? void 0 : _o.$case) === "update" && (obj.update = ((_p = message.message) === null || _p === void 0 ? void 0 : _p.update) ? ParticipantUpdate.toJSON((_q = message.message) === null || _q === void 0 ? void 0 : _q.update) : undefined); ((_r = message.message) === null || _r === void 0 ? void 0 : _r.$case) === "trackPublished" && (obj.trackPublished = ((_s = message.message) === null || _s === void 0 ? void 0 : _s.trackPublished) ? TrackPublishedResponse.toJSON((_t = message.message) === null || _t === void 0 ? void 0 : _t.trackPublished) : undefined); ((_u = message.message) === null || _u === void 0 ? void 0 : _u.$case) === "leave" && (obj.leave = ((_v = message.message) === null || _v === void 0 ? void 0 : _v.leave) ? LeaveRequest.toJSON((_w = message.message) === null || _w === void 0 ? void 0 : _w.leave) : undefined); ((_x = message.message) === null || _x === void 0 ? void 0 : _x.$case) === "mute" && (obj.mute = ((_y = message.message) === null || _y === void 0 ? void 0 : _y.mute) ? MuteTrackRequest.toJSON((_z = message.message) === null || _z === void 0 ? void 0 : _z.mute) : undefined); ((_0 = message.message) === null || _0 === void 0 ? void 0 : _0.$case) === "speakersChanged" && (obj.speakersChanged = ((_1 = message.message) === null || _1 === void 0 ? void 0 : _1.speakersChanged) ? SpeakersChanged.toJSON((_2 = message.message) === null || _2 === void 0 ? void 0 : _2.speakersChanged) : undefined); ((_3 = message.message) === null || _3 === void 0 ? void 0 : _3.$case) === "roomUpdate" && (obj.roomUpdate = ((_4 = message.message) === null || _4 === void 0 ? void 0 : _4.roomUpdate) ? RoomUpdate.toJSON((_5 = message.message) === null || _5 === void 0 ? void 0 : _5.roomUpdate) : undefined); ((_6 = message.message) === null || _6 === void 0 ? void 0 : _6.$case) === "connectionQuality" && (obj.connectionQuality = ((_7 = message.message) === null || _7 === void 0 ? void 0 : _7.connectionQuality) ? ConnectionQualityUpdate.toJSON((_8 = message.message) === null || _8 === void 0 ? void 0 : _8.connectionQuality) : undefined); ((_9 = message.message) === null || _9 === void 0 ? void 0 : _9.$case) === "streamStateUpdate" && (obj.streamStateUpdate = ((_10 = message.message) === null || _10 === void 0 ? void 0 : _10.streamStateUpdate) ? StreamStateUpdate.toJSON((_11 = message.message) === null || _11 === void 0 ? void 0 : _11.streamStateUpdate) : undefined); ((_12 = message.message) === null || _12 === void 0 ? void 0 : _12.$case) === "subscribedQualityUpdate" && (obj.subscribedQualityUpdate = ((_13 = message.message) === null || _13 === void 0 ? void 0 : _13.subscribedQualityUpdate) ? SubscribedQualityUpdate.toJSON((_14 = message.message) === null || _14 === void 0 ? void 0 : _14.subscribedQualityUpdate) : undefined); ((_15 = message.message) === null || _15 === void 0 ? void 0 : _15.$case) === "subscriptionPermissionUpdate" && (obj.subscriptionPermissionUpdate = ((_16 = message.message) === null || _16 === void 0 ? void 0 : _16.subscriptionPermissionUpdate) ? SubscriptionPermissionUpdate.toJSON((_17 = message.message) === null || _17 === void 0 ? void 0 : _17.subscriptionPermissionUpdate) : undefined); ((_18 = message.message) === null || _18 === void 0 ? void 0 : _18.$case) === "refreshToken" && (obj.refreshToken = (_19 = message.message) === null || _19 === void 0 ? void 0 : _19.refreshToken); ((_20 = message.message) === null || _20 === void 0 ? void 0 : _20.$case) === "trackUnpublished" && (obj.trackUnpublished = ((_21 = message.message) === null || _21 === void 0 ? void 0 : _21.trackUnpublished) ? TrackUnpublishedResponse.toJSON((_22 = message.message) === null || _22 === void 0 ? void 0 : _22.trackUnpublished) : undefined); ((_23 = message.message) === null || _23 === void 0 ? void 0 : _23.$case) === "pong" && (obj.pong = Math.round((_24 = message.message) === null || _24 === void 0 ? void 0 : _24.pong)); ((_25 = message.message) === null || _25 === void 0 ? void 0 : _25.$case) === "reconnect" && (obj.reconnect = ((_26 = message.message) === null || _26 === void 0 ? void 0 : _26.reconnect) ? ReconnectResponse.toJSON((_27 = message.message) === null || _27 === void 0 ? void 0 : _27.reconnect) : undefined); ((_28 = message.message) === null || _28 === void 0 ? void 0 : _28.$case) === "pongResp" && (obj.pongResp = ((_29 = message.message) === null || _29 === void 0 ? void 0 : _29.pongResp) ? Pong.toJSON((_30 = message.message) === null || _30 === void 0 ? void 0 : _30.pongResp) : undefined); return obj; }, create(base) { return SignalResponse.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32; const message = createBaseSignalResponse(); if (((_a = object.message) === null || _a === void 0 ? void 0 : _a.$case) === "join" && ((_b = object.message) === null || _b === void 0 ? void 0 : _b.join) !== undefined && ((_c = object.message) === null || _c === void 0 ? void 0 : _c.join) !== null) { message.message = { $case: "join", join: JoinResponse.fromPartial(object.message.join) }; } if (((_d = object.message) === null || _d === void 0 ? void 0 : _d.$case) === "answer" && ((_e = object.message) === null || _e === void 0 ? void 0 : _e.answer) !== undefined && ((_f = object.message) === null || _f === void 0 ? void 0 : _f.answer) !== null) { message.message = { $case: "answer", answer: SessionDescription.fromPartial(object.message.answer) }; } if (((_g = object.message) === null || _g === void 0 ? void 0 : _g.$case) === "offer" && ((_h = object.message) === null || _h === void 0 ? void 0 : _h.offer) !== undefined && ((_j = object.message) === null || _j === void 0 ? void 0 : _j.offer) !== null) { message.message = { $case: "offer", offer: SessionDescription.fromPartial(object.message.offer) }; } if (((_k = object.message) === null || _k === void 0 ? void 0 : _k.$case) === "trickle" && ((_l = object.message) === null || _l === void 0 ? void 0 : _l.trickle) !== undefined && ((_m = object.message) === null || _m === void 0 ? void 0 : _m.trickle) !== null) { message.message = { $case: "trickle", trickle: TrickleRequest.fromPartial(object.message.trickle) }; } if (((_o = object.message) === null || _o === void 0 ? void 0 : _o.$case) === "update" && ((_p = object.message) === null || _p === void 0 ? void 0 : _p.update) !== undefined && ((_q = object.message) === null || _q === void 0 ? void 0 : _q.update) !== null) { message.message = { $case: "update", update: ParticipantUpdate.fromPartial(object.message.update) }; } if (((_r = object.message) === null || _r === void 0 ? void 0 : _r.$case) === "trackPublished" && ((_s = object.message) === null || _s === void 0 ? void 0 : _s.trackPublished) !== undefined && ((_t = object.message) === null || _t === void 0 ? void 0 : _t.trackPublished) !== null) { message.message = { $case: "trackPublished", trackPublished: TrackPublishedResponse.fromPartial(object.message.trackPublished) }; } if (((_u = object.message) === null || _u === void 0 ? void 0 : _u.$case) === "leave" && ((_v = object.message) === null || _v === void 0 ? void 0 : _v.leave) !== undefined && ((_w = object.message) === null || _w === void 0 ? void 0 : _w.leave) !== null) { message.message = { $case: "leave", leave: LeaveRequest.fromPartial(object.message.leave) }; } if (((_x = object.message) === null || _x === void 0 ? void 0 : _x.$case) === "mute" && ((_y = object.message) === null || _y === void 0 ? void 0 : _y.mute) !== undefined && ((_z = object.message) === null || _z === void 0 ? void 0 : _z.mute) !== null) { message.message = { $case: "mute", mute: MuteTrackRequest.fromPartial(object.message.mute) }; } if (((_0 = object.message) === null || _0 === void 0 ? void 0 : _0.$case) === "speakersChanged" && ((_1 = object.message) === null || _1 === void 0 ? void 0 : _1.speakersChanged) !== undefined && ((_2 = object.message) === null || _2 === void 0 ? void 0 : _2.speakersChanged) !== null) { message.message = { $case: "speakersChanged", speakersChanged: SpeakersChanged.fromPartial(object.message.speakersChanged) }; } if (((_3 = object.message) === null || _3 === void 0 ? void 0 : _3.$case) === "roomUpdate" && ((_4 = object.message) === null || _4 === void 0 ? void 0 : _4.roomUpdate) !== undefined && ((_5 = object.message) === null || _5 === void 0 ? void 0 : _5.roomUpdate) !== null) { message.message = { $case: "roomUpdate", roomUpdate: RoomUpdate.fromPartial(object.message.roomUpdate) }; } if (((_6 = object.message) === null || _6 === void 0 ? void 0 : _6.$case) === "connectionQuality" && ((_7 = object.message) === null || _7 === void 0 ? void 0 : _7.connectionQuality) !== undefined && ((_8 = object.message) === null || _8 === void 0 ? void 0 : _8.connectionQuality) !== null) { message.message = { $case: "connectionQuality", connectionQuality: ConnectionQualityUpdate.fromPartial(object.message.connectionQuality) }; } if (((_9 = object.message) === null || _9 === void 0 ? void 0 : _9.$case) === "streamStateUpdate" && ((_10 = object.message) === null || _10 === void 0 ? void 0 : _10.streamStateUpdate) !== undefined && ((_11 = object.message) === null || _11 === void 0 ? void 0 : _11.streamStateUpdate) !== null) { message.message = { $case: "streamStateUpdate", streamStateUpdate: StreamStateUpdate.fromPartial(object.message.streamStateUpdate) }; } if (((_12 = object.message) === null || _12 === void 0 ? void 0 : _12.$case) === "subscribedQualityUpdate" && ((_13 = object.message) === null || _13 === void 0 ? void 0 : _13.subscribedQualityUpdate) !== undefined && ((_14 = object.message) === null || _14 === void 0 ? void 0 : _14.subscribedQualityUpdate) !== null) { message.message = { $case: "subscribedQualityUpdate", subscribedQualityUpdate: SubscribedQualityUpdate.fromPartial(object.message.subscribedQualityUpdate) }; } if (((_15 = object.message) === null || _15 === void 0 ? void 0 : _15.$case) === "subscriptionPermissionUpdate" && ((_16 = object.message) === null || _16 === void 0 ? void 0 : _16.subscriptionPermissionUpdate) !== undefined && ((_17 = object.message) === null || _17 === void 0 ? void 0 : _17.subscriptionPermissionUpdate) !== null) { message.message = { $case: "subscriptionPermissionUpdate", subscriptionPermissionUpdate: SubscriptionPermissionUpdate.fromPartial(object.message.subscriptionPermissionUpdate) }; } if (((_18 = object.message) === null || _18 === void 0 ? void 0 : _18.$case) === "refreshToken" && ((_19 = object.message) === null || _19 === void 0 ? void 0 : _19.refreshToken) !== undefined && ((_20 = object.message) === null || _20 === void 0 ? void 0 : _20.refreshToken) !== null) { message.message = { $case: "refreshToken", refreshToken: object.message.refreshToken }; } if (((_21 = object.message) === null || _21 === void 0 ? void 0 : _21.$case) === "trackUnpublished" && ((_22 = object.message) === null || _22 === void 0 ? void 0 : _22.trackUnpublished) !== undefined && ((_23 = object.message) === null || _23 === void 0 ? void 0 : _23.trackUnpublished) !== null) { message.message = { $case: "trackUnpublished", trackUnpublished: TrackUnpublishedResponse.fromPartial(object.message.trackUnpublished) }; } if (((_24 = object.message) === null || _24 === void 0 ? void 0 : _24.$case) === "pong" && ((_25 = object.message) === null || _25 === void 0 ? void 0 : _25.pong) !== undefined && ((_26 = object.message) === null || _26 === void 0 ? void 0 : _26.pong) !== null) { message.message = { $case: "pong", pong: object.message.pong }; } if (((_27 = object.message) === null || _27 === void 0 ? void 0 : _27.$case) === "reconnect" && ((_28 = object.message) === null || _28 === void 0 ? void 0 : _28.reconnect) !== undefined && ((_29 = object.message) === null || _29 === void 0 ? void 0 : _29.reconnect) !== null) { message.message = { $case: "reconnect", reconnect: ReconnectResponse.fromPartial(object.message.reconnect) }; } if (((_30 = object.message) === null || _30 === void 0 ? void 0 : _30.$case) === "pongResp" && ((_31 = object.message) === null || _31 === void 0 ? void 0 : _31.pongResp) !== undefined && ((_32 = object.message) === null || _32 === void 0 ? void 0 : _32.pongResp) !== null) { message.message = { $case: "pongResp", pongResp: Pong.fromPartial(object.message.pongResp) }; } return message; } }; function createBaseSimulcastCodec() { return { codec: "", cid: "", enableSimulcastLayers: false }; } const SimulcastCodec = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.codec !== "") { writer.uint32(10).string(message.codec); } if (message.cid !== "") { writer.uint32(18).string(message.cid); } if (message.enableSimulcastLayers === true) { writer.uint32(24).bool(message.enableSimulcastLayers); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseSimulcastCodec(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.codec = reader.string(); break; case 2: message.cid = reader.string(); break; case 3: message.enableSimulcastLayers = reader.bool(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { codec: isSet(object.codec) ? String(object.codec) : "", cid: isSet(object.cid) ? String(object.cid) : "", enableSimulcastLayers: isSet(object.enableSimulcastLayers) ? Boolean(object.enableSimulcastLayers) : false }; }, toJSON(message) { const obj = {}; message.codec !== undefined && (obj.codec = message.codec); message.cid !== undefined && (obj.cid = message.cid); message.enableSimulcastLayers !== undefined && (obj.enableSimulcastLayers = message.enableSimulcastLayers); return obj; }, create(base) { return SimulcastCodec.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c; const message = createBaseSimulcastCodec(); message.codec = (_a = object.codec) !== null && _a !== void 0 ? _a : ""; message.cid = (_b = object.cid) !== null && _b !== void 0 ? _b : ""; message.enableSimulcastLayers = (_c = object.enableSimulcastLayers) !== null && _c !== void 0 ? _c : false; return message; } }; function createBaseAddTrackRequest() { return { cid: "", name: "", type: 0, width: 0, height: 0, muted: false, disableDtx: false, source: 0, layers: [], simulcastCodecs: [], sid: "", stereo: false, disableRed: false, encryption: 0 }; } const AddTrackRequest = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.cid !== "") { writer.uint32(10).string(message.cid); } if (message.name !== "") { writer.uint32(18).string(message.name); } if (message.type !== 0) { writer.uint32(24).int32(message.type); } if (message.width !== 0) { writer.uint32(32).uint32(message.width); } if (message.height !== 0) { writer.uint32(40).uint32(message.height); } if (message.muted === true) { writer.uint32(48).bool(message.muted); } if (message.disableDtx === true) { writer.uint32(56).bool(message.disableDtx); } if (message.source !== 0) { writer.uint32(64).int32(message.source); } for (const v of message.layers) { VideoLayer.encode(v, writer.uint32(74).fork()).ldelim(); } for (const v of message.simulcastCodecs) { SimulcastCodec.encode(v, writer.uint32(82).fork()).ldelim(); } if (message.sid !== "") { writer.uint32(90).string(message.sid); } if (message.stereo === true) { writer.uint32(96).bool(message.stereo); } if (message.disableRed === true) { writer.uint32(104).bool(message.disableRed); } if (message.encryption !== 0) { writer.uint32(112).int32(message.encryption); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseAddTrackRequest(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.cid = reader.string(); break; case 2: message.name = reader.string(); break; case 3: message.type = reader.int32(); break; case 4: message.width = reader.uint32(); break; case 5: message.height = reader.uint32(); break; case 6: message.muted = reader.bool(); break; case 7: message.disableDtx = reader.bool(); break; case 8: message.source = reader.int32(); break; case 9: message.layers.push(VideoLayer.decode(reader, reader.uint32())); break; case 10: message.simulcastCodecs.push(SimulcastCodec.decode(reader, reader.uint32())); break; case 11: message.sid = reader.string(); break; case 12: message.stereo = reader.bool(); break; case 13: message.disableRed = reader.bool(); break; case 14: message.encryption = reader.int32(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { cid: isSet(object.cid) ? String(object.cid) : "", name: isSet(object.name) ? String(object.name) : "", type: isSet(object.type) ? trackTypeFromJSON(object.type) : 0, width: isSet(object.width) ? Number(object.width) : 0, height: isSet(object.height) ? Number(object.height) : 0, muted: isSet(object.muted) ? Boolean(object.muted) : false, disableDtx: isSet(object.disableDtx) ? Boolean(object.disableDtx) : false, source: isSet(object.source) ? trackSourceFromJSON(object.source) : 0, layers: Array.isArray(object === null || object === void 0 ? void 0 : object.layers) ? object.layers.map(e => VideoLayer.fromJSON(e)) : [], simulcastCodecs: Array.isArray(object === null || object === void 0 ? void 0 : object.simulcastCodecs) ? object.simulcastCodecs.map(e => SimulcastCodec.fromJSON(e)) : [], sid: isSet(object.sid) ? String(object.sid) : "", stereo: isSet(object.stereo) ? Boolean(object.stereo) : false, disableRed: isSet(object.disableRed) ? Boolean(object.disableRed) : false, encryption: isSet(object.encryption) ? encryption_TypeFromJSON(object.encryption) : 0 }; }, toJSON(message) { const obj = {}; message.cid !== undefined && (obj.cid = message.cid); message.name !== undefined && (obj.name = message.name); message.type !== undefined && (obj.type = trackTypeToJSON(message.type)); message.width !== undefined && (obj.width = Math.round(message.width)); message.height !== undefined && (obj.height = Math.round(message.height)); message.muted !== undefined && (obj.muted = message.muted); message.disableDtx !== undefined && (obj.disableDtx = message.disableDtx); message.source !== undefined && (obj.source = trackSourceToJSON(message.source)); if (message.layers) { obj.layers = message.layers.map(e => e ? VideoLayer.toJSON(e) : undefined); } else { obj.layers = []; } if (message.simulcastCodecs) { obj.simulcastCodecs = message.simulcastCodecs.map(e => e ? SimulcastCodec.toJSON(e) : undefined); } else { obj.simulcastCodecs = []; } message.sid !== undefined && (obj.sid = message.sid); message.stereo !== undefined && (obj.stereo = message.stereo); message.disableRed !== undefined && (obj.disableRed = message.disableRed); message.encryption !== undefined && (obj.encryption = encryption_TypeToJSON(message.encryption)); return obj; }, create(base) { return AddTrackRequest.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p; const message = createBaseAddTrackRequest(); message.cid = (_a = object.cid) !== null && _a !== void 0 ? _a : ""; message.name = (_b = object.name) !== null && _b !== void 0 ? _b : ""; message.type = (_c = object.type) !== null && _c !== void 0 ? _c : 0; message.width = (_d = object.width) !== null && _d !== void 0 ? _d : 0; message.height = (_e = object.height) !== null && _e !== void 0 ? _e : 0; message.muted = (_f = object.muted) !== null && _f !== void 0 ? _f : false; message.disableDtx = (_g = object.disableDtx) !== null && _g !== void 0 ? _g : false; message.source = (_h = object.source) !== null && _h !== void 0 ? _h : 0; message.layers = ((_j = object.layers) === null || _j === void 0 ? void 0 : _j.map(e => VideoLayer.fromPartial(e))) || []; message.simulcastCodecs = ((_k = object.simulcastCodecs) === null || _k === void 0 ? void 0 : _k.map(e => SimulcastCodec.fromPartial(e))) || []; message.sid = (_l = object.sid) !== null && _l !== void 0 ? _l : ""; message.stereo = (_m = object.stereo) !== null && _m !== void 0 ? _m : false; message.disableRed = (_o = object.disableRed) !== null && _o !== void 0 ? _o : false; message.encryption = (_p = object.encryption) !== null && _p !== void 0 ? _p : 0; return message; } }; function createBaseTrickleRequest() { return { candidateInit: "", target: 0 }; } const TrickleRequest = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.candidateInit !== "") { writer.uint32(10).string(message.candidateInit); } if (message.target !== 0) { writer.uint32(16).int32(message.target); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseTrickleRequest(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.candidateInit = reader.string(); break; case 2: message.target = reader.int32(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { candidateInit: isSet(object.candidateInit) ? String(object.candidateInit) : "", target: isSet(object.target) ? signalTargetFromJSON(object.target) : 0 }; }, toJSON(message) { const obj = {}; message.candidateInit !== undefined && (obj.candidateInit = message.candidateInit); message.target !== undefined && (obj.target = signalTargetToJSON(message.target)); return obj; }, create(base) { return TrickleRequest.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b; const message = createBaseTrickleRequest(); message.candidateInit = (_a = object.candidateInit) !== null && _a !== void 0 ? _a : ""; message.target = (_b = object.target) !== null && _b !== void 0 ? _b : 0; return message; } }; function createBaseMuteTrackRequest() { return { sid: "", muted: false }; } const MuteTrackRequest = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.sid !== "") { writer.uint32(10).string(message.sid); } if (message.muted === true) { writer.uint32(16).bool(message.muted); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseMuteTrackRequest(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.sid = reader.string(); break; case 2: message.muted = reader.bool(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { sid: isSet(object.sid) ? String(object.sid) : "", muted: isSet(object.muted) ? Boolean(object.muted) : false }; }, toJSON(message) { const obj = {}; message.sid !== undefined && (obj.sid = message.sid); message.muted !== undefined && (obj.muted = message.muted); return obj; }, create(base) { return MuteTrackRequest.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b; const message = createBaseMuteTrackRequest(); message.sid = (_a = object.sid) !== null && _a !== void 0 ? _a : ""; message.muted = (_b = object.muted) !== null && _b !== void 0 ? _b : false; return message; } }; function createBaseJoinResponse() { return { room: undefined, participant: undefined, otherParticipants: [], serverVersion: "", iceServers: [], subscriberPrimary: false, alternativeUrl: "", clientConfiguration: undefined, serverRegion: "", pingTimeout: 0, pingInterval: 0, serverInfo: undefined }; } const JoinResponse = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.room !== undefined) { Room$1.encode(message.room, writer.uint32(10).fork()).ldelim(); } if (message.participant !== undefined) { ParticipantInfo.encode(message.participant, writer.uint32(18).fork()).ldelim(); } for (const v of message.otherParticipants) { ParticipantInfo.encode(v, writer.uint32(26).fork()).ldelim(); } if (message.serverVersion !== "") { writer.uint32(34).string(message.serverVersion); } for (const v of message.iceServers) { ICEServer.encode(v, writer.uint32(42).fork()).ldelim(); } if (message.subscriberPrimary === true) { writer.uint32(48).bool(message.subscriberPrimary); } if (message.alternativeUrl !== "") { writer.uint32(58).string(message.alternativeUrl); } if (message.clientConfiguration !== undefined) { ClientConfiguration.encode(message.clientConfiguration, writer.uint32(66).fork()).ldelim(); } if (message.serverRegion !== "") { writer.uint32(74).string(message.serverRegion); } if (message.pingTimeout !== 0) { writer.uint32(80).int32(message.pingTimeout); } if (message.pingInterval !== 0) { writer.uint32(88).int32(message.pingInterval); } if (message.serverInfo !== undefined) { ServerInfo.encode(message.serverInfo, writer.uint32(98).fork()).ldelim(); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseJoinResponse(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.room = Room$1.decode(reader, reader.uint32()); break; case 2: message.participant = ParticipantInfo.decode(reader, reader.uint32()); break; case 3: message.otherParticipants.push(ParticipantInfo.decode(reader, reader.uint32())); break; case 4: message.serverVersion = reader.string(); break; case 5: message.iceServers.push(ICEServer.decode(reader, reader.uint32())); break; case 6: message.subscriberPrimary = reader.bool(); break; case 7: message.alternativeUrl = reader.string(); break; case 8: message.clientConfiguration = ClientConfiguration.decode(reader, reader.uint32()); break; case 9: message.serverRegion = reader.string(); break; case 10: message.pingTimeout = reader.int32(); break; case 11: message.pingInterval = reader.int32(); break; case 12: message.serverInfo = ServerInfo.decode(reader, reader.uint32()); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { room: isSet(object.room) ? Room$1.fromJSON(object.room) : undefined, participant: isSet(object.participant) ? ParticipantInfo.fromJSON(object.participant) : undefined, otherParticipants: Array.isArray(object === null || object === void 0 ? void 0 : object.otherParticipants) ? object.otherParticipants.map(e => ParticipantInfo.fromJSON(e)) : [], serverVersion: isSet(object.serverVersion) ? String(object.serverVersion) : "", iceServers: Array.isArray(object === null || object === void 0 ? void 0 : object.iceServers) ? object.iceServers.map(e => ICEServer.fromJSON(e)) : [], subscriberPrimary: isSet(object.subscriberPrimary) ? Boolean(object.subscriberPrimary) : false, alternativeUrl: isSet(object.alternativeUrl) ? String(object.alternativeUrl) : "", clientConfiguration: isSet(object.clientConfiguration) ? ClientConfiguration.fromJSON(object.clientConfiguration) : undefined, serverRegion: isSet(object.serverRegion) ? String(object.serverRegion) : "", pingTimeout: isSet(object.pingTimeout) ? Number(object.pingTimeout) : 0, pingInterval: isSet(object.pingInterval) ? Number(object.pingInterval) : 0, serverInfo: isSet(object.serverInfo) ? ServerInfo.fromJSON(object.serverInfo) : undefined }; }, toJSON(message) { const obj = {}; message.room !== undefined && (obj.room = message.room ? Room$1.toJSON(message.room) : undefined); message.participant !== undefined && (obj.participant = message.participant ? ParticipantInfo.toJSON(message.participant) : undefined); if (message.otherParticipants) { obj.otherParticipants = message.otherParticipants.map(e => e ? ParticipantInfo.toJSON(e) : undefined); } else { obj.otherParticipants = []; } message.serverVersion !== undefined && (obj.serverVersion = message.serverVersion); if (message.iceServers) { obj.iceServers = message.iceServers.map(e => e ? ICEServer.toJSON(e) : undefined); } else { obj.iceServers = []; } message.subscriberPrimary !== undefined && (obj.subscriberPrimary = message.subscriberPrimary); message.alternativeUrl !== undefined && (obj.alternativeUrl = message.alternativeUrl); message.clientConfiguration !== undefined && (obj.clientConfiguration = message.clientConfiguration ? ClientConfiguration.toJSON(message.clientConfiguration) : undefined); message.serverRegion !== undefined && (obj.serverRegion = message.serverRegion); message.pingTimeout !== undefined && (obj.pingTimeout = Math.round(message.pingTimeout)); message.pingInterval !== undefined && (obj.pingInterval = Math.round(message.pingInterval)); message.serverInfo !== undefined && (obj.serverInfo = message.serverInfo ? ServerInfo.toJSON(message.serverInfo) : undefined); return obj; }, create(base) { return JoinResponse.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c, _d, _e, _f, _g, _h; const message = createBaseJoinResponse(); message.room = object.room !== undefined && object.room !== null ? Room$1.fromPartial(object.room) : undefined; message.participant = object.participant !== undefined && object.participant !== null ? ParticipantInfo.fromPartial(object.participant) : undefined; message.otherParticipants = ((_a = object.otherParticipants) === null || _a === void 0 ? void 0 : _a.map(e => ParticipantInfo.fromPartial(e))) || []; message.serverVersion = (_b = object.serverVersion) !== null && _b !== void 0 ? _b : ""; message.iceServers = ((_c = object.iceServers) === null || _c === void 0 ? void 0 : _c.map(e => ICEServer.fromPartial(e))) || []; message.subscriberPrimary = (_d = object.subscriberPrimary) !== null && _d !== void 0 ? _d : false; message.alternativeUrl = (_e = object.alternativeUrl) !== null && _e !== void 0 ? _e : ""; message.clientConfiguration = object.clientConfiguration !== undefined && object.clientConfiguration !== null ? ClientConfiguration.fromPartial(object.clientConfiguration) : undefined; message.serverRegion = (_f = object.serverRegion) !== null && _f !== void 0 ? _f : ""; message.pingTimeout = (_g = object.pingTimeout) !== null && _g !== void 0 ? _g : 0; message.pingInterval = (_h = object.pingInterval) !== null && _h !== void 0 ? _h : 0; message.serverInfo = object.serverInfo !== undefined && object.serverInfo !== null ? ServerInfo.fromPartial(object.serverInfo) : undefined; return message; } }; function createBaseReconnectResponse() { return { iceServers: [], clientConfiguration: undefined }; } const ReconnectResponse = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); for (const v of message.iceServers) { ICEServer.encode(v, writer.uint32(10).fork()).ldelim(); } if (message.clientConfiguration !== undefined) { ClientConfiguration.encode(message.clientConfiguration, writer.uint32(18).fork()).ldelim(); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseReconnectResponse(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.iceServers.push(ICEServer.decode(reader, reader.uint32())); break; case 2: message.clientConfiguration = ClientConfiguration.decode(reader, reader.uint32()); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { iceServers: Array.isArray(object === null || object === void 0 ? void 0 : object.iceServers) ? object.iceServers.map(e => ICEServer.fromJSON(e)) : [], clientConfiguration: isSet(object.clientConfiguration) ? ClientConfiguration.fromJSON(object.clientConfiguration) : undefined }; }, toJSON(message) { const obj = {}; if (message.iceServers) { obj.iceServers = message.iceServers.map(e => e ? ICEServer.toJSON(e) : undefined); } else { obj.iceServers = []; } message.clientConfiguration !== undefined && (obj.clientConfiguration = message.clientConfiguration ? ClientConfiguration.toJSON(message.clientConfiguration) : undefined); return obj; }, create(base) { return ReconnectResponse.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a; const message = createBaseReconnectResponse(); message.iceServers = ((_a = object.iceServers) === null || _a === void 0 ? void 0 : _a.map(e => ICEServer.fromPartial(e))) || []; message.clientConfiguration = object.clientConfiguration !== undefined && object.clientConfiguration !== null ? ClientConfiguration.fromPartial(object.clientConfiguration) : undefined; return message; } }; function createBaseTrackPublishedResponse() { return { cid: "", track: undefined }; } const TrackPublishedResponse = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.cid !== "") { writer.uint32(10).string(message.cid); } if (message.track !== undefined) { TrackInfo.encode(message.track, writer.uint32(18).fork()).ldelim(); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseTrackPublishedResponse(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.cid = reader.string(); break; case 2: message.track = TrackInfo.decode(reader, reader.uint32()); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { cid: isSet(object.cid) ? String(object.cid) : "", track: isSet(object.track) ? TrackInfo.fromJSON(object.track) : undefined }; }, toJSON(message) { const obj = {}; message.cid !== undefined && (obj.cid = message.cid); message.track !== undefined && (obj.track = message.track ? TrackInfo.toJSON(message.track) : undefined); return obj; }, create(base) { return TrackPublishedResponse.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a; const message = createBaseTrackPublishedResponse(); message.cid = (_a = object.cid) !== null && _a !== void 0 ? _a : ""; message.track = object.track !== undefined && object.track !== null ? TrackInfo.fromPartial(object.track) : undefined; return message; } }; function createBaseTrackUnpublishedResponse() { return { trackSid: "" }; } const TrackUnpublishedResponse = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.trackSid !== "") { writer.uint32(10).string(message.trackSid); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseTrackUnpublishedResponse(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.trackSid = reader.string(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { trackSid: isSet(object.trackSid) ? String(object.trackSid) : "" }; }, toJSON(message) { const obj = {}; message.trackSid !== undefined && (obj.trackSid = message.trackSid); return obj; }, create(base) { return TrackUnpublishedResponse.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a; const message = createBaseTrackUnpublishedResponse(); message.trackSid = (_a = object.trackSid) !== null && _a !== void 0 ? _a : ""; return message; } }; function createBaseSessionDescription() { return { type: "", sdp: "" }; } const SessionDescription = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.type !== "") { writer.uint32(10).string(message.type); } if (message.sdp !== "") { writer.uint32(18).string(message.sdp); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseSessionDescription(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.type = reader.string(); break; case 2: message.sdp = reader.string(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { type: isSet(object.type) ? String(object.type) : "", sdp: isSet(object.sdp) ? String(object.sdp) : "" }; }, toJSON(message) { const obj = {}; message.type !== undefined && (obj.type = message.type); message.sdp !== undefined && (obj.sdp = message.sdp); return obj; }, create(base) { return SessionDescription.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b; const message = createBaseSessionDescription(); message.type = (_a = object.type) !== null && _a !== void 0 ? _a : ""; message.sdp = (_b = object.sdp) !== null && _b !== void 0 ? _b : ""; return message; } }; function createBaseParticipantUpdate() { return { participants: [] }; } const ParticipantUpdate = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); for (const v of message.participants) { ParticipantInfo.encode(v, writer.uint32(10).fork()).ldelim(); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseParticipantUpdate(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.participants.push(ParticipantInfo.decode(reader, reader.uint32())); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { participants: Array.isArray(object === null || object === void 0 ? void 0 : object.participants) ? object.participants.map(e => ParticipantInfo.fromJSON(e)) : [] }; }, toJSON(message) { const obj = {}; if (message.participants) { obj.participants = message.participants.map(e => e ? ParticipantInfo.toJSON(e) : undefined); } else { obj.participants = []; } return obj; }, create(base) { return ParticipantUpdate.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a; const message = createBaseParticipantUpdate(); message.participants = ((_a = object.participants) === null || _a === void 0 ? void 0 : _a.map(e => ParticipantInfo.fromPartial(e))) || []; return message; } }; function createBaseUpdateSubscription() { return { trackSids: [], subscribe: false, participantTracks: [] }; } const UpdateSubscription = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); for (const v of message.trackSids) { writer.uint32(10).string(v); } if (message.subscribe === true) { writer.uint32(16).bool(message.subscribe); } for (const v of message.participantTracks) { ParticipantTracks.encode(v, writer.uint32(26).fork()).ldelim(); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseUpdateSubscription(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.trackSids.push(reader.string()); break; case 2: message.subscribe = reader.bool(); break; case 3: message.participantTracks.push(ParticipantTracks.decode(reader, reader.uint32())); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { trackSids: Array.isArray(object === null || object === void 0 ? void 0 : object.trackSids) ? object.trackSids.map(e => String(e)) : [], subscribe: isSet(object.subscribe) ? Boolean(object.subscribe) : false, participantTracks: Array.isArray(object === null || object === void 0 ? void 0 : object.participantTracks) ? object.participantTracks.map(e => ParticipantTracks.fromJSON(e)) : [] }; }, toJSON(message) { const obj = {}; if (message.trackSids) { obj.trackSids = message.trackSids.map(e => e); } else { obj.trackSids = []; } message.subscribe !== undefined && (obj.subscribe = message.subscribe); if (message.participantTracks) { obj.participantTracks = message.participantTracks.map(e => e ? ParticipantTracks.toJSON(e) : undefined); } else { obj.participantTracks = []; } return obj; }, create(base) { return UpdateSubscription.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c; const message = createBaseUpdateSubscription(); message.trackSids = ((_a = object.trackSids) === null || _a === void 0 ? void 0 : _a.map(e => e)) || []; message.subscribe = (_b = object.subscribe) !== null && _b !== void 0 ? _b : false; message.participantTracks = ((_c = object.participantTracks) === null || _c === void 0 ? void 0 : _c.map(e => ParticipantTracks.fromPartial(e))) || []; return message; } }; function createBaseUpdateTrackSettings() { return { trackSids: [], disabled: false, quality: 0, width: 0, height: 0, fps: 0, priority: 0 }; } const UpdateTrackSettings = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); for (const v of message.trackSids) { writer.uint32(10).string(v); } if (message.disabled === true) { writer.uint32(24).bool(message.disabled); } if (message.quality !== 0) { writer.uint32(32).int32(message.quality); } if (message.width !== 0) { writer.uint32(40).uint32(message.width); } if (message.height !== 0) { writer.uint32(48).uint32(message.height); } if (message.fps !== 0) { writer.uint32(56).uint32(message.fps); } if (message.priority !== 0) { writer.uint32(64).uint32(message.priority); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseUpdateTrackSettings(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.trackSids.push(reader.string()); break; case 3: message.disabled = reader.bool(); break; case 4: message.quality = reader.int32(); break; case 5: message.width = reader.uint32(); break; case 6: message.height = reader.uint32(); break; case 7: message.fps = reader.uint32(); break; case 8: message.priority = reader.uint32(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { trackSids: Array.isArray(object === null || object === void 0 ? void 0 : object.trackSids) ? object.trackSids.map(e => String(e)) : [], disabled: isSet(object.disabled) ? Boolean(object.disabled) : false, quality: isSet(object.quality) ? videoQualityFromJSON(object.quality) : 0, width: isSet(object.width) ? Number(object.width) : 0, height: isSet(object.height) ? Number(object.height) : 0, fps: isSet(object.fps) ? Number(object.fps) : 0, priority: isSet(object.priority) ? Number(object.priority) : 0 }; }, toJSON(message) { const obj = {}; if (message.trackSids) { obj.trackSids = message.trackSids.map(e => e); } else { obj.trackSids = []; } message.disabled !== undefined && (obj.disabled = message.disabled); message.quality !== undefined && (obj.quality = videoQualityToJSON(message.quality)); message.width !== undefined && (obj.width = Math.round(message.width)); message.height !== undefined && (obj.height = Math.round(message.height)); message.fps !== undefined && (obj.fps = Math.round(message.fps)); message.priority !== undefined && (obj.priority = Math.round(message.priority)); return obj; }, create(base) { return UpdateTrackSettings.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c, _d, _e, _f, _g; const message = createBaseUpdateTrackSettings(); message.trackSids = ((_a = object.trackSids) === null || _a === void 0 ? void 0 : _a.map(e => e)) || []; message.disabled = (_b = object.disabled) !== null && _b !== void 0 ? _b : false; message.quality = (_c = object.quality) !== null && _c !== void 0 ? _c : 0; message.width = (_d = object.width) !== null && _d !== void 0 ? _d : 0; message.height = (_e = object.height) !== null && _e !== void 0 ? _e : 0; message.fps = (_f = object.fps) !== null && _f !== void 0 ? _f : 0; message.priority = (_g = object.priority) !== null && _g !== void 0 ? _g : 0; return message; } }; function createBaseLeaveRequest() { return { canReconnect: false, reason: 0 }; } const LeaveRequest = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.canReconnect === true) { writer.uint32(8).bool(message.canReconnect); } if (message.reason !== 0) { writer.uint32(16).int32(message.reason); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseLeaveRequest(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.canReconnect = reader.bool(); break; case 2: message.reason = reader.int32(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { canReconnect: isSet(object.canReconnect) ? Boolean(object.canReconnect) : false, reason: isSet(object.reason) ? disconnectReasonFromJSON(object.reason) : 0 }; }, toJSON(message) { const obj = {}; message.canReconnect !== undefined && (obj.canReconnect = message.canReconnect); message.reason !== undefined && (obj.reason = disconnectReasonToJSON(message.reason)); return obj; }, create(base) { return LeaveRequest.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b; const message = createBaseLeaveRequest(); message.canReconnect = (_a = object.canReconnect) !== null && _a !== void 0 ? _a : false; message.reason = (_b = object.reason) !== null && _b !== void 0 ? _b : 0; return message; } }; function createBaseUpdateVideoLayers() { return { trackSid: "", layers: [] }; } const UpdateVideoLayers = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.trackSid !== "") { writer.uint32(10).string(message.trackSid); } for (const v of message.layers) { VideoLayer.encode(v, writer.uint32(18).fork()).ldelim(); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseUpdateVideoLayers(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.trackSid = reader.string(); break; case 2: message.layers.push(VideoLayer.decode(reader, reader.uint32())); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { trackSid: isSet(object.trackSid) ? String(object.trackSid) : "", layers: Array.isArray(object === null || object === void 0 ? void 0 : object.layers) ? object.layers.map(e => VideoLayer.fromJSON(e)) : [] }; }, toJSON(message) { const obj = {}; message.trackSid !== undefined && (obj.trackSid = message.trackSid); if (message.layers) { obj.layers = message.layers.map(e => e ? VideoLayer.toJSON(e) : undefined); } else { obj.layers = []; } return obj; }, create(base) { return UpdateVideoLayers.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b; const message = createBaseUpdateVideoLayers(); message.trackSid = (_a = object.trackSid) !== null && _a !== void 0 ? _a : ""; message.layers = ((_b = object.layers) === null || _b === void 0 ? void 0 : _b.map(e => VideoLayer.fromPartial(e))) || []; return message; } }; function createBaseUpdateParticipantMetadata() { return { metadata: "" }; } const UpdateParticipantMetadata = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.metadata !== "") { writer.uint32(10).string(message.metadata); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseUpdateParticipantMetadata(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.metadata = reader.string(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { metadata: isSet(object.metadata) ? String(object.metadata) : "" }; }, toJSON(message) { const obj = {}; message.metadata !== undefined && (obj.metadata = message.metadata); return obj; }, create(base) { return UpdateParticipantMetadata.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a; const message = createBaseUpdateParticipantMetadata(); message.metadata = (_a = object.metadata) !== null && _a !== void 0 ? _a : ""; return message; } }; function createBaseICEServer() { return { urls: [], username: "", credential: "" }; } const ICEServer = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); for (const v of message.urls) { writer.uint32(10).string(v); } if (message.username !== "") { writer.uint32(18).string(message.username); } if (message.credential !== "") { writer.uint32(26).string(message.credential); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseICEServer(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.urls.push(reader.string()); break; case 2: message.username = reader.string(); break; case 3: message.credential = reader.string(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { urls: Array.isArray(object === null || object === void 0 ? void 0 : object.urls) ? object.urls.map(e => String(e)) : [], username: isSet(object.username) ? String(object.username) : "", credential: isSet(object.credential) ? String(object.credential) : "" }; }, toJSON(message) { const obj = {}; if (message.urls) { obj.urls = message.urls.map(e => e); } else { obj.urls = []; } message.username !== undefined && (obj.username = message.username); message.credential !== undefined && (obj.credential = message.credential); return obj; }, create(base) { return ICEServer.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c; const message = createBaseICEServer(); message.urls = ((_a = object.urls) === null || _a === void 0 ? void 0 : _a.map(e => e)) || []; message.username = (_b = object.username) !== null && _b !== void 0 ? _b : ""; message.credential = (_c = object.credential) !== null && _c !== void 0 ? _c : ""; return message; } }; function createBaseSpeakersChanged() { return { speakers: [] }; } const SpeakersChanged = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); for (const v of message.speakers) { SpeakerInfo.encode(v, writer.uint32(10).fork()).ldelim(); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseSpeakersChanged(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.speakers.push(SpeakerInfo.decode(reader, reader.uint32())); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { speakers: Array.isArray(object === null || object === void 0 ? void 0 : object.speakers) ? object.speakers.map(e => SpeakerInfo.fromJSON(e)) : [] }; }, toJSON(message) { const obj = {}; if (message.speakers) { obj.speakers = message.speakers.map(e => e ? SpeakerInfo.toJSON(e) : undefined); } else { obj.speakers = []; } return obj; }, create(base) { return SpeakersChanged.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a; const message = createBaseSpeakersChanged(); message.speakers = ((_a = object.speakers) === null || _a === void 0 ? void 0 : _a.map(e => SpeakerInfo.fromPartial(e))) || []; return message; } }; function createBaseRoomUpdate() { return { room: undefined }; } const RoomUpdate = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.room !== undefined) { Room$1.encode(message.room, writer.uint32(10).fork()).ldelim(); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseRoomUpdate(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.room = Room$1.decode(reader, reader.uint32()); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { room: isSet(object.room) ? Room$1.fromJSON(object.room) : undefined }; }, toJSON(message) { const obj = {}; message.room !== undefined && (obj.room = message.room ? Room$1.toJSON(message.room) : undefined); return obj; }, create(base) { return RoomUpdate.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { const message = createBaseRoomUpdate(); message.room = object.room !== undefined && object.room !== null ? Room$1.fromPartial(object.room) : undefined; return message; } }; function createBaseConnectionQualityInfo() { return { participantSid: "", quality: 0, score: 0 }; } const ConnectionQualityInfo = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.participantSid !== "") { writer.uint32(10).string(message.participantSid); } if (message.quality !== 0) { writer.uint32(16).int32(message.quality); } if (message.score !== 0) { writer.uint32(29).float(message.score); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseConnectionQualityInfo(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.participantSid = reader.string(); break; case 2: message.quality = reader.int32(); break; case 3: message.score = reader.float(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { participantSid: isSet(object.participantSid) ? String(object.participantSid) : "", quality: isSet(object.quality) ? connectionQualityFromJSON(object.quality) : 0, score: isSet(object.score) ? Number(object.score) : 0 }; }, toJSON(message) { const obj = {}; message.participantSid !== undefined && (obj.participantSid = message.participantSid); message.quality !== undefined && (obj.quality = connectionQualityToJSON(message.quality)); message.score !== undefined && (obj.score = message.score); return obj; }, create(base) { return ConnectionQualityInfo.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c; const message = createBaseConnectionQualityInfo(); message.participantSid = (_a = object.participantSid) !== null && _a !== void 0 ? _a : ""; message.quality = (_b = object.quality) !== null && _b !== void 0 ? _b : 0; message.score = (_c = object.score) !== null && _c !== void 0 ? _c : 0; return message; } }; function createBaseConnectionQualityUpdate() { return { updates: [] }; } const ConnectionQualityUpdate = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); for (const v of message.updates) { ConnectionQualityInfo.encode(v, writer.uint32(10).fork()).ldelim(); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseConnectionQualityUpdate(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.updates.push(ConnectionQualityInfo.decode(reader, reader.uint32())); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { updates: Array.isArray(object === null || object === void 0 ? void 0 : object.updates) ? object.updates.map(e => ConnectionQualityInfo.fromJSON(e)) : [] }; }, toJSON(message) { const obj = {}; if (message.updates) { obj.updates = message.updates.map(e => e ? ConnectionQualityInfo.toJSON(e) : undefined); } else { obj.updates = []; } return obj; }, create(base) { return ConnectionQualityUpdate.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a; const message = createBaseConnectionQualityUpdate(); message.updates = ((_a = object.updates) === null || _a === void 0 ? void 0 : _a.map(e => ConnectionQualityInfo.fromPartial(e))) || []; return message; } }; function createBaseStreamStateInfo() { return { participantSid: "", trackSid: "", state: 0 }; } const StreamStateInfo = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.participantSid !== "") { writer.uint32(10).string(message.participantSid); } if (message.trackSid !== "") { writer.uint32(18).string(message.trackSid); } if (message.state !== 0) { writer.uint32(24).int32(message.state); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseStreamStateInfo(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.participantSid = reader.string(); break; case 2: message.trackSid = reader.string(); break; case 3: message.state = reader.int32(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { participantSid: isSet(object.participantSid) ? String(object.participantSid) : "", trackSid: isSet(object.trackSid) ? String(object.trackSid) : "", state: isSet(object.state) ? streamStateFromJSON(object.state) : 0 }; }, toJSON(message) { const obj = {}; message.participantSid !== undefined && (obj.participantSid = message.participantSid); message.trackSid !== undefined && (obj.trackSid = message.trackSid); message.state !== undefined && (obj.state = streamStateToJSON(message.state)); return obj; }, create(base) { return StreamStateInfo.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c; const message = createBaseStreamStateInfo(); message.participantSid = (_a = object.participantSid) !== null && _a !== void 0 ? _a : ""; message.trackSid = (_b = object.trackSid) !== null && _b !== void 0 ? _b : ""; message.state = (_c = object.state) !== null && _c !== void 0 ? _c : 0; return message; } }; function createBaseStreamStateUpdate() { return { streamStates: [] }; } const StreamStateUpdate = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); for (const v of message.streamStates) { StreamStateInfo.encode(v, writer.uint32(10).fork()).ldelim(); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseStreamStateUpdate(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.streamStates.push(StreamStateInfo.decode(reader, reader.uint32())); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { streamStates: Array.isArray(object === null || object === void 0 ? void 0 : object.streamStates) ? object.streamStates.map(e => StreamStateInfo.fromJSON(e)) : [] }; }, toJSON(message) { const obj = {}; if (message.streamStates) { obj.streamStates = message.streamStates.map(e => e ? StreamStateInfo.toJSON(e) : undefined); } else { obj.streamStates = []; } return obj; }, create(base) { return StreamStateUpdate.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a; const message = createBaseStreamStateUpdate(); message.streamStates = ((_a = object.streamStates) === null || _a === void 0 ? void 0 : _a.map(e => StreamStateInfo.fromPartial(e))) || []; return message; } }; function createBaseSubscribedQuality() { return { quality: 0, enabled: false }; } const SubscribedQuality = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.quality !== 0) { writer.uint32(8).int32(message.quality); } if (message.enabled === true) { writer.uint32(16).bool(message.enabled); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseSubscribedQuality(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.quality = reader.int32(); break; case 2: message.enabled = reader.bool(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { quality: isSet(object.quality) ? videoQualityFromJSON(object.quality) : 0, enabled: isSet(object.enabled) ? Boolean(object.enabled) : false }; }, toJSON(message) { const obj = {}; message.quality !== undefined && (obj.quality = videoQualityToJSON(message.quality)); message.enabled !== undefined && (obj.enabled = message.enabled); return obj; }, create(base) { return SubscribedQuality.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b; const message = createBaseSubscribedQuality(); message.quality = (_a = object.quality) !== null && _a !== void 0 ? _a : 0; message.enabled = (_b = object.enabled) !== null && _b !== void 0 ? _b : false; return message; } }; function createBaseSubscribedCodec() { return { codec: "", qualities: [] }; } const SubscribedCodec = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.codec !== "") { writer.uint32(10).string(message.codec); } for (const v of message.qualities) { SubscribedQuality.encode(v, writer.uint32(18).fork()).ldelim(); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseSubscribedCodec(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.codec = reader.string(); break; case 2: message.qualities.push(SubscribedQuality.decode(reader, reader.uint32())); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { codec: isSet(object.codec) ? String(object.codec) : "", qualities: Array.isArray(object === null || object === void 0 ? void 0 : object.qualities) ? object.qualities.map(e => SubscribedQuality.fromJSON(e)) : [] }; }, toJSON(message) { const obj = {}; message.codec !== undefined && (obj.codec = message.codec); if (message.qualities) { obj.qualities = message.qualities.map(e => e ? SubscribedQuality.toJSON(e) : undefined); } else { obj.qualities = []; } return obj; }, create(base) { return SubscribedCodec.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b; const message = createBaseSubscribedCodec(); message.codec = (_a = object.codec) !== null && _a !== void 0 ? _a : ""; message.qualities = ((_b = object.qualities) === null || _b === void 0 ? void 0 : _b.map(e => SubscribedQuality.fromPartial(e))) || []; return message; } }; function createBaseSubscribedQualityUpdate() { return { trackSid: "", subscribedQualities: [], subscribedCodecs: [] }; } const SubscribedQualityUpdate = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.trackSid !== "") { writer.uint32(10).string(message.trackSid); } for (const v of message.subscribedQualities) { SubscribedQuality.encode(v, writer.uint32(18).fork()).ldelim(); } for (const v of message.subscribedCodecs) { SubscribedCodec.encode(v, writer.uint32(26).fork()).ldelim(); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseSubscribedQualityUpdate(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.trackSid = reader.string(); break; case 2: message.subscribedQualities.push(SubscribedQuality.decode(reader, reader.uint32())); break; case 3: message.subscribedCodecs.push(SubscribedCodec.decode(reader, reader.uint32())); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { trackSid: isSet(object.trackSid) ? String(object.trackSid) : "", subscribedQualities: Array.isArray(object === null || object === void 0 ? void 0 : object.subscribedQualities) ? object.subscribedQualities.map(e => SubscribedQuality.fromJSON(e)) : [], subscribedCodecs: Array.isArray(object === null || object === void 0 ? void 0 : object.subscribedCodecs) ? object.subscribedCodecs.map(e => SubscribedCodec.fromJSON(e)) : [] }; }, toJSON(message) { const obj = {}; message.trackSid !== undefined && (obj.trackSid = message.trackSid); if (message.subscribedQualities) { obj.subscribedQualities = message.subscribedQualities.map(e => e ? SubscribedQuality.toJSON(e) : undefined); } else { obj.subscribedQualities = []; } if (message.subscribedCodecs) { obj.subscribedCodecs = message.subscribedCodecs.map(e => e ? SubscribedCodec.toJSON(e) : undefined); } else { obj.subscribedCodecs = []; } return obj; }, create(base) { return SubscribedQualityUpdate.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c; const message = createBaseSubscribedQualityUpdate(); message.trackSid = (_a = object.trackSid) !== null && _a !== void 0 ? _a : ""; message.subscribedQualities = ((_b = object.subscribedQualities) === null || _b === void 0 ? void 0 : _b.map(e => SubscribedQuality.fromPartial(e))) || []; message.subscribedCodecs = ((_c = object.subscribedCodecs) === null || _c === void 0 ? void 0 : _c.map(e => SubscribedCodec.fromPartial(e))) || []; return message; } }; function createBaseTrackPermission() { return { participantSid: "", allTracks: false, trackSids: [], participantIdentity: "" }; } const TrackPermission = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.participantSid !== "") { writer.uint32(10).string(message.participantSid); } if (message.allTracks === true) { writer.uint32(16).bool(message.allTracks); } for (const v of message.trackSids) { writer.uint32(26).string(v); } if (message.participantIdentity !== "") { writer.uint32(34).string(message.participantIdentity); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseTrackPermission(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.participantSid = reader.string(); break; case 2: message.allTracks = reader.bool(); break; case 3: message.trackSids.push(reader.string()); break; case 4: message.participantIdentity = reader.string(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { participantSid: isSet(object.participantSid) ? String(object.participantSid) : "", allTracks: isSet(object.allTracks) ? Boolean(object.allTracks) : false, trackSids: Array.isArray(object === null || object === void 0 ? void 0 : object.trackSids) ? object.trackSids.map(e => String(e)) : [], participantIdentity: isSet(object.participantIdentity) ? String(object.participantIdentity) : "" }; }, toJSON(message) { const obj = {}; message.participantSid !== undefined && (obj.participantSid = message.participantSid); message.allTracks !== undefined && (obj.allTracks = message.allTracks); if (message.trackSids) { obj.trackSids = message.trackSids.map(e => e); } else { obj.trackSids = []; } message.participantIdentity !== undefined && (obj.participantIdentity = message.participantIdentity); return obj; }, create(base) { return TrackPermission.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c, _d; const message = createBaseTrackPermission(); message.participantSid = (_a = object.participantSid) !== null && _a !== void 0 ? _a : ""; message.allTracks = (_b = object.allTracks) !== null && _b !== void 0 ? _b : false; message.trackSids = ((_c = object.trackSids) === null || _c === void 0 ? void 0 : _c.map(e => e)) || []; message.participantIdentity = (_d = object.participantIdentity) !== null && _d !== void 0 ? _d : ""; return message; } }; function createBaseSubscriptionPermission() { return { allParticipants: false, trackPermissions: [] }; } const SubscriptionPermission = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.allParticipants === true) { writer.uint32(8).bool(message.allParticipants); } for (const v of message.trackPermissions) { TrackPermission.encode(v, writer.uint32(18).fork()).ldelim(); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseSubscriptionPermission(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.allParticipants = reader.bool(); break; case 2: message.trackPermissions.push(TrackPermission.decode(reader, reader.uint32())); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { allParticipants: isSet(object.allParticipants) ? Boolean(object.allParticipants) : false, trackPermissions: Array.isArray(object === null || object === void 0 ? void 0 : object.trackPermissions) ? object.trackPermissions.map(e => TrackPermission.fromJSON(e)) : [] }; }, toJSON(message) { const obj = {}; message.allParticipants !== undefined && (obj.allParticipants = message.allParticipants); if (message.trackPermissions) { obj.trackPermissions = message.trackPermissions.map(e => e ? TrackPermission.toJSON(e) : undefined); } else { obj.trackPermissions = []; } return obj; }, create(base) { return SubscriptionPermission.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b; const message = createBaseSubscriptionPermission(); message.allParticipants = (_a = object.allParticipants) !== null && _a !== void 0 ? _a : false; message.trackPermissions = ((_b = object.trackPermissions) === null || _b === void 0 ? void 0 : _b.map(e => TrackPermission.fromPartial(e))) || []; return message; } }; function createBaseSubscriptionPermissionUpdate() { return { participantSid: "", trackSid: "", allowed: false }; } const SubscriptionPermissionUpdate = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.participantSid !== "") { writer.uint32(10).string(message.participantSid); } if (message.trackSid !== "") { writer.uint32(18).string(message.trackSid); } if (message.allowed === true) { writer.uint32(24).bool(message.allowed); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseSubscriptionPermissionUpdate(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.participantSid = reader.string(); break; case 2: message.trackSid = reader.string(); break; case 3: message.allowed = reader.bool(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { participantSid: isSet(object.participantSid) ? String(object.participantSid) : "", trackSid: isSet(object.trackSid) ? String(object.trackSid) : "", allowed: isSet(object.allowed) ? Boolean(object.allowed) : false }; }, toJSON(message) { const obj = {}; message.participantSid !== undefined && (obj.participantSid = message.participantSid); message.trackSid !== undefined && (obj.trackSid = message.trackSid); message.allowed !== undefined && (obj.allowed = message.allowed); return obj; }, create(base) { return SubscriptionPermissionUpdate.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c; const message = createBaseSubscriptionPermissionUpdate(); message.participantSid = (_a = object.participantSid) !== null && _a !== void 0 ? _a : ""; message.trackSid = (_b = object.trackSid) !== null && _b !== void 0 ? _b : ""; message.allowed = (_c = object.allowed) !== null && _c !== void 0 ? _c : false; return message; } }; function createBaseSyncState() { return { answer: undefined, subscription: undefined, publishTracks: [], dataChannels: [], offer: undefined }; } const SyncState = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.answer !== undefined) { SessionDescription.encode(message.answer, writer.uint32(10).fork()).ldelim(); } if (message.subscription !== undefined) { UpdateSubscription.encode(message.subscription, writer.uint32(18).fork()).ldelim(); } for (const v of message.publishTracks) { TrackPublishedResponse.encode(v, writer.uint32(26).fork()).ldelim(); } for (const v of message.dataChannels) { DataChannelInfo.encode(v, writer.uint32(34).fork()).ldelim(); } if (message.offer !== undefined) { SessionDescription.encode(message.offer, writer.uint32(42).fork()).ldelim(); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseSyncState(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.answer = SessionDescription.decode(reader, reader.uint32()); break; case 2: message.subscription = UpdateSubscription.decode(reader, reader.uint32()); break; case 3: message.publishTracks.push(TrackPublishedResponse.decode(reader, reader.uint32())); break; case 4: message.dataChannels.push(DataChannelInfo.decode(reader, reader.uint32())); break; case 5: message.offer = SessionDescription.decode(reader, reader.uint32()); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { answer: isSet(object.answer) ? SessionDescription.fromJSON(object.answer) : undefined, subscription: isSet(object.subscription) ? UpdateSubscription.fromJSON(object.subscription) : undefined, publishTracks: Array.isArray(object === null || object === void 0 ? void 0 : object.publishTracks) ? object.publishTracks.map(e => TrackPublishedResponse.fromJSON(e)) : [], dataChannels: Array.isArray(object === null || object === void 0 ? void 0 : object.dataChannels) ? object.dataChannels.map(e => DataChannelInfo.fromJSON(e)) : [], offer: isSet(object.offer) ? SessionDescription.fromJSON(object.offer) : undefined }; }, toJSON(message) { const obj = {}; message.answer !== undefined && (obj.answer = message.answer ? SessionDescription.toJSON(message.answer) : undefined); message.subscription !== undefined && (obj.subscription = message.subscription ? UpdateSubscription.toJSON(message.subscription) : undefined); if (message.publishTracks) { obj.publishTracks = message.publishTracks.map(e => e ? TrackPublishedResponse.toJSON(e) : undefined); } else { obj.publishTracks = []; } if (message.dataChannels) { obj.dataChannels = message.dataChannels.map(e => e ? DataChannelInfo.toJSON(e) : undefined); } else { obj.dataChannels = []; } message.offer !== undefined && (obj.offer = message.offer ? SessionDescription.toJSON(message.offer) : undefined); return obj; }, create(base) { return SyncState.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b; const message = createBaseSyncState(); message.answer = object.answer !== undefined && object.answer !== null ? SessionDescription.fromPartial(object.answer) : undefined; message.subscription = object.subscription !== undefined && object.subscription !== null ? UpdateSubscription.fromPartial(object.subscription) : undefined; message.publishTracks = ((_a = object.publishTracks) === null || _a === void 0 ? void 0 : _a.map(e => TrackPublishedResponse.fromPartial(e))) || []; message.dataChannels = ((_b = object.dataChannels) === null || _b === void 0 ? void 0 : _b.map(e => DataChannelInfo.fromPartial(e))) || []; message.offer = object.offer !== undefined && object.offer !== null ? SessionDescription.fromPartial(object.offer) : undefined; return message; } }; function createBaseDataChannelInfo() { return { label: "", id: 0, target: 0 }; } const DataChannelInfo = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.label !== "") { writer.uint32(10).string(message.label); } if (message.id !== 0) { writer.uint32(16).uint32(message.id); } if (message.target !== 0) { writer.uint32(24).int32(message.target); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseDataChannelInfo(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.label = reader.string(); break; case 2: message.id = reader.uint32(); break; case 3: message.target = reader.int32(); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { label: isSet(object.label) ? String(object.label) : "", id: isSet(object.id) ? Number(object.id) : 0, target: isSet(object.target) ? signalTargetFromJSON(object.target) : 0 }; }, toJSON(message) { const obj = {}; message.label !== undefined && (obj.label = message.label); message.id !== undefined && (obj.id = Math.round(message.id)); message.target !== undefined && (obj.target = signalTargetToJSON(message.target)); return obj; }, create(base) { return DataChannelInfo.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c; const message = createBaseDataChannelInfo(); message.label = (_a = object.label) !== null && _a !== void 0 ? _a : ""; message.id = (_b = object.id) !== null && _b !== void 0 ? _b : 0; message.target = (_c = object.target) !== null && _c !== void 0 ? _c : 0; return message; } }; function createBaseSimulateScenario() { return { scenario: undefined }; } const SimulateScenario = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); var _a; switch ((_a = message.scenario) === null || _a === void 0 ? void 0 : _a.$case) { case "speakerUpdate": writer.uint32(8).int32(message.scenario.speakerUpdate); break; case "nodeFailure": writer.uint32(16).bool(message.scenario.nodeFailure); break; case "migration": writer.uint32(24).bool(message.scenario.migration); break; case "serverLeave": writer.uint32(32).bool(message.scenario.serverLeave); break; case "switchCandidateProtocol": writer.uint32(40).int32(message.scenario.switchCandidateProtocol); break; } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseSimulateScenario(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.scenario = { $case: "speakerUpdate", speakerUpdate: reader.int32() }; break; case 2: message.scenario = { $case: "nodeFailure", nodeFailure: reader.bool() }; break; case 3: message.scenario = { $case: "migration", migration: reader.bool() }; break; case 4: message.scenario = { $case: "serverLeave", serverLeave: reader.bool() }; break; case 5: message.scenario = { $case: "switchCandidateProtocol", switchCandidateProtocol: reader.int32() }; break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { scenario: isSet(object.speakerUpdate) ? { $case: "speakerUpdate", speakerUpdate: Number(object.speakerUpdate) } : isSet(object.nodeFailure) ? { $case: "nodeFailure", nodeFailure: Boolean(object.nodeFailure) } : isSet(object.migration) ? { $case: "migration", migration: Boolean(object.migration) } : isSet(object.serverLeave) ? { $case: "serverLeave", serverLeave: Boolean(object.serverLeave) } : isSet(object.switchCandidateProtocol) ? { $case: "switchCandidateProtocol", switchCandidateProtocol: candidateProtocolFromJSON(object.switchCandidateProtocol) } : undefined }; }, toJSON(message) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l; const obj = {}; ((_a = message.scenario) === null || _a === void 0 ? void 0 : _a.$case) === "speakerUpdate" && (obj.speakerUpdate = Math.round((_b = message.scenario) === null || _b === void 0 ? void 0 : _b.speakerUpdate)); ((_c = message.scenario) === null || _c === void 0 ? void 0 : _c.$case) === "nodeFailure" && (obj.nodeFailure = (_d = message.scenario) === null || _d === void 0 ? void 0 : _d.nodeFailure); ((_e = message.scenario) === null || _e === void 0 ? void 0 : _e.$case) === "migration" && (obj.migration = (_f = message.scenario) === null || _f === void 0 ? void 0 : _f.migration); ((_g = message.scenario) === null || _g === void 0 ? void 0 : _g.$case) === "serverLeave" && (obj.serverLeave = (_h = message.scenario) === null || _h === void 0 ? void 0 : _h.serverLeave); ((_j = message.scenario) === null || _j === void 0 ? void 0 : _j.$case) === "switchCandidateProtocol" && (obj.switchCandidateProtocol = ((_k = message.scenario) === null || _k === void 0 ? void 0 : _k.switchCandidateProtocol) !== undefined ? candidateProtocolToJSON((_l = message.scenario) === null || _l === void 0 ? void 0 : _l.switchCandidateProtocol) : undefined); return obj; }, create(base) { return SimulateScenario.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q; const message = createBaseSimulateScenario(); if (((_a = object.scenario) === null || _a === void 0 ? void 0 : _a.$case) === "speakerUpdate" && ((_b = object.scenario) === null || _b === void 0 ? void 0 : _b.speakerUpdate) !== undefined && ((_c = object.scenario) === null || _c === void 0 ? void 0 : _c.speakerUpdate) !== null) { message.scenario = { $case: "speakerUpdate", speakerUpdate: object.scenario.speakerUpdate }; } if (((_d = object.scenario) === null || _d === void 0 ? void 0 : _d.$case) === "nodeFailure" && ((_e = object.scenario) === null || _e === void 0 ? void 0 : _e.nodeFailure) !== undefined && ((_f = object.scenario) === null || _f === void 0 ? void 0 : _f.nodeFailure) !== null) { message.scenario = { $case: "nodeFailure", nodeFailure: object.scenario.nodeFailure }; } if (((_g = object.scenario) === null || _g === void 0 ? void 0 : _g.$case) === "migration" && ((_h = object.scenario) === null || _h === void 0 ? void 0 : _h.migration) !== undefined && ((_j = object.scenario) === null || _j === void 0 ? void 0 : _j.migration) !== null) { message.scenario = { $case: "migration", migration: object.scenario.migration }; } if (((_k = object.scenario) === null || _k === void 0 ? void 0 : _k.$case) === "serverLeave" && ((_l = object.scenario) === null || _l === void 0 ? void 0 : _l.serverLeave) !== undefined && ((_m = object.scenario) === null || _m === void 0 ? void 0 : _m.serverLeave) !== null) { message.scenario = { $case: "serverLeave", serverLeave: object.scenario.serverLeave }; } if (((_o = object.scenario) === null || _o === void 0 ? void 0 : _o.$case) === "switchCandidateProtocol" && ((_p = object.scenario) === null || _p === void 0 ? void 0 : _p.switchCandidateProtocol) !== undefined && ((_q = object.scenario) === null || _q === void 0 ? void 0 : _q.switchCandidateProtocol) !== null) { message.scenario = { $case: "switchCandidateProtocol", switchCandidateProtocol: object.scenario.switchCandidateProtocol }; } return message; } }; function createBasePing() { return { timestamp: 0, rtt: 0 }; } const Ping = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.timestamp !== 0) { writer.uint32(8).int64(message.timestamp); } if (message.rtt !== 0) { writer.uint32(16).int64(message.rtt); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBasePing(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.timestamp = longToNumber(reader.int64()); break; case 2: message.rtt = longToNumber(reader.int64()); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { timestamp: isSet(object.timestamp) ? Number(object.timestamp) : 0, rtt: isSet(object.rtt) ? Number(object.rtt) : 0 }; }, toJSON(message) { const obj = {}; message.timestamp !== undefined && (obj.timestamp = Math.round(message.timestamp)); message.rtt !== undefined && (obj.rtt = Math.round(message.rtt)); return obj; }, create(base) { return Ping.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b; const message = createBasePing(); message.timestamp = (_a = object.timestamp) !== null && _a !== void 0 ? _a : 0; message.rtt = (_b = object.rtt) !== null && _b !== void 0 ? _b : 0; return message; } }; function createBasePong() { return { lastPingTimestamp: 0, timestamp: 0 }; } const Pong = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.lastPingTimestamp !== 0) { writer.uint32(8).int64(message.lastPingTimestamp); } if (message.timestamp !== 0) { writer.uint32(16).int64(message.timestamp); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBasePong(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: message.lastPingTimestamp = longToNumber(reader.int64()); break; case 2: message.timestamp = longToNumber(reader.int64()); break; default: reader.skipType(tag & 7); break; } } return message; }, fromJSON(object) { return { lastPingTimestamp: isSet(object.lastPingTimestamp) ? Number(object.lastPingTimestamp) : 0, timestamp: isSet(object.timestamp) ? Number(object.timestamp) : 0 }; }, toJSON(message) { const obj = {}; message.lastPingTimestamp !== undefined && (obj.lastPingTimestamp = Math.round(message.lastPingTimestamp)); message.timestamp !== undefined && (obj.timestamp = Math.round(message.timestamp)); return obj; }, create(base) { return Pong.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b; const message = createBasePong(); message.lastPingTimestamp = (_a = object.lastPingTimestamp) !== null && _a !== void 0 ? _a : 0; message.timestamp = (_b = object.timestamp) !== null && _b !== void 0 ? _b : 0; return message; } }; var tsProtoGlobalThis = (() => { if (typeof globalThis !== "undefined") { return globalThis; } if (typeof self !== "undefined") { return self; } if (typeof window !== "undefined") { return window; } if (typeof global !== "undefined") { return global; } throw "Unable to locate global object"; })(); function longToNumber(long) { if (long.gt(Number.MAX_SAFE_INTEGER)) { throw new tsProtoGlobalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER"); } return long.toNumber(); } if (_m0.util.Long !== Long) { _m0.util.Long = Long; _m0.configure(); } function isSet(value) { return value !== null && value !== undefined; } class LivekitError extends Error { constructor(code, message) { super(message || 'an error has occured'); this.code = code; } } class ConnectionError extends LivekitError { constructor(message, reason, status) { super(1, message); this.status = status; this.reason = reason; } } class DeviceUnsupportedError extends LivekitError { constructor(message) { super(21, message !== null && message !== void 0 ? message : 'device is unsupported'); } } class TrackInvalidError extends LivekitError { constructor(message) { super(20, message !== null && message !== void 0 ? message : 'track is invalid'); } } class UnsupportedServer extends LivekitError { constructor(message) { super(10, message !== null && message !== void 0 ? message : 'unsupported server'); } } class UnexpectedConnectionState extends LivekitError { constructor(message) { super(12, message !== null && message !== void 0 ? message : 'unexpected connection state'); } } class NegotiationError extends LivekitError { constructor(message) { super(13, message !== null && message !== void 0 ? message : 'unable to negotiate'); } } class PublishDataError extends LivekitError { constructor(message) { super(13, message !== null && message !== void 0 ? message : 'unable to publish data'); } } var MediaDeviceFailure; (function (MediaDeviceFailure) { // user rejected permissions MediaDeviceFailure["PermissionDenied"] = "PermissionDenied"; // device is not available MediaDeviceFailure["NotFound"] = "NotFound"; // device is in use. On Windows, only a single tab may get access to a device at a time. MediaDeviceFailure["DeviceInUse"] = "DeviceInUse"; MediaDeviceFailure["Other"] = "Other"; })(MediaDeviceFailure || (MediaDeviceFailure = {})); (function (MediaDeviceFailure) { function getFailure(error) { if (error && 'name' in error) { if (error.name === 'NotFoundError' || error.name === 'DevicesNotFoundError') { return MediaDeviceFailure.NotFound; } if (error.name === 'NotAllowedError' || error.name === 'PermissionDeniedError') { return MediaDeviceFailure.PermissionDenied; } if (error.name === 'NotReadableError' || error.name === 'TrackStartError') { return MediaDeviceFailure.DeviceInUse; } return MediaDeviceFailure.Other; } } MediaDeviceFailure.getFailure = getFailure; })(MediaDeviceFailure || (MediaDeviceFailure = {})); /** * Events are the primary way LiveKit notifies your application of changes. * * The following are events emitted by [[Room]], listen to room events like * * ```typescript * room.on(RoomEvent.TrackPublished, (track, publication, participant) => {}) * ``` */ var RoomEvent; (function (RoomEvent) { /** * When the connection to the server has been established */ RoomEvent["Connected"] = "connected"; /** * When the connection to the server has been interrupted and it's attempting * to reconnect. */ RoomEvent["Reconnecting"] = "reconnecting"; /** * Fires when a reconnection has been successful. */ RoomEvent["Reconnected"] = "reconnected"; /** * When disconnected from room. This fires when room.disconnect() is called or * when an unrecoverable connection issue had occured */ RoomEvent["Disconnected"] = "disconnected"; /** * Whenever the connection state of the room changes * * args: ([[ConnectionState]]) */ RoomEvent["ConnectionStateChanged"] = "connectionStateChanged"; /** * @deprecated StateChanged has been renamed to ConnectionStateChanged */ RoomEvent["StateChanged"] = "connectionStateChanged"; /** * When input or output devices on the machine have changed. */ RoomEvent["MediaDevicesChanged"] = "mediaDevicesChanged"; /** * When a [[RemoteParticipant]] joins *after* the local * participant. It will not emit events for participants that are already * in the room * * args: ([[RemoteParticipant]]) */ RoomEvent["ParticipantConnected"] = "participantConnected"; /** * When a [[RemoteParticipant]] leaves *after* the local * participant has joined. * * args: ([[RemoteParticipant]]) */ RoomEvent["ParticipantDisconnected"] = "participantDisconnected"; /** * When a new track is published to room *after* the local * participant has joined. It will not fire for tracks that are already published. * * A track published doesn't mean the participant has subscribed to it. It's * simply reflecting the state of the room. * * args: ([[RemoteTrackPublication]], [[RemoteParticipant]]) */ RoomEvent["TrackPublished"] = "trackPublished"; /** * The [[LocalParticipant]] has subscribed to a new track. This event will **always** * fire as long as new tracks are ready for use. * * args: ([[RemoteTrack]], [[RemoteTrackPublication]], [[RemoteParticipant]]) */ RoomEvent["TrackSubscribed"] = "trackSubscribed"; /** * Could not subscribe to a track * * args: (track sid, [[RemoteParticipant]]) */ RoomEvent["TrackSubscriptionFailed"] = "trackSubscriptionFailed"; /** * A [[RemoteParticipant]] has unpublished a track * * args: ([[RemoteTrackPublication]], [[RemoteParticipant]]) */ RoomEvent["TrackUnpublished"] = "trackUnpublished"; /** * A subscribed track is no longer available. Clients should listen to this * event and ensure they detach tracks. * * args: ([[Track]], [[RemoteTrackPublication]], [[RemoteParticipant]]) */ RoomEvent["TrackUnsubscribed"] = "trackUnsubscribed"; /** * A track that was muted, fires on both [[RemoteParticipant]]s and [[LocalParticipant]] * * args: ([[TrackPublication]], [[Participant]]) */ RoomEvent["TrackMuted"] = "trackMuted"; /** * A track that was unmuted, fires on both [[RemoteParticipant]]s and [[LocalParticipant]] * * args: ([[TrackPublication]], [[Participant]]) */ RoomEvent["TrackUnmuted"] = "trackUnmuted"; /** * A local track was published successfully. This event is helpful to know * when to update your local UI with the newly published track. * * args: ([[LocalTrackPublication]], [[LocalParticipant]]) */ RoomEvent["LocalTrackPublished"] = "localTrackPublished"; /** * A local track was unpublished. This event is helpful to know when to remove * the local track from your UI. * * When a user stops sharing their screen by pressing "End" on the browser UI, * this event will also fire. * * args: ([[LocalTrackPublication]], [[LocalParticipant]]) */ RoomEvent["LocalTrackUnpublished"] = "localTrackUnpublished"; /** * When a local audio track is published the SDK checks whether there is complete silence * on that track and emits the LocalAudioSilenceDetected event in that case. * This allows for applications to show UI informing users that they might have to * reset their audio hardware or check for proper device connectivity. */ RoomEvent["LocalAudioSilenceDetected"] = "localAudioSilenceDetected"; /** * Active speakers changed. List of speakers are ordered by their audio level. * loudest speakers first. This will include the LocalParticipant too. * * Speaker updates are sent only to the publishing participant and their subscribers. * * args: (Array<[[Participant]]>) */ RoomEvent["ActiveSpeakersChanged"] = "activeSpeakersChanged"; /** * Participant metadata is a simple way for app-specific state to be pushed to * all users. * When RoomService.UpdateParticipantMetadata is called to change a participant's * state, *all* participants in the room will fire this event. * * args: (prevMetadata: string, [[Participant]]) * */ RoomEvent["ParticipantMetadataChanged"] = "participantMetadataChanged"; /** * Room metadata is a simple way for app-specific state to be pushed to * all users. * When RoomService.UpdateRoomMetadata is called to change a room's state, * *all* participants in the room will fire this event. * * args: (string) */ RoomEvent["RoomMetadataChanged"] = "roomMetadataChanged"; /** * Data received from another participant. * Data packets provides the ability to use LiveKit to send/receive arbitrary payloads. * All participants in the room will receive the messages sent to the room. * * args: (payload: Uint8Array, participant: [[Participant]], kind: [[DataPacket_Kind]], topic?: string) */ RoomEvent["DataReceived"] = "dataReceived"; /** * Connection quality was changed for a Participant. It'll receive updates * from the local participant, as well as any [[RemoteParticipant]]s that we are * subscribed to. * * args: (connectionQuality: [[ConnectionQuality]], participant: [[Participant]]) */ RoomEvent["ConnectionQualityChanged"] = "connectionQualityChanged"; /** * StreamState indicates if a subscribed (remote) track has been paused by the SFU * (typically this happens because of subscriber's bandwidth constraints) * * When bandwidth conditions allow, the track will be resumed automatically. * TrackStreamStateChanged will also be emitted when that happens. * * args: (pub: [[RemoteTrackPublication]], streamState: [[Track.StreamState]], * participant: [[RemoteParticipant]]) */ RoomEvent["TrackStreamStateChanged"] = "trackStreamStateChanged"; /** * One of subscribed tracks have changed its permissions for the current * participant. If permission was revoked, then the track will no longer * be subscribed. If permission was granted, a TrackSubscribed event will * be emitted. * * args: (pub: [[RemoteTrackPublication]], * status: [[TrackPublication.SubscriptionStatus]], * participant: [[RemoteParticipant]]) */ RoomEvent["TrackSubscriptionPermissionChanged"] = "trackSubscriptionPermissionChanged"; /** * One of subscribed tracks have changed its status for the current * participant. * * args: (pub: [[RemoteTrackPublication]], * status: [[TrackPublication.SubscriptionStatus]], * participant: [[RemoteParticipant]]) */ RoomEvent["TrackSubscriptionStatusChanged"] = "trackSubscriptionStatusChanged"; /** * LiveKit will attempt to autoplay all audio tracks when you attach them to * audio elements. However, if that fails, we'll notify you via AudioPlaybackStatusChanged. * `Room.canPlayAudio` will indicate if audio playback is permitted. */ RoomEvent["AudioPlaybackStatusChanged"] = "audioPlaybackChanged"; /** * When we have encountered an error while attempting to create a track. * The errors take place in getUserMedia(). * Use MediaDeviceFailure.getFailure(error) to get the reason of failure. * [[LocalParticipant.lastCameraError]] and [[LocalParticipant.lastMicrophoneError]] * will indicate if it had an error while creating the audio or video track respectively. * * args: (error: Error) */ RoomEvent["MediaDevicesError"] = "mediaDevicesError"; /** * A participant's permission has changed. Currently only fired on LocalParticipant. * args: (prevPermissions: [[ParticipantPermission]], participant: [[Participant]]) */ RoomEvent["ParticipantPermissionsChanged"] = "participantPermissionsChanged"; /** * Signal connected, can publish tracks. */ RoomEvent["SignalConnected"] = "signalConnected"; /** * Recording of a room has started/stopped. Room.isRecording will be updated too. * args: (isRecording: boolean) */ RoomEvent["RecordingStatusChanged"] = "recordingStatusChanged"; })(RoomEvent || (RoomEvent = {})); var ParticipantEvent; (function (ParticipantEvent) { /** * When a new track is published to room *after* the local * participant has joined. It will not fire for tracks that are already published. * * A track published doesn't mean the participant has subscribed to it. It's * simply reflecting the state of the room. * * args: ([[RemoteTrackPublication]]) */ ParticipantEvent["TrackPublished"] = "trackPublished"; /** * Successfully subscribed to the [[RemoteParticipant]]'s track. * This event will **always** fire as long as new tracks are ready for use. * * args: ([[RemoteTrack]], [[RemoteTrackPublication]]) */ ParticipantEvent["TrackSubscribed"] = "trackSubscribed"; /** * Could not subscribe to a track * * args: (track sid) */ ParticipantEvent["TrackSubscriptionFailed"] = "trackSubscriptionFailed"; /** * A [[RemoteParticipant]] has unpublished a track * * args: ([[RemoteTrackPublication]]) */ ParticipantEvent["TrackUnpublished"] = "trackUnpublished"; /** * A subscribed track is no longer available. Clients should listen to this * event and ensure they detach tracks. * * args: ([[RemoteTrack]], [[RemoteTrackPublication]]) */ ParticipantEvent["TrackUnsubscribed"] = "trackUnsubscribed"; /** * A track that was muted, fires on both [[RemoteParticipant]]s and [[LocalParticipant]] * * args: ([[TrackPublication]]) */ ParticipantEvent["TrackMuted"] = "trackMuted"; /** * A track that was unmuted, fires on both [[RemoteParticipant]]s and [[LocalParticipant]] * * args: ([[TrackPublication]]) */ ParticipantEvent["TrackUnmuted"] = "trackUnmuted"; /** * A local track was published successfully. This event is helpful to know * when to update your local UI with the newly published track. * * args: ([[LocalTrackPublication]]) */ ParticipantEvent["LocalTrackPublished"] = "localTrackPublished"; /** * A local track was unpublished. This event is helpful to know when to remove * the local track from your UI. * * When a user stops sharing their screen by pressing "End" on the browser UI, * this event will also fire. * * args: ([[LocalTrackPublication]]) */ ParticipantEvent["LocalTrackUnpublished"] = "localTrackUnpublished"; /** * Participant metadata is a simple way for app-specific state to be pushed to * all users. * When RoomService.UpdateParticipantMetadata is called to change a participant's * state, *all* participants in the room will fire this event. * To access the current metadata, see [[Participant.metadata]]. * * args: (prevMetadata: string) * */ ParticipantEvent["ParticipantMetadataChanged"] = "participantMetadataChanged"; /** * Data received from this participant as sender. * Data packets provides the ability to use LiveKit to send/receive arbitrary payloads. * All participants in the room will receive the messages sent to the room. * * args: (payload: Uint8Array, kind: [[DataPacket_Kind]]) */ ParticipantEvent["DataReceived"] = "dataReceived"; /** * Has speaking status changed for the current participant * * args: (speaking: boolean) */ ParticipantEvent["IsSpeakingChanged"] = "isSpeakingChanged"; /** * Connection quality was changed for a Participant. It'll receive updates * from the local participant, as well as any [[RemoteParticipant]]s that we are * subscribed to. * * args: (connectionQuality: [[ConnectionQuality]]) */ ParticipantEvent["ConnectionQualityChanged"] = "connectionQualityChanged"; /** * StreamState indicates if a subscribed track has been paused by the SFU * (typically this happens because of subscriber's bandwidth constraints) * * When bandwidth conditions allow, the track will be resumed automatically. * TrackStreamStateChanged will also be emitted when that happens. * * args: (pub: [[RemoteTrackPublication]], streamState: [[Track.StreamState]]) */ ParticipantEvent["TrackStreamStateChanged"] = "trackStreamStateChanged"; /** * One of subscribed tracks have changed its permissions for the current * participant. If permission was revoked, then the track will no longer * be subscribed. If permission was granted, a TrackSubscribed event will * be emitted. * * args: (pub: [[RemoteTrackPublication]], * status: [[TrackPublication.SubscriptionStatus]]) */ ParticipantEvent["TrackSubscriptionPermissionChanged"] = "trackSubscriptionPermissionChanged"; /** * One of the remote participants publications has changed its subscription status. * */ ParticipantEvent["TrackSubscriptionStatusChanged"] = "trackSubscriptionStatusChanged"; // fired only on LocalParticipant /** @internal */ ParticipantEvent["MediaDevicesError"] = "mediaDevicesError"; /** * A participant's permission has changed. Currently only fired on LocalParticipant. * args: (prevPermissions: [[ParticipantPermission]]) */ ParticipantEvent["ParticipantPermissionsChanged"] = "participantPermissionsChanged"; })(ParticipantEvent || (ParticipantEvent = {})); /** @internal */ var EngineEvent; (function (EngineEvent) { EngineEvent["TransportsCreated"] = "transportsCreated"; EngineEvent["Connected"] = "connected"; EngineEvent["Disconnected"] = "disconnected"; EngineEvent["Resuming"] = "resuming"; EngineEvent["Resumed"] = "resumed"; EngineEvent["Restarting"] = "restarting"; EngineEvent["Restarted"] = "restarted"; EngineEvent["SignalResumed"] = "signalResumed"; EngineEvent["Closing"] = "closing"; EngineEvent["MediaTrackAdded"] = "mediaTrackAdded"; EngineEvent["ActiveSpeakersUpdate"] = "activeSpeakersUpdate"; EngineEvent["DataPacketReceived"] = "dataPacketReceived"; })(EngineEvent || (EngineEvent = {})); var TrackEvent; (function (TrackEvent) { TrackEvent["Message"] = "message"; TrackEvent["Muted"] = "muted"; TrackEvent["Unmuted"] = "unmuted"; /** * Only fires on LocalTracks */ TrackEvent["Restarted"] = "restarted"; TrackEvent["Ended"] = "ended"; TrackEvent["Subscribed"] = "subscribed"; TrackEvent["Unsubscribed"] = "unsubscribed"; /** @internal */ TrackEvent["UpdateSettings"] = "updateSettings"; /** @internal */ TrackEvent["UpdateSubscription"] = "updateSubscription"; /** @internal */ TrackEvent["AudioPlaybackStarted"] = "audioPlaybackStarted"; /** @internal */ TrackEvent["AudioPlaybackFailed"] = "audioPlaybackFailed"; /** * @internal * Only fires on LocalAudioTrack instances */ TrackEvent["AudioSilenceDetected"] = "audioSilenceDetected"; /** @internal */ TrackEvent["VisibilityChanged"] = "visibilityChanged"; /** @internal */ TrackEvent["VideoDimensionsChanged"] = "videoDimensionsChanged"; /** @internal */ TrackEvent["ElementAttached"] = "elementAttached"; /** @internal */ TrackEvent["ElementDetached"] = "elementDetached"; /** * @internal * Only fires on LocalTracks */ TrackEvent["UpstreamPaused"] = "upstreamPaused"; /** * @internal * Only fires on LocalTracks */ TrackEvent["UpstreamResumed"] = "upstreamResumed"; /** * @internal * Fires on RemoteTrackPublication */ TrackEvent["SubscriptionPermissionChanged"] = "subscriptionPermissionChanged"; /** * Fires on RemoteTrackPublication */ TrackEvent["SubscriptionStatusChanged"] = "subscriptionStatusChanged"; })(TrackEvent || (TrackEvent = {})); const monitorFrequency = 2000; function computeBitrate(currentStats, prevStats) { if (!prevStats) { return 0; } let bytesNow; let bytesPrev; if ('bytesReceived' in currentStats) { bytesNow = currentStats.bytesReceived; bytesPrev = prevStats.bytesReceived; } else if ('bytesSent' in currentStats) { bytesNow = currentStats.bytesSent; bytesPrev = prevStats.bytesSent; } if (bytesNow === undefined || bytesPrev === undefined || currentStats.timestamp === undefined || prevStats.timestamp === undefined) { return 0; } return (bytesNow - bytesPrev) * 8 * 1000 / (currentStats.timestamp - prevStats.timestamp); } var uaParserExports = {}; var uaParser = { get exports(){ return uaParserExports; }, set exports(v){ uaParserExports = v; }, }; (function (module, exports) { ///////////////////////////////////////////////////////////////////////////////// /* UAParser.js v1.0.33 Copyright © 2012-2021 Faisal Salman MIT License */ /* Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data. Supports browser & node.js environment. Demo : https://faisalman.github.io/ua-parser-js Source : https://github.com/faisalman/ua-parser-js */ ///////////////////////////////////////////////////////////////////////////////// (function (window, undefined$1) { ////////////// // Constants ///////////// var LIBVERSION = '1.0.33', EMPTY = '', UNKNOWN = '?', FUNC_TYPE = 'function', UNDEF_TYPE = 'undefined', OBJ_TYPE = 'object', STR_TYPE = 'string', MAJOR = 'major', MODEL = 'model', NAME = 'name', TYPE = 'type', VENDOR = 'vendor', VERSION = 'version', ARCHITECTURE = 'architecture', CONSOLE = 'console', MOBILE = 'mobile', TABLET = 'tablet', SMARTTV = 'smarttv', WEARABLE = 'wearable', EMBEDDED = 'embedded', UA_MAX_LENGTH = 350; var AMAZON = 'Amazon', APPLE = 'Apple', ASUS = 'ASUS', BLACKBERRY = 'BlackBerry', BROWSER = 'Browser', CHROME = 'Chrome', EDGE = 'Edge', FIREFOX = 'Firefox', GOOGLE = 'Google', HUAWEI = 'Huawei', LG = 'LG', MICROSOFT = 'Microsoft', MOTOROLA = 'Motorola', OPERA = 'Opera', SAMSUNG = 'Samsung', SHARP = 'Sharp', SONY = 'Sony', XIAOMI = 'Xiaomi', ZEBRA = 'Zebra', FACEBOOK = 'Facebook'; /////////// // Helper ////////// var extend = function (regexes, extensions) { var mergedRegexes = {}; for (var i in regexes) { if (extensions[i] && extensions[i].length % 2 === 0) { mergedRegexes[i] = extensions[i].concat(regexes[i]); } else { mergedRegexes[i] = regexes[i]; } } return mergedRegexes; }, enumerize = function (arr) { var enums = {}; for (var i = 0; i < arr.length; i++) { enums[arr[i].toUpperCase()] = arr[i]; } return enums; }, has = function (str1, str2) { return typeof str1 === STR_TYPE ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false; }, lowerize = function (str) { return str.toLowerCase(); }, majorize = function (version) { return typeof version === STR_TYPE ? version.replace(/[^\d\.]/g, EMPTY).split('.')[0] : undefined$1; }, trim = function (str, len) { if (typeof str === STR_TYPE) { str = str.replace(/^\s\s*/, EMPTY); return typeof len === UNDEF_TYPE ? str : str.substring(0, UA_MAX_LENGTH); } }; /////////////// // Map helper ////////////// var rgxMapper = function (ua, arrays) { var i = 0, j, k, p, q, matches, match; // loop through all regexes maps while (i < arrays.length && !matches) { var regex = arrays[i], // even sequence (0,2,4,..) props = arrays[i + 1]; // odd sequence (1,3,5,..) j = k = 0; // try matching uastring with regexes while (j < regex.length && !matches) { matches = regex[j++].exec(ua); if (!!matches) { for (p = 0; p < props.length; p++) { match = matches[++k]; q = props[p]; // check if given property is actually array if (typeof q === OBJ_TYPE && q.length > 0) { if (q.length === 2) { if (typeof q[1] == FUNC_TYPE) { // assign modified match this[q[0]] = q[1].call(this, match); } else { // assign given value, ignore regex match this[q[0]] = q[1]; } } else if (q.length === 3) { // check whether function or regex if (typeof q[1] === FUNC_TYPE && !(q[1].exec && q[1].test)) { // call function (usually string mapper) this[q[0]] = match ? q[1].call(this, match, q[2]) : undefined$1; } else { // sanitize match using given regex this[q[0]] = match ? match.replace(q[1], q[2]) : undefined$1; } } else if (q.length === 4) { this[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined$1; } } else { this[q] = match ? match : undefined$1; } } } } i += 2; } }, strMapper = function (str, map) { for (var i in map) { // check if current value is array if (typeof map[i] === OBJ_TYPE && map[i].length > 0) { for (var j = 0; j < map[i].length; j++) { if (has(map[i][j], str)) { return i === UNKNOWN ? undefined$1 : i; } } } else if (has(map[i], str)) { return i === UNKNOWN ? undefined$1 : i; } } return str; }; /////////////// // String map ////////////// // Safari < 3.0 var oldSafariMap = { '1.0': '/8', '1.2': '/1', '1.3': '/3', '2.0': '/412', '2.0.2': '/416', '2.0.3': '/417', '2.0.4': '/419', '?': '/' }, windowsVersionMap = { 'ME': '4.90', 'NT 3.11': 'NT3.51', 'NT 4.0': 'NT4.0', '2000': 'NT 5.0', 'XP': ['NT 5.1', 'NT 5.2'], 'Vista': 'NT 6.0', '7': 'NT 6.1', '8': 'NT 6.2', '8.1': 'NT 6.3', '10': ['NT 6.4', 'NT 10.0'], 'RT': 'ARM' }; ////////////// // Regex map ///////////// var regexes = { browser: [[/\b(?:crmo|crios)\/([\w\.]+)/i // Chrome for Android/iOS ], [VERSION, [NAME, 'Chrome']], [/edg(?:e|ios|a)?\/([\w\.]+)/i // Microsoft Edge ], [VERSION, [NAME, 'Edge']], [ // Presto based /(opera mini)\/([-\w\.]+)/i, // Opera Mini /(opera [mobiletab]{3,6})\b.+version\/([-\w\.]+)/i, // Opera Mobi/Tablet /(opera)(?:.+version\/|[\/ ]+)([\w\.]+)/i // Opera ], [NAME, VERSION], [/opios[\/ ]+([\w\.]+)/i // Opera mini on iphone >= 8.0 ], [VERSION, [NAME, OPERA + ' Mini']], [/\bopr\/([\w\.]+)/i // Opera Webkit ], [VERSION, [NAME, OPERA]], [ // Mixed /(kindle)\/([\w\.]+)/i, // Kindle /(lunascape|maxthon|netfront|jasmine|blazer)[\/ ]?([\w\.]*)/i, // Lunascape/Maxthon/Netfront/Jasmine/Blazer // Trident based /(avant |iemobile|slim)(?:browser)?[\/ ]?([\w\.]*)/i, // Avant/IEMobile/SlimBrowser /(ba?idubrowser)[\/ ]?([\w\.]+)/i, // Baidu Browser /(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer // Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon /(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|quark|qupzilla|falkon|rekonq|puffin|brave|whale|qqbrowserlite|qq|duckduckgo)\/([-\w\.]+)/i, // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ, aka ShouQ /(weibo)__([\d\.]+)/i // Weibo ], [NAME, VERSION], [/(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i // UCBrowser ], [VERSION, [NAME, 'UC' + BROWSER]], [/microm.+\bqbcore\/([\w\.]+)/i, // WeChat Desktop for Windows Built-in Browser /\bqbcore\/([\w\.]+).+microm/i], [VERSION, [NAME, 'WeChat(Win) Desktop']], [/micromessenger\/([\w\.]+)/i // WeChat ], [VERSION, [NAME, 'WeChat']], [/konqueror\/([\w\.]+)/i // Konqueror ], [VERSION, [NAME, 'Konqueror']], [/trident.+rv[: ]([\w\.]{1,9})\b.+like gecko/i // IE11 ], [VERSION, [NAME, 'IE']], [/yabrowser\/([\w\.]+)/i // Yandex ], [VERSION, [NAME, 'Yandex']], [/(avast|avg)\/([\w\.]+)/i // Avast/AVG Secure Browser ], [[NAME, /(.+)/, '$1 Secure ' + BROWSER], VERSION], [/\bfocus\/([\w\.]+)/i // Firefox Focus ], [VERSION, [NAME, FIREFOX + ' Focus']], [/\bopt\/([\w\.]+)/i // Opera Touch ], [VERSION, [NAME, OPERA + ' Touch']], [/coc_coc\w+\/([\w\.]+)/i // Coc Coc Browser ], [VERSION, [NAME, 'Coc Coc']], [/dolfin\/([\w\.]+)/i // Dolphin ], [VERSION, [NAME, 'Dolphin']], [/coast\/([\w\.]+)/i // Opera Coast ], [VERSION, [NAME, OPERA + ' Coast']], [/miuibrowser\/([\w\.]+)/i // MIUI Browser ], [VERSION, [NAME, 'MIUI ' + BROWSER]], [/fxios\/([-\w\.]+)/i // Firefox for iOS ], [VERSION, [NAME, FIREFOX]], [/\bqihu|(qi?ho?o?|360)browser/i // 360 ], [[NAME, '360 ' + BROWSER]], [/(oculus|samsung|sailfish|huawei)browser\/([\w\.]+)/i], [[NAME, /(.+)/, '$1 ' + BROWSER], VERSION], [ // Oculus/Samsung/Sailfish/Huawei Browser /(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon ], [[NAME, /_/g, ' '], VERSION], [/(electron)\/([\w\.]+) safari/i, // Electron-based App /(tesla)(?: qtcarbrowser|\/(20\d\d\.[-\w\.]+))/i, // Tesla /m?(qqbrowser|baiduboxapp|2345Explorer)[\/ ]?([\w\.]+)/i // QQBrowser/Baidu App/2345 Browser ], [NAME, VERSION], [/(metasr)[\/ ]?([\w\.]+)/i, // SouGouBrowser /(lbbrowser)/i, // LieBao Browser /\[(linkedin)app\]/i // LinkedIn App for iOS & Android ], [NAME], [ // WebView /((?:fban\/fbios|fb_iab\/fb4a)(?!.+fbav)|;fbav\/([\w\.]+);)/i // Facebook App for iOS & Android ], [[NAME, FACEBOOK], VERSION], [/safari (line)\/([\w\.]+)/i, // Line App for iOS /\b(line)\/([\w\.]+)\/iab/i, // Line App for Android /(chromium|instagram)[\/ ]([-\w\.]+)/i // Chromium/Instagram ], [NAME, VERSION], [/\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS ], [VERSION, [NAME, 'GSA']], [/headlesschrome(?:\/([\w\.]+)| )/i // Chrome Headless ], [VERSION, [NAME, CHROME + ' Headless']], [/ wv\).+(chrome)\/([\w\.]+)/i // Chrome WebView ], [[NAME, CHROME + ' WebView'], VERSION], [/droid.+ version\/([\w\.]+)\b.+(?:mobile safari|safari)/i // Android Browser ], [VERSION, [NAME, 'Android ' + BROWSER]], [/(chrome|omniweb|arora|[tizenoka]{5} ?browser)\/v?([\w\.]+)/i // Chrome/OmniWeb/Arora/Tizen/Nokia ], [NAME, VERSION], [/version\/([\w\.\,]+) .*mobile\/\w+ (safari)/i // Mobile Safari ], [VERSION, [NAME, 'Mobile Safari']], [/version\/([\w(\.|\,)]+) .*(mobile ?safari|safari)/i // Safari & Safari Mobile ], [VERSION, NAME], [/webkit.+?(mobile ?safari|safari)(\/[\w\.]+)/i // Safari < 3.0 ], [NAME, [VERSION, strMapper, oldSafariMap]], [/(webkit|khtml)\/([\w\.]+)/i], [NAME, VERSION], [ // Gecko based /(navigator|netscape\d?)\/([-\w\.]+)/i // Netscape ], [[NAME, 'Netscape'], VERSION], [/mobile vr; rv:([\w\.]+)\).+firefox/i // Firefox Reality ], [VERSION, [NAME, FIREFOX + ' Reality']], [/ekiohf.+(flow)\/([\w\.]+)/i, // Flow /(swiftfox)/i, // Swiftfox /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror|klar)[\/ ]?([\w\.\+]+)/i, // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror/Klar /(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\/([-\w\.]+)$/i, // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix /(firefox)\/([\w\.]+)/i, // Other Firefox-based /(mozilla)\/([\w\.]+) .+rv\:.+gecko\/\d+/i, // Mozilla // Other /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i, // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Sleipnir/Obigo/Mosaic/Go/ICE/UP.Browser /(links) \(([\w\.]+)/i // Links ], [NAME, VERSION], [/(cobalt)\/([\w\.]+)/i // Cobalt ], [NAME, [VERSION, /master.|lts./, ""]]], cpu: [[/(?:(amd|x(?:(?:86|64)[-_])?|wow|win)64)[;\)]/i // AMD64 (x64) ], [[ARCHITECTURE, 'amd64']], [/(ia32(?=;))/i // IA32 (quicktime) ], [[ARCHITECTURE, lowerize]], [/((?:i[346]|x)86)[;\)]/i // IA32 (x86) ], [[ARCHITECTURE, 'ia32']], [/\b(aarch64|arm(v?8e?l?|_?64))\b/i // ARM64 ], [[ARCHITECTURE, 'arm64']], [/\b(arm(?:v[67])?ht?n?[fl]p?)\b/i // ARMHF ], [[ARCHITECTURE, 'armhf']], [ // PocketPC mistakenly identified as PowerPC /windows (ce|mobile); ppc;/i], [[ARCHITECTURE, 'arm']], [/((?:ppc|powerpc)(?:64)?)(?: mac|;|\))/i // PowerPC ], [[ARCHITECTURE, /ower/, EMPTY, lowerize]], [/(sun4\w)[;\)]/i // SPARC ], [[ARCHITECTURE, 'sparc']], [/((?:avr32|ia64(?=;))|68k(?=\))|\barm(?=v(?:[1-7]|[5-7]1)l?|;|eabi)|(?=atmel )avr|(?:irix|mips|sparc)(?:64)?\b|pa-risc)/i // IA64, 68K, ARM/64, AVR/32, IRIX/64, MIPS/64, SPARC/64, PA-RISC ], [[ARCHITECTURE, lowerize]]], device: [[ ////////////////////////// // MOBILES & TABLETS // Ordered by popularity ///////////////////////// // Samsung /\b(sch-i[89]0\d|shw-m380s|sm-[ptx]\w{2,4}|gt-[pn]\d{2,4}|sgh-t8[56]9|nexus 10)/i], [MODEL, [VENDOR, SAMSUNG], [TYPE, TABLET]], [/\b((?:s[cgp]h|gt|sm)-\w+|galaxy nexus)/i, /samsung[- ]([-\w]+)/i, /sec-(sgh\w+)/i], [MODEL, [VENDOR, SAMSUNG], [TYPE, MOBILE]], [ // Apple /\((ip(?:hone|od)[\w ]*);/i // iPod/iPhone ], [MODEL, [VENDOR, APPLE], [TYPE, MOBILE]], [/\((ipad);[-\w\),; ]+apple/i, // iPad /applecoremedia\/[\w\.]+ \((ipad)/i, /\b(ipad)\d\d?,\d\d?[;\]].+ios/i], [MODEL, [VENDOR, APPLE], [TYPE, TABLET]], [/(macintosh);/i], [MODEL, [VENDOR, APPLE]], [ // Huawei /\b((?:ag[rs][23]?|bah2?|sht?|btv)-a?[lw]\d{2})\b(?!.+d\/s)/i], [MODEL, [VENDOR, HUAWEI], [TYPE, TABLET]], [/(?:huawei|honor)([-\w ]+)[;\)]/i, /\b(nexus 6p|\w{2,4}e?-[atu]?[ln][\dx][012359c][adn]?)\b(?!.+d\/s)/i], [MODEL, [VENDOR, HUAWEI], [TYPE, MOBILE]], [ // Xiaomi /\b(poco[\w ]+)(?: bui|\))/i, // Xiaomi POCO /\b; (\w+) build\/hm\1/i, // Xiaomi Hongmi 'numeric' models /\b(hm[-_ ]?note?[_ ]?(?:\d\w)?) bui/i, // Xiaomi Hongmi /\b(redmi[\-_ ]?(?:note|k)?[\w_ ]+)(?: bui|\))/i, // Xiaomi Redmi /\b(mi[-_ ]?(?:a\d|one|one[_ ]plus|note lte|max|cc)?[_ ]?(?:\d?\w?)[_ ]?(?:plus|se|lite)?)(?: bui|\))/i // Xiaomi Mi ], [[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, MOBILE]], [/\b(mi[-_ ]?(?:pad)(?:[\w_ ]+))(?: bui|\))/i // Mi Pad tablets ], [[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, TABLET]], [ // OPPO /; (\w+) bui.+ oppo/i, /\b(cph[12]\d{3}|p(?:af|c[al]|d\w|e[ar])[mt]\d0|x9007|a101op)\b/i], [MODEL, [VENDOR, 'OPPO'], [TYPE, MOBILE]], [ // Vivo /vivo (\w+)(?: bui|\))/i, /\b(v[12]\d{3}\w?[at])(?: bui|;)/i], [MODEL, [VENDOR, 'Vivo'], [TYPE, MOBILE]], [ // Realme /\b(rmx[12]\d{3})(?: bui|;|\))/i], [MODEL, [VENDOR, 'Realme'], [TYPE, MOBILE]], [ // Motorola /\b(milestone|droid(?:[2-4x]| (?:bionic|x2|pro|razr))?:?( 4g)?)\b[\w ]+build\//i, /\bmot(?:orola)?[- ](\w*)/i, /((?:moto[\w\(\) ]+|xt\d{3,4}|nexus 6)(?= bui|\)))/i], [MODEL, [VENDOR, MOTOROLA], [TYPE, MOBILE]], [/\b(mz60\d|xoom[2 ]{0,2}) build\//i], [MODEL, [VENDOR, MOTOROLA], [TYPE, TABLET]], [ // LG /((?=lg)?[vl]k\-?\d{3}) bui| 3\.[-\w; ]{10}lg?-([06cv9]{3,4})/i], [MODEL, [VENDOR, LG], [TYPE, TABLET]], [/(lm(?:-?f100[nv]?|-[\w\.]+)(?= bui|\))|nexus [45])/i, /\blg[-e;\/ ]+((?!browser|netcast|android tv)\w+)/i, /\blg-?([\d\w]+) bui/i], [MODEL, [VENDOR, LG], [TYPE, MOBILE]], [ // Lenovo /(ideatab[-\w ]+)/i, /lenovo ?(s[56]000[-\w]+|tab(?:[\w ]+)|yt[-\d\w]{6}|tb[-\d\w]{6})/i], [MODEL, [VENDOR, 'Lenovo'], [TYPE, TABLET]], [ // Nokia /(?:maemo|nokia).*(n900|lumia \d+)/i, /nokia[-_ ]?([-\w\.]*)/i], [[MODEL, /_/g, ' '], [VENDOR, 'Nokia'], [TYPE, MOBILE]], [ // Google /(pixel c)\b/i // Google Pixel C ], [MODEL, [VENDOR, GOOGLE], [TYPE, TABLET]], [/droid.+; (pixel[\daxl ]{0,6})(?: bui|\))/i // Google Pixel ], [MODEL, [VENDOR, GOOGLE], [TYPE, MOBILE]], [ // Sony /droid.+ (a?\d[0-2]{2}so|[c-g]\d{4}|so[-gl]\w+|xq-a\w[4-7][12])(?= bui|\).+chrome\/(?![1-6]{0,1}\d\.))/i], [MODEL, [VENDOR, SONY], [TYPE, MOBILE]], [/sony tablet [ps]/i, /\b(?:sony)?sgp\w+(?: bui|\))/i], [[MODEL, 'Xperia Tablet'], [VENDOR, SONY], [TYPE, TABLET]], [ // OnePlus / (kb2005|in20[12]5|be20[12][59])\b/i, /(?:one)?(?:plus)? (a\d0\d\d)(?: b|\))/i], [MODEL, [VENDOR, 'OnePlus'], [TYPE, MOBILE]], [ // Amazon /(alexa)webm/i, /(kf[a-z]{2}wi)( bui|\))/i, // Kindle Fire without Silk /(kf[a-z]+)( bui|\)).+silk\//i // Kindle Fire HD ], [MODEL, [VENDOR, AMAZON], [TYPE, TABLET]], [/((?:sd|kf)[0349hijorstuw]+)( bui|\)).+silk\//i // Fire Phone ], [[MODEL, /(.+)/g, 'Fire Phone $1'], [VENDOR, AMAZON], [TYPE, MOBILE]], [ // BlackBerry /(playbook);[-\w\),; ]+(rim)/i // BlackBerry PlayBook ], [MODEL, VENDOR, [TYPE, TABLET]], [/\b((?:bb[a-f]|st[hv])100-\d)/i, /\(bb10; (\w+)/i // BlackBerry 10 ], [MODEL, [VENDOR, BLACKBERRY], [TYPE, MOBILE]], [ // Asus /(?:\b|asus_)(transfo[prime ]{4,10} \w+|eeepc|slider \w+|nexus 7|padfone|p00[cj])/i], [MODEL, [VENDOR, ASUS], [TYPE, TABLET]], [/ (z[bes]6[027][012][km][ls]|zenfone \d\w?)\b/i], [MODEL, [VENDOR, ASUS], [TYPE, MOBILE]], [ // HTC /(nexus 9)/i // HTC Nexus 9 ], [MODEL, [VENDOR, 'HTC'], [TYPE, TABLET]], [/(htc)[-;_ ]{1,2}([\w ]+(?=\)| bui)|\w+)/i, // HTC // ZTE /(zte)[- ]([\w ]+?)(?: bui|\/|\))/i, /(alcatel|geeksphone|nexian|panasonic|sony(?!-bra))[-_ ]?([-\w]*)/i // Alcatel/GeeksPhone/Nexian/Panasonic/Sony ], [VENDOR, [MODEL, /_/g, ' '], [TYPE, MOBILE]], [ // Acer /droid.+; ([ab][1-7]-?[0178a]\d\d?)/i], [MODEL, [VENDOR, 'Acer'], [TYPE, TABLET]], [ // Meizu /droid.+; (m[1-5] note) bui/i, /\bmz-([-\w]{2,})/i], [MODEL, [VENDOR, 'Meizu'], [TYPE, MOBILE]], [ // Sharp /\b(sh-?[altvz]?\d\d[a-ekm]?)/i], [MODEL, [VENDOR, SHARP], [TYPE, MOBILE]], [ // MIXED /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron)[-_ ]?([-\w]*)/i, // BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron /(hp) ([\w ]+\w)/i, // HP iPAQ /(asus)-?(\w+)/i, // Asus /(microsoft); (lumia[\w ]+)/i, // Microsoft Lumia /(lenovo)[-_ ]?([-\w]+)/i, // Lenovo /(jolla)/i, // Jolla /(oppo) ?([\w ]+) bui/i // OPPO ], [VENDOR, MODEL, [TYPE, MOBILE]], [/(archos) (gamepad2?)/i, // Archos /(hp).+(touchpad(?!.+tablet)|tablet)/i, // HP TouchPad /(kindle)\/([\w\.]+)/i, // Kindle /(nook)[\w ]+build\/(\w+)/i, // Nook /(dell) (strea[kpr\d ]*[\dko])/i, // Dell Streak /(le[- ]+pan)[- ]+(\w{1,9}) bui/i, // Le Pan Tablets /(trinity)[- ]*(t\d{3}) bui/i, // Trinity Tablets /(gigaset)[- ]+(q\w{1,9}) bui/i, // Gigaset Tablets /(vodafone) ([\w ]+)(?:\)| bui)/i // Vodafone ], [VENDOR, MODEL, [TYPE, TABLET]], [/(surface duo)/i // Surface Duo ], [MODEL, [VENDOR, MICROSOFT], [TYPE, TABLET]], [/droid [\d\.]+; (fp\du?)(?: b|\))/i // Fairphone ], [MODEL, [VENDOR, 'Fairphone'], [TYPE, MOBILE]], [/(u304aa)/i // AT&T ], [MODEL, [VENDOR, 'AT&T'], [TYPE, MOBILE]], [/\bsie-(\w*)/i // Siemens ], [MODEL, [VENDOR, 'Siemens'], [TYPE, MOBILE]], [/\b(rct\w+) b/i // RCA Tablets ], [MODEL, [VENDOR, 'RCA'], [TYPE, TABLET]], [/\b(venue[\d ]{2,7}) b/i // Dell Venue Tablets ], [MODEL, [VENDOR, 'Dell'], [TYPE, TABLET]], [/\b(q(?:mv|ta)\w+) b/i // Verizon Tablet ], [MODEL, [VENDOR, 'Verizon'], [TYPE, TABLET]], [/\b(?:barnes[& ]+noble |bn[rt])([\w\+ ]*) b/i // Barnes & Noble Tablet ], [MODEL, [VENDOR, 'Barnes & Noble'], [TYPE, TABLET]], [/\b(tm\d{3}\w+) b/i], [MODEL, [VENDOR, 'NuVision'], [TYPE, TABLET]], [/\b(k88) b/i // ZTE K Series Tablet ], [MODEL, [VENDOR, 'ZTE'], [TYPE, TABLET]], [/\b(nx\d{3}j) b/i // ZTE Nubia ], [MODEL, [VENDOR, 'ZTE'], [TYPE, MOBILE]], [/\b(gen\d{3}) b.+49h/i // Swiss GEN Mobile ], [MODEL, [VENDOR, 'Swiss'], [TYPE, MOBILE]], [/\b(zur\d{3}) b/i // Swiss ZUR Tablet ], [MODEL, [VENDOR, 'Swiss'], [TYPE, TABLET]], [/\b((zeki)?tb.*\b) b/i // Zeki Tablets ], [MODEL, [VENDOR, 'Zeki'], [TYPE, TABLET]], [/\b([yr]\d{2}) b/i, /\b(dragon[- ]+touch |dt)(\w{5}) b/i // Dragon Touch Tablet ], [[VENDOR, 'Dragon Touch'], MODEL, [TYPE, TABLET]], [/\b(ns-?\w{0,9}) b/i // Insignia Tablets ], [MODEL, [VENDOR, 'Insignia'], [TYPE, TABLET]], [/\b((nxa|next)-?\w{0,9}) b/i // NextBook Tablets ], [MODEL, [VENDOR, 'NextBook'], [TYPE, TABLET]], [/\b(xtreme\_)?(v(1[045]|2[015]|[3469]0|7[05])) b/i // Voice Xtreme Phones ], [[VENDOR, 'Voice'], MODEL, [TYPE, MOBILE]], [/\b(lvtel\-)?(v1[12]) b/i // LvTel Phones ], [[VENDOR, 'LvTel'], MODEL, [TYPE, MOBILE]], [/\b(ph-1) /i // Essential PH-1 ], [MODEL, [VENDOR, 'Essential'], [TYPE, MOBILE]], [/\b(v(100md|700na|7011|917g).*\b) b/i // Envizen Tablets ], [MODEL, [VENDOR, 'Envizen'], [TYPE, TABLET]], [/\b(trio[-\w\. ]+) b/i // MachSpeed Tablets ], [MODEL, [VENDOR, 'MachSpeed'], [TYPE, TABLET]], [/\btu_(1491) b/i // Rotor Tablets ], [MODEL, [VENDOR, 'Rotor'], [TYPE, TABLET]], [/(shield[\w ]+) b/i // Nvidia Shield Tablets ], [MODEL, [VENDOR, 'Nvidia'], [TYPE, TABLET]], [/(sprint) (\w+)/i // Sprint Phones ], [VENDOR, MODEL, [TYPE, MOBILE]], [/(kin\.[onetw]{3})/i // Microsoft Kin ], [[MODEL, /\./g, ' '], [VENDOR, MICROSOFT], [TYPE, MOBILE]], [/droid.+; (cc6666?|et5[16]|mc[239][23]x?|vc8[03]x?)\)/i // Zebra ], [MODEL, [VENDOR, ZEBRA], [TYPE, TABLET]], [/droid.+; (ec30|ps20|tc[2-8]\d[kx])\)/i], [MODEL, [VENDOR, ZEBRA], [TYPE, MOBILE]], [ /////////////////// // CONSOLES /////////////////// /(ouya)/i, // Ouya /(nintendo) ([wids3utch]+)/i // Nintendo ], [VENDOR, MODEL, [TYPE, CONSOLE]], [/droid.+; (shield) bui/i // Nvidia ], [MODEL, [VENDOR, 'Nvidia'], [TYPE, CONSOLE]], [/(playstation [345portablevi]+)/i // Playstation ], [MODEL, [VENDOR, SONY], [TYPE, CONSOLE]], [/\b(xbox(?: one)?(?!; xbox))[\); ]/i // Microsoft Xbox ], [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], [ /////////////////// // SMARTTVS /////////////////// /smart-tv.+(samsung)/i // Samsung ], [VENDOR, [TYPE, SMARTTV]], [/hbbtv.+maple;(\d+)/i], [[MODEL, /^/, 'SmartTV'], [VENDOR, SAMSUNG], [TYPE, SMARTTV]], [/(nux; netcast.+smarttv|lg (netcast\.tv-201\d|android tv))/i // LG SmartTV ], [[VENDOR, LG], [TYPE, SMARTTV]], [/(apple) ?tv/i // Apple TV ], [VENDOR, [MODEL, APPLE + ' TV'], [TYPE, SMARTTV]], [/crkey/i // Google Chromecast ], [[MODEL, CHROME + 'cast'], [VENDOR, GOOGLE], [TYPE, SMARTTV]], [/droid.+aft(\w)( bui|\))/i // Fire TV ], [MODEL, [VENDOR, AMAZON], [TYPE, SMARTTV]], [/\(dtv[\);].+(aquos)/i, /(aquos-tv[\w ]+)\)/i // Sharp ], [MODEL, [VENDOR, SHARP], [TYPE, SMARTTV]], [/(bravia[\w ]+)( bui|\))/i // Sony ], [MODEL, [VENDOR, SONY], [TYPE, SMARTTV]], [/(mitv-\w{5}) bui/i // Xiaomi ], [MODEL, [VENDOR, XIAOMI], [TYPE, SMARTTV]], [/\b(roku)[\dx]*[\)\/]((?:dvp-)?[\d\.]*)/i, // Roku /hbbtv\/\d+\.\d+\.\d+ +\([\w ]*; *(\w[^;]*);([^;]*)/i // HbbTV devices ], [[VENDOR, trim], [MODEL, trim], [TYPE, SMARTTV]], [/\b(android tv|smart[- ]?tv|opera tv|tv; rv:)\b/i // SmartTV from Unidentified Vendors ], [[TYPE, SMARTTV]], [ /////////////////// // WEARABLES /////////////////// /((pebble))app/i // Pebble ], [VENDOR, MODEL, [TYPE, WEARABLE]], [/droid.+; (glass) \d/i // Google Glass ], [MODEL, [VENDOR, GOOGLE], [TYPE, WEARABLE]], [/droid.+; (wt63?0{2,3})\)/i], [MODEL, [VENDOR, ZEBRA], [TYPE, WEARABLE]], [/(quest( 2)?)/i // Oculus Quest ], [MODEL, [VENDOR, FACEBOOK], [TYPE, WEARABLE]], [ /////////////////// // EMBEDDED /////////////////// /(tesla)(?: qtcarbrowser|\/[-\w\.]+)/i // Tesla ], [VENDOR, [TYPE, EMBEDDED]], [ //////////////////// // MIXED (GENERIC) /////////////////// /droid .+?; ([^;]+?)(?: bui|\) applew).+? mobile safari/i // Android Phones from Unidentified Vendors ], [MODEL, [TYPE, MOBILE]], [/droid .+?; ([^;]+?)(?: bui|\) applew).+?(?! mobile) safari/i // Android Tablets from Unidentified Vendors ], [MODEL, [TYPE, TABLET]], [/\b((tablet|tab)[;\/]|focus\/\d(?!.+mobile))/i // Unidentifiable Tablet ], [[TYPE, TABLET]], [/(phone|mobile(?:[;\/]| [ \w\/\.]*safari)|pda(?=.+windows ce))/i // Unidentifiable Mobile ], [[TYPE, MOBILE]], [/(android[-\w\. ]{0,9});.+buil/i // Generic Android Device ], [MODEL, [VENDOR, 'Generic']]], engine: [[/windows.+ edge\/([\w\.]+)/i // EdgeHTML ], [VERSION, [NAME, EDGE + 'HTML']], [/webkit\/537\.36.+chrome\/(?!27)([\w\.]+)/i // Blink ], [VERSION, [NAME, 'Blink']], [/(presto)\/([\w\.]+)/i, // Presto /(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m/Goanna /ekioh(flow)\/([\w\.]+)/i, // Flow /(khtml|tasman|links)[\/ ]\(?([\w\.]+)/i, // KHTML/Tasman/Links /(icab)[\/ ]([23]\.[\d\.]+)/i // iCab ], [NAME, VERSION], [/rv\:([\w\.]{1,9})\b.+(gecko)/i // Gecko ], [VERSION, NAME]], os: [[ // Windows /microsoft (windows) (vista|xp)/i // Windows (iTunes) ], [NAME, VERSION], [/(windows) nt 6\.2; (arm)/i, // Windows RT /(windows (?:phone(?: os)?|mobile))[\/ ]?([\d\.\w ]*)/i, // Windows Phone /(windows)[\/ ]?([ntce\d\. ]+\w)(?!.+xbox)/i], [NAME, [VERSION, strMapper, windowsVersionMap]], [/(win(?=3|9|n)|win 9x )([nt\d\.]+)/i], [[NAME, 'Windows'], [VERSION, strMapper, windowsVersionMap]], [ // iOS/macOS /ip[honead]{2,4}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS /cfnetwork\/.+darwin/i], [[VERSION, /_/g, '.'], [NAME, 'iOS']], [/(mac os x) ?([\w\. ]*)/i, /(macintosh|mac_powerpc\b)(?!.+haiku)/i // Mac OS ], [[NAME, 'Mac OS'], [VERSION, /_/g, '.']], [ // Mobile OSes /droid ([\w\.]+)\b.+(android[- ]x86|harmonyos)/i // Android-x86/HarmonyOS ], [VERSION, NAME], [ // Android/WebOS/QNX/Bada/RIM/Maemo/MeeGo/Sailfish OS /(android|webos|qnx|bada|rim tablet os|maemo|meego|sailfish)[-\/ ]?([\w\.]*)/i, /(blackberry)\w*\/([\w\.]*)/i, // Blackberry /(tizen|kaios)[\/ ]([\w\.]+)/i, // Tizen/KaiOS /\((series40);/i // Series 40 ], [NAME, VERSION], [/\(bb(10);/i // BlackBerry 10 ], [VERSION, [NAME, BLACKBERRY]], [/(?:symbian ?os|symbos|s60(?=;)|series60)[-\/ ]?([\w\.]*)/i // Symbian ], [VERSION, [NAME, 'Symbian']], [/mozilla\/[\d\.]+ \((?:mobile|tablet|tv|mobile; [\w ]+); rv:.+ gecko\/([\w\.]+)/i // Firefox OS ], [VERSION, [NAME, FIREFOX + ' OS']], [/web0s;.+rt(tv)/i, /\b(?:hp)?wos(?:browser)?\/([\w\.]+)/i // WebOS ], [VERSION, [NAME, 'webOS']], [ // Google Chromecast /crkey\/([\d\.]+)/i // Google Chromecast ], [VERSION, [NAME, CHROME + 'cast']], [/(cros) [\w]+ ([\w\.]+\w)/i // Chromium OS ], [[NAME, 'Chromium OS'], VERSION], [ // Console /(nintendo|playstation) ([wids345portablevuch]+)/i, // Nintendo/Playstation /(xbox); +xbox ([^\);]+)/i, // Microsoft Xbox (360, One, X, S, Series X, Series S) // Other /\b(joli|palm)\b ?(?:os)?\/?([\w\.]*)/i, // Joli/Palm /(mint)[\/\(\) ]?(\w*)/i, // Mint /(mageia|vectorlinux)[; ]/i, // Mageia/VectorLinux /([kxln]?ubuntu|debian|suse|opensuse|gentoo|arch(?= linux)|slackware|fedora|mandriva|centos|pclinuxos|red ?hat|zenwalk|linpus|raspbian|plan 9|minix|risc os|contiki|deepin|manjaro|elementary os|sabayon|linspire)(?: gnu\/linux)?(?: enterprise)?(?:[- ]linux)?(?:-gnu)?[-\/ ]?(?!chrom|package)([-\w\.]*)/i, // Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware/Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus/Raspbian/Plan9/Minix/RISCOS/Contiki/Deepin/Manjaro/elementary/Sabayon/Linspire /(hurd|linux) ?([\w\.]*)/i, // Hurd/Linux /(gnu) ?([\w\.]*)/i, // GNU /\b([-frentopcghs]{0,5}bsd|dragonfly)[\/ ]?(?!amd|[ix346]{1,2}86)([\w\.]*)/i, // FreeBSD/NetBSD/OpenBSD/PC-BSD/GhostBSD/DragonFly /(haiku) (\w+)/i // Haiku ], [NAME, VERSION], [/(sunos) ?([\w\.\d]*)/i // Solaris ], [[NAME, 'Solaris'], VERSION], [/((?:open)?solaris)[-\/ ]?([\w\.]*)/i, // Solaris /(aix) ((\d)(?=\.|\)| )[\w\.])*/i, // AIX /\b(beos|os\/2|amigaos|morphos|openvms|fuchsia|hp-ux)/i, // BeOS/OS2/AmigaOS/MorphOS/OpenVMS/Fuchsia/HP-UX /(unix) ?([\w\.]*)/i // UNIX ], [NAME, VERSION]] }; ///////////////// // Constructor //////////////// var UAParser = function (ua, extensions) { if (typeof ua === OBJ_TYPE) { extensions = ua; ua = undefined$1; } if (!(this instanceof UAParser)) { return new UAParser(ua, extensions).getResult(); } var _ua = ua || (typeof window !== UNDEF_TYPE && window.navigator && window.navigator.userAgent ? window.navigator.userAgent : EMPTY); var _rgxmap = extensions ? extend(regexes, extensions) : regexes; this.getBrowser = function () { var _browser = {}; _browser[NAME] = undefined$1; _browser[VERSION] = undefined$1; rgxMapper.call(_browser, _ua, _rgxmap.browser); _browser.major = majorize(_browser.version); return _browser; }; this.getCPU = function () { var _cpu = {}; _cpu[ARCHITECTURE] = undefined$1; rgxMapper.call(_cpu, _ua, _rgxmap.cpu); return _cpu; }; this.getDevice = function () { var _device = {}; _device[VENDOR] = undefined$1; _device[MODEL] = undefined$1; _device[TYPE] = undefined$1; rgxMapper.call(_device, _ua, _rgxmap.device); return _device; }; this.getEngine = function () { var _engine = {}; _engine[NAME] = undefined$1; _engine[VERSION] = undefined$1; rgxMapper.call(_engine, _ua, _rgxmap.engine); return _engine; }; this.getOS = function () { var _os = {}; _os[NAME] = undefined$1; _os[VERSION] = undefined$1; rgxMapper.call(_os, _ua, _rgxmap.os); return _os; }; this.getResult = function () { return { ua: this.getUA(), browser: this.getBrowser(), engine: this.getEngine(), os: this.getOS(), device: this.getDevice(), cpu: this.getCPU() }; }; this.getUA = function () { return _ua; }; this.setUA = function (ua) { _ua = typeof ua === STR_TYPE && ua.length > UA_MAX_LENGTH ? trim(ua, UA_MAX_LENGTH) : ua; return this; }; this.setUA(_ua); return this; }; UAParser.VERSION = LIBVERSION; UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR]); UAParser.CPU = enumerize([ARCHITECTURE]); UAParser.DEVICE = enumerize([MODEL, VENDOR, TYPE, CONSOLE, MOBILE, SMARTTV, TABLET, WEARABLE, EMBEDDED]); UAParser.ENGINE = UAParser.OS = enumerize([NAME, VERSION]); /////////// // Export ////////// // check js environment { // nodejs env if (module.exports) { exports = module.exports = UAParser; } exports.UAParser = UAParser; } // jQuery/Zepto specific (optional) // Note: // In AMD env the global scope should be kept clean, but jQuery is an exception. // jQuery always exports to global scope, unless jQuery.noConflict(true) is used, // and we should catch that. var $ = typeof window !== UNDEF_TYPE && (window.jQuery || window.Zepto); if ($ && !$.ua) { var parser = new UAParser(); $.ua = parser.getResult(); $.ua.get = function () { return parser.getUA(); }; $.ua.set = function (ua) { parser.setUA(ua); var result = parser.getResult(); for (var prop in result) { $.ua[prop] = result[prop]; } }; } })(typeof window === 'object' ? window : commonjsGlobal); })(uaParser, uaParserExports); var UAParser = uaParserExports; var version$1 = "1.7.1"; const version = version$1; const protocolVersion = 9; function mergeDefaultOptions(options, audioDefaults, videoDefaults) { const opts = _objectSpread2({}, options); if (opts.audio === true) opts.audio = {}; if (opts.video === true) opts.video = {}; // use defaults if (opts.audio) { mergeObjectWithoutOverwriting(opts.audio, audioDefaults); } if (opts.video) { mergeObjectWithoutOverwriting(opts.video, videoDefaults); } return opts; } function mergeObjectWithoutOverwriting(mainObject, objectToMerge) { Object.keys(objectToMerge).forEach(key => { if (mainObject[key] === undefined) mainObject[key] = objectToMerge[key]; }); return mainObject; } function constraintsForOptions(options) { const constraints = {}; if (options.video) { // default video options if (typeof options.video === 'object') { const videoOptions = {}; const target = videoOptions; const source = options.video; Object.keys(source).forEach(key => { switch (key) { case 'resolution': // flatten VideoResolution fields mergeObjectWithoutOverwriting(target, source.resolution); break; default: target[key] = source[key]; } }); constraints.video = videoOptions; } else { constraints.video = options.video; } } else { constraints.video = false; } if (options.audio) { if (typeof options.audio === 'object') { constraints.audio = options.audio; } else { constraints.audio = true; } } else { constraints.audio = false; } return constraints; } /** * This function detects silence on a given [[Track]] instance. * Returns true if the track seems to be entirely silent. */ async function detectSilence(track) { let timeOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 200; const ctx = getNewAudioContext(); if (ctx) { const analyser = ctx.createAnalyser(); analyser.fftSize = 2048; const bufferLength = analyser.frequencyBinCount; const dataArray = new Uint8Array(bufferLength); const source = ctx.createMediaStreamSource(new MediaStream([track.mediaStreamTrack])); source.connect(analyser); await sleep(timeOffset); analyser.getByteTimeDomainData(dataArray); const someNoise = dataArray.some(sample => sample !== 128 && sample !== 0); ctx.close(); return !someNoise; } return false; } /** * @internal */ function getNewAudioContext() { const AudioContext = // @ts-ignore typeof window !== 'undefined' && (window.AudioContext || window.webkitAudioContext); if (AudioContext) { return new AudioContext({ latencyHint: 'interactive' }); } } const separator = '|'; function unpackStreamId(packed) { const parts = packed.split(separator); if (parts.length > 1) { return [parts[0], packed.substr(parts[0].length + 1)]; } return [packed, '']; } async function sleep(duration) { return new Promise(resolve => setTimeout(resolve, duration)); } /** @internal */ function supportsTransceiver() { return 'addTransceiver' in RTCPeerConnection.prototype; } /** @internal */ function supportsAddTrack() { return 'addTrack' in RTCPeerConnection.prototype; } function supportsAdaptiveStream() { return typeof ResizeObserver !== undefined && typeof IntersectionObserver !== undefined; } function supportsDynacast() { return supportsTransceiver(); } function supportsAV1() { const capabilities = RTCRtpReceiver.getCapabilities('video'); let hasAV1 = false; let hasDDExt = false; if (capabilities) { for (const codec of capabilities.codecs) { if (codec.mimeType === 'video/AV1') { hasAV1 = true; break; } } for (const ext of capabilities.headerExtensions) { if (ext.uri === 'https://aomediacodec.github.io/av1-rtp-spec/#dependency-descriptor-rtp-header-extension') { hasDDExt = true; break; } } } return hasAV1 && hasDDExt; } function supportsSetSinkId(elm) { if (!document) { return false; } if (!elm) { elm = document.createElement('audio'); } return 'setSinkId' in elm; } const setCodecPreferencesVersions = { Chrome: '100', Chromium: '100', Safari: '15', Firefox: '100', Edge: '100', Brave: '1.40' }; function supportsSetCodecPreferences(transceiver) { if (!isWeb()) { return false; } if (!('setCodecPreferences' in transceiver)) { return false; } const uap = UAParser(); if (!uap.browser.name || !uap.browser.version) { // version is required return false; } const v = setCodecPreferencesVersions[uap.browser.name]; if (v) { return compareVersions(uap.browser.version, v) >= 0; } return false; } function isBrowserSupported() { return supportsTransceiver() || supportsAddTrack(); } function isFireFox() { if (!isWeb()) return false; return navigator.userAgent.indexOf('Firefox') !== -1; } function isSafari() { if (!isWeb()) return false; return /^((?!chrome|android).)*safari/i.test(navigator.userAgent); } function isMobile() { if (!isWeb()) return false; return /Tablet|iPad|Mobile|Android|BlackBerry/.test(navigator.userAgent); } function isWeb() { return typeof document !== 'undefined'; } function isReactNative() { // navigator.product is deprecated on browsers, but will be set appropriately for react-native. return navigator.product == 'ReactNative'; } function getReactNativeOs() { if (!isReactNative()) { return undefined; } // global defined only for ReactNative. // @ts-ignore if (global && global.LiveKitReactNativeGlobal) { // @ts-ignore return global.LiveKitReactNativeGlobal.platform; } return undefined; } function compareVersions(v1, v2) { const parts1 = v1.split('.'); const parts2 = v2.split('.'); const k = Math.min(v1.length, v2.length); for (let i = 0; i < k; ++i) { const p1 = parseInt(parts1[i], 10); const p2 = parseInt(parts2[i], 10); if (p1 > p2) return 1; if (p1 < p2) return -1; } return parts1.length == parts2.length ? 0 : parts1.length < parts2.length ? -1 : 1; } function roDispatchCallback(entries) { for (const entry of entries) { entry.target.handleResize(entry); } } function ioDispatchCallback(entries) { for (const entry of entries) { entry.target.handleVisibilityChanged(entry); } } let resizeObserver = null; const getResizeObserver = () => { if (!resizeObserver) resizeObserver = new ResizeObserver(roDispatchCallback); return resizeObserver; }; let intersectionObserver = null; const getIntersectionObserver = () => { if (!intersectionObserver) intersectionObserver = new IntersectionObserver(ioDispatchCallback, { root: document, rootMargin: '0px' }); return intersectionObserver; }; function getClientInfo() { var _a; const info = ClientInfo.fromPartial({ sdk: ClientInfo_SDK.JS, protocol: protocolVersion, version }); if (isReactNative()) { info.os = (_a = getReactNativeOs()) !== null && _a !== void 0 ? _a : ''; } return info; } let emptyVideoStreamTrack; function getEmptyVideoStreamTrack() { if (!emptyVideoStreamTrack) { emptyVideoStreamTrack = createDummyVideoStreamTrack(); } return emptyVideoStreamTrack; } function createDummyVideoStreamTrack() { let width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 16; let height = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 16; let enabled = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; let paintContent = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; const canvas = document.createElement('canvas'); // the canvas size is set to 16 by default, because electron apps seem to fail with smaller values canvas.width = width; canvas.height = height; const ctx = canvas.getContext('2d'); ctx === null || ctx === void 0 ? void 0 : ctx.fillRect(0, 0, canvas.width, canvas.height); if (paintContent && ctx) { ctx.beginPath(); ctx.arc(width / 2, height / 2, 50, 0, Math.PI * 2, true); ctx.closePath(); ctx.fillStyle = 'grey'; ctx.fill(); } // @ts-ignore const dummyStream = canvas.captureStream(); const [dummyTrack] = dummyStream.getTracks(); if (!dummyTrack) { throw Error('Could not get empty media stream video track'); } dummyTrack.enabled = enabled; return dummyTrack; } let emptyAudioStreamTrack; function getEmptyAudioStreamTrack() { if (!emptyAudioStreamTrack) { // implementation adapted from https://blog.mozilla.org/webrtc/warm-up-with-replacetrack/ const ctx = new AudioContext(); const oscillator = ctx.createOscillator(); const dst = ctx.createMediaStreamDestination(); oscillator.connect(dst); oscillator.start(); [emptyAudioStreamTrack] = dst.stream.getAudioTracks(); if (!emptyAudioStreamTrack) { throw Error('Could not get empty media stream audio track'); } emptyAudioStreamTrack.enabled = false; } return emptyAudioStreamTrack; } class Future { constructor(futureBase, onFinally) { this.onFinally = onFinally; this.promise = new Promise(async (resolve, reject) => { this.resolve = resolve; this.reject = reject; if (futureBase) { await futureBase(resolve, reject); } }).finally(() => { var _a; return (_a = this.onFinally) === null || _a === void 0 ? void 0 : _a.call(this); }); } } /** * Creates and returns an analyser web audio node that is attached to the provided track. * Additionally returns a convenience method `calculateVolume` to perform instant volume readings on that track. * Call the returned `cleanup` function to close the audioContext that has been created for the instance of this helper */ function createAudioAnalyser(track, options) { const opts = _objectSpread2({ cloneTrack: false, fftSize: 2048, smoothingTimeConstant: 0.8, minDecibels: -100, maxDecibels: -80 }, options); const audioContext = getNewAudioContext(); if (!audioContext) { throw new Error('Audio Context not supported on this browser'); } const streamTrack = opts.cloneTrack ? track.mediaStreamTrack.clone() : track.mediaStreamTrack; const mediaStreamSource = audioContext.createMediaStreamSource(new MediaStream([streamTrack])); const analyser = audioContext.createAnalyser(); analyser.minDecibels = opts.minDecibels; analyser.maxDecibels = opts.maxDecibels; analyser.fftSize = opts.fftSize; analyser.smoothingTimeConstant = opts.smoothingTimeConstant; mediaStreamSource.connect(analyser); const dataArray = new Uint8Array(analyser.frequencyBinCount); /** * Calculates the current volume of the track in the range from 0 to 1 */ const calculateVolume = () => { analyser.getByteFrequencyData(dataArray); let sum = 0; for (const amplitude of dataArray) { sum += Math.pow(amplitude / 255, 2); } const volume = Math.sqrt(sum / dataArray.length); return volume; }; const cleanup = () => { audioContext.close(); if (opts.cloneTrack) { streamTrack.stop(); } }; return { calculateVolume, analyser, cleanup }; } class Mutex { constructor() { this._locking = Promise.resolve(); this._locks = 0; } isLocked() { return this._locks > 0; } lock() { this._locks += 1; let unlockNext; const willLock = new Promise(resolve => unlockNext = () => { this._locks -= 1; resolve(); }); const willUnlock = this._locking.then(() => unlockNext); this._locking = this._locking.then(() => willLock); return willUnlock; } } class Queue { /** * @class Queue * * Priority queue with rate limiting
* See the medium article:
* https://mmomtchev.medium.com/parallelizing-download-loops-in-js-with-async-await-queue-670420880cd6 * * @param {number} [_maxConcurrent=1] Number of tasks allowed to run simultaneously * @param {number} [_minCycle=0] Minimum number of milliseconds between two consecutive tasks */ constructor(_maxConcurrent, _minCycle) { this.maxConcurrent = _maxConcurrent || 1; this.minCycle = _minCycle || 0; this.queueRunning = []; this.queueWaiting = {}; this.lastRun = 0; } /** @private */ dequeue(hash) { const q = this.queueRunning; const idx = q.findIndex(x => x.hash === hash); if (idx == -1) throw 'queue desync'; const o = q[idx]; q.splice(idx, 1); return o; } /** @private */ getFirstWaiting() { for (let p of Object.keys(this.queueWaiting).sort((a, b) => a - b)) if (this.queueWaiting[p] !== undefined && this.queueWaiting[p].length > 0) return this.queueWaiting[p]; return undefined; } /** * Signal that the task `hash` has finished.
* Frees its slot in the queue * * @method end * @param {any} hash Unique hash identifying the task, Symbol() works very well */ end(hash) { const me = this.dequeue(hash); me.resolve(); /* Choose the next task to run and unblock its promise */ const q = this.getFirstWaiting(); if (q !== undefined) { const next = q.shift(); next.resolve(); } } /** * Wait for a slot in the queue * * @method wait * @param {any} hash Unique hash identifying the task * @param {number} [priority=0] Optional priority, -1 is higher priority than 1 * @return {Promise} Resolved when the task is ready to run */ async wait(hash, _priority) { const priority = _priority === undefined ? 0 : _priority; /* Us on the queue */ let me = { hash, priority }; /* Create priorities on the fly */ if (this.queueWaiting[priority] == undefined) this.queueWaiting[priority] = []; /* Are we allowed to run? */ if (this.queueRunning.length >= this.maxConcurrent) { /* This promise will be unlocked from the outside */ /* and it cannot reject */ me.promise = new Promise(resolve => { me.resolve = resolve; }); /* Get in the line */ this.queueWaiting[priority].push(me); await me.promise; } this.queueRunning.push(me); me.promise = new Promise(resolve => { me.resolve = resolve; }); /* Wait if it is too soon */ while (Date.now() - this.lastRun < this.minCycle) { await new Promise(resolve => setTimeout(resolve, this.minCycle - Date.now() + this.lastRun)); } this.lastRun = Date.now(); } /** * Run a job (equivalent to calling Queue.wait(), fn() and then Queue.end())
* fn can be both synchronous or asynchronous function * * @method run * @param {Function} fn The job * @param {number} [priority=0] Optional priority, -1 is higher priority than 1 * @return {Promise} Resolved when the task has finished with the return value of fn */ run(job, _priority) { const priority = _priority === undefined ? 0 : _priority; const id = Symbol(); return this.wait(id, priority).then(() => job()).finally(() => { this.end(id); }); } /** * @interface QueueStats {running: number, waiting: number, last: number} */ /** * Return the number of running and waiting jobs * * @method stat * @return {QueueStats} running, waiting, last */ stat() { return { running: this.queueRunning.length, waiting: Object.keys(this.queueWaiting).reduce((t, x) => t += this.queueWaiting[x].length, 0), last: this.lastRun }; } /** * Returns a promise that resolves when the queue is empty * * @method flush * @return {Promise} */ async flush() { /* Aways wait on the lowest priority in the queue */ while (this.stat().waiting > 0) { for (let p of Object.keys(this.queueWaiting).sort((a, b) => b - a)) { const qp = this.queueWaiting[p]; if (qp !== undefined && qp.length > 0) { await qp[qp.length - 1].promise; } } } /* And then finish on the running queue */ while (this.queueRunning.length > 0) { await Promise.allSettled(this.queueRunning.map(x => x.promise)); } } } const defaultId = 'default'; class DeviceManager { static getInstance() { if (this.instance === undefined) { this.instance = new DeviceManager(); } return this.instance; } async getDevices(kind) { let requestPermissions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; var _a; if (((_a = DeviceManager.userMediaPromiseMap) === null || _a === void 0 ? void 0 : _a.size) > 0) { livekitLogger.debug('awaiting getUserMedia promise'); try { if (kind) { await DeviceManager.userMediaPromiseMap.get(kind); } else { await Promise.all(DeviceManager.userMediaPromiseMap.values()); } } catch (e) { livekitLogger.warn('error waiting for media permissons'); } } let devices = await navigator.mediaDevices.enumerateDevices(); if (requestPermissions && kind && ( // for safari we need to skip this check, as otherwise it will re-acquire user media and fail on iOS https://bugs.webkit.org/show_bug.cgi?id=179363 !DeviceManager.userMediaPromiseMap.get(kind) || !isSafari())) { const isDummyDeviceOrEmpty = devices.length === 0 || devices.some(device => { const noLabel = device.label === ''; const isRelevant = kind ? device.kind === kind : true; return noLabel && isRelevant; }); if (isDummyDeviceOrEmpty) { const permissionsToAcquire = { video: kind !== 'audioinput' && kind !== 'audiooutput', audio: kind !== 'videoinput' }; const stream = await navigator.mediaDevices.getUserMedia(permissionsToAcquire); devices = await navigator.mediaDevices.enumerateDevices(); stream.getTracks().forEach(track => { track.stop(); }); } } if (kind) { devices = devices.filter(device => device.kind === kind); } return devices; } async normalizeDeviceId(kind, deviceId, groupId) { if (deviceId !== defaultId) { return deviceId; } // resolve actual device id if it's 'default': Chrome returns it when no // device has been chosen const devices = await this.getDevices(kind); const device = devices.find(d => d.groupId === groupId && d.deviceId !== defaultId); return device === null || device === void 0 ? void 0 : device.deviceId; } } DeviceManager.mediaDeviceKinds = ['audioinput', 'audiooutput', 'videoinput']; DeviceManager.userMediaPromiseMap = new Map(); var eventsExports = {}; var events = { get exports(){ return eventsExports; }, set exports(v){ eventsExports = v; }, }; var R = typeof Reflect === 'object' ? Reflect : null; var ReflectApply = R && typeof R.apply === 'function' ? R.apply : function ReflectApply(target, receiver, args) { return Function.prototype.apply.call(target, receiver, args); }; var ReflectOwnKeys; if (R && typeof R.ownKeys === 'function') { ReflectOwnKeys = R.ownKeys; } else if (Object.getOwnPropertySymbols) { ReflectOwnKeys = function ReflectOwnKeys(target) { return Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target)); }; } else { ReflectOwnKeys = function ReflectOwnKeys(target) { return Object.getOwnPropertyNames(target); }; } function ProcessEmitWarning(warning) { if (console && console.warn) console.warn(warning); } var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) { return value !== value; }; function EventEmitter() { EventEmitter.init.call(this); } events.exports = EventEmitter; eventsExports.once = once; // Backwards-compat with node 0.10.x EventEmitter.EventEmitter = EventEmitter; EventEmitter.prototype._events = undefined; EventEmitter.prototype._eventsCount = 0; EventEmitter.prototype._maxListeners = undefined; // By default EventEmitters will print a warning if more than 10 listeners are // added to it. This is a useful default which helps finding memory leaks. var defaultMaxListeners = 10; function checkListener(listener) { if (typeof listener !== 'function') { throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener); } } Object.defineProperty(EventEmitter, 'defaultMaxListeners', { enumerable: true, get: function () { return defaultMaxListeners; }, set: function (arg) { if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) { throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.'); } defaultMaxListeners = arg; } }); EventEmitter.init = function () { if (this._events === undefined || this._events === Object.getPrototypeOf(this)._events) { this._events = Object.create(null); this._eventsCount = 0; } this._maxListeners = this._maxListeners || undefined; }; // Obviously not all Emitters should be limited to 10. This function allows // that to be increased. Set to zero for unlimited. EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) { throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.'); } this._maxListeners = n; return this; }; function _getMaxListeners(that) { if (that._maxListeners === undefined) return EventEmitter.defaultMaxListeners; return that._maxListeners; } EventEmitter.prototype.getMaxListeners = function getMaxListeners() { return _getMaxListeners(this); }; EventEmitter.prototype.emit = function emit(type) { var args = []; for (var i = 1; i < arguments.length; i++) args.push(arguments[i]); var doError = type === 'error'; var events = this._events; if (events !== undefined) doError = doError && events.error === undefined;else if (!doError) return false; // If there is no 'error' event listener then throw. if (doError) { var er; if (args.length > 0) er = args[0]; if (er instanceof Error) { // Note: The comments on the `throw` lines are intentional, they show // up in Node's output if this results in an unhandled exception. throw er; // Unhandled 'error' event } // At least give some kind of context to the user var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : '')); err.context = er; throw err; // Unhandled 'error' event } var handler = events[type]; if (handler === undefined) return false; if (typeof handler === 'function') { ReflectApply(handler, this, args); } else { var len = handler.length; var listeners = arrayClone(handler, len); for (var i = 0; i < len; ++i) ReflectApply(listeners[i], this, args); } return true; }; function _addListener(target, type, listener, prepend) { var m; var events; var existing; checkListener(listener); events = target._events; if (events === undefined) { events = target._events = Object.create(null); target._eventsCount = 0; } else { // To avoid recursion in the case that type === "newListener"! Before // adding it to the listeners, first emit "newListener". if (events.newListener !== undefined) { target.emit('newListener', type, listener.listener ? listener.listener : listener); // Re-assign `events` because a newListener handler could have caused the // this._events to be assigned to a new object events = target._events; } existing = events[type]; } if (existing === undefined) { // Optimize the case of one listener. Don't need the extra array object. existing = events[type] = listener; ++target._eventsCount; } else { if (typeof existing === 'function') { // Adding the second element, need to change to array. existing = events[type] = prepend ? [listener, existing] : [existing, listener]; // If we've already got an array, just append. } else if (prepend) { existing.unshift(listener); } else { existing.push(listener); } // Check for listener leak m = _getMaxListeners(target); if (m > 0 && existing.length > m && !existing.warned) { existing.warned = true; // No error code for this since it is a Warning // eslint-disable-next-line no-restricted-syntax var w = new Error('Possible EventEmitter memory leak detected. ' + existing.length + ' ' + String(type) + ' listeners ' + 'added. Use emitter.setMaxListeners() to ' + 'increase limit'); w.name = 'MaxListenersExceededWarning'; w.emitter = target; w.type = type; w.count = existing.length; ProcessEmitWarning(w); } } return target; } EventEmitter.prototype.addListener = function addListener(type, listener) { return _addListener(this, type, listener, false); }; EventEmitter.prototype.on = EventEmitter.prototype.addListener; EventEmitter.prototype.prependListener = function prependListener(type, listener) { return _addListener(this, type, listener, true); }; function onceWrapper() { if (!this.fired) { this.target.removeListener(this.type, this.wrapFn); this.fired = true; if (arguments.length === 0) return this.listener.call(this.target); return this.listener.apply(this.target, arguments); } } function _onceWrap(target, type, listener) { var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener }; var wrapped = onceWrapper.bind(state); wrapped.listener = listener; state.wrapFn = wrapped; return wrapped; } EventEmitter.prototype.once = function once(type, listener) { checkListener(listener); this.on(type, _onceWrap(this, type, listener)); return this; }; EventEmitter.prototype.prependOnceListener = function prependOnceListener(type, listener) { checkListener(listener); this.prependListener(type, _onceWrap(this, type, listener)); return this; }; // Emits a 'removeListener' event if and only if the listener was removed. EventEmitter.prototype.removeListener = function removeListener(type, listener) { var list, events, position, i, originalListener; checkListener(listener); events = this._events; if (events === undefined) return this; list = events[type]; if (list === undefined) return this; if (list === listener || list.listener === listener) { if (--this._eventsCount === 0) this._events = Object.create(null);else { delete events[type]; if (events.removeListener) this.emit('removeListener', type, list.listener || listener); } } else if (typeof list !== 'function') { position = -1; for (i = list.length - 1; i >= 0; i--) { if (list[i] === listener || list[i].listener === listener) { originalListener = list[i].listener; position = i; break; } } if (position < 0) return this; if (position === 0) list.shift();else { spliceOne(list, position); } if (list.length === 1) events[type] = list[0]; if (events.removeListener !== undefined) this.emit('removeListener', type, originalListener || listener); } return this; }; EventEmitter.prototype.off = EventEmitter.prototype.removeListener; EventEmitter.prototype.removeAllListeners = function removeAllListeners(type) { var listeners, events, i; events = this._events; if (events === undefined) return this; // not listening for removeListener, no need to emit if (events.removeListener === undefined) { if (arguments.length === 0) { this._events = Object.create(null); this._eventsCount = 0; } else if (events[type] !== undefined) { if (--this._eventsCount === 0) this._events = Object.create(null);else delete events[type]; } return this; } // emit removeListener for all listeners on all events if (arguments.length === 0) { var keys = Object.keys(events); var key; for (i = 0; i < keys.length; ++i) { key = keys[i]; if (key === 'removeListener') continue; this.removeAllListeners(key); } this.removeAllListeners('removeListener'); this._events = Object.create(null); this._eventsCount = 0; return this; } listeners = events[type]; if (typeof listeners === 'function') { this.removeListener(type, listeners); } else if (listeners !== undefined) { // LIFO order for (i = listeners.length - 1; i >= 0; i--) { this.removeListener(type, listeners[i]); } } return this; }; function _listeners(target, type, unwrap) { var events = target._events; if (events === undefined) return []; var evlistener = events[type]; if (evlistener === undefined) return []; if (typeof evlistener === 'function') return unwrap ? [evlistener.listener || evlistener] : [evlistener]; return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); } EventEmitter.prototype.listeners = function listeners(type) { return _listeners(this, type, true); }; EventEmitter.prototype.rawListeners = function rawListeners(type) { return _listeners(this, type, false); }; EventEmitter.listenerCount = function (emitter, type) { if (typeof emitter.listenerCount === 'function') { return emitter.listenerCount(type); } else { return listenerCount.call(emitter, type); } }; EventEmitter.prototype.listenerCount = listenerCount; function listenerCount(type) { var events = this._events; if (events !== undefined) { var evlistener = events[type]; if (typeof evlistener === 'function') { return 1; } else if (evlistener !== undefined) { return evlistener.length; } } return 0; } EventEmitter.prototype.eventNames = function eventNames() { return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : []; }; function arrayClone(arr, n) { var copy = new Array(n); for (var i = 0; i < n; ++i) copy[i] = arr[i]; return copy; } function spliceOne(list, index) { for (; index + 1 < list.length; index++) list[index] = list[index + 1]; list.pop(); } function unwrapListeners(arr) { var ret = new Array(arr.length); for (var i = 0; i < ret.length; ++i) { ret[i] = arr[i].listener || arr[i]; } return ret; } function once(emitter, name) { return new Promise(function (resolve, reject) { function errorListener(err) { emitter.removeListener(name, resolver); reject(err); } function resolver() { if (typeof emitter.removeListener === 'function') { emitter.removeListener('error', errorListener); } resolve([].slice.call(arguments)); } eventTargetAgnosticAddListener(emitter, name, resolver, { once: true }); if (name !== 'error') { addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true }); } }); } function addErrorHandlerIfEventEmitter(emitter, handler, flags) { if (typeof emitter.on === 'function') { eventTargetAgnosticAddListener(emitter, 'error', handler, flags); } } function eventTargetAgnosticAddListener(emitter, name, listener, flags) { if (typeof emitter.on === 'function') { if (flags.once) { emitter.once(name, listener); } else { emitter.on(name, listener); } } else if (typeof emitter.addEventListener === 'function') { // EventTarget does not have `error` event semantics like Node // EventEmitters, we do not listen for `error` events here. emitter.addEventListener(name, function wrapListener(arg) { // IE does not have builtin `{ once: true }` support so we // have to do it manually. if (flags.once) { emitter.removeEventListener(name, wrapListener); } listener(arg); }); } else { throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter); } } const BACKGROUND_REACTION_DELAY = 5000; // keep old audio elements when detached, we would re-use them since on iOS // Safari tracks which audio elements have been "blessed" by the user. const recycledElements = []; class Track extends eventsExports.EventEmitter { constructor(mediaTrack, kind) { super(); this.attachedElements = []; this.isMuted = false; /** * indicates current state of stream, it'll indicate `paused` if the track * has been paused by congestion controller */ this.streamState = Track.StreamState.Active; this._currentBitrate = 0; this.appVisibilityChangedListener = () => { if (this.backgroundTimeout) { clearTimeout(this.backgroundTimeout); } // delay app visibility update if it goes to hidden // update immediately if it comes back to focus if (document.visibilityState === 'hidden') { this.backgroundTimeout = setTimeout(() => this.handleAppVisibilityChanged(), BACKGROUND_REACTION_DELAY); } else { this.handleAppVisibilityChanged(); } }; this.setMaxListeners(100); this.kind = kind; this._mediaStreamTrack = mediaTrack; this._mediaStreamID = mediaTrack.id; this.source = Track.Source.Unknown; if (isWeb()) { this.isInBackground = document.visibilityState === 'hidden'; document.addEventListener('visibilitychange', this.appVisibilityChangedListener); } else { this.isInBackground = false; } } /** current receive bits per second */ get currentBitrate() { return this._currentBitrate; } get mediaStreamTrack() { return this._mediaStreamTrack; } /** * @internal * used for keep mediaStream's first id, since it's id might change * if we disable/enable a track */ get mediaStreamID() { return this._mediaStreamID; } attach(element) { let elementType = 'audio'; if (this.kind === Track.Kind.Video) { elementType = 'video'; } if (!element) { if (elementType === 'audio') { recycledElements.forEach(e => { if (e.parentElement === null && !element) { element = e; } }); if (element) { // remove it from pool recycledElements.splice(recycledElements.indexOf(element), 1); } } if (!element) { element = document.createElement(elementType); } } if (!this.attachedElements.includes(element)) { this.attachedElements.push(element); } // even if we believe it's already attached to the element, it's possible // the element's srcObject was set to something else out of band. // we'll want to re-attach it in that case attachToElement(this._mediaStreamTrack, element); // handle auto playback failures const allMediaStreamTracks = element.srcObject.getTracks(); if (allMediaStreamTracks.some(tr => tr.kind === 'audio')) { // manually play audio to detect audio playback status element.play().then(() => { this.emit(TrackEvent.AudioPlaybackStarted); }).catch(e => { if (e.name === 'NotAllowedError') { this.emit(TrackEvent.AudioPlaybackFailed, e); } else { livekitLogger.warn('could not playback audio', e); } // If audio playback isn't allowed make sure we still play back the video if (element && allMediaStreamTracks.some(tr => tr.kind === 'video') && e.name === 'NotAllowedError') { element.muted = true; element.play().catch(() => { // catch for Safari, exceeded options at this point to automatically play the media element }); } }); } this.emit(TrackEvent.ElementAttached, element); return element; } detach(element) { // detach from a single element if (element) { detachTrack(this._mediaStreamTrack, element); const idx = this.attachedElements.indexOf(element); if (idx >= 0) { this.attachedElements.splice(idx, 1); this.recycleElement(element); this.emit(TrackEvent.ElementDetached, element); } return element; } const detached = []; this.attachedElements.forEach(elm => { detachTrack(this._mediaStreamTrack, elm); detached.push(elm); this.recycleElement(elm); this.emit(TrackEvent.ElementDetached, elm); }); // remove all tracks this.attachedElements = []; return detached; } stop() { this.stopMonitor(); this._mediaStreamTrack.stop(); if (isWeb()) { document.removeEventListener('visibilitychange', this.appVisibilityChangedListener); } } enable() { this._mediaStreamTrack.enabled = true; } disable() { this._mediaStreamTrack.enabled = false; } /* @internal */ stopMonitor() { if (this.monitorInterval) { clearInterval(this.monitorInterval); } } recycleElement(element) { if (element instanceof HTMLAudioElement) { // we only need to re-use a single element let shouldCache = true; element.pause(); recycledElements.forEach(e => { if (!e.parentElement) { shouldCache = false; } }); if (shouldCache) { recycledElements.push(element); } } } async handleAppVisibilityChanged() { this.isInBackground = document.visibilityState === 'hidden'; } } /** @internal */ function attachToElement(track, element) { let mediaStream; if (element.srcObject instanceof MediaStream) { mediaStream = element.srcObject; } else { mediaStream = new MediaStream(); } // check if track matches existing track let existingTracks; if (track.kind === 'audio') { existingTracks = mediaStream.getAudioTracks(); } else { existingTracks = mediaStream.getVideoTracks(); } if (!existingTracks.includes(track)) { existingTracks.forEach(et => { mediaStream.removeTrack(et); }); mediaStream.addTrack(track); } element.autoplay = true; // In case there are no audio tracks present on the mediastream, we set the element as muted to ensure autoplay works element.muted = mediaStream.getAudioTracks().length === 0; if (element instanceof HTMLVideoElement) { element.playsInline = true; } // avoid flicker if (element.srcObject !== mediaStream) { element.srcObject = mediaStream; if ((isSafari() || isFireFox()) && element instanceof HTMLVideoElement) { // Firefox also has a timing issue where video doesn't actually get attached unless // performed out-of-band // Safari 15 has a bug where in certain layouts, video element renders // black until the page is resized or other changes take place. // Resetting the src triggers it to render. // https://developer.apple.com/forums/thread/690523 setTimeout(() => { element.srcObject = mediaStream; // Safari 15 sometimes fails to start a video // when the window is backgrounded before the first frame is drawn // manually calling play here seems to fix that element.play().catch(() => { /* do nothing */ }); }, 0); } } } /** @internal */ function detachTrack(track, element) { if (element.srcObject instanceof MediaStream) { const mediaStream = element.srcObject; mediaStream.removeTrack(track); if (mediaStream.getTracks().length > 0) { element.srcObject = mediaStream; } else { element.srcObject = null; } } } (function (Track) { let Kind; (function (Kind) { Kind["Audio"] = "audio"; Kind["Video"] = "video"; Kind["Unknown"] = "unknown"; })(Kind = Track.Kind || (Track.Kind = {})); let Source; (function (Source) { Source["Camera"] = "camera"; Source["Microphone"] = "microphone"; Source["ScreenShare"] = "screen_share"; Source["ScreenShareAudio"] = "screen_share_audio"; Source["Unknown"] = "unknown"; })(Source = Track.Source || (Track.Source = {})); let StreamState$1; (function (StreamState) { StreamState["Active"] = "active"; StreamState["Paused"] = "paused"; StreamState["Unknown"] = "unknown"; })(StreamState$1 = Track.StreamState || (Track.StreamState = {})); /** @internal */ function kindToProto(k) { switch (k) { case Kind.Audio: return TrackType.AUDIO; case Kind.Video: return TrackType.VIDEO; default: return TrackType.UNRECOGNIZED; } } Track.kindToProto = kindToProto; /** @internal */ function kindFromProto(t) { switch (t) { case TrackType.AUDIO: return Kind.Audio; case TrackType.VIDEO: return Kind.Video; default: return Kind.Unknown; } } Track.kindFromProto = kindFromProto; /** @internal */ function sourceToProto(s) { switch (s) { case Source.Camera: return TrackSource.CAMERA; case Source.Microphone: return TrackSource.MICROPHONE; case Source.ScreenShare: return TrackSource.SCREEN_SHARE; case Source.ScreenShareAudio: return TrackSource.SCREEN_SHARE_AUDIO; default: return TrackSource.UNRECOGNIZED; } } Track.sourceToProto = sourceToProto; /** @internal */ function sourceFromProto(s) { switch (s) { case TrackSource.CAMERA: return Source.Camera; case TrackSource.MICROPHONE: return Source.Microphone; case TrackSource.SCREEN_SHARE: return Source.ScreenShare; case TrackSource.SCREEN_SHARE_AUDIO: return Source.ScreenShareAudio; default: return Source.Unknown; } } Track.sourceFromProto = sourceFromProto; /** @internal */ function streamStateFromProto(s) { switch (s) { case StreamState.ACTIVE: return StreamState$1.Active; case StreamState.PAUSED: return StreamState$1.Paused; default: return StreamState$1.Unknown; } } Track.streamStateFromProto = streamStateFromProto; })(Track || (Track = {})); const defaultDimensionsTimeout = 2 * 1000; class LocalTrack extends Track { /** * * @param mediaTrack * @param kind * @param constraints MediaTrackConstraints that are being used when restarting or reacquiring tracks * @param userProvidedTrack Signals to the SDK whether or not the mediaTrack should be managed (i.e. released and reacquired) internally by the SDK */ constructor(mediaTrack, kind, constraints) { let userProvidedTrack = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; super(mediaTrack, kind); this._isUpstreamPaused = false; this.handleEnded = () => { if (this.isInBackground) { this.reacquireTrack = true; } this.emit(TrackEvent.Ended, this); }; this._mediaStreamTrack.addEventListener('ended', this.handleEnded); this.constraints = constraints !== null && constraints !== void 0 ? constraints : mediaTrack.getConstraints(); this.reacquireTrack = false; this.providedByUser = userProvidedTrack; this.muteQueue = new Queue(); } get id() { return this._mediaStreamTrack.id; } get dimensions() { if (this.kind !== Track.Kind.Video) { return undefined; } const { width, height } = this._mediaStreamTrack.getSettings(); if (width && height) { return { width, height }; } return undefined; } get isUpstreamPaused() { return this._isUpstreamPaused; } get isUserProvided() { return this.providedByUser; } async waitForDimensions() { let timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultDimensionsTimeout; if (this.kind === Track.Kind.Audio) { throw new Error('cannot get dimensions for audio tracks'); } const started = Date.now(); while (Date.now() - started < timeout) { const dims = this.dimensions; if (dims) { return dims; } await sleep(50); } throw new TrackInvalidError('unable to get track dimensions after timeout'); } /** * @returns DeviceID of the device that is currently being used for this track */ async getDeviceId() { // screen share doesn't have a usable device id if (this.source === Track.Source.ScreenShare) { return; } const { deviceId, groupId } = this._mediaStreamTrack.getSettings(); const kind = this.kind === Track.Kind.Audio ? 'audioinput' : 'videoinput'; return DeviceManager.getInstance().normalizeDeviceId(kind, deviceId, groupId); } async mute() { this.setTrackMuted(true); return this; } async unmute() { this.setTrackMuted(false); return this; } async replaceTrack(track) { let userProvidedTrack = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; if (!this.sender) { throw new TrackInvalidError('unable to replace an unpublished track'); } // detach this.attachedElements.forEach(el => { detachTrack(this._mediaStreamTrack, el); }); this._mediaStreamTrack.removeEventListener('ended', this.handleEnded); // on Safari, the old audio track must be stopped before attempting to acquire // the new track, otherwise the new track will stop with // 'A MediaStreamTrack ended due to a capture failure` if (!this.providedByUser) { this._mediaStreamTrack.stop(); } track.addEventListener('ended', this.handleEnded); livekitLogger.debug('replace MediaStreamTrack'); if (this.sender) { await this.sender.replaceTrack(track); } this._mediaStreamTrack = track; // sync muted state with the enabled state of the newly provided track this._mediaStreamTrack.enabled = !this.isMuted; await this.resumeUpstream(); this.attachedElements.forEach(el => { attachToElement(track, el); }); this.mediaStream = new MediaStream([track]); this.providedByUser = userProvidedTrack; return this; } async restart(constraints) { if (!constraints) { constraints = this.constraints; } livekitLogger.debug('restarting track with constraints', constraints); const streamConstraints = { audio: false, video: false }; if (this.kind === Track.Kind.Video) { streamConstraints.video = constraints; } else { streamConstraints.audio = constraints; } // detach this.attachedElements.forEach(el => { detachTrack(this._mediaStreamTrack, el); }); this._mediaStreamTrack.removeEventListener('ended', this.handleEnded); // on Safari, the old audio track must be stopped before attempting to acquire // the new track, otherwise the new track will stop with // 'A MediaStreamTrack ended due to a capture failure` this._mediaStreamTrack.stop(); // create new track and attach const mediaStream = await navigator.mediaDevices.getUserMedia(streamConstraints); const newTrack = mediaStream.getTracks()[0]; newTrack.addEventListener('ended', this.handleEnded); livekitLogger.debug('re-acquired MediaStreamTrack'); if (this.sender) { // Track can be restarted after it's unpublished await this.sender.replaceTrack(newTrack); } this._mediaStreamTrack = newTrack; await this.resumeUpstream(); this.attachedElements.forEach(el => { attachToElement(newTrack, el); }); this.mediaStream = mediaStream; this.constraints = constraints; this.emit(TrackEvent.Restarted, this); return this; } setTrackMuted(muted) { livekitLogger.debug("setting ".concat(this.kind, " track ").concat(muted ? 'muted' : 'unmuted')); if (this.isMuted === muted && this._mediaStreamTrack.enabled !== muted) { return; } this.isMuted = muted; this._mediaStreamTrack.enabled = !muted; this.emit(muted ? TrackEvent.Muted : TrackEvent.Unmuted, this); } get needsReAcquisition() { return this._mediaStreamTrack.readyState !== 'live' || this._mediaStreamTrack.muted || !this._mediaStreamTrack.enabled || this.reacquireTrack; } async handleAppVisibilityChanged() { await super.handleAppVisibilityChanged(); if (!isMobile()) return; livekitLogger.debug("visibility changed, is in Background: ".concat(this.isInBackground)); if (!this.isInBackground && this.needsReAcquisition && !this.isUserProvided && !this.isMuted) { livekitLogger.debug("track needs to be reaquired, restarting ".concat(this.source)); await this.restart(); this.reacquireTrack = false; } } async pauseUpstream() { this.muteQueue.run(async () => { if (this._isUpstreamPaused === true) { return; } if (!this.sender) { livekitLogger.warn('unable to pause upstream for an unpublished track'); return; } this._isUpstreamPaused = true; this.emit(TrackEvent.UpstreamPaused, this); const emptyTrack = this.kind === Track.Kind.Audio ? getEmptyAudioStreamTrack() : getEmptyVideoStreamTrack(); await this.sender.replaceTrack(emptyTrack); }); } async resumeUpstream() { this.muteQueue.run(async () => { if (this._isUpstreamPaused === false) { return; } if (!this.sender) { livekitLogger.warn('unable to resume upstream for an unpublished track'); return; } this._isUpstreamPaused = false; this.emit(TrackEvent.UpstreamResumed, this); await this.sender.replaceTrack(this._mediaStreamTrack); }); } } class LocalAudioTrack extends LocalTrack { /** * * @param mediaTrack * @param constraints MediaTrackConstraints that are being used when restarting or reacquiring tracks * @param userProvidedTrack Signals to the SDK whether or not the mediaTrack should be managed (i.e. released and reacquired) internally by the SDK */ constructor(mediaTrack, constraints) { let userProvidedTrack = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; super(mediaTrack, Track.Kind.Audio, constraints, userProvidedTrack); /** @internal */ this.stopOnMute = false; this.monitorSender = async () => { if (!this.sender) { this._currentBitrate = 0; return; } let stats; try { stats = await this.getSenderStats(); } catch (e) { livekitLogger.error('could not get audio sender stats', { error: e }); return; } if (stats && this.prevStats) { this._currentBitrate = computeBitrate(stats, this.prevStats); } this.prevStats = stats; }; this.checkForSilence(); } async setDeviceId(deviceId) { if (this.constraints.deviceId === deviceId) { return; } this.constraints.deviceId = deviceId; if (!this.isMuted) { await this.restartTrack(); } } async mute() { await this.muteQueue.run(async () => { // disabled special handling as it will cause BT headsets to switch communication modes if (this.source === Track.Source.Microphone && this.stopOnMute && !this.isUserProvided) { livekitLogger.debug('stopping mic track'); // also stop the track, so that microphone indicator is turned off this._mediaStreamTrack.stop(); } await super.mute(); }); return this; } async unmute() { await this.muteQueue.run(async () => { if (this.source === Track.Source.Microphone && (this.stopOnMute || this._mediaStreamTrack.readyState === 'ended') && !this.isUserProvided) { livekitLogger.debug('reacquiring mic track'); await this.restartTrack(); } await super.unmute(); }); return this; } async restartTrack(options) { let constraints; if (options) { const streamConstraints = constraintsForOptions({ audio: options }); if (typeof streamConstraints.audio !== 'boolean') { constraints = streamConstraints.audio; } } await this.restart(constraints); } async restart(constraints) { const track = await super.restart(constraints); this.checkForSilence(); return track; } /* @internal */ startMonitor() { if (!isWeb()) { return; } if (this.monitorInterval) { return; } this.monitorInterval = setInterval(() => { this.monitorSender(); }, monitorFrequency); } async getSenderStats() { var _a; if (!((_a = this.sender) === null || _a === void 0 ? void 0 : _a.getStats)) { return undefined; } const stats = await this.sender.getStats(); let audioStats; stats.forEach(v => { if (v.type === 'outbound-rtp') { audioStats = { type: 'audio', streamId: v.id, packetsSent: v.packetsSent, packetsLost: v.packetsLost, bytesSent: v.bytesSent, timestamp: v.timestamp, roundTripTime: v.roundTripTime, jitter: v.jitter }; } }); return audioStats; } async checkForSilence() { const trackIsSilent = await detectSilence(this); if (trackIsSilent) { if (!this.isMuted) { livekitLogger.warn('silence detected on local audio track'); } this.emit(TrackEvent.AudioSilenceDetected); } return trackIsSilent; } } const refreshSubscribedCodecAfterNewCodec = 5000; class LocalVideoTrack extends LocalTrack { /** * * @param mediaTrack * @param constraints MediaTrackConstraints that are being used when restarting or reacquiring tracks * @param userProvidedTrack Signals to the SDK whether or not the mediaTrack should be managed (i.e. released and reacquired) internally by the SDK */ constructor(mediaTrack, constraints) { let userProvidedTrack = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; super(mediaTrack, Track.Kind.Video, constraints, userProvidedTrack); /* @internal */ this.simulcastCodecs = new Map(); this.monitorSender = async () => { if (!this.sender) { this._currentBitrate = 0; return; } let stats; try { stats = await this.getSenderStats(); } catch (e) { livekitLogger.error('could not get audio sender stats', { error: e }); return; } const statsMap = new Map(stats.map(s => [s.rid, s])); if (this.prevStats) { let totalBitrate = 0; statsMap.forEach((s, key) => { var _a; const prev = (_a = this.prevStats) === null || _a === void 0 ? void 0 : _a.get(key); totalBitrate += computeBitrate(s, prev); }); this._currentBitrate = totalBitrate; } this.prevStats = statsMap; }; this.senderLock = new Mutex(); } get isSimulcast() { if (this.sender && this.sender.getParameters().encodings.length > 1) { return true; } return false; } /* @internal */ startMonitor(signalClient) { var _a; this.signalClient = signalClient; if (!isWeb()) { return; } // save original encodings // TODO : merge simulcast tracks stats const params = (_a = this.sender) === null || _a === void 0 ? void 0 : _a.getParameters(); if (params) { this.encodings = params.encodings; } if (this.monitorInterval) { return; } this.monitorInterval = setInterval(() => { this.monitorSender(); }, monitorFrequency); } stop() { this._mediaStreamTrack.getConstraints(); this.simulcastCodecs.forEach(trackInfo => { trackInfo.mediaStreamTrack.stop(); }); super.stop(); } async mute() { await this.muteQueue.run(async () => { if (this.source === Track.Source.Camera && !this.isUserProvided) { livekitLogger.debug('stopping camera track'); // also stop the track, so that camera indicator is turned off this._mediaStreamTrack.stop(); } await super.mute(); }); return this; } async unmute() { await this.muteQueue.run(async () => { if (this.source === Track.Source.Camera && !this.isUserProvided) { livekitLogger.debug('reacquiring camera track'); await this.restartTrack(); } await super.unmute(); }); return this; } async getSenderStats() { var _a; if (!((_a = this.sender) === null || _a === void 0 ? void 0 : _a.getStats)) { return []; } const items = []; const stats = await this.sender.getStats(); stats.forEach(v => { var _a; if (v.type === 'outbound-rtp') { const vs = { type: 'video', streamId: v.id, frameHeight: v.frameHeight, frameWidth: v.frameWidth, firCount: v.firCount, pliCount: v.pliCount, nackCount: v.nackCount, packetsSent: v.packetsSent, bytesSent: v.bytesSent, framesSent: v.framesSent, timestamp: v.timestamp, rid: (_a = v.rid) !== null && _a !== void 0 ? _a : v.id, retransmittedPacketsSent: v.retransmittedPacketsSent, qualityLimitationReason: v.qualityLimitationReason, qualityLimitationResolutionChanges: v.qualityLimitationResolutionChanges }; // locate the appropriate remote-inbound-rtp item const r = stats.get(v.remoteId); if (r) { vs.jitter = r.jitter; vs.packetsLost = r.packetsLost; vs.roundTripTime = r.roundTripTime; } items.push(vs); } }); return items; } setPublishingQuality(maxQuality) { const qualities = []; for (let q = VideoQuality.LOW; q <= VideoQuality.HIGH; q += 1) { qualities.push({ quality: q, enabled: q <= maxQuality }); } livekitLogger.debug("setting publishing quality. max quality ".concat(maxQuality)); this.setPublishingLayers(qualities); } async setDeviceId(deviceId) { if (this.constraints.deviceId === deviceId) { return; } this.constraints.deviceId = deviceId; // when video is muted, underlying media stream track is stopped and // will be restarted later if (!this.isMuted) { await this.restartTrack(); } } async restartTrack(options) { let constraints; if (options) { const streamConstraints = constraintsForOptions({ video: options }); if (typeof streamConstraints.video !== 'boolean') { constraints = streamConstraints.video; } } await this.restart(constraints); } addSimulcastTrack(codec, encodings) { if (this.simulcastCodecs.has(codec)) { throw new Error("".concat(codec, " already added")); } const simulcastCodecInfo = { codec, mediaStreamTrack: this.mediaStreamTrack.clone(), sender: undefined, encodings }; this.simulcastCodecs.set(codec, simulcastCodecInfo); return simulcastCodecInfo; } setSimulcastTrackSender(codec, sender) { const simulcastCodecInfo = this.simulcastCodecs.get(codec); if (!simulcastCodecInfo) { return; } simulcastCodecInfo.sender = sender; // browser will reenable disabled codec/layers after new codec has been published, // so refresh subscribedCodecs after publish a new codec setTimeout(() => { if (this.subscribedCodecs) { this.setPublishingCodecs(this.subscribedCodecs); } }, refreshSubscribedCodecAfterNewCodec); } /** * @internal * Sets codecs that should be publishing */ async setPublishingCodecs(codecs) { livekitLogger.debug('setting publishing codecs', { codecs, currentCodec: this.codec }); // only enable simulcast codec for preference codec setted if (!this.codec && codecs.length > 0) { await this.setPublishingLayers(codecs[0].qualities); return []; } this.subscribedCodecs = codecs; const newCodecs = []; var _iteratorAbruptCompletion = false; var _didIteratorError = false; var _iteratorError; try { for (var _iterator = _asyncIterator(codecs), _step; _iteratorAbruptCompletion = !(_step = await _iterator.next()).done; _iteratorAbruptCompletion = false) { const codec = _step.value; { if (!this.codec || this.codec === codec.codec) { await this.setPublishingLayers(codec.qualities); } else { const simulcastCodecInfo = this.simulcastCodecs.get(codec.codec); livekitLogger.debug("try setPublishingCodec for ".concat(codec.codec), simulcastCodecInfo); if (!simulcastCodecInfo || !simulcastCodecInfo.sender) { for (const q of codec.qualities) { if (q.enabled) { newCodecs.push(codec.codec); break; } } } else if (simulcastCodecInfo.encodings) { livekitLogger.debug("try setPublishingLayersForSender ".concat(codec.codec)); await setPublishingLayersForSender(simulcastCodecInfo.sender, simulcastCodecInfo.encodings, codec.qualities, this.senderLock); } } } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (_iteratorAbruptCompletion && _iterator.return != null) { await _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } return newCodecs; } /** * @internal * Sets layers that should be publishing */ async setPublishingLayers(qualities) { livekitLogger.debug('setting publishing layers', qualities); if (!this.sender || !this.encodings) { return; } await setPublishingLayersForSender(this.sender, this.encodings, qualities, this.senderLock); } async handleAppVisibilityChanged() { await super.handleAppVisibilityChanged(); if (!isMobile()) return; if (this.isInBackground && this.source === Track.Source.Camera) { this._mediaStreamTrack.enabled = false; } } } async function setPublishingLayersForSender(sender, senderEncodings, qualities, senderLock) { const unlock = await senderLock.lock(); livekitLogger.debug('setPublishingLayersForSender', { sender, qualities, senderEncodings }); try { const params = sender.getParameters(); const { encodings } = params; if (!encodings) { return; } if (encodings.length !== senderEncodings.length) { livekitLogger.warn('cannot set publishing layers, encodings mismatch'); return; } let hasChanged = false; encodings.forEach((encoding, idx) => { var _a; let rid = (_a = encoding.rid) !== null && _a !== void 0 ? _a : ''; if (rid === '') { rid = 'q'; } const quality = videoQualityForRid(rid); const subscribedQuality = qualities.find(q => q.quality === quality); if (!subscribedQuality) { return; } if (encoding.active !== subscribedQuality.enabled) { hasChanged = true; encoding.active = subscribedQuality.enabled; livekitLogger.debug("setting layer ".concat(subscribedQuality.quality, " to ").concat(encoding.active ? 'enabled' : 'disabled')); // FireFox does not support setting encoding.active to false, so we // have a workaround of lowering its bitrate and resolution to the min. if (isFireFox()) { if (subscribedQuality.enabled) { encoding.scaleResolutionDownBy = senderEncodings[idx].scaleResolutionDownBy; encoding.maxBitrate = senderEncodings[idx].maxBitrate; /* @ts-ignore */ encoding.maxFrameRate = senderEncodings[idx].maxFrameRate; } else { encoding.scaleResolutionDownBy = 4; encoding.maxBitrate = 10; /* @ts-ignore */ encoding.maxFrameRate = 2; } } } }); if (hasChanged) { params.encodings = encodings; await sender.setParameters(params); } } finally { unlock(); } } function videoQualityForRid(rid) { switch (rid) { case 'f': return VideoQuality.HIGH; case 'h': return VideoQuality.MEDIUM; case 'q': return VideoQuality.LOW; default: return VideoQuality.UNRECOGNIZED; } } function videoLayersFromEncodings(width, height, encodings) { // default to a single layer, HQ if (!encodings) { return [{ quality: VideoQuality.HIGH, width, height, bitrate: 0, ssrc: 0 }]; } return encodings.map(encoding => { var _a, _b, _c; const scale = (_a = encoding.scaleResolutionDownBy) !== null && _a !== void 0 ? _a : 1; let quality = videoQualityForRid((_b = encoding.rid) !== null && _b !== void 0 ? _b : ''); if (quality === VideoQuality.UNRECOGNIZED && encodings.length === 1) { quality = VideoQuality.HIGH; } return { quality, width: width / scale, height: height / scale, bitrate: (_c = encoding.maxBitrate) !== null && _c !== void 0 ? _c : 0, ssrc: 0 }; }); } class RemoteTrack extends Track { constructor(mediaTrack, sid, kind, receiver) { super(mediaTrack, kind); this.sid = sid; this.receiver = receiver; } /** @internal */ setMuted(muted) { if (this.isMuted !== muted) { this.isMuted = muted; this._mediaStreamTrack.enabled = !muted; this.emit(muted ? TrackEvent.Muted : TrackEvent.Unmuted, this); } } /** @internal */ setMediaStream(stream) { // this is needed to determine when the track is finished // we send each track down in its own MediaStream, so we can assume the // current track is the only one that can be removed. this.mediaStream = stream; stream.onremovetrack = () => { this.receiver = undefined; this._currentBitrate = 0; this.emit(TrackEvent.Ended, this); }; } start() { this.startMonitor(); // use `enabled` of track to enable re-use of transceiver super.enable(); } stop() { this.stopMonitor(); // use `enabled` of track to enable re-use of transceiver super.disable(); } /* @internal */ startMonitor() { if (!this.monitorInterval) { this.monitorInterval = setInterval(() => this.monitorReceiver(), monitorFrequency); } } } class RemoteAudioTrack extends RemoteTrack { constructor(mediaTrack, sid, receiver, audioContext, audioOutput) { super(mediaTrack, sid, Track.Kind.Audio, receiver); this.monitorReceiver = async () => { if (!this.receiver) { this._currentBitrate = 0; return; } const stats = await this.getReceiverStats(); if (stats && this.prevStats && this.receiver) { this._currentBitrate = computeBitrate(stats, this.prevStats); } this.prevStats = stats; }; this.audioContext = audioContext; this.webAudioPluginNodes = []; if (audioOutput) { this.sinkId = audioOutput.deviceId; } } /** * sets the volume for all attached audio elements */ setVolume(volume) { var _a; for (const el of this.attachedElements) { if (this.audioContext) { (_a = this.gainNode) === null || _a === void 0 ? void 0 : _a.gain.setTargetAtTime(volume, 0, 0.1); } else { el.volume = volume; } } this.elementVolume = volume; } /** * gets the volume of attached audio elements (loudest) */ getVolume() { if (this.elementVolume) { return this.elementVolume; } let highestVolume = 0; this.attachedElements.forEach(element => { if (element.volume > highestVolume) { highestVolume = element.volume; } }); return highestVolume; } /** * calls setSinkId on all attached elements, if supported * @param deviceId audio output device */ async setSinkId(deviceId) { this.sinkId = deviceId; await Promise.all(this.attachedElements.map(elm => { if (!supportsSetSinkId(elm)) { return; } /* @ts-ignore */ return elm.setSinkId(deviceId); })); } attach(element) { const needsNewWebAudioConnection = this.attachedElements.length === 0; if (!element) { element = super.attach(); } else { super.attach(element); } if (this.elementVolume) { element.volume = this.elementVolume; } if (this.sinkId && supportsSetSinkId(element)) { /* @ts-ignore */ element.setSinkId(this.sinkId); } if (this.audioContext && needsNewWebAudioConnection) { livekitLogger.debug('using audio context mapping'); this.connectWebAudio(this.audioContext, element); element.volume = 0; element.muted = true; } return element; } detach(element) { let detached; if (!element) { detached = super.detach(); this.disconnectWebAudio(); } else { detached = super.detach(element); // if there are still any attached elements after detaching, connect webaudio to the first element that's left // disconnect webaudio otherwise if (this.audioContext) { if (this.attachedElements.length > 0) { this.connectWebAudio(this.audioContext, this.attachedElements[0]); } else { this.disconnectWebAudio(); } } } return detached; } /** * @internal * @experimental */ setAudioContext(audioContext) { this.audioContext = audioContext; if (audioContext && this.attachedElements.length > 0) { this.connectWebAudio(audioContext, this.attachedElements[0]); } else if (!audioContext) { this.disconnectWebAudio(); } } /** * @internal * @experimental * @param {AudioNode[]} nodes - An array of WebAudio nodes. These nodes should not be connected to each other when passed, as the sdk will take care of connecting them in the order of the array. */ setWebAudioPlugins(nodes) { this.webAudioPluginNodes = nodes; if (this.attachedElements.length > 0 && this.audioContext) { this.connectWebAudio(this.audioContext, this.attachedElements[0]); } } connectWebAudio(context, element) { this.disconnectWebAudio(); // @ts-ignore attached elements always have a srcObject set this.sourceNode = context.createMediaStreamSource(element.srcObject); let lastNode = this.sourceNode; this.webAudioPluginNodes.forEach(node => { lastNode.connect(node); lastNode = node; }); this.gainNode = context.createGain(); lastNode.connect(this.gainNode); this.gainNode.connect(context.destination); if (this.elementVolume) { this.gainNode.gain.setTargetAtTime(this.elementVolume, 0, 0.1); } // try to resume the context if it isn't running already if (context.state !== 'running') { context.resume().then(() => { if (context.state !== 'running') { this.emit(TrackEvent.AudioPlaybackFailed, new Error("Audio Context couldn't be started automatically")); } }).catch(e => { this.emit(TrackEvent.AudioPlaybackFailed, e); }); } } disconnectWebAudio() { var _a, _b; (_a = this.gainNode) === null || _a === void 0 ? void 0 : _a.disconnect(); (_b = this.sourceNode) === null || _b === void 0 ? void 0 : _b.disconnect(); this.gainNode = undefined; this.sourceNode = undefined; } async getReceiverStats() { if (!this.receiver || !this.receiver.getStats) { return; } const stats = await this.receiver.getStats(); let receiverStats; stats.forEach(v => { if (v.type === 'inbound-rtp') { receiverStats = { type: 'audio', timestamp: v.timestamp, jitter: v.jitter, bytesReceived: v.bytesReceived, concealedSamples: v.concealedSamples, concealmentEvents: v.concealmentEvents, silentConcealedSamples: v.silentConcealedSamples, silentConcealmentEvents: v.silentConcealmentEvents, totalAudioEnergy: v.totalAudioEnergy, totalSamplesDuration: v.totalSamplesDuration }; } }); return receiverStats; } } function r(r, e, n) { var i, t, o; void 0 === e && (e = 50), void 0 === n && (n = {}); var a = null != (i = n.isImmediate) && i, u = null != (t = n.callback) && t, c = n.maxWait, v = Date.now(), l = []; function f() { if (void 0 !== c) { var r = Date.now() - v; if (r + e >= c) return c - r; } return e; } var d = function () { var e = [].slice.call(arguments), n = this; return new Promise(function (i, t) { var c = a && void 0 === o; if (void 0 !== o && clearTimeout(o), o = setTimeout(function () { if (o = void 0, v = Date.now(), !a) { var i = r.apply(n, e); u && u(i), l.forEach(function (r) { return (0, r.resolve)(i); }), l = []; } }, f()), c) { var d = r.apply(n, e); return u && u(d), i(d); } l.push({ resolve: i, reject: t }); }); }; return d.cancel = function (r) { void 0 !== o && clearTimeout(o), l.forEach(function (e) { return (0, e.reject)(r); }), l = []; }, d; } /** * Timers that can be overridden with platform specific implementations * that ensure that they are fired. These should be used when it is critical * that the timer fires on time. */ class CriticalTimers {} // eslint-disable-next-line @typescript-eslint/no-implied-eval CriticalTimers.setTimeout = function () { return setTimeout(...arguments); }; // eslint-disable-next-line @typescript-eslint/no-implied-eval CriticalTimers.setInterval = function () { return setInterval(...arguments); }; CriticalTimers.clearTimeout = function () { return clearTimeout(...arguments); }; CriticalTimers.clearInterval = function () { return clearInterval(...arguments); }; const REACTION_DELAY = 100; class RemoteVideoTrack extends RemoteTrack { constructor(mediaTrack, sid, receiver, adaptiveStreamSettings) { super(mediaTrack, sid, Track.Kind.Video, receiver); this.elementInfos = []; this.hasUsedAttach = false; this.monitorReceiver = async () => { if (!this.receiver) { this._currentBitrate = 0; return; } const stats = await this.getReceiverStats(); if (stats && this.prevStats && this.receiver) { this._currentBitrate = computeBitrate(stats, this.prevStats); } this.prevStats = stats; }; this.debouncedHandleResize = r(() => { this.updateDimensions(); }, REACTION_DELAY); this.adaptiveStreamSettings = adaptiveStreamSettings; } get isAdaptiveStream() { return this.adaptiveStreamSettings !== undefined; } get mediaStreamTrack() { if (this.isAdaptiveStream && !this.hasUsedAttach) { livekitLogger.warn('When using adaptiveStream, you need to use remoteVideoTrack.attach() to add the track to a HTMLVideoElement, otherwise your video tracks might never start'); } return this._mediaStreamTrack; } /** @internal */ setMuted(muted) { super.setMuted(muted); this.attachedElements.forEach(element => { // detach or attach if (muted) { detachTrack(this._mediaStreamTrack, element); } else { attachToElement(this._mediaStreamTrack, element); } }); } attach(element) { if (!element) { element = super.attach(); } else { super.attach(element); } // It's possible attach is called multiple times on an element. When that's // the case, we'd want to avoid adding duplicate elementInfos if (this.adaptiveStreamSettings && this.elementInfos.find(info => info.element === element) === undefined) { const elementInfo = new HTMLElementInfo(element); this.observeElementInfo(elementInfo); } this.hasUsedAttach = true; return element; } /** * Observe an ElementInfo for changes when adaptive streaming. * @param elementInfo * @internal */ observeElementInfo(elementInfo) { if (this.adaptiveStreamSettings && this.elementInfos.find(info => info === elementInfo) === undefined) { elementInfo.handleResize = () => { this.debouncedHandleResize(); }; elementInfo.handleVisibilityChanged = () => { this.updateVisibility(); }; this.elementInfos.push(elementInfo); elementInfo.observe(); // trigger the first resize update cycle // if the tab is backgrounded, the initial resize event does not fire until // the tab comes into focus for the first time. this.debouncedHandleResize(); this.updateVisibility(); } else { livekitLogger.warn('visibility resize observer not triggered'); } } /** * Stop observing an ElementInfo for changes. * @param elementInfo * @internal */ stopObservingElementInfo(elementInfo) { if (!this.isAdaptiveStream) { livekitLogger.warn('stopObservingElementInfo ignored'); return; } const stopElementInfos = this.elementInfos.filter(info => info === elementInfo); for (const info of stopElementInfos) { info.stopObserving(); } this.elementInfos = this.elementInfos.filter(info => info !== elementInfo); this.updateVisibility(); } detach(element) { let detachedElements = []; if (element) { this.stopObservingElement(element); return super.detach(element); } detachedElements = super.detach(); for (const e of detachedElements) { this.stopObservingElement(e); } return detachedElements; } /** @internal */ getDecoderImplementation() { var _a; return (_a = this.prevStats) === null || _a === void 0 ? void 0 : _a.decoderImplementation; } async getReceiverStats() { if (!this.receiver || !this.receiver.getStats) { return; } const stats = await this.receiver.getStats(); let receiverStats; stats.forEach(v => { if (v.type === 'inbound-rtp') { receiverStats = { type: 'video', framesDecoded: v.framesDecoded, framesDropped: v.framesDropped, framesReceived: v.framesReceived, packetsReceived: v.packetsReceived, packetsLost: v.packetsLost, frameWidth: v.frameWidth, frameHeight: v.frameHeight, pliCount: v.pliCount, firCount: v.firCount, nackCount: v.nackCount, jitter: v.jitter, timestamp: v.timestamp, bytesReceived: v.bytesReceived, decoderImplementation: v.decoderImplementation }; } }); return receiverStats; } stopObservingElement(element) { const stopElementInfos = this.elementInfos.filter(info => info.element === element); for (const info of stopElementInfos) { info.stopObserving(); } this.elementInfos = this.elementInfos.filter(info => info.element !== element); } async handleAppVisibilityChanged() { await super.handleAppVisibilityChanged(); if (!this.isAdaptiveStream) return; this.updateVisibility(); } updateVisibility() { var _a, _b; const lastVisibilityChange = this.elementInfos.reduce((prev, info) => Math.max(prev, info.visibilityChangedAt || 0), 0); const backgroundPause = ((_b = (_a = this.adaptiveStreamSettings) === null || _a === void 0 ? void 0 : _a.pauseVideoInBackground) !== null && _b !== void 0 ? _b : true // default to true ) ? this.isInBackground : false; const isPiPMode = this.elementInfos.some(info => info.pictureInPicture); const isVisible = this.elementInfos.some(info => info.visible) && !backgroundPause || isPiPMode; if (this.lastVisible === isVisible) { return; } if (!isVisible && Date.now() - lastVisibilityChange < REACTION_DELAY) { // delay hidden events CriticalTimers.setTimeout(() => { this.updateVisibility(); }, REACTION_DELAY); return; } this.lastVisible = isVisible; this.emit(TrackEvent.VisibilityChanged, isVisible, this); } updateDimensions() { var _a, _b, _c, _d; let maxWidth = 0; let maxHeight = 0; for (const info of this.elementInfos) { const pixelDensity = (_b = (_a = this.adaptiveStreamSettings) === null || _a === void 0 ? void 0 : _a.pixelDensity) !== null && _b !== void 0 ? _b : 1; const pixelDensityValue = pixelDensity === 'screen' ? window.devicePixelRatio : pixelDensity; const currentElementWidth = info.width() * pixelDensityValue; const currentElementHeight = info.height() * pixelDensityValue; if (currentElementWidth + currentElementHeight > maxWidth + maxHeight) { maxWidth = currentElementWidth; maxHeight = currentElementHeight; } } if (((_c = this.lastDimensions) === null || _c === void 0 ? void 0 : _c.width) === maxWidth && ((_d = this.lastDimensions) === null || _d === void 0 ? void 0 : _d.height) === maxHeight) { return; } this.lastDimensions = { width: maxWidth, height: maxHeight }; this.emit(TrackEvent.VideoDimensionsChanged, this.lastDimensions, this); } } class HTMLElementInfo { get visible() { return this.isPiP || this.isIntersecting; } get pictureInPicture() { return this.isPiP; } constructor(element, visible) { this.onVisibilityChanged = entry => { var _a; const { target, isIntersecting } = entry; if (target === this.element) { this.isIntersecting = isIntersecting; this.visibilityChangedAt = Date.now(); (_a = this.handleVisibilityChanged) === null || _a === void 0 ? void 0 : _a.call(this); } }; this.onEnterPiP = () => { var _a; this.isPiP = true; (_a = this.handleVisibilityChanged) === null || _a === void 0 ? void 0 : _a.call(this); }; this.onLeavePiP = () => { var _a; this.isPiP = false; (_a = this.handleVisibilityChanged) === null || _a === void 0 ? void 0 : _a.call(this); }; this.element = element; this.isIntersecting = visible !== null && visible !== void 0 ? visible : isElementInViewport(element); this.isPiP = isWeb() && document.pictureInPictureElement === element; this.visibilityChangedAt = 0; } width() { return this.element.clientWidth; } height() { return this.element.clientHeight; } observe() { // make sure we update the current visible state once we start to observe this.isIntersecting = isElementInViewport(this.element); this.isPiP = document.pictureInPictureElement === this.element; this.element.handleResize = () => { var _a; (_a = this.handleResize) === null || _a === void 0 ? void 0 : _a.call(this); }; this.element.handleVisibilityChanged = this.onVisibilityChanged; getIntersectionObserver().observe(this.element); getResizeObserver().observe(this.element); this.element.addEventListener('enterpictureinpicture', this.onEnterPiP); this.element.addEventListener('leavepictureinpicture', this.onLeavePiP); } stopObserving() { var _a, _b; (_a = getIntersectionObserver()) === null || _a === void 0 ? void 0 : _a.unobserve(this.element); (_b = getResizeObserver()) === null || _b === void 0 ? void 0 : _b.unobserve(this.element); this.element.removeEventListener('enterpictureinpicture', this.onEnterPiP); this.element.removeEventListener('leavepictureinpicture', this.onLeavePiP); } } // does not account for occlusion by other elements function isElementInViewport(el) { let top = el.offsetTop; let left = el.offsetLeft; const width = el.offsetWidth; const height = el.offsetHeight; const { hidden } = el; const { opacity, display } = getComputedStyle(el); while (el.offsetParent) { el = el.offsetParent; top += el.offsetTop; left += el.offsetLeft; } return top < window.pageYOffset + window.innerHeight && left < window.pageXOffset + window.innerWidth && top + height > window.pageYOffset && left + width > window.pageXOffset && !hidden && (opacity !== '' ? parseFloat(opacity) > 0 : true) && display !== 'none'; } class TrackPublication extends eventsExports.EventEmitter { constructor(kind, id, name) { super(); this.metadataMuted = false; this.handleMuted = () => { this.emit(TrackEvent.Muted); }; this.handleUnmuted = () => { this.emit(TrackEvent.Unmuted); }; this.setMaxListeners(100); this.kind = kind; this.trackSid = id; this.trackName = name; this.source = Track.Source.Unknown; } /** @internal */ setTrack(track) { if (this.track) { this.track.off(TrackEvent.Muted, this.handleMuted); this.track.off(TrackEvent.Unmuted, this.handleUnmuted); } this.track = track; if (track) { // forward events track.on(TrackEvent.Muted, this.handleMuted); track.on(TrackEvent.Unmuted, this.handleUnmuted); } } get isMuted() { return this.metadataMuted; } get isEnabled() { return true; } get isSubscribed() { return this.track !== undefined; } /** * an [AudioTrack] if this publication holds an audio track */ get audioTrack() { if (this.track instanceof LocalAudioTrack || this.track instanceof RemoteAudioTrack) { return this.track; } } /** * an [VideoTrack] if this publication holds a video track */ get videoTrack() { if (this.track instanceof LocalVideoTrack || this.track instanceof RemoteVideoTrack) { return this.track; } } /** @internal */ updateInfo(info) { this.trackSid = info.sid; this.trackName = info.name; this.source = Track.sourceFromProto(info.source); this.mimeType = info.mimeType; if (this.kind === Track.Kind.Video && info.width > 0) { this.dimensions = { width: info.width, height: info.height }; this.simulcasted = info.simulcast; } this.trackInfo = info; livekitLogger.trace('update publication info', { info }); } } (function (TrackPublication) { (function (SubscriptionStatus) { SubscriptionStatus["Desired"] = "desired"; SubscriptionStatus["Subscribed"] = "subscribed"; SubscriptionStatus["Unsubscribed"] = "unsubscribed"; })(TrackPublication.SubscriptionStatus || (TrackPublication.SubscriptionStatus = {})); (function (PermissionStatus) { PermissionStatus["Allowed"] = "allowed"; PermissionStatus["NotAllowed"] = "not_allowed"; })(TrackPublication.PermissionStatus || (TrackPublication.PermissionStatus = {})); })(TrackPublication || (TrackPublication = {})); class LocalTrackPublication extends TrackPublication { get isUpstreamPaused() { var _a; return (_a = this.track) === null || _a === void 0 ? void 0 : _a.isUpstreamPaused; } constructor(kind, ti, track) { super(kind, ti.sid, ti.name); this.track = undefined; this.handleTrackEnded = () => { this.emit(TrackEvent.Ended); }; this.updateInfo(ti); this.setTrack(track); } setTrack(track) { if (this.track) { this.track.off(TrackEvent.Ended, this.handleTrackEnded); } super.setTrack(track); if (track) { track.on(TrackEvent.Ended, this.handleTrackEnded); } } get isMuted() { if (this.track) { return this.track.isMuted; } return super.isMuted; } get audioTrack() { return super.audioTrack; } get videoTrack() { return super.videoTrack; } /** * Mute the track associated with this publication */ async mute() { var _a; return (_a = this.track) === null || _a === void 0 ? void 0 : _a.mute(); } /** * Unmute track associated with this publication */ async unmute() { var _a; return (_a = this.track) === null || _a === void 0 ? void 0 : _a.unmute(); } /** * Pauses the media stream track associated with this publication from being sent to the server * and signals "muted" event to other participants * Useful if you want to pause the stream without pausing the local media stream track */ async pauseUpstream() { var _a; await ((_a = this.track) === null || _a === void 0 ? void 0 : _a.pauseUpstream()); } /** * Resumes sending the media stream track associated with this publication to the server after a call to [[pauseUpstream()]] * and signals "unmuted" event to other participants (unless the track is explicitly muted) */ async resumeUpstream() { var _a; await ((_a = this.track) === null || _a === void 0 ? void 0 : _a.resumeUpstream()); } } class VideoPreset { constructor(width, height, maxBitrate, maxFramerate) { this.width = width; this.height = height; this.encoding = { maxBitrate, maxFramerate }; } get resolution() { return { width: this.width, height: this.height, frameRate: this.encoding.maxFramerate, aspectRatio: this.width / this.height }; } } const backupCodecs = ['vp8', 'h264']; function isBackupCodec(codec) { return !!backupCodecs.find(backup => backup === codec); } var AudioPresets; (function (AudioPresets) { AudioPresets.telephone = { maxBitrate: 12000 }; AudioPresets.speech = { maxBitrate: 20000 }; AudioPresets.music = { maxBitrate: 32000 }; AudioPresets.musicStereo = { maxBitrate: 48000 }; AudioPresets.musicHighQuality = { maxBitrate: 64000 }; AudioPresets.musicHighQualityStereo = { maxBitrate: 96000 }; })(AudioPresets || (AudioPresets = {})); /** * Sane presets for video resolution/encoding */ const VideoPresets = { h90: new VideoPreset(160, 90, 60000, 15), h180: new VideoPreset(320, 180, 120000, 15), h216: new VideoPreset(384, 216, 180000, 15), h360: new VideoPreset(640, 360, 300000, 20), h540: new VideoPreset(960, 540, 600000, 25), h720: new VideoPreset(1280, 720, 1700000, 30), h1080: new VideoPreset(1920, 1080, 3000000, 30), h1440: new VideoPreset(2560, 1440, 5000000, 30), h2160: new VideoPreset(3840, 2160, 8000000, 30) }; /** * Four by three presets */ const VideoPresets43 = { h120: new VideoPreset(160, 120, 80000, 15), h180: new VideoPreset(240, 180, 100000, 15), h240: new VideoPreset(320, 240, 150000, 15), h360: new VideoPreset(480, 360, 225000, 20), h480: new VideoPreset(640, 480, 300000, 20), h540: new VideoPreset(720, 540, 450000, 25), h720: new VideoPreset(960, 720, 1500000, 30), h1080: new VideoPreset(1440, 1080, 2500000, 30), h1440: new VideoPreset(1920, 1440, 3500000, 30) }; const ScreenSharePresets = { h360fps3: new VideoPreset(640, 360, 200000, 3), h720fps5: new VideoPreset(1280, 720, 400000, 5), h720fps15: new VideoPreset(1280, 720, 1000000, 15), h1080fps15: new VideoPreset(1920, 1080, 1500000, 15), h1080fps30: new VideoPreset(1920, 1080, 3000000, 30) }; var ConnectionQuality; (function (ConnectionQuality) { ConnectionQuality["Excellent"] = "excellent"; ConnectionQuality["Good"] = "good"; ConnectionQuality["Poor"] = "poor"; ConnectionQuality["Unknown"] = "unknown"; })(ConnectionQuality || (ConnectionQuality = {})); function qualityFromProto(q) { switch (q) { case ConnectionQuality$1.EXCELLENT: return ConnectionQuality.Excellent; case ConnectionQuality$1.GOOD: return ConnectionQuality.Good; case ConnectionQuality$1.POOR: return ConnectionQuality.Poor; default: return ConnectionQuality.Unknown; } } class Participant extends eventsExports.EventEmitter { /** @internal */ constructor(sid, identity, name, metadata) { super(); /** audio level between 0-1.0, 1 being loudest, 0 being softest */ this.audioLevel = 0; /** if participant is currently speaking */ this.isSpeaking = false; this._connectionQuality = ConnectionQuality.Unknown; this.setMaxListeners(100); this.sid = sid; this.identity = identity; this.name = name; this.metadata = metadata; this.audioTracks = new Map(); this.videoTracks = new Map(); this.tracks = new Map(); } getTracks() { return Array.from(this.tracks.values()); } /** * Finds the first track that matches the source filter, for example, getting * the user's camera track with getTrackBySource(Track.Source.Camera). * @param source * @returns */ getTrack(source) { for (const [, pub] of this.tracks) { if (pub.source === source) { return pub; } } } /** * Finds the first track that matches the track's name. * @param name * @returns */ getTrackByName(name) { for (const [, pub] of this.tracks) { if (pub.trackName === name) { return pub; } } } get connectionQuality() { return this._connectionQuality; } get isCameraEnabled() { var _a; const track = this.getTrack(Track.Source.Camera); return !((_a = track === null || track === void 0 ? void 0 : track.isMuted) !== null && _a !== void 0 ? _a : true); } get isMicrophoneEnabled() { var _a; const track = this.getTrack(Track.Source.Microphone); return !((_a = track === null || track === void 0 ? void 0 : track.isMuted) !== null && _a !== void 0 ? _a : true); } get isScreenShareEnabled() { const track = this.getTrack(Track.Source.ScreenShare); return !!track; } get isLocal() { return false; } /** when participant joined the room */ get joinedAt() { if (this.participantInfo) { return new Date(this.participantInfo.joinedAt * 1000); } return new Date(); } /** @internal */ updateInfo(info) { this.identity = info.identity; this.sid = info.sid; this.name = info.name; this.setMetadata(info.metadata); if (info.permission) { this.setPermissions(info.permission); } // set this last so setMetadata can detect changes this.participantInfo = info; livekitLogger.trace('update participant info', { info }); } /** @internal */ setMetadata(md) { const changed = this.metadata !== md; const prevMetadata = this.metadata; this.metadata = md; if (changed) { this.emit(ParticipantEvent.ParticipantMetadataChanged, prevMetadata); } } /** @internal */ setPermissions(permissions) { var _a, _b, _c, _d, _e; const prevPermissions = this.permissions; const changed = permissions.canPublish !== ((_a = this.permissions) === null || _a === void 0 ? void 0 : _a.canPublish) || permissions.canSubscribe !== ((_b = this.permissions) === null || _b === void 0 ? void 0 : _b.canSubscribe) || permissions.canPublishData !== ((_c = this.permissions) === null || _c === void 0 ? void 0 : _c.canPublishData) || permissions.hidden !== ((_d = this.permissions) === null || _d === void 0 ? void 0 : _d.hidden) || permissions.recorder !== ((_e = this.permissions) === null || _e === void 0 ? void 0 : _e.recorder) || permissions.canPublishSources.length !== this.permissions.canPublishSources.length || permissions.canPublishSources.some((value, index) => { var _a; return value !== ((_a = this.permissions) === null || _a === void 0 ? void 0 : _a.canPublishSources[index]); }); this.permissions = permissions; if (changed) { this.emit(ParticipantEvent.ParticipantPermissionsChanged, prevPermissions); } return changed; } /** @internal */ setIsSpeaking(speaking) { if (speaking === this.isSpeaking) { return; } this.isSpeaking = speaking; if (speaking) { this.lastSpokeAt = new Date(); } this.emit(ParticipantEvent.IsSpeakingChanged, speaking); } /** @internal */ setConnectionQuality(q) { const prevQuality = this._connectionQuality; this._connectionQuality = qualityFromProto(q); if (prevQuality !== this._connectionQuality) { this.emit(ParticipantEvent.ConnectionQualityChanged, this._connectionQuality); } } addTrackPublication(publication) { // forward publication driven events publication.on(TrackEvent.Muted, () => { this.emit(ParticipantEvent.TrackMuted, publication); }); publication.on(TrackEvent.Unmuted, () => { this.emit(ParticipantEvent.TrackUnmuted, publication); }); const pub = publication; if (pub.track) { pub.track.sid = publication.trackSid; } this.tracks.set(publication.trackSid, publication); switch (publication.kind) { case Track.Kind.Audio: this.audioTracks.set(publication.trackSid, publication); break; case Track.Kind.Video: this.videoTracks.set(publication.trackSid, publication); break; } } } function trackPermissionToProto(perms) { var _a, _b, _c; if (!perms.participantSid && !perms.participantIdentity) { throw new Error('Invalid track permission, must provide at least one of participantIdentity and participantSid'); } return { participantIdentity: (_a = perms.participantIdentity) !== null && _a !== void 0 ? _a : '', participantSid: (_b = perms.participantSid) !== null && _b !== void 0 ? _b : '', allTracks: (_c = perms.allowAll) !== null && _c !== void 0 ? _c : false, trackSids: perms.allowedTrackSids || [] }; } /** @internal */ function mediaTrackToLocalTrack(mediaStreamTrack, constraints) { switch (mediaStreamTrack.kind) { case 'audio': return new LocalAudioTrack(mediaStreamTrack, constraints, false); case 'video': return new LocalVideoTrack(mediaStreamTrack, constraints, false); default: throw new TrackInvalidError("unsupported track type: ".concat(mediaStreamTrack.kind)); } } /* @internal */ const presets169 = Object.values(VideoPresets); /* @internal */ const presets43 = Object.values(VideoPresets43); /* @internal */ const presetsScreenShare = Object.values(ScreenSharePresets); /* @internal */ const defaultSimulcastPresets169 = [VideoPresets.h180, VideoPresets.h360]; /* @internal */ const defaultSimulcastPresets43 = [VideoPresets43.h180, VideoPresets43.h360]; /* @internal */ const computeDefaultScreenShareSimulcastPresets = fromPreset => { const layers = [{ scaleResolutionDownBy: 2, fps: 3 }]; return layers.map(t => { var _a; return new VideoPreset(Math.floor(fromPreset.width / t.scaleResolutionDownBy), Math.floor(fromPreset.height / t.scaleResolutionDownBy), Math.max(150000, Math.floor(fromPreset.encoding.maxBitrate / (t.scaleResolutionDownBy ** 2 * (((_a = fromPreset.encoding.maxFramerate) !== null && _a !== void 0 ? _a : 30) / t.fps)))), t.fps); }); }; // /** // * // * @internal // * @experimental // */ // const computeDefaultMultiCodecSimulcastEncodings = (width: number, height: number) => { // // use vp8 as a default // const vp8 = determineAppropriateEncoding(false, width, height); // const vp9 = { ...vp8, maxBitrate: vp8.maxBitrate * 0.9 }; // const h264 = { ...vp8, maxBitrate: vp8.maxBitrate * 1.1 }; // const av1 = { ...vp8, maxBitrate: vp8.maxBitrate * 0.7 }; // return { // vp8, // vp9, // h264, // av1, // }; // }; const videoRids = ['q', 'h', 'f']; /* @internal */ function computeVideoEncodings(isScreenShare, width, height, options) { var _a, _b; let videoEncoding = options === null || options === void 0 ? void 0 : options.videoEncoding; if (isScreenShare) { videoEncoding = options === null || options === void 0 ? void 0 : options.screenShareEncoding; } const useSimulcast = options === null || options === void 0 ? void 0 : options.simulcast; const scalabilityMode = options === null || options === void 0 ? void 0 : options.scalabilityMode; const videoCodec = options === null || options === void 0 ? void 0 : options.videoCodec; if (!videoEncoding && !useSimulcast && !scalabilityMode || !width || !height) { // when we aren't simulcasting or svc, will need to return a single encoding without // capping bandwidth. we always require a encoding for dynacast return [{}]; } if (!videoEncoding) { // find the right encoding based on width/height videoEncoding = determineAppropriateEncoding(isScreenShare, width, height, videoCodec); livekitLogger.debug('using video encoding', videoEncoding); } const original = new VideoPreset(width, height, videoEncoding.maxBitrate, videoEncoding.maxFramerate); if (scalabilityMode && videoCodec === 'av1') { livekitLogger.debug("using svc with scalabilityMode ".concat(scalabilityMode)); const encodings = []; // svc use first encoding as the original, so we sort encoding from high to low switch (scalabilityMode) { case 'L3T3': for (let i = 0; i < 3; i += 1) { encodings.push({ rid: videoRids[2 - i], scaleResolutionDownBy: 2 ** i, maxBitrate: videoEncoding.maxBitrate / 3 ** i, /* @ts-ignore */ maxFramerate: original.encoding.maxFramerate, /* @ts-ignore */ scalabilityMode: 'L3T3' }); } livekitLogger.debug('encodings', encodings); return encodings; default: // TODO : support other scalability modes throw new Error("unsupported scalabilityMode: ".concat(scalabilityMode)); } } if (!useSimulcast) { return [videoEncoding]; } let presets = []; if (isScreenShare) { presets = (_a = sortPresets(options === null || options === void 0 ? void 0 : options.screenShareSimulcastLayers)) !== null && _a !== void 0 ? _a : defaultSimulcastLayers(isScreenShare, original); } else { presets = (_b = sortPresets(options === null || options === void 0 ? void 0 : options.videoSimulcastLayers)) !== null && _b !== void 0 ? _b : defaultSimulcastLayers(isScreenShare, original); } let midPreset; if (presets.length > 0) { const lowPreset = presets[0]; if (presets.length > 1) { [, midPreset] = presets; } // NOTE: // 1. Ordering of these encodings is important. Chrome seems // to use the index into encodings to decide which layer // to disable when CPU constrained. // So encodings should be ordered in increasing spatial // resolution order. // 2. ion-sfu translates rids into layers. So, all encodings // should have the base layer `q` and then more added // based on other conditions. const size = Math.max(width, height); if (size >= 960 && midPreset) { return encodingsFromPresets(width, height, [lowPreset, midPreset, original]); } if (size >= 480) { return encodingsFromPresets(width, height, [lowPreset, original]); } } return encodingsFromPresets(width, height, [original]); } function computeTrackBackupEncodings(track, videoCodec, opts) { var _a, _b, _c, _d; if (!opts.backupCodec || opts.backupCodec.codec === opts.videoCodec) { // backup codec publishing is disabled return; } if (videoCodec !== opts.backupCodec.codec) { livekitLogger.warn('requested a different codec than specified as backup', { serverRequested: videoCodec, backup: opts.backupCodec.codec }); } opts.videoCodec = videoCodec; // use backup encoding setting as videoEncoding for backup codec publishing opts.videoEncoding = opts.backupCodec.encoding; const settings = track.mediaStreamTrack.getSettings(); const width = (_a = settings.width) !== null && _a !== void 0 ? _a : (_b = track.dimensions) === null || _b === void 0 ? void 0 : _b.width; const height = (_c = settings.height) !== null && _c !== void 0 ? _c : (_d = track.dimensions) === null || _d === void 0 ? void 0 : _d.height; const encodings = computeVideoEncodings(track.source === Track.Source.ScreenShare, width, height, opts); return encodings; } /* @internal */ function determineAppropriateEncoding(isScreenShare, width, height, codec) { const presets = presetsForResolution(isScreenShare, width, height); let { encoding } = presets[0]; // handle portrait by swapping dimensions const size = Math.max(width, height); for (let i = 0; i < presets.length; i += 1) { const preset = presets[i]; encoding = preset.encoding; if (preset.width >= size) { break; } } // presets are based on the assumption of vp8 as a codec // for other codecs we adjust the maxBitrate if no specific videoEncoding has been provided // TODO make the bitrate multipliers configurable per codec if (codec) { switch (codec) { case 'av1': encoding.maxBitrate = encoding.maxBitrate * 0.7; break; } } return encoding; } /* @internal */ function presetsForResolution(isScreenShare, width, height) { if (isScreenShare) { return presetsScreenShare; } const aspect = width > height ? width / height : height / width; if (Math.abs(aspect - 16.0 / 9) < Math.abs(aspect - 4.0 / 3)) { return presets169; } return presets43; } /* @internal */ function defaultSimulcastLayers(isScreenShare, original) { if (isScreenShare) { return computeDefaultScreenShareSimulcastPresets(original); } const { width, height } = original; const aspect = width > height ? width / height : height / width; if (Math.abs(aspect - 16.0 / 9) < Math.abs(aspect - 4.0 / 3)) { return defaultSimulcastPresets169; } return defaultSimulcastPresets43; } // presets should be ordered by low, medium, high function encodingsFromPresets(width, height, presets) { const encodings = []; presets.forEach((preset, idx) => { if (idx >= videoRids.length) { return; } const size = Math.min(width, height); const rid = videoRids[idx]; encodings.push({ rid, scaleResolutionDownBy: Math.max(1, size / Math.min(preset.width, preset.height)), maxBitrate: preset.encoding.maxBitrate, /* @ts-ignore */ maxFramerate: preset.encoding.maxFramerate }); }); return encodings; } /** @internal */ function sortPresets(presets) { if (!presets) return; return presets.sort((a, b) => { const { encoding: aEnc } = a; const { encoding: bEnc } = b; if (aEnc.maxBitrate > bEnc.maxBitrate) { return 1; } if (aEnc.maxBitrate < bEnc.maxBitrate) return -1; if (aEnc.maxBitrate === bEnc.maxBitrate && aEnc.maxFramerate && bEnc.maxFramerate) { return aEnc.maxFramerate > bEnc.maxFramerate ? 1 : -1; } return 0; }); } class RemoteTrackPublication extends TrackPublication { constructor(kind, ti, autoSubscribe) { super(kind, ti.sid, ti.name); this.track = undefined; /** @internal */ this.allowed = true; this.disabled = false; this.currentVideoQuality = VideoQuality.HIGH; this.handleEnded = track => { this.setTrack(undefined); this.emit(TrackEvent.Ended, track); }; this.handleVisibilityChange = visible => { livekitLogger.debug("adaptivestream video visibility ".concat(this.trackSid, ", visible=").concat(visible), { trackSid: this.trackSid }); this.disabled = !visible; this.emitTrackUpdate(); }; this.handleVideoDimensionsChange = dimensions => { livekitLogger.debug("adaptivestream video dimensions ".concat(dimensions.width, "x").concat(dimensions.height), { trackSid: this.trackSid }); this.videoDimensions = dimensions; this.emitTrackUpdate(); }; this.subscribed = autoSubscribe; this.updateInfo(ti); } /** * Subscribe or unsubscribe to this remote track * @param subscribed true to subscribe to a track, false to unsubscribe */ setSubscribed(subscribed) { const prevStatus = this.subscriptionStatus; const prevPermission = this.permissionStatus; this.subscribed = subscribed; // reset allowed status when desired subscription state changes // server will notify client via signal message if it's not allowed if (subscribed) { this.allowed = true; } const sub = { trackSids: [this.trackSid], subscribe: this.subscribed, participantTracks: [{ // sending an empty participant id since TrackPublication doesn't keep it // this is filled in by the participant that receives this message participantSid: '', trackSids: [this.trackSid] }] }; this.emit(TrackEvent.UpdateSubscription, sub); this.emitSubscriptionUpdateIfChanged(prevStatus); this.emitPermissionUpdateIfChanged(prevPermission); } get subscriptionStatus() { if (this.subscribed === false) { return TrackPublication.SubscriptionStatus.Unsubscribed; } if (!super.isSubscribed) { return TrackPublication.SubscriptionStatus.Desired; } return TrackPublication.SubscriptionStatus.Subscribed; } get permissionStatus() { return this.allowed ? TrackPublication.PermissionStatus.Allowed : TrackPublication.PermissionStatus.NotAllowed; } /** * Returns true if track is subscribed, and ready for playback */ get isSubscribed() { if (this.subscribed === false) { return false; } return super.isSubscribed; } // returns client's desire to subscribe to a track, also true if autoSubscribe is enabled get isDesired() { return this.subscribed !== false; } get isEnabled() { return !this.disabled; } /** * disable server from sending down data for this track. this is useful when * the participant is off screen, you may disable streaming down their video * to reduce bandwidth requirements * @param enabled */ setEnabled(enabled) { if (!this.isManualOperationAllowed() || this.disabled === !enabled) { return; } this.disabled = !enabled; this.emitTrackUpdate(); } /** * for tracks that support simulcasting, adjust subscribed quality * * This indicates the highest quality the client can accept. if network * bandwidth does not allow, server will automatically reduce quality to * optimize for uninterrupted video */ setVideoQuality(quality) { if (!this.isManualOperationAllowed() || this.currentVideoQuality === quality) { return; } this.currentVideoQuality = quality; this.videoDimensions = undefined; this.emitTrackUpdate(); } setVideoDimensions(dimensions) { var _a, _b; if (!this.isManualOperationAllowed()) { return; } if (((_a = this.videoDimensions) === null || _a === void 0 ? void 0 : _a.width) === dimensions.width && ((_b = this.videoDimensions) === null || _b === void 0 ? void 0 : _b.height) === dimensions.height) { return; } if (this.track instanceof RemoteVideoTrack) { this.videoDimensions = dimensions; } this.currentVideoQuality = undefined; this.emitTrackUpdate(); } setVideoFPS(fps) { if (!this.isManualOperationAllowed()) { return; } if (!(this.track instanceof RemoteVideoTrack)) { return; } if (this.fps === fps) { return; } this.fps = fps; this.emitTrackUpdate(); } get videoQuality() { return this.currentVideoQuality; } /** @internal */ setTrack(track) { const prevStatus = this.subscriptionStatus; const prevPermission = this.permissionStatus; const prevTrack = this.track; if (prevTrack === track) { return; } if (prevTrack) { // unregister listener prevTrack.off(TrackEvent.VideoDimensionsChanged, this.handleVideoDimensionsChange); prevTrack.off(TrackEvent.VisibilityChanged, this.handleVisibilityChange); prevTrack.off(TrackEvent.Ended, this.handleEnded); prevTrack.detach(); this.emit(TrackEvent.Unsubscribed, prevTrack); } super.setTrack(track); if (track) { track.sid = this.trackSid; track.on(TrackEvent.VideoDimensionsChanged, this.handleVideoDimensionsChange); track.on(TrackEvent.VisibilityChanged, this.handleVisibilityChange); track.on(TrackEvent.Ended, this.handleEnded); this.emit(TrackEvent.Subscribed, track); } this.emitPermissionUpdateIfChanged(prevPermission); this.emitSubscriptionUpdateIfChanged(prevStatus); } /** @internal */ setAllowed(allowed) { const prevStatus = this.subscriptionStatus; const prevPermission = this.permissionStatus; this.allowed = allowed; this.emitPermissionUpdateIfChanged(prevPermission); this.emitSubscriptionUpdateIfChanged(prevStatus); } /** @internal */ updateInfo(info) { super.updateInfo(info); const prevMetadataMuted = this.metadataMuted; this.metadataMuted = info.muted; if (this.track) { this.track.setMuted(info.muted); } else if (prevMetadataMuted !== info.muted) { this.emit(info.muted ? TrackEvent.Muted : TrackEvent.Unmuted); } } emitSubscriptionUpdateIfChanged(previousStatus) { const currentStatus = this.subscriptionStatus; if (previousStatus === currentStatus) { return; } this.emit(TrackEvent.SubscriptionStatusChanged, currentStatus, previousStatus); } emitPermissionUpdateIfChanged(previousPermissionStatus) { const currentPermissionStatus = this.permissionStatus; if (currentPermissionStatus !== previousPermissionStatus) { this.emit(TrackEvent.SubscriptionPermissionChanged, this.permissionStatus, previousPermissionStatus); } } isManualOperationAllowed() { if (this.isAdaptiveStream) { livekitLogger.warn('adaptive stream is enabled, cannot change track settings', { trackSid: this.trackSid }); return false; } if (!this.isDesired) { livekitLogger.warn('cannot update track settings when not subscribed', { trackSid: this.trackSid }); return false; } return true; } get isAdaptiveStream() { return this.track instanceof RemoteVideoTrack && this.track.isAdaptiveStream; } /* @internal */ emitTrackUpdate() { const settings = UpdateTrackSettings.fromPartial({ trackSids: [this.trackSid], disabled: this.disabled, fps: this.fps }); if (this.videoDimensions) { settings.width = this.videoDimensions.width; settings.height = this.videoDimensions.height; } else if (this.currentVideoQuality !== undefined) { settings.quality = this.currentVideoQuality; } else { // defaults to high quality settings.quality = VideoQuality.HIGH; } this.emit(TrackEvent.UpdateSettings, settings); } } class RemoteParticipant extends Participant { /** @internal */ static fromParticipantInfo(signalClient, pi) { return new RemoteParticipant(signalClient, pi.sid, pi.identity, pi.name, pi.metadata); } /** @internal */ constructor(signalClient, sid, identity, name, metadata) { super(sid, identity || '', name, metadata); this.signalClient = signalClient; this.tracks = new Map(); this.audioTracks = new Map(); this.videoTracks = new Map(); } addTrackPublication(publication) { super.addTrackPublication(publication); // register action events publication.on(TrackEvent.UpdateSettings, settings => { livekitLogger.debug('send update settings', settings); this.signalClient.sendUpdateTrackSettings(settings); }); publication.on(TrackEvent.UpdateSubscription, sub => { sub.participantTracks.forEach(pt => { pt.participantSid = this.sid; }); this.signalClient.sendUpdateSubscription(sub); }); publication.on(TrackEvent.SubscriptionPermissionChanged, status => { this.emit(ParticipantEvent.TrackSubscriptionPermissionChanged, publication, status); }); publication.on(TrackEvent.SubscriptionStatusChanged, status => { this.emit(ParticipantEvent.TrackSubscriptionStatusChanged, publication, status); }); publication.on(TrackEvent.Subscribed, track => { this.emit(ParticipantEvent.TrackSubscribed, track, publication); }); publication.on(TrackEvent.Unsubscribed, previousTrack => { this.emit(ParticipantEvent.TrackUnsubscribed, previousTrack, publication); }); } getTrack(source) { const track = super.getTrack(source); if (track) { return track; } } getTrackByName(name) { const track = super.getTrackByName(name); if (track) { return track; } } /** * sets the volume on the participant's microphone track * if no track exists the volume will be applied when the microphone track is added */ setVolume(volume) { this.volume = volume; const audioPublication = this.getTrack(Track.Source.Microphone); if (audioPublication && audioPublication.track) { audioPublication.track.setVolume(volume); } } /** * gets the volume on the participant's microphone track */ getVolume() { const audioPublication = this.getTrack(Track.Source.Microphone); if (audioPublication && audioPublication.track) { return audioPublication.track.getVolume(); } return this.volume; } /** @internal */ addSubscribedMediaTrack(mediaTrack, sid, mediaStream, receiver, adaptiveStreamSettings, triesLeft) { // find the track publication // it's possible for the media track to arrive before participant info let publication = this.getTrackPublication(sid); // it's also possible that the browser didn't honor our original track id // FireFox would use its own local uuid instead of server track id if (!publication) { if (!sid.startsWith('TR')) { // find the first track that matches type this.tracks.forEach(p => { if (!publication && mediaTrack.kind === p.kind.toString()) { publication = p; } }); } } // when we couldn't locate the track, it's possible that the metadata hasn't // yet arrived. Wait a bit longer for it to arrive, or fire an error if (!publication) { if (triesLeft === 0) { livekitLogger.error('could not find published track', { participant: this.sid, trackSid: sid }); this.emit(ParticipantEvent.TrackSubscriptionFailed, sid); return; } if (triesLeft === undefined) triesLeft = 20; setTimeout(() => { this.addSubscribedMediaTrack(mediaTrack, sid, mediaStream, receiver, adaptiveStreamSettings, triesLeft - 1); }, 150); return; } if (mediaTrack.readyState === 'ended') { livekitLogger.error('unable to subscribe because MediaStreamTrack is ended. Do not call MediaStreamTrack.stop()', { participant: this.sid, trackSid: sid }); this.emit(ParticipantEvent.TrackSubscriptionFailed, sid); return; } const isVideo = mediaTrack.kind === 'video'; let track; if (isVideo) { track = new RemoteVideoTrack(mediaTrack, sid, receiver, adaptiveStreamSettings); } else { track = new RemoteAudioTrack(mediaTrack, sid, receiver, this.audioContext, this.audioOutput); } // set track info track.source = publication.source; // keep publication's muted status track.isMuted = publication.isMuted; track.setMediaStream(mediaStream); track.start(); publication.setTrack(track); // set participant volume on new microphone tracks if (this.volume !== undefined && track instanceof RemoteAudioTrack && track.source === Track.Source.Microphone) { track.setVolume(this.volume); } return publication; } /** @internal */ get hasMetadata() { return !!this.participantInfo; } getTrackPublication(sid) { return this.tracks.get(sid); } /** @internal */ updateInfo(info) { super.updateInfo(info); // we are getting a list of all available tracks, reconcile in here // and send out events for changes // reconcile track publications, publish events only if metadata is already there // i.e. changes since the local participant has joined const validTracks = new Map(); const newTracks = new Map(); info.tracks.forEach(ti => { var _a; let publication = this.getTrackPublication(ti.sid); if (!publication) { // new publication const kind = Track.kindFromProto(ti.type); if (!kind) { return; } publication = new RemoteTrackPublication(kind, ti, (_a = this.signalClient.connectOptions) === null || _a === void 0 ? void 0 : _a.autoSubscribe); publication.updateInfo(ti); newTracks.set(ti.sid, publication); const existingTrackOfSource = Array.from(this.tracks.values()).find(publishedTrack => publishedTrack.source === (publication === null || publication === void 0 ? void 0 : publication.source)); if (existingTrackOfSource && publication.source !== Track.Source.Unknown) { livekitLogger.debug("received a second track publication for ".concat(this.identity, " with the same source: ").concat(publication.source), { oldTrack: existingTrackOfSource, newTrack: publication, participant: this, participantInfo: info }); } this.addTrackPublication(publication); } else { publication.updateInfo(ti); } validTracks.set(ti.sid, publication); }); // detect removed tracks this.tracks.forEach(publication => { if (!validTracks.has(publication.trackSid)) { livekitLogger.trace('detected removed track on remote participant, unpublishing', { publication, participantSid: this.sid }); this.unpublishTrack(publication.trackSid, true); } }); // always emit events for new publications, Room will not forward them unless it's ready newTracks.forEach(publication => { this.emit(ParticipantEvent.TrackPublished, publication); }); } /** @internal */ unpublishTrack(sid, sendUnpublish) { const publication = this.tracks.get(sid); if (!publication) { return; } this.tracks.delete(sid); // remove from the right type map switch (publication.kind) { case Track.Kind.Audio: this.audioTracks.delete(sid); break; case Track.Kind.Video: this.videoTracks.delete(sid); break; } // also send unsubscribe, if track is actively subscribed const { track } = publication; if (track) { track.stop(); publication.setTrack(undefined); } if (sendUnpublish) { this.emit(ParticipantEvent.TrackUnpublished, publication); } } /** * @internal */ setAudioContext(ctx) { this.audioContext = ctx; this.audioTracks.forEach(track => track.track instanceof RemoteAudioTrack && track.track.setAudioContext(ctx)); } /** * @internal */ async setAudioOutput(output) { this.audioOutput = output; const promises = []; this.audioTracks.forEach(pub => { var _a; if (pub.track instanceof RemoteAudioTrack) { promises.push(pub.track.setSinkId((_a = output.deviceId) !== null && _a !== void 0 ? _a : 'default')); } }); await Promise.all(promises); } /** @internal */ emit(event) { for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { args[_key - 1] = arguments[_key]; } livekitLogger.trace('participant event', { participant: this.sid, event, args }); return super.emit(event, ...args); } } class LocalParticipant extends Participant { /** @internal */ constructor(sid, identity, engine, options) { super(sid, identity); this.pendingPublishing = new Set(); this.pendingPublishPromises = new Map(); this.participantTrackPermissions = []; this.allParticipantsAllowedToSubscribe = true; this.handleReconnecting = () => { if (!this.reconnectFuture) { this.reconnectFuture = new Future(); } }; this.handleReconnected = () => { var _a, _b; (_b = (_a = this.reconnectFuture) === null || _a === void 0 ? void 0 : _a.resolve) === null || _b === void 0 ? void 0 : _b.call(_a); this.reconnectFuture = undefined; this.updateTrackSubscriptionPermissions(); }; this.handleDisconnected = () => { var _a, _b; (_b = (_a = this.reconnectFuture) === null || _a === void 0 ? void 0 : _a.reject) === null || _b === void 0 ? void 0 : _b.call(_a, 'Got disconnected during publishing attempt'); this.reconnectFuture = undefined; }; this.updateTrackSubscriptionPermissions = () => { livekitLogger.debug('updating track subscription permissions', { allParticipantsAllowed: this.allParticipantsAllowedToSubscribe, participantTrackPermissions: this.participantTrackPermissions }); this.engine.client.sendUpdateSubscriptionPermissions(this.allParticipantsAllowedToSubscribe, this.participantTrackPermissions.map(p => trackPermissionToProto(p))); }; /** @internal */ this.onTrackUnmuted = track => { this.onTrackMuted(track, track.isUpstreamPaused); }; // when the local track changes in mute status, we'll notify server as such /** @internal */ this.onTrackMuted = (track, muted) => { if (muted === undefined) { muted = true; } if (!track.sid) { livekitLogger.error('could not update mute status for unpublished track', track); return; } this.engine.updateMuteStatus(track.sid, muted); }; this.onTrackUpstreamPaused = track => { livekitLogger.debug('upstream paused'); this.onTrackMuted(track, true); }; this.onTrackUpstreamResumed = track => { livekitLogger.debug('upstream resumed'); this.onTrackMuted(track, track.isMuted); }; this.handleSubscribedQualityUpdate = async update => { var _a, _b; if (!((_a = this.roomOptions) === null || _a === void 0 ? void 0 : _a.dynacast)) { return; } const pub = this.videoTracks.get(update.trackSid); if (!pub) { livekitLogger.warn('received subscribed quality update for unknown track', { method: 'handleSubscribedQualityUpdate', sid: update.trackSid }); return; } if (update.subscribedCodecs.length > 0) { if (!pub.videoTrack) { return; } const newCodecs = await pub.videoTrack.setPublishingCodecs(update.subscribedCodecs); var _iteratorAbruptCompletion = false; var _didIteratorError = false; var _iteratorError; try { for (var _iterator = _asyncIterator(newCodecs), _step; _iteratorAbruptCompletion = !(_step = await _iterator.next()).done; _iteratorAbruptCompletion = false) { const codec = _step.value; { if (isBackupCodec(codec)) { livekitLogger.debug("publish ".concat(codec, " for ").concat(pub.videoTrack.sid)); await this.publishAdditionalCodecForTrack(pub.videoTrack, codec, pub.options); } } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (_iteratorAbruptCompletion && _iterator.return != null) { await _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } } else if (update.subscribedQualities.length > 0) { await ((_b = pub.videoTrack) === null || _b === void 0 ? void 0 : _b.setPublishingLayers(update.subscribedQualities)); } }; this.handleLocalTrackUnpublished = unpublished => { const track = this.tracks.get(unpublished.trackSid); if (!track) { livekitLogger.warn('received unpublished event for unknown track', { method: 'handleLocalTrackUnpublished', trackSid: unpublished.trackSid }); return; } this.unpublishTrack(track.track); }; this.handleTrackEnded = async track => { if (track.source === Track.Source.ScreenShare || track.source === Track.Source.ScreenShareAudio) { livekitLogger.debug('unpublishing local track due to TrackEnded', { track: track.sid }); this.unpublishTrack(track); } else if (track.isUserProvided) { await track.mute(); } else if (track instanceof LocalAudioTrack || track instanceof LocalVideoTrack) { try { if (isWeb()) { try { const currentPermissions = await (navigator === null || navigator === void 0 ? void 0 : navigator.permissions.query({ // the permission query for camera and microphone currently not supported in Safari and Firefox // @ts-ignore name: track.source === Track.Source.Camera ? 'camera' : 'microphone' })); if (currentPermissions && currentPermissions.state === 'denied') { livekitLogger.warn("user has revoked access to ".concat(track.source)); // detect granted change after permissions were denied to try and resume then currentPermissions.onchange = () => { if (currentPermissions.state !== 'denied') { if (!track.isMuted) { track.restartTrack(); } currentPermissions.onchange = null; } }; throw new Error('GetUserMedia Permission denied'); } } catch (e) { // permissions query fails for firefox, we continue and try to restart the track } } if (!track.isMuted) { livekitLogger.debug('track ended, attempting to use a different device'); await track.restartTrack(); } } catch (e) { livekitLogger.warn("could not restart track, muting instead"); await track.mute(); } } }; this.audioTracks = new Map(); this.videoTracks = new Map(); this.tracks = new Map(); this.engine = engine; this.roomOptions = options; this.setupEngine(engine); } get lastCameraError() { return this.cameraError; } get lastMicrophoneError() { return this.microphoneError; } getTrack(source) { const track = super.getTrack(source); if (track) { return track; } } getTrackByName(name) { const track = super.getTrackByName(name); if (track) { return track; } } /** * @internal */ setupEngine(engine) { this.engine = engine; this.engine.client.onRemoteMuteChanged = (trackSid, muted) => { const pub = this.tracks.get(trackSid); if (!pub || !pub.track) { return; } if (muted) { pub.mute(); } else { pub.unmute(); } }; this.engine.client.onSubscribedQualityUpdate = this.handleSubscribedQualityUpdate; this.engine.client.onLocalTrackUnpublished = this.handleLocalTrackUnpublished; this.engine.on(EngineEvent.Connected, this.handleReconnected).on(EngineEvent.Restarted, this.handleReconnected).on(EngineEvent.Resumed, this.handleReconnected).on(EngineEvent.Restarting, this.handleReconnecting).on(EngineEvent.Resuming, this.handleReconnecting).on(EngineEvent.Disconnected, this.handleDisconnected); } /** * Enable or disable a participant's camera track. * * If a track has already published, it'll mute or unmute the track. * Resolves with a `LocalTrackPublication` instance if successful and `undefined` otherwise */ setCameraEnabled(enabled, options, publishOptions) { return this.setTrackEnabled(Track.Source.Camera, enabled, options, publishOptions); } /** * Enable or disable a participant's microphone track. * * If a track has already published, it'll mute or unmute the track. * Resolves with a `LocalTrackPublication` instance if successful and `undefined` otherwise */ setMicrophoneEnabled(enabled, options, publishOptions) { return this.setTrackEnabled(Track.Source.Microphone, enabled, options, publishOptions); } /** * Start or stop sharing a participant's screen * Resolves with a `LocalTrackPublication` instance if successful and `undefined` otherwise */ setScreenShareEnabled(enabled, options, publishOptions) { return this.setTrackEnabled(Track.Source.ScreenShare, enabled, options, publishOptions); } async setTrackEnabled(source, enabled, options, publishOptions) { var _a, _b; livekitLogger.debug('setTrackEnabled', { source, enabled }); let track = this.getTrack(source); if (enabled) { if (track) { await track.unmute(); } else { let localTracks; if (this.pendingPublishing.has(source)) { livekitLogger.info('skipping duplicate published source', { source }); // no-op it's already been requested return; } this.pendingPublishing.add(source); try { switch (source) { case Track.Source.Camera: localTracks = await this.createTracks({ video: (_a = options) !== null && _a !== void 0 ? _a : true }); break; case Track.Source.Microphone: localTracks = await this.createTracks({ audio: (_b = options) !== null && _b !== void 0 ? _b : true }); break; case Track.Source.ScreenShare: localTracks = await this.createScreenTracks(_objectSpread2({}, options)); break; default: throw new TrackInvalidError(source); } const publishPromises = []; for (const localTrack of localTracks) { livekitLogger.info('publishing track', { localTrack }); publishPromises.push(this.publishTrack(localTrack, publishOptions)); } const publishedTracks = await Promise.all(publishPromises); // for screen share publications including audio, this will only return the screen share publication, not the screen share audio one // revisit if we want to return an array of tracks instead for v2 [track] = publishedTracks; } catch (e) { if (e instanceof Error && !(e instanceof TrackInvalidError)) { this.emit(ParticipantEvent.MediaDevicesError, e); } throw e; } finally { this.pendingPublishing.delete(source); } } } else if (track && track.track) { // screenshare cannot be muted, unpublish instead if (source === Track.Source.ScreenShare) { track = await this.unpublishTrack(track.track); const screenAudioTrack = this.getTrack(Track.Source.ScreenShareAudio); if (screenAudioTrack && screenAudioTrack.track) { this.unpublishTrack(screenAudioTrack.track); } } else { await track.mute(); } } return track; } /** * Publish both camera and microphone at the same time. This is useful for * displaying a single Permission Dialog box to the end user. */ async enableCameraAndMicrophone() { if (this.pendingPublishing.has(Track.Source.Camera) || this.pendingPublishing.has(Track.Source.Microphone)) { // no-op it's already been requested return; } this.pendingPublishing.add(Track.Source.Camera); this.pendingPublishing.add(Track.Source.Microphone); try { const tracks = await this.createTracks({ audio: true, video: true }); await Promise.all(tracks.map(track => this.publishTrack(track))); } finally { this.pendingPublishing.delete(Track.Source.Camera); this.pendingPublishing.delete(Track.Source.Microphone); } } /** * Create local camera and/or microphone tracks * @param options * @returns */ async createTracks(options) { var _a, _b; const opts = mergeDefaultOptions(options, (_a = this.roomOptions) === null || _a === void 0 ? void 0 : _a.audioCaptureDefaults, (_b = this.roomOptions) === null || _b === void 0 ? void 0 : _b.videoCaptureDefaults); const constraints = constraintsForOptions(opts); let stream; try { stream = await navigator.mediaDevices.getUserMedia(constraints); } catch (err) { if (err instanceof Error) { if (constraints.audio) { this.microphoneError = err; } if (constraints.video) { this.cameraError = err; } } throw err; } if (constraints.audio) { this.microphoneError = undefined; } if (constraints.video) { this.cameraError = undefined; } return stream.getTracks().map(mediaStreamTrack => { const isAudio = mediaStreamTrack.kind === 'audio'; isAudio ? options.audio : options.video; let trackConstraints; const conOrBool = isAudio ? constraints.audio : constraints.video; if (typeof conOrBool !== 'boolean') { trackConstraints = conOrBool; } const track = mediaTrackToLocalTrack(mediaStreamTrack, trackConstraints); if (track.kind === Track.Kind.Video) { track.source = Track.Source.Camera; } else if (track.kind === Track.Kind.Audio) { track.source = Track.Source.Microphone; } track.mediaStream = stream; return track; }); } /** * Creates a screen capture tracks with getDisplayMedia(). * A LocalVideoTrack is always created and returned. * If { audio: true }, and the browser supports audio capture, a LocalAudioTrack is also created. */ async createScreenTracks(options) { var _a; if (options === undefined) { options = {}; } if (options.resolution === undefined) { options.resolution = ScreenSharePresets.h1080fps15.resolution; } let videoConstraints = true; if (options.resolution) { if (isSafari()) { videoConstraints = { width: { max: options.resolution.width }, height: { max: options.resolution.height }, frameRate: options.resolution.frameRate }; } else { videoConstraints = { width: { ideal: options.resolution.width }, height: { ideal: options.resolution.height }, frameRate: options.resolution.frameRate }; } } if (navigator.mediaDevices.getDisplayMedia === undefined) { throw new DeviceUnsupportedError('getDisplayMedia not supported'); } const stream = await navigator.mediaDevices.getDisplayMedia({ audio: (_a = options.audio) !== null && _a !== void 0 ? _a : false, video: videoConstraints, // @ts-expect-error support for experimental display media features controller: options.controller, selfBrowserSurface: options.selfBrowserSurface, surfaceSwitching: options.surfaceSwitching, systemAudio: options.systemAudio }); const tracks = stream.getVideoTracks(); if (tracks.length === 0) { throw new TrackInvalidError('no video track found'); } const screenVideo = new LocalVideoTrack(tracks[0], undefined, false); screenVideo.source = Track.Source.ScreenShare; const localTracks = [screenVideo]; if (stream.getAudioTracks().length > 0) { const screenAudio = new LocalAudioTrack(stream.getAudioTracks()[0], undefined, false); screenAudio.source = Track.Source.ScreenShareAudio; localTracks.push(screenAudio); } return localTracks; } /** * Publish a new track to the room * @param track * @param options */ async publishTrack(track, options) { var _a, _b, _c; await ((_a = this.reconnectFuture) === null || _a === void 0 ? void 0 : _a.promise); if (track instanceof LocalTrack && this.pendingPublishPromises.has(track)) { await this.pendingPublishPromises.get(track); } // convert raw media track into audio or video track if (track instanceof MediaStreamTrack) { switch (track.kind) { case 'audio': track = new LocalAudioTrack(track, undefined, true); break; case 'video': track = new LocalVideoTrack(track, undefined, true); break; default: throw new TrackInvalidError("unsupported MediaStreamTrack kind ".concat(track.kind)); } } // is it already published? if so skip let existingPublication; this.tracks.forEach(publication => { if (!publication.track) { return; } if (publication.track === track) { existingPublication = publication; } }); if (existingPublication) { livekitLogger.warn('track has already been published, skipping'); return existingPublication; } const isStereo = (options === null || options === void 0 ? void 0 : options.forceStereo) || 'channelCount' in track.mediaStreamTrack.getSettings() && // @ts-ignore `channelCount` on getSettings() is currently only available for Safari, but is generally the best way to determine a stereo track https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackSettings/channelCount track.mediaStreamTrack.getSettings().channelCount === 2 || track.mediaStreamTrack.getConstraints().channelCount === 2; // disable dtx for stereo track if not enabled explicitly if (isStereo) { if (!options) { options = {}; } if (options.dtx === undefined) { livekitLogger.info("Opus DTX will be disabled for stereo tracks by default. Enable them explicitly to make it work."); } if (options.red === undefined) { livekitLogger.info("Opus RED will be disabled for stereo tracks by default. Enable them explicitly to make it work."); } (_b = options.dtx) !== null && _b !== void 0 ? _b : options.dtx = false; (_c = options.red) !== null && _c !== void 0 ? _c : options.red = false; } const opts = _objectSpread2(_objectSpread2({}, this.roomOptions.publishDefaults), options); if (opts.source) { track.source = opts.source; } const publishPromise = this.publish(track, opts, options, isStereo); this.pendingPublishPromises.set(track, publishPromise); try { const publication = await publishPromise; return publication; } catch (e) { throw e; } finally { this.pendingPublishPromises.delete(track); } } async publish(track, opts, options, isStereo) { var _a, _b, _c, _d; const existingTrackOfSource = Array.from(this.tracks.values()).find(publishedTrack => track instanceof LocalTrack && publishedTrack.source === track.source); if (existingTrackOfSource && track.source !== Track.Source.Unknown) { try { // throw an Error in order to capture the stack trace throw Error("publishing a second track with the same source: ".concat(track.source)); } catch (e) { if (e instanceof Error) { livekitLogger.warn(e.message, { oldTrack: existingTrackOfSource, newTrack: track, trace: e.stack }); } } } if (opts.stopMicTrackOnMute && track instanceof LocalAudioTrack) { track.stopOnMute = true; } if (track.source === Track.Source.ScreenShare && isFireFox()) { // Firefox does not work well with simulcasted screen share // we frequently get no data on layer 0 when enabled opts.simulcast = false; } // require full AV1 SVC support prior to using it if (opts.videoCodec === 'av1' && !supportsAV1()) { opts.videoCodec = undefined; } // handle track actions track.on(TrackEvent.Muted, this.onTrackMuted); track.on(TrackEvent.Unmuted, this.onTrackUnmuted); track.on(TrackEvent.Ended, this.handleTrackEnded); track.on(TrackEvent.UpstreamPaused, this.onTrackUpstreamPaused); track.on(TrackEvent.UpstreamResumed, this.onTrackUpstreamResumed); // create track publication from track const req = AddTrackRequest.fromPartial({ // get local track id for use during publishing cid: track.mediaStreamTrack.id, name: options === null || options === void 0 ? void 0 : options.name, type: Track.kindToProto(track.kind), muted: track.isMuted, source: Track.sourceToProto(track.source), disableDtx: !((_a = opts.dtx) !== null && _a !== void 0 ? _a : true), stereo: isStereo, disableRed: !((_b = opts.red) !== null && _b !== void 0 ? _b : true) }); // compute encodings and layers for video let encodings; let simEncodings; if (track.kind === Track.Kind.Video) { let dims = { width: 0, height: 0 }; try { dims = await track.waitForDimensions(); } catch (e) { // log failure livekitLogger.error('could not determine track dimensions'); } // width and height should be defined for video req.width = dims.width; req.height = dims.height; // for svc codecs, disable simulcast and use vp8 for backup codec if (track instanceof LocalVideoTrack) { if ((opts === null || opts === void 0 ? void 0 : opts.videoCodec) === 'av1') { // set scalabilityMode to 'L3T3' by default opts.scalabilityMode = (_c = opts.scalabilityMode) !== null && _c !== void 0 ? _c : 'L3T3'; } // set up backup if (opts.videoCodec && opts.backupCodec && opts.videoCodec !== opts.backupCodec.codec) { const simOpts = _objectSpread2({}, opts); simOpts.simulcast = true; simEncodings = computeTrackBackupEncodings(track, opts.backupCodec.codec, simOpts); req.simulcastCodecs = [{ codec: opts.videoCodec, cid: track.mediaStreamTrack.id, enableSimulcastLayers: true }, { codec: opts.backupCodec.codec, cid: '', enableSimulcastLayers: true }]; } } encodings = computeVideoEncodings(track.source === Track.Source.ScreenShare, dims.width, dims.height, opts); req.layers = videoLayersFromEncodings(req.width, req.height, simEncodings !== null && simEncodings !== void 0 ? simEncodings : encodings); } else if (track.kind === Track.Kind.Audio && opts.audioBitrate) { encodings = [{ maxBitrate: opts.audioBitrate }]; } if (!this.engine || this.engine.isClosed) { throw new UnexpectedConnectionState('cannot publish track when not connected'); } const ti = await this.engine.addTrack(req); const publication = new LocalTrackPublication(track.kind, ti, track); // save options for when it needs to be republished again publication.options = opts; track.sid = ti.sid; if (!this.engine.publisher) { throw new UnexpectedConnectionState('publisher is closed'); } livekitLogger.debug("publishing ".concat(track.kind, " with encodings"), { encodings, trackInfo: ti }); // store RTPSender track.sender = await this.engine.createSender(track, opts, encodings); if (track.codec === 'av1' && encodings && ((_d = encodings[0]) === null || _d === void 0 ? void 0 : _d.maxBitrate)) { this.engine.publisher.setTrackCodecBitrate(req.cid, track.codec, encodings[0].maxBitrate / 1000); } this.engine.negotiate(); if (track instanceof LocalVideoTrack) { track.startMonitor(this.engine.client); } else if (track instanceof LocalAudioTrack) { track.startMonitor(); } this.addTrackPublication(publication); // send event for publication this.emit(ParticipantEvent.LocalTrackPublished, publication); return publication; } get isLocal() { return true; } /** @internal * publish additional codec to existing track */ async publishAdditionalCodecForTrack(track, videoCodec, options) { var _a; // is it not published? if so skip let existingPublication; this.tracks.forEach(publication => { if (!publication.track) { return; } if (publication.track === track) { existingPublication = publication; } }); if (!existingPublication) { throw new TrackInvalidError('track is not published'); } if (!(track instanceof LocalVideoTrack)) { throw new TrackInvalidError('track is not a video track'); } const opts = _objectSpread2(_objectSpread2({}, (_a = this.roomOptions) === null || _a === void 0 ? void 0 : _a.publishDefaults), options); const encodings = computeTrackBackupEncodings(track, videoCodec, opts); if (!encodings) { livekitLogger.info("backup codec has been disabled, ignoring request to add additional codec for track"); return; } const simulcastTrack = track.addSimulcastTrack(videoCodec, encodings); const req = AddTrackRequest.fromPartial({ cid: simulcastTrack.mediaStreamTrack.id, type: Track.kindToProto(track.kind), muted: track.isMuted, source: Track.sourceToProto(track.source), sid: track.sid, simulcastCodecs: [{ codec: opts.videoCodec, cid: simulcastTrack.mediaStreamTrack.id, enableSimulcastLayers: opts.simulcast }] }); req.layers = videoLayersFromEncodings(req.width, req.height, encodings); if (!this.engine || this.engine.isClosed) { throw new UnexpectedConnectionState('cannot publish track when not connected'); } const ti = await this.engine.addTrack(req); await this.engine.createSimulcastSender(track, simulcastTrack, opts, encodings); this.engine.negotiate(); livekitLogger.debug("published ".concat(videoCodec, " for track ").concat(track.sid), { encodings, trackInfo: ti }); } async unpublishTrack(track, stopOnUnpublish) { var _a, _b; // look through all published tracks to find the right ones const publication = this.getPublicationForTrack(track); livekitLogger.debug('unpublishing track', { track, method: 'unpublishTrack' }); if (!publication || !publication.track) { livekitLogger.warn('track was not unpublished because no publication was found', { track, method: 'unpublishTrack' }); return undefined; } track = publication.track; track.off(TrackEvent.Muted, this.onTrackMuted); track.off(TrackEvent.Unmuted, this.onTrackUnmuted); track.off(TrackEvent.Ended, this.handleTrackEnded); track.off(TrackEvent.UpstreamPaused, this.onTrackUpstreamPaused); track.off(TrackEvent.UpstreamResumed, this.onTrackUpstreamResumed); if (stopOnUnpublish === undefined) { stopOnUnpublish = (_b = (_a = this.roomOptions) === null || _a === void 0 ? void 0 : _a.stopLocalTrackOnUnpublish) !== null && _b !== void 0 ? _b : true; } if (stopOnUnpublish) { track.stop(); } let negotiationNeeded = false; const trackSender = track.sender; track.sender = undefined; if (this.engine.publisher && this.engine.publisher.pc.connectionState !== 'closed' && trackSender) { try { if (this.engine.removeTrack(trackSender)) { negotiationNeeded = true; } if (track instanceof LocalVideoTrack) { for (const [, trackInfo] of track.simulcastCodecs) { if (trackInfo.sender) { if (this.engine.removeTrack(trackInfo.sender)) { negotiationNeeded = true; } trackInfo.sender = undefined; } } track.simulcastCodecs.clear(); } } catch (e) { livekitLogger.warn('failed to unpublish track', { error: e, method: 'unpublishTrack' }); } } // remove from our maps this.tracks.delete(publication.trackSid); switch (publication.kind) { case Track.Kind.Audio: this.audioTracks.delete(publication.trackSid); break; case Track.Kind.Video: this.videoTracks.delete(publication.trackSid); break; } this.emit(ParticipantEvent.LocalTrackUnpublished, publication); publication.setTrack(undefined); if (negotiationNeeded) { await this.engine.negotiate(); } return publication; } async unpublishTracks(tracks) { const results = await Promise.all(tracks.map(track => this.unpublishTrack(track))); return results.filter(track => track instanceof LocalTrackPublication); } async republishAllTracks(options) { const localPubs = []; this.tracks.forEach(pub => { if (pub.track) { if (options) { pub.options = _objectSpread2(_objectSpread2({}, pub.options), options); } localPubs.push(pub); } }); await Promise.all(localPubs.map(async pub => { const track = pub.track; await this.unpublishTrack(track, false); await this.publishTrack(track, pub.options); })); } async publishData(data, kind) { let publishOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; const destination = Array.isArray(publishOptions) ? publishOptions : publishOptions === null || publishOptions === void 0 ? void 0 : publishOptions.destination; const destinationSids = []; const topic = !Array.isArray(publishOptions) ? publishOptions.topic : undefined; if (destination !== undefined) { destination.forEach(val => { if (val instanceof RemoteParticipant) { destinationSids.push(val.sid); } else { destinationSids.push(val); } }); } const packet = { kind, value: { $case: 'user', user: { participantSid: this.sid, payload: data, destinationSids: destinationSids, topic } } }; await this.engine.sendDataPacket(packet, kind); } /** * Control who can subscribe to LocalParticipant's published tracks. * * By default, all participants can subscribe. This allows fine-grained control over * who is able to subscribe at a participant and track level. * * Note: if access is given at a track-level (i.e. both [allParticipantsAllowed] and * [ParticipantTrackPermission.allTracksAllowed] are false), any newer published tracks * will not grant permissions to any participants and will require a subsequent * permissions update to allow subscription. * * @param allParticipantsAllowed Allows all participants to subscribe all tracks. * Takes precedence over [[participantTrackPermissions]] if set to true. * By default this is set to true. * @param participantTrackPermissions Full list of individual permissions per * participant/track. Any omitted participants will not receive any permissions. */ setTrackSubscriptionPermissions(allParticipantsAllowed) { let participantTrackPermissions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; this.participantTrackPermissions = participantTrackPermissions; this.allParticipantsAllowedToSubscribe = allParticipantsAllowed; if (this.engine.client.isConnected) { this.updateTrackSubscriptionPermissions(); } } /** @internal */ updateInfo(info) { if (info.sid !== this.sid) { // drop updates that specify a wrong sid. // the sid for local participant is only explicitly set on join and full reconnect return; } super.updateInfo(info); // reconcile track mute status. // if server's track mute status doesn't match actual, we'll have to update // the server's copy info.tracks.forEach(ti => { var _a, _b; const pub = this.tracks.get(ti.sid); if (pub) { const mutedOnServer = pub.isMuted || ((_b = (_a = pub.track) === null || _a === void 0 ? void 0 : _a.isUpstreamPaused) !== null && _b !== void 0 ? _b : false); if (mutedOnServer !== ti.muted) { livekitLogger.debug('updating server mute state after reconcile', { sid: ti.sid, muted: mutedOnServer }); this.engine.client.sendMuteTrack(ti.sid, mutedOnServer); } } }); } getPublicationForTrack(track) { let publication; this.tracks.forEach(pub => { const localTrack = pub.track; if (!localTrack) { return; } // this looks overly complicated due to this object tree if (track instanceof MediaStreamTrack) { if (localTrack instanceof LocalAudioTrack || localTrack instanceof LocalVideoTrack) { if (localTrack.mediaStreamTrack === track) { publication = pub; } } } else if (track === localTrack) { publication = pub; } }); return publication; } /** @internal */ publishedTracksInfo() { const infos = []; this.tracks.forEach(track => { if (track.track !== undefined) { infos.push({ cid: track.track.mediaStreamID, track: track.trackInfo }); } }); return infos; } /** @internal */ dataChannelsInfo() { const infos = []; const getInfo = (dc, target) => { if ((dc === null || dc === void 0 ? void 0 : dc.id) !== undefined && dc.id !== null) { infos.push({ label: dc.label, id: dc.id, target }); } }; getInfo(this.engine.dataChannelForKind(DataPacket_Kind.LOSSY), SignalTarget.PUBLISHER); getInfo(this.engine.dataChannelForKind(DataPacket_Kind.RELIABLE), SignalTarget.PUBLISHER); getInfo(this.engine.dataChannelForKind(DataPacket_Kind.LOSSY, true), SignalTarget.SUBSCRIBER); getInfo(this.engine.dataChannelForKind(DataPacket_Kind.RELIABLE, true), SignalTarget.SUBSCRIBER); return infos; } } const passThroughQueueSignals = ['syncState', 'trickle', 'offer', 'answer', 'simulate', 'leave']; function canPassThroughQueue(req) { const canPass = passThroughQueueSignals.includes(req.$case); livekitLogger.trace('request allowed to bypass queue:', { canPass, req }); return canPass; } /** @internal */ class SignalClient { constructor() { let useJSON = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; /** signal rtt in milliseconds */ this.rtt = 0; this.isConnected = false; this.isReconnecting = false; this.useJSON = useJSON; this.requestQueue = new Queue(); this.queuedRequests = []; this.closingLock = new Mutex(); } async join(url, token, opts, abortSignal) { // during a full reconnect, we'd want to start the sequence even if currently // connected this.isConnected = false; this.options = opts; const res = await this.connect(url, token, opts, abortSignal); return res; } async reconnect(url, token, sid, reason) { if (!this.options) { livekitLogger.warn('attempted to reconnect without signal options being set, ignoring'); return; } this.isReconnecting = true; // clear ping interval and restart it once reconnected this.clearPingInterval(); const res = await this.connect(url, token, _objectSpread2(_objectSpread2({}, this.options), {}, { reconnect: true, sid, reconnectReason: reason })); return res; } connect(url, token, opts, abortSignal) { this.connectOptions = opts; if (url.startsWith('http')) { url = url.replace('http', 'ws'); } // strip trailing slash url = url.replace(/\/$/, ''); url += '/rtc'; const clientInfo = getClientInfo(); const params = createConnectionParams(token, clientInfo, opts); return new Promise(async (resolve, reject) => { const abortHandler = async () => { await this.close(); reject(new ConnectionError('room connection has been cancelled')); }; if (abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.aborted) { abortHandler(); } abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.addEventListener('abort', abortHandler); livekitLogger.debug("connecting to ".concat(url + params)); if (this.ws) { await this.close(); } this.ws = new WebSocket(url + params); this.ws.binaryType = 'arraybuffer'; this.ws.onerror = async ev => { if (!this.isConnected) { try { const resp = await fetch("http".concat(url.substring(2), "/validate").concat(params)); if (!resp.ok) { const msg = await resp.text(); reject(new ConnectionError(msg, 0 /* ConnectionErrorReason.NotAllowed */, resp.status)); } else { reject(new ConnectionError('Internal error', 2 /* ConnectionErrorReason.InternalError */, resp.status)); } } catch (e) { reject(new ConnectionError('server was not reachable', 1 /* ConnectionErrorReason.ServerUnreachable */)); } return; } // other errors, handle this.handleWSError(ev); }; this.ws.onmessage = async ev => { var _a, _b, _c, _d; // not considered connected until JoinResponse is received let resp; if (typeof ev.data === 'string') { const json = JSON.parse(ev.data); resp = SignalResponse.fromJSON(json); } else if (ev.data instanceof ArrayBuffer) { resp = SignalResponse.decode(new Uint8Array(ev.data)); } else { livekitLogger.error("could not decode websocket message: ".concat(typeof ev.data)); return; } if (!this.isConnected) { let shouldProcessMessage = false; // handle join message only if (((_a = resp.message) === null || _a === void 0 ? void 0 : _a.$case) === 'join') { this.isConnected = true; abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.removeEventListener('abort', abortHandler); this.pingTimeoutDuration = resp.message.join.pingTimeout; this.pingIntervalDuration = resp.message.join.pingInterval; if (this.pingTimeoutDuration && this.pingTimeoutDuration > 0) { livekitLogger.debug('ping config', { timeout: this.pingTimeoutDuration, interval: this.pingIntervalDuration }); this.startPingInterval(); } resolve(resp.message.join); } else if (opts.reconnect) { // in reconnecting, any message received means signal reconnected this.isConnected = true; abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.removeEventListener('abort', abortHandler); this.startPingInterval(); if (((_b = resp.message) === null || _b === void 0 ? void 0 : _b.$case) === 'reconnect') { resolve((_c = resp.message) === null || _c === void 0 ? void 0 : _c.reconnect); } else { resolve(); shouldProcessMessage = true; } } else if (!opts.reconnect) { // non-reconnect case, should receive join response first reject(new ConnectionError("did not receive join response, got ".concat((_d = resp.message) === null || _d === void 0 ? void 0 : _d.$case, " instead"))); } if (!shouldProcessMessage) { return; } } if (this.signalLatency) { await sleep(this.signalLatency); } this.handleSignalResponse(resp); }; this.ws.onclose = ev => { if (!this.isConnected) return; livekitLogger.debug("websocket connection closed: ".concat(ev.reason)); this.isConnected = false; if (this.onClose) { this.onClose(ev.reason); } this.ws = undefined; }; }); } async close() { const unlock = await this.closingLock.lock(); try { this.isConnected = false; if (this.ws) { this.ws.onclose = null; this.ws.onmessage = null; this.ws.onopen = null; // calling `ws.close()` only starts the closing handshake (CLOSING state), prefer to wait until state is actually CLOSED const closePromise = new Promise(resolve => { if (this.ws) { this.ws.onclose = resolve; } else { resolve(true); } }); this.ws.close(); // 250ms grace period for ws to close gracefully await Promise.race([closePromise, sleep(250)]); } this.ws = undefined; this.clearPingInterval(); } finally { unlock(); } } // initial offer after joining sendOffer(offer) { livekitLogger.debug('sending offer', offer); this.sendRequest({ $case: 'offer', offer: toProtoSessionDescription(offer) }); } // answer a server-initiated offer sendAnswer(answer) { livekitLogger.debug('sending answer'); this.sendRequest({ $case: 'answer', answer: toProtoSessionDescription(answer) }); } sendIceCandidate(candidate, target) { livekitLogger.trace('sending ice candidate', candidate); this.sendRequest({ $case: 'trickle', trickle: { candidateInit: JSON.stringify(candidate), target } }); } sendMuteTrack(trackSid, muted) { this.sendRequest({ $case: 'mute', mute: { sid: trackSid, muted } }); } sendAddTrack(req) { this.sendRequest({ $case: 'addTrack', addTrack: AddTrackRequest.fromPartial(req) }); } sendUpdateTrackSettings(settings) { this.sendRequest({ $case: 'trackSetting', trackSetting: settings }); } sendUpdateSubscription(sub) { this.sendRequest({ $case: 'subscription', subscription: sub }); } sendSyncState(sync) { this.sendRequest({ $case: 'syncState', syncState: sync }); } sendUpdateVideoLayers(trackSid, layers) { this.sendRequest({ $case: 'updateLayers', updateLayers: { trackSid, layers } }); } sendUpdateSubscriptionPermissions(allParticipants, trackPermissions) { this.sendRequest({ $case: 'subscriptionPermission', subscriptionPermission: { allParticipants, trackPermissions } }); } sendSimulateScenario(scenario) { this.sendRequest({ $case: 'simulate', simulate: scenario }); } sendPing() { /** send both of ping and pingReq for compatibility to old and new server */ this.sendRequest({ $case: 'ping', ping: Date.now() }); this.sendRequest({ $case: 'pingReq', pingReq: { timestamp: Date.now(), rtt: this.rtt } }); } async sendLeave() { await this.sendRequest({ $case: 'leave', leave: { canReconnect: false, reason: DisconnectReason.CLIENT_INITIATED } }); } async sendRequest(message) { let fromQueue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; // capture all requests while reconnecting and put them in a queue // unless the request originates from the queue, then don't enqueue again const canQueue = !fromQueue && !canPassThroughQueue(message); if (canQueue && this.isReconnecting) { this.queuedRequests.push(async () => { await this.sendRequest(message, true); }); return; } // make sure previously queued requests are being sent first if (!fromQueue) { await this.requestQueue.flush(); } if (this.signalLatency) { await sleep(this.signalLatency); } if (!this.ws || this.ws.readyState !== this.ws.OPEN) { livekitLogger.error("cannot send signal request before connected, type: ".concat(message === null || message === void 0 ? void 0 : message.$case)); return; } const req = { message }; try { if (this.useJSON) { this.ws.send(JSON.stringify(SignalRequest.toJSON(req))); } else { this.ws.send(SignalRequest.encode(req).finish()); } } catch (e) { livekitLogger.error('error sending signal message', { error: e }); } } handleSignalResponse(res) { var _a, _b; const msg = res.message; if (msg == undefined) { livekitLogger.debug('received unsupported message'); return; } if (msg.$case === 'answer') { const sd = fromProtoSessionDescription(msg.answer); if (this.onAnswer) { this.onAnswer(sd); } } else if (msg.$case === 'offer') { const sd = fromProtoSessionDescription(msg.offer); if (this.onOffer) { this.onOffer(sd); } } else if (msg.$case === 'trickle') { const candidate = JSON.parse(msg.trickle.candidateInit); if (this.onTrickle) { this.onTrickle(candidate, msg.trickle.target); } } else if (msg.$case === 'update') { if (this.onParticipantUpdate) { this.onParticipantUpdate((_a = msg.update.participants) !== null && _a !== void 0 ? _a : []); } } else if (msg.$case === 'trackPublished') { if (this.onLocalTrackPublished) { this.onLocalTrackPublished(msg.trackPublished); } } else if (msg.$case === 'speakersChanged') { if (this.onSpeakersChanged) { this.onSpeakersChanged((_b = msg.speakersChanged.speakers) !== null && _b !== void 0 ? _b : []); } } else if (msg.$case === 'leave') { if (this.onLeave) { this.onLeave(msg.leave); } } else if (msg.$case === 'mute') { if (this.onRemoteMuteChanged) { this.onRemoteMuteChanged(msg.mute.sid, msg.mute.muted); } } else if (msg.$case === 'roomUpdate') { if (this.onRoomUpdate && msg.roomUpdate.room) { this.onRoomUpdate(msg.roomUpdate.room); } } else if (msg.$case === 'connectionQuality') { if (this.onConnectionQuality) { this.onConnectionQuality(msg.connectionQuality); } } else if (msg.$case === 'streamStateUpdate') { if (this.onStreamStateUpdate) { this.onStreamStateUpdate(msg.streamStateUpdate); } } else if (msg.$case === 'subscribedQualityUpdate') { if (this.onSubscribedQualityUpdate) { this.onSubscribedQualityUpdate(msg.subscribedQualityUpdate); } } else if (msg.$case === 'subscriptionPermissionUpdate') { if (this.onSubscriptionPermissionUpdate) { this.onSubscriptionPermissionUpdate(msg.subscriptionPermissionUpdate); } } else if (msg.$case === 'refreshToken') { if (this.onTokenRefresh) { this.onTokenRefresh(msg.refreshToken); } } else if (msg.$case === 'trackUnpublished') { if (this.onLocalTrackUnpublished) { this.onLocalTrackUnpublished(msg.trackUnpublished); } } else if (msg.$case === 'pong') { this.resetPingTimeout(); } else if (msg.$case === 'pongResp') { this.rtt = Date.now() - msg.pongResp.lastPingTimestamp; this.resetPingTimeout(); } else { livekitLogger.debug('unsupported message', msg); } } setReconnected() { while (this.queuedRequests.length > 0) { const req = this.queuedRequests.shift(); if (req) { this.requestQueue.run(req); } } this.isReconnecting = false; } handleWSError(ev) { livekitLogger.error('websocket error', ev); } /** * Resets the ping timeout and starts a new timeout. * Call this after receiving a pong message */ resetPingTimeout() { this.clearPingTimeout(); if (!this.pingTimeoutDuration) { livekitLogger.warn('ping timeout duration not set'); return; } this.pingTimeout = CriticalTimers.setTimeout(() => { livekitLogger.warn("ping timeout triggered. last pong received at: ".concat(new Date(Date.now() - this.pingTimeoutDuration * 1000).toUTCString())); if (this.onClose) { this.onClose('ping timeout'); } }, this.pingTimeoutDuration * 1000); } /** * Clears ping timeout (does not start a new timeout) */ clearPingTimeout() { if (this.pingTimeout) { CriticalTimers.clearTimeout(this.pingTimeout); } } startPingInterval() { this.clearPingInterval(); this.resetPingTimeout(); if (!this.pingIntervalDuration) { livekitLogger.warn('ping interval duration not set'); return; } livekitLogger.debug('start ping interval'); this.pingInterval = CriticalTimers.setInterval(() => { this.sendPing(); }, this.pingIntervalDuration * 1000); } clearPingInterval() { livekitLogger.debug('clearing ping interval'); this.clearPingTimeout(); if (this.pingInterval) { CriticalTimers.clearInterval(this.pingInterval); } } } function fromProtoSessionDescription(sd) { const rsd = { type: 'offer', sdp: sd.sdp }; switch (sd.type) { case 'answer': case 'offer': case 'pranswer': case 'rollback': rsd.type = sd.type; break; } return rsd; } function toProtoSessionDescription(rsd) { const sd = { sdp: rsd.sdp, type: rsd.type }; return sd; } function createConnectionParams(token, info, opts) { var _a; const params = new URLSearchParams(); params.set('access_token', token); // opts if (opts.reconnect) { params.set('reconnect', '1'); if (opts.sid) { params.set('sid', opts.sid); } } params.set('auto_subscribe', opts.autoSubscribe ? '1' : '0'); // ClientInfo params.set('sdk', isReactNative() ? 'reactnative' : 'js'); params.set('version', info.version); params.set('protocol', info.protocol.toString()); if (info.deviceModel) { params.set('device_model', info.deviceModel); } if (info.os) { params.set('os', info.os); } if (info.osVersion) { params.set('os_version', info.osVersion); } if (info.browser) { params.set('browser', info.browser); } if (info.browserVersion) { params.set('browser_version', info.browserVersion); } if (opts.publishOnly !== undefined) { params.set('publish', opts.publishOnly); } if (opts.adaptiveStream) { params.set('adaptive_stream', '1'); } if (opts.reconnectReason) { params.set('reconnect_reason', opts.reconnectReason.toString()); } // @ts-ignore if ((_a = navigator.connection) === null || _a === void 0 ? void 0 : _a.type) { // @ts-ignore params.set('network', navigator.connection.type); } return "?".concat(params.toString()); } const publishDefaults = { audioBitrate: AudioPresets.music.maxBitrate, dtx: true, red: true, forceStereo: false, simulcast: true, screenShareEncoding: ScreenSharePresets.h1080fps15.encoding, stopMicTrackOnMute: false, videoCodec: 'vp8', backupCodec: { codec: 'vp8', encoding: VideoPresets.h540.encoding } }; const audioDefaults = { autoGainControl: true, echoCancellation: true, noiseSuppression: true }; const videoDefaults = { resolution: VideoPresets.h720.resolution }; const roomOptionDefaults = { adaptiveStream: false, dynacast: false, stopLocalTrackOnUnpublish: true, reconnectPolicy: new DefaultReconnectPolicy(), disconnectOnPageLeave: true, expWebAudioMix: false }; const roomConnectOptionDefaults = { autoSubscribe: true, maxRetries: 1, peerConnectionTimeout: 15000 }; var parser$1 = {}; var grammarExports = {}; var grammar$2 = { get exports(){ return grammarExports; }, set exports(v){ grammarExports = v; }, }; var grammar$1 = grammar$2.exports = { v: [{ name: 'version', reg: /^(\d*)$/ }], o: [{ // o=- 20518 0 IN IP4 203.0.113.1 // NB: sessionId will be a String in most cases because it is huge name: 'origin', reg: /^(\S*) (\d*) (\d*) (\S*) IP(\d) (\S*)/, names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'], format: '%s %s %d %s IP%d %s' }], // default parsing of these only (though some of these feel outdated) s: [{ name: 'name' }], i: [{ name: 'description' }], u: [{ name: 'uri' }], e: [{ name: 'email' }], p: [{ name: 'phone' }], z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly... r: [{ name: 'repeats' }], // TODO: this one can also be parsed properly // k: [{}], // outdated thing ignored t: [{ // t=0 0 name: 'timing', reg: /^(\d*) (\d*)/, names: ['start', 'stop'], format: '%d %d' }], c: [{ // c=IN IP4 10.47.197.26 name: 'connection', reg: /^IN IP(\d) (\S*)/, names: ['version', 'ip'], format: 'IN IP%d %s' }], b: [{ // b=AS:4000 push: 'bandwidth', reg: /^(TIAS|AS|CT|RR|RS):(\d*)/, names: ['type', 'limit'], format: '%s:%s' }], m: [{ // m=video 51744 RTP/AVP 126 97 98 34 31 // NB: special - pushes to session // TODO: rtp/fmtp should be filtered by the payloads found here? reg: /^(\w*) (\d*) ([\w/]*)(?: (.*))?/, names: ['type', 'port', 'protocol', 'payloads'], format: '%s %d %s %s' }], a: [{ // a=rtpmap:110 opus/48000/2 push: 'rtp', reg: /^rtpmap:(\d*) ([\w\-.]*)(?:\s*\/(\d*)(?:\s*\/(\S*))?)?/, names: ['payload', 'codec', 'rate', 'encoding'], format: function (o) { return o.encoding ? 'rtpmap:%d %s/%s/%s' : o.rate ? 'rtpmap:%d %s/%s' : 'rtpmap:%d %s'; } }, { // a=fmtp:108 profile-level-id=24;object=23;bitrate=64000 // a=fmtp:111 minptime=10; useinbandfec=1 push: 'fmtp', reg: /^fmtp:(\d*) ([\S| ]*)/, names: ['payload', 'config'], format: 'fmtp:%d %s' }, { // a=control:streamid=0 name: 'control', reg: /^control:(.*)/, format: 'control:%s' }, { // a=rtcp:65179 IN IP4 193.84.77.194 name: 'rtcp', reg: /^rtcp:(\d*)(?: (\S*) IP(\d) (\S*))?/, names: ['port', 'netType', 'ipVer', 'address'], format: function (o) { return o.address != null ? 'rtcp:%d %s IP%d %s' : 'rtcp:%d'; } }, { // a=rtcp-fb:98 trr-int 100 push: 'rtcpFbTrrInt', reg: /^rtcp-fb:(\*|\d*) trr-int (\d*)/, names: ['payload', 'value'], format: 'rtcp-fb:%s trr-int %d' }, { // a=rtcp-fb:98 nack rpsi push: 'rtcpFb', reg: /^rtcp-fb:(\*|\d*) ([\w-_]*)(?: ([\w-_]*))?/, names: ['payload', 'type', 'subtype'], format: function (o) { return o.subtype != null ? 'rtcp-fb:%s %s %s' : 'rtcp-fb:%s %s'; } }, { // a=extmap:2 urn:ietf:params:rtp-hdrext:toffset // a=extmap:1/recvonly URI-gps-string // a=extmap:3 urn:ietf:params:rtp-hdrext:encrypt urn:ietf:params:rtp-hdrext:smpte-tc 25@600/24 push: 'ext', reg: /^extmap:(\d+)(?:\/(\w+))?(?: (urn:ietf:params:rtp-hdrext:encrypt))? (\S*)(?: (\S*))?/, names: ['value', 'direction', 'encrypt-uri', 'uri', 'config'], format: function (o) { return 'extmap:%d' + (o.direction ? '/%s' : '%v') + (o['encrypt-uri'] ? ' %s' : '%v') + ' %s' + (o.config ? ' %s' : ''); } }, { // a=extmap-allow-mixed name: 'extmapAllowMixed', reg: /^(extmap-allow-mixed)/ }, { // a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32 push: 'crypto', reg: /^crypto:(\d*) ([\w_]*) (\S*)(?: (\S*))?/, names: ['id', 'suite', 'config', 'sessionConfig'], format: function (o) { return o.sessionConfig != null ? 'crypto:%d %s %s %s' : 'crypto:%d %s %s'; } }, { // a=setup:actpass name: 'setup', reg: /^setup:(\w*)/, format: 'setup:%s' }, { // a=connection:new name: 'connectionType', reg: /^connection:(new|existing)/, format: 'connection:%s' }, { // a=mid:1 name: 'mid', reg: /^mid:([^\s]*)/, format: 'mid:%s' }, { // a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a name: 'msid', reg: /^msid:(.*)/, format: 'msid:%s' }, { // a=ptime:20 name: 'ptime', reg: /^ptime:(\d*(?:\.\d*)*)/, format: 'ptime:%d' }, { // a=maxptime:60 name: 'maxptime', reg: /^maxptime:(\d*(?:\.\d*)*)/, format: 'maxptime:%d' }, { // a=sendrecv name: 'direction', reg: /^(sendrecv|recvonly|sendonly|inactive)/ }, { // a=ice-lite name: 'icelite', reg: /^(ice-lite)/ }, { // a=ice-ufrag:F7gI name: 'iceUfrag', reg: /^ice-ufrag:(\S*)/, format: 'ice-ufrag:%s' }, { // a=ice-pwd:x9cml/YzichV2+XlhiMu8g name: 'icePwd', reg: /^ice-pwd:(\S*)/, format: 'ice-pwd:%s' }, { // a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33 name: 'fingerprint', reg: /^fingerprint:(\S*) (\S*)/, names: ['type', 'hash'], format: 'fingerprint:%s %s' }, { // a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host // a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0 network-id 3 network-cost 10 // a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0 network-id 3 network-cost 10 // a=candidate:229815620 1 tcp 1518280447 192.168.150.19 60017 typ host tcptype active generation 0 network-id 3 network-cost 10 // a=candidate:3289912957 2 tcp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 tcptype passive generation 0 network-id 3 network-cost 10 push: 'candidates', reg: /^candidate:(\S*) (\d*) (\S*) (\d*) (\S*) (\d*) typ (\S*)(?: raddr (\S*) rport (\d*))?(?: tcptype (\S*))?(?: generation (\d*))?(?: network-id (\d*))?(?: network-cost (\d*))?/, names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'tcptype', 'generation', 'network-id', 'network-cost'], format: function (o) { var str = 'candidate:%s %d %s %d %s %d typ %s'; str += o.raddr != null ? ' raddr %s rport %d' : '%v%v'; // NB: candidate has three optional chunks, so %void middles one if it's missing str += o.tcptype != null ? ' tcptype %s' : '%v'; if (o.generation != null) { str += ' generation %d'; } str += o['network-id'] != null ? ' network-id %d' : '%v'; str += o['network-cost'] != null ? ' network-cost %d' : '%v'; return str; } }, { // a=end-of-candidates (keep after the candidates line for readability) name: 'endOfCandidates', reg: /^(end-of-candidates)/ }, { // a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ... name: 'remoteCandidates', reg: /^remote-candidates:(.*)/, format: 'remote-candidates:%s' }, { // a=ice-options:google-ice name: 'iceOptions', reg: /^ice-options:(\S*)/, format: 'ice-options:%s' }, { // a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1 push: 'ssrcs', reg: /^ssrc:(\d*) ([\w_-]*)(?::(.*))?/, names: ['id', 'attribute', 'value'], format: function (o) { var str = 'ssrc:%d'; if (o.attribute != null) { str += ' %s'; if (o.value != null) { str += ':%s'; } } return str; } }, { // a=ssrc-group:FEC 1 2 // a=ssrc-group:FEC-FR 3004364195 1080772241 push: 'ssrcGroups', // token-char = %x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39 / %x41-5A / %x5E-7E reg: /^ssrc-group:([\x21\x23\x24\x25\x26\x27\x2A\x2B\x2D\x2E\w]*) (.*)/, names: ['semantics', 'ssrcs'], format: 'ssrc-group:%s %s' }, { // a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV name: 'msidSemantic', reg: /^msid-semantic:\s?(\w*) (\S*)/, names: ['semantic', 'token'], format: 'msid-semantic: %s %s' // space after ':' is not accidental }, { // a=group:BUNDLE audio video push: 'groups', reg: /^group:(\w*) (.*)/, names: ['type', 'mids'], format: 'group:%s %s' }, { // a=rtcp-mux name: 'rtcpMux', reg: /^(rtcp-mux)/ }, { // a=rtcp-rsize name: 'rtcpRsize', reg: /^(rtcp-rsize)/ }, { // a=sctpmap:5000 webrtc-datachannel 1024 name: 'sctpmap', reg: /^sctpmap:([\w_/]*) (\S*)(?: (\S*))?/, names: ['sctpmapNumber', 'app', 'maxMessageSize'], format: function (o) { return o.maxMessageSize != null ? 'sctpmap:%s %s %s' : 'sctpmap:%s %s'; } }, { // a=x-google-flag:conference name: 'xGoogleFlag', reg: /^x-google-flag:([^\s]*)/, format: 'x-google-flag:%s' }, { // a=rid:1 send max-width=1280;max-height=720;max-fps=30;depend=0 push: 'rids', reg: /^rid:([\d\w]+) (\w+)(?: ([\S| ]*))?/, names: ['id', 'direction', 'params'], format: function (o) { return o.params ? 'rid:%s %s %s' : 'rid:%s %s'; } }, { // a=imageattr:97 send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] recv [x=330,y=250] // a=imageattr:* send [x=800,y=640] recv * // a=imageattr:100 recv [x=320,y=240] push: 'imageattrs', reg: new RegExp( // a=imageattr:97 '^imageattr:(\\d+|\\*)' + // send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] '[\\s\\t]+(send|recv)[\\s\\t]+(\\*|\\[\\S+\\](?:[\\s\\t]+\\[\\S+\\])*)' + // recv [x=330,y=250] '(?:[\\s\\t]+(recv|send)[\\s\\t]+(\\*|\\[\\S+\\](?:[\\s\\t]+\\[\\S+\\])*))?'), names: ['pt', 'dir1', 'attrs1', 'dir2', 'attrs2'], format: function (o) { return 'imageattr:%s %s %s' + (o.dir2 ? ' %s %s' : ''); } }, { // a=simulcast:send 1,2,3;~4,~5 recv 6;~7,~8 // a=simulcast:recv 1;4,5 send 6;7 name: 'simulcast', reg: new RegExp( // a=simulcast: '^simulcast:' + // send 1,2,3;~4,~5 '(send|recv) ([a-zA-Z0-9\\-_~;,]+)' + // space + recv 6;~7,~8 '(?:\\s?(send|recv) ([a-zA-Z0-9\\-_~;,]+))?' + // end '$'), names: ['dir1', 'list1', 'dir2', 'list2'], format: function (o) { return 'simulcast:%s %s' + (o.dir2 ? ' %s %s' : ''); } }, { // old simulcast draft 03 (implemented by Firefox) // https://tools.ietf.org/html/draft-ietf-mmusic-sdp-simulcast-03 // a=simulcast: recv pt=97;98 send pt=97 // a=simulcast: send rid=5;6;7 paused=6,7 name: 'simulcast_03', reg: /^simulcast:[\s\t]+([\S+\s\t]+)$/, names: ['value'], format: 'simulcast: %s' }, { // a=framerate:25 // a=framerate:29.97 name: 'framerate', reg: /^framerate:(\d+(?:$|\.\d+))/, format: 'framerate:%s' }, { // RFC4570 // a=source-filter: incl IN IP4 239.5.2.31 10.1.15.5 name: 'sourceFilter', reg: /^source-filter: *(excl|incl) (\S*) (IP4|IP6|\*) (\S*) (.*)/, names: ['filterMode', 'netType', 'addressTypes', 'destAddress', 'srcList'], format: 'source-filter: %s %s %s %s %s' }, { // a=bundle-only name: 'bundleOnly', reg: /^(bundle-only)/ }, { // a=label:1 name: 'label', reg: /^label:(.+)/, format: 'label:%s' }, { // RFC version 26 for SCTP over DTLS // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-5 name: 'sctpPort', reg: /^sctp-port:(\d+)$/, format: 'sctp-port:%s' }, { // RFC version 26 for SCTP over DTLS // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-6 name: 'maxMessageSize', reg: /^max-message-size:(\d+)$/, format: 'max-message-size:%s' }, { // RFC7273 // a=ts-refclk:ptp=IEEE1588-2008:39-A7-94-FF-FE-07-CB-D0:37 push: 'tsRefClocks', reg: /^ts-refclk:([^\s=]*)(?:=(\S*))?/, names: ['clksrc', 'clksrcExt'], format: function (o) { return 'ts-refclk:%s' + (o.clksrcExt != null ? '=%s' : ''); } }, { // RFC7273 // a=mediaclk:direct=963214424 name: 'mediaClk', reg: /^mediaclk:(?:id=(\S*))? *([^\s=]*)(?:=(\S*))?(?: *rate=(\d+)\/(\d+))?/, names: ['id', 'mediaClockName', 'mediaClockValue', 'rateNumerator', 'rateDenominator'], format: function (o) { var str = 'mediaclk:'; str += o.id != null ? 'id=%s %s' : '%v%s'; str += o.mediaClockValue != null ? '=%s' : ''; str += o.rateNumerator != null ? ' rate=%s' : ''; str += o.rateDenominator != null ? '/%s' : ''; return str; } }, { // a=keywds:keywords name: 'keywords', reg: /^keywds:(.+)$/, format: 'keywds:%s' }, { // a=content:main name: 'content', reg: /^content:(.+)/, format: 'content:%s' }, // BFCP https://tools.ietf.org/html/rfc4583 { // a=floorctrl:c-s name: 'bfcpFloorCtrl', reg: /^floorctrl:(c-only|s-only|c-s)/, format: 'floorctrl:%s' }, { // a=confid:1 name: 'bfcpConfId', reg: /^confid:(\d+)/, format: 'confid:%s' }, { // a=userid:1 name: 'bfcpUserId', reg: /^userid:(\d+)/, format: 'userid:%s' }, { // a=floorid:1 name: 'bfcpFloorId', reg: /^floorid:(.+) (?:m-stream|mstrm):(.+)/, names: ['id', 'mStream'], format: 'floorid:%s mstrm:%s' }, { // any a= that we don't understand is kept verbatim on media.invalid push: 'invalid', names: ['value'] }] }; // set sensible defaults to avoid polluting the grammar with boring details Object.keys(grammar$1).forEach(function (key) { var objs = grammar$1[key]; objs.forEach(function (obj) { if (!obj.reg) { obj.reg = /(.*)/; } if (!obj.format) { obj.format = '%s'; } }); }); (function (exports) { var toIntIfInt = function (v) { return String(Number(v)) === v ? Number(v) : v; }; var attachProperties = function (match, location, names, rawName) { if (rawName && !names) { location[rawName] = toIntIfInt(match[1]); } else { for (var i = 0; i < names.length; i += 1) { if (match[i + 1] != null) { location[names[i]] = toIntIfInt(match[i + 1]); } } } }; var parseReg = function (obj, location, content) { var needsBlank = obj.name && obj.names; if (obj.push && !location[obj.push]) { location[obj.push] = []; } else if (needsBlank && !location[obj.name]) { location[obj.name] = {}; } var keyLocation = obj.push ? {} : // blank object that will be pushed needsBlank ? location[obj.name] : location; // otherwise, named location or root attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name); if (obj.push) { location[obj.push].push(keyLocation); } }; var grammar = grammarExports; var validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/); exports.parse = function (sdp) { var session = {}, media = [], location = session; // points at where properties go under (one of the above) // parse lines we understand sdp.split(/(\r\n|\r|\n)/).filter(validLine).forEach(function (l) { var type = l[0]; var content = l.slice(2); if (type === 'm') { media.push({ rtp: [], fmtp: [] }); location = media[media.length - 1]; // point at latest media line } for (var j = 0; j < (grammar[type] || []).length; j += 1) { var obj = grammar[type][j]; if (obj.reg.test(content)) { return parseReg(obj, location, content); } } }); session.media = media; // link it up return session; }; var paramReducer = function (acc, expr) { var s = expr.split(/=(.+)/, 2); if (s.length === 2) { acc[s[0]] = toIntIfInt(s[1]); } else if (s.length === 1 && expr.length > 1) { acc[s[0]] = undefined; } return acc; }; exports.parseParams = function (str) { return str.split(/;\s?/).reduce(paramReducer, {}); }; // For backward compatibility - alias will be removed in 3.0.0 exports.parseFmtpConfig = exports.parseParams; exports.parsePayloads = function (str) { return str.toString().split(' ').map(Number); }; exports.parseRemoteCandidates = function (str) { var candidates = []; var parts = str.split(' ').map(toIntIfInt); for (var i = 0; i < parts.length; i += 3) { candidates.push({ component: parts[i], ip: parts[i + 1], port: parts[i + 2] }); } return candidates; }; exports.parseImageAttributes = function (str) { return str.split(' ').map(function (item) { return item.substring(1, item.length - 1).split(',').reduce(paramReducer, {}); }); }; exports.parseSimulcastStreamList = function (str) { return str.split(';').map(function (stream) { return stream.split(',').map(function (format) { var scid, paused = false; if (format[0] !== '~') { scid = toIntIfInt(format); } else { scid = toIntIfInt(format.substring(1, format.length)); paused = true; } return { scid: scid, paused: paused }; }); }); }; })(parser$1); var grammar = grammarExports; // customized util.format - discards excess arguments and can void middle ones var formatRegExp = /%[sdv%]/g; var format = function (formatStr) { var i = 1; var args = arguments; var len = args.length; return formatStr.replace(formatRegExp, function (x) { if (i >= len) { return x; // missing argument } var arg = args[i]; i += 1; switch (x) { case '%%': return '%'; case '%s': return String(arg); case '%d': return Number(arg); case '%v': return ''; } }); // NB: we discard excess arguments - they are typically undefined from makeLine }; var makeLine = function (type, obj, location) { var str = obj.format instanceof Function ? obj.format(obj.push ? location : location[obj.name]) : obj.format; var args = [type + '=' + str]; if (obj.names) { for (var i = 0; i < obj.names.length; i += 1) { var n = obj.names[i]; if (obj.name) { args.push(location[obj.name][n]); } else { // for mLine and push attributes args.push(location[obj.names[i]]); } } } else { args.push(location[obj.name]); } return format.apply(null, args); }; // RFC specified order // TODO: extend this with all the rest var defaultOuterOrder = ['v', 'o', 's', 'i', 'u', 'e', 'p', 'c', 'b', 't', 'r', 'z', 'a']; var defaultInnerOrder = ['i', 'c', 'b', 'a']; var writer$1 = function (session, opts) { opts = opts || {}; // ensure certain properties exist if (session.version == null) { session.version = 0; // 'v=0' must be there (only defined version atm) } if (session.name == null) { session.name = ' '; // 's= ' must be there if no meaningful name set } session.media.forEach(function (mLine) { if (mLine.payloads == null) { mLine.payloads = ''; } }); var outerOrder = opts.outerOrder || defaultOuterOrder; var innerOrder = opts.innerOrder || defaultInnerOrder; var sdp = []; // loop through outerOrder for matching properties on session outerOrder.forEach(function (type) { grammar[type].forEach(function (obj) { if (obj.name in session && session[obj.name] != null) { sdp.push(makeLine(type, obj, session)); } else if (obj.push in session && session[obj.push] != null) { session[obj.push].forEach(function (el) { sdp.push(makeLine(type, obj, el)); }); } }); }); // then for each media line, follow the innerOrder session.media.forEach(function (mLine) { sdp.push(makeLine('m', grammar.m[0], mLine)); innerOrder.forEach(function (type) { grammar[type].forEach(function (obj) { if (obj.name in mLine && mLine[obj.name] != null) { sdp.push(makeLine(type, obj, mLine)); } else if (obj.push in mLine && mLine[obj.push] != null) { mLine[obj.push].forEach(function (el) { sdp.push(makeLine(type, obj, el)); }); } }); }); }); return sdp.join('\r\n') + '\r\n'; }; var parser = parser$1; var writer = writer$1; var write = writer; var parse = parser.parse; parser.parseParams; parser.parseFmtpConfig; // Alias of parseParams(). parser.parsePayloads; parser.parseRemoteCandidates; parser.parseImageAttributes; parser.parseSimulcastStreamList; const PCEvents = { NegotiationStarted: 'negotiationStarted', NegotiationComplete: 'negotiationComplete' }; /** @internal */ class PCTransport extends eventsExports { constructor(config) { super(); this.pendingCandidates = []; this.restartingIce = false; this.renegotiate = false; this.trackBitrates = []; this.remoteStereoMids = []; this.remoteNackMids = []; // debounced negotiate interface this.negotiate = r(onError => { this.emit(PCEvents.NegotiationStarted); try { this.createAndSendOffer(); } catch (e) { if (onError) { onError(e); } else { throw e; } } }, 100); this.pc = new RTCPeerConnection(config); } get isICEConnected() { return this.pc.iceConnectionState === 'connected' || this.pc.iceConnectionState === 'completed'; } async addIceCandidate(candidate) { if (this.pc.remoteDescription && !this.restartingIce) { return this.pc.addIceCandidate(candidate); } this.pendingCandidates.push(candidate); } async setRemoteDescription(sd) { if (sd.type === 'offer') { let { stereoMids, nackMids } = extractStereoAndNackAudioFromOffer(sd); this.remoteStereoMids = stereoMids; this.remoteNackMids = nackMids; } await this.pc.setRemoteDescription(sd); this.pendingCandidates.forEach(candidate => { this.pc.addIceCandidate(candidate); }); this.pendingCandidates = []; this.restartingIce = false; if (this.renegotiate) { this.renegotiate = false; this.createAndSendOffer(); } else if (sd.type === 'answer') { this.emit(PCEvents.NegotiationComplete); } } async createAndSendOffer(options) { var _a; if (this.onOffer === undefined) { return; } if (options === null || options === void 0 ? void 0 : options.iceRestart) { livekitLogger.debug('restarting ICE'); this.restartingIce = true; } if (this.pc.signalingState === 'have-local-offer') { // we're waiting for the peer to accept our offer, so we'll just wait // the only exception to this is when ICE restart is needed const currentSD = this.pc.remoteDescription; if ((options === null || options === void 0 ? void 0 : options.iceRestart) && currentSD) { // TODO: handle when ICE restart is needed but we don't have a remote description // the best thing to do is to recreate the peerconnection await this.pc.setRemoteDescription(currentSD); } else { this.renegotiate = true; return; } } else if (this.pc.signalingState === 'closed') { livekitLogger.warn('could not createOffer with closed peer connection'); return; } // actually negotiate livekitLogger.debug('starting to negotiate'); const offer = await this.pc.createOffer(options); const sdpParsed = parse((_a = offer.sdp) !== null && _a !== void 0 ? _a : ''); sdpParsed.media.forEach(media => { if (media.type === 'audio') { ensureAudioNackAndStereo(media, [], []); } else if (media.type === 'video') { // mung sdp for codec bitrate setting that can't apply by sendEncoding this.trackBitrates.some(trackbr => { if (!media.msid || !media.msid.includes(trackbr.sid)) { return false; } let codecPayload = 0; media.rtp.some(rtp => { if (rtp.codec.toUpperCase() === trackbr.codec.toUpperCase()) { codecPayload = rtp.payload; return true; } return false; }); // add x-google-max-bitrate to fmtp line if not exist if (codecPayload > 0) { if (!media.fmtp.some(fmtp => { if (fmtp.payload === codecPayload) { if (!fmtp.config.includes('x-google-max-bitrate')) { fmtp.config += ";x-google-max-bitrate=".concat(trackbr.maxbr); } return true; } return false; })) { media.fmtp.push({ payload: codecPayload, config: "x-google-max-bitrate=".concat(trackbr.maxbr) }); } } return true; }); } }); this.trackBitrates = []; await this.setMungedLocalDescription(offer, write(sdpParsed)); this.onOffer(offer); } async createAndSetAnswer() { var _a; const answer = await this.pc.createAnswer(); const sdpParsed = parse((_a = answer.sdp) !== null && _a !== void 0 ? _a : ''); sdpParsed.media.forEach(media => { if (media.type === 'audio') { ensureAudioNackAndStereo(media, this.remoteStereoMids, this.remoteNackMids); } }); await this.setMungedLocalDescription(answer, write(sdpParsed)); return answer; } setTrackCodecBitrate(sid, codec, maxbr) { this.trackBitrates.push({ sid, codec, maxbr }); } close() { this.pc.onconnectionstatechange = null; this.pc.oniceconnectionstatechange = null; this.pc.close(); } async setMungedLocalDescription(sd, munged) { const originalSdp = sd.sdp; sd.sdp = munged; try { livekitLogger.debug('setting munged local description'); await this.pc.setLocalDescription(sd); return; } catch (e) { livekitLogger.warn("not able to set ".concat(sd.type, ", falling back to unmodified sdp"), { error: e }); sd.sdp = originalSdp; } try { await this.pc.setLocalDescription(sd); } catch (e) { // this error cannot always be caught. // If the local description has a setCodecPreferences error, this error will be uncaught let msg = 'unknown error'; if (e instanceof Error) { msg = e.message; } else if (typeof e === 'string') { msg = e; } throw new NegotiationError(msg); } } } function ensureAudioNackAndStereo(media, stereoMids, nackMids) { // found opus codec to add nack fb let opusPayload = 0; media.rtp.some(rtp => { if (rtp.codec === 'opus') { opusPayload = rtp.payload; return true; } return false; }); // add nack rtcpfb if not exist if (opusPayload > 0) { if (!media.rtcpFb) { media.rtcpFb = []; } if (nackMids.includes(media.mid) && !media.rtcpFb.some(fb => fb.payload === opusPayload && fb.type === 'nack')) { media.rtcpFb.push({ payload: opusPayload, type: 'nack' }); } if (stereoMids.includes(media.mid)) { media.fmtp.some(fmtp => { if (fmtp.payload === opusPayload) { if (!fmtp.config.includes('stereo=1')) { fmtp.config += ';stereo=1'; } return true; } return false; }); } } } function extractStereoAndNackAudioFromOffer(offer) { var _a; const stereoMids = []; const nackMids = []; const sdpParsed = parse((_a = offer.sdp) !== null && _a !== void 0 ? _a : ''); let opusPayload = 0; sdpParsed.media.forEach(media => { var _a; if (media.type === 'audio') { media.rtp.some(rtp => { if (rtp.codec === 'opus') { opusPayload = rtp.payload; return true; } return false; }); if ((_a = media.rtcpFb) === null || _a === void 0 ? void 0 : _a.some(fb => fb.payload === opusPayload && fb.type === 'nack')) { nackMids.push(media.mid); } media.fmtp.some(fmtp => { if (fmtp.payload === opusPayload) { if (fmtp.config.includes('sprop-stereo=1')) { stereoMids.push(media.mid); } return true; } return false; }); } }); return { stereoMids, nackMids }; } const lossyDataChannel = '_lossy'; const reliableDataChannel = '_reliable'; const minReconnectWait = 2 * 1000; const leaveReconnect = 'leave-reconnect'; var PCState; (function (PCState) { PCState[PCState["New"] = 0] = "New"; PCState[PCState["Connected"] = 1] = "Connected"; PCState[PCState["Disconnected"] = 2] = "Disconnected"; PCState[PCState["Reconnecting"] = 3] = "Reconnecting"; PCState[PCState["Closed"] = 4] = "Closed"; })(PCState || (PCState = {})); /** @internal */ class RTCEngine extends eventsExports.EventEmitter { get isClosed() { return this._isClosed; } constructor(options) { super(); this.options = options; this.rtcConfig = {}; this.peerConnectionTimeout = roomConnectOptionDefaults.peerConnectionTimeout; this.subscriberPrimary = false; this.pcState = PCState.New; this._isClosed = true; this.pendingTrackResolvers = {}; // true if publisher connection has already been established. // this is helpful to know if we need to restart ICE on the publisher connection this.hasPublished = false; this.reconnectAttempts = 0; this.reconnectStart = 0; this.fullReconnectOnNext = false; this.attemptingReconnect = false; /** keeps track of how often an initial join connection has been tried */ this.joinAttempts = 0; /** specifies how often an initial join connection is allowed to retry */ this.maxJoinAttempts = 1; this.shouldFailNext = false; this.handleDataChannel = async _ref => { let { channel } = _ref; if (!channel) { return; } if (channel.label === reliableDataChannel) { this.reliableDCSub = channel; } else if (channel.label === lossyDataChannel) { this.lossyDCSub = channel; } else { return; } livekitLogger.debug("on data channel ".concat(channel.id, ", ").concat(channel.label)); channel.onmessage = this.handleDataMessage; }; this.handleDataMessage = async message => { var _a, _b; // make sure to respect incoming data message order by processing message events one after the other const unlock = await this.dataProcessLock.lock(); try { // decode let buffer; if (message.data instanceof ArrayBuffer) { buffer = message.data; } else if (message.data instanceof Blob) { buffer = await message.data.arrayBuffer(); } else { livekitLogger.error('unsupported data type', message.data); return; } const dp = DataPacket.decode(new Uint8Array(buffer)); if (((_a = dp.value) === null || _a === void 0 ? void 0 : _a.$case) === 'speaker') { // dispatch speaker updates this.emit(EngineEvent.ActiveSpeakersUpdate, dp.value.speaker.speakers); } else if (((_b = dp.value) === null || _b === void 0 ? void 0 : _b.$case) === 'user') { this.emit(EngineEvent.DataPacketReceived, dp.value.user, dp.kind); } } finally { unlock(); } }; this.handleDataError = event => { const channel = event.currentTarget; const channelKind = channel.maxRetransmits === 0 ? 'lossy' : 'reliable'; if (event instanceof ErrorEvent) { const { error } = event.error; livekitLogger.error("DataChannel error on ".concat(channelKind, ": ").concat(event.message), error); } else { livekitLogger.error("Unknown DataChannel Error on ".concat(channelKind), event); } }; // websocket reconnect behavior. if websocket is interrupted, and the PeerConnection // continues to work, we can reconnect to websocket to continue the session // after a number of retries, we'll close and give up permanently this.handleDisconnect = (connection, disconnectReason) => { if (this._isClosed) { return; } livekitLogger.warn("".concat(connection, " disconnected")); if (this.reconnectAttempts === 0) { // only reset start time on the first try this.reconnectStart = Date.now(); } const disconnect = duration => { livekitLogger.warn("could not recover connection after ".concat(this.reconnectAttempts, " attempts, ").concat(duration, "ms. giving up")); this.emit(EngineEvent.Disconnected); this.close(); }; const duration = Date.now() - this.reconnectStart; let delay = this.getNextRetryDelay({ elapsedMs: duration, retryCount: this.reconnectAttempts }); if (delay === null) { disconnect(duration); return; } if (connection === leaveReconnect) { delay = 0; } livekitLogger.debug("reconnecting in ".concat(delay, "ms")); this.clearReconnectTimeout(); this.reconnectTimeout = CriticalTimers.setTimeout(() => this.attemptReconnect(disconnectReason), delay); }; this.handleBrowserOnLine = () => { // in case the engine is currently reconnecting, attempt a reconnect immediately after the browser state has changed to 'onLine' if (this.client.isReconnecting) { this.clearReconnectTimeout(); this.attemptReconnect(ReconnectReason.RR_SIGNAL_DISCONNECTED); } }; this.client = new SignalClient(); this.client.signalLatency = this.options.expSignalLatency; this.reconnectPolicy = this.options.reconnectPolicy; this.registerOnLineListener(); this.closingLock = new Mutex(); this.dataProcessLock = new Mutex(); } async join(url, token, opts, abortSignal) { this.url = url; this.token = token; this.signalOpts = opts; try { this.joinAttempts += 1; const joinResponse = await this.client.join(url, token, opts, abortSignal); this._isClosed = false; this.subscriberPrimary = joinResponse.subscriberPrimary; if (!this.publisher) { this.configure(joinResponse); } // create offer if (!this.subscriberPrimary) { this.negotiate(); } this.clientConfiguration = joinResponse.clientConfiguration; return joinResponse; } catch (e) { if (e instanceof ConnectionError) { if (e.reason === 1 /* ConnectionErrorReason.ServerUnreachable */) { livekitLogger.warn("Couldn't connect to server, attempt ".concat(this.joinAttempts, " of ").concat(this.maxJoinAttempts)); if (this.joinAttempts < this.maxJoinAttempts) { return this.join(url, token, opts, abortSignal); } } } throw e; } } async close() { const unlock = await this.closingLock.lock(); if (this.isClosed) { unlock(); return; } try { this._isClosed = true; this.emit(EngineEvent.Closing); this.removeAllListeners(); this.deregisterOnLineListener(); this.clearPendingReconnect(); if (this.publisher && this.publisher.pc.signalingState !== 'closed') { this.publisher.pc.getSenders().forEach(sender => { var _a, _b; try { // TODO: react-native-webrtc doesn't have removeTrack yet. if ((_a = this.publisher) === null || _a === void 0 ? void 0 : _a.pc.removeTrack) { (_b = this.publisher) === null || _b === void 0 ? void 0 : _b.pc.removeTrack(sender); } } catch (e) { livekitLogger.warn('could not removeTrack', { error: e }); } }); this.publisher.close(); this.publisher = undefined; } if (this.subscriber) { this.subscriber.close(); this.subscriber = undefined; } await this.client.close(); } finally { unlock(); } } addTrack(req) { if (this.pendingTrackResolvers[req.cid]) { throw new TrackInvalidError('a track with the same ID has already been published'); } return new Promise((resolve, reject) => { const publicationTimeout = setTimeout(() => { delete this.pendingTrackResolvers[req.cid]; reject(new ConnectionError('publication of local track timed out, no response from server')); }, 10000); this.pendingTrackResolvers[req.cid] = { resolve: info => { clearTimeout(publicationTimeout); resolve(info); }, reject: () => { clearTimeout(publicationTimeout); reject(new Error('Cancelled publication by calling unpublish')); } }; this.client.sendAddTrack(req); }); } /** * Removes sender from PeerConnection, returning true if it was removed successfully * and a negotiation is necessary * @param sender * @returns */ removeTrack(sender) { var _a; if (sender.track && this.pendingTrackResolvers[sender.track.id]) { const { reject } = this.pendingTrackResolvers[sender.track.id]; if (reject) { reject(); } delete this.pendingTrackResolvers[sender.track.id]; } try { (_a = this.publisher) === null || _a === void 0 ? void 0 : _a.pc.removeTrack(sender); return true; } catch (e) { livekitLogger.warn('failed to remove track', { error: e, method: 'removeTrack' }); } return false; } updateMuteStatus(trackSid, muted) { this.client.sendMuteTrack(trackSid, muted); } get dataSubscriberReadyState() { var _a; return (_a = this.reliableDCSub) === null || _a === void 0 ? void 0 : _a.readyState; } async getConnectedServerAddress() { if (this.primaryPC === undefined) { return undefined; } return getConnectedAddress(this.primaryPC); } configure(joinResponse) { var _a; // already configured if (this.publisher || this.subscriber) { return; } this.participantSid = (_a = joinResponse.participant) === null || _a === void 0 ? void 0 : _a.sid; const rtcConfig = this.makeRTCConfiguration(joinResponse); this.publisher = new PCTransport(rtcConfig); this.subscriber = new PCTransport(rtcConfig); this.emit(EngineEvent.TransportsCreated, this.publisher, this.subscriber); this.publisher.pc.onicecandidate = ev => { if (!ev.candidate) return; livekitLogger.trace('adding ICE candidate for peer', ev.candidate); this.client.sendIceCandidate(ev.candidate, SignalTarget.PUBLISHER); }; this.subscriber.pc.onicecandidate = ev => { if (!ev.candidate) return; this.client.sendIceCandidate(ev.candidate, SignalTarget.SUBSCRIBER); }; this.publisher.onOffer = offer => { this.client.sendOffer(offer); }; let primaryPC = this.publisher.pc; let secondaryPC = this.subscriber.pc; let subscriberPrimary = joinResponse.subscriberPrimary; if (subscriberPrimary) { primaryPC = this.subscriber.pc; secondaryPC = this.publisher.pc; // in subscriber primary mode, server side opens sub data channels. this.subscriber.pc.ondatachannel = this.handleDataChannel; } this.primaryPC = primaryPC; primaryPC.onconnectionstatechange = async () => { livekitLogger.debug("primary PC state changed ".concat(primaryPC.connectionState)); if (primaryPC.connectionState === 'connected') { const shouldEmit = this.pcState === PCState.New; this.pcState = PCState.Connected; if (shouldEmit) { this.emit(EngineEvent.Connected, joinResponse); } } else if (primaryPC.connectionState === 'failed') { // on Safari, PeerConnection will switch to 'disconnected' during renegotiation if (this.pcState === PCState.Connected) { this.pcState = PCState.Disconnected; this.handleDisconnect('primary peerconnection', subscriberPrimary ? ReconnectReason.RR_SUBSCRIBER_FAILED : ReconnectReason.RR_PUBLISHER_FAILED); } } }; secondaryPC.onconnectionstatechange = async () => { livekitLogger.debug("secondary PC state changed ".concat(secondaryPC.connectionState)); // also reconnect if secondary peerconnection fails if (secondaryPC.connectionState === 'failed') { this.handleDisconnect('secondary peerconnection', subscriberPrimary ? ReconnectReason.RR_PUBLISHER_FAILED : ReconnectReason.RR_SUBSCRIBER_FAILED); } }; this.subscriber.pc.ontrack = ev => { this.emit(EngineEvent.MediaTrackAdded, ev.track, ev.streams[0], ev.receiver); }; this.createDataChannels(); // configure signaling client this.client.onAnswer = async sd => { if (!this.publisher) { return; } livekitLogger.debug('received server answer', { RTCSdpType: sd.type, signalingState: this.publisher.pc.signalingState }); await this.publisher.setRemoteDescription(sd); }; // add candidate on trickle this.client.onTrickle = (candidate, target) => { if (!this.publisher || !this.subscriber) { return; } livekitLogger.trace('got ICE candidate from peer', { candidate, target }); if (target === SignalTarget.PUBLISHER) { this.publisher.addIceCandidate(candidate); } else { this.subscriber.addIceCandidate(candidate); } }; // when server creates an offer for the client this.client.onOffer = async sd => { if (!this.subscriber) { return; } livekitLogger.debug('received server offer', { RTCSdpType: sd.type, signalingState: this.subscriber.pc.signalingState }); await this.subscriber.setRemoteDescription(sd); // answer the offer const answer = await this.subscriber.createAndSetAnswer(); this.client.sendAnswer(answer); }; this.client.onLocalTrackPublished = res => { livekitLogger.debug('received trackPublishedResponse', res); const { resolve } = this.pendingTrackResolvers[res.cid]; if (!resolve) { livekitLogger.error("missing track resolver for ".concat(res.cid)); return; } delete this.pendingTrackResolvers[res.cid]; resolve(res.track); }; this.client.onTokenRefresh = token => { this.token = token; }; this.client.onClose = () => { this.handleDisconnect('signal', ReconnectReason.RR_SIGNAL_DISCONNECTED); }; this.client.onLeave = leave => { if (leave === null || leave === void 0 ? void 0 : leave.canReconnect) { this.fullReconnectOnNext = true; this.primaryPC = undefined; // reconnect immediately instead of waiting for next attempt this.handleDisconnect(leaveReconnect); } else { this.emit(EngineEvent.Disconnected, leave === null || leave === void 0 ? void 0 : leave.reason); this.close(); } livekitLogger.trace('leave request', { leave }); }; } makeRTCConfiguration(serverResponse) { const rtcConfig = _objectSpread2({}, this.rtcConfig); // update ICE servers before creating PeerConnection if (serverResponse.iceServers && !rtcConfig.iceServers) { const rtcIceServers = []; serverResponse.iceServers.forEach(iceServer => { const rtcIceServer = { urls: iceServer.urls }; if (iceServer.username) rtcIceServer.username = iceServer.username; if (iceServer.credential) { rtcIceServer.credential = iceServer.credential; } rtcIceServers.push(rtcIceServer); }); rtcConfig.iceServers = rtcIceServers; } if (serverResponse.clientConfiguration && serverResponse.clientConfiguration.forceRelay === ClientConfigSetting.ENABLED) { rtcConfig.iceTransportPolicy = 'relay'; } // @ts-ignore rtcConfig.sdpSemantics = 'unified-plan'; // @ts-ignore rtcConfig.continualGatheringPolicy = 'gather_continually'; return rtcConfig; } createDataChannels() { if (!this.publisher) { return; } // clear old data channel callbacks if recreate if (this.lossyDC) { this.lossyDC.onmessage = null; this.lossyDC.onerror = null; } if (this.reliableDC) { this.reliableDC.onmessage = null; this.reliableDC.onerror = null; } // create data channels this.lossyDC = this.publisher.pc.createDataChannel(lossyDataChannel, { // will drop older packets that arrive ordered: true, maxRetransmits: 0 }); this.reliableDC = this.publisher.pc.createDataChannel(reliableDataChannel, { ordered: true }); // also handle messages over the pub channel, for backwards compatibility this.lossyDC.onmessage = this.handleDataMessage; this.reliableDC.onmessage = this.handleDataMessage; // handle datachannel errors this.lossyDC.onerror = this.handleDataError; this.reliableDC.onerror = this.handleDataError; } setPreferredCodec(transceiver, kind, videoCodec) { if (!('getCapabilities' in RTCRtpSender)) { return; } const cap = RTCRtpSender.getCapabilities(kind); if (!cap) return; livekitLogger.debug('get capabilities', cap); const matched = []; const partialMatched = []; const unmatched = []; cap.codecs.forEach(c => { const codec = c.mimeType.toLowerCase(); if (codec === 'audio/opus') { matched.push(c); return; } const matchesVideoCodec = codec === "video/".concat(videoCodec); if (!matchesVideoCodec) { unmatched.push(c); return; } // for h264 codecs that have sdpFmtpLine available, use only if the // profile-level-id is 42e01f for cross-browser compatibility if (videoCodec === 'h264') { if (c.sdpFmtpLine && c.sdpFmtpLine.includes('profile-level-id=42e01f')) { matched.push(c); } else { partialMatched.push(c); } return; } matched.push(c); }); if (supportsSetCodecPreferences(transceiver)) { transceiver.setCodecPreferences(matched.concat(partialMatched, unmatched)); } } async createSender(track, opts, encodings) { if (supportsTransceiver()) { return this.createTransceiverRTCRtpSender(track, opts, encodings); } if (supportsAddTrack()) { livekitLogger.debug('using add-track fallback'); return this.createRTCRtpSender(track.mediaStreamTrack); } throw new UnexpectedConnectionState('Required webRTC APIs not supported on this device'); } async createSimulcastSender(track, simulcastTrack, opts, encodings) { // store RTCRtpSender // @ts-ignore if (supportsTransceiver()) { return this.createSimulcastTransceiverSender(track, simulcastTrack, opts, encodings); } if (supportsAddTrack()) { livekitLogger.debug('using add-track fallback'); return this.createRTCRtpSender(track.mediaStreamTrack); } throw new UnexpectedConnectionState('Cannot stream on this device'); } async createTransceiverRTCRtpSender(track, opts, encodings) { if (!this.publisher) { throw new UnexpectedConnectionState('publisher is closed'); } const transceiverInit = { direction: 'sendonly' }; if (encodings) { transceiverInit.sendEncodings = encodings; } // addTransceiver for react-native is async. web is synchronous, but await won't effect it. const transceiver = await this.publisher.pc.addTransceiver(track.mediaStreamTrack, transceiverInit); if (track.kind === Track.Kind.Video && opts.videoCodec) { this.setPreferredCodec(transceiver, track.kind, opts.videoCodec); track.codec = opts.videoCodec; } return transceiver.sender; } async createSimulcastTransceiverSender(track, simulcastTrack, opts, encodings) { if (!this.publisher) { throw new UnexpectedConnectionState('publisher is closed'); } const transceiverInit = { direction: 'sendonly' }; if (encodings) { transceiverInit.sendEncodings = encodings; } // addTransceiver for react-native is async. web is synchronous, but await won't effect it. const transceiver = await this.publisher.pc.addTransceiver(simulcastTrack.mediaStreamTrack, transceiverInit); if (!opts.videoCodec) { return; } this.setPreferredCodec(transceiver, track.kind, opts.videoCodec); track.setSimulcastTrackSender(opts.videoCodec, transceiver.sender); return transceiver.sender; } async createRTCRtpSender(track) { if (!this.publisher) { throw new UnexpectedConnectionState('publisher is closed'); } return this.publisher.pc.addTrack(track); } async attemptReconnect(reason) { var _a, _b, _c; if (this._isClosed) { return; } // guard for attempting reconnection multiple times while one attempt is still not finished if (this.attemptingReconnect) { return; } if (((_a = this.clientConfiguration) === null || _a === void 0 ? void 0 : _a.resumeConnection) === ClientConfigSetting.DISABLED || // signaling state could change to closed due to hardware sleep // those connections cannot be resumed ((_c = (_b = this.primaryPC) === null || _b === void 0 ? void 0 : _b.signalingState) !== null && _c !== void 0 ? _c : 'closed') === 'closed') { this.fullReconnectOnNext = true; } try { this.attemptingReconnect = true; if (this.fullReconnectOnNext) { await this.restartConnection(); } else { await this.resumeConnection(reason); } this.clearPendingReconnect(); this.fullReconnectOnNext = false; } catch (e) { this.reconnectAttempts += 1; let recoverable = true; if (e instanceof UnexpectedConnectionState) { livekitLogger.debug('received unrecoverable error', { error: e }); // unrecoverable recoverable = false; } else if (!(e instanceof SignalReconnectError)) { // cannot resume this.fullReconnectOnNext = true; } if (recoverable) { this.handleDisconnect('reconnect', ReconnectReason.RR_UNKOWN); } else { livekitLogger.info("could not recover connection after ".concat(this.reconnectAttempts, " attempts, ").concat(Date.now() - this.reconnectStart, "ms. giving up")); this.emit(EngineEvent.Disconnected); this.close(); } } finally { this.attemptingReconnect = false; } } getNextRetryDelay(context) { try { return this.reconnectPolicy.nextRetryDelayInMs(context); } catch (e) { livekitLogger.warn('encountered error in reconnect policy', { error: e }); } // error in user code with provided reconnect policy, stop reconnecting return null; } async restartConnection() { var _a, _b; if (!this.url || !this.token) { // permanent failure, don't attempt reconnection throw new UnexpectedConnectionState('could not reconnect, url or token not saved'); } livekitLogger.info("reconnecting, attempt: ".concat(this.reconnectAttempts)); this.emit(EngineEvent.Restarting); if (this.client.isConnected) { await this.client.sendLeave(); } await this.client.close(); this.primaryPC = undefined; (_a = this.publisher) === null || _a === void 0 ? void 0 : _a.close(); this.publisher = undefined; (_b = this.subscriber) === null || _b === void 0 ? void 0 : _b.close(); this.subscriber = undefined; let joinResponse; try { if (!this.signalOpts) { livekitLogger.warn('attempted connection restart, without signal options present'); throw new SignalReconnectError(); } joinResponse = await this.join(this.url, this.token, this.signalOpts); } catch (e) { throw new SignalReconnectError(); } if (this.shouldFailNext) { this.shouldFailNext = false; throw new Error('simulated failure'); } await this.waitForPCConnected(); this.client.setReconnected(); // reconnect success this.emit(EngineEvent.Restarted, joinResponse); } async resumeConnection(reason) { var _a; if (!this.url || !this.token) { // permanent failure, don't attempt reconnection throw new UnexpectedConnectionState('could not reconnect, url or token not saved'); } // trigger publisher reconnect if (!this.publisher || !this.subscriber) { throw new UnexpectedConnectionState('publisher and subscriber connections unset'); } livekitLogger.info("resuming signal connection, attempt ".concat(this.reconnectAttempts)); this.emit(EngineEvent.Resuming); try { const res = await this.client.reconnect(this.url, this.token, this.participantSid, reason); if (res) { const rtcConfig = this.makeRTCConfiguration(res); this.publisher.pc.setConfiguration(rtcConfig); this.subscriber.pc.setConfiguration(rtcConfig); } } catch (e) { let message = ''; if (e instanceof Error) { message = e.message; } throw new SignalReconnectError(message); } this.emit(EngineEvent.SignalResumed); if (this.shouldFailNext) { this.shouldFailNext = false; throw new Error('simulated failure'); } this.subscriber.restartingIce = true; // only restart publisher if it's needed if (this.hasPublished) { await this.publisher.createAndSendOffer({ iceRestart: true }); } await this.waitForPCConnected(); this.client.setReconnected(); // recreate publish datachannel if it's id is null // (for safari https://bugs.webkit.org/show_bug.cgi?id=184688) if (((_a = this.reliableDC) === null || _a === void 0 ? void 0 : _a.readyState) === 'open' && this.reliableDC.id === null) { this.createDataChannels(); } // resume success this.emit(EngineEvent.Resumed); } async waitForPCConnected() { var _a; const startTime = Date.now(); let now = startTime; this.pcState = PCState.Reconnecting; livekitLogger.debug('waiting for peer connection to reconnect'); while (now - startTime < this.peerConnectionTimeout) { if (this.primaryPC === undefined) { // we can abort early, connection is hosed break; } else if ( // on Safari, we don't get a connectionstatechanged event during ICE restart // this means we'd have to check its status manually and update address // manually now - startTime > minReconnectWait && ((_a = this.primaryPC) === null || _a === void 0 ? void 0 : _a.connectionState) === 'connected') { this.pcState = PCState.Connected; } if (this.pcState === PCState.Connected) { return; } await sleep(100); now = Date.now(); } // have not reconnected, throw throw new ConnectionError('could not establish PC connection'); } /* @internal */ async sendDataPacket(packet, kind) { const msg = DataPacket.encode(packet).finish(); // make sure we do have a data connection await this.ensurePublisherConnected(kind); if (kind === DataPacket_Kind.LOSSY && this.lossyDC) { this.lossyDC.send(msg); } else if (kind === DataPacket_Kind.RELIABLE && this.reliableDC) { this.reliableDC.send(msg); } } /** * @internal */ async ensureDataTransportConnected(kind) { let subscriber = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.subscriberPrimary; var _a, _b, _c; const transport = subscriber ? this.subscriber : this.publisher; const transportName = subscriber ? 'Subscriber' : 'Publisher'; if (!transport) { throw new ConnectionError("".concat(transportName, " connection not set")); } if (!subscriber && !((_a = this.publisher) === null || _a === void 0 ? void 0 : _a.isICEConnected) && ((_b = this.publisher) === null || _b === void 0 ? void 0 : _b.pc.iceConnectionState) !== 'checking') { // start negotiation this.negotiate(); } const targetChannel = this.dataChannelForKind(kind, subscriber); if ((targetChannel === null || targetChannel === void 0 ? void 0 : targetChannel.readyState) === 'open') { return; } // wait until ICE connected const endTime = new Date().getTime() + this.peerConnectionTimeout; while (new Date().getTime() < endTime) { if (transport.isICEConnected && ((_c = this.dataChannelForKind(kind, subscriber)) === null || _c === void 0 ? void 0 : _c.readyState) === 'open') { return; } await sleep(50); } throw new ConnectionError("could not establish ".concat(transportName, " connection, state: ").concat(transport.pc.iceConnectionState)); } async ensurePublisherConnected(kind) { await this.ensureDataTransportConnected(kind, false); } /** @internal */ negotiate() { // observe signal state return new Promise((resolve, reject) => { if (!this.publisher) { reject(new NegotiationError('publisher is not defined')); return; } this.hasPublished = true; const handleClosed = () => { livekitLogger.debug('engine disconnected while negotiation was ongoing'); cleanup(); resolve(); return; }; this.on(EngineEvent.Closing, handleClosed); const negotiationTimeout = setTimeout(() => { reject('negotiation timed out'); this.handleDisconnect('negotiation', ReconnectReason.RR_SIGNAL_DISCONNECTED); }, this.peerConnectionTimeout); const cleanup = () => { clearTimeout(negotiationTimeout); this.off(EngineEvent.Closing, handleClosed); }; this.publisher.once(PCEvents.NegotiationStarted, () => { var _a; (_a = this.publisher) === null || _a === void 0 ? void 0 : _a.once(PCEvents.NegotiationComplete, () => { cleanup(); resolve(); }); }); this.publisher.negotiate(e => { cleanup(); reject(e); if (e instanceof NegotiationError) { this.fullReconnectOnNext = true; } this.handleDisconnect('negotiation', ReconnectReason.RR_UNKOWN); }); }); } dataChannelForKind(kind, sub) { if (!sub) { if (kind === DataPacket_Kind.LOSSY) { return this.lossyDC; } if (kind === DataPacket_Kind.RELIABLE) { return this.reliableDC; } } else { if (kind === DataPacket_Kind.LOSSY) { return this.lossyDCSub; } if (kind === DataPacket_Kind.RELIABLE) { return this.reliableDCSub; } } } /* @internal */ failNext() { // debugging method to fail the next reconnect/resume attempt this.shouldFailNext = true; } clearReconnectTimeout() { if (this.reconnectTimeout) { CriticalTimers.clearTimeout(this.reconnectTimeout); } } clearPendingReconnect() { this.clearReconnectTimeout(); this.reconnectAttempts = 0; } registerOnLineListener() { if (isWeb()) { window.addEventListener('online', this.handleBrowserOnLine); } } deregisterOnLineListener() { if (isWeb()) { window.removeEventListener('online', this.handleBrowserOnLine); } } } async function getConnectedAddress(pc) { var _a; let selectedCandidatePairId = ''; const candidatePairs = new Map(); // id -> candidate ip const candidates = new Map(); const stats = await pc.getStats(); stats.forEach(v => { switch (v.type) { case 'transport': selectedCandidatePairId = v.selectedCandidatePairId; break; case 'candidate-pair': if (selectedCandidatePairId === '' && v.selected) { selectedCandidatePairId = v.id; } candidatePairs.set(v.id, v); break; case 'remote-candidate': candidates.set(v.id, "".concat(v.address, ":").concat(v.port)); break; } }); if (selectedCandidatePairId === '') { return undefined; } const selectedID = (_a = candidatePairs.get(selectedCandidatePairId)) === null || _a === void 0 ? void 0 : _a.remoteCandidateId; if (selectedID === undefined) { return undefined; } return candidates.get(selectedID); } class SignalReconnectError extends Error {} var ConnectionState; (function (ConnectionState) { ConnectionState["Disconnected"] = "disconnected"; ConnectionState["Connecting"] = "connecting"; ConnectionState["Connected"] = "connected"; ConnectionState["Reconnecting"] = "reconnecting"; })(ConnectionState || (ConnectionState = {})); /** @deprecated RoomState has been renamed to [[ConnectionState]] */ const RoomState = ConnectionState; /** * In LiveKit, a room is the logical grouping for a list of participants. * Participants in a room can publish tracks, and subscribe to others' tracks. * * a Room fires [[RoomEvent | RoomEvents]]. * * @noInheritDoc */ class Room extends eventsExports.EventEmitter { /** * Creates a new Room, the primary construct for a LiveKit session. * @param options */ constructor(options) { var _this; super(); _this = this; this.state = ConnectionState.Disconnected; /** * list of participants that are actively speaking. when this changes * a [[RoomEvent.ActiveSpeakersChanged]] event is fired */ this.activeSpeakers = []; // available after connected /** server assigned unique room id */ this.sid = ''; /** user assigned name, derived from JWT token */ this.name = ''; /** room metadata */ this.metadata = undefined; this._isRecording = false; this.audioEnabled = true; this.connect = async (url, token, opts) => { // In case a disconnect called happened right before the connect call, make sure the disconnect is completed first by awaiting its lock const unlockDisconnect = await this.disconnectLock.lock(); if (this.state === ConnectionState.Connected) { // when the state is reconnecting or connected, this function returns immediately livekitLogger.info("already connected to room ".concat(this.name)); unlockDisconnect(); return Promise.resolve(); } if (this.connectFuture) { unlockDisconnect(); return this.connectFuture.promise; } this.setAndEmitConnectionState(ConnectionState.Connecting); const connectFn = async (resolve, reject) => { var _a, _b; if (!this.abortController || this.abortController.signal.aborted) { this.abortController = new AbortController(); } // at this point the intention to connect has been signalled so we can allow cancelling of the connection via disconnect() again unlockDisconnect(); if (this.state === ConnectionState.Reconnecting) { livekitLogger.info('Reconnection attempt replaced by new connection attempt'); // make sure we close and recreate the existing engine in order to get rid of any potentially ongoing reconnection attempts this.recreateEngine(); } else { // create engine if previously disconnected this.maybeCreateEngine(); } this.acquireAudioContext(); this.connOptions = _objectSpread2(_objectSpread2({}, roomConnectOptionDefaults), opts); if (this.connOptions.rtcConfig) { this.engine.rtcConfig = this.connOptions.rtcConfig; } if (this.connOptions.peerConnectionTimeout) { this.engine.peerConnectionTimeout = this.connOptions.peerConnectionTimeout; } try { const joinResponse = await this.engine.join(url, token, { autoSubscribe: this.connOptions.autoSubscribe, publishOnly: this.connOptions.publishOnly, adaptiveStream: typeof this.options.adaptiveStream === 'object' ? true : this.options.adaptiveStream, maxRetries: this.connOptions.maxRetries }, this.abortController.signal); let serverInfo = joinResponse.serverInfo; if (!serverInfo) { serverInfo = { version: joinResponse.serverVersion, region: joinResponse.serverRegion }; } livekitLogger.debug("connected to Livekit Server ".concat(Object.entries(serverInfo).map(_ref => { let [key, value] = _ref; return "".concat(key, ": ").concat(value); }).join(', '))); if (!joinResponse.serverVersion) { throw new UnsupportedServer('unknown server version'); } if (joinResponse.serverVersion === '0.15.1' && this.options.dynacast) { livekitLogger.debug('disabling dynacast due to server version'); // dynacast has a bug in 0.15.1, so we cannot use it then this.options.dynacast = false; } const pi = joinResponse.participant; this.localParticipant.sid = pi.sid; this.localParticipant.identity = pi.identity; this.localParticipant.updateInfo(pi); // forward metadata changed for the local participant this.setupLocalParticipantEvents(); // populate remote participants, these should not trigger new events joinResponse.otherParticipants.forEach(info => { if (info.sid !== this.localParticipant.sid && info.identity !== this.localParticipant.identity) { this.getOrCreateParticipant(info.sid, info); } else { livekitLogger.warn('received info to create local participant as remote participant', { info, localParticipant: this.localParticipant }); } }); this.name = joinResponse.room.name; this.sid = joinResponse.room.sid; this.metadata = joinResponse.room.metadata; if (this._isRecording !== joinResponse.room.activeRecording) { this._isRecording = joinResponse.room.activeRecording; this.emit(RoomEvent.RecordingStatusChanged, joinResponse.room.activeRecording); } this.emit(RoomEvent.SignalConnected); } catch (err) { this.recreateEngine(); this.handleDisconnect(this.options.stopLocalTrackOnUnpublish); const resultingError = new ConnectionError("could not establish signal connection"); if (err instanceof Error) { resultingError.message = "".concat(resultingError.message, ": ").concat(err.message); } if (err instanceof ConnectionError) { resultingError.reason = err.reason; resultingError.status = err.status; } livekitLogger.debug("error trying to establish signal connection", { error: err }); reject(resultingError); return; } // don't return until ICE connected const connectTimeout = CriticalTimers.setTimeout(() => { // timeout this.recreateEngine(); this.handleDisconnect(this.options.stopLocalTrackOnUnpublish); reject(new ConnectionError('could not connect PeerConnection after timeout')); }, this.connOptions.peerConnectionTimeout); const abortHandler = () => { livekitLogger.warn('closing engine'); CriticalTimers.clearTimeout(connectTimeout); this.recreateEngine(); this.handleDisconnect(this.options.stopLocalTrackOnUnpublish); reject(new ConnectionError('room connection has been cancelled')); }; if ((_a = this.abortController) === null || _a === void 0 ? void 0 : _a.signal.aborted) { abortHandler(); } (_b = this.abortController) === null || _b === void 0 ? void 0 : _b.signal.addEventListener('abort', abortHandler); this.engine.once(EngineEvent.Connected, () => { var _a, _b; CriticalTimers.clearTimeout(connectTimeout); (_a = this.abortController) === null || _a === void 0 ? void 0 : _a.signal.removeEventListener('abort', abortHandler); // also hook unload event if (isWeb() && this.options.disconnectOnPageLeave) { // capturing both 'pagehide' and 'beforeunload' to capture broadest set of browser behaviors window.addEventListener('pagehide', this.onPageLeave); window.addEventListener('beforeunload', this.onPageLeave); (_b = navigator.mediaDevices) === null || _b === void 0 ? void 0 : _b.addEventListener('devicechange', this.handleDeviceChange); } this.setAndEmitConnectionState(ConnectionState.Connected); this.emit(RoomEvent.Connected); resolve(); }); }; this.connectFuture = new Future(connectFn, () => { this.clearConnectionFutures(); }); return this.connectFuture.promise; }; /** * disconnects the room, emits [[RoomEvent.Disconnected]] */ this.disconnect = async function () { let stopTracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; var _a, _b, _c, _d; const unlock = await _this.disconnectLock.lock(); try { if (_this.state === ConnectionState.Disconnected) { livekitLogger.debug('already disconnected'); return; } livekitLogger.info('disconnect from room', { identity: _this.localParticipant.identity }); if (_this.state === ConnectionState.Connecting || _this.state === ConnectionState.Reconnecting) { // try aborting pending connection attempt livekitLogger.warn('abort connection attempt'); (_a = _this.abortController) === null || _a === void 0 ? void 0 : _a.abort(); // in case the abort controller didn't manage to cancel the connection attempt, reject the connect promise explicitly (_c = (_b = _this.connectFuture) === null || _b === void 0 ? void 0 : _b.reject) === null || _c === void 0 ? void 0 : _c.call(_b, new ConnectionError('Client initiated disconnect')); _this.connectFuture = undefined; } // send leave if ((_d = _this.engine) === null || _d === void 0 ? void 0 : _d.client.isConnected) { await _this.engine.client.sendLeave(); } // close engine (also closes client) if (_this.engine) { await _this.engine.close(); } _this.handleDisconnect(stopTracks, DisconnectReason.CLIENT_INITIATED); /* @ts-ignore */ _this.engine = undefined; } finally { unlock(); } }; this.onPageLeave = async () => { await this.disconnect(); }; this.handleRestarting = () => { // also unwind existing participants & existing subscriptions for (const p of this.participants.values()) { this.handleParticipantDisconnected(p.sid, p); } if (this.setAndEmitConnectionState(ConnectionState.Reconnecting)) { this.emit(RoomEvent.Reconnecting); } }; this.handleRestarted = async joinResponse => { livekitLogger.debug("reconnected to server", { region: joinResponse.serverRegion }); try { // rehydrate participants if (joinResponse.participant) { // with a restart, the sid will have changed, we'll map our understanding to it this.localParticipant.sid = joinResponse.participant.sid; this.handleParticipantUpdates([joinResponse.participant]); } this.handleParticipantUpdates(joinResponse.otherParticipants); // unpublish & republish tracks const localPubs = []; this.localParticipant.tracks.forEach(pub => { if (pub.track) { localPubs.push(pub); } }); await Promise.all(localPubs.map(async pub => { const track = pub.track; this.localParticipant.unpublishTrack(track, false); if (!track.isMuted) { if ((track instanceof LocalAudioTrack || track instanceof LocalVideoTrack) && !track.isUserProvided) { // we need to restart the track before publishing, often a full reconnect // is necessary because computer had gone to sleep. livekitLogger.debug('restarting existing track', { track: pub.trackSid }); await track.restartTrack(); } livekitLogger.debug('publishing new track', { track: pub.trackSid }); await this.localParticipant.publishTrack(track, pub.options); } })); } catch (error) { livekitLogger.error('error trying to re-publish tracks after reconnection', { error }); } finally { this.setAndEmitConnectionState(ConnectionState.Connected); this.emit(RoomEvent.Reconnected); } }; this.handleParticipantUpdates = participantInfos => { // handle changes to participant state, and send events participantInfos.forEach(info => { if (info.identity === this.localParticipant.identity) { this.localParticipant.updateInfo(info); return; } // ensure identity <=> sid mapping const sid = this.identityToSid.get(info.identity); if (sid && sid !== info.sid) { // sid had changed, need to remove previous participant this.handleParticipantDisconnected(sid, this.participants.get(sid)); } let remoteParticipant = this.participants.get(info.sid); const isNewParticipant = !remoteParticipant; // when it's disconnected, send updates if (info.state === ParticipantInfo_State.DISCONNECTED) { this.handleParticipantDisconnected(info.sid, remoteParticipant); } else { // create participant if doesn't exist remoteParticipant = this.getOrCreateParticipant(info.sid, info); if (!isNewParticipant) { // just update, no events remoteParticipant.updateInfo(info); } } }); }; // updates are sent only when there's a change to speaker ordering this.handleActiveSpeakersUpdate = speakers => { const activeSpeakers = []; const seenSids = {}; speakers.forEach(speaker => { seenSids[speaker.sid] = true; if (speaker.sid === this.localParticipant.sid) { this.localParticipant.audioLevel = speaker.level; this.localParticipant.setIsSpeaking(true); activeSpeakers.push(this.localParticipant); } else { const p = this.participants.get(speaker.sid); if (p) { p.audioLevel = speaker.level; p.setIsSpeaking(true); activeSpeakers.push(p); } } }); if (!seenSids[this.localParticipant.sid]) { this.localParticipant.audioLevel = 0; this.localParticipant.setIsSpeaking(false); } this.participants.forEach(p => { if (!seenSids[p.sid]) { p.audioLevel = 0; p.setIsSpeaking(false); } }); this.activeSpeakers = activeSpeakers; this.emitWhenConnected(RoomEvent.ActiveSpeakersChanged, activeSpeakers); }; // process list of changed speakers this.handleSpeakersChanged = speakerUpdates => { const lastSpeakers = new Map(); this.activeSpeakers.forEach(p => { lastSpeakers.set(p.sid, p); }); speakerUpdates.forEach(speaker => { let p = this.participants.get(speaker.sid); if (speaker.sid === this.localParticipant.sid) { p = this.localParticipant; } if (!p) { return; } p.audioLevel = speaker.level; p.setIsSpeaking(speaker.active); if (speaker.active) { lastSpeakers.set(speaker.sid, p); } else { lastSpeakers.delete(speaker.sid); } }); const activeSpeakers = Array.from(lastSpeakers.values()); activeSpeakers.sort((a, b) => b.audioLevel - a.audioLevel); this.activeSpeakers = activeSpeakers; this.emitWhenConnected(RoomEvent.ActiveSpeakersChanged, activeSpeakers); }; this.handleStreamStateUpdate = streamStateUpdate => { streamStateUpdate.streamStates.forEach(streamState => { const participant = this.participants.get(streamState.participantSid); if (!participant) { return; } const pub = participant.getTrackPublication(streamState.trackSid); if (!pub || !pub.track) { return; } pub.track.streamState = Track.streamStateFromProto(streamState.state); participant.emit(ParticipantEvent.TrackStreamStateChanged, pub, pub.track.streamState); this.emitWhenConnected(RoomEvent.TrackStreamStateChanged, pub, pub.track.streamState, participant); }); }; this.handleSubscriptionPermissionUpdate = update => { const participant = this.participants.get(update.participantSid); if (!participant) { return; } const pub = participant.getTrackPublication(update.trackSid); if (!pub) { return; } pub.setAllowed(update.allowed); }; this.handleDataPacket = (userPacket, kind) => { // find the participant const participant = this.participants.get(userPacket.participantSid); this.emit(RoomEvent.DataReceived, userPacket.payload, participant, kind, userPacket.topic); // also emit on the participant participant === null || participant === void 0 ? void 0 : participant.emit(ParticipantEvent.DataReceived, userPacket.payload, kind); }; this.handleAudioPlaybackStarted = () => { if (this.canPlaybackAudio) { return; } this.audioEnabled = true; this.emit(RoomEvent.AudioPlaybackStatusChanged, true); }; this.handleAudioPlaybackFailed = e => { livekitLogger.warn('could not playback audio', e); if (!this.canPlaybackAudio) { return; } this.audioEnabled = false; this.emit(RoomEvent.AudioPlaybackStatusChanged, false); }; this.handleDeviceChange = async () => { this.emit(RoomEvent.MediaDevicesChanged); }; this.handleRoomUpdate = r => { if (this._isRecording !== r.activeRecording) { this._isRecording = r.activeRecording; this.emit(RoomEvent.RecordingStatusChanged, r.activeRecording); } if (this.metadata !== r.metadata) { this.metadata = r.metadata; this.emitWhenConnected(RoomEvent.RoomMetadataChanged, r.metadata); } }; this.handleConnectionQualityUpdate = update => { update.updates.forEach(info => { if (info.participantSid === this.localParticipant.sid) { this.localParticipant.setConnectionQuality(info.quality); return; } const participant = this.participants.get(info.participantSid); if (participant) { participant.setConnectionQuality(info.quality); } }); }; this.onLocalParticipantMetadataChanged = metadata => { this.emit(RoomEvent.ParticipantMetadataChanged, metadata, this.localParticipant); }; this.onLocalTrackMuted = pub => { this.emit(RoomEvent.TrackMuted, pub, this.localParticipant); }; this.onLocalTrackUnmuted = pub => { this.emit(RoomEvent.TrackUnmuted, pub, this.localParticipant); }; this.onLocalTrackPublished = async pub => { this.emit(RoomEvent.LocalTrackPublished, pub, this.localParticipant); if (pub.track instanceof LocalAudioTrack) { const trackIsSilent = await pub.track.checkForSilence(); if (trackIsSilent) { this.emit(RoomEvent.LocalAudioSilenceDetected, pub); } } }; this.onLocalTrackUnpublished = pub => { this.emit(RoomEvent.LocalTrackUnpublished, pub, this.localParticipant); }; this.onLocalConnectionQualityChanged = quality => { this.emit(RoomEvent.ConnectionQualityChanged, quality, this.localParticipant); }; this.onMediaDevicesError = e => { this.emit(RoomEvent.MediaDevicesError, e); }; this.onLocalParticipantPermissionsChanged = prevPermissions => { this.emit(RoomEvent.ParticipantPermissionsChanged, prevPermissions, this.localParticipant); }; this.setMaxListeners(100); this.participants = new Map(); this.identityToSid = new Map(); this.options = _objectSpread2(_objectSpread2({}, roomOptionDefaults), options); this.options.audioCaptureDefaults = _objectSpread2(_objectSpread2({}, audioDefaults), options === null || options === void 0 ? void 0 : options.audioCaptureDefaults); this.options.videoCaptureDefaults = _objectSpread2(_objectSpread2({}, videoDefaults), options === null || options === void 0 ? void 0 : options.videoCaptureDefaults); this.options.publishDefaults = _objectSpread2(_objectSpread2({}, publishDefaults), options === null || options === void 0 ? void 0 : options.publishDefaults); this.maybeCreateEngine(); this.disconnectLock = new Mutex(); this.localParticipant = new LocalParticipant('', '', this.engine, this.options); } maybeCreateEngine() { if (this.engine) { return; } this.engine = new RTCEngine(this.options); this.engine.client.onParticipantUpdate = this.handleParticipantUpdates; this.engine.client.onRoomUpdate = this.handleRoomUpdate; this.engine.client.onSpeakersChanged = this.handleSpeakersChanged; this.engine.client.onStreamStateUpdate = this.handleStreamStateUpdate; this.engine.client.onSubscriptionPermissionUpdate = this.handleSubscriptionPermissionUpdate; this.engine.client.onConnectionQuality = this.handleConnectionQualityUpdate; this.engine.on(EngineEvent.MediaTrackAdded, (mediaTrack, stream, receiver) => { this.onTrackAdded(mediaTrack, stream, receiver); }).on(EngineEvent.Disconnected, reason => { this.handleDisconnect(this.options.stopLocalTrackOnUnpublish, reason); }).on(EngineEvent.ActiveSpeakersUpdate, this.handleActiveSpeakersUpdate).on(EngineEvent.DataPacketReceived, this.handleDataPacket).on(EngineEvent.Resuming, () => { if (this.setAndEmitConnectionState(ConnectionState.Reconnecting)) { this.emit(RoomEvent.Reconnecting); } }).on(EngineEvent.Resumed, () => { this.setAndEmitConnectionState(ConnectionState.Connected); this.emit(RoomEvent.Reconnected); this.updateSubscriptions(); }).on(EngineEvent.SignalResumed, () => { if (this.state === ConnectionState.Reconnecting) { this.sendSyncState(); } }).on(EngineEvent.Restarting, this.handleRestarting).on(EngineEvent.Restarted, this.handleRestarted); if (this.localParticipant) { this.localParticipant.setupEngine(this.engine); } } /** * getLocalDevices abstracts navigator.mediaDevices.enumerateDevices. * In particular, it handles Chrome's unique behavior of creating `default` * devices. When encountered, it'll be removed from the list of devices. * The actual default device will be placed at top. * @param kind * @returns a list of available local devices */ static getLocalDevices(kind) { let requestPermissions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; return DeviceManager.getInstance().getDevices(kind, requestPermissions); } /** * prepares the connection to the livekit server by sending a HEAD request in order to * 1. speed up DNS resolution * 2. speed up TLS setup * on the actual connection request * throws an error if server is not reachable after the request timeout * @experimental */ async prepareConnection(url) { await fetch("http".concat(url.substring(2)), { method: 'HEAD' }); } /** * retrieves a participant by identity * @param identity * @returns */ getParticipantByIdentity(identity) { if (this.localParticipant.identity === identity) { return this.localParticipant; } const sid = this.identityToSid.get(identity); if (sid) { return this.participants.get(sid); } } clearConnectionFutures() { this.connectFuture = undefined; } /** * if the current room has a participant with `recorder: true` in its JWT grant **/ get isRecording() { return this._isRecording; } /** * @internal for testing */ async simulateScenario(scenario) { let postAction = () => {}; let req; switch (scenario) { case 'signal-reconnect': await this.engine.client.close(); if (this.engine.client.onClose) { this.engine.client.onClose('simulate disconnect'); } break; case 'speaker': req = SimulateScenario.fromPartial({ scenario: { $case: 'speakerUpdate', speakerUpdate: 3 } }); break; case 'node-failure': req = SimulateScenario.fromPartial({ scenario: { $case: 'nodeFailure', nodeFailure: true } }); break; case 'server-leave': req = SimulateScenario.fromPartial({ scenario: { $case: 'serverLeave', serverLeave: true } }); break; case 'migration': req = SimulateScenario.fromPartial({ scenario: { $case: 'migration', migration: true } }); break; case 'resume-reconnect': this.engine.failNext(); await this.engine.client.close(); if (this.engine.client.onClose) { this.engine.client.onClose('simulate resume-reconnect'); } break; case 'force-tcp': case 'force-tls': req = SimulateScenario.fromPartial({ scenario: { $case: 'switchCandidateProtocol', switchCandidateProtocol: scenario === 'force-tls' ? 2 : 1 } }); postAction = async () => { const onLeave = this.engine.client.onLeave; if (onLeave) { onLeave({ reason: DisconnectReason.CLIENT_INITIATED, canReconnect: true }); } }; break; } if (req) { this.engine.client.sendSimulateScenario(req); postAction(); } } /** * Browsers have different policies regarding audio playback. Most requiring * some form of user interaction (click/tap/etc). * In those cases, audio will be silent until a click/tap triggering one of the following * - `startAudio` * - `getUserMedia` */ async startAudio() { await this.acquireAudioContext(); const elements = []; this.participants.forEach(p => { p.audioTracks.forEach(t => { if (t.track) { t.track.attachedElements.forEach(e => { elements.push(e); }); } }); }); try { await Promise.all(elements.map(e => { e.muted = false; return e.play(); })); this.handleAudioPlaybackStarted(); } catch (err) { this.handleAudioPlaybackFailed(err); throw err; } } /** * Returns true if audio playback is enabled */ get canPlaybackAudio() { return this.audioEnabled; } /** * Returns the active audio output device used in this room. * * Note: to get the active `audioinput` or `videoinput` use [[LocalTrack.getDeviceId()]] * * @return the previously successfully set audio output device ID or an empty string if the default device is used. */ getActiveAudioOutputDevice() { var _a, _b; return (_b = (_a = this.options.audioOutput) === null || _a === void 0 ? void 0 : _a.deviceId) !== null && _b !== void 0 ? _b : ''; } /** * Switches all active devices used in this room to the given device. * * Note: setting AudioOutput is not supported on some browsers. See [setSinkId](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId#browser_compatibility) * * @param kind use `videoinput` for camera track, * `audioinput` for microphone track, * `audiooutput` to set speaker for all incoming audio tracks * @param deviceId */ async switchActiveDevice(kind, deviceId) { let exact = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; var _a; var _b; const deviceConstraint = exact ? { exact: deviceId } : deviceId; if (kind === 'audioinput') { const prevDeviceId = this.options.audioCaptureDefaults.deviceId; this.options.audioCaptureDefaults.deviceId = deviceConstraint; const tracks = Array.from(this.localParticipant.audioTracks.values()).filter(track => track.source === Track.Source.Microphone); try { await Promise.all(tracks.map(t => { var _a; return (_a = t.audioTrack) === null || _a === void 0 ? void 0 : _a.setDeviceId(deviceConstraint); })); } catch (e) { this.options.audioCaptureDefaults.deviceId = prevDeviceId; throw e; } } else if (kind === 'videoinput') { const prevDeviceId = this.options.videoCaptureDefaults.deviceId; this.options.videoCaptureDefaults.deviceId = deviceConstraint; const tracks = Array.from(this.localParticipant.videoTracks.values()).filter(track => track.source === Track.Source.Camera); try { await Promise.all(tracks.map(t => { var _a; return (_a = t.videoTrack) === null || _a === void 0 ? void 0 : _a.setDeviceId(deviceConstraint); })); } catch (e) { this.options.videoCaptureDefaults.deviceId = prevDeviceId; throw e; } } else if (kind === 'audiooutput') { // TODO add support for webaudio mix once the API becomes available https://github.com/WebAudio/web-audio-api/pull/2498 if (!supportsSetSinkId()) { throw new Error('cannot switch audio output, setSinkId not supported'); } (_a = (_b = this.options).audioOutput) !== null && _a !== void 0 ? _a : _b.audioOutput = {}; const prevDeviceId = this.options.audioOutput.deviceId; this.options.audioOutput.deviceId = deviceId; try { await Promise.all(Array.from(this.participants.values()).map(p => p.setAudioOutput({ deviceId }))); } catch (e) { this.options.audioOutput.deviceId = prevDeviceId; throw e; } } } setupLocalParticipantEvents() { this.localParticipant.on(ParticipantEvent.ParticipantMetadataChanged, this.onLocalParticipantMetadataChanged).on(ParticipantEvent.TrackMuted, this.onLocalTrackMuted).on(ParticipantEvent.TrackUnmuted, this.onLocalTrackUnmuted).on(ParticipantEvent.LocalTrackPublished, this.onLocalTrackPublished).on(ParticipantEvent.LocalTrackUnpublished, this.onLocalTrackUnpublished).on(ParticipantEvent.ConnectionQualityChanged, this.onLocalConnectionQualityChanged).on(ParticipantEvent.MediaDevicesError, this.onMediaDevicesError).on(ParticipantEvent.ParticipantPermissionsChanged, this.onLocalParticipantPermissionsChanged); } recreateEngine() { var _a; (_a = this.engine) === null || _a === void 0 ? void 0 : _a.close(); /* @ts-ignore */ this.engine = undefined; // clear out existing remote participants, since they may have attached // the old engine this.participants.clear(); this.maybeCreateEngine(); } onTrackAdded(mediaTrack, stream, receiver) { // don't fire onSubscribed when connecting // WebRTC fires onTrack as soon as setRemoteDescription is called on the offer // at that time, ICE connectivity has not been established so the track is not // technically subscribed. // We'll defer these events until when the room is connected or eventually disconnected. if (this.state === ConnectionState.Connecting || this.state === ConnectionState.Reconnecting) { const reconnectedHandler = () => { this.onTrackAdded(mediaTrack, stream, receiver); cleanup(); }; const cleanup = () => { this.off(RoomEvent.Reconnected, reconnectedHandler); this.off(RoomEvent.Connected, reconnectedHandler); this.off(RoomEvent.Disconnected, cleanup); }; this.once(RoomEvent.Reconnected, reconnectedHandler); this.once(RoomEvent.Connected, reconnectedHandler); this.once(RoomEvent.Disconnected, cleanup); return; } if (this.state === ConnectionState.Disconnected) { livekitLogger.warn('skipping incoming track after Room disconnected'); return; } const parts = unpackStreamId(stream.id); const participantId = parts[0]; let trackId = parts[1]; if (!trackId || trackId === '') trackId = mediaTrack.id; if (participantId === this.localParticipant.sid) { livekitLogger.warn('tried to create RemoteParticipant for local participant'); return; } const participant = this.getOrCreateParticipant(participantId); let adaptiveStreamSettings; if (this.options.adaptiveStream) { if (typeof this.options.adaptiveStream === 'object') { adaptiveStreamSettings = this.options.adaptiveStream; } else { adaptiveStreamSettings = {}; } } participant.addSubscribedMediaTrack(mediaTrack, trackId, stream, receiver, adaptiveStreamSettings); } handleDisconnect() { let shouldStopTracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; let reason = arguments.length > 1 ? arguments[1] : undefined; var _a; if (this.state === ConnectionState.Disconnected) { return; } this.participants.forEach(p => { p.tracks.forEach(pub => { p.unpublishTrack(pub.trackSid); }); }); this.localParticipant.tracks.forEach(pub => { var _a, _b; if (pub.track) { this.localParticipant.unpublishTrack(pub.track, shouldStopTracks); } if (shouldStopTracks) { (_a = pub.track) === null || _a === void 0 ? void 0 : _a.detach(); (_b = pub.track) === null || _b === void 0 ? void 0 : _b.stop(); } }); this.localParticipant.off(ParticipantEvent.ParticipantMetadataChanged, this.onLocalParticipantMetadataChanged).off(ParticipantEvent.TrackMuted, this.onLocalTrackMuted).off(ParticipantEvent.TrackUnmuted, this.onLocalTrackUnmuted).off(ParticipantEvent.LocalTrackPublished, this.onLocalTrackPublished).off(ParticipantEvent.LocalTrackUnpublished, this.onLocalTrackUnpublished).off(ParticipantEvent.ConnectionQualityChanged, this.onLocalConnectionQualityChanged).off(ParticipantEvent.MediaDevicesError, this.onMediaDevicesError).off(ParticipantEvent.ParticipantPermissionsChanged, this.onLocalParticipantPermissionsChanged); this.localParticipant.tracks.clear(); this.localParticipant.videoTracks.clear(); this.localParticipant.audioTracks.clear(); this.participants.clear(); this.activeSpeakers = []; if (this.audioContext && typeof this.options.expWebAudioMix === 'boolean') { this.audioContext.close(); this.audioContext = undefined; } if (isWeb()) { window.removeEventListener('beforeunload', this.onPageLeave); window.removeEventListener('pagehide', this.onPageLeave); (_a = navigator.mediaDevices) === null || _a === void 0 ? void 0 : _a.removeEventListener('devicechange', this.handleDeviceChange); } this.setAndEmitConnectionState(ConnectionState.Disconnected); this.emit(RoomEvent.Disconnected, reason); } handleParticipantDisconnected(sid, participant) { // remove and send event this.participants.delete(sid); if (!participant) { return; } this.identityToSid.delete(participant.identity); participant.tracks.forEach(publication => { participant.unpublishTrack(publication.trackSid, true); }); this.emit(RoomEvent.ParticipantDisconnected, participant); } async acquireAudioContext() { var _a, _b; if (typeof this.options.expWebAudioMix !== 'boolean' && this.options.expWebAudioMix.audioContext) { // override audio context with custom audio context if supplied by user this.audioContext = this.options.expWebAudioMix.audioContext; await this.audioContext.resume(); } else { // by using an AudioContext, it reduces lag on audio elements // https://stackoverflow.com/questions/9811429/html5-audio-tag-on-safari-has-a-delay/54119854#54119854 this.audioContext = (_a = getNewAudioContext()) !== null && _a !== void 0 ? _a : undefined; } if (this.options.expWebAudioMix) { this.participants.forEach(participant => participant.setAudioContext(this.audioContext)); } const newContextIsRunning = ((_b = this.audioContext) === null || _b === void 0 ? void 0 : _b.state) === 'running'; if (newContextIsRunning !== this.canPlaybackAudio) { this.audioEnabled = newContextIsRunning; this.emit(RoomEvent.AudioPlaybackStatusChanged, newContextIsRunning); } } createParticipant(id, info) { let participant; if (info) { participant = RemoteParticipant.fromParticipantInfo(this.engine.client, info); } else { participant = new RemoteParticipant(this.engine.client, id, '', undefined, undefined); } if (this.options.expWebAudioMix) { participant.setAudioContext(this.audioContext); } return participant; } getOrCreateParticipant(id, info) { if (this.participants.has(id)) { return this.participants.get(id); } // it's possible for the RTC track to arrive before signaling data // when this happens, we'll create the participant and make the track work const participant = this.createParticipant(id, info); this.participants.set(id, participant); if (info) { this.identityToSid.set(info.identity, info.sid); // if we have valid info and the participant wasn't in the map before, we can assume the participant is new // firing here to make sure that `ParticipantConnected` fires before the initial track events this.emitWhenConnected(RoomEvent.ParticipantConnected, participant); } // also forward events // trackPublished is only fired for tracks added after both local participant // and remote participant joined the room participant.on(ParticipantEvent.TrackPublished, trackPublication => { this.emitWhenConnected(RoomEvent.TrackPublished, trackPublication, participant); }).on(ParticipantEvent.TrackSubscribed, (track, publication) => { // monitor playback status if (track.kind === Track.Kind.Audio) { track.on(TrackEvent.AudioPlaybackStarted, this.handleAudioPlaybackStarted); track.on(TrackEvent.AudioPlaybackFailed, this.handleAudioPlaybackFailed); } this.emit(RoomEvent.TrackSubscribed, track, publication, participant); }).on(ParticipantEvent.TrackUnpublished, publication => { this.emit(RoomEvent.TrackUnpublished, publication, participant); }).on(ParticipantEvent.TrackUnsubscribed, (track, publication) => { this.emit(RoomEvent.TrackUnsubscribed, track, publication, participant); }).on(ParticipantEvent.TrackSubscriptionFailed, sid => { this.emit(RoomEvent.TrackSubscriptionFailed, sid, participant); }).on(ParticipantEvent.TrackMuted, pub => { this.emitWhenConnected(RoomEvent.TrackMuted, pub, participant); }).on(ParticipantEvent.TrackUnmuted, pub => { this.emitWhenConnected(RoomEvent.TrackUnmuted, pub, participant); }).on(ParticipantEvent.ParticipantMetadataChanged, metadata => { this.emitWhenConnected(RoomEvent.ParticipantMetadataChanged, metadata, participant); }).on(ParticipantEvent.ConnectionQualityChanged, quality => { this.emitWhenConnected(RoomEvent.ConnectionQualityChanged, quality, participant); }).on(ParticipantEvent.ParticipantPermissionsChanged, prevPermissions => { this.emitWhenConnected(RoomEvent.ParticipantPermissionsChanged, prevPermissions, participant); }).on(ParticipantEvent.TrackSubscriptionStatusChanged, (pub, status) => { this.emitWhenConnected(RoomEvent.TrackSubscriptionStatusChanged, pub, status, participant); }).on(ParticipantEvent.TrackSubscriptionPermissionChanged, (pub, status) => { this.emitWhenConnected(RoomEvent.TrackSubscriptionPermissionChanged, pub, status, participant); }); // update info at the end after callbacks have been set up if (info) { participant.updateInfo(info); } return participant; } sendSyncState() { var _a, _b; if (this.engine.subscriber === undefined || this.engine.subscriber.pc.localDescription === null) { return; } const previousAnswer = this.engine.subscriber.pc.localDescription; const previousOffer = this.engine.subscriber.pc.remoteDescription; /* 1. autosubscribe on, so subscribed tracks = all tracks - unsub tracks, in this case, we send unsub tracks, so server add all tracks to this subscribe pc and unsub special tracks from it. 2. autosubscribe off, we send subscribed tracks. */ const autoSubscribe = (_b = (_a = this.connOptions) === null || _a === void 0 ? void 0 : _a.autoSubscribe) !== null && _b !== void 0 ? _b : true; const trackSids = new Array(); this.participants.forEach(participant => { participant.tracks.forEach(track => { if (track.isDesired !== autoSubscribe) { trackSids.push(track.trackSid); } }); }); this.engine.client.sendSyncState({ answer: toProtoSessionDescription({ sdp: previousAnswer.sdp, type: previousAnswer.type }), offer: previousOffer ? toProtoSessionDescription({ sdp: previousOffer.sdp, type: previousOffer.type }) : undefined, subscription: { trackSids, subscribe: !autoSubscribe, participantTracks: [] }, publishTracks: this.localParticipant.publishedTracksInfo(), dataChannels: this.localParticipant.dataChannelsInfo() }); } /** * After resuming, we'll need to notify the server of the current * subscription settings. */ updateSubscriptions() { for (const p of this.participants.values()) { for (const pub of p.videoTracks.values()) { if (pub.isSubscribed && pub instanceof RemoteTrackPublication) { pub.emitTrackUpdate(); } } } } setAndEmitConnectionState(state) { if (state === this.state) { // unchanged return false; } this.state = state; this.emit(RoomEvent.ConnectionStateChanged, this.state); return true; } emitWhenConnected(event) { if (this.state === ConnectionState.Connected) { for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { args[_key - 1] = arguments[_key]; } return this.emit(event, ...args); } return false; } /** * Allows to populate a room with simulated participants. * No actual connection to a server will be established, all state is * @experimental */ async simulateParticipants(options) { var _a, _b; const publishOptions = _objectSpread2({ audio: true, video: true, useRealTracks: false }, options.publish); const participantOptions = _objectSpread2({ count: 9, audio: false, video: true, aspectRatios: [1.66, 1.7, 1.3] }, options.participants); this.handleDisconnect(); this.name = 'simulated-room'; this.localParticipant.updateInfo(ParticipantInfo.fromPartial({ identity: 'simulated-local', name: 'local-name' })); this.setupLocalParticipantEvents(); this.emit(RoomEvent.SignalConnected); this.emit(RoomEvent.Connected); this.setAndEmitConnectionState(ConnectionState.Connected); if (publishOptions.video) { const camPub = new LocalTrackPublication(Track.Kind.Video, TrackInfo.fromPartial({ source: TrackSource.CAMERA, sid: Math.floor(Math.random() * 10000).toString(), type: TrackType.AUDIO, name: 'video-dummy' }), new LocalVideoTrack(publishOptions.useRealTracks ? (await navigator.mediaDevices.getUserMedia({ video: true })).getVideoTracks()[0] : createDummyVideoStreamTrack((_a = 160 * participantOptions.aspectRatios[0]) !== null && _a !== void 0 ? _a : 1, 160, true, true))); // @ts-ignore this.localParticipant.addTrackPublication(camPub); this.localParticipant.emit(ParticipantEvent.LocalTrackPublished, camPub); } if (publishOptions.audio) { const audioPub = new LocalTrackPublication(Track.Kind.Audio, TrackInfo.fromPartial({ source: TrackSource.MICROPHONE, sid: Math.floor(Math.random() * 10000).toString(), type: TrackType.AUDIO }), new LocalAudioTrack(publishOptions.useRealTracks ? (await navigator.mediaDevices.getUserMedia({ audio: true })).getAudioTracks()[0] : getEmptyAudioStreamTrack())); // @ts-ignore this.localParticipant.addTrackPublication(audioPub); this.localParticipant.emit(ParticipantEvent.LocalTrackPublished, audioPub); } for (let i = 0; i < participantOptions.count - 1; i += 1) { let info = ParticipantInfo.fromPartial({ sid: Math.floor(Math.random() * 10000).toString(), identity: "simulated-".concat(i), state: ParticipantInfo_State.ACTIVE, tracks: [], joinedAt: Date.now() }); const p = this.getOrCreateParticipant(info.identity, info); if (participantOptions.video) { const dummyVideo = createDummyVideoStreamTrack((_b = 160 * participantOptions.aspectRatios[i % participantOptions.aspectRatios.length]) !== null && _b !== void 0 ? _b : 1, 160, false, true); const videoTrack = TrackInfo.fromPartial({ source: TrackSource.CAMERA, sid: Math.floor(Math.random() * 10000).toString(), type: TrackType.AUDIO }); p.addSubscribedMediaTrack(dummyVideo, videoTrack.sid, new MediaStream([dummyVideo])); info.tracks = [...info.tracks, videoTrack]; } if (participantOptions.audio) { const dummyTrack = getEmptyAudioStreamTrack(); const audioTrack = TrackInfo.fromPartial({ source: TrackSource.MICROPHONE, sid: Math.floor(Math.random() * 10000).toString(), type: TrackType.AUDIO }); p.addSubscribedMediaTrack(dummyTrack, audioTrack.sid, new MediaStream([dummyTrack])); info.tracks = [...info.tracks, audioTrack]; } p.updateInfo(info); } } // /** @internal */ emit(event) { for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { args[_key2 - 1] = arguments[_key2]; } // active speaker updates are too spammy if (event !== RoomEvent.ActiveSpeakersChanged) { livekitLogger.debug("room event ".concat(event), { event, args }); } return super.emit(event, ...args); } } /** * Creates a local video and audio track at the same time. When acquiring both * audio and video tracks together, it'll display a single permission prompt to * the user instead of two separate ones. * @param options */ async function createLocalTracks(options) { var _a, _b; // set default options to true options !== null && options !== void 0 ? options : options = {}; (_a = options.audio) !== null && _a !== void 0 ? _a : options.audio = true; (_b = options.video) !== null && _b !== void 0 ? _b : options.video = true; const opts = mergeDefaultOptions(options, audioDefaults, videoDefaults); const constraints = constraintsForOptions(opts); // Keep a reference to the promise on DeviceManager and await it in getLocalDevices() // works around iOS Safari Bug https://bugs.webkit.org/show_bug.cgi?id=179363 const mediaPromise = navigator.mediaDevices.getUserMedia(constraints); if (options.audio) { DeviceManager.userMediaPromiseMap.set('audioinput', mediaPromise); mediaPromise.catch(() => DeviceManager.userMediaPromiseMap.delete('audioinput')); } if (options.video) { DeviceManager.userMediaPromiseMap.set('videoinput', mediaPromise); mediaPromise.catch(() => DeviceManager.userMediaPromiseMap.delete('videoinput')); } const stream = await mediaPromise; return stream.getTracks().map(mediaStreamTrack => { const isAudio = mediaStreamTrack.kind === 'audio'; isAudio ? options.audio : options.video; let trackConstraints; const conOrBool = isAudio ? constraints.audio : constraints.video; if (typeof conOrBool !== 'boolean') { trackConstraints = conOrBool; } const track = mediaTrackToLocalTrack(mediaStreamTrack, trackConstraints); if (track.kind === Track.Kind.Video) { track.source = Track.Source.Camera; } else if (track.kind === Track.Kind.Audio) { track.source = Track.Source.Microphone; } track.mediaStream = stream; return track; }); } /** * Creates a [[LocalVideoTrack]] with getUserMedia() * @param options */ async function createLocalVideoTrack(options) { const tracks = await createLocalTracks({ audio: false, video: options }); return tracks[0]; } async function createLocalAudioTrack(options) { const tracks = await createLocalTracks({ audio: options, video: false }); return tracks[0]; } /** * Creates a screen capture tracks with getDisplayMedia(). * A LocalVideoTrack is always created and returned. * If { audio: true }, and the browser supports audio capture, a LocalAudioTrack is also created. */ async function createLocalScreenTracks(options) { var _a; if (options === undefined) { options = {}; } if (options.resolution === undefined) { options.resolution = VideoPresets.h1080.resolution; } let videoConstraints = true; if (options.resolution) { videoConstraints = { width: options.resolution.width, height: options.resolution.height }; } if (navigator.mediaDevices.getDisplayMedia === undefined) { throw new DeviceUnsupportedError('getDisplayMedia not supported'); } // typescript definition is missing getDisplayMedia: https://github.com/microsoft/TypeScript/issues/33232 // @ts-ignore const stream = await navigator.mediaDevices.getDisplayMedia({ audio: (_a = options.audio) !== null && _a !== void 0 ? _a : false, video: videoConstraints }); const tracks = stream.getVideoTracks(); if (tracks.length === 0) { throw new TrackInvalidError('no video track found'); } const screenVideo = new LocalVideoTrack(tracks[0], undefined, false); screenVideo.source = Track.Source.ScreenShare; const localTracks = [screenVideo]; if (stream.getAudioTracks().length > 0) { const screenAudio = new LocalAudioTrack(stream.getAudioTracks()[0], undefined, false); screenAudio.source = Track.Source.ScreenShareAudio; localTracks.push(screenAudio); } return localTracks; } var CheckStatus; (function (CheckStatus) { CheckStatus[CheckStatus["IDLE"] = 0] = "IDLE"; CheckStatus[CheckStatus["RUNNING"] = 1] = "RUNNING"; CheckStatus[CheckStatus["SKIPPED"] = 2] = "SKIPPED"; CheckStatus[CheckStatus["SUCCESS"] = 3] = "SUCCESS"; CheckStatus[CheckStatus["FAILED"] = 4] = "FAILED"; })(CheckStatus || (CheckStatus = {})); class Checker extends eventsExports.EventEmitter { constructor(url, token) { let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; super(); this.status = CheckStatus.IDLE; this.logs = []; this.errorsAsWarnings = false; this.url = url; this.token = token; this.name = this.constructor.name; this.room = new Room(options.roomOptions); this.connectOptions = options.connectOptions; if (options.errorsAsWarnings) { this.errorsAsWarnings = options.errorsAsWarnings; } } async run(onComplete) { if (this.status !== CheckStatus.IDLE) { throw Error('check is running already'); } this.setStatus(CheckStatus.RUNNING); this.appendMessage("".concat(this.name, " started.")); try { await this.perform(); } catch (err) { if (err instanceof Error) { if (this.errorsAsWarnings) { this.appendWarning(err.message); } else { this.appendError(err.message); } } } await this.disconnect(); // sleep for a bit to ensure disconnect await new Promise(resolve => setTimeout(resolve, 500)); // @ts-ignore if (this.status !== CheckStatus.SKIPPED) { this.setStatus(this.isSuccess() ? CheckStatus.SUCCESS : CheckStatus.FAILED); } if (onComplete) { onComplete(); } return this.getInfo(); } isSuccess() { return !this.logs.some(l => l.level === 'error'); } async connect() { if (this.room.state === ConnectionState.Connected) { return this.room; } await this.room.connect(this.url, this.token); return this.room; } async disconnect() { if (this.room && this.room.state !== ConnectionState.Disconnected) { await this.room.disconnect(); // wait for it to go through await new Promise(resolve => setTimeout(resolve, 500)); } } skip() { this.setStatus(CheckStatus.SKIPPED); } appendMessage(message) { this.logs.push({ level: 'info', message }); this.emit('update', this.getInfo()); } appendWarning(message) { this.logs.push({ level: 'warning', message }); this.emit('update', this.getInfo()); } appendError(message) { this.logs.push({ level: 'error', message }); this.emit('update', this.getInfo()); } setStatus(status) { this.status = status; this.emit('update', this.getInfo()); } get engine() { var _a; return (_a = this.room) === null || _a === void 0 ? void 0 : _a.engine; } getInfo() { return { logs: this.logs, name: this.name, status: this.status, description: this.description }; } } class PublishAudioCheck extends Checker { get description() { return 'Can publish audio'; } async perform() { var _a; const room = await this.connect(); const track = await createLocalAudioTrack(); room.localParticipant.publishTrack(track); // wait for a few seconds to publish await new Promise(resolve => setTimeout(resolve, 3000)); // verify RTC stats that it's publishing const stats = await ((_a = track.sender) === null || _a === void 0 ? void 0 : _a.getStats()); if (!stats) { throw new Error('Could not get RTCStats'); } let numPackets = 0; stats.forEach(stat => { if (stat.type === 'outbound-rtp' && stat.mediaType === 'audio') { numPackets = stat.packetsSent; } }); if (numPackets === 0) { throw new Error('Could not determine packets are sent'); } this.appendMessage("published ".concat(numPackets, " audio packets")); } } class PublishVideoCheck extends Checker { get description() { return 'Can publish video'; } async perform() { var _a; const room = await this.connect(); const track = await createLocalVideoTrack(); room.localParticipant.publishTrack(track); // wait for a few seconds to publish await new Promise(resolve => setTimeout(resolve, 3000)); // verify RTC stats that it's publishing const stats = await ((_a = track.sender) === null || _a === void 0 ? void 0 : _a.getStats()); if (!stats) { throw new Error('Could not get RTCStats'); } let numPackets = 0; stats.forEach(stat => { if (stat.type === 'outbound-rtp' && stat.mediaType === 'video') { numPackets = stat.packetsSent; } }); if (numPackets === 0) { throw new Error('Could not determine packets are sent'); } this.appendMessage("published ".concat(numPackets, " video packets")); } } class ReconnectCheck extends Checker { get description() { return 'Resuming connection after interruption'; } async perform() { var _a; const room = await this.connect(); let reconnectingTriggered = false; let reconnected = false; let reconnectResolver; const reconnectTimeout = new Promise(resolve => { setTimeout(resolve, 5000); reconnectResolver = resolve; }); room.on(RoomEvent.Reconnecting, () => { reconnectingTriggered = true; }).on(RoomEvent.Reconnected, () => { reconnected = true; reconnectResolver(true); }); (_a = room.engine.client.ws) === null || _a === void 0 ? void 0 : _a.close(); const onClose = room.engine.client.onClose; if (onClose) { onClose(''); } await reconnectTimeout; if (!reconnectingTriggered) { throw new Error('Did not attempt to reconnect'); } else if (!reconnected || room.state !== ConnectionState.Connected) { this.appendWarning('reconnection is only possible in Redis-based configurations'); throw new Error('Not able to reconnect'); } } } class TURNCheck extends Checker { get description() { return 'Can connect via TURN'; } async perform() { var _a, _b; const signalClient = new SignalClient(); const joinRes = await signalClient.join(this.url, this.token, { autoSubscribe: true, maxRetries: 0 }); let hasTLS = false; let hasTURN = false; let hasSTUN = false; for (let iceServer of joinRes.iceServers) { for (let url of iceServer.urls) { if (url.startsWith('turn:')) { hasTURN = true; hasSTUN = true; } else if (url.startsWith('turns:')) { hasTURN = true; hasSTUN = true; hasTLS = true; } if (url.startsWith('stun:')) { hasSTUN = true; } } } if (!hasSTUN) { this.appendWarning('No STUN servers configured on server side.'); } else if (hasTURN && !hasTLS) { this.appendWarning('TURN is configured server side, but TURN/TLS is unavailable.'); } await signalClient.close(); if (((_b = (_a = this.connectOptions) === null || _a === void 0 ? void 0 : _a.rtcConfig) === null || _b === void 0 ? void 0 : _b.iceServers) || hasTURN) { await this.room.connect(this.url, this.token, { rtcConfig: { iceTransportPolicy: 'relay' } }); } else { this.appendWarning('No TURN servers configured.'); this.skip(); await new Promise(resolve => setTimeout(resolve, 0)); } } } class WebRTCCheck extends Checker { get description() { return 'Establishing WebRTC connection'; } async perform() { try { console.log('initiating room connection'); this.room = await this.connect(); console.log('now the room is connected'); } catch (err) { this.appendWarning('ports need to be open on firewall in order to connect.'); throw err; } } } class WebSocketCheck extends Checker { get description() { return 'Connecting to signal connection via WebSocket'; } async perform() { if (this.url.startsWith('ws:') || this.url.startsWith('http:')) { this.appendWarning('Server is insecure, clients may block connections to it'); } let signalClient = new SignalClient(); const joinRes = await signalClient.join(this.url, this.token, { autoSubscribe: true, maxRetries: 0 }); this.appendMessage("Connected to server, version ".concat(joinRes.serverVersion, ".")); await signalClient.close(); } } class ConnectionCheck extends eventsExports { constructor(url, token) { super(); this.checkResults = new Map(); this.url = url; this.token = token; } getNextCheckId() { const nextId = this.checkResults.size; this.checkResults.set(nextId, { logs: [], status: CheckStatus.IDLE, name: '', description: '' }); return nextId; } updateCheck(checkId, info) { this.checkResults.set(checkId, info); this.emit('checkUpdate', checkId, info); } isSuccess() { return Array.from(this.checkResults.values()).every(r => r.status !== CheckStatus.FAILED); } getResults() { return Array.from(this.checkResults.values()); } async createAndRunCheck(check) { const checkId = this.getNextCheckId(); const test = new check(this.url, this.token); const handleUpdate = info => { this.updateCheck(checkId, info); }; test.on('update', handleUpdate); const result = await test.run(); test.off('update', handleUpdate); return result; } async checkWebsocket() { return this.createAndRunCheck(WebSocketCheck); } async checkWebRTC() { return this.createAndRunCheck(WebRTCCheck); } async checkTURN() { return this.createAndRunCheck(TURNCheck); } async checkReconnect() { return this.createAndRunCheck(ReconnectCheck); } async checkPublishAudio() { return this.createAndRunCheck(PublishAudioCheck); } async checkPublishVideo() { return this.createAndRunCheck(PublishVideoCheck); } } //# sourceMappingURL=livekit-client.esm.mjs.map /***/ }), /***/ "./node_modules/@firebase/app/dist/esm/index.esm2017.js": /*!**************************************************************!*\ !*** ./node_modules/@firebase/app/dist/esm/index.esm2017.js ***! \**************************************************************/ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "FirebaseError": () => (/* reexport safe */ _firebase_util__WEBPACK_IMPORTED_MODULE_2__.FirebaseError), /* harmony export */ "SDK_VERSION": () => (/* binding */ SDK_VERSION), /* harmony export */ "_DEFAULT_ENTRY_NAME": () => (/* binding */ DEFAULT_ENTRY_NAME), /* harmony export */ "_addComponent": () => (/* binding */ _addComponent), /* harmony export */ "_addOrOverwriteComponent": () => (/* binding */ _addOrOverwriteComponent), /* harmony export */ "_apps": () => (/* binding */ _apps), /* harmony export */ "_clearComponents": () => (/* binding */ _clearComponents), /* harmony export */ "_components": () => (/* binding */ _components), /* harmony export */ "_getProvider": () => (/* binding */ _getProvider), /* harmony export */ "_registerComponent": () => (/* binding */ _registerComponent), /* harmony export */ "_removeServiceInstance": () => (/* binding */ _removeServiceInstance), /* harmony export */ "deleteApp": () => (/* binding */ deleteApp), /* harmony export */ "getApp": () => (/* binding */ getApp), /* harmony export */ "getApps": () => (/* binding */ getApps), /* harmony export */ "initializeApp": () => (/* binding */ initializeApp), /* harmony export */ "onLog": () => (/* binding */ onLog), /* harmony export */ "registerVersion": () => (/* binding */ registerVersion), /* harmony export */ "setLogLevel": () => (/* binding */ setLogLevel) /* harmony export */ }); /* harmony import */ var _firebase_component__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @firebase/component */ "./node_modules/@firebase/component/dist/esm/index.esm2017.js"); /* harmony import */ var _firebase_logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @firebase/logger */ "./node_modules/@firebase/logger/dist/esm/index.esm2017.js"); /* harmony import */ var _firebase_util__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @firebase/util */ "./node_modules/@firebase/util/dist/index.esm2017.js"); /* harmony import */ var idb__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! idb */ "./node_modules/idb/build/index.js"); /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class PlatformLoggerServiceImpl { constructor(container) { this.container = container; } // In initial implementation, this will be called by installations on // auth token refresh, and installations will send this string. getPlatformInfoString() { const providers = this.container.getProviders(); // Loop through providers and get library/version pairs from any that are // version components. return providers .map(provider => { if (isVersionServiceProvider(provider)) { const service = provider.getImmediate(); return `${service.library}/${service.version}`; } else { return null; } }) .filter(logString => logString) .join(' '); } } /** * * @param provider check if this provider provides a VersionService * * NOTE: Using Provider<'app-version'> is a hack to indicate that the provider * provides VersionService. The provider is not necessarily a 'app-version' * provider. */ function isVersionServiceProvider(provider) { const component = provider.getComponent(); return (component === null || component === void 0 ? void 0 : component.type) === "VERSION" /* ComponentType.VERSION */; } const name$o = "@firebase/app"; const version$1 = "0.9.5"; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const logger = new _firebase_logger__WEBPACK_IMPORTED_MODULE_1__.Logger('@firebase/app'); const name$n = "@firebase/app-compat"; const name$m = "@firebase/analytics-compat"; const name$l = "@firebase/analytics"; const name$k = "@firebase/app-check-compat"; const name$j = "@firebase/app-check"; const name$i = "@firebase/auth"; const name$h = "@firebase/auth-compat"; const name$g = "@firebase/database"; const name$f = "@firebase/database-compat"; const name$e = "@firebase/functions"; const name$d = "@firebase/functions-compat"; const name$c = "@firebase/installations"; const name$b = "@firebase/installations-compat"; const name$a = "@firebase/messaging"; const name$9 = "@firebase/messaging-compat"; const name$8 = "@firebase/performance"; const name$7 = "@firebase/performance-compat"; const name$6 = "@firebase/remote-config"; const name$5 = "@firebase/remote-config-compat"; const name$4 = "@firebase/storage"; const name$3 = "@firebase/storage-compat"; const name$2 = "@firebase/firestore"; const name$1 = "@firebase/firestore-compat"; const name = "firebase"; const version = "9.18.0"; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * The default app name * * @internal */ const DEFAULT_ENTRY_NAME = '[DEFAULT]'; const PLATFORM_LOG_STRING = { [name$o]: 'fire-core', [name$n]: 'fire-core-compat', [name$l]: 'fire-analytics', [name$m]: 'fire-analytics-compat', [name$j]: 'fire-app-check', [name$k]: 'fire-app-check-compat', [name$i]: 'fire-auth', [name$h]: 'fire-auth-compat', [name$g]: 'fire-rtdb', [name$f]: 'fire-rtdb-compat', [name$e]: 'fire-fn', [name$d]: 'fire-fn-compat', [name$c]: 'fire-iid', [name$b]: 'fire-iid-compat', [name$a]: 'fire-fcm', [name$9]: 'fire-fcm-compat', [name$8]: 'fire-perf', [name$7]: 'fire-perf-compat', [name$6]: 'fire-rc', [name$5]: 'fire-rc-compat', [name$4]: 'fire-gcs', [name$3]: 'fire-gcs-compat', [name$2]: 'fire-fst', [name$1]: 'fire-fst-compat', 'fire-js': 'fire-js', [name]: 'fire-js-all' }; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @internal */ const _apps = new Map(); /** * Registered components. * * @internal */ // eslint-disable-next-line @typescript-eslint/no-explicit-any const _components = new Map(); /** * @param component - the component being added to this app's container * * @internal */ function _addComponent(app, component) { try { app.container.addComponent(component); } catch (e) { logger.debug(`Component ${component.name} failed to register with FirebaseApp ${app.name}`, e); } } /** * * @internal */ function _addOrOverwriteComponent(app, component) { app.container.addOrOverwriteComponent(component); } /** * * @param component - the component to register * @returns whether or not the component is registered successfully * * @internal */ function _registerComponent(component) { const componentName = component.name; if (_components.has(componentName)) { logger.debug(`There were multiple attempts to register component ${componentName}.`); return false; } _components.set(componentName, component); // add the component to existing app instances for (const app of _apps.values()) { _addComponent(app, component); } return true; } /** * * @param app - FirebaseApp instance * @param name - service name * * @returns the provider for the service with the matching name * * @internal */ function _getProvider(app, name) { const heartbeatController = app.container .getProvider('heartbeat') .getImmediate({ optional: true }); if (heartbeatController) { void heartbeatController.triggerHeartbeat(); } return app.container.getProvider(name); } /** * * @param app - FirebaseApp instance * @param name - service name * @param instanceIdentifier - service instance identifier in case the service supports multiple instances * * @internal */ function _removeServiceInstance(app, name, instanceIdentifier = DEFAULT_ENTRY_NAME) { _getProvider(app, name).clearInstance(instanceIdentifier); } /** * Test only * * @internal */ function _clearComponents() { _components.clear(); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const ERRORS = { ["no-app" /* AppError.NO_APP */]: "No Firebase App '{$appName}' has been created - " + 'call Firebase App.initializeApp()', ["bad-app-name" /* AppError.BAD_APP_NAME */]: "Illegal App name: '{$appName}", ["duplicate-app" /* AppError.DUPLICATE_APP */]: "Firebase App named '{$appName}' already exists with different options or config", ["app-deleted" /* AppError.APP_DELETED */]: "Firebase App named '{$appName}' already deleted", ["no-options" /* AppError.NO_OPTIONS */]: 'Need to provide options, when not being deployed to hosting via source.', ["invalid-app-argument" /* AppError.INVALID_APP_ARGUMENT */]: 'firebase.{$appName}() takes either no argument or a ' + 'Firebase App instance.', ["invalid-log-argument" /* AppError.INVALID_LOG_ARGUMENT */]: 'First argument to `onLog` must be null or a function.', ["idb-open" /* AppError.IDB_OPEN */]: 'Error thrown when opening IndexedDB. Original error: {$originalErrorMessage}.', ["idb-get" /* AppError.IDB_GET */]: 'Error thrown when reading from IndexedDB. Original error: {$originalErrorMessage}.', ["idb-set" /* AppError.IDB_WRITE */]: 'Error thrown when writing to IndexedDB. Original error: {$originalErrorMessage}.', ["idb-delete" /* AppError.IDB_DELETE */]: 'Error thrown when deleting from IndexedDB. Original error: {$originalErrorMessage}.' }; const ERROR_FACTORY = new _firebase_util__WEBPACK_IMPORTED_MODULE_2__.ErrorFactory('app', 'Firebase', ERRORS); /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class FirebaseAppImpl { constructor(options, config, container) { this._isDeleted = false; this._options = Object.assign({}, options); this._config = Object.assign({}, config); this._name = config.name; this._automaticDataCollectionEnabled = config.automaticDataCollectionEnabled; this._container = container; this.container.addComponent(new _firebase_component__WEBPACK_IMPORTED_MODULE_0__.Component('app', () => this, "PUBLIC" /* ComponentType.PUBLIC */)); } get automaticDataCollectionEnabled() { this.checkDestroyed(); return this._automaticDataCollectionEnabled; } set automaticDataCollectionEnabled(val) { this.checkDestroyed(); this._automaticDataCollectionEnabled = val; } get name() { this.checkDestroyed(); return this._name; } get options() { this.checkDestroyed(); return this._options; } get config() { this.checkDestroyed(); return this._config; } get container() { return this._container; } get isDeleted() { return this._isDeleted; } set isDeleted(val) { this._isDeleted = val; } /** * This function will throw an Error if the App has already been deleted - * use before performing API actions on the App. */ checkDestroyed() { if (this.isDeleted) { throw ERROR_FACTORY.create("app-deleted" /* AppError.APP_DELETED */, { appName: this._name }); } } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * The current SDK version. * * @public */ const SDK_VERSION = version; function initializeApp(_options, rawConfig = {}) { let options = _options; if (typeof rawConfig !== 'object') { const name = rawConfig; rawConfig = { name }; } const config = Object.assign({ name: DEFAULT_ENTRY_NAME, automaticDataCollectionEnabled: false }, rawConfig); const name = config.name; if (typeof name !== 'string' || !name) { throw ERROR_FACTORY.create("bad-app-name" /* AppError.BAD_APP_NAME */, { appName: String(name) }); } options || (options = (0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.getDefaultAppConfig)()); if (!options) { throw ERROR_FACTORY.create("no-options" /* AppError.NO_OPTIONS */); } const existingApp = _apps.get(name); if (existingApp) { // return the existing app if options and config deep equal the ones in the existing app. if ((0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.deepEqual)(options, existingApp.options) && (0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.deepEqual)(config, existingApp.config)) { return existingApp; } else { throw ERROR_FACTORY.create("duplicate-app" /* AppError.DUPLICATE_APP */, { appName: name }); } } const container = new _firebase_component__WEBPACK_IMPORTED_MODULE_0__.ComponentContainer(name); for (const component of _components.values()) { container.addComponent(component); } const newApp = new FirebaseAppImpl(options, config, container); _apps.set(name, newApp); return newApp; } /** * Retrieves a {@link @firebase/app#FirebaseApp} instance. * * When called with no arguments, the default app is returned. When an app name * is provided, the app corresponding to that name is returned. * * An exception is thrown if the app being retrieved has not yet been * initialized. * * @example * ```javascript * // Return the default app * const app = getApp(); * ``` * * @example * ```javascript * // Return a named app * const otherApp = getApp("otherApp"); * ``` * * @param name - Optional name of the app to return. If no name is * provided, the default is `"[DEFAULT]"`. * * @returns The app corresponding to the provided app name. * If no app name is provided, the default app is returned. * * @public */ function getApp(name = DEFAULT_ENTRY_NAME) { const app = _apps.get(name); if (!app && name === DEFAULT_ENTRY_NAME) { return initializeApp(); } if (!app) { throw ERROR_FACTORY.create("no-app" /* AppError.NO_APP */, { appName: name }); } return app; } /** * A (read-only) array of all initialized apps. * @public */ function getApps() { return Array.from(_apps.values()); } /** * Renders this app unusable and frees the resources of all associated * services. * * @example * ```javascript * deleteApp(app) * .then(function() { * console.log("App deleted successfully"); * }) * .catch(function(error) { * console.log("Error deleting app:", error); * }); * ``` * * @public */ async function deleteApp(app) { const name = app.name; if (_apps.has(name)) { _apps.delete(name); await Promise.all(app.container .getProviders() .map(provider => provider.delete())); app.isDeleted = true; } } /** * Registers a library's name and version for platform logging purposes. * @param library - Name of 1p or 3p library (e.g. firestore, angularfire) * @param version - Current version of that library. * @param variant - Bundle variant, e.g., node, rn, etc. * * @public */ function registerVersion(libraryKeyOrName, version, variant) { var _a; // TODO: We can use this check to whitelist strings when/if we set up // a good whitelist system. let library = (_a = PLATFORM_LOG_STRING[libraryKeyOrName]) !== null && _a !== void 0 ? _a : libraryKeyOrName; if (variant) { library += `-${variant}`; } const libraryMismatch = library.match(/\s|\//); const versionMismatch = version.match(/\s|\//); if (libraryMismatch || versionMismatch) { const warning = [ `Unable to register library "${library}" with version "${version}":` ]; if (libraryMismatch) { warning.push(`library name "${library}" contains illegal characters (whitespace or "/")`); } if (libraryMismatch && versionMismatch) { warning.push('and'); } if (versionMismatch) { warning.push(`version name "${version}" contains illegal characters (whitespace or "/")`); } logger.warn(warning.join(' ')); return; } _registerComponent(new _firebase_component__WEBPACK_IMPORTED_MODULE_0__.Component(`${library}-version`, () => ({ library, version }), "VERSION" /* ComponentType.VERSION */)); } /** * Sets log handler for all Firebase SDKs. * @param logCallback - An optional custom log handler that executes user code whenever * the Firebase SDK makes a logging call. * * @public */ function onLog(logCallback, options) { if (logCallback !== null && typeof logCallback !== 'function') { throw ERROR_FACTORY.create("invalid-log-argument" /* AppError.INVALID_LOG_ARGUMENT */); } (0,_firebase_logger__WEBPACK_IMPORTED_MODULE_1__.setUserLogHandler)(logCallback, options); } /** * Sets log level for all Firebase SDKs. * * All of the log types above the current log level are captured (i.e. if * you set the log level to `info`, errors are logged, but `debug` and * `verbose` logs are not). * * @public */ function setLogLevel(logLevel) { (0,_firebase_logger__WEBPACK_IMPORTED_MODULE_1__.setLogLevel)(logLevel); } /** * @license * Copyright 2021 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const DB_NAME = 'firebase-heartbeat-database'; const DB_VERSION = 1; const STORE_NAME = 'firebase-heartbeat-store'; let dbPromise = null; function getDbPromise() { if (!dbPromise) { dbPromise = (0,idb__WEBPACK_IMPORTED_MODULE_3__.openDB)(DB_NAME, DB_VERSION, { upgrade: (db, oldVersion) => { // We don't use 'break' in this switch statement, the fall-through // behavior is what we want, because if there are multiple versions between // the old version and the current version, we want ALL the migrations // that correspond to those versions to run, not only the last one. // eslint-disable-next-line default-case switch (oldVersion) { case 0: db.createObjectStore(STORE_NAME); } } }).catch(e => { throw ERROR_FACTORY.create("idb-open" /* AppError.IDB_OPEN */, { originalErrorMessage: e.message }); }); } return dbPromise; } async function readHeartbeatsFromIndexedDB(app) { try { const db = await getDbPromise(); return db .transaction(STORE_NAME) .objectStore(STORE_NAME) .get(computeKey(app)); } catch (e) { if (e instanceof _firebase_util__WEBPACK_IMPORTED_MODULE_2__.FirebaseError) { logger.warn(e.message); } else { const idbGetError = ERROR_FACTORY.create("idb-get" /* AppError.IDB_GET */, { originalErrorMessage: e === null || e === void 0 ? void 0 : e.message }); logger.warn(idbGetError.message); } } } async function writeHeartbeatsToIndexedDB(app, heartbeatObject) { try { const db = await getDbPromise(); const tx = db.transaction(STORE_NAME, 'readwrite'); const objectStore = tx.objectStore(STORE_NAME); await objectStore.put(heartbeatObject, computeKey(app)); return tx.done; } catch (e) { if (e instanceof _firebase_util__WEBPACK_IMPORTED_MODULE_2__.FirebaseError) { logger.warn(e.message); } else { const idbGetError = ERROR_FACTORY.create("idb-set" /* AppError.IDB_WRITE */, { originalErrorMessage: e === null || e === void 0 ? void 0 : e.message }); logger.warn(idbGetError.message); } } } function computeKey(app) { return `${app.name}!${app.options.appId}`; } /** * @license * Copyright 2021 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const MAX_HEADER_BYTES = 1024; // 30 days const STORED_HEARTBEAT_RETENTION_MAX_MILLIS = 30 * 24 * 60 * 60 * 1000; class HeartbeatServiceImpl { constructor(container) { this.container = container; /** * In-memory cache for heartbeats, used by getHeartbeatsHeader() to generate * the header string. * Stores one record per date. This will be consolidated into the standard * format of one record per user agent string before being sent as a header. * Populated from indexedDB when the controller is instantiated and should * be kept in sync with indexedDB. * Leave public for easier testing. */ this._heartbeatsCache = null; const app = this.container.getProvider('app').getImmediate(); this._storage = new HeartbeatStorageImpl(app); this._heartbeatsCachePromise = this._storage.read().then(result => { this._heartbeatsCache = result; return result; }); } /** * Called to report a heartbeat. The function will generate * a HeartbeatsByUserAgent object, update heartbeatsCache, and persist it * to IndexedDB. * Note that we only store one heartbeat per day. So if a heartbeat for today is * already logged, subsequent calls to this function in the same day will be ignored. */ async triggerHeartbeat() { const platformLogger = this.container .getProvider('platform-logger') .getImmediate(); // This is the "Firebase user agent" string from the platform logger // service, not the browser user agent. const agent = platformLogger.getPlatformInfoString(); const date = getUTCDateString(); if (this._heartbeatsCache === null) { this._heartbeatsCache = await this._heartbeatsCachePromise; } // Do not store a heartbeat if one is already stored for this day // or if a header has already been sent today. if (this._heartbeatsCache.lastSentHeartbeatDate === date || this._heartbeatsCache.heartbeats.some(singleDateHeartbeat => singleDateHeartbeat.date === date)) { return; } else { // There is no entry for this date. Create one. this._heartbeatsCache.heartbeats.push({ date, agent }); } // Remove entries older than 30 days. this._heartbeatsCache.heartbeats = this._heartbeatsCache.heartbeats.filter(singleDateHeartbeat => { const hbTimestamp = new Date(singleDateHeartbeat.date).valueOf(); const now = Date.now(); return now - hbTimestamp <= STORED_HEARTBEAT_RETENTION_MAX_MILLIS; }); return this._storage.overwrite(this._heartbeatsCache); } /** * Returns a base64 encoded string which can be attached to the heartbeat-specific header directly. * It also clears all heartbeats from memory as well as in IndexedDB. * * NOTE: Consuming product SDKs should not send the header if this method * returns an empty string. */ async getHeartbeatsHeader() { if (this._heartbeatsCache === null) { await this._heartbeatsCachePromise; } // If it's still null or the array is empty, there is no data to send. if (this._heartbeatsCache === null || this._heartbeatsCache.heartbeats.length === 0) { return ''; } const date = getUTCDateString(); // Extract as many heartbeats from the cache as will fit under the size limit. const { heartbeatsToSend, unsentEntries } = extractHeartbeatsForHeader(this._heartbeatsCache.heartbeats); const headerString = (0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.base64urlEncodeWithoutPadding)(JSON.stringify({ version: 2, heartbeats: heartbeatsToSend })); // Store last sent date to prevent another being logged/sent for the same day. this._heartbeatsCache.lastSentHeartbeatDate = date; if (unsentEntries.length > 0) { // Store any unsent entries if they exist. this._heartbeatsCache.heartbeats = unsentEntries; // This seems more likely than emptying the array (below) to lead to some odd state // since the cache isn't empty and this will be called again on the next request, // and is probably safest if we await it. await this._storage.overwrite(this._heartbeatsCache); } else { this._heartbeatsCache.heartbeats = []; // Do not wait for this, to reduce latency. void this._storage.overwrite(this._heartbeatsCache); } return headerString; } } function getUTCDateString() { const today = new Date(); // Returns date format 'YYYY-MM-DD' return today.toISOString().substring(0, 10); } function extractHeartbeatsForHeader(heartbeatsCache, maxSize = MAX_HEADER_BYTES) { // Heartbeats grouped by user agent in the standard format to be sent in // the header. const heartbeatsToSend = []; // Single date format heartbeats that are not sent. let unsentEntries = heartbeatsCache.slice(); for (const singleDateHeartbeat of heartbeatsCache) { // Look for an existing entry with the same user agent. const heartbeatEntry = heartbeatsToSend.find(hb => hb.agent === singleDateHeartbeat.agent); if (!heartbeatEntry) { // If no entry for this user agent exists, create one. heartbeatsToSend.push({ agent: singleDateHeartbeat.agent, dates: [singleDateHeartbeat.date] }); if (countBytes(heartbeatsToSend) > maxSize) { // If the header would exceed max size, remove the added heartbeat // entry and stop adding to the header. heartbeatsToSend.pop(); break; } } else { heartbeatEntry.dates.push(singleDateHeartbeat.date); // If the header would exceed max size, remove the added date // and stop adding to the header. if (countBytes(heartbeatsToSend) > maxSize) { heartbeatEntry.dates.pop(); break; } } // Pop unsent entry from queue. (Skipped if adding the entry exceeded // quota and the loop breaks early.) unsentEntries = unsentEntries.slice(1); } return { heartbeatsToSend, unsentEntries }; } class HeartbeatStorageImpl { constructor(app) { this.app = app; this._canUseIndexedDBPromise = this.runIndexedDBEnvironmentCheck(); } async runIndexedDBEnvironmentCheck() { if (!(0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.isIndexedDBAvailable)()) { return false; } else { return (0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.validateIndexedDBOpenable)() .then(() => true) .catch(() => false); } } /** * Read all heartbeats. */ async read() { const canUseIndexedDB = await this._canUseIndexedDBPromise; if (!canUseIndexedDB) { return { heartbeats: [] }; } else { const idbHeartbeatObject = await readHeartbeatsFromIndexedDB(this.app); return idbHeartbeatObject || { heartbeats: [] }; } } // overwrite the storage with the provided heartbeats async overwrite(heartbeatsObject) { var _a; const canUseIndexedDB = await this._canUseIndexedDBPromise; if (!canUseIndexedDB) { return; } else { const existingHeartbeatsObject = await this.read(); return writeHeartbeatsToIndexedDB(this.app, { lastSentHeartbeatDate: (_a = heartbeatsObject.lastSentHeartbeatDate) !== null && _a !== void 0 ? _a : existingHeartbeatsObject.lastSentHeartbeatDate, heartbeats: heartbeatsObject.heartbeats }); } } // add heartbeats async add(heartbeatsObject) { var _a; const canUseIndexedDB = await this._canUseIndexedDBPromise; if (!canUseIndexedDB) { return; } else { const existingHeartbeatsObject = await this.read(); return writeHeartbeatsToIndexedDB(this.app, { lastSentHeartbeatDate: (_a = heartbeatsObject.lastSentHeartbeatDate) !== null && _a !== void 0 ? _a : existingHeartbeatsObject.lastSentHeartbeatDate, heartbeats: [ ...existingHeartbeatsObject.heartbeats, ...heartbeatsObject.heartbeats ] }); } } } /** * Calculate bytes of a HeartbeatsByUserAgent array after being wrapped * in a platform logging header JSON object, stringified, and converted * to base 64. */ function countBytes(heartbeatsCache) { // base64 has a restricted set of characters, all of which should be 1 byte. return (0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.base64urlEncodeWithoutPadding)( // heartbeatsCache wrapper properties JSON.stringify({ version: 2, heartbeats: heartbeatsCache })).length; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function registerCoreComponents(variant) { _registerComponent(new _firebase_component__WEBPACK_IMPORTED_MODULE_0__.Component('platform-logger', container => new PlatformLoggerServiceImpl(container), "PRIVATE" /* ComponentType.PRIVATE */)); _registerComponent(new _firebase_component__WEBPACK_IMPORTED_MODULE_0__.Component('heartbeat', container => new HeartbeatServiceImpl(container), "PRIVATE" /* ComponentType.PRIVATE */)); // Register `app` package. registerVersion(name$o, version$1, variant); // BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation registerVersion(name$o, version$1, 'esm2017'); // Register platform SDK identifier (no version). registerVersion('fire-js', ''); } /** * Firebase App * * @remarks This package coordinates the communication between the different Firebase components * @packageDocumentation */ registerCoreComponents(''); //# sourceMappingURL=index.esm2017.js.map /***/ }), /***/ "./node_modules/@firebase/component/dist/esm/index.esm2017.js": /*!********************************************************************!*\ !*** ./node_modules/@firebase/component/dist/esm/index.esm2017.js ***! \********************************************************************/ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Component": () => (/* binding */ Component), /* harmony export */ "ComponentContainer": () => (/* binding */ ComponentContainer), /* harmony export */ "Provider": () => (/* binding */ Provider) /* harmony export */ }); /* harmony import */ var _firebase_util__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @firebase/util */ "./node_modules/@firebase/util/dist/index.esm2017.js"); /** * Component for service name T, e.g. `auth`, `auth-internal` */ class Component { /** * * @param name The public service name, e.g. app, auth, firestore, database * @param instanceFactory Service factory responsible for creating the public interface * @param type whether the service provided by the component is public or private */ constructor(name, instanceFactory, type) { this.name = name; this.instanceFactory = instanceFactory; this.type = type; this.multipleInstances = false; /** * Properties to be added to the service namespace */ this.serviceProps = {}; this.instantiationMode = "LAZY" /* InstantiationMode.LAZY */; this.onInstanceCreated = null; } setInstantiationMode(mode) { this.instantiationMode = mode; return this; } setMultipleInstances(multipleInstances) { this.multipleInstances = multipleInstances; return this; } setServiceProps(props) { this.serviceProps = props; return this; } setInstanceCreatedCallback(callback) { this.onInstanceCreated = callback; return this; } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const DEFAULT_ENTRY_NAME = '[DEFAULT]'; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Provider for instance for service name T, e.g. 'auth', 'auth-internal' * NameServiceMapping[T] is an alias for the type of the instance */ class Provider { constructor(name, container) { this.name = name; this.container = container; this.component = null; this.instances = new Map(); this.instancesDeferred = new Map(); this.instancesOptions = new Map(); this.onInitCallbacks = new Map(); } /** * @param identifier A provider can provide mulitple instances of a service * if this.component.multipleInstances is true. */ get(identifier) { // if multipleInstances is not supported, use the default name const normalizedIdentifier = this.normalizeInstanceIdentifier(identifier); if (!this.instancesDeferred.has(normalizedIdentifier)) { const deferred = new _firebase_util__WEBPACK_IMPORTED_MODULE_0__.Deferred(); this.instancesDeferred.set(normalizedIdentifier, deferred); if (this.isInitialized(normalizedIdentifier) || this.shouldAutoInitialize()) { // initialize the service if it can be auto-initialized try { const instance = this.getOrInitializeService({ instanceIdentifier: normalizedIdentifier }); if (instance) { deferred.resolve(instance); } } catch (e) { // when the instance factory throws an exception during get(), it should not cause // a fatal error. We just return the unresolved promise in this case. } } } return this.instancesDeferred.get(normalizedIdentifier).promise; } getImmediate(options) { var _a; // if multipleInstances is not supported, use the default name const normalizedIdentifier = this.normalizeInstanceIdentifier(options === null || options === void 0 ? void 0 : options.identifier); const optional = (_a = options === null || options === void 0 ? void 0 : options.optional) !== null && _a !== void 0 ? _a : false; if (this.isInitialized(normalizedIdentifier) || this.shouldAutoInitialize()) { try { return this.getOrInitializeService({ instanceIdentifier: normalizedIdentifier }); } catch (e) { if (optional) { return null; } else { throw e; } } } else { // In case a component is not initialized and should/can not be auto-initialized at the moment, return null if the optional flag is set, or throw if (optional) { return null; } else { throw Error(`Service ${this.name} is not available`); } } } getComponent() { return this.component; } setComponent(component) { if (component.name !== this.name) { throw Error(`Mismatching Component ${component.name} for Provider ${this.name}.`); } if (this.component) { throw Error(`Component for ${this.name} has already been provided`); } this.component = component; // return early without attempting to initialize the component if the component requires explicit initialization (calling `Provider.initialize()`) if (!this.shouldAutoInitialize()) { return; } // if the service is eager, initialize the default instance if (isComponentEager(component)) { try { this.getOrInitializeService({ instanceIdentifier: DEFAULT_ENTRY_NAME }); } catch (e) { // when the instance factory for an eager Component throws an exception during the eager // initialization, it should not cause a fatal error. // TODO: Investigate if we need to make it configurable, because some component may want to cause // a fatal error in this case? } } // Create service instances for the pending promises and resolve them // NOTE: if this.multipleInstances is false, only the default instance will be created // and all promises with resolve with it regardless of the identifier. for (const [instanceIdentifier, instanceDeferred] of this.instancesDeferred.entries()) { const normalizedIdentifier = this.normalizeInstanceIdentifier(instanceIdentifier); try { // `getOrInitializeService()` should always return a valid instance since a component is guaranteed. use ! to make typescript happy. const instance = this.getOrInitializeService({ instanceIdentifier: normalizedIdentifier }); instanceDeferred.resolve(instance); } catch (e) { // when the instance factory throws an exception, it should not cause // a fatal error. We just leave the promise unresolved. } } } clearInstance(identifier = DEFAULT_ENTRY_NAME) { this.instancesDeferred.delete(identifier); this.instancesOptions.delete(identifier); this.instances.delete(identifier); } // app.delete() will call this method on every provider to delete the services // TODO: should we mark the provider as deleted? async delete() { const services = Array.from(this.instances.values()); await Promise.all([ ...services .filter(service => 'INTERNAL' in service) // legacy services // eslint-disable-next-line @typescript-eslint/no-explicit-any .map(service => service.INTERNAL.delete()), ...services .filter(service => '_delete' in service) // modularized services // eslint-disable-next-line @typescript-eslint/no-explicit-any .map(service => service._delete()) ]); } isComponentSet() { return this.component != null; } isInitialized(identifier = DEFAULT_ENTRY_NAME) { return this.instances.has(identifier); } getOptions(identifier = DEFAULT_ENTRY_NAME) { return this.instancesOptions.get(identifier) || {}; } initialize(opts = {}) { const { options = {} } = opts; const normalizedIdentifier = this.normalizeInstanceIdentifier(opts.instanceIdentifier); if (this.isInitialized(normalizedIdentifier)) { throw Error(`${this.name}(${normalizedIdentifier}) has already been initialized`); } if (!this.isComponentSet()) { throw Error(`Component ${this.name} has not been registered yet`); } const instance = this.getOrInitializeService({ instanceIdentifier: normalizedIdentifier, options }); // resolve any pending promise waiting for the service instance for (const [instanceIdentifier, instanceDeferred] of this.instancesDeferred.entries()) { const normalizedDeferredIdentifier = this.normalizeInstanceIdentifier(instanceIdentifier); if (normalizedIdentifier === normalizedDeferredIdentifier) { instanceDeferred.resolve(instance); } } return instance; } /** * * @param callback - a function that will be invoked after the provider has been initialized by calling provider.initialize(). * The function is invoked SYNCHRONOUSLY, so it should not execute any longrunning tasks in order to not block the program. * * @param identifier An optional instance identifier * @returns a function to unregister the callback */ onInit(callback, identifier) { var _a; const normalizedIdentifier = this.normalizeInstanceIdentifier(identifier); const existingCallbacks = (_a = this.onInitCallbacks.get(normalizedIdentifier)) !== null && _a !== void 0 ? _a : new Set(); existingCallbacks.add(callback); this.onInitCallbacks.set(normalizedIdentifier, existingCallbacks); const existingInstance = this.instances.get(normalizedIdentifier); if (existingInstance) { callback(existingInstance, normalizedIdentifier); } return () => { existingCallbacks.delete(callback); }; } /** * Invoke onInit callbacks synchronously * @param instance the service instance` */ invokeOnInitCallbacks(instance, identifier) { const callbacks = this.onInitCallbacks.get(identifier); if (!callbacks) { return; } for (const callback of callbacks) { try { callback(instance, identifier); } catch (_a) { // ignore errors in the onInit callback } } } getOrInitializeService({ instanceIdentifier, options = {} }) { let instance = this.instances.get(instanceIdentifier); if (!instance && this.component) { instance = this.component.instanceFactory(this.container, { instanceIdentifier: normalizeIdentifierForFactory(instanceIdentifier), options }); this.instances.set(instanceIdentifier, instance); this.instancesOptions.set(instanceIdentifier, options); /** * Invoke onInit listeners. * Note this.component.onInstanceCreated is different, which is used by the component creator, * while onInit listeners are registered by consumers of the provider. */ this.invokeOnInitCallbacks(instance, instanceIdentifier); /** * Order is important * onInstanceCreated() should be called after this.instances.set(instanceIdentifier, instance); which * makes `isInitialized()` return true. */ if (this.component.onInstanceCreated) { try { this.component.onInstanceCreated(this.container, instanceIdentifier, instance); } catch (_a) { // ignore errors in the onInstanceCreatedCallback } } } return instance || null; } normalizeInstanceIdentifier(identifier = DEFAULT_ENTRY_NAME) { if (this.component) { return this.component.multipleInstances ? identifier : DEFAULT_ENTRY_NAME; } else { return identifier; // assume multiple instances are supported before the component is provided. } } shouldAutoInitialize() { return (!!this.component && this.component.instantiationMode !== "EXPLICIT" /* InstantiationMode.EXPLICIT */); } } // undefined should be passed to the service factory for the default instance function normalizeIdentifierForFactory(identifier) { return identifier === DEFAULT_ENTRY_NAME ? undefined : identifier; } function isComponentEager(component) { return component.instantiationMode === "EAGER" /* InstantiationMode.EAGER */; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * ComponentContainer that provides Providers for service name T, e.g. `auth`, `auth-internal` */ class ComponentContainer { constructor(name) { this.name = name; this.providers = new Map(); } /** * * @param component Component being added * @param overwrite When a component with the same name has already been registered, * if overwrite is true: overwrite the existing component with the new component and create a new * provider with the new component. It can be useful in tests where you want to use different mocks * for different tests. * if overwrite is false: throw an exception */ addComponent(component) { const provider = this.getProvider(component.name); if (provider.isComponentSet()) { throw new Error(`Component ${component.name} has already been registered with ${this.name}`); } provider.setComponent(component); } addOrOverwriteComponent(component) { const provider = this.getProvider(component.name); if (provider.isComponentSet()) { // delete the existing provider from the container, so we can register the new component this.providers.delete(component.name); } this.addComponent(component); } /** * getProvider provides a type safe interface where it can only be called with a field name * present in NameServiceMapping interface. * * Firebase SDKs providing services should extend NameServiceMapping interface to register * themselves. */ getProvider(name) { if (this.providers.has(name)) { return this.providers.get(name); } // create a Provider for a service that hasn't registered with Firebase const provider = new Provider(name, this); this.providers.set(name, provider); return provider; } getProviders() { return Array.from(this.providers.values()); } } //# sourceMappingURL=index.esm2017.js.map /***/ }), /***/ "./node_modules/@firebase/installations/dist/esm/index.esm2017.js": /*!************************************************************************!*\ !*** ./node_modules/@firebase/installations/dist/esm/index.esm2017.js ***! \************************************************************************/ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "deleteInstallations": () => (/* binding */ deleteInstallations), /* harmony export */ "getId": () => (/* binding */ getId), /* harmony export */ "getInstallations": () => (/* binding */ getInstallations), /* harmony export */ "getToken": () => (/* binding */ getToken), /* harmony export */ "onIdChange": () => (/* binding */ onIdChange) /* harmony export */ }); /* harmony import */ var _firebase_app__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @firebase/app */ "./node_modules/@firebase/app/dist/esm/index.esm2017.js"); /* harmony import */ var _firebase_component__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @firebase/component */ "./node_modules/@firebase/component/dist/esm/index.esm2017.js"); /* harmony import */ var _firebase_util__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @firebase/util */ "./node_modules/@firebase/util/dist/index.esm2017.js"); /* harmony import */ var idb__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! idb */ "./node_modules/idb/build/index.js"); const name = "@firebase/installations"; const version = "0.6.4"; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const PENDING_TIMEOUT_MS = 10000; const PACKAGE_VERSION = `w:${version}`; const INTERNAL_AUTH_VERSION = 'FIS_v2'; const INSTALLATIONS_API_URL = 'https://firebaseinstallations.googleapis.com/v1'; const TOKEN_EXPIRATION_BUFFER = 60 * 60 * 1000; // One hour const SERVICE = 'installations'; const SERVICE_NAME = 'Installations'; /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const ERROR_DESCRIPTION_MAP = { ["missing-app-config-values" /* ErrorCode.MISSING_APP_CONFIG_VALUES */]: 'Missing App configuration value: "{$valueName}"', ["not-registered" /* ErrorCode.NOT_REGISTERED */]: 'Firebase Installation is not registered.', ["installation-not-found" /* ErrorCode.INSTALLATION_NOT_FOUND */]: 'Firebase Installation not found.', ["request-failed" /* ErrorCode.REQUEST_FAILED */]: '{$requestName} request failed with error "{$serverCode} {$serverStatus}: {$serverMessage}"', ["app-offline" /* ErrorCode.APP_OFFLINE */]: 'Could not process request. Application offline.', ["delete-pending-registration" /* ErrorCode.DELETE_PENDING_REGISTRATION */]: "Can't delete installation while there is a pending registration request." }; const ERROR_FACTORY = new _firebase_util__WEBPACK_IMPORTED_MODULE_2__.ErrorFactory(SERVICE, SERVICE_NAME, ERROR_DESCRIPTION_MAP); /** Returns true if error is a FirebaseError that is based on an error from the server. */ function isServerError(error) { return (error instanceof _firebase_util__WEBPACK_IMPORTED_MODULE_2__.FirebaseError && error.code.includes("request-failed" /* ErrorCode.REQUEST_FAILED */)); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function getInstallationsEndpoint({ projectId }) { return `${INSTALLATIONS_API_URL}/projects/${projectId}/installations`; } function extractAuthTokenInfoFromResponse(response) { return { token: response.token, requestStatus: 2 /* RequestStatus.COMPLETED */, expiresIn: getExpiresInFromResponseExpiresIn(response.expiresIn), creationTime: Date.now() }; } async function getErrorFromResponse(requestName, response) { const responseJson = await response.json(); const errorData = responseJson.error; return ERROR_FACTORY.create("request-failed" /* ErrorCode.REQUEST_FAILED */, { requestName, serverCode: errorData.code, serverMessage: errorData.message, serverStatus: errorData.status }); } function getHeaders({ apiKey }) { return new Headers({ 'Content-Type': 'application/json', Accept: 'application/json', 'x-goog-api-key': apiKey }); } function getHeadersWithAuth(appConfig, { refreshToken }) { const headers = getHeaders(appConfig); headers.append('Authorization', getAuthorizationHeader(refreshToken)); return headers; } /** * Calls the passed in fetch wrapper and returns the response. * If the returned response has a status of 5xx, re-runs the function once and * returns the response. */ async function retryIfServerError(fn) { const result = await fn(); if (result.status >= 500 && result.status < 600) { // Internal Server Error. Retry request. return fn(); } return result; } function getExpiresInFromResponseExpiresIn(responseExpiresIn) { // This works because the server will never respond with fractions of a second. return Number(responseExpiresIn.replace('s', '000')); } function getAuthorizationHeader(refreshToken) { return `${INTERNAL_AUTH_VERSION} ${refreshToken}`; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function createInstallationRequest({ appConfig, heartbeatServiceProvider }, { fid }) { const endpoint = getInstallationsEndpoint(appConfig); const headers = getHeaders(appConfig); // If heartbeat service exists, add the heartbeat string to the header. const heartbeatService = heartbeatServiceProvider.getImmediate({ optional: true }); if (heartbeatService) { const heartbeatsHeader = await heartbeatService.getHeartbeatsHeader(); if (heartbeatsHeader) { headers.append('x-firebase-client', heartbeatsHeader); } } const body = { fid, authVersion: INTERNAL_AUTH_VERSION, appId: appConfig.appId, sdkVersion: PACKAGE_VERSION }; const request = { method: 'POST', headers, body: JSON.stringify(body) }; const response = await retryIfServerError(() => fetch(endpoint, request)); if (response.ok) { const responseValue = await response.json(); const registeredInstallationEntry = { fid: responseValue.fid || fid, registrationStatus: 2 /* RequestStatus.COMPLETED */, refreshToken: responseValue.refreshToken, authToken: extractAuthTokenInfoFromResponse(responseValue.authToken) }; return registeredInstallationEntry; } else { throw await getErrorFromResponse('Create Installation', response); } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** Returns a promise that resolves after given time passes. */ function sleep(ms) { return new Promise(resolve => { setTimeout(resolve, ms); }); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function bufferToBase64UrlSafe(array) { const b64 = btoa(String.fromCharCode(...array)); return b64.replace(/\+/g, '-').replace(/\//g, '_'); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const VALID_FID_PATTERN = /^[cdef][\w-]{21}$/; const INVALID_FID = ''; /** * Generates a new FID using random values from Web Crypto API. * Returns an empty string if FID generation fails for any reason. */ function generateFid() { try { // A valid FID has exactly 22 base64 characters, which is 132 bits, or 16.5 // bytes. our implementation generates a 17 byte array instead. const fidByteArray = new Uint8Array(17); const crypto = self.crypto || self.msCrypto; crypto.getRandomValues(fidByteArray); // Replace the first 4 random bits with the constant FID header of 0b0111. fidByteArray[0] = 0b01110000 + (fidByteArray[0] % 0b00010000); const fid = encode(fidByteArray); return VALID_FID_PATTERN.test(fid) ? fid : INVALID_FID; } catch (_a) { // FID generation errored return INVALID_FID; } } /** Converts a FID Uint8Array to a base64 string representation. */ function encode(fidByteArray) { const b64String = bufferToBase64UrlSafe(fidByteArray); // Remove the 23rd character that was added because of the extra 4 bits at the // end of our 17 byte array, and the '=' padding. return b64String.substr(0, 22); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** Returns a string key that can be used to identify the app. */ function getKey(appConfig) { return `${appConfig.appName}!${appConfig.appId}`; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const fidChangeCallbacks = new Map(); /** * Calls the onIdChange callbacks with the new FID value, and broadcasts the * change to other tabs. */ function fidChanged(appConfig, fid) { const key = getKey(appConfig); callFidChangeCallbacks(key, fid); broadcastFidChange(key, fid); } function addCallback(appConfig, callback) { // Open the broadcast channel if it's not already open, // to be able to listen to change events from other tabs. getBroadcastChannel(); const key = getKey(appConfig); let callbackSet = fidChangeCallbacks.get(key); if (!callbackSet) { callbackSet = new Set(); fidChangeCallbacks.set(key, callbackSet); } callbackSet.add(callback); } function removeCallback(appConfig, callback) { const key = getKey(appConfig); const callbackSet = fidChangeCallbacks.get(key); if (!callbackSet) { return; } callbackSet.delete(callback); if (callbackSet.size === 0) { fidChangeCallbacks.delete(key); } // Close broadcast channel if there are no more callbacks. closeBroadcastChannel(); } function callFidChangeCallbacks(key, fid) { const callbacks = fidChangeCallbacks.get(key); if (!callbacks) { return; } for (const callback of callbacks) { callback(fid); } } function broadcastFidChange(key, fid) { const channel = getBroadcastChannel(); if (channel) { channel.postMessage({ key, fid }); } closeBroadcastChannel(); } let broadcastChannel = null; /** Opens and returns a BroadcastChannel if it is supported by the browser. */ function getBroadcastChannel() { if (!broadcastChannel && 'BroadcastChannel' in self) { broadcastChannel = new BroadcastChannel('[Firebase] FID Change'); broadcastChannel.onmessage = e => { callFidChangeCallbacks(e.data.key, e.data.fid); }; } return broadcastChannel; } function closeBroadcastChannel() { if (fidChangeCallbacks.size === 0 && broadcastChannel) { broadcastChannel.close(); broadcastChannel = null; } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const DATABASE_NAME = 'firebase-installations-database'; const DATABASE_VERSION = 1; const OBJECT_STORE_NAME = 'firebase-installations-store'; let dbPromise = null; function getDbPromise() { if (!dbPromise) { dbPromise = (0,idb__WEBPACK_IMPORTED_MODULE_3__.openDB)(DATABASE_NAME, DATABASE_VERSION, { upgrade: (db, oldVersion) => { // We don't use 'break' in this switch statement, the fall-through // behavior is what we want, because if there are multiple versions between // the old version and the current version, we want ALL the migrations // that correspond to those versions to run, not only the last one. // eslint-disable-next-line default-case switch (oldVersion) { case 0: db.createObjectStore(OBJECT_STORE_NAME); } } }); } return dbPromise; } /** Assigns or overwrites the record for the given key with the given value. */ async function set(appConfig, value) { const key = getKey(appConfig); const db = await getDbPromise(); const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite'); const objectStore = tx.objectStore(OBJECT_STORE_NAME); const oldValue = (await objectStore.get(key)); await objectStore.put(value, key); await tx.done; if (!oldValue || oldValue.fid !== value.fid) { fidChanged(appConfig, value.fid); } return value; } /** Removes record(s) from the objectStore that match the given key. */ async function remove(appConfig) { const key = getKey(appConfig); const db = await getDbPromise(); const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite'); await tx.objectStore(OBJECT_STORE_NAME).delete(key); await tx.done; } /** * Atomically updates a record with the result of updateFn, which gets * called with the current value. If newValue is undefined, the record is * deleted instead. * @return Updated value */ async function update(appConfig, updateFn) { const key = getKey(appConfig); const db = await getDbPromise(); const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite'); const store = tx.objectStore(OBJECT_STORE_NAME); const oldValue = (await store.get(key)); const newValue = updateFn(oldValue); if (newValue === undefined) { await store.delete(key); } else { await store.put(newValue, key); } await tx.done; if (newValue && (!oldValue || oldValue.fid !== newValue.fid)) { fidChanged(appConfig, newValue.fid); } return newValue; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Updates and returns the InstallationEntry from the database. * Also triggers a registration request if it is necessary and possible. */ async function getInstallationEntry(installations) { let registrationPromise; const installationEntry = await update(installations.appConfig, oldEntry => { const installationEntry = updateOrCreateInstallationEntry(oldEntry); const entryWithPromise = triggerRegistrationIfNecessary(installations, installationEntry); registrationPromise = entryWithPromise.registrationPromise; return entryWithPromise.installationEntry; }); if (installationEntry.fid === INVALID_FID) { // FID generation failed. Waiting for the FID from the server. return { installationEntry: await registrationPromise }; } return { installationEntry, registrationPromise }; } /** * Creates a new Installation Entry if one does not exist. * Also clears timed out pending requests. */ function updateOrCreateInstallationEntry(oldEntry) { const entry = oldEntry || { fid: generateFid(), registrationStatus: 0 /* RequestStatus.NOT_STARTED */ }; return clearTimedOutRequest(entry); } /** * If the Firebase Installation is not registered yet, this will trigger the * registration and return an InProgressInstallationEntry. * * If registrationPromise does not exist, the installationEntry is guaranteed * to be registered. */ function triggerRegistrationIfNecessary(installations, installationEntry) { if (installationEntry.registrationStatus === 0 /* RequestStatus.NOT_STARTED */) { if (!navigator.onLine) { // Registration required but app is offline. const registrationPromiseWithError = Promise.reject(ERROR_FACTORY.create("app-offline" /* ErrorCode.APP_OFFLINE */)); return { installationEntry, registrationPromise: registrationPromiseWithError }; } // Try registering. Change status to IN_PROGRESS. const inProgressEntry = { fid: installationEntry.fid, registrationStatus: 1 /* RequestStatus.IN_PROGRESS */, registrationTime: Date.now() }; const registrationPromise = registerInstallation(installations, inProgressEntry); return { installationEntry: inProgressEntry, registrationPromise }; } else if (installationEntry.registrationStatus === 1 /* RequestStatus.IN_PROGRESS */) { return { installationEntry, registrationPromise: waitUntilFidRegistration(installations) }; } else { return { installationEntry }; } } /** This will be executed only once for each new Firebase Installation. */ async function registerInstallation(installations, installationEntry) { try { const registeredInstallationEntry = await createInstallationRequest(installations, installationEntry); return set(installations.appConfig, registeredInstallationEntry); } catch (e) { if (isServerError(e) && e.customData.serverCode === 409) { // Server returned a "FID can not be used" error. // Generate a new ID next time. await remove(installations.appConfig); } else { // Registration failed. Set FID as not registered. await set(installations.appConfig, { fid: installationEntry.fid, registrationStatus: 0 /* RequestStatus.NOT_STARTED */ }); } throw e; } } /** Call if FID registration is pending in another request. */ async function waitUntilFidRegistration(installations) { // Unfortunately, there is no way of reliably observing when a value in // IndexedDB changes (yet, see https://github.com/WICG/indexed-db-observers), // so we need to poll. let entry = await updateInstallationRequest(installations.appConfig); while (entry.registrationStatus === 1 /* RequestStatus.IN_PROGRESS */) { // createInstallation request still in progress. await sleep(100); entry = await updateInstallationRequest(installations.appConfig); } if (entry.registrationStatus === 0 /* RequestStatus.NOT_STARTED */) { // The request timed out or failed in a different call. Try again. const { installationEntry, registrationPromise } = await getInstallationEntry(installations); if (registrationPromise) { return registrationPromise; } else { // if there is no registrationPromise, entry is registered. return installationEntry; } } return entry; } /** * Called only if there is a CreateInstallation request in progress. * * Updates the InstallationEntry in the DB based on the status of the * CreateInstallation request. * * Returns the updated InstallationEntry. */ function updateInstallationRequest(appConfig) { return update(appConfig, oldEntry => { if (!oldEntry) { throw ERROR_FACTORY.create("installation-not-found" /* ErrorCode.INSTALLATION_NOT_FOUND */); } return clearTimedOutRequest(oldEntry); }); } function clearTimedOutRequest(entry) { if (hasInstallationRequestTimedOut(entry)) { return { fid: entry.fid, registrationStatus: 0 /* RequestStatus.NOT_STARTED */ }; } return entry; } function hasInstallationRequestTimedOut(installationEntry) { return (installationEntry.registrationStatus === 1 /* RequestStatus.IN_PROGRESS */ && installationEntry.registrationTime + PENDING_TIMEOUT_MS < Date.now()); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function generateAuthTokenRequest({ appConfig, heartbeatServiceProvider }, installationEntry) { const endpoint = getGenerateAuthTokenEndpoint(appConfig, installationEntry); const headers = getHeadersWithAuth(appConfig, installationEntry); // If heartbeat service exists, add the heartbeat string to the header. const heartbeatService = heartbeatServiceProvider.getImmediate({ optional: true }); if (heartbeatService) { const heartbeatsHeader = await heartbeatService.getHeartbeatsHeader(); if (heartbeatsHeader) { headers.append('x-firebase-client', heartbeatsHeader); } } const body = { installation: { sdkVersion: PACKAGE_VERSION, appId: appConfig.appId } }; const request = { method: 'POST', headers, body: JSON.stringify(body) }; const response = await retryIfServerError(() => fetch(endpoint, request)); if (response.ok) { const responseValue = await response.json(); const completedAuthToken = extractAuthTokenInfoFromResponse(responseValue); return completedAuthToken; } else { throw await getErrorFromResponse('Generate Auth Token', response); } } function getGenerateAuthTokenEndpoint(appConfig, { fid }) { return `${getInstallationsEndpoint(appConfig)}/${fid}/authTokens:generate`; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Returns a valid authentication token for the installation. Generates a new * token if one doesn't exist, is expired or about to expire. * * Should only be called if the Firebase Installation is registered. */ async function refreshAuthToken(installations, forceRefresh = false) { let tokenPromise; const entry = await update(installations.appConfig, oldEntry => { if (!isEntryRegistered(oldEntry)) { throw ERROR_FACTORY.create("not-registered" /* ErrorCode.NOT_REGISTERED */); } const oldAuthToken = oldEntry.authToken; if (!forceRefresh && isAuthTokenValid(oldAuthToken)) { // There is a valid token in the DB. return oldEntry; } else if (oldAuthToken.requestStatus === 1 /* RequestStatus.IN_PROGRESS */) { // There already is a token request in progress. tokenPromise = waitUntilAuthTokenRequest(installations, forceRefresh); return oldEntry; } else { // No token or token expired. if (!navigator.onLine) { throw ERROR_FACTORY.create("app-offline" /* ErrorCode.APP_OFFLINE */); } const inProgressEntry = makeAuthTokenRequestInProgressEntry(oldEntry); tokenPromise = fetchAuthTokenFromServer(installations, inProgressEntry); return inProgressEntry; } }); const authToken = tokenPromise ? await tokenPromise : entry.authToken; return authToken; } /** * Call only if FID is registered and Auth Token request is in progress. * * Waits until the current pending request finishes. If the request times out, * tries once in this thread as well. */ async function waitUntilAuthTokenRequest(installations, forceRefresh) { // Unfortunately, there is no way of reliably observing when a value in // IndexedDB changes (yet, see https://github.com/WICG/indexed-db-observers), // so we need to poll. let entry = await updateAuthTokenRequest(installations.appConfig); while (entry.authToken.requestStatus === 1 /* RequestStatus.IN_PROGRESS */) { // generateAuthToken still in progress. await sleep(100); entry = await updateAuthTokenRequest(installations.appConfig); } const authToken = entry.authToken; if (authToken.requestStatus === 0 /* RequestStatus.NOT_STARTED */) { // The request timed out or failed in a different call. Try again. return refreshAuthToken(installations, forceRefresh); } else { return authToken; } } /** * Called only if there is a GenerateAuthToken request in progress. * * Updates the InstallationEntry in the DB based on the status of the * GenerateAuthToken request. * * Returns the updated InstallationEntry. */ function updateAuthTokenRequest(appConfig) { return update(appConfig, oldEntry => { if (!isEntryRegistered(oldEntry)) { throw ERROR_FACTORY.create("not-registered" /* ErrorCode.NOT_REGISTERED */); } const oldAuthToken = oldEntry.authToken; if (hasAuthTokenRequestTimedOut(oldAuthToken)) { return Object.assign(Object.assign({}, oldEntry), { authToken: { requestStatus: 0 /* RequestStatus.NOT_STARTED */ } }); } return oldEntry; }); } async function fetchAuthTokenFromServer(installations, installationEntry) { try { const authToken = await generateAuthTokenRequest(installations, installationEntry); const updatedInstallationEntry = Object.assign(Object.assign({}, installationEntry), { authToken }); await set(installations.appConfig, updatedInstallationEntry); return authToken; } catch (e) { if (isServerError(e) && (e.customData.serverCode === 401 || e.customData.serverCode === 404)) { // Server returned a "FID not found" or a "Invalid authentication" error. // Generate a new ID next time. await remove(installations.appConfig); } else { const updatedInstallationEntry = Object.assign(Object.assign({}, installationEntry), { authToken: { requestStatus: 0 /* RequestStatus.NOT_STARTED */ } }); await set(installations.appConfig, updatedInstallationEntry); } throw e; } } function isEntryRegistered(installationEntry) { return (installationEntry !== undefined && installationEntry.registrationStatus === 2 /* RequestStatus.COMPLETED */); } function isAuthTokenValid(authToken) { return (authToken.requestStatus === 2 /* RequestStatus.COMPLETED */ && !isAuthTokenExpired(authToken)); } function isAuthTokenExpired(authToken) { const now = Date.now(); return (now < authToken.creationTime || authToken.creationTime + authToken.expiresIn < now + TOKEN_EXPIRATION_BUFFER); } /** Returns an updated InstallationEntry with an InProgressAuthToken. */ function makeAuthTokenRequestInProgressEntry(oldEntry) { const inProgressAuthToken = { requestStatus: 1 /* RequestStatus.IN_PROGRESS */, requestTime: Date.now() }; return Object.assign(Object.assign({}, oldEntry), { authToken: inProgressAuthToken }); } function hasAuthTokenRequestTimedOut(authToken) { return (authToken.requestStatus === 1 /* RequestStatus.IN_PROGRESS */ && authToken.requestTime + PENDING_TIMEOUT_MS < Date.now()); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Creates a Firebase Installation if there isn't one for the app and * returns the Installation ID. * @param installations - The `Installations` instance. * * @public */ async function getId(installations) { const installationsImpl = installations; const { installationEntry, registrationPromise } = await getInstallationEntry(installationsImpl); if (registrationPromise) { registrationPromise.catch(console.error); } else { // If the installation is already registered, update the authentication // token if needed. refreshAuthToken(installationsImpl).catch(console.error); } return installationEntry.fid; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Returns a Firebase Installations auth token, identifying the current * Firebase Installation. * @param installations - The `Installations` instance. * @param forceRefresh - Force refresh regardless of token expiration. * * @public */ async function getToken(installations, forceRefresh = false) { const installationsImpl = installations; await completeInstallationRegistration(installationsImpl); // At this point we either have a Registered Installation in the DB, or we've // already thrown an error. const authToken = await refreshAuthToken(installationsImpl, forceRefresh); return authToken.token; } async function completeInstallationRegistration(installations) { const { registrationPromise } = await getInstallationEntry(installations); if (registrationPromise) { // A createInstallation request is in progress. Wait until it finishes. await registrationPromise; } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function deleteInstallationRequest(appConfig, installationEntry) { const endpoint = getDeleteEndpoint(appConfig, installationEntry); const headers = getHeadersWithAuth(appConfig, installationEntry); const request = { method: 'DELETE', headers }; const response = await retryIfServerError(() => fetch(endpoint, request)); if (!response.ok) { throw await getErrorFromResponse('Delete Installation', response); } } function getDeleteEndpoint(appConfig, { fid }) { return `${getInstallationsEndpoint(appConfig)}/${fid}`; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Deletes the Firebase Installation and all associated data. * @param installations - The `Installations` instance. * * @public */ async function deleteInstallations(installations) { const { appConfig } = installations; const entry = await update(appConfig, oldEntry => { if (oldEntry && oldEntry.registrationStatus === 0 /* RequestStatus.NOT_STARTED */) { // Delete the unregistered entry without sending a deleteInstallation request. return undefined; } return oldEntry; }); if (entry) { if (entry.registrationStatus === 1 /* RequestStatus.IN_PROGRESS */) { // Can't delete while trying to register. throw ERROR_FACTORY.create("delete-pending-registration" /* ErrorCode.DELETE_PENDING_REGISTRATION */); } else if (entry.registrationStatus === 2 /* RequestStatus.COMPLETED */) { if (!navigator.onLine) { throw ERROR_FACTORY.create("app-offline" /* ErrorCode.APP_OFFLINE */); } else { await deleteInstallationRequest(appConfig, entry); await remove(appConfig); } } } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Sets a new callback that will get called when Installation ID changes. * Returns an unsubscribe function that will remove the callback when called. * @param installations - The `Installations` instance. * @param callback - The callback function that is invoked when FID changes. * @returns A function that can be called to unsubscribe. * * @public */ function onIdChange(installations, callback) { const { appConfig } = installations; addCallback(appConfig, callback); return () => { removeCallback(appConfig, callback); }; } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Returns an instance of {@link Installations} associated with the given * {@link @firebase/app#FirebaseApp} instance. * @param app - The {@link @firebase/app#FirebaseApp} instance. * * @public */ function getInstallations(app = (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__.getApp)()) { const installationsImpl = (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__._getProvider)(app, 'installations').getImmediate(); return installationsImpl; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function extractAppConfig(app) { if (!app || !app.options) { throw getMissingValueError('App Configuration'); } if (!app.name) { throw getMissingValueError('App Name'); } // Required app config keys const configKeys = [ 'projectId', 'apiKey', 'appId' ]; for (const keyName of configKeys) { if (!app.options[keyName]) { throw getMissingValueError(keyName); } } return { appName: app.name, projectId: app.options.projectId, apiKey: app.options.apiKey, appId: app.options.appId }; } function getMissingValueError(valueName) { return ERROR_FACTORY.create("missing-app-config-values" /* ErrorCode.MISSING_APP_CONFIG_VALUES */, { valueName }); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const INSTALLATIONS_NAME = 'installations'; const INSTALLATIONS_NAME_INTERNAL = 'installations-internal'; const publicFactory = (container) => { const app = container.getProvider('app').getImmediate(); // Throws if app isn't configured properly. const appConfig = extractAppConfig(app); const heartbeatServiceProvider = (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__._getProvider)(app, 'heartbeat'); const installationsImpl = { app, appConfig, heartbeatServiceProvider, _delete: () => Promise.resolve() }; return installationsImpl; }; const internalFactory = (container) => { const app = container.getProvider('app').getImmediate(); // Internal FIS instance relies on public FIS instance. const installations = (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__._getProvider)(app, INSTALLATIONS_NAME).getImmediate(); const installationsInternal = { getId: () => getId(installations), getToken: (forceRefresh) => getToken(installations, forceRefresh) }; return installationsInternal; }; function registerInstallations() { (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__._registerComponent)(new _firebase_component__WEBPACK_IMPORTED_MODULE_1__.Component(INSTALLATIONS_NAME, publicFactory, "PUBLIC" /* ComponentType.PUBLIC */)); (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__._registerComponent)(new _firebase_component__WEBPACK_IMPORTED_MODULE_1__.Component(INSTALLATIONS_NAME_INTERNAL, internalFactory, "PRIVATE" /* ComponentType.PRIVATE */)); } /** * Firebase Installations * * @packageDocumentation */ registerInstallations(); (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__.registerVersion)(name, version); // BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__.registerVersion)(name, version, 'esm2017'); //# sourceMappingURL=index.esm2017.js.map /***/ }), /***/ "./node_modules/@firebase/logger/dist/esm/index.esm2017.js": /*!*****************************************************************!*\ !*** ./node_modules/@firebase/logger/dist/esm/index.esm2017.js ***! \*****************************************************************/ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "LogLevel": () => (/* binding */ LogLevel), /* harmony export */ "Logger": () => (/* binding */ Logger), /* harmony export */ "setLogLevel": () => (/* binding */ setLogLevel), /* harmony export */ "setUserLogHandler": () => (/* binding */ setUserLogHandler) /* harmony export */ }); /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * A container for all of the Logger instances */ const instances = []; /** * The JS SDK supports 5 log levels and also allows a user the ability to * silence the logs altogether. * * The order is a follows: * DEBUG < VERBOSE < INFO < WARN < ERROR * * All of the log types above the current log level will be captured (i.e. if * you set the log level to `INFO`, errors will still be logged, but `DEBUG` and * `VERBOSE` logs will not) */ var LogLevel; (function (LogLevel) { LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG"; LogLevel[LogLevel["VERBOSE"] = 1] = "VERBOSE"; LogLevel[LogLevel["INFO"] = 2] = "INFO"; LogLevel[LogLevel["WARN"] = 3] = "WARN"; LogLevel[LogLevel["ERROR"] = 4] = "ERROR"; LogLevel[LogLevel["SILENT"] = 5] = "SILENT"; })(LogLevel || (LogLevel = {})); const levelStringToEnum = { 'debug': LogLevel.DEBUG, 'verbose': LogLevel.VERBOSE, 'info': LogLevel.INFO, 'warn': LogLevel.WARN, 'error': LogLevel.ERROR, 'silent': LogLevel.SILENT }; /** * The default log level */ const defaultLogLevel = LogLevel.INFO; /** * By default, `console.debug` is not displayed in the developer console (in * chrome). To avoid forcing users to have to opt-in to these logs twice * (i.e. once for firebase, and once in the console), we are sending `DEBUG` * logs to the `console.log` function. */ const ConsoleMethod = { [LogLevel.DEBUG]: 'log', [LogLevel.VERBOSE]: 'log', [LogLevel.INFO]: 'info', [LogLevel.WARN]: 'warn', [LogLevel.ERROR]: 'error' }; /** * The default log handler will forward DEBUG, VERBOSE, INFO, WARN, and ERROR * messages on to their corresponding console counterparts (if the log method * is supported by the current log level) */ const defaultLogHandler = (instance, logType, ...args) => { if (logType < instance.logLevel) { return; } const now = new Date().toISOString(); const method = ConsoleMethod[logType]; if (method) { console[method](`[${now}] ${instance.name}:`, ...args); } else { throw new Error(`Attempted to log a message with an invalid logType (value: ${logType})`); } }; class Logger { /** * Gives you an instance of a Logger to capture messages according to * Firebase's logging scheme. * * @param name The name that the logs will be associated with */ constructor(name) { this.name = name; /** * The log level of the given Logger instance. */ this._logLevel = defaultLogLevel; /** * The main (internal) log handler for the Logger instance. * Can be set to a new function in internal package code but not by user. */ this._logHandler = defaultLogHandler; /** * The optional, additional, user-defined log handler for the Logger instance. */ this._userLogHandler = null; /** * Capture the current instance for later use */ instances.push(this); } get logLevel() { return this._logLevel; } set logLevel(val) { if (!(val in LogLevel)) { throw new TypeError(`Invalid value "${val}" assigned to \`logLevel\``); } this._logLevel = val; } // Workaround for setter/getter having to be the same type. setLogLevel(val) { this._logLevel = typeof val === 'string' ? levelStringToEnum[val] : val; } get logHandler() { return this._logHandler; } set logHandler(val) { if (typeof val !== 'function') { throw new TypeError('Value assigned to `logHandler` must be a function'); } this._logHandler = val; } get userLogHandler() { return this._userLogHandler; } set userLogHandler(val) { this._userLogHandler = val; } /** * The functions below are all based on the `console` interface */ debug(...args) { this._userLogHandler && this._userLogHandler(this, LogLevel.DEBUG, ...args); this._logHandler(this, LogLevel.DEBUG, ...args); } log(...args) { this._userLogHandler && this._userLogHandler(this, LogLevel.VERBOSE, ...args); this._logHandler(this, LogLevel.VERBOSE, ...args); } info(...args) { this._userLogHandler && this._userLogHandler(this, LogLevel.INFO, ...args); this._logHandler(this, LogLevel.INFO, ...args); } warn(...args) { this._userLogHandler && this._userLogHandler(this, LogLevel.WARN, ...args); this._logHandler(this, LogLevel.WARN, ...args); } error(...args) { this._userLogHandler && this._userLogHandler(this, LogLevel.ERROR, ...args); this._logHandler(this, LogLevel.ERROR, ...args); } } function setLogLevel(level) { instances.forEach(inst => { inst.setLogLevel(level); }); } function setUserLogHandler(logCallback, options) { for (const instance of instances) { let customLogLevel = null; if (options && options.level) { customLogLevel = levelStringToEnum[options.level]; } if (logCallback === null) { instance.userLogHandler = null; } else { instance.userLogHandler = (instance, level, ...args) => { const message = args .map(arg => { if (arg == null) { return null; } else if (typeof arg === 'string') { return arg; } else if (typeof arg === 'number' || typeof arg === 'boolean') { return arg.toString(); } else if (arg instanceof Error) { return arg.message; } else { try { return JSON.stringify(arg); } catch (ignored) { return null; } } }) .filter(arg => arg) .join(' '); if (level >= (customLogLevel !== null && customLogLevel !== void 0 ? customLogLevel : instance.logLevel)) { logCallback({ level: LogLevel[level].toLowerCase(), message, args, type: instance.name }); } }; } } } //# sourceMappingURL=index.esm2017.js.map /***/ }), /***/ "./node_modules/@firebase/messaging/dist/esm/index.esm2017.js": /*!********************************************************************!*\ !*** ./node_modules/@firebase/messaging/dist/esm/index.esm2017.js ***! \********************************************************************/ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "deleteToken": () => (/* binding */ deleteToken), /* harmony export */ "getMessaging": () => (/* binding */ getMessagingInWindow), /* harmony export */ "getToken": () => (/* binding */ getToken), /* harmony export */ "isSupported": () => (/* binding */ isWindowSupported), /* harmony export */ "onMessage": () => (/* binding */ onMessage) /* harmony export */ }); /* harmony import */ var _firebase_installations__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @firebase/installations */ "./node_modules/@firebase/installations/dist/esm/index.esm2017.js"); /* harmony import */ var _firebase_component__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @firebase/component */ "./node_modules/@firebase/component/dist/esm/index.esm2017.js"); /* harmony import */ var idb__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! idb */ "./node_modules/idb/build/index.js"); /* harmony import */ var _firebase_util__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @firebase/util */ "./node_modules/@firebase/util/dist/index.esm2017.js"); /* harmony import */ var _firebase_app__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @firebase/app */ "./node_modules/@firebase/app/dist/esm/index.esm2017.js"); /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const DEFAULT_SW_PATH = '/firebase-messaging-sw.js'; const DEFAULT_SW_SCOPE = '/firebase-cloud-messaging-push-scope'; const DEFAULT_VAPID_KEY = 'BDOU99-h67HcA6JeFXHbSNMu7e2yNNu3RzoMj8TM4W88jITfq7ZmPvIM1Iv-4_l2LxQcYwhqby2xGpWwzjfAnG4'; const ENDPOINT = 'https://fcmregistrations.googleapis.com/v1'; const CONSOLE_CAMPAIGN_ID = 'google.c.a.c_id'; const CONSOLE_CAMPAIGN_NAME = 'google.c.a.c_l'; const CONSOLE_CAMPAIGN_TIME = 'google.c.a.ts'; /** Set to '1' if Analytics is enabled for the campaign */ const CONSOLE_CAMPAIGN_ANALYTICS_ENABLED = 'google.c.a.e'; var MessageType$1; (function (MessageType) { MessageType[MessageType["DATA_MESSAGE"] = 1] = "DATA_MESSAGE"; MessageType[MessageType["DISPLAY_NOTIFICATION"] = 3] = "DISPLAY_NOTIFICATION"; })(MessageType$1 || (MessageType$1 = {})); /** * @license * Copyright 2018 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ var MessageType; (function (MessageType) { MessageType["PUSH_RECEIVED"] = "push-received"; MessageType["NOTIFICATION_CLICKED"] = "notification-clicked"; })(MessageType || (MessageType = {})); /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function arrayToBase64(array) { const uint8Array = new Uint8Array(array); const base64String = btoa(String.fromCharCode(...uint8Array)); return base64String.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); } function base64ToArray(base64String) { const padding = '='.repeat((4 - (base64String.length % 4)) % 4); const base64 = (base64String + padding) .replace(/\-/g, '+') .replace(/_/g, '/'); const rawData = atob(base64); const outputArray = new Uint8Array(rawData.length); for (let i = 0; i < rawData.length; ++i) { outputArray[i] = rawData.charCodeAt(i); } return outputArray; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const OLD_DB_NAME = 'fcm_token_details_db'; /** * The last DB version of 'fcm_token_details_db' was 4. This is one higher, so that the upgrade * callback is called for all versions of the old DB. */ const OLD_DB_VERSION = 5; const OLD_OBJECT_STORE_NAME = 'fcm_token_object_Store'; async function migrateOldDatabase(senderId) { if ('databases' in indexedDB) { // indexedDb.databases() is an IndexedDB v3 API and does not exist in all browsers. TODO: Remove // typecast when it lands in TS types. const databases = await indexedDB.databases(); const dbNames = databases.map(db => db.name); if (!dbNames.includes(OLD_DB_NAME)) { // old DB didn't exist, no need to open. return null; } } let tokenDetails = null; const db = await (0,idb__WEBPACK_IMPORTED_MODULE_2__.openDB)(OLD_DB_NAME, OLD_DB_VERSION, { upgrade: async (db, oldVersion, newVersion, upgradeTransaction) => { var _a; if (oldVersion < 2) { // Database too old, skip migration. return; } if (!db.objectStoreNames.contains(OLD_OBJECT_STORE_NAME)) { // Database did not exist. Nothing to do. return; } const objectStore = upgradeTransaction.objectStore(OLD_OBJECT_STORE_NAME); const value = await objectStore.index('fcmSenderId').get(senderId); await objectStore.clear(); if (!value) { // No entry in the database, nothing to migrate. return; } if (oldVersion === 2) { const oldDetails = value; if (!oldDetails.auth || !oldDetails.p256dh || !oldDetails.endpoint) { return; } tokenDetails = { token: oldDetails.fcmToken, createTime: (_a = oldDetails.createTime) !== null && _a !== void 0 ? _a : Date.now(), subscriptionOptions: { auth: oldDetails.auth, p256dh: oldDetails.p256dh, endpoint: oldDetails.endpoint, swScope: oldDetails.swScope, vapidKey: typeof oldDetails.vapidKey === 'string' ? oldDetails.vapidKey : arrayToBase64(oldDetails.vapidKey) } }; } else if (oldVersion === 3) { const oldDetails = value; tokenDetails = { token: oldDetails.fcmToken, createTime: oldDetails.createTime, subscriptionOptions: { auth: arrayToBase64(oldDetails.auth), p256dh: arrayToBase64(oldDetails.p256dh), endpoint: oldDetails.endpoint, swScope: oldDetails.swScope, vapidKey: arrayToBase64(oldDetails.vapidKey) } }; } else if (oldVersion === 4) { const oldDetails = value; tokenDetails = { token: oldDetails.fcmToken, createTime: oldDetails.createTime, subscriptionOptions: { auth: arrayToBase64(oldDetails.auth), p256dh: arrayToBase64(oldDetails.p256dh), endpoint: oldDetails.endpoint, swScope: oldDetails.swScope, vapidKey: arrayToBase64(oldDetails.vapidKey) } }; } } }); db.close(); // Delete all old databases. await (0,idb__WEBPACK_IMPORTED_MODULE_2__.deleteDB)(OLD_DB_NAME); await (0,idb__WEBPACK_IMPORTED_MODULE_2__.deleteDB)('fcm_vapid_details_db'); await (0,idb__WEBPACK_IMPORTED_MODULE_2__.deleteDB)('undefined'); return checkTokenDetails(tokenDetails) ? tokenDetails : null; } function checkTokenDetails(tokenDetails) { if (!tokenDetails || !tokenDetails.subscriptionOptions) { return false; } const { subscriptionOptions } = tokenDetails; return (typeof tokenDetails.createTime === 'number' && tokenDetails.createTime > 0 && typeof tokenDetails.token === 'string' && tokenDetails.token.length > 0 && typeof subscriptionOptions.auth === 'string' && subscriptionOptions.auth.length > 0 && typeof subscriptionOptions.p256dh === 'string' && subscriptionOptions.p256dh.length > 0 && typeof subscriptionOptions.endpoint === 'string' && subscriptionOptions.endpoint.length > 0 && typeof subscriptionOptions.swScope === 'string' && subscriptionOptions.swScope.length > 0 && typeof subscriptionOptions.vapidKey === 'string' && subscriptionOptions.vapidKey.length > 0); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Exported for tests. const DATABASE_NAME = 'firebase-messaging-database'; const DATABASE_VERSION = 1; const OBJECT_STORE_NAME = 'firebase-messaging-store'; let dbPromise = null; function getDbPromise() { if (!dbPromise) { dbPromise = (0,idb__WEBPACK_IMPORTED_MODULE_2__.openDB)(DATABASE_NAME, DATABASE_VERSION, { upgrade: (upgradeDb, oldVersion) => { // We don't use 'break' in this switch statement, the fall-through behavior is what we want, // because if there are multiple versions between the old version and the current version, we // want ALL the migrations that correspond to those versions to run, not only the last one. // eslint-disable-next-line default-case switch (oldVersion) { case 0: upgradeDb.createObjectStore(OBJECT_STORE_NAME); } } }); } return dbPromise; } /** Gets record(s) from the objectStore that match the given key. */ async function dbGet(firebaseDependencies) { const key = getKey(firebaseDependencies); const db = await getDbPromise(); const tokenDetails = (await db .transaction(OBJECT_STORE_NAME) .objectStore(OBJECT_STORE_NAME) .get(key)); if (tokenDetails) { return tokenDetails; } else { // Check if there is a tokenDetails object in the old DB. const oldTokenDetails = await migrateOldDatabase(firebaseDependencies.appConfig.senderId); if (oldTokenDetails) { await dbSet(firebaseDependencies, oldTokenDetails); return oldTokenDetails; } } } /** Assigns or overwrites the record for the given key with the given value. */ async function dbSet(firebaseDependencies, tokenDetails) { const key = getKey(firebaseDependencies); const db = await getDbPromise(); const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite'); await tx.objectStore(OBJECT_STORE_NAME).put(tokenDetails, key); await tx.done; return tokenDetails; } /** Removes record(s) from the objectStore that match the given key. */ async function dbRemove(firebaseDependencies) { const key = getKey(firebaseDependencies); const db = await getDbPromise(); const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite'); await tx.objectStore(OBJECT_STORE_NAME).delete(key); await tx.done; } function getKey({ appConfig }) { return appConfig.appId; } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const ERROR_MAP = { ["missing-app-config-values" /* ErrorCode.MISSING_APP_CONFIG_VALUES */]: 'Missing App configuration value: "{$valueName}"', ["only-available-in-window" /* ErrorCode.AVAILABLE_IN_WINDOW */]: 'This method is available in a Window context.', ["only-available-in-sw" /* ErrorCode.AVAILABLE_IN_SW */]: 'This method is available in a service worker context.', ["permission-default" /* ErrorCode.PERMISSION_DEFAULT */]: 'The notification permission was not granted and dismissed instead.', ["permission-blocked" /* ErrorCode.PERMISSION_BLOCKED */]: 'The notification permission was not granted and blocked instead.', ["unsupported-browser" /* ErrorCode.UNSUPPORTED_BROWSER */]: "This browser doesn't support the API's required to use the Firebase SDK.", ["indexed-db-unsupported" /* ErrorCode.INDEXED_DB_UNSUPPORTED */]: "This browser doesn't support indexedDb.open() (ex. Safari iFrame, Firefox Private Browsing, etc)", ["failed-service-worker-registration" /* ErrorCode.FAILED_DEFAULT_REGISTRATION */]: 'We are unable to register the default service worker. {$browserErrorMessage}', ["token-subscribe-failed" /* ErrorCode.TOKEN_SUBSCRIBE_FAILED */]: 'A problem occurred while subscribing the user to FCM: {$errorInfo}', ["token-subscribe-no-token" /* ErrorCode.TOKEN_SUBSCRIBE_NO_TOKEN */]: 'FCM returned no token when subscribing the user to push.', ["token-unsubscribe-failed" /* ErrorCode.TOKEN_UNSUBSCRIBE_FAILED */]: 'A problem occurred while unsubscribing the ' + 'user from FCM: {$errorInfo}', ["token-update-failed" /* ErrorCode.TOKEN_UPDATE_FAILED */]: 'A problem occurred while updating the user from FCM: {$errorInfo}', ["token-update-no-token" /* ErrorCode.TOKEN_UPDATE_NO_TOKEN */]: 'FCM returned no token when updating the user to push.', ["use-sw-after-get-token" /* ErrorCode.USE_SW_AFTER_GET_TOKEN */]: 'The useServiceWorker() method may only be called once and must be ' + 'called before calling getToken() to ensure your service worker is used.', ["invalid-sw-registration" /* ErrorCode.INVALID_SW_REGISTRATION */]: 'The input to useServiceWorker() must be a ServiceWorkerRegistration.', ["invalid-bg-handler" /* ErrorCode.INVALID_BG_HANDLER */]: 'The input to setBackgroundMessageHandler() must be a function.', ["invalid-vapid-key" /* ErrorCode.INVALID_VAPID_KEY */]: 'The public VAPID key must be a string.', ["use-vapid-key-after-get-token" /* ErrorCode.USE_VAPID_KEY_AFTER_GET_TOKEN */]: 'The usePublicVapidKey() method may only be called once and must be ' + 'called before calling getToken() to ensure your VAPID key is used.' }; const ERROR_FACTORY = new _firebase_util__WEBPACK_IMPORTED_MODULE_3__.ErrorFactory('messaging', 'Messaging', ERROR_MAP); /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function requestGetToken(firebaseDependencies, subscriptionOptions) { const headers = await getHeaders(firebaseDependencies); const body = getBody(subscriptionOptions); const subscribeOptions = { method: 'POST', headers, body: JSON.stringify(body) }; let responseData; try { const response = await fetch(getEndpoint(firebaseDependencies.appConfig), subscribeOptions); responseData = await response.json(); } catch (err) { throw ERROR_FACTORY.create("token-subscribe-failed" /* ErrorCode.TOKEN_SUBSCRIBE_FAILED */, { errorInfo: err === null || err === void 0 ? void 0 : err.toString() }); } if (responseData.error) { const message = responseData.error.message; throw ERROR_FACTORY.create("token-subscribe-failed" /* ErrorCode.TOKEN_SUBSCRIBE_FAILED */, { errorInfo: message }); } if (!responseData.token) { throw ERROR_FACTORY.create("token-subscribe-no-token" /* ErrorCode.TOKEN_SUBSCRIBE_NO_TOKEN */); } return responseData.token; } async function requestUpdateToken(firebaseDependencies, tokenDetails) { const headers = await getHeaders(firebaseDependencies); const body = getBody(tokenDetails.subscriptionOptions); const updateOptions = { method: 'PATCH', headers, body: JSON.stringify(body) }; let responseData; try { const response = await fetch(`${getEndpoint(firebaseDependencies.appConfig)}/${tokenDetails.token}`, updateOptions); responseData = await response.json(); } catch (err) { throw ERROR_FACTORY.create("token-update-failed" /* ErrorCode.TOKEN_UPDATE_FAILED */, { errorInfo: err === null || err === void 0 ? void 0 : err.toString() }); } if (responseData.error) { const message = responseData.error.message; throw ERROR_FACTORY.create("token-update-failed" /* ErrorCode.TOKEN_UPDATE_FAILED */, { errorInfo: message }); } if (!responseData.token) { throw ERROR_FACTORY.create("token-update-no-token" /* ErrorCode.TOKEN_UPDATE_NO_TOKEN */); } return responseData.token; } async function requestDeleteToken(firebaseDependencies, token) { const headers = await getHeaders(firebaseDependencies); const unsubscribeOptions = { method: 'DELETE', headers }; try { const response = await fetch(`${getEndpoint(firebaseDependencies.appConfig)}/${token}`, unsubscribeOptions); const responseData = await response.json(); if (responseData.error) { const message = responseData.error.message; throw ERROR_FACTORY.create("token-unsubscribe-failed" /* ErrorCode.TOKEN_UNSUBSCRIBE_FAILED */, { errorInfo: message }); } } catch (err) { throw ERROR_FACTORY.create("token-unsubscribe-failed" /* ErrorCode.TOKEN_UNSUBSCRIBE_FAILED */, { errorInfo: err === null || err === void 0 ? void 0 : err.toString() }); } } function getEndpoint({ projectId }) { return `${ENDPOINT}/projects/${projectId}/registrations`; } async function getHeaders({ appConfig, installations }) { const authToken = await installations.getToken(); return new Headers({ 'Content-Type': 'application/json', Accept: 'application/json', 'x-goog-api-key': appConfig.apiKey, 'x-goog-firebase-installations-auth': `FIS ${authToken}` }); } function getBody({ p256dh, auth, endpoint, vapidKey }) { const body = { web: { endpoint, auth, p256dh } }; if (vapidKey !== DEFAULT_VAPID_KEY) { body.web.applicationPubKey = vapidKey; } return body; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // UpdateRegistration will be called once every week. const TOKEN_EXPIRATION_MS = 7 * 24 * 60 * 60 * 1000; // 7 days async function getTokenInternal(messaging) { const pushSubscription = await getPushSubscription(messaging.swRegistration, messaging.vapidKey); const subscriptionOptions = { vapidKey: messaging.vapidKey, swScope: messaging.swRegistration.scope, endpoint: pushSubscription.endpoint, auth: arrayToBase64(pushSubscription.getKey('auth')), p256dh: arrayToBase64(pushSubscription.getKey('p256dh')) }; const tokenDetails = await dbGet(messaging.firebaseDependencies); if (!tokenDetails) { // No token, get a new one. return getNewToken(messaging.firebaseDependencies, subscriptionOptions); } else if (!isTokenValid(tokenDetails.subscriptionOptions, subscriptionOptions)) { // Invalid token, get a new one. try { await requestDeleteToken(messaging.firebaseDependencies, tokenDetails.token); } catch (e) { // Suppress errors because of #2364 console.warn(e); } return getNewToken(messaging.firebaseDependencies, subscriptionOptions); } else if (Date.now() >= tokenDetails.createTime + TOKEN_EXPIRATION_MS) { // Weekly token refresh return updateToken(messaging, { token: tokenDetails.token, createTime: Date.now(), subscriptionOptions }); } else { // Valid token, nothing to do. return tokenDetails.token; } } /** * This method deletes the token from the database, unsubscribes the token from FCM, and unregisters * the push subscription if it exists. */ async function deleteTokenInternal(messaging) { const tokenDetails = await dbGet(messaging.firebaseDependencies); if (tokenDetails) { await requestDeleteToken(messaging.firebaseDependencies, tokenDetails.token); await dbRemove(messaging.firebaseDependencies); } // Unsubscribe from the push subscription. const pushSubscription = await messaging.swRegistration.pushManager.getSubscription(); if (pushSubscription) { return pushSubscription.unsubscribe(); } // If there's no SW, consider it a success. return true; } async function updateToken(messaging, tokenDetails) { try { const updatedToken = await requestUpdateToken(messaging.firebaseDependencies, tokenDetails); const updatedTokenDetails = Object.assign(Object.assign({}, tokenDetails), { token: updatedToken, createTime: Date.now() }); await dbSet(messaging.firebaseDependencies, updatedTokenDetails); return updatedToken; } catch (e) { await deleteTokenInternal(messaging); throw e; } } async function getNewToken(firebaseDependencies, subscriptionOptions) { const token = await requestGetToken(firebaseDependencies, subscriptionOptions); const tokenDetails = { token, createTime: Date.now(), subscriptionOptions }; await dbSet(firebaseDependencies, tokenDetails); return tokenDetails.token; } /** * Gets a PushSubscription for the current user. */ async function getPushSubscription(swRegistration, vapidKey) { const subscription = await swRegistration.pushManager.getSubscription(); if (subscription) { return subscription; } return swRegistration.pushManager.subscribe({ userVisibleOnly: true, // Chrome <= 75 doesn't support base64-encoded VAPID key. For backward compatibility, VAPID key // submitted to pushManager#subscribe must be of type Uint8Array. applicationServerKey: base64ToArray(vapidKey) }); } /** * Checks if the saved tokenDetails object matches the configuration provided. */ function isTokenValid(dbOptions, currentOptions) { const isVapidKeyEqual = currentOptions.vapidKey === dbOptions.vapidKey; const isEndpointEqual = currentOptions.endpoint === dbOptions.endpoint; const isAuthEqual = currentOptions.auth === dbOptions.auth; const isP256dhEqual = currentOptions.p256dh === dbOptions.p256dh; return isVapidKeyEqual && isEndpointEqual && isAuthEqual && isP256dhEqual; } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function externalizePayload(internalPayload) { const payload = { from: internalPayload.from, // eslint-disable-next-line camelcase collapseKey: internalPayload.collapse_key, // eslint-disable-next-line camelcase messageId: internalPayload.fcmMessageId }; propagateNotificationPayload(payload, internalPayload); propagateDataPayload(payload, internalPayload); propagateFcmOptions(payload, internalPayload); return payload; } function propagateNotificationPayload(payload, messagePayloadInternal) { if (!messagePayloadInternal.notification) { return; } payload.notification = {}; const title = messagePayloadInternal.notification.title; if (!!title) { payload.notification.title = title; } const body = messagePayloadInternal.notification.body; if (!!body) { payload.notification.body = body; } const image = messagePayloadInternal.notification.image; if (!!image) { payload.notification.image = image; } const icon = messagePayloadInternal.notification.icon; if (!!icon) { payload.notification.icon = icon; } } function propagateDataPayload(payload, messagePayloadInternal) { if (!messagePayloadInternal.data) { return; } payload.data = messagePayloadInternal.data; } function propagateFcmOptions(payload, messagePayloadInternal) { var _a, _b, _c, _d, _e; // fcmOptions.link value is written into notification.click_action. see more in b/232072111 if (!messagePayloadInternal.fcmOptions && !((_a = messagePayloadInternal.notification) === null || _a === void 0 ? void 0 : _a.click_action)) { return; } payload.fcmOptions = {}; const link = (_c = (_b = messagePayloadInternal.fcmOptions) === null || _b === void 0 ? void 0 : _b.link) !== null && _c !== void 0 ? _c : (_d = messagePayloadInternal.notification) === null || _d === void 0 ? void 0 : _d.click_action; if (!!link) { payload.fcmOptions.link = link; } // eslint-disable-next-line camelcase const analyticsLabel = (_e = messagePayloadInternal.fcmOptions) === null || _e === void 0 ? void 0 : _e.analytics_label; if (!!analyticsLabel) { payload.fcmOptions.analyticsLabel = analyticsLabel; } } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function isConsoleMessage(data) { // This message has a campaign ID, meaning it was sent using the Firebase Console. return typeof data === 'object' && !!data && CONSOLE_CAMPAIGN_ID in data; } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ _mergeStrings('hts/frbslgigp.ogepscmv/ieo/eaylg', 'tp:/ieaeogn-agolai.o/1frlglgc/o'); _mergeStrings('AzSCbw63g1R0nCw85jG8', 'Iaya3yLKwmgvh7cF0q4'); function _mergeStrings(s1, s2) { const resultArray = []; for (let i = 0; i < s1.length; i++) { resultArray.push(s1.charAt(i)); if (i < s2.length) { resultArray.push(s2.charAt(i)); } } return resultArray.join(''); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function extractAppConfig(app) { if (!app || !app.options) { throw getMissingValueError('App Configuration Object'); } if (!app.name) { throw getMissingValueError('App Name'); } // Required app config keys const configKeys = [ 'projectId', 'apiKey', 'appId', 'messagingSenderId' ]; const { options } = app; for (const keyName of configKeys) { if (!options[keyName]) { throw getMissingValueError(keyName); } } return { appName: app.name, projectId: options.projectId, apiKey: options.apiKey, appId: options.appId, senderId: options.messagingSenderId }; } function getMissingValueError(valueName) { return ERROR_FACTORY.create("missing-app-config-values" /* ErrorCode.MISSING_APP_CONFIG_VALUES */, { valueName }); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class MessagingService { constructor(app, installations, analyticsProvider) { // logging is only done with end user consent. Default to false. this.deliveryMetricsExportedToBigQueryEnabled = false; this.onBackgroundMessageHandler = null; this.onMessageHandler = null; this.logEvents = []; this.isLogServiceStarted = false; const appConfig = extractAppConfig(app); this.firebaseDependencies = { app, appConfig, installations, analyticsProvider }; } _delete() { return Promise.resolve(); } } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function registerDefaultSw(messaging) { try { messaging.swRegistration = await navigator.serviceWorker.register(DEFAULT_SW_PATH, { scope: DEFAULT_SW_SCOPE }); // The timing when browser updates sw when sw has an update is unreliable from experiment. It // leads to version conflict when the SDK upgrades to a newer version in the main page, but sw // is stuck with the old version. For example, // https://github.com/firebase/firebase-js-sdk/issues/2590 The following line reliably updates // sw if there was an update. messaging.swRegistration.update().catch(() => { /* it is non blocking and we don't care if it failed */ }); } catch (e) { throw ERROR_FACTORY.create("failed-service-worker-registration" /* ErrorCode.FAILED_DEFAULT_REGISTRATION */, { browserErrorMessage: e === null || e === void 0 ? void 0 : e.message }); } } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function updateSwReg(messaging, swRegistration) { if (!swRegistration && !messaging.swRegistration) { await registerDefaultSw(messaging); } if (!swRegistration && !!messaging.swRegistration) { return; } if (!(swRegistration instanceof ServiceWorkerRegistration)) { throw ERROR_FACTORY.create("invalid-sw-registration" /* ErrorCode.INVALID_SW_REGISTRATION */); } messaging.swRegistration = swRegistration; } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function updateVapidKey(messaging, vapidKey) { if (!!vapidKey) { messaging.vapidKey = vapidKey; } else if (!messaging.vapidKey) { messaging.vapidKey = DEFAULT_VAPID_KEY; } } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function getToken$1(messaging, options) { if (!navigator) { throw ERROR_FACTORY.create("only-available-in-window" /* ErrorCode.AVAILABLE_IN_WINDOW */); } if (Notification.permission === 'default') { await Notification.requestPermission(); } if (Notification.permission !== 'granted') { throw ERROR_FACTORY.create("permission-blocked" /* ErrorCode.PERMISSION_BLOCKED */); } await updateVapidKey(messaging, options === null || options === void 0 ? void 0 : options.vapidKey); await updateSwReg(messaging, options === null || options === void 0 ? void 0 : options.serviceWorkerRegistration); return getTokenInternal(messaging); } /** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function logToScion(messaging, messageType, data) { const eventType = getEventType(messageType); const analytics = await messaging.firebaseDependencies.analyticsProvider.get(); analytics.logEvent(eventType, { /* eslint-disable camelcase */ message_id: data[CONSOLE_CAMPAIGN_ID], message_name: data[CONSOLE_CAMPAIGN_NAME], message_time: data[CONSOLE_CAMPAIGN_TIME], message_device_time: Math.floor(Date.now() / 1000) /* eslint-enable camelcase */ }); } function getEventType(messageType) { switch (messageType) { case MessageType.NOTIFICATION_CLICKED: return 'notification_open'; case MessageType.PUSH_RECEIVED: return 'notification_foreground'; default: throw new Error(); } } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function messageEventListener(messaging, event) { const internalPayload = event.data; if (!internalPayload.isFirebaseMessaging) { return; } if (messaging.onMessageHandler && internalPayload.messageType === MessageType.PUSH_RECEIVED) { if (typeof messaging.onMessageHandler === 'function') { messaging.onMessageHandler(externalizePayload(internalPayload)); } else { messaging.onMessageHandler.next(externalizePayload(internalPayload)); } } // Log to Scion if applicable const dataPayload = internalPayload.data; if (isConsoleMessage(dataPayload) && dataPayload[CONSOLE_CAMPAIGN_ANALYTICS_ENABLED] === '1') { await logToScion(messaging, internalPayload.messageType, dataPayload); } } const name = "@firebase/messaging"; const version = "0.12.4"; /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const WindowMessagingFactory = (container) => { const messaging = new MessagingService(container.getProvider('app').getImmediate(), container.getProvider('installations-internal').getImmediate(), container.getProvider('analytics-internal')); navigator.serviceWorker.addEventListener('message', e => messageEventListener(messaging, e)); return messaging; }; const WindowMessagingInternalFactory = (container) => { const messaging = container .getProvider('messaging') .getImmediate(); const messagingInternal = { getToken: (options) => getToken$1(messaging, options) }; return messagingInternal; }; function registerMessagingInWindow() { (0,_firebase_app__WEBPACK_IMPORTED_MODULE_4__._registerComponent)(new _firebase_component__WEBPACK_IMPORTED_MODULE_1__.Component('messaging', WindowMessagingFactory, "PUBLIC" /* ComponentType.PUBLIC */)); (0,_firebase_app__WEBPACK_IMPORTED_MODULE_4__._registerComponent)(new _firebase_component__WEBPACK_IMPORTED_MODULE_1__.Component('messaging-internal', WindowMessagingInternalFactory, "PRIVATE" /* ComponentType.PRIVATE */)); (0,_firebase_app__WEBPACK_IMPORTED_MODULE_4__.registerVersion)(name, version); // BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation (0,_firebase_app__WEBPACK_IMPORTED_MODULE_4__.registerVersion)(name, version, 'esm2017'); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Checks if all required APIs exist in the browser. * @returns a Promise that resolves to a boolean. * * @public */ async function isWindowSupported() { try { // This throws if open() is unsupported, so adding it to the conditional // statement below can cause an uncaught error. await (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.validateIndexedDBOpenable)(); } catch (e) { return false; } // firebase-js-sdk/issues/2393 reveals that idb#open in Safari iframe and Firefox private browsing // might be prohibited to run. In these contexts, an error would be thrown during the messaging // instantiating phase, informing the developers to import/call isSupported for special handling. return (typeof window !== 'undefined' && (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.isIndexedDBAvailable)() && (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.areCookiesEnabled)() && 'serviceWorker' in navigator && 'PushManager' in window && 'Notification' in window && 'fetch' in window && ServiceWorkerRegistration.prototype.hasOwnProperty('showNotification') && PushSubscription.prototype.hasOwnProperty('getKey')); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ async function deleteToken$1(messaging) { if (!navigator) { throw ERROR_FACTORY.create("only-available-in-window" /* ErrorCode.AVAILABLE_IN_WINDOW */); } if (!messaging.swRegistration) { await registerDefaultSw(messaging); } return deleteTokenInternal(messaging); } /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function onMessage$1(messaging, nextOrObserver) { if (!navigator) { throw ERROR_FACTORY.create("only-available-in-window" /* ErrorCode.AVAILABLE_IN_WINDOW */); } messaging.onMessageHandler = nextOrObserver; return () => { messaging.onMessageHandler = null; }; } /** * @license * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Retrieves a Firebase Cloud Messaging instance. * * @returns The Firebase Cloud Messaging instance associated with the provided firebase app. * * @public */ function getMessagingInWindow(app = (0,_firebase_app__WEBPACK_IMPORTED_MODULE_4__.getApp)()) { // Conscious decision to make this async check non-blocking during the messaging instance // initialization phase for performance consideration. An error would be thrown latter for // developer's information. Developers can then choose to import and call `isSupported` for // special handling. isWindowSupported().then(isSupported => { // If `isWindowSupported()` resolved, but returned false. if (!isSupported) { throw ERROR_FACTORY.create("unsupported-browser" /* ErrorCode.UNSUPPORTED_BROWSER */); } }, _ => { // If `isWindowSupported()` rejected. throw ERROR_FACTORY.create("indexed-db-unsupported" /* ErrorCode.INDEXED_DB_UNSUPPORTED */); }); return (0,_firebase_app__WEBPACK_IMPORTED_MODULE_4__._getProvider)((0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.getModularInstance)(app), 'messaging').getImmediate(); } /** * Subscribes the {@link Messaging} instance to push notifications. Returns an Firebase Cloud * Messaging registration token that can be used to send push messages to that {@link Messaging} * instance. * * If a notification permission isn't already granted, this method asks the user for permission. The * returned promise rejects if the user does not allow the app to show notifications. * * @param messaging - The {@link Messaging} instance. * @param options - Provides an optional vapid key and an optinoal service worker registration * * @returns The promise resolves with an FCM registration token. * * @public */ async function getToken(messaging, options) { messaging = (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.getModularInstance)(messaging); return getToken$1(messaging, options); } /** * Deletes the registration token associated with this {@link Messaging} instance and unsubscribes * the {@link Messaging} instance from the push subscription. * * @param messaging - The {@link Messaging} instance. * * @returns The promise resolves when the token has been successfully deleted. * * @public */ function deleteToken(messaging) { messaging = (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.getModularInstance)(messaging); return deleteToken$1(messaging); } /** * When a push message is received and the user is currently on a page for your origin, the * message is passed to the page and an `onMessage()` event is dispatched with the payload of * the push message. * * * @param messaging - The {@link Messaging} instance. * @param nextOrObserver - This function, or observer object with `next` defined, * is called when a message is received and the user is currently viewing your page. * @returns To stop listening for messages execute this returned function. * * @public */ function onMessage(messaging, nextOrObserver) { messaging = (0,_firebase_util__WEBPACK_IMPORTED_MODULE_3__.getModularInstance)(messaging); return onMessage$1(messaging, nextOrObserver); } /** * Firebase Cloud Messaging * * @packageDocumentation */ registerMessagingInWindow(); //# sourceMappingURL=index.esm2017.js.map /***/ }), /***/ "./node_modules/firebase/app/dist/esm/index.esm.js": /*!*********************************************************!*\ !*** ./node_modules/firebase/app/dist/esm/index.esm.js ***! \*********************************************************/ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "FirebaseError": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.FirebaseError), /* harmony export */ "SDK_VERSION": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.SDK_VERSION), /* harmony export */ "_DEFAULT_ENTRY_NAME": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._DEFAULT_ENTRY_NAME), /* harmony export */ "_addComponent": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._addComponent), /* harmony export */ "_addOrOverwriteComponent": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._addOrOverwriteComponent), /* harmony export */ "_apps": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._apps), /* harmony export */ "_clearComponents": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._clearComponents), /* harmony export */ "_components": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._components), /* harmony export */ "_getProvider": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._getProvider), /* harmony export */ "_registerComponent": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._registerComponent), /* harmony export */ "_removeServiceInstance": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__._removeServiceInstance), /* harmony export */ "deleteApp": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.deleteApp), /* harmony export */ "getApp": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.getApp), /* harmony export */ "getApps": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.getApps), /* harmony export */ "initializeApp": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.initializeApp), /* harmony export */ "onLog": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.onLog), /* harmony export */ "registerVersion": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.registerVersion), /* harmony export */ "setLogLevel": () => (/* reexport safe */ _firebase_app__WEBPACK_IMPORTED_MODULE_0__.setLogLevel) /* harmony export */ }); /* harmony import */ var _firebase_app__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @firebase/app */ "./node_modules/@firebase/app/dist/esm/index.esm2017.js"); var name = "firebase"; var version = "9.18.0"; /** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ (0,_firebase_app__WEBPACK_IMPORTED_MODULE_0__.registerVersion)(name, version, 'app'); //# sourceMappingURL=index.esm.js.map /***/ }), /***/ "./node_modules/firebase/messaging/dist/esm/index.esm.js": /*!***************************************************************!*\ !*** ./node_modules/firebase/messaging/dist/esm/index.esm.js ***! \***************************************************************/ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "deleteToken": () => (/* reexport safe */ _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__.deleteToken), /* harmony export */ "getMessaging": () => (/* reexport safe */ _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__.getMessaging), /* harmony export */ "getToken": () => (/* reexport safe */ _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__.getToken), /* harmony export */ "isSupported": () => (/* reexport safe */ _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__.isSupported), /* harmony export */ "onMessage": () => (/* reexport safe */ _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__.onMessage) /* harmony export */ }); /* harmony import */ var _firebase_messaging__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @firebase/messaging */ "./node_modules/@firebase/messaging/dist/esm/index.esm2017.js"); //# sourceMappingURL=index.esm.js.map /***/ }), /***/ "./node_modules/idb/build/index.js": /*!*****************************************!*\ !*** ./node_modules/idb/build/index.js ***! \*****************************************/ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "deleteDB": () => (/* binding */ deleteDB), /* harmony export */ "openDB": () => (/* binding */ openDB), /* harmony export */ "unwrap": () => (/* reexport safe */ _wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.u), /* harmony export */ "wrap": () => (/* reexport safe */ _wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.w) /* harmony export */ }); /* harmony import */ var _wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./wrap-idb-value.js */ "./node_modules/idb/build/wrap-idb-value.js"); /** * Open a database. * * @param name Name of the database. * @param version Schema version. * @param callbacks Additional callbacks. */ function openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) { const request = indexedDB.open(name, version); const openPromise = (0,_wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.w)(request); if (upgrade) { request.addEventListener('upgradeneeded', (event) => { upgrade((0,_wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.w)(request.result), event.oldVersion, event.newVersion, (0,_wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.w)(request.transaction)); }); } if (blocked) request.addEventListener('blocked', () => blocked()); openPromise .then((db) => { if (terminated) db.addEventListener('close', () => terminated()); if (blocking) db.addEventListener('versionchange', () => blocking()); }) .catch(() => { }); return openPromise; } /** * Delete a database. * * @param name Name of the database. */ function deleteDB(name, { blocked } = {}) { const request = indexedDB.deleteDatabase(name); if (blocked) request.addEventListener('blocked', () => blocked()); return (0,_wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.w)(request).then(() => undefined); } const readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count']; const writeMethods = ['put', 'add', 'delete', 'clear']; const cachedMethods = new Map(); function getMethod(target, prop) { if (!(target instanceof IDBDatabase && !(prop in target) && typeof prop === 'string')) { return; } if (cachedMethods.get(prop)) return cachedMethods.get(prop); const targetFuncName = prop.replace(/FromIndex$/, ''); const useIndex = prop !== targetFuncName; const isWrite = writeMethods.includes(targetFuncName); if ( // Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge. !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) || !(isWrite || readMethods.includes(targetFuncName))) { return; } const method = async function (storeName, ...args) { // isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :( const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly'); let target = tx.store; if (useIndex) target = target.index(args.shift()); // Must reject if op rejects. // If it's a write operation, must reject if tx.done rejects. // Must reject with op rejection first. // Must resolve with op value. // Must handle both promises (no unhandled rejections) return (await Promise.all([ target[targetFuncName](...args), isWrite && tx.done, ]))[0]; }; cachedMethods.set(prop, method); return method; } (0,_wrap_idb_value_js__WEBPACK_IMPORTED_MODULE_0__.r)((oldTraps) => ({ ...oldTraps, get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver), has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop), })); /***/ }), /***/ "./node_modules/idb/build/wrap-idb-value.js": /*!**************************************************!*\ !*** ./node_modules/idb/build/wrap-idb-value.js ***! \**************************************************/ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "a": () => (/* binding */ reverseTransformCache), /* harmony export */ "i": () => (/* binding */ instanceOfAny), /* harmony export */ "r": () => (/* binding */ replaceTraps), /* harmony export */ "u": () => (/* binding */ unwrap), /* harmony export */ "w": () => (/* binding */ wrap) /* harmony export */ }); const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c); let idbProxyableTypes; let cursorAdvanceMethods; // This is a function to prevent it throwing up in node environments. function getIdbProxyableTypes() { return (idbProxyableTypes || (idbProxyableTypes = [ IDBDatabase, IDBObjectStore, IDBIndex, IDBCursor, IDBTransaction, ])); } // This is a function to prevent it throwing up in node environments. function getCursorAdvanceMethods() { return (cursorAdvanceMethods || (cursorAdvanceMethods = [ IDBCursor.prototype.advance, IDBCursor.prototype.continue, IDBCursor.prototype.continuePrimaryKey, ])); } const cursorRequestMap = new WeakMap(); const transactionDoneMap = new WeakMap(); const transactionStoreNamesMap = new WeakMap(); const transformCache = new WeakMap(); const reverseTransformCache = new WeakMap(); function promisifyRequest(request) { const promise = new Promise((resolve, reject) => { const unlisten = () => { request.removeEventListener('success', success); request.removeEventListener('error', error); }; const success = () => { resolve(wrap(request.result)); unlisten(); }; const error = () => { reject(request.error); unlisten(); }; request.addEventListener('success', success); request.addEventListener('error', error); }); promise .then((value) => { // Since cursoring reuses the IDBRequest (*sigh*), we cache it for later retrieval // (see wrapFunction). if (value instanceof IDBCursor) { cursorRequestMap.set(value, request); } // Catching to avoid "Uncaught Promise exceptions" }) .catch(() => { }); // This mapping exists in reverseTransformCache but doesn't doesn't exist in transformCache. This // is because we create many promises from a single IDBRequest. reverseTransformCache.set(promise, request); return promise; } function cacheDonePromiseForTransaction(tx) { // Early bail if we've already created a done promise for this transaction. if (transactionDoneMap.has(tx)) return; const done = new Promise((resolve, reject) => { const unlisten = () => { tx.removeEventListener('complete', complete); tx.removeEventListener('error', error); tx.removeEventListener('abort', error); }; const complete = () => { resolve(); unlisten(); }; const error = () => { reject(tx.error || new DOMException('AbortError', 'AbortError')); unlisten(); }; tx.addEventListener('complete', complete); tx.addEventListener('error', error); tx.addEventListener('abort', error); }); // Cache it for later retrieval. transactionDoneMap.set(tx, done); } let idbProxyTraps = { get(target, prop, receiver) { if (target instanceof IDBTransaction) { // Special handling for transaction.done. if (prop === 'done') return transactionDoneMap.get(target); // Polyfill for objectStoreNames because of Edge. if (prop === 'objectStoreNames') { return target.objectStoreNames || transactionStoreNamesMap.get(target); } // Make tx.store return the only store in the transaction, or undefined if there are many. if (prop === 'store') { return receiver.objectStoreNames[1] ? undefined : receiver.objectStore(receiver.objectStoreNames[0]); } } // Else transform whatever we get back. return wrap(target[prop]); }, set(target, prop, value) { target[prop] = value; return true; }, has(target, prop) { if (target instanceof IDBTransaction && (prop === 'done' || prop === 'store')) { return true; } return prop in target; }, }; function replaceTraps(callback) { idbProxyTraps = callback(idbProxyTraps); } function wrapFunction(func) { // Due to expected object equality (which is enforced by the caching in `wrap`), we // only create one new func per func. // Edge doesn't support objectStoreNames (booo), so we polyfill it here. if (func === IDBDatabase.prototype.transaction && !('objectStoreNames' in IDBTransaction.prototype)) { return function (storeNames, ...args) { const tx = func.call(unwrap(this), storeNames, ...args); transactionStoreNamesMap.set(tx, storeNames.sort ? storeNames.sort() : [storeNames]); return wrap(tx); }; } // Cursor methods are special, as the behaviour is a little more different to standard IDB. In // IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the // cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense // with real promises, so each advance methods returns a new promise for the cursor object, or // undefined if the end of the cursor has been reached. if (getCursorAdvanceMethods().includes(func)) { return function (...args) { // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use // the original object. func.apply(unwrap(this), args); return wrap(cursorRequestMap.get(this)); }; } return function (...args) { // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use // the original object. return wrap(func.apply(unwrap(this), args)); }; } function transformCachableValue(value) { if (typeof value === 'function') return wrapFunction(value); // This doesn't return, it just creates a 'done' promise for the transaction, // which is later returned for transaction.done (see idbObjectHandler). if (value instanceof IDBTransaction) cacheDonePromiseForTransaction(value); if (instanceOfAny(value, getIdbProxyableTypes())) return new Proxy(value, idbProxyTraps); // Return the same value back if we're not going to transform it. return value; } function wrap(value) { // We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because // IDB is weird and a single IDBRequest can yield many responses, so these can't be cached. if (value instanceof IDBRequest) return promisifyRequest(value); // If we've already transformed this value before, reuse the transformed value. // This is faster, but it also provides object equality. if (transformCache.has(value)) return transformCache.get(value); const newValue = transformCachableValue(value); // Not all types are transformed. // These may be primitive types, so they can't be WeakMap keys. if (newValue !== value) { transformCache.set(value, newValue); reverseTransformCache.set(newValue, value); } return newValue; } const unwrap = (value) => reverseTransformCache.get(value); /***/ }) /******/ }); /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ var cachedModule = __webpack_module_cache__[moduleId]; /******/ if (cachedModule !== undefined) { /******/ return cachedModule.exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = __webpack_module_cache__[moduleId] = { /******/ // no module.id needed /******/ // no module.loaded needed /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = __webpack_modules__; /******/ /************************************************************************/ /******/ /* webpack/runtime/compat get default export */ /******/ (() => { /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = (module) => { /******/ var getter = module && module.__esModule ? /******/ () => (module['default']) : /******/ () => (module); /******/ __webpack_require__.d(getter, { a: getter }); /******/ return getter; /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/create fake namespace object */ /******/ (() => { /******/ var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__); /******/ var leafPrototypes; /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 16: return value when it's Promise-like /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = this(value); /******/ if(mode & 8) return value; /******/ if(typeof value === 'object' && value) { /******/ if((mode & 4) && value.__esModule) return value; /******/ if((mode & 16) && typeof value.then === 'function') return value; /******/ } /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ var def = {}; /******/ leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)]; /******/ for(var current = mode & 2 && value; typeof current == 'object' && !~leafPrototypes.indexOf(current); current = getProto(current)) { /******/ Object.getOwnPropertyNames(current).forEach((key) => (def[key] = () => (value[key]))); /******/ } /******/ def['default'] = () => (value); /******/ __webpack_require__.d(ns, def); /******/ return ns; /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports /******/ __webpack_require__.d = (exports, definition) => { /******/ for(var key in definition) { /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); /******/ } /******/ } /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/ensure chunk */ /******/ (() => { /******/ __webpack_require__.f = {}; /******/ // This file contains only the entry chunk. /******/ // The chunk loading function for additional chunks /******/ __webpack_require__.e = (chunkId) => { /******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => { /******/ __webpack_require__.f[key](chunkId, promises); /******/ return promises; /******/ }, [])); /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/get javascript chunk filename */ /******/ (() => { /******/ // This function allow to reference async chunks /******/ __webpack_require__.u = (chunkId) => { /******/ // return url for filenames based on template /******/ return "" + chunkId + ".dev.js"; /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/global */ /******/ (() => { /******/ __webpack_require__.g = (function() { /******/ if (typeof globalThis === 'object') return globalThis; /******/ try { /******/ return this || new Function('return this')(); /******/ } catch (e) { /******/ if (typeof window === 'object') return window; /******/ } /******/ })(); /******/ })(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ (() => { /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) /******/ })(); /******/ /******/ /* webpack/runtime/load script */ /******/ (() => { /******/ var inProgress = {}; /******/ var dataWebpackPrefix = "tinode-webapp:"; /******/ // loadScript function to load a script via script tag /******/ __webpack_require__.l = (url, done, key, chunkId) => { /******/ if(inProgress[url]) { inProgress[url].push(done); return; } /******/ var script, needAttach; /******/ if(key !== undefined) { /******/ var scripts = document.getElementsByTagName("script"); /******/ for(var i = 0; i < scripts.length; i++) { /******/ var s = scripts[i]; /******/ if(s.getAttribute("src") == url || s.getAttribute("data-webpack") == dataWebpackPrefix + key) { script = s; break; } /******/ } /******/ } /******/ if(!script) { /******/ needAttach = true; /******/ script = document.createElement('script'); /******/ /******/ script.charset = 'utf-8'; /******/ script.timeout = 120; /******/ if (__webpack_require__.nc) { /******/ script.setAttribute("nonce", __webpack_require__.nc); /******/ } /******/ script.setAttribute("data-webpack", dataWebpackPrefix + key); /******/ script.src = url; /******/ } /******/ inProgress[url] = [done]; /******/ var onScriptComplete = (prev, event) => { /******/ // avoid mem leaks in IE. /******/ script.onerror = script.onload = null; /******/ clearTimeout(timeout); /******/ var doneFns = inProgress[url]; /******/ delete inProgress[url]; /******/ script.parentNode && script.parentNode.removeChild(script); /******/ doneFns && doneFns.forEach((fn) => (fn(event))); /******/ if(prev) return prev(event); /******/ } /******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000); /******/ script.onerror = onScriptComplete.bind(null, script.onerror); /******/ script.onload = onScriptComplete.bind(null, script.onload); /******/ needAttach && document.head.appendChild(script); /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/make namespace object */ /******/ (() => { /******/ // define __esModule on exports /******/ __webpack_require__.r = (exports) => { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/publicPath */ /******/ (() => { /******/ __webpack_require__.p = "/umd/"; /******/ })(); /******/ /******/ /* webpack/runtime/jsonp chunk loading */ /******/ (() => { /******/ // no baseURI /******/ /******/ // object to store loaded and loading chunks /******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched /******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded /******/ var installedChunks = { /******/ "index": 0 /******/ }; /******/ /******/ __webpack_require__.f.j = (chunkId, promises) => { /******/ // JSONP chunk loading for javascript /******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined; /******/ if(installedChunkData !== 0) { // 0 means "already installed". /******/ /******/ // a Promise means "currently loading". /******/ if(installedChunkData) { /******/ promises.push(installedChunkData[2]); /******/ } else { /******/ if(true) { // all chunks have JS /******/ // setup Promise in chunk cache /******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject])); /******/ promises.push(installedChunkData[2] = promise); /******/ /******/ // start chunk loading /******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId); /******/ // create error before stack unwound to get useful stacktrace later /******/ var error = new Error(); /******/ var loadingEnded = (event) => { /******/ if(__webpack_require__.o(installedChunks, chunkId)) { /******/ installedChunkData = installedChunks[chunkId]; /******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined; /******/ if(installedChunkData) { /******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type); /******/ var realSrc = event && event.target && event.target.src; /******/ error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')'; /******/ error.name = 'ChunkLoadError'; /******/ error.type = errorType; /******/ error.request = realSrc; /******/ installedChunkData[1](error); /******/ } /******/ } /******/ }; /******/ __webpack_require__.l(url, loadingEnded, "chunk-" + chunkId, chunkId); /******/ } else installedChunks[chunkId] = 0; /******/ } /******/ } /******/ }; /******/ /******/ // no prefetching /******/ /******/ // no preloaded /******/ /******/ // no HMR /******/ /******/ // no HMR manifest /******/ /******/ // no on chunks loaded /******/ /******/ // install a JSONP callback for chunk loading /******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { /******/ var [chunkIds, moreModules, runtime] = data; /******/ // add "moreModules" to the modules object, /******/ // then flag all "chunkIds" as loaded and fire callback /******/ var moduleId, chunkId, i = 0; /******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) { /******/ for(moduleId in moreModules) { /******/ if(__webpack_require__.o(moreModules, moduleId)) { /******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; /******/ } /******/ } /******/ if(runtime) var result = runtime(__webpack_require__); /******/ } /******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); /******/ for(;i < chunkIds.length; i++) { /******/ chunkId = chunkIds[i]; /******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { /******/ installedChunks[chunkId][0](); /******/ } /******/ installedChunks[chunkId] = 0; /******/ } /******/ /******/ } /******/ /******/ var chunkLoadingGlobal = globalThis["webpackChunktinode_webapp"] = globalThis["webpackChunktinode_webapp"] || []; /******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); /******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); /******/ })(); /******/ /************************************************************************/ var __webpack_exports__ = {}; // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. (() => { /*!**********************!*\ !*** ./src/index.js ***! \**********************/ __webpack_require__.r(__webpack_exports__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_dom_client__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-dom/client */ "./node_modules/react-dom/client.js"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react-intl */ "react-intl"); /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _views_tinode_web_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./views/tinode-web.jsx */ "./src/views/tinode-web.jsx"); /* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./lib/navigation.js */ "./src/lib/navigation.js"); if (typeof FIREBASE_INIT != 'undefined' && FIREBASE_INIT && FIREBASE_INIT.measurementId) { const head = document.getElementsByTagName('head')[0]; let script = document.createElement('script'); script.src = 'https://www.googletagmanager.com/gtag/js?id=' + FIREBASE_INIT.measurementId; script.async = true; head.prepend(script); window.dataLayer = window.dataLayer || []; function gtag() { dataLayer.push(arguments); } gtag('js', new Date()); gtag('config', FIREBASE_INIT.measurementId); } const messageLoader = { 'de': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_de_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/de.json */ "./src/i18n.min/de.json", 19)), 'en': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_en_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/en.json */ "./src/i18n.min/en.json", 19)), 'es': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_es_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/es.json */ "./src/i18n.min/es.json", 19)), 'fr': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_fr_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/fr.json */ "./src/i18n.min/fr.json", 19)), 'ko': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_ko_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/ko.json */ "./src/i18n.min/ko.json", 19)), 'ro': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_ro_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/ro.json */ "./src/i18n.min/ro.json", 19)), 'ru': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_ru_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/ru.json */ "./src/i18n.min/ru.json", 19)), 'zh': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_zh_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/zh.json */ "./src/i18n.min/zh.json", 19)), 'zh-TW': _ => __webpack_require__.e(/*! import() */ "src_i18n_min_zh-TW_json").then(__webpack_require__.t.bind(__webpack_require__, /*! ./i18n.min/zh-TW.json */ "./src/i18n.min/zh-TW.json", 19)) }; const { params } = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_4__["default"].parseUrlHash(window.location.hash); const language = params && params.hl || navigator.languages && navigator.languages[0] || navigator.language || navigator.userLanguage || 'en'; const normalized = language.replace('_', '-'); const baseLanguage = normalized.split('-')[0].toLowerCase(); const htmlLang = messageLoader[normalized] ? language : messageLoader[baseLanguage] ? baseLanguage : 'en'; document.getElementsByTagName('html')[0].setAttribute('lang', htmlLang); const root = (0,react_dom_client__WEBPACK_IMPORTED_MODULE_1__.createRoot)(document.getElementById('mountPoint')); messageLoader[htmlLang]().then(messages => root.render(react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_2__.IntlProvider, { locale: language, messages: messages, textComponent: (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment) }, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_views_tinode_web_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], null)))); })(); /******/ })() ; //# sourceMappingURL=index.dev.js.map