/******/ (() => { // 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-rc2"; /***/ }), /***/ "./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; let visibilityStatus = false; this.chatMessageRefs.every((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) { visibilityStatus = true; min = Math.min(min, seq); max = Math.max(max, seq); } else if (visibilityStatus) { return false; } } return true; }); 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, subsVersion: 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 || this.processingScrollEvent) { return; } if (event.target.scrollTop <= FETCH_PAGE_TRIGGER) { const topic = this.props.tinode.getTopic(this.state.topic); if (topic && topic.isSubscribed()) { this.processingScrollEvent = true; 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 })); }); } } } this.processingScrollEvent = 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, subsVersion: this.state.subsVersion + 1 }; 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" }] }, password_reset_success: { id: "password_reset_success", defaultMessage: [{ "type": 0, "value": "Password reset 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(_ => { this.handleError(this.props.intl.formatMessage(messages.password_reset_success), 'info'); _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 */ "./node_modules/livekit-client/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 */ "./node_modules/livekit-client/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 */ "./node_modules/livekit-client/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 (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; /***/ }), /***/ "./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.12"; /** * @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.22.2"; /** * @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 initializeApp() first', ["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 && (0,_firebase_util__WEBPACK_IMPORTED_MODULE_2__.getDefaultAppConfig)()) { 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(); const result = await db .transaction(STORE_NAME) .objectStore(STORE_NAME) .get(computeKey(app)); return result; } 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)); await 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/@firebase/installations/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/installations/node_modules/idb/build/index.js": /*!******************************************************************************!*\ !*** ./node_modules/@firebase/installations/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/@firebase/installations/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/@firebase/installations/node_modules/idb/build/wrap-idb-value.js": /*!***************************************************************************************!*\ !*** ./node_modules/@firebase/installations/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); /***/ }), /***/ "./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/@firebase/messaging/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/messaging/node_modules/idb/build/index.js": /*!**************************************************************************!*\ !*** ./node_modules/@firebase/messaging/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/@firebase/messaging/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/@firebase/messaging/node_modules/idb/build/wrap-idb-value.js": /*!***********************************************************************************!*\ !*** ./node_modules/@firebase/messaging/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); /***/ }), /***/ "./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.22.2"; /** * @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), event); }); } if (blocked) { request.addEventListener('blocked', (event) => blocked( // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405 event.oldVersion, event.newVersion, event)); } openPromise .then((db) => { if (terminated) db.addEventListener('close', () => terminated()); if (blocking) { db.addEventListener('versionchange', (event) => blocking(event.oldVersion, event.newVersion, event)); } }) .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', (event) => blocked( // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405 event.oldVersion, event)); } 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); /***/ }), /***/ "./node_modules/livekit-client/dist/livekit-client.esm.mjs": /*!*****************************************************************!*\ !*** ./node_modules/livekit-client/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 */ isCodecEqual: () => (/* binding */ isCodecEqual), /* 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 */ supportsVP9: () => (/* binding */ supportsVP9), /* 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 loglevel = {exports: {}}; /* * 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 loglevelExports = loglevel.exports; 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 } var long = Long; /** * wasm 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; } /** * 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, (value | 0) < 0 ? -1 : 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 (str === "NaN" || str === "Infinity" || str === "+Infinity" || str === "-Infinity") return ZERO; if (typeof unsigned === 'number') { // For goog.math.long compatibility radix = unsigned, unsigned = false; } else { unsigned = !!unsigned; } 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. * @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). * @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. * @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. * @returns {number} Signed high bits */ LongPrototype.getHighBits = function getHighBits() { return this.high; }; /** * Gets the high 32 bits as an unsigned integer. * @returns {number} Unsigned high bits */ LongPrototype.getHighBitsUnsigned = function getHighBitsUnsigned() { return this.high >>> 0; }; /** * Gets the low 32 bits as a signed integer. * @returns {number} Signed low bits */ LongPrototype.getLowBits = function getLowBits() { return this.low; }; /** * Gets the low 32 bits as an unsigned integer. * @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. * @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. * @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. * @returns {boolean} */ LongPrototype.isNegative = function isNegative() { return !this.unsigned && this.high < 0; }; /** * Tests if this Long's value is positive. * @returns {boolean} */ LongPrototype.isPositive = function isPositive() { return this.unsigned || this.high >= 0; }; /** * Tests if this Long's value is odd. * @returns {boolean} */ LongPrototype.isOdd = function isOdd() { return (this.low & 1) === 1; }; /** * Tests if this Long's value is even. * @returns {boolean} */ LongPrototype.isEven = function isEven() { return (this.low & 1) === 0; }; /** * Tests if this Long's value equals the specified's. * @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. * @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. * @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. * @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. * @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. * @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. * @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. * @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. * @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. * @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. * @param {!Long|number|string} multiplier Multiplier * @returns {!Long} Product */ LongPrototype.multiply = function multiply(multiplier) { if (this.isZero()) return ZERO; 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 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. * @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. * @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. * @returns {!Long} */ LongPrototype.not = function not() { return fromBits(~this.low, ~this.high, this.unsigned); }; /** * Returns the bitwise AND of this Long and the specified. * @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. * @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. * @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. * @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. * @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. * @param {number|!Long} numBits Number of bits * @returns {!Long} Shifted Long */ LongPrototype.shiftRightUnsigned = function shiftRightUnsigned(numBits) { if (isLong(numBits)) numBits = numBits.toInt(); numBits &= 63; if (numBits === 0) return this;else { var high = this.high; if (numBits < 32) { var low = this.low; return fromBits(low >>> numBits | high << 32 - numBits, high >>> numBits, this.unsigned); } else if (numBits === 32) return fromBits(high, 0, this.unsigned);else return fromBits(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; /** * Converts this Long to signed. * @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. * @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 * @returns {!Array.} Byte representation */ LongPrototype.toBytes = function toBytes(le) { return le ? this.toBytesLE() : this.toBytesBE(); }; /** * Converts this Long to its little endian byte representation. * @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. * @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 Long$1 = /*@__PURE__*/getDefaultExportFromCjs(long); var indexMinimal = {}; var minimal$1 = {}; var aspromise; var hasRequiredAspromise; function requireAspromise() { if (hasRequiredAspromise) return aspromise; hasRequiredAspromise = 1; 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); } } }); } return aspromise; } var base64$1 = {}; var hasRequiredBase64; function requireBase64() { if (hasRequiredBase64) return base64$1; hasRequiredBase64 = 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); return base64$1; } var eventemitter; var hasRequiredEventemitter; function requireEventemitter() { if (hasRequiredEventemitter) return eventemitter; hasRequiredEventemitter = 1; eventemitter = EventEmitter; /** * Constructs a new event emitter instance. * @classdesc A minimal event emitter. * @memberof util * @constructor */ function EventEmitter() { /** * 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.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.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.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; }; return eventemitter; } var float; var hasRequiredFloat; function requireFloat() { if (hasRequiredFloat) return float; hasRequiredFloat = 1; 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; } return float; } var inquire_1; var hasRequiredInquire; function requireInquire() { if (hasRequiredInquire) return inquire_1; hasRequiredInquire = 1; 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; } return inquire_1; } var utf8$2 = {}; var hasRequiredUtf8; function requireUtf8() { if (hasRequiredUtf8) return utf8$2; hasRequiredUtf8 = 1; (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); return utf8$2; } var pool_1; var hasRequiredPool; function requirePool() { if (hasRequiredPool) return pool_1; hasRequiredPool = 1; 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; }; } return pool_1; } 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$1; hasRequiredMinimal = 1; (function (exports) { var util = exports; // used to return a Promise where callback is omitted util.asPromise = requireAspromise(); // converts to / from base64 encoded strings util.base64 = requireBase64(); // base class of rpc.Service util.EventEmitter = requireEventemitter(); // float handling accross browsers util.float = requireFloat(); // requires modules optionally and hides the call from bundlers util.inquire = requireInquire(); // converts to / from utf8 encoded strings util.utf8 = requireUtf8(); // provides a node-like buffer pool in the browser util.pool = requirePool(); // 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: function 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: function 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$1); return minimal$1; } 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); var minimal = indexMinimal; var _m0 = /*@__PURE__*/getDefaultExportFromCjs(minimal); /* 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$1) { _m0.util.Long = Long$1; _m0.configure(); } /* eslint-disable */ var AudioCodec; (function (AudioCodec) { AudioCodec[AudioCodec["DEFAULT_AC"] = 0] = "DEFAULT_AC"; AudioCodec[AudioCodec["OPUS"] = 1] = "OPUS"; AudioCodec[AudioCodec["AAC"] = 2] = "AAC"; AudioCodec[AudioCodec["UNRECOGNIZED"] = -1] = "UNRECOGNIZED"; })(AudioCodec || (AudioCodec = {})); var VideoCodec; (function (VideoCodec) { VideoCodec[VideoCodec["DEFAULT_VC"] = 0] = "DEFAULT_VC"; VideoCodec[VideoCodec["H264_BASELINE"] = 1] = "H264_BASELINE"; VideoCodec[VideoCodec["H264_MAIN"] = 2] = "H264_MAIN"; VideoCodec[VideoCodec["H264_HIGH"] = 3] = "H264_HIGH"; VideoCodec[VideoCodec["VP8"] = 4] = "VP8"; VideoCodec[VideoCodec["UNRECOGNIZED"] = -1] = "UNRECOGNIZED"; })(VideoCodec || (VideoCodec = {})); 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 SubscriptionError; (function (SubscriptionError) { SubscriptionError[SubscriptionError["SE_UNKOWN"] = 0] = "SE_UNKOWN"; SubscriptionError[SubscriptionError["SE_CODEC_UNSUPPORTED"] = 1] = "SE_CODEC_UNSUPPORTED"; SubscriptionError[SubscriptionError["SE_TRACK_NOTFOUND"] = 2] = "SE_TRACK_NOTFOUND"; SubscriptionError[SubscriptionError["UNRECOGNIZED"] = -1] = "UNRECOGNIZED"; })(SubscriptionError || (SubscriptionError = {})); function subscriptionErrorFromJSON(object) { switch (object) { case 0: case "SE_UNKOWN": return SubscriptionError.SE_UNKOWN; case 1: case "SE_CODEC_UNSUPPORTED": return SubscriptionError.SE_CODEC_UNSUPPORTED; case 2: case "SE_TRACK_NOTFOUND": return SubscriptionError.SE_TRACK_NOTFOUND; case -1: case "UNRECOGNIZED": default: return SubscriptionError.UNRECOGNIZED; } } function subscriptionErrorToJSON(object) { switch (object) { case SubscriptionError.SE_UNKOWN: return "SE_UNKOWN"; case SubscriptionError.SE_CODEC_UNSUPPORTED: return "SE_CODEC_UNSUPPORTED"; case SubscriptionError.SE_TRACK_NOTFOUND: return "SE_TRACK_NOTFOUND"; case SubscriptionError.UNRECOGNIZED: default: return "UNRECOGNIZED"; } } 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["REACT_NATIVE"] = 7] = "REACT_NATIVE"; ClientInfo_SDK[ClientInfo_SDK["RUST"] = 8] = "RUST"; 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 7: case "REACT_NATIVE": return ClientInfo_SDK.REACT_NATIVE; case 8: case "RUST": return ClientInfo_SDK.RUST; 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.REACT_NATIVE: return "REACT_NATIVE"; case ClientInfo_SDK.RUST: return "RUST"; case ClientInfo_SDK.UNRECOGNIZED: default: return "UNRECOGNIZED"; } } function createBaseRoom() { return { sid: "", name: "", emptyTimeout: 0, maxParticipants: 0, creationTime: 0, turnPassword: "", enabledCodecs: [], metadata: "", numParticipants: 0, numPublishers: 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.numPublishers !== 0) { writer.uint32(88).uint32(message.numPublishers); } if (message.activeRecording === true) { writer.uint32(80).bool(message.activeRecording); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(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: if (tag !== 10) { break; } message.sid = reader.string(); continue; case 2: if (tag !== 18) { break; } message.name = reader.string(); continue; case 3: if (tag !== 24) { break; } message.emptyTimeout = reader.uint32(); continue; case 4: if (tag !== 32) { break; } message.maxParticipants = reader.uint32(); continue; case 5: if (tag !== 40) { break; } message.creationTime = longToNumber$1(reader.int64()); continue; case 6: if (tag !== 50) { break; } message.turnPassword = reader.string(); continue; case 7: if (tag !== 58) { break; } message.enabledCodecs.push(Codec.decode(reader, reader.uint32())); continue; case 8: if (tag !== 66) { break; } message.metadata = reader.string(); continue; case 9: if (tag !== 72) { break; } message.numParticipants = reader.uint32(); continue; case 11: if (tag !== 88) { break; } message.numPublishers = reader.uint32(); continue; case 10: if (tag !== 80) { break; } message.activeRecording = reader.bool(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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, numPublishers: isSet$1(object.numPublishers) ? Number(object.numPublishers) : 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.numPublishers !== undefined && (obj.numPublishers = Math.round(message.numPublishers)); 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, _l; 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.numPublishers = (_k = object.numPublishers) !== null && _k !== void 0 ? _k : 0; message.activeRecording = (_l = object.activeRecording) !== null && _l !== void 0 ? _l : 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.mime = reader.string(); continue; case 2: if (tag !== 18) { break; } message.fmtpLine = reader.string(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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, canUpdateMetadata: 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); } if (message.canUpdateMetadata === true) { writer.uint32(80).bool(message.canUpdateMetadata); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(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: if (tag !== 8) { break; } message.canSubscribe = reader.bool(); continue; case 2: if (tag !== 16) { break; } message.canPublish = reader.bool(); continue; case 3: if (tag !== 24) { break; } message.canPublishData = reader.bool(); continue; case 9: if (tag === 72) { message.canPublishSources.push(reader.int32()); continue; } if (tag === 74) { const end2 = reader.uint32() + reader.pos; while (reader.pos < end2) { message.canPublishSources.push(reader.int32()); } continue; } break; case 7: if (tag !== 56) { break; } message.hidden = reader.bool(); continue; case 8: if (tag !== 64) { break; } message.recorder = reader.bool(); continue; case 10: if (tag !== 80) { break; } message.canUpdateMetadata = reader.bool(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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, canUpdateMetadata: isSet$1(object.canUpdateMetadata) ? Boolean(object.canUpdateMetadata) : 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); message.canUpdateMetadata !== undefined && (obj.canUpdateMetadata = message.canUpdateMetadata); return obj; }, create(base) { return ParticipantPermission.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c, _d, _e, _f, _g; 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; message.canUpdateMetadata = (_g = object.canUpdateMetadata) !== null && _g !== void 0 ? _g : 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.sid = reader.string(); continue; case 2: if (tag !== 18) { break; } message.identity = reader.string(); continue; case 3: if (tag !== 24) { break; } message.state = reader.int32(); continue; case 4: if (tag !== 34) { break; } message.tracks.push(TrackInfo.decode(reader, reader.uint32())); continue; case 5: if (tag !== 42) { break; } message.metadata = reader.string(); continue; case 6: if (tag !== 48) { break; } message.joinedAt = longToNumber$1(reader.int64()); continue; case 9: if (tag !== 74) { break; } message.name = reader.string(); continue; case 10: if (tag !== 80) { break; } message.version = reader.uint32(); continue; case 11: if (tag !== 90) { break; } message.permission = ParticipantPermission.decode(reader, reader.uint32()); continue; case 12: if (tag !== 98) { break; } message.region = reader.string(); continue; case 13: if (tag !== 104) { break; } message.isPublisher = reader.bool(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.mimeType = reader.string(); continue; case 2: if (tag !== 18) { break; } message.mid = reader.string(); continue; case 3: if (tag !== 26) { break; } message.cid = reader.string(); continue; case 4: if (tag !== 34) { break; } message.layers.push(VideoLayer.decode(reader, reader.uint32())); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.sid = reader.string(); continue; case 2: if (tag !== 16) { break; } message.type = reader.int32(); continue; case 3: if (tag !== 26) { break; } message.name = reader.string(); continue; case 4: if (tag !== 32) { break; } message.muted = reader.bool(); continue; case 5: if (tag !== 40) { break; } message.width = reader.uint32(); continue; case 6: if (tag !== 48) { break; } message.height = reader.uint32(); continue; case 7: if (tag !== 56) { break; } message.simulcast = reader.bool(); continue; case 8: if (tag !== 64) { break; } message.disableDtx = reader.bool(); continue; case 9: if (tag !== 72) { break; } message.source = reader.int32(); continue; case 10: if (tag !== 82) { break; } message.layers.push(VideoLayer.decode(reader, reader.uint32())); continue; case 11: if (tag !== 90) { break; } message.mimeType = reader.string(); continue; case 12: if (tag !== 98) { break; } message.mid = reader.string(); continue; case 13: if (tag !== 106) { break; } message.codecs.push(SimulcastCodecInfo.decode(reader, reader.uint32())); continue; case 14: if (tag !== 112) { break; } message.stereo = reader.bool(); continue; case 15: if (tag !== 120) { break; } message.disableRed = reader.bool(); continue; case 16: if (tag !== 128) { break; } message.encryption = reader.int32(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 8) { break; } message.quality = reader.int32(); continue; case 2: if (tag !== 16) { break; } message.width = reader.uint32(); continue; case 3: if (tag !== 24) { break; } message.height = reader.uint32(); continue; case 4: if (tag !== 32) { break; } message.bitrate = reader.uint32(); continue; case 5: if (tag !== 40) { break; } message.ssrc = reader.uint32(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 8) { break; } message.kind = reader.int32(); continue; case 2: if (tag !== 18) { break; } message.value = { $case: "user", user: UserPacket.decode(reader, reader.uint32()) }; continue; case 3: if (tag !== 26) { break; } message.value = { $case: "speaker", speaker: ActiveSpeakerUpdate.decode(reader, reader.uint32()) }; continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.speakers.push(SpeakerInfo.decode(reader, reader.uint32())); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.sid = reader.string(); continue; case 2: if (tag !== 21) { break; } message.level = reader.float(); continue; case 3: if (tag !== 24) { break; } message.active = reader.bool(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.participantSid = reader.string(); continue; case 2: if (tag !== 18) { break; } message.payload = reader.bytes(); continue; case 3: if (tag !== 26) { break; } message.destinationSids.push(reader.string()); continue; case 4: if (tag !== 34) { break; } message.topic = reader.string(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } return message; }, fromJSON(object) { return { participantSid: isSet$1(object.participantSid) ? String(object.participantSid) : "", payload: isSet$1(object.payload) ? bytesFromBase64$1(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$1(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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.participantSid = reader.string(); continue; case 2: if (tag !== 18) { break; } message.trackSids.push(reader.string()); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 8) { break; } message.edition = reader.int32(); continue; case 2: if (tag !== 18) { break; } message.version = reader.string(); continue; case 3: if (tag !== 24) { break; } message.protocol = reader.int32(); continue; case 4: if (tag !== 34) { break; } message.region = reader.string(); continue; case 5: if (tag !== 42) { break; } message.nodeId = reader.string(); continue; case 6: if (tag !== 50) { break; } message.debugInfo = reader.string(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 8) { break; } message.sdk = reader.int32(); continue; case 2: if (tag !== 18) { break; } message.version = reader.string(); continue; case 3: if (tag !== 24) { break; } message.protocol = reader.int32(); continue; case 4: if (tag !== 34) { break; } message.os = reader.string(); continue; case 5: if (tag !== 42) { break; } message.osVersion = reader.string(); continue; case 6: if (tag !== 50) { break; } message.deviceModel = reader.string(); continue; case 7: if (tag !== 58) { break; } message.browser = reader.string(); continue; case 8: if (tag !== 66) { break; } message.browserVersion = reader.string(); continue; case 9: if (tag !== 74) { break; } message.address = reader.string(); continue; case 10: if (tag !== 82) { break; } message.network = reader.string(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.video = VideoConfiguration.decode(reader, reader.uint32()); continue; case 2: if (tag !== 18) { break; } message.screen = VideoConfiguration.decode(reader, reader.uint32()); continue; case 3: if (tag !== 24) { break; } message.resumeConnection = reader.int32(); continue; case 4: if (tag !== 34) { break; } message.disabledCodecs = DisabledCodecs.decode(reader, reader.uint32()); continue; case 5: if (tag !== 40) { break; } message.forceRelay = reader.int32(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 8) { break; } message.hardwareEncoder = reader.int32(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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: [], publish: [] }; } 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(); } for (const v of message.publish) { Codec.encode(v, writer.uint32(18).fork()).ldelim(); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(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: if (tag !== 10) { break; } message.codecs.push(Codec.decode(reader, reader.uint32())); continue; case 2: if (tag !== 18) { break; } message.publish.push(Codec.decode(reader, reader.uint32())); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } return message; }, fromJSON(object) { return { codecs: Array.isArray(object === null || object === void 0 ? void 0 : object.codecs) ? object.codecs.map(e => Codec.fromJSON(e)) : [], publish: Array.isArray(object === null || object === void 0 ? void 0 : object.publish) ? object.publish.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 = []; } if (message.publish) { obj.publish = message.publish.map(e => e ? Codec.toJSON(e) : undefined); } else { obj.publish = []; } return obj; }, create(base) { return DisabledCodecs.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b; const message = createBaseDisabledCodecs(); message.codecs = ((_a = object.codecs) === null || _a === void 0 ? void 0 : _a.map(e => Codec.fromPartial(e))) || []; message.publish = ((_b = object.publish) === null || _b === void 0 ? void 0 : _b.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$1(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$1(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$1) { _m0.util.Long = Long$1; _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; } } /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise */ function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __values(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); } function __asyncValues(o) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var m = o[Symbol.asyncIterator], i; return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } } var events = {exports: {}}; 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; events.exports.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); } } var eventsExports = events.exports; /* * 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. */ /* eslint-env node */ 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) { // 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. */ /* eslint-env node */ 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. */ /* eslint-env node */ 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. */ /* eslint-env node */ 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. */ /* eslint-env node */ 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. */ /* eslint-env node */ 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. */ /* eslint-env node */ 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 = []; // WebIDL input coercion and validation let sendEncodings = arguments[1] && arguments[1].sendEncodings; if (sendEncodings === undefined) { sendEncodings = []; } sendEncodings = [...sendEncodings]; const shouldPerformCheck = sendEncodings.length > 0; if (shouldPerformCheck) { // If sendEncodings params are provided, validate grammar 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 = sendEncodings; sender.sendEncodings = 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.urls === undefined && server.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 sdp$1 = {exports: {}}; /* 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).substring(2, 12); }; // 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.substring(14).split(' '); }; // Parses a rtpmap line, returns RTCRtpCoddecParameters. Sample input: // a=rtpmap:111 opus/48000/2 SDPUtils.parseRtpMap = function (line) { let parts = line.substring(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.substring(9).split(' '); return { id: parseInt(parts[0], 10), direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv', uri: parts[1], attributes: parts.slice(2).join(' ') }; }; // 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 + (headerExtension.attributes ? ' ' + headerExtension.attributes : '') + '\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.substring(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.substring(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.substring(7, sp), 10) }; const colon = line.indexOf(':', sp); if (colon > -1) { parts.attribute = line.substring(sp + 1, colon); parts.value = line.substring(colon + 1); } else { parts.attribute = line.substring(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.substring(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.substring(6); } }; // Parses a fingerprint line for DTLS-SRTP. SDPUtils.parseFingerprint = function (line) { const parts = line.substring(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.substring(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.substring(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.substring(12), password: pwd.substring(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(' '); description.profile = mline[2]; 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)); }); const wildcardRtcpFb = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-fb:* ').map(SDPUtils.parseRtcpFb); description.codecs.forEach(codec => { wildcardRtcpFb.forEach(fb => { const duplicate = codec.rtcpFeedback.find(existingFeedback => { return existingFeedback.type === fb.type && existingFeedback.parameter === fb.parameter; }); if (!duplicate) { codec.rtcpFeedback.push(fb); } }); }); // 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 += ' ' + (caps.profile || '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.substring(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].substring(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].substring(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].substring(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].substring(19), 10); } if (isNaN(maxMessageSize)) { maxMessageSize = 65536; } const sctpPort = SDPUtils.matchPrefix(mediaSection, 'a=sctp-port:'); if (sctpPort.length > 0) { return { port: parseInt(sctpPort[0].substring(12), 10), protocol: mline.fmt, maxMessageSize }; } const sctpMapLines = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:'); if (sctpMapLines.length > 0) { const parts = sctpMapLines[0].substring(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, 22); }; // 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].substring(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].substring(2); }; SDPUtils.isRejected = function (mediaSection) { return mediaSection.split(' ', 2)[1] === '0'; }; SDPUtils.parseMLine = function (mediaSection) { const lines = SDPUtils.splitLines(mediaSection); const parts = lines[0].substring(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.substring(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 sdpExports = sdp$1.exports; var SDPUtils = /*@__PURE__*/getDefaultExportFromCjs(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. */ /* eslint-env node */ 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.substring(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); for (const key in parsedCandidate) { if (!(key in nativeCandidate)) { Object.defineProperty(nativeCandidate, key, { value: parsedCandidate[key] }); } } // Override serializer to not serialize the extra attributes. nativeCandidate.toJSON = function toJSON() { return { candidate: nativeCandidate.candidate, sdpMid: nativeCandidate.sdpMid, sdpMLineIndex: nativeCandidate.sdpMLineIndex, usernameFragment: nativeCandidate.usernameFragment }; }; return nativeCandidate; } 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 shimRTCIceCandidateRelayProtocol(window) { if (!window.RTCIceCandidate || window.RTCIceCandidate && 'relayProtocol' in window.RTCIceCandidate.prototype) { return; } // Hook up the augmented candidate in onicecandidate and // addEventListener('icecandidate', ...) wrapPeerConnectionEvent(window, 'icecandidate', e => { if (e.candidate) { const parsedCandidate = SDPUtils.parseCandidate(e.candidate.candidate); if (parsedCandidate.type === 'relay') { // This is a libwebrtc-specific mapping of local type preference // to relayProtocol. e.candidate.relayProtocol = { 0: 'tls', 1: 'tcp', 2: 'udp' }[parsedCandidate.priority >> 24]; } } 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].substring(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, shimRTCIceCandidateRelayProtocol: shimRTCIceCandidateRelayProtocol, 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); shimRTCIceCandidateRelayProtocol(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); shimRTCIceCandidateRelayProtocol(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. */ /* eslint-env node */ 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.message = { $case: "offer", offer: SessionDescription.decode(reader, reader.uint32()) }; continue; case 2: if (tag !== 18) { break; } message.message = { $case: "answer", answer: SessionDescription.decode(reader, reader.uint32()) }; continue; case 3: if (tag !== 26) { break; } message.message = { $case: "trickle", trickle: TrickleRequest.decode(reader, reader.uint32()) }; continue; case 4: if (tag !== 34) { break; } message.message = { $case: "addTrack", addTrack: AddTrackRequest.decode(reader, reader.uint32()) }; continue; case 5: if (tag !== 42) { break; } message.message = { $case: "mute", mute: MuteTrackRequest.decode(reader, reader.uint32()) }; continue; case 6: if (tag !== 50) { break; } message.message = { $case: "subscription", subscription: UpdateSubscription.decode(reader, reader.uint32()) }; continue; case 7: if (tag !== 58) { break; } message.message = { $case: "trackSetting", trackSetting: UpdateTrackSettings.decode(reader, reader.uint32()) }; continue; case 8: if (tag !== 66) { break; } message.message = { $case: "leave", leave: LeaveRequest.decode(reader, reader.uint32()) }; continue; case 10: if (tag !== 82) { break; } message.message = { $case: "updateLayers", updateLayers: UpdateVideoLayers.decode(reader, reader.uint32()) }; continue; case 11: if (tag !== 90) { break; } message.message = { $case: "subscriptionPermission", subscriptionPermission: SubscriptionPermission.decode(reader, reader.uint32()) }; continue; case 12: if (tag !== 98) { break; } message.message = { $case: "syncState", syncState: SyncState.decode(reader, reader.uint32()) }; continue; case 13: if (tag !== 106) { break; } message.message = { $case: "simulate", simulate: SimulateScenario.decode(reader, reader.uint32()) }; continue; case 14: if (tag !== 112) { break; } message.message = { $case: "ping", ping: longToNumber(reader.int64()) }; continue; case 15: if (tag !== 122) { break; } message.message = { $case: "updateMetadata", updateMetadata: UpdateParticipantMetadata.decode(reader, reader.uint32()) }; continue; case 16: if (tag !== 130) { break; } message.message = { $case: "pingReq", pingReq: Ping.decode(reader, reader.uint32()) }; continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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; case "subscriptionResponse": SubscriptionResponse.encode(message.message.subscriptionResponse, writer.uint32(170).fork()).ldelim(); break; } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(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: if (tag !== 10) { break; } message.message = { $case: "join", join: JoinResponse.decode(reader, reader.uint32()) }; continue; case 2: if (tag !== 18) { break; } message.message = { $case: "answer", answer: SessionDescription.decode(reader, reader.uint32()) }; continue; case 3: if (tag !== 26) { break; } message.message = { $case: "offer", offer: SessionDescription.decode(reader, reader.uint32()) }; continue; case 4: if (tag !== 34) { break; } message.message = { $case: "trickle", trickle: TrickleRequest.decode(reader, reader.uint32()) }; continue; case 5: if (tag !== 42) { break; } message.message = { $case: "update", update: ParticipantUpdate.decode(reader, reader.uint32()) }; continue; case 6: if (tag !== 50) { break; } message.message = { $case: "trackPublished", trackPublished: TrackPublishedResponse.decode(reader, reader.uint32()) }; continue; case 8: if (tag !== 66) { break; } message.message = { $case: "leave", leave: LeaveRequest.decode(reader, reader.uint32()) }; continue; case 9: if (tag !== 74) { break; } message.message = { $case: "mute", mute: MuteTrackRequest.decode(reader, reader.uint32()) }; continue; case 10: if (tag !== 82) { break; } message.message = { $case: "speakersChanged", speakersChanged: SpeakersChanged.decode(reader, reader.uint32()) }; continue; case 11: if (tag !== 90) { break; } message.message = { $case: "roomUpdate", roomUpdate: RoomUpdate.decode(reader, reader.uint32()) }; continue; case 12: if (tag !== 98) { break; } message.message = { $case: "connectionQuality", connectionQuality: ConnectionQualityUpdate.decode(reader, reader.uint32()) }; continue; case 13: if (tag !== 106) { break; } message.message = { $case: "streamStateUpdate", streamStateUpdate: StreamStateUpdate.decode(reader, reader.uint32()) }; continue; case 14: if (tag !== 114) { break; } message.message = { $case: "subscribedQualityUpdate", subscribedQualityUpdate: SubscribedQualityUpdate.decode(reader, reader.uint32()) }; continue; case 15: if (tag !== 122) { break; } message.message = { $case: "subscriptionPermissionUpdate", subscriptionPermissionUpdate: SubscriptionPermissionUpdate.decode(reader, reader.uint32()) }; continue; case 16: if (tag !== 130) { break; } message.message = { $case: "refreshToken", refreshToken: reader.string() }; continue; case 17: if (tag !== 138) { break; } message.message = { $case: "trackUnpublished", trackUnpublished: TrackUnpublishedResponse.decode(reader, reader.uint32()) }; continue; case 18: if (tag !== 144) { break; } message.message = { $case: "pong", pong: longToNumber(reader.int64()) }; continue; case 19: if (tag !== 154) { break; } message.message = { $case: "reconnect", reconnect: ReconnectResponse.decode(reader, reader.uint32()) }; continue; case 20: if (tag !== 162) { break; } message.message = { $case: "pongResp", pongResp: Pong.decode(reader, reader.uint32()) }; continue; case 21: if (tag !== 170) { break; } message.message = { $case: "subscriptionResponse", subscriptionResponse: SubscriptionResponse.decode(reader, reader.uint32()) }; continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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) } : isSet(object.subscriptionResponse) ? { $case: "subscriptionResponse", subscriptionResponse: SubscriptionResponse.fromJSON(object.subscriptionResponse) } : 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, _31, _32, _33; 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); ((_31 = message.message) === null || _31 === void 0 ? void 0 : _31.$case) === "subscriptionResponse" && (obj.subscriptionResponse = ((_32 = message.message) === null || _32 === void 0 ? void 0 : _32.subscriptionResponse) ? SubscriptionResponse.toJSON((_33 = message.message) === null || _33 === void 0 ? void 0 : _33.subscriptionResponse) : 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, _33, _34, _35; 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) }; } if (((_33 = object.message) === null || _33 === void 0 ? void 0 : _33.$case) === "subscriptionResponse" && ((_34 = object.message) === null || _34 === void 0 ? void 0 : _34.subscriptionResponse) !== undefined && ((_35 = object.message) === null || _35 === void 0 ? void 0 : _35.subscriptionResponse) !== null) { message.message = { $case: "subscriptionResponse", subscriptionResponse: SubscriptionResponse.fromPartial(object.message.subscriptionResponse) }; } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.codec = reader.string(); continue; case 2: if (tag !== 18) { break; } message.cid = reader.string(); continue; case 3: if (tag !== 24) { break; } message.enableSimulcastLayers = reader.bool(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.cid = reader.string(); continue; case 2: if (tag !== 18) { break; } message.name = reader.string(); continue; case 3: if (tag !== 24) { break; } message.type = reader.int32(); continue; case 4: if (tag !== 32) { break; } message.width = reader.uint32(); continue; case 5: if (tag !== 40) { break; } message.height = reader.uint32(); continue; case 6: if (tag !== 48) { break; } message.muted = reader.bool(); continue; case 7: if (tag !== 56) { break; } message.disableDtx = reader.bool(); continue; case 8: if (tag !== 64) { break; } message.source = reader.int32(); continue; case 9: if (tag !== 74) { break; } message.layers.push(VideoLayer.decode(reader, reader.uint32())); continue; case 10: if (tag !== 82) { break; } message.simulcastCodecs.push(SimulcastCodec.decode(reader, reader.uint32())); continue; case 11: if (tag !== 90) { break; } message.sid = reader.string(); continue; case 12: if (tag !== 96) { break; } message.stereo = reader.bool(); continue; case 13: if (tag !== 104) { break; } message.disableRed = reader.bool(); continue; case 14: if (tag !== 112) { break; } message.encryption = reader.int32(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.candidateInit = reader.string(); continue; case 2: if (tag !== 16) { break; } message.target = reader.int32(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.sid = reader.string(); continue; case 2: if (tag !== 16) { break; } message.muted = reader.bool(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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, sifTrailer: new Uint8Array() }; } 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(); } if (message.sifTrailer.length !== 0) { writer.uint32(106).bytes(message.sifTrailer); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(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: if (tag !== 10) { break; } message.room = Room$1.decode(reader, reader.uint32()); continue; case 2: if (tag !== 18) { break; } message.participant = ParticipantInfo.decode(reader, reader.uint32()); continue; case 3: if (tag !== 26) { break; } message.otherParticipants.push(ParticipantInfo.decode(reader, reader.uint32())); continue; case 4: if (tag !== 34) { break; } message.serverVersion = reader.string(); continue; case 5: if (tag !== 42) { break; } message.iceServers.push(ICEServer.decode(reader, reader.uint32())); continue; case 6: if (tag !== 48) { break; } message.subscriberPrimary = reader.bool(); continue; case 7: if (tag !== 58) { break; } message.alternativeUrl = reader.string(); continue; case 8: if (tag !== 66) { break; } message.clientConfiguration = ClientConfiguration.decode(reader, reader.uint32()); continue; case 9: if (tag !== 74) { break; } message.serverRegion = reader.string(); continue; case 10: if (tag !== 80) { break; } message.pingTimeout = reader.int32(); continue; case 11: if (tag !== 88) { break; } message.pingInterval = reader.int32(); continue; case 12: if (tag !== 98) { break; } message.serverInfo = ServerInfo.decode(reader, reader.uint32()); continue; case 13: if (tag !== 106) { break; } message.sifTrailer = reader.bytes(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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, sifTrailer: isSet(object.sifTrailer) ? bytesFromBase64(object.sifTrailer) : new Uint8Array() }; }, 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); message.sifTrailer !== undefined && (obj.sifTrailer = base64FromBytes(message.sifTrailer !== undefined ? message.sifTrailer : new Uint8Array())); return obj; }, create(base) { return JoinResponse.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b, _c, _d, _e, _f, _g, _h, _j; 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; message.sifTrailer = (_j = object.sifTrailer) !== null && _j !== void 0 ? _j : new Uint8Array(); 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.iceServers.push(ICEServer.decode(reader, reader.uint32())); continue; case 2: if (tag !== 18) { break; } message.clientConfiguration = ClientConfiguration.decode(reader, reader.uint32()); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.cid = reader.string(); continue; case 2: if (tag !== 18) { break; } message.track = TrackInfo.decode(reader, reader.uint32()); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.trackSid = reader.string(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.type = reader.string(); continue; case 2: if (tag !== 18) { break; } message.sdp = reader.string(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.participants.push(ParticipantInfo.decode(reader, reader.uint32())); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.trackSids.push(reader.string()); continue; case 2: if (tag !== 16) { break; } message.subscribe = reader.bool(); continue; case 3: if (tag !== 26) { break; } message.participantTracks.push(ParticipantTracks.decode(reader, reader.uint32())); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.trackSids.push(reader.string()); continue; case 3: if (tag !== 24) { break; } message.disabled = reader.bool(); continue; case 4: if (tag !== 32) { break; } message.quality = reader.int32(); continue; case 5: if (tag !== 40) { break; } message.width = reader.uint32(); continue; case 6: if (tag !== 48) { break; } message.height = reader.uint32(); continue; case 7: if (tag !== 56) { break; } message.fps = reader.uint32(); continue; case 8: if (tag !== 64) { break; } message.priority = reader.uint32(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 8) { break; } message.canReconnect = reader.bool(); continue; case 2: if (tag !== 16) { break; } message.reason = reader.int32(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.trackSid = reader.string(); continue; case 2: if (tag !== 18) { break; } message.layers.push(VideoLayer.decode(reader, reader.uint32())); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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: "", name: "" }; } 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); } if (message.name !== "") { writer.uint32(18).string(message.name); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(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: if (tag !== 10) { break; } message.metadata = reader.string(); continue; case 2: if (tag !== 18) { break; } message.name = reader.string(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } return message; }, fromJSON(object) { return { metadata: isSet(object.metadata) ? String(object.metadata) : "", name: isSet(object.name) ? String(object.name) : "" }; }, toJSON(message) { const obj = {}; message.metadata !== undefined && (obj.metadata = message.metadata); message.name !== undefined && (obj.name = message.name); return obj; }, create(base) { return UpdateParticipantMetadata.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b; const message = createBaseUpdateParticipantMetadata(); message.metadata = (_a = object.metadata) !== null && _a !== void 0 ? _a : ""; message.name = (_b = object.name) !== null && _b !== void 0 ? _b : ""; 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.urls.push(reader.string()); continue; case 2: if (tag !== 18) { break; } message.username = reader.string(); continue; case 3: if (tag !== 26) { break; } message.credential = reader.string(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.speakers.push(SpeakerInfo.decode(reader, reader.uint32())); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.room = Room$1.decode(reader, reader.uint32()); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.participantSid = reader.string(); continue; case 2: if (tag !== 16) { break; } message.quality = reader.int32(); continue; case 3: if (tag !== 29) { break; } message.score = reader.float(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.updates.push(ConnectionQualityInfo.decode(reader, reader.uint32())); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.participantSid = reader.string(); continue; case 2: if (tag !== 18) { break; } message.trackSid = reader.string(); continue; case 3: if (tag !== 24) { break; } message.state = reader.int32(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.streamStates.push(StreamStateInfo.decode(reader, reader.uint32())); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 8) { break; } message.quality = reader.int32(); continue; case 2: if (tag !== 16) { break; } message.enabled = reader.bool(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.codec = reader.string(); continue; case 2: if (tag !== 18) { break; } message.qualities.push(SubscribedQuality.decode(reader, reader.uint32())); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.trackSid = reader.string(); continue; case 2: if (tag !== 18) { break; } message.subscribedQualities.push(SubscribedQuality.decode(reader, reader.uint32())); continue; case 3: if (tag !== 26) { break; } message.subscribedCodecs.push(SubscribedCodec.decode(reader, reader.uint32())); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.participantSid = reader.string(); continue; case 2: if (tag !== 16) { break; } message.allTracks = reader.bool(); continue; case 3: if (tag !== 26) { break; } message.trackSids.push(reader.string()); continue; case 4: if (tag !== 34) { break; } message.participantIdentity = reader.string(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 8) { break; } message.allParticipants = reader.bool(); continue; case 2: if (tag !== 18) { break; } message.trackPermissions.push(TrackPermission.decode(reader, reader.uint32())); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.participantSid = reader.string(); continue; case 2: if (tag !== 18) { break; } message.trackSid = reader.string(); continue; case 3: if (tag !== 24) { break; } message.allowed = reader.bool(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.answer = SessionDescription.decode(reader, reader.uint32()); continue; case 2: if (tag !== 18) { break; } message.subscription = UpdateSubscription.decode(reader, reader.uint32()); continue; case 3: if (tag !== 26) { break; } message.publishTracks.push(TrackPublishedResponse.decode(reader, reader.uint32())); continue; case 4: if (tag !== 34) { break; } message.dataChannels.push(DataChannelInfo.decode(reader, reader.uint32())); continue; case 5: if (tag !== 42) { break; } message.offer = SessionDescription.decode(reader, reader.uint32()); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 10) { break; } message.label = reader.string(); continue; case 2: if (tag !== 16) { break; } message.id = reader.uint32(); continue; case 3: if (tag !== 24) { break; } message.target = reader.int32(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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; case "subscriberBandwidth": writer.uint32(48).int64(message.scenario.subscriberBandwidth); break; } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(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: if (tag !== 8) { break; } message.scenario = { $case: "speakerUpdate", speakerUpdate: reader.int32() }; continue; case 2: if (tag !== 16) { break; } message.scenario = { $case: "nodeFailure", nodeFailure: reader.bool() }; continue; case 3: if (tag !== 24) { break; } message.scenario = { $case: "migration", migration: reader.bool() }; continue; case 4: if (tag !== 32) { break; } message.scenario = { $case: "serverLeave", serverLeave: reader.bool() }; continue; case 5: if (tag !== 40) { break; } message.scenario = { $case: "switchCandidateProtocol", switchCandidateProtocol: reader.int32() }; continue; case 6: if (tag !== 48) { break; } message.scenario = { $case: "subscriberBandwidth", subscriberBandwidth: longToNumber(reader.int64()) }; continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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) } : isSet(object.subscriberBandwidth) ? { $case: "subscriberBandwidth", subscriberBandwidth: Number(object.subscriberBandwidth) } : undefined }; }, toJSON(message) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o; 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); ((_m = message.scenario) === null || _m === void 0 ? void 0 : _m.$case) === "subscriberBandwidth" && (obj.subscriberBandwidth = Math.round((_o = message.scenario) === null || _o === void 0 ? void 0 : _o.subscriberBandwidth)); 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, _r, _s, _t; 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 }; } if (((_r = object.scenario) === null || _r === void 0 ? void 0 : _r.$case) === "subscriberBandwidth" && ((_s = object.scenario) === null || _s === void 0 ? void 0 : _s.subscriberBandwidth) !== undefined && ((_t = object.scenario) === null || _t === void 0 ? void 0 : _t.subscriberBandwidth) !== null) { message.scenario = { $case: "subscriberBandwidth", subscriberBandwidth: object.scenario.subscriberBandwidth }; } 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 : _m0.Reader.create(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: if (tag !== 8) { break; } message.timestamp = longToNumber(reader.int64()); continue; case 2: if (tag !== 16) { break; } message.rtt = longToNumber(reader.int64()); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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 : _m0.Reader.create(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: if (tag !== 8) { break; } message.lastPingTimestamp = longToNumber(reader.int64()); continue; case 2: if (tag !== 16) { break; } message.timestamp = longToNumber(reader.int64()); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } 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; } }; function createBaseSubscriptionResponse() { return { trackSid: "", err: 0 }; } const SubscriptionResponse = { encode(message) { let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _m0.Writer.create(); if (message.trackSid !== "") { writer.uint32(10).string(message.trackSid); } if (message.err !== 0) { writer.uint32(16).int32(message.err); } return writer; }, decode(input, length) { const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); let end = length === undefined ? reader.len : reader.pos + length; const message = createBaseSubscriptionResponse(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { case 1: if (tag !== 10) { break; } message.trackSid = reader.string(); continue; case 2: if (tag !== 16) { break; } message.err = reader.int32(); continue; } if ((tag & 7) === 4 || tag === 0) { break; } reader.skipType(tag & 7); } return message; }, fromJSON(object) { return { trackSid: isSet(object.trackSid) ? String(object.trackSid) : "", err: isSet(object.err) ? subscriptionErrorFromJSON(object.err) : 0 }; }, toJSON(message) { const obj = {}; message.trackSid !== undefined && (obj.trackSid = message.trackSid); message.err !== undefined && (obj.err = subscriptionErrorToJSON(message.err)); return obj; }, create(base) { return SubscriptionResponse.fromPartial(base !== null && base !== void 0 ? base : {}); }, fromPartial(object) { var _a, _b; const message = createBaseSubscriptionResponse(); message.trackSid = (_a = object.trackSid) !== null && _a !== void 0 ? _a : ""; message.err = (_b = object.err) !== 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 bytesFromBase64(b64) { if (tsProtoGlobalThis.Buffer) { return Uint8Array.from(tsProtoGlobalThis.Buffer.from(b64, "base64")); } else { const bin = tsProtoGlobalThis.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.Buffer) { return tsProtoGlobalThis.Buffer.from(arr).toString("base64"); } else { const bin = []; arr.forEach(byte => { bin.push(String.fromCharCode(byte)); }); return tsProtoGlobalThis.btoa(bin.join("")); } } 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$1) { _m0.util.Long = Long$1; _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 = {})); /** * 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); }; // tiny, simplified version of https://github.com/lancedikson/bowser/blob/master/src/parser-browsers.js // reduced to only differentiate Chrome(ium) based browsers / Firefox / Safari const commonVersionIdentifier = /version\/(\d+(\.?_?\d+)+)/i; let browserDetails; /** * @internal */ function getBrowser(userAgent) { let force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; if (typeof userAgent === 'undefined' && typeof navigator === 'undefined') { return; } const ua = (userAgent !== null && userAgent !== void 0 ? userAgent : navigator.userAgent).toLowerCase(); if (browserDetails === undefined || force) { const browser = browsersList.find(_ref => { let { test } = _ref; return test.test(ua); }); browserDetails = browser === null || browser === void 0 ? void 0 : browser.describe(ua); } return browserDetails; } const browsersList = [{ test: /firefox|iceweasel|fxios/i, describe(ua) { const browser = { name: 'Firefox', version: getMatch(/(?:firefox|iceweasel|fxios)[\s/](\d+(\.?_?\d+)+)/i, ua) }; return browser; } }, { test: /chrom|crios|crmo/i, describe(ua) { const browser = { name: 'Chrome', version: getMatch(/(?:chrome|chromium|crios|crmo)\/(\d+(\.?_?\d+)+)/i, ua) }; return browser; } }, /* Safari */ { test: /safari|applewebkit/i, describe(ua) { const browser = { name: 'Safari', version: getMatch(commonVersionIdentifier, ua) }; return browser; } }]; function getMatch(exp, ua) { let id = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1; const match = ua.match(exp); return match && match.length >= id && match[id] || ''; } var version$1 = "1.10.0"; const version = version$1; const protocolVersion = 9; function mergeDefaultOptions(options, audioDefaults, videoDefaults) { const opts = Object.assign({}, 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. */ function detectSilence(track) { let timeOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 200; return __awaiter(this, void 0, void 0, function* () { 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); yield 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 = '|'; const ddExtensionURI = 'https://aomediacodec.github.io/av1-rtp-spec/#dependency-descriptor-rtp-header-extension'; function unpackStreamId(packed) { const parts = packed.split(separator); if (parts.length > 1) { return [parts[0], packed.substr(parts[0].length + 1)]; } return [packed, '']; } function sleep(duration) { return __awaiter(this, void 0, void 0, function* () { 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() { if (!('getCapabilities' in RTCRtpSender)) { return false; } const capabilities = RTCRtpSender.getCapabilities('video'); let hasAV1 = false; if (capabilities) { for (const codec of capabilities.codecs) { if (codec.mimeType === 'video/AV1') { hasAV1 = true; break; } } } return hasAV1; } function supportsVP9() { if (!('getCapabilities' in RTCRtpSender)) { // technically speaking FireFox supports VP9, but SVC publishing is broken // https://bugzilla.mozilla.org/show_bug.cgi?id=1633876 return false; } const capabilities = RTCRtpSender.getCapabilities('video'); let hasVP9 = false; if (capabilities) { for (const codec of capabilities.codecs) { if (codec.mimeType === 'video/VP9') { hasVP9 = true; break; } } } return hasVP9; } function isSVCCodec(codec) { return codec === 'av1' || codec === 'vp9'; } function supportsSetSinkId(elm) { if (!document) { return false; } if (!elm) { elm = document.createElement('audio'); } return 'setSinkId' in elm; } const setCodecPreferencesVersions = { Chrome: '100', Safari: '15', Firefox: '100' }; function supportsSetCodecPreferences(transceiver) { if (!isWeb()) { return false; } if (!('setCodecPreferences' in transceiver)) { return false; } const browser = getBrowser(); if (!(browser === null || browser === void 0 ? void 0 : browser.name) || !browser.version) { // version is required return false; } const v = setCodecPreferencesVersions[browser.name]; if (v) { return compareVersions(browser.version, v) >= 0; } return false; } function isBrowserSupported() { return supportsTransceiver() || supportsAddTrack(); } function isFireFox() { var _a; return ((_a = getBrowser()) === null || _a === void 0 ? void 0 : _a.name) === 'Firefox'; } function isChromiumBased() { var _a; return ((_a = getBrowser()) === null || _a === void 0 ? void 0 : _a.name) === 'Chrome'; } function isSafari() { var _a; return ((_a = getBrowser()) === null || _a === void 0 ? void 0 : _a.name) === 'Safari'; } 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 isCloud(serverUrl) { return serverUrl.hostname.endsWith('.livekit.cloud'); } function getLKReactNativeInfo() { // global defined only for ReactNative. // @ts-ignore if (global && global.LiveKitReactNativeGlobal) { // @ts-ignore return global.LiveKitReactNativeGlobal; } return undefined; } function getReactNativeOs() { if (!isReactNative()) { return undefined; } let info = getLKReactNativeInfo(); if (info) { return info.platform; } return undefined; } function getDevicePixelRatio() { if (isWeb()) { return window.devicePixelRatio; } if (isReactNative()) { let info = getLKReactNativeInfo(); if (info) { return info.devicePixelRatio; } } return 1; } function compareVersions(v1, v2) { const parts1 = v1.split('.'); const parts2 = v2.split('.'); const k = Math.min(parts1.length, parts2.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; if (i === k - 1 && p1 === p2) return 0; } if (v1 === '' && v2 !== '') { return -1; } else if (v2 === '') { 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: null, 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((resolve, reject) => __awaiter(this, void 0, void 0, function* () { this.resolve = resolve; this.reject = reject; if (futureBase) { yield 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 = Object.assign({ 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; } } var QueueTaskStatus; (function (QueueTaskStatus) { QueueTaskStatus[QueueTaskStatus["WAITING"] = 0] = "WAITING"; QueueTaskStatus[QueueTaskStatus["RUNNING"] = 1] = "RUNNING"; QueueTaskStatus[QueueTaskStatus["COMPLETED"] = 2] = "COMPLETED"; })(QueueTaskStatus || (QueueTaskStatus = {})); class AsyncQueue { constructor() { this.pendingTasks = new Map(); this.taskMutex = new Mutex(); this.nextTaskIndex = 0; } run(task) { return __awaiter(this, void 0, void 0, function* () { const taskInfo = { id: this.nextTaskIndex++, enqueuedAt: Date.now(), status: QueueTaskStatus.WAITING }; this.pendingTasks.set(taskInfo.id, taskInfo); const unlock = yield this.taskMutex.lock(); try { taskInfo.executedAt = Date.now(); taskInfo.status = QueueTaskStatus.RUNNING; return yield task(); } finally { taskInfo.status = QueueTaskStatus.COMPLETED; this.pendingTasks.delete(taskInfo.id); unlock(); } }); } flush() { return __awaiter(this, void 0, void 0, function* () { return this.run(() => __awaiter(this, void 0, void 0, function* () {})); }); } snapshot() { return Array.from(this.pendingTasks.values()); } } const passThroughQueueSignals = ['syncState', 'trickle', 'offer', 'answer', 'simulate', 'leave']; function canPassThroughQueue(req) { const canPass = passThroughQueueSignals.indexOf(req.$case) >= 0; 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 AsyncQueue(); this.queuedRequests = []; this.closingLock = new Mutex(); } join(url, token, opts, abortSignal) { return __awaiter(this, void 0, void 0, function* () { // during a full reconnect, we'd want to start the sequence even if currently // connected this.isConnected = false; this.options = opts; const res = yield this.connect(url, token, opts, abortSignal); return res; }); } reconnect(url, token, sid, reason) { return __awaiter(this, void 0, void 0, function* () { 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 = yield this.connect(url, token, Object.assign(Object.assign({}, 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((resolve, reject) => __awaiter(this, void 0, void 0, function* () { const abortHandler = () => __awaiter(this, void 0, void 0, function* () { this.close(); reject(new ConnectionError('room connection has been cancelled (signal)')); }); 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) { yield this.close(); } this.ws = new WebSocket(url + params); this.ws.binaryType = 'arraybuffer'; this.ws.onerror = ev => __awaiter(this, void 0, void 0, function* () { if (!this.isConnected) { try { const resp = yield fetch("http".concat(url.substring(2), "/validate").concat(params)); if (resp.status.toFixed(0).startsWith('4')) { const msg = yield 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 = ev => __awaiter(this, void 0, void 0, function* () { 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) { yield sleep(this.signalLatency); } this.handleSignalResponse(resp); }); this.ws.onclose = ev => { livekitLogger.warn("websocket closed", { ev }); this.handleOnClose(ev.reason); }; })); } close() { return __awaiter(this, void 0, void 0, function* () { const unlock = yield 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); } }); if (this.ws.readyState < this.ws.CLOSING) { this.ws.close(); // 250ms grace period for ws to close gracefully yield 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'); return this.sendRequest({ $case: 'answer', answer: toProtoSessionDescription(answer) }); } sendIceCandidate(candidate, target) { livekitLogger.trace('sending ice candidate', candidate); return this.sendRequest({ $case: 'trickle', trickle: { candidateInit: JSON.stringify(candidate), target } }); } sendMuteTrack(trackSid, muted) { return this.sendRequest({ $case: 'mute', mute: { sid: trackSid, muted } }); } sendAddTrack(req) { return this.sendRequest({ $case: 'addTrack', addTrack: AddTrackRequest.fromPartial(req) }); } sendUpdateLocalMetadata(metadata, name) { return this.sendRequest({ $case: 'updateMetadata', updateMetadata: { metadata, name } }); } sendUpdateTrackSettings(settings) { this.sendRequest({ $case: 'trackSetting', trackSetting: settings }); } sendUpdateSubscription(sub) { return this.sendRequest({ $case: 'subscription', subscription: sub }); } sendSyncState(sync) { return this.sendRequest({ $case: 'syncState', syncState: sync }); } sendUpdateVideoLayers(trackSid, layers) { return this.sendRequest({ $case: 'updateLayers', updateLayers: { trackSid, layers } }); } sendUpdateSubscriptionPermissions(allParticipants, trackPermissions) { return this.sendRequest({ $case: 'subscriptionPermission', subscriptionPermission: { allParticipants, trackPermissions } }); } sendSimulateScenario(scenario) { return this.sendRequest({ $case: 'simulate', simulate: scenario }); } sendPing() { /** send both of ping and pingReq for compatibility to old and new server */ return Promise.all([this.sendRequest({ $case: 'ping', ping: Date.now() }), this.sendRequest({ $case: 'pingReq', pingReq: { timestamp: Date.now(), rtt: this.rtt } })]); } sendLeave() { return this.sendRequest({ $case: 'leave', leave: { canReconnect: false, reason: DisconnectReason.CLIENT_INITIATED } }); } sendRequest(message) { let fromQueue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; return __awaiter(this, void 0, void 0, function* () { // 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(() => __awaiter(this, void 0, void 0, function* () { yield this.sendRequest(message, true); })); return; } // make sure previously queued requests are being sent first if (!fromQueue) { yield this.requestQueue.flush(); } if (this.signalLatency) { yield 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 === 'subscriptionResponse') { if (this.onSubscriptionError) { this.onSubscriptionError(msg.subscriptionResponse); } } 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; } handleOnClose(reason) { return __awaiter(this, void 0, void 0, function* () { if (!this.isConnected) return; yield this.close(); livekitLogger.debug("websocket connection closed: ".concat(reason)); if (this.onClose) { this.onClose(reason); } }); } 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())); this.handleOnClose('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 defaultId = 'default'; class DeviceManager { static getInstance() { if (this.instance === undefined) { this.instance = new DeviceManager(); } return this.instance; } getDevices(kind) { let requestPermissions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; var _a; return __awaiter(this, void 0, void 0, function* () { if (((_a = DeviceManager.userMediaPromiseMap) === null || _a === void 0 ? void 0 : _a.size) > 0) { livekitLogger.debug('awaiting getUserMedia promise'); try { if (kind) { yield DeviceManager.userMediaPromiseMap.get(kind); } else { yield Promise.all(DeviceManager.userMediaPromiseMap.values()); } } catch (e) { livekitLogger.warn('error waiting for media permissons'); } } let devices = yield 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 = yield navigator.mediaDevices.getUserMedia(permissionsToAcquire); devices = yield navigator.mediaDevices.enumerateDevices(); stream.getTracks().forEach(track => { track.stop(); }); } } if (kind) { devices = devices.filter(device => device.kind === kind); } return devices; }); } normalizeDeviceId(kind, deviceId, groupId) { return __awaiter(this, void 0, void 0, function* () { if (deviceId !== defaultId) { return deviceId; } // resolve actual device id if it's 'default': Chrome returns it when no // device has been chosen const devices = yield 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 parser$1 = {}; var grammar$2 = {exports: {}}; 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'; } }); }); var grammarExports = grammar$2.exports; (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; 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; } const PCEvents = { NegotiationStarted: 'negotiationStarted', NegotiationComplete: 'negotiationComplete' }; /** @internal */ class PCTransport extends eventsExports.EventEmitter { constructor(config) { let mediaConstraints = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 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 = isChromiumBased() ? // @ts-expect-error chrome allows additional media constraints to be passed into the RTCPeerConnection constructor new RTCPeerConnection(config, mediaConstraints) : new RTCPeerConnection(config); } get isICEConnected() { return this.pc.iceConnectionState === 'connected' || this.pc.iceConnectionState === 'completed'; } addIceCandidate(candidate) { return __awaiter(this, void 0, void 0, function* () { if (this.pc.remoteDescription && !this.restartingIce) { return this.pc.addIceCandidate(candidate); } this.pendingCandidates.push(candidate); }); } setRemoteDescription(sd) { return __awaiter(this, void 0, void 0, function* () { if (sd.type === 'offer') { let { stereoMids, nackMids } = extractStereoAndNackAudioFromOffer(sd); this.remoteStereoMids = stereoMids; this.remoteNackMids = nackMids; } yield 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); } }); } createAndSendOffer(options) { var _a; return __awaiter(this, void 0, void 0, function* () { 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 yield 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 = yield 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') { ensureVideoDDExtensionForSVC(media); // 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-start-bitrate')) { fmtp.config += ";x-google-start-bitrate=".concat(trackbr.maxbr * 0.7); } 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-start-bitrate=".concat(trackbr.maxbr * 0.7, ";x-google-max-bitrate=").concat(trackbr.maxbr) }); } } return true; }); } }); this.trackBitrates = []; yield this.setMungedLocalDescription(offer, write(sdpParsed)); this.onOffer(offer); }); } createAndSetAnswer() { var _a; return __awaiter(this, void 0, void 0, function* () { const answer = yield 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); } }); yield 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(); } setMungedLocalDescription(sd, munged) { return __awaiter(this, void 0, void 0, function* () { const originalSdp = sd.sdp; sd.sdp = munged; try { livekitLogger.debug('setting munged local description'); yield 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 { yield 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 ensureVideoDDExtensionForSVC(media) { var _a, _b, _c, _d; const codec = (_b = (_a = media.rtp[0]) === null || _a === void 0 ? void 0 : _a.codec) === null || _b === void 0 ? void 0 : _b.toLowerCase(); if (!isSVCCodec(codec)) { return; } let maxID = 0; const ddFound = (_c = media.ext) === null || _c === void 0 ? void 0 : _c.some(ext => { if (ext.uri === ddExtensionURI) { return true; } if (ext.value > maxID) { maxID = ext.value; } return false; }); if (!ddFound) { (_d = media.ext) === null || _d === void 0 ? void 0 : _d.push({ value: maxID + 1, uri: ddExtensionURI }); } } 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 }; } class RegionUrlProvider { constructor(url, token) { this.lastUpdateAt = 0; this.settingsCacheTime = 3000; this.attemptedRegions = []; this.serverUrl = new URL(url); this.token = token; } isCloud() { return isCloud(this.serverUrl); } getNextBestRegionUrl(abortSignal) { return __awaiter(this, void 0, void 0, function* () { if (!this.isCloud()) { throw Error('region availability is only supported for LiveKit Cloud domains'); } if (!this.regionSettings || Date.now() - this.lastUpdateAt > this.settingsCacheTime) { this.regionSettings = yield this.fetchRegionSettings(abortSignal); } const regionsLeft = this.regionSettings.regions.filter(region => !this.attemptedRegions.find(attempted => attempted.url === region.url)); if (regionsLeft.length > 0) { const nextRegion = regionsLeft[0]; this.attemptedRegions.push(nextRegion); livekitLogger.debug("next region: ".concat(nextRegion.region)); return nextRegion.url; } else { return null; } }); } resetAttempts() { this.attemptedRegions = []; } fetchRegionSettings(signal) { return __awaiter(this, void 0, void 0, function* () { const regionSettingsResponse = yield fetch("".concat(getCloudConfigUrl(this.serverUrl), "/regions"), { headers: { authorization: "Bearer ".concat(this.token) }, signal }); if (regionSettingsResponse.ok) { const regionSettings = yield regionSettingsResponse.json(); this.lastUpdateAt = Date.now(); return regionSettings; } else { throw new ConnectionError("Could not fetch region settings: ".concat(regionSettingsResponse.statusText), regionSettingsResponse.status === 401 ? 0 /* ConnectionErrorReason.NotAllowed */ : undefined, regionSettingsResponse.status); } }); } } function getCloudConfigUrl(serverUrl) { return "".concat(serverUrl.protocol.replace('ws', 'http'), "//").concat(serverUrl.host, "/settings"); } class VideoPreset { constructor(width, height, maxBitrate, maxFramerate, priority) { this.width = width; this.height = height; this.encoding = { maxBitrate, maxFramerate, priority }; } 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); } function isCodecEqual(c1, c2) { return (c1 === null || c1 === void 0 ? void 0 : c1.toLowerCase().replace(/audio\/|video\//y, '')) === (c2 === null || c2 === void 0 ? void 0 : c2.toLowerCase().replace(/audio\/|video\//y, '')); } 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, 'medium'), h720fps5: new VideoPreset(1280, 720, 400000, 5, 'medium'), h720fps15: new VideoPreset(1280, 720, 1000000, 15, 'medium'), h1080fps15: new VideoPreset(1920, 1080, 1500000, 15, 'medium'), h1080fps30: new VideoPreset(1920, 1080, 3000000, 30, 'medium') }; const publishDefaults = { /** * @deprecated */ audioBitrate: AudioPresets.music.maxBitrate, audioPreset: AudioPresets.music, 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 }; /** * 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"; /** * Participant's display name changed * * args: (name: string, [[Participant]]) * */ RoomEvent["ParticipantNameChanged"] = "participantNameChanged"; /** * 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"; /** * Emits whenever the current buffer status of a data channel changes * args: (isLow: boolean, kind: [[DataPacket_Kind]]) */ RoomEvent["DCBufferStatusChanged"] = "dcBufferStatusChanged"; })(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"; /** * Participant's display name changed * * args: (name: string, [[Participant]]) * */ ParticipantEvent["ParticipantNameChanged"] = "participantNameChanged"; /** * 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["SignalRestarted"] = "signalRestarted"; EngineEvent["Closing"] = "closing"; EngineEvent["MediaTrackAdded"] = "mediaTrackAdded"; EngineEvent["ActiveSpeakersUpdate"] = "activeSpeakersUpdate"; EngineEvent["DataPacketReceived"] = "dataPacketReceived"; EngineEvent["DCBufferStatusChanged"] = "dcBufferStatusChanged"; })(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"; /** * Fires on RemoteTrackPublication */ TrackEvent["SubscriptionFailed"] = "subscriptionFailed"; })(TrackEvent || (TrackEvent = {})); 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.isInBackground = false; 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; } /** 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 (this.attachedElements.length === 0 && Track.Kind.Video) { this.addAppVisibilityListener(); } 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) { try { // 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; } finally { if (this.attachedElements.length === 0) { this.removeAppVisibilityListener(); } } } stop() { this.stopMonitor(); this._mediaStreamTrack.stop(); } 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); } } } handleAppVisibilityChanged() { return __awaiter(this, void 0, void 0, function* () { this.isInBackground = document.visibilityState === 'hidden'; }); } addAppVisibilityListener() { if (isWeb()) { this.isInBackground = document.visibilityState === 'hidden'; document.addEventListener('visibilitychange', this.appVisibilityChangedListener); } else { this.isInBackground = false; } } removeAppVisibilityListener() { if (isWeb()) { document.removeEventListener('visibilitychange', this.appVisibilityChangedListener); } } } /** @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 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.fullReconnectOnNext = false; 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.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 = _ref => { let { channel } = _ref; return __awaiter(this, void 0, void 0, function* () { 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 = message => __awaiter(this, void 0, void 0, function* () { var _a, _b; // make sure to respect incoming data message order by processing message events one after the other const unlock = yield this.dataProcessLock.lock(); try { // decode let buffer; if (message.data instanceof ArrayBuffer) { buffer = message.data; } else if (message.data instanceof Blob) { buffer = yield 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); } }; this.handleBufferedAmountLow = event => { const channel = event.currentTarget; const channelKind = channel.maxRetransmits === 0 ? DataPacket_Kind.LOSSY : DataPacket_Kind.RELIABLE; this.updateAndEmitDCBufferStatus(channelKind); }; // 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(); if (this.url && this.token && isCloud(new URL(this.url))) { this.regionUrlProvider = new RegionUrlProvider(this.url, this.token); } this.reconnectTimeout = CriticalTimers.setTimeout(() => this.attemptReconnect(disconnectReason), delay); }; this.waitForRestarted = () => { return new Promise((resolve, reject) => { if (this.pcState === PCState.Connected) { resolve(); } const onRestarted = () => { this.off(EngineEvent.Disconnected, onDisconnected); resolve(); }; const onDisconnected = () => { this.off(EngineEvent.Restarted, onRestarted); reject(); }; this.once(EngineEvent.Restarted, onRestarted); this.once(EngineEvent.Disconnected, onDisconnected); }); }; this.updateAndEmitDCBufferStatus = kind => { const status = this.isBufferStatusLow(kind); if (typeof status !== 'undefined' && status !== this.dcBufferStatus.get(kind)) { this.dcBufferStatus.set(kind, status); this.emit(EngineEvent.DCBufferStatusChanged, status, kind); } }; this.isBufferStatusLow = kind => { const dc = this.dataChannelForKind(kind); if (dc) { return dc.bufferedAmount <= dc.bufferedAmountLowThreshold; } }; 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(); this.dcBufferStatus = new Map([[DataPacket_Kind.LOSSY, true], [DataPacket_Kind.RELIABLE, true]]); } join(url, token, opts, abortSignal) { return __awaiter(this, void 0, void 0, function* () { this.url = url; this.token = token; this.signalOpts = opts; try { this.joinAttempts += 1; const joinResponse = yield this.client.join(url, token, opts, abortSignal); this._isClosed = false; this.latestJoinResponse = joinResponse; 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; } }); } close() { return __awaiter(this, void 0, void 0, function* () { const unlock = yield 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; } yield 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; } getConnectedServerAddress() { return __awaiter(this, void 0, void 0, function* () { 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); const googConstraints = { optional: [{ googDscp: true }] }; this.publisher = new PCTransport(rtcConfig, googConstraints); 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 = () => __awaiter(this, void 0, void 0, function* () { 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 = () => __awaiter(this, void 0, void 0, function* () { 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 = sd => __awaiter(this, void 0, void 0, function* () { if (!this.publisher) { return; } livekitLogger.debug('received server answer', { RTCSdpType: sd.type, signalingState: this.publisher.pc.signalingState }); yield 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 = sd => __awaiter(this, void 0, void 0, function* () { if (!this.subscriber) { return; } livekitLogger.debug('received server offer', { RTCSdpType: sd.type, signalingState: this.subscriber.pc.signalingState }); yield this.subscriber.setRemoteDescription(sd); // answer the offer const answer = yield 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 = Object.assign({}, 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; // set up dc buffer threshold, set to 64kB (otherwise 0 by default) this.lossyDC.bufferedAmountLowThreshold = 65535; this.reliableDC.bufferedAmountLowThreshold = 65535; // handle buffer amount low events this.lossyDC.onbufferedamountlow = this.handleBufferedAmountLow; this.reliableDC.onbufferedamountlow = this.handleBufferedAmountLow; } 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)); } } createSender(track, opts, encodings) { return __awaiter(this, void 0, void 0, function* () { 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'); }); } createSimulcastSender(track, simulcastTrack, opts, encodings) { return __awaiter(this, void 0, void 0, function* () { // 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'); }); } createTransceiverRTCRtpSender(track, opts, encodings) { return __awaiter(this, void 0, void 0, function* () { 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 = yield 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; }); } createSimulcastTransceiverSender(track, simulcastTrack, opts, encodings) { return __awaiter(this, void 0, void 0, function* () { 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 = yield 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; }); } createRTCRtpSender(track) { return __awaiter(this, void 0, void 0, function* () { if (!this.publisher) { throw new UnexpectedConnectionState('publisher is closed'); } return this.publisher.pc.addTrack(track); }); } attemptReconnect(reason) { var _a, _b, _c; return __awaiter(this, void 0, void 0, function* () { 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) { yield this.restartConnection(); } else { yield 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); yield 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; } restartConnection(regionUrl) { var _a, _b, _c, _d, _e; return __awaiter(this, void 0, void 0, function* () { try { 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) { yield this.client.sendLeave(); } yield 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(); } // in case a regionUrl is passed, the region URL takes precedence joinResponse = yield this.join(regionUrl !== null && regionUrl !== void 0 ? regionUrl : this.url, this.token, this.signalOpts); } catch (e) { if (e instanceof ConnectionError && e.reason === 0 /* ConnectionErrorReason.NotAllowed */) { throw new UnexpectedConnectionState('could not reconnect, token might be expired'); } throw new SignalReconnectError(); } if (this.shouldFailNext) { this.shouldFailNext = false; throw new Error('simulated failure'); } this.client.setReconnected(); this.emit(EngineEvent.SignalRestarted, joinResponse); yield this.waitForPCReconnected(); (_c = this.regionUrlProvider) === null || _c === void 0 ? void 0 : _c.resetAttempts(); // reconnect success this.emit(EngineEvent.Restarted); } catch (error) { const nextRegionUrl = yield (_d = this.regionUrlProvider) === null || _d === void 0 ? void 0 : _d.getNextBestRegionUrl(); if (nextRegionUrl) { yield this.restartConnection(nextRegionUrl); return; } else { // no more regions to try (or we're not on cloud) (_e = this.regionUrlProvider) === null || _e === void 0 ? void 0 : _e.resetAttempts(); throw error; } } }); } resumeConnection(reason) { var _a; return __awaiter(this, void 0, void 0, function* () { 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 = yield 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; } if (e instanceof ConnectionError && e.reason === 0 /* ConnectionErrorReason.NotAllowed */) { throw new UnexpectedConnectionState('could not reconnect, token might be expired'); } 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) { yield this.publisher.createAndSendOffer({ iceRestart: true }); } yield this.waitForPCReconnected(); 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); }); } waitForPCInitialConnection(timeout, abortController) { return __awaiter(this, void 0, void 0, function* () { if (this.pcState === PCState.Connected) { return; } if (this.pcState !== PCState.New) { throw new UnexpectedConnectionState('Expected peer connection to be new on initial connection'); } return new Promise((resolve, reject) => { const abortHandler = () => { livekitLogger.warn('closing engine'); CriticalTimers.clearTimeout(connectTimeout); reject(new ConnectionError('room connection has been cancelled', 3 /* ConnectionErrorReason.Cancelled */)); }; if (abortController === null || abortController === void 0 ? void 0 : abortController.signal.aborted) { abortHandler(); } abortController === null || abortController === void 0 ? void 0 : abortController.signal.addEventListener('abort', abortHandler); const onConnected = () => { CriticalTimers.clearTimeout(connectTimeout); abortController === null || abortController === void 0 ? void 0 : abortController.signal.removeEventListener('abort', abortHandler); resolve(); }; const connectTimeout = CriticalTimers.setTimeout(() => { this.off(EngineEvent.Connected, onConnected); reject(new ConnectionError('could not establish pc connection')); }, timeout !== null && timeout !== void 0 ? timeout : this.peerConnectionTimeout); this.once(EngineEvent.Connected, onConnected); }); }); } waitForPCReconnected() { var _a; return __awaiter(this, void 0, void 0, function* () { 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; } yield sleep(100); now = Date.now(); } // have not reconnected, throw throw new ConnectionError('could not establish PC connection'); }); } /* @internal */ sendDataPacket(packet, kind) { return __awaiter(this, void 0, void 0, function* () { const msg = DataPacket.encode(packet).finish(); // make sure we do have a data connection yield this.ensurePublisherConnected(kind); const dc = this.dataChannelForKind(kind); if (dc) { dc.send(msg); } this.updateAndEmitDCBufferStatus(kind); }); } /** * @internal */ ensureDataTransportConnected(kind) { let subscriber = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.subscriberPrimary; var _a, _b, _c; return __awaiter(this, void 0, void 0, function* () { 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; } yield sleep(50); } throw new ConnectionError("could not establish ".concat(transportName, " connection, state: ").concat(transport.pc.iceConnectionState)); }); } ensurePublisherConnected(kind) { return __awaiter(this, void 0, void 0, function* () { yield this.ensureDataTransportConnected(kind, false); }); } /* @internal */ verifyTransport() { // primary connection if (!this.primaryPC) { return false; } if (this.primaryPC.connectionState === 'closed' || this.primaryPC.connectionState === 'failed') { return false; } // also verify publisher connection if it's needed or different if (this.hasPublished && this.subscriberPrimary) { if (!this.publisher) { return false; } if (this.publisher.pc.connectionState === 'closed' || this.publisher.pc.connectionState === 'failed') { return false; } } // ensure signal is connected if (!this.client.ws || this.client.ws.readyState === WebSocket.CLOSED) { return false; } return true; } /** @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); } } } function getConnectedAddress(pc) { var _a; return __awaiter(this, void 0, void 0, function* () { let selectedCandidatePairId = ''; const candidatePairs = new Map(); // id -> candidate ip const candidates = new Map(); const stats = yield 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 {} 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); } const defaultDimensionsTimeout = 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.isSettingUpProcessor = false; 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.muteLock = new Mutex(); this.pauseUpstreamLock = new Mutex(); } 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; } get mediaStreamTrack() { var _a, _b; return (_b = (_a = this.processor) === null || _a === void 0 ? void 0 : _a.processedTrack) !== null && _b !== void 0 ? _b : this._mediaStreamTrack; } waitForDimensions() { let timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultDimensionsTimeout; return __awaiter(this, void 0, void 0, function* () { 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; } yield 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 */ getDeviceId() { return __awaiter(this, void 0, void 0, function* () { // 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); }); } mute() { return __awaiter(this, void 0, void 0, function* () { this.setTrackMuted(true); return this; }); } unmute() { return __awaiter(this, void 0, void 0, function* () { this.setTrackMuted(false); return this; }); } replaceTrack(track) { let userProvidedTrack = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; return __awaiter(this, void 0, void 0, function* () { 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) { yield this.sender.replaceTrack(track); } this._mediaStreamTrack = track; // sync muted state with the enabled state of the newly provided track this._mediaStreamTrack.enabled = !this.isMuted; yield this.resumeUpstream(); this.attachedElements.forEach(el => { attachToElement(track, el); }); this.mediaStream = new MediaStream([track]); this.providedByUser = userProvidedTrack; if (this.processor) { yield this.stopProcessor(); } return this; }); } restart(constraints) { return __awaiter(this, void 0, void 0, function* () { 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 = yield 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 yield this.sender.replaceTrack(newTrack); } this._mediaStreamTrack = newTrack; yield this.resumeUpstream(); this.mediaStream = mediaStream; this.constraints = constraints; if (this.processor) { const processor = this.processor; yield this.setProcessor(processor); } else { this.attachedElements.forEach(el => { attachToElement(this._mediaStreamTrack, el); }); } 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; } handleAppVisibilityChanged() { const _super = Object.create(null, { handleAppVisibilityChanged: { get: () => super.handleAppVisibilityChanged } }); return __awaiter(this, void 0, void 0, function* () { yield _super.handleAppVisibilityChanged.call(this); 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)); yield this.restart(); this.reacquireTrack = false; } }); } stop() { var _a; super.stop(); (_a = this.processor) === null || _a === void 0 ? void 0 : _a.destroy(); this.processor = undefined; } /** * pauses publishing to the server without disabling the local MediaStreamTrack * this is used to display a user's own video locally while pausing publishing to * the server. * this API is unsupported on Safari < 12 due to a bug **/ pauseUpstream() { return __awaiter(this, void 0, void 0, function* () { const unlock = yield this.pauseUpstreamLock.lock(); try { 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 browser = getBrowser(); if ((browser === null || browser === void 0 ? void 0 : browser.name) === 'Safari' && compareVersions(browser.version, '12.0') < 0) { // https://bugs.webkit.org/show_bug.cgi?id=184911 throw new DeviceUnsupportedError('pauseUpstream is not supported on Safari < 12.'); } yield this.sender.replaceTrack(null); } finally { unlock(); } }); } resumeUpstream() { return __awaiter(this, void 0, void 0, function* () { const unlock = yield this.pauseUpstreamLock.lock(); try { 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); yield this.sender.replaceTrack(this._mediaStreamTrack); } finally { unlock(); } }); } /** * Sets a processor on this track. * See https://github.com/livekit/track-processors-js for example usage * * @experimental * * @param processor * @param showProcessedStreamLocally * @returns */ setProcessor(processor) { let showProcessedStreamLocally = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; var _a, _b; return __awaiter(this, void 0, void 0, function* () { if (this.isSettingUpProcessor) { livekitLogger.warn('already trying to set up a processor'); return; } livekitLogger.debug('setting up processor'); this.isSettingUpProcessor = true; if (this.processor) { yield this.stopProcessor(); } if (this.kind === 'unknown') { throw TypeError('cannot set processor on track of unknown kind'); } this.processorElement = (_a = this.processorElement) !== null && _a !== void 0 ? _a : document.createElement(this.kind); this.processorElement.muted = true; attachToElement(this._mediaStreamTrack, this.processorElement); this.processorElement.play().catch(e => livekitLogger.error(e)); const processorOptions = { kind: this.kind, track: this._mediaStreamTrack, element: this.processorElement }; yield processor.init(processorOptions); this.processor = processor; if (this.processor.processedTrack) { for (const el of this.attachedElements) { if (el !== this.processorElement && showProcessedStreamLocally) { detachTrack(this._mediaStreamTrack, el); attachToElement(this.processor.processedTrack, el); } } yield (_b = this.sender) === null || _b === void 0 ? void 0 : _b.replaceTrack(this.processor.processedTrack); } this.isSettingUpProcessor = false; }); } getProcessor() { return this.processor; } /** * Stops the track processor * See https://github.com/livekit/track-processors-js for example usage * * @experimental * @returns */ stopProcessor() { var _a, _b; return __awaiter(this, void 0, void 0, function* () { if (!this.processor) return; livekitLogger.debug('stopping processor'); (_a = this.processor.processedTrack) === null || _a === void 0 ? void 0 : _a.stop(); yield this.processor.destroy(); this.processor = undefined; (_b = this.processorElement) === null || _b === void 0 ? void 0 : _b.remove(); this.processorElement = undefined; yield this.restart(); }); } } 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 = () => __awaiter(this, void 0, void 0, function* () { if (!this.sender) { this._currentBitrate = 0; return; } let stats; try { stats = yield 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(); } setDeviceId(deviceId) { return __awaiter(this, void 0, void 0, function* () { if (this.constraints.deviceId === deviceId) { return; } this.constraints.deviceId = deviceId; if (!this.isMuted) { yield this.restartTrack(); } }); } mute() { const _super = Object.create(null, { mute: { get: () => super.mute } }); return __awaiter(this, void 0, void 0, function* () { const unlock = yield this.muteLock.lock(); try { // 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(); } yield _super.mute.call(this); return this; } finally { unlock(); } }); } unmute() { const _super = Object.create(null, { unmute: { get: () => super.unmute } }); return __awaiter(this, void 0, void 0, function* () { const unlock = yield this.muteLock.lock(); try { if (this.source === Track.Source.Microphone && (this.stopOnMute || this._mediaStreamTrack.readyState === 'ended') && !this.isUserProvided) { livekitLogger.debug('reacquiring mic track'); yield this.restartTrack(); } yield _super.unmute.call(this); return this; } finally { unlock(); } }); } restartTrack(options) { return __awaiter(this, void 0, void 0, function* () { let constraints; if (options) { const streamConstraints = constraintsForOptions({ audio: options }); if (typeof streamConstraints.audio !== 'boolean') { constraints = streamConstraints.audio; } } yield this.restart(constraints); }); } restart(constraints) { const _super = Object.create(null, { restart: { get: () => super.restart } }); return __awaiter(this, void 0, void 0, function* () { const track = yield _super.restart.call(this, constraints); this.checkForSilence(); return track; }); } /* @internal */ startMonitor() { if (!isWeb()) { return; } if (this.monitorInterval) { return; } this.monitorInterval = setInterval(() => { this.monitorSender(); }, monitorFrequency); } getSenderStats() { var _a; return __awaiter(this, void 0, void 0, function* () { if (!((_a = this.sender) === null || _a === void 0 ? void 0 : _a.getStats)) { return undefined; } const stats = yield 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; }); } checkForSilence() { return __awaiter(this, void 0, void 0, function* () { const trackIsSilent = yield detectSilence(this); if (trackIsSilent) { if (!this.isMuted) { livekitLogger.warn('silence detected on local audio track'); } this.emit(TrackEvent.AudioSilenceDetected); } return trackIsSilent; }); } } /** @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 / (Math.pow(t.scaleResolutionDownBy, 2) * (((_a = fromPreset.encoding.maxFramerate) !== null && _a !== void 0 ? _a : 30) / t.fps)))), t.fps, fromPreset.encoding.priority); }); }; // /** // * // * @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 && isSVCCodec(videoCodec)) { 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': case 'L3T3_KEY': encodings.push({ rid: videoRids[2], maxBitrate: videoEncoding.maxBitrate, /* @ts-ignore */ maxFramerate: original.encoding.maxFramerate, /* @ts-ignore */ scalabilityMode: scalabilityMode }); 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 = Object.assign({}, encoding); encoding.maxBitrate = encoding.maxBitrate * 0.7; break; case 'vp9': encoding = Object.assign({}, encoding); encoding.maxBitrate = encoding.maxBitrate * 0.85; 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]; const encoding = { rid, scaleResolutionDownBy: Math.max(1, size / Math.min(preset.width, preset.height)), maxBitrate: preset.encoding.maxBitrate }; if (preset.encoding.maxFramerate) { encoding.maxFramerate = preset.encoding.maxFramerate; } if (preset.encoding.priority) { encoding.priority = preset.encoding.priority; encoding.networkPriority = preset.encoding.priority; } encodings.push(encoding); }); // RN ios simulcast requires all same framerates. if (isReactNative() && getReactNativeOs() === 'ios') { let topFramerate = undefined; encodings.forEach(encoding => { if (!topFramerate) { topFramerate = encoding.maxFramerate; } else if (encoding.maxFramerate && encoding.maxFramerate > topFramerate) { topFramerate = encoding.maxFramerate; } }); let notifyOnce = true; encodings.forEach(encoding => { var _a; if (encoding.maxFramerate != topFramerate) { if (notifyOnce) { notifyOnce = false; livekitLogger.info("Simulcast on iOS React-Native requires all encodings to share the same framerate."); } livekitLogger.info("Setting framerate of encoding \"".concat((_a = encoding.rid) !== null && _a !== void 0 ? _a : '', "\" to ").concat(topFramerate)); encoding.maxFramerate = topFramerate; } }); } 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; }); } /** @internal */ class ScalabilityMode { constructor(scalabilityMode) { const results = scalabilityMode.match(/^L(\d)T(\d)(h|_KEY|_KEY_SHIFT){0,1}$/); if (!results) { throw new Error('invalid scalability mode'); } this.spatial = parseInt(results[1]); this.temporal = parseInt(results[2]); if (results.length > 3) { switch (results[3]) { case 'h': case '_KEY': case '_KEY_SHIFT': this.suffix = results[3]; } } } toString() { var _a; return "L".concat(this.spatial, "T").concat(this.temporal).concat((_a = this.suffix) !== null && _a !== void 0 ? _a : ''); } } 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 = () => __awaiter(this, void 0, void 0, function* () { if (!this.sender) { this._currentBitrate = 0; return; } let stats; try { stats = yield 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(); } mute() { const _super = Object.create(null, { mute: { get: () => super.mute } }); return __awaiter(this, void 0, void 0, function* () { const unlock = yield this.muteLock.lock(); try { 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(); } yield _super.mute.call(this); return this; } finally { unlock(); } }); } unmute() { const _super = Object.create(null, { unmute: { get: () => super.unmute } }); return __awaiter(this, void 0, void 0, function* () { const unlock = yield this.muteLock.lock(); try { if (this.source === Track.Source.Camera && !this.isUserProvided) { livekitLogger.debug('reacquiring camera track'); yield this.restartTrack(); } yield _super.unmute.call(this); return this; } finally { unlock(); } }); } getSenderStats() { var _a; return __awaiter(this, void 0, void 0, function* () { if (!((_a = this.sender) === null || _a === void 0 ? void 0 : _a.getStats)) { return []; } const items = []; const stats = yield 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); } setDeviceId(deviceId) { return __awaiter(this, void 0, void 0, function* () { 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) { yield this.restartTrack(); } }); } restartTrack(options) { return __awaiter(this, void 0, void 0, function* () { let constraints; if (options) { const streamConstraints = constraintsForOptions({ video: options }); if (typeof streamConstraints.video !== 'boolean') { constraints = streamConstraints.video; } } yield 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 */ setPublishingCodecs(codecs) { var _a, codecs_1, codecs_1_1; var _b, e_1, _c, _d; return __awaiter(this, void 0, void 0, function* () { livekitLogger.debug('setting publishing codecs', { codecs, currentCodec: this.codec }); // only enable simulcast codec for preference codec setted if (!this.codec && codecs.length > 0) { yield this.setPublishingLayers(codecs[0].qualities); return []; } this.subscribedCodecs = codecs; const newCodecs = []; try { for (_a = true, codecs_1 = __asyncValues(codecs); codecs_1_1 = yield codecs_1.next(), _b = codecs_1_1.done, !_b; _a = true) { _d = codecs_1_1.value; _a = false; const codec = _d; if (!this.codec || this.codec === codec.codec) { yield 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)); yield setPublishingLayersForSender(simulcastCodecInfo.sender, simulcastCodecInfo.encodings, codec.qualities, this.senderLock); } } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (!_a && !_b && (_c = codecs_1.return)) yield _c.call(codecs_1); } finally { if (e_1) throw e_1.error; } } return newCodecs; }); } /** * @internal * Sets layers that should be publishing */ setPublishingLayers(qualities) { return __awaiter(this, void 0, void 0, function* () { livekitLogger.debug('setting publishing layers', qualities); if (!this.sender || !this.encodings) { return; } yield setPublishingLayersForSender(this.sender, this.encodings, qualities, this.senderLock); }); } handleAppVisibilityChanged() { const _super = Object.create(null, { handleAppVisibilityChanged: { get: () => super.handleAppVisibilityChanged } }); return __awaiter(this, void 0, void 0, function* () { yield _super.handleAppVisibilityChanged.call(this); if (!isMobile()) return; if (this.isInBackground && this.source === Track.Source.Camera) { this._mediaStreamTrack.enabled = false; } }); } } function setPublishingLayersForSender(sender, senderEncodings, qualities, senderLock) { return __awaiter(this, void 0, void 0, function* () { const unlock = yield 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; /* @ts-ignore */ if (encodings.length === 1 && encodings[0].scalabilityMode) { // svc dynacast encodings const encoding = encodings[0]; /* @ts-ignore */ // const mode = new ScalabilityMode(encoding.scalabilityMode); let maxQuality = VideoQuality.OFF; qualities.forEach(q => { if (q.enabled && (maxQuality === VideoQuality.OFF || q.quality > maxQuality)) { maxQuality = q.quality; } }); if (maxQuality === VideoQuality.OFF) { if (encoding.active) { encoding.active = false; hasChanged = true; } } else if (!encoding.active /* || mode.spatial !== maxQuality + 1*/) { hasChanged = true; encoding.active = true; /* disable closable spatial layer as it has video blur/frozen issue with current server/client 1. chrome 113: when switching to up layer with scalability Mode change, it will generate a low resolution frame and recover very quickly, but noticable 2. livekit sfu: additional pli request cause video frozen for a few frames, also noticable @ts-ignore const originalMode = new ScalabilityMode(senderEncodings[0].scalabilityMode) mode.spatial = maxQuality + 1; mode.suffix = originalMode.suffix; if (mode.spatial === 1) { // no suffix for L1Tx mode.suffix = undefined; } @ts-ignore encoding.scalabilityMode = mode.toString(); encoding.scaleResolutionDownBy = 2 ** (2 - maxQuality); */ } } else { // simulcast dynacast encodings 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; livekitLogger.debug("setting encodings", params.encodings); yield 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 }]; } /* @ts-ignore */ if (encodings.length === 1 && encodings[0].scalabilityMode) { // svc layers /* @ts-ignore */ const sm = new ScalabilityMode(encodings[0].scalabilityMode); const layers = []; for (let i = 0; i < sm.spatial; i += 1) { layers.push({ quality: VideoQuality.HIGH - i, width: width / Math.pow(2, i), height: height / Math.pow(2, i), bitrate: encodings[0].maxBitrate ? encodings[0].maxBitrate / Math.pow(3, i) : 0, ssrc: 0 }); } return layers; } 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 = () => __awaiter(this, void 0, void 0, function* () { if (!this.receiver) { this._currentBitrate = 0; return; } const stats = yield 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 */ setSinkId(deviceId) { return __awaiter(this, void 0, void 0, function* () { this.sinkId = deviceId; yield 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; } getReceiverStats() { return __awaiter(this, void 0, void 0, function* () { if (!this.receiver || !this.receiver.getStats) { return; } const stats = yield 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; }); } } const REACTION_DELAY = 100; class RemoteVideoTrack extends RemoteTrack { constructor(mediaTrack, sid, receiver, adaptiveStreamSettings) { super(mediaTrack, sid, Track.Kind.Video, receiver); this.elementInfos = []; this.isObserved = false; this.monitorReceiver = () => __awaiter(this, void 0, void 0, function* () { if (!this.receiver) { this._currentBitrate = 0; return; } const stats = yield 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.isObserved) { 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); } 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(); this.isObserved = true; } 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; } getReceiverStats() { return __awaiter(this, void 0, void 0, function* () { if (!this.receiver || !this.receiver.getStats) { return; } const stats = yield 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); } handleAppVisibilityChanged() { const _super = Object.create(null, { handleAppVisibilityChanged: { get: () => super.handleAppVisibilityChanged } }); return __awaiter(this, void 0, void 0, function* () { yield _super.handleAppVisibilityChanged.call(this); 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' ? getDevicePixelRatio() : 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 */ mute() { var _a; return __awaiter(this, void 0, void 0, function* () { return (_a = this.track) === null || _a === void 0 ? void 0 : _a.mute(); }); } /** * Unmute track associated with this publication */ unmute() { var _a; return __awaiter(this, void 0, void 0, function* () { 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 */ pauseUpstream() { var _a; return __awaiter(this, void 0, void 0, function* () { yield (_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) */ resumeUpstream() { var _a; return __awaiter(this, void 0, void 0, function* () { yield (_a = this.track) === null || _a === void 0 ? void 0 : _a.resumeUpstream(); }); } } 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) { // it's possible the update could be applied out of order due to await // during reconnect sequences. when that happens, it's possible for server // to have sent more recent version of participant info while JS is waiting // to process the existing payload. // when the participant sid remains the same, and we already have a later version // of the payload, they can be safely skipped if (this.participantInfo && this.participantInfo.sid === info.sid && this.participantInfo.version > info.version) { return false; } this.identity = info.identity; this.sid = info.sid; this.setName(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 }); return true; } /** @internal */ setMetadata(md) { const changed = this.metadata !== md; const prevMetadata = this.metadata; this.metadata = md; if (changed) { this.emit(ParticipantEvent.ParticipantMetadataChanged, prevMetadata); } } setName(name) { const changed = this.name !== name; this.name = name; if (changed) { this.emit(ParticipantEvent.ParticipantNameChanged, name); } } /** @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 || [] }; } 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(); prevTrack.stopMonitor(); 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 */ setSubscriptionError(error) { this.emit(TrackEvent.SubscriptionFailed, error); } /** @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.kind === Track.Kind.Video && this.isAdaptiveStream) { livekitLogger.warn('adaptive stream is enabled, cannot change video 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); }); publication.on(TrackEvent.SubscriptionFailed, error => { this.emit(ParticipantEvent.TrackSubscriptionFailed, publication.trackSid, error); }); } 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) { if (!super.updateInfo(info)) { return false; } // 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); }); return true; } /** @internal */ unpublishTrack(sid, sendUnpublish) { const publication = this.tracks.get(sid); if (!publication) { return; } // also send unsubscribe, if track is actively subscribed const { track } = publication; if (track) { track.stop(); publication.setTrack(undefined); } // remove track from maps only after unsubscribed has been fired 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; } 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 */ setAudioOutput(output) { return __awaiter(this, void 0, void 0, function* () { 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')); } }); yield 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 = update => __awaiter(this, void 0, void 0, function* () { var _a, e_1, _b, _c; var _d, _e; if (!((_d = this.roomOptions) === null || _d === void 0 ? void 0 : _d.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 = yield pub.videoTrack.setPublishingCodecs(update.subscribedCodecs); try { for (var _f = true, newCodecs_1 = __asyncValues(newCodecs), newCodecs_1_1; newCodecs_1_1 = yield newCodecs_1.next(), _a = newCodecs_1_1.done, !_a; _f = true) { _c = newCodecs_1_1.value; _f = false; const codec = _c; if (isBackupCodec(codec)) { livekitLogger.debug("publish ".concat(codec, " for ").concat(pub.videoTrack.sid)); yield this.publishAdditionalCodecForTrack(pub.videoTrack, codec, pub.options); } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (!_f && !_a && (_b = newCodecs_1.return)) yield _b.call(newCodecs_1); } finally { if (e_1) throw e_1.error; } } } else if (update.subscribedQualities.length > 0) { yield (_e = pub.videoTrack) === null || _e === void 0 ? void 0 : _e.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 = track => __awaiter(this, void 0, void 0, function* () { 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) { yield track.mute(); } else if (track instanceof LocalAudioTrack || track instanceof LocalVideoTrack) { try { if (isWeb()) { try { const currentPermissions = yield 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'); yield track.restartTrack(); } } catch (e) { livekitLogger.warn("could not restart track, muting instead"); yield 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); } /** * Sets and updates the metadata of the local participant. * Note: this requires `canUpdateOwnMetadata` permission encoded in the token. * @param metadata */ setMetadata(metadata) { var _a; super.setMetadata(metadata); this.engine.client.sendUpdateLocalMetadata(metadata, (_a = this.name) !== null && _a !== void 0 ? _a : ''); } /** * Sets and updates the name of the local participant. * Note: this requires `canUpdateOwnMetadata` permission encoded in the token. * @param metadata */ setName(name) { var _a; super.setName(name); this.engine.client.sendUpdateLocalMetadata((_a = this.metadata) !== null && _a !== void 0 ? _a : '', name); } /** * 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); } setTrackEnabled(source, enabled, options, publishOptions) { var _a, _b; return __awaiter(this, void 0, void 0, function* () { livekitLogger.debug('setTrackEnabled', { source, enabled }); let track = this.getTrack(source); if (enabled) { if (track) { yield 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 = yield this.createTracks({ video: (_a = options) !== null && _a !== void 0 ? _a : true }); break; case Track.Source.Microphone: localTracks = yield this.createTracks({ audio: (_b = options) !== null && _b !== void 0 ? _b : true }); break; case Track.Source.ScreenShare: localTracks = yield this.createScreenTracks(Object.assign({}, 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 = yield 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 = yield this.unpublishTrack(track.track); const screenAudioTrack = this.getTrack(Track.Source.ScreenShareAudio); if (screenAudioTrack && screenAudioTrack.track) { this.unpublishTrack(screenAudioTrack.track); } } else { yield 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. */ enableCameraAndMicrophone() { return __awaiter(this, void 0, void 0, function* () { 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 = yield this.createTracks({ audio: true, video: true }); yield 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 */ createTracks(options) { var _a, _b; return __awaiter(this, void 0, void 0, function* () { 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 = yield 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. */ createScreenTracks(options) { var _a; return __awaiter(this, void 0, void 0, function* () { 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 = yield 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 */ publishTrack(track, options) { var _a, _b, _c; return __awaiter(this, void 0, void 0, function* () { yield (_a = this.reconnectFuture) === null || _a === void 0 ? void 0 : _a.promise; if (track instanceof LocalTrack && this.pendingPublishPromises.has(track)) { yield 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 = Object.assign(Object.assign({}, 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 = yield publishPromise; return publication; } catch (e) { throw e; } finally { this.pendingPublishPromises.delete(track); } }); } publish(track, opts, options, isStereo) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o; return __awaiter(this, void 0, void 0, function* () { 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/VP9 SVC support prior to using it if (opts.videoCodec === 'av1' && !supportsAV1()) { opts.videoCodec = undefined; } if (opts.videoCodec === 'vp9' && !supportsVP9()) { 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 = yield track.waitForDimensions(); } catch (e) { // use defaults, it's quite painful for congestion control without simulcast // so using default dims according to publish settings const defaultRes = (_d = (_c = this.roomOptions.videoCaptureDefaults) === null || _c === void 0 ? void 0 : _c.resolution) !== null && _d !== void 0 ? _d : VideoPresets.h720.resolution; dims = { width: defaultRes.width, height: defaultRes.height }; // log failure livekitLogger.error('could not determine track dimensions, using defaults', dims); } // 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 (isSVCCodec(opts.videoCodec)) { // set scalabilityMode to 'L3T3_KEY' by default opts.scalabilityMode = (_e = opts.scalabilityMode) !== null && _e !== void 0 ? _e : 'L3T3_KEY'; } // set up backup if (opts.videoCodec && opts.backupCodec && opts.videoCodec !== opts.backupCodec.codec) { const simOpts = Object.assign({}, 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 }]; } else if (opts.videoCodec) { // pass codec info to sfu so it can prefer codec for the client which don't support // setCodecPreferences req.simulcastCodecs = [{ codec: opts.videoCodec, cid: track.mediaStreamTrack.id, enableSimulcastLayers: (_f = opts.simulcast) !== null && _f !== void 0 ? _f : false }]; } } encodings = computeVideoEncodings(track.source === Track.Source.ScreenShare, dims.width, dims.height, opts); req.layers = videoLayersFromEncodings(req.width, req.height, encodings); } else if (track.kind === Track.Kind.Audio) { encodings = [{ maxBitrate: (_h = (_g = opts.audioPreset) === null || _g === void 0 ? void 0 : _g.maxBitrate) !== null && _h !== void 0 ? _h : opts.audioBitrate, priority: (_k = (_j = opts.audioPreset) === null || _j === void 0 ? void 0 : _j.priority) !== null && _k !== void 0 ? _k : 'high', networkPriority: (_m = (_l = opts.audioPreset) === null || _l === void 0 ? void 0 : _l.priority) !== null && _m !== void 0 ? _m : 'high' }]; } if (!this.engine || this.engine.isClosed) { throw new UnexpectedConnectionState('cannot publish track when not connected'); } const ti = yield this.engine.addTrack(req); let primaryCodecSupported = false; let backupCodecSupported = false; ti.codecs.forEach(c => { if (isCodecEqual(c.mimeType, opts.videoCodec)) { primaryCodecSupported = true; } else if (opts.backupCodec && isCodecEqual(c.mimeType, opts.backupCodec.codec)) { backupCodecSupported = true; } }); if (req.simulcastCodecs.length > 0) { if (!primaryCodecSupported && !backupCodecSupported) { throw Error('cannot publish track, codec not supported by server'); } if (!primaryCodecSupported && opts.backupCodec) { const backupCodec = opts.backupCodec; opts = Object.assign({}, opts); livekitLogger.debug("primary codec ".concat(opts.videoCodec, " not supported, fallback to ").concat(backupCodec.codec)); opts.videoCodec = backupCodec.codec; opts.videoEncoding = backupCodec.encoding; encodings = simEncodings; } } 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 = yield this.engine.createSender(track, opts, encodings); if (track.codec && isSVCCodec(track.codec) && encodings && ((_o = encodings[0]) === null || _o === void 0 ? void 0 : _o.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 */ publishAdditionalCodecForTrack(track, videoCodec, options) { var _a; return __awaiter(this, void 0, void 0, function* () { // 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 = Object.assign(Object.assign({}, (_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 = yield this.engine.addTrack(req); yield this.engine.createSimulcastSender(track, simulcastTrack, opts, encodings); this.engine.negotiate(); livekitLogger.debug("published ".concat(videoCodec, " for track ").concat(track.sid), { encodings, trackInfo: ti }); }); } unpublishTrack(track, stopOnUnpublish) { var _a, _b; return __awaiter(this, void 0, void 0, function* () { // 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 { for (const transceiver of this.engine.publisher.pc.getTransceivers()) { // if sender is not currently sending (after replaceTrack(null)) // removeTrack would have no effect. // to ensure we end up successfully removing the track, manually set // the transceiver to inactive if (transceiver.sender === trackSender) { transceiver.direction = 'inactive'; negotiationNeeded = true; } } 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) { yield this.engine.negotiate(); } return publication; }); } unpublishTracks(tracks) { return __awaiter(this, void 0, void 0, function* () { const results = yield Promise.all(tracks.map(track => this.unpublishTrack(track))); return results.filter(track => track instanceof LocalTrackPublication); }); } republishAllTracks(options) { return __awaiter(this, void 0, void 0, function* () { const localPubs = []; this.tracks.forEach(pub => { if (pub.track) { if (options) { pub.options = Object.assign(Object.assign({}, pub.options), options); } localPubs.push(pub); } }); yield Promise.all(localPubs.map(pub => __awaiter(this, void 0, void 0, function* () { const track = pub.track; yield this.unpublishTrack(track, false); yield this.publishTrack(track, pub.options); }))); }); } publishData(data, kind) { let publishOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; return __awaiter(this, void 0, void 0, function* () { 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 } } }; yield 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 false; } if (!super.updateInfo(info)) { return false; } // 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); } } }); return true; } 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; } } var ConnectionState; (function (ConnectionState) { ConnectionState["Disconnected"] = "disconnected"; ConnectionState["Connecting"] = "connecting"; ConnectionState["Connected"] = "connected"; ConnectionState["Reconnecting"] = "reconnecting"; })(ConnectionState || (ConnectionState = {})); const connectionReconcileFrequency = 2 * 1000; /** @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 = []; this.audioEnabled = true; this.connect = (url, token, opts) => __awaiter(this, void 0, void 0, function* () { // In case a disconnect called happened right before the connect call, make sure the disconnect is completed first by awaiting its lock const unlockDisconnect = yield 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 urlProvider = new RegionUrlProvider(url, token); const connectFn = (resolve, reject, regionUrl) => __awaiter(this, void 0, void 0, function* () { var _a; if (this.abortController) { this.abortController.abort(); } 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 === null || unlockDisconnect === void 0 ? void 0 : unlockDisconnect(); try { yield this.attemptConnection(regionUrl !== null && regionUrl !== void 0 ? regionUrl : url, token, opts, this.abortController); this.abortController = undefined; resolve(); } catch (e) { if (isCloud(new URL(url)) && e instanceof ConnectionError && e.reason !== 3 /* ConnectionErrorReason.Cancelled */) { let nextUrl = null; try { nextUrl = yield urlProvider.getNextBestRegionUrl((_a = this.abortController) === null || _a === void 0 ? void 0 : _a.signal); } catch (error) { if (error instanceof ConnectionError && (error.status === 401 || error.reason === 3 /* ConnectionErrorReason.Cancelled */)) { reject(error); return; } } if (nextUrl) { livekitLogger.debug('initial connection failed, retrying with another region'); yield connectFn(resolve, reject, nextUrl); } else { reject(e); } } else { reject(e); } } }); this.connectFuture = new Future(connectFn, () => { this.clearConnectionFutures(); }); return this.connectFuture.promise; }); this.connectSignal = (url, token, engine, connectOptions, roomOptions, abortController) => __awaiter(this, void 0, void 0, function* () { const joinResponse = yield engine.join(url, token, { autoSubscribe: connectOptions.autoSubscribe, publishOnly: connectOptions.publishOnly, adaptiveStream: typeof roomOptions.adaptiveStream === 'object' ? true : roomOptions.adaptiveStream, maxRetries: connectOptions.maxRetries }, 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 roomOptions.dynacast = false; } return joinResponse; }); this.applyJoinResponse = joinResponse => { const pi = joinResponse.participant; this.localParticipant.sid = pi.sid; this.localParticipant.identity = pi.identity; // populate remote participants, these should not trigger new events this.handleParticipantUpdates([pi, ...joinResponse.otherParticipants]); if (joinResponse.room) { this.handleRoomUpdate(joinResponse.room); } }; this.attemptConnection = (url, token, opts, abortController) => __awaiter(this, void 0, void 0, function* () { var _b; 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 = Object.assign(Object.assign({}, 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 = yield this.connectSignal(url, token, this.engine, this.connOptions, this.options, abortController); this.applyJoinResponse(joinResponse); // forward metadata changed for the local participant this.setupLocalParticipantEvents(); 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 }); throw resultingError; } if (abortController.signal.aborted) { this.recreateEngine(); this.handleDisconnect(this.options.stopLocalTrackOnUnpublish); throw new ConnectionError("Connection attempt aborted"); } try { yield this.engine.waitForPCInitialConnection(this.connOptions.peerConnectionTimeout, abortController); } catch (e) { this.recreateEngine(); this.handleDisconnect(this.options.stopLocalTrackOnUnpublish); throw e; } // 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); this.registerConnectionReconcile(); }); /** * disconnects the room, emits [[RoomEvent.Disconnected]] */ this.disconnect = function () { let stopTracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; return __awaiter(_this, void 0, void 0, function* () { var _c, _d, _e, _f; const unlock = yield 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'); (_c = this.abortController) === null || _c === void 0 ? void 0 : _c.abort(); // in case the abort controller didn't manage to cancel the connection attempt, reject the connect promise explicitly (_e = (_d = this.connectFuture) === null || _d === void 0 ? void 0 : _d.reject) === null || _e === void 0 ? void 0 : _e.call(_d, new ConnectionError('Client initiated disconnect')); this.connectFuture = undefined; } // send leave if ((_f = this.engine) === null || _f === void 0 ? void 0 : _f.client.isConnected) { yield this.engine.client.sendLeave(); } // close engine (also closes client) if (this.engine) { yield this.engine.close(); } this.handleDisconnect(stopTracks, DisconnectReason.CLIENT_INITIATED); /* @ts-ignore */ this.engine = undefined; } finally { unlock(); } }); }; this.onPageLeave = () => __awaiter(this, void 0, void 0, function* () { yield this.disconnect(); }); this.handleRestarting = () => { this.clearConnectionReconcile(); // 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.handleSignalRestarted = joinResponse => __awaiter(this, void 0, void 0, function* () { livekitLogger.debug("signal reconnected to server", { region: joinResponse.serverRegion }); this.cachedParticipantSids = []; this.applyJoinResponse(joinResponse); try { // unpublish & republish tracks const localPubs = []; this.localParticipant.tracks.forEach(pub => { if (pub.track) { localPubs.push(pub); } }); yield Promise.all(localPubs.map(pub => __awaiter(this, void 0, void 0, function* () { 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 }); yield track.restartTrack(); } livekitLogger.debug('publishing new track', { track: pub.trackSid }); yield this.localParticipant.publishTrack(track, pub.options); } }))); } catch (error) { livekitLogger.error('error trying to re-publish tracks after reconnection', { error }); } try { yield this.engine.waitForRestarted(); livekitLogger.debug("fully reconnected to server", { region: joinResponse.serverRegion }); } catch (_g) { // reconnection failed, handleDisconnect is being invoked already, just return here return; } this.setAndEmitConnectionState(ConnectionState.Connected); this.emit(RoomEvent.Reconnected); this.registerConnectionReconcile(); // emit participant connected events after connection has been re-established this.participants.forEach(participant => { this.emit(RoomEvent.ParticipantConnected, participant); }); }); 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.handleSubscriptionError = update => { const participant = Array.from(this.participants.values()).find(p => p.tracks.has(update.trackSid)); if (!participant) { return; } const pub = participant.getTrackPublication(update.trackSid); if (!pub) { return; } pub.setSubscriptionError(update.err); }; 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 = () => __awaiter(this, void 0, void 0, function* () { this.emit(RoomEvent.MediaDevicesChanged); }); this.handleRoomUpdate = room => { const oldRoom = this.roomInfo; this.roomInfo = room; if (oldRoom && oldRoom.metadata !== room.metadata) { this.emitWhenConnected(RoomEvent.RoomMetadataChanged, room.metadata); } if ((oldRoom === null || oldRoom === void 0 ? void 0 : oldRoom.activeRecording) !== room.activeRecording) { this.emitWhenConnected(RoomEvent.RecordingStatusChanged, room.activeRecording); } }; 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.onLocalParticipantNameChanged = name => { this.emit(RoomEvent.ParticipantNameChanged, name, this.localParticipant); }; this.onLocalTrackMuted = pub => { this.emit(RoomEvent.TrackMuted, pub, this.localParticipant); }; this.onLocalTrackUnmuted = pub => { this.emit(RoomEvent.TrackUnmuted, pub, this.localParticipant); }; this.onLocalTrackPublished = pub => __awaiter(this, void 0, void 0, function* () { this.emit(RoomEvent.LocalTrackPublished, pub, this.localParticipant); if (pub.track instanceof LocalAudioTrack) { const trackIsSilent = yield 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.cachedParticipantSids = []; this.identityToSid = new Map(); this.options = Object.assign(Object.assign({}, roomOptionDefaults), options); this.options.audioCaptureDefaults = Object.assign(Object.assign({}, audioDefaults), options === null || options === void 0 ? void 0 : options.audioCaptureDefaults); this.options.videoCaptureDefaults = Object.assign(Object.assign({}, videoDefaults), options === null || options === void 0 ? void 0 : options.videoCaptureDefaults); this.options.publishDefaults = Object.assign(Object.assign({}, publishDefaults), options === null || options === void 0 ? void 0 : options.publishDefaults); this.maybeCreateEngine(); this.disconnectLock = new Mutex(); this.localParticipant = new LocalParticipant('', '', this.engine, this.options); } /** * if the current room has a participant with `recorder: true` in its JWT grant **/ get isRecording() { var _a, _b; return (_b = (_a = this.roomInfo) === null || _a === void 0 ? void 0 : _a.activeRecording) !== null && _b !== void 0 ? _b : false; } /** server assigned unique room id */ get sid() { var _a, _b; return (_b = (_a = this.roomInfo) === null || _a === void 0 ? void 0 : _a.sid) !== null && _b !== void 0 ? _b : ''; } /** user assigned name, derived from JWT token */ get name() { var _a, _b; return (_b = (_a = this.roomInfo) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : ''; } /** room metadata */ get metadata() { var _a; return (_a = this.roomInfo) === null || _a === void 0 ? void 0 : _a.metadata; } get numParticipants() { var _a, _b; return (_b = (_a = this.roomInfo) === null || _a === void 0 ? void 0 : _a.numParticipants) !== null && _b !== void 0 ? _b : 0; } get numPublishers() { var _a, _b; return (_b = (_a = this.roomInfo) === null || _a === void 0 ? void 0 : _a.numPublishers) !== null && _b !== void 0 ? _b : 0; } maybeCreateEngine() { if (this.engine && !this.engine.isClosed) { 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.client.onSubscriptionError = this.handleSubscriptionError; 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, () => { this.clearConnectionReconcile(); if (this.setAndEmitConnectionState(ConnectionState.Reconnecting)) { this.emit(RoomEvent.Reconnecting); } this.cachedParticipantSids = Array.from(this.participants.keys()); }).on(EngineEvent.Resumed, () => { this.setAndEmitConnectionState(ConnectionState.Connected); this.emit(RoomEvent.Reconnected); this.registerConnectionReconcile(); this.updateSubscriptions(); // once reconnected, figure out if any participants connected during reconnect and emit events for it const diffParticipants = Array.from(this.participants.values()).filter(p => !this.cachedParticipantSids.includes(p.sid)); diffParticipants.forEach(p => this.emit(RoomEvent.ParticipantConnected, p)); this.cachedParticipantSids = []; }).on(EngineEvent.SignalResumed, () => { if (this.state === ConnectionState.Reconnecting) { this.sendSyncState(); } }).on(EngineEvent.Restarting, this.handleRestarting).on(EngineEvent.SignalRestarted, this.handleSignalRestarted).on(EngineEvent.DCBufferStatusChanged, (status, kind) => { this.emit(RoomEvent.DCBufferStatusChanged, status, kind); }); 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 */ prepareConnection(url) { return __awaiter(this, void 0, void 0, function* () { yield 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; } /** * @internal for testing */ simulateScenario(scenario) { return __awaiter(this, void 0, void 0, function* () { let postAction = () => {}; let req; switch (scenario) { case 'signal-reconnect': yield 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(); yield this.engine.client.close(); if (this.engine.client.onClose) { this.engine.client.onClose('simulate resume-reconnect'); } break; case 'full-reconnect': this.engine.fullReconnectOnNext = true; yield this.engine.client.close(); if (this.engine.client.onClose) { this.engine.client.onClose('simulate full-reconnect'); } break; case 'force-tcp': case 'force-tls': req = SimulateScenario.fromPartial({ scenario: { $case: 'switchCandidateProtocol', switchCandidateProtocol: scenario === 'force-tls' ? 2 : 1 } }); postAction = () => __awaiter(this, void 0, void 0, function* () { 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` */ startAudio() { return __awaiter(this, void 0, void 0, function* () { yield this.acquireAudioContext(); const elements = []; this.participants.forEach(p => { p.audioTracks.forEach(t => { if (t.track) { t.track.attachedElements.forEach(e => { elements.push(e); }); } }); }); try { yield 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 */ switchActiveDevice(kind, deviceId) { let exact = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; var _a; var _b; return __awaiter(this, void 0, void 0, function* () { 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 { yield 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 { yield 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 { yield 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.ParticipantNameChanged, this.onLocalParticipantNameChanged).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; this.clearConnectionReconcile(); if (this.state === ConnectionState.Disconnected) { return; } try { 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.ParticipantNameChanged, this.onLocalParticipantNameChanged).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); } } finally { 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); } acquireAudioContext() { var _a, _b; return __awaiter(this, void 0, void 0, function* () { 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; yield 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.ParticipantNameChanged, name => { this.emitWhenConnected(RoomEvent.ParticipantNameChanged, name, 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.TrackSubscriptionFailed, (trackSid, error) => { this.emit(RoomEvent.TrackSubscriptionFailed, trackSid, participant, error); }).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(); } } } } registerConnectionReconcile() { this.clearConnectionReconcile(); let consecutiveFailures = 0; this.connectionReconcileInterval = CriticalTimers.setInterval(() => { if ( // ensure we didn't tear it down !this.engine || // engine detected close, but Room missed it this.engine.isClosed || // transports failed without notifying engine !this.engine.verifyTransport()) { consecutiveFailures++; livekitLogger.warn('detected connection state mismatch', { numFailures: consecutiveFailures }); if (consecutiveFailures >= 3) { this.recreateEngine(); this.handleDisconnect(this.options.stopLocalTrackOnUnpublish, DisconnectReason.STATE_MISMATCH); } } else { consecutiveFailures = 0; } }, connectionReconcileFrequency); } clearConnectionReconcile() { if (this.connectionReconcileInterval) { CriticalTimers.clearInterval(this.connectionReconcileInterval); } } 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 */ simulateParticipants(options) { var _a, _b; return __awaiter(this, void 0, void 0, function* () { const publishOptions = Object.assign({ audio: true, video: true, useRealTracks: false }, options.publish); const participantOptions = Object.assign({ count: 9, audio: false, video: true, aspectRatios: [1.66, 1.7, 1.3] }, options.participants); this.handleDisconnect(); this.roomInfo = { sid: 'RM_SIMULATED', name: 'simulated-room', emptyTimeout: 0, maxParticipants: 0, creationTime: new Date().getTime(), metadata: '', numParticipants: 1, numPublishers: 1, turnPassword: '', enabledCodecs: [], activeRecording: false }; 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 ? (yield 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 ? (yield 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); } } 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; } } run(onComplete) { return __awaiter(this, void 0, void 0, function* () { if (this.status !== CheckStatus.IDLE) { throw Error('check is running already'); } this.setStatus(CheckStatus.RUNNING); this.appendMessage("".concat(this.name, " started.")); try { yield this.perform(); } catch (err) { if (err instanceof Error) { if (this.errorsAsWarnings) { this.appendWarning(err.message); } else { this.appendError(err.message); } } } yield this.disconnect(); // sleep for a bit to ensure disconnect yield 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'); } connect() { return __awaiter(this, void 0, void 0, function* () { if (this.room.state === ConnectionState.Connected) { return this.room; } yield this.room.connect(this.url, this.token); return this.room; }); } disconnect() { return __awaiter(this, void 0, void 0, function* () { if (this.room && this.room.state !== ConnectionState.Disconnected) { yield this.room.disconnect(); // wait for it to go through yield 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 }; } } /** * 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 */ function createLocalTracks(options) { var _a, _b; return __awaiter(this, void 0, void 0, function* () { // 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 = yield 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 */ function createLocalVideoTrack(options) { return __awaiter(this, void 0, void 0, function* () { const tracks = yield createLocalTracks({ audio: false, video: options }); return tracks[0]; }); } function createLocalAudioTrack(options) { return __awaiter(this, void 0, void 0, function* () { const tracks = yield 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. */ function createLocalScreenTracks(options) { var _a; return __awaiter(this, void 0, void 0, function* () { 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 = yield 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; }); } class PublishAudioCheck extends Checker { get description() { return 'Can publish audio'; } perform() { var _a; return __awaiter(this, void 0, void 0, function* () { const room = yield this.connect(); const track = yield createLocalAudioTrack(); room.localParticipant.publishTrack(track); // wait for a few seconds to publish yield new Promise(resolve => setTimeout(resolve, 3000)); // verify RTC stats that it's publishing const stats = yield (_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'; } perform() { var _a; return __awaiter(this, void 0, void 0, function* () { const room = yield this.connect(); const track = yield createLocalVideoTrack(); room.localParticipant.publishTrack(track); // wait for a few seconds to publish yield new Promise(resolve => setTimeout(resolve, 3000)); // verify RTC stats that it's publishing const stats = yield (_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'; } perform() { var _a; return __awaiter(this, void 0, void 0, function* () { const room = yield 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(''); } yield 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'; } perform() { var _a, _b; return __awaiter(this, void 0, void 0, function* () { const signalClient = new SignalClient(); const joinRes = yield 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.'); } yield signalClient.close(); if (((_b = (_a = this.connectOptions) === null || _a === void 0 ? void 0 : _a.rtcConfig) === null || _b === void 0 ? void 0 : _b.iceServers) || hasTURN) { yield this.room.connect(this.url, this.token, { rtcConfig: { iceTransportPolicy: 'relay' } }); } else { this.appendWarning('No TURN servers configured.'); this.skip(); yield new Promise(resolve => setTimeout(resolve, 0)); } }); } } class WebRTCCheck extends Checker { get description() { return 'Establishing WebRTC connection'; } perform() { return __awaiter(this, void 0, void 0, function* () { try { console.log('initiating room connection'); this.room = yield 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'; } perform() { return __awaiter(this, void 0, void 0, function* () { 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 = yield signalClient.join(this.url, this.token, { autoSubscribe: true, maxRetries: 0 }); this.appendMessage("Connected to server, version ".concat(joinRes.serverVersion, ".")); yield signalClient.close(); }); } } class ConnectionCheck extends eventsExports.EventEmitter { 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()); } createAndRunCheck(check) { return __awaiter(this, void 0, void 0, function* () { 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 = yield test.run(); test.off('update', handleUpdate); return result; }); } checkWebsocket() { return __awaiter(this, void 0, void 0, function* () { return this.createAndRunCheck(WebSocketCheck); }); } checkWebRTC() { return __awaiter(this, void 0, void 0, function* () { return this.createAndRunCheck(WebRTCCheck); }); } checkTURN() { return __awaiter(this, void 0, void 0, function* () { return this.createAndRunCheck(TURNCheck); }); } checkReconnect() { return __awaiter(this, void 0, void 0, function* () { return this.createAndRunCheck(ReconnectCheck); }); } checkPublishAudio() { return __awaiter(this, void 0, void 0, function* () { return this.createAndRunCheck(PublishAudioCheck); }); } checkPublishVideo() { return __awaiter(this, void 0, void 0, function* () { return this.createAndRunCheck(PublishVideoCheck); }); } } //# sourceMappingURL=livekit-client.esm.mjs.map /***/ }) /******/ }); /************************************************************************/ /******/ // 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); /******/ } /******/ } /******/ } /******/ }; /******/ /******/ // 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