From d813509541240d1523d1ee9683f1a18d94c58cac Mon Sep 17 00:00:00 2001 From: Robert Long Date: Fri, 10 Sep 2021 12:20:17 -0700 Subject: [PATCH] Moving to matrix-js-sdk --- index.html | 1 - package-lock.json | 1110 +++-------------------------- package.json | 2 +- src/App.jsx | 23 +- src/ConferenceCallManager.js | 981 ------------------------- src/ConferenceCallManagerHooks.js | 650 +++++++++-------- src/GuestAuthPage.jsx | 91 +++ src/GuestAuthPage.module.css | 8 + src/Home.jsx | 27 +- src/LoginPage.jsx | 13 +- src/RegisterPage.jsx | 14 +- src/Room.jsx | 394 +++++----- src/VideoGrid.jsx | 26 +- 13 files changed, 821 insertions(+), 2519 deletions(-) delete mode 100644 src/ConferenceCallManager.js create mode 100644 src/GuestAuthPage.jsx create mode 100644 src/GuestAuthPage.module.css diff --git a/index.html b/index.html index 4c8f329..72c59a7 100644 --- a/index.html +++ b/index.html @@ -8,7 +8,6 @@ -
diff --git a/package-lock.json b/package-lock.json index 3537bde..63f6ade 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "color-hash": "^2.0.1", "events": "^3.3.0", "lodash-move": "^1.1.1", - "matrix-js-sdk": "^12.0.1", + "matrix-js-sdk": "file:../matrix-js-sdk", "re-resizable": "^6.9.0", "react": "^17.0.0", "react-dom": "^17.0.0", @@ -26,6 +26,62 @@ "vite": "^2.4.2" } }, + "../matrix-js-sdk": { + "version": "12.4.0", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.12.5", + "another-json": "^0.2.0", + "browser-request": "^0.3.3", + "bs58": "^4.0.1", + "content-type": "^1.0.4", + "loglevel": "^1.7.1", + "p-retry": "^4.5.0", + "qs": "^6.9.6", + "request": "^2.88.2", + "unhomoglyph": "^1.0.6" + }, + "devDependencies": { + "@babel/cli": "^7.12.10", + "@babel/core": "^7.12.10", + "@babel/eslint-parser": "^7.12.10", + "@babel/eslint-plugin": "^7.12.10", + "@babel/plugin-proposal-class-properties": "^7.12.1", + "@babel/plugin-proposal-numeric-separator": "^7.12.7", + "@babel/plugin-proposal-object-rest-spread": "^7.12.1", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.12.10", + "@babel/preset-env": "^7.12.11", + "@babel/preset-typescript": "^7.12.7", + "@babel/register": "^7.12.10", + "@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz", + "@types/bs58": "^4.0.1", + "@types/jest": "^26.0.20", + "@types/node": "12", + "@types/request": "^2.48.5", + "@typescript-eslint/eslint-plugin": "^4.17.0", + "@typescript-eslint/parser": "^4.17.0", + "allchange": "^1.0.2", + "babel-jest": "^26.6.3", + "babelify": "^10.0.0", + "better-docs": "^2.4.0-beta.9", + "browserify": "^17.0.0", + "docdash": "^1.2.0", + "eslint": "7.18.0", + "eslint-config-google": "^0.14.0", + "eslint-plugin-matrix-org": "github:matrix-org/eslint-plugin-matrix-org#2306b3d4da4eba908b256014b979f1d3d43d2945", + "exorcist": "^1.0.1", + "fake-indexeddb": "^3.1.2", + "jest": "^26.6.3", + "jest-localstorage-mock": "^2.4.6", + "jsdoc": "^3.6.6", + "matrix-mock-request": "^1.2.3", + "rimraf": "^3.0.2", + "terser": "^5.5.1", + "tsify": "^5.0.2", + "typescript": "^4.1.3" + } + }, "node_modules/@babel/code-frame": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", @@ -625,11 +681,6 @@ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, - "node_modules/@types/retry": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", - "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==" - }, "node_modules/@vitejs/plugin-react-refresh": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-refresh/-/plugin-react-refresh-1.3.5.tgz", @@ -646,26 +697,6 @@ "node": ">=12.0.0" } }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/another-json": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/another-json/-/another-json-0.2.0.tgz", - "integrity": "sha1-tfQBnJc7bdXGUGotk0acttMq7tw=" - }, "node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -677,64 +708,6 @@ "node": ">=4" } }, - "node_modules/asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" - }, - "node_modules/base-x": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz", - "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/browser-request": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/browser-request/-/browser-request-0.3.3.tgz", - "integrity": "sha1-ns5bWsqJopkyJC4Yv5M975h2zBc=", - "engines": [ - "node" - ] - }, "node_modules/browserslist": { "version": "4.16.6", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", @@ -757,26 +730,6 @@ "url": "https://opencollective.com/browserslist" } }, - "node_modules/bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", - "dependencies": { - "base-x": "^3.0.2" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -805,11 +758,6 @@ "url": "https://opencollective.com/browserslist" } }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -851,25 +799,6 @@ "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/convert-source-map": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", @@ -878,11 +807,6 @@ "safe-buffer": "~5.1.1" } }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, "node_modules/cosmiconfig": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", @@ -898,17 +822,6 @@ "node": ">=10" } }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/debounce": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", @@ -930,23 +843,6 @@ } } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, "node_modules/electron-to-chromium": { "version": "1.3.777", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.777.tgz", @@ -999,55 +895,11 @@ "node": ">=0.8.x" } }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, "node_modules/fast-memoize": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz", "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==" }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, "node_modules/fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", @@ -1074,27 +926,6 @@ "node": ">=6.9.0" } }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dependencies": { - "assert-plus": "^1.0.0" - } - }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -1103,27 +934,6 @@ "node": ">=4" } }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -1143,17 +953,6 @@ "node": ">=4" } }, - "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/history": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", @@ -1175,20 +974,6 @@ "react-is": "^16.7.0" } }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -1220,31 +1005,16 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, "node_modules/isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -1261,21 +1031,6 @@ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, - "node_modules/json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, "node_modules/json5": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", @@ -1290,20 +1045,6 @@ "node": ">=6" } }, - "node_modules/jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, "node_modules/lines-and-columns": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", @@ -1322,18 +1063,6 @@ "lodash": "^4.6.1" } }, - "node_modules/loglevel": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", - "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==", - "engines": { - "node": ">= 0.6.0" - }, - "funding": { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/loglevel" - } - }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -1346,40 +1075,8 @@ } }, "node_modules/matrix-js-sdk": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-12.0.1.tgz", - "integrity": "sha512-HkOWv8QHojceo3kPbC+vAIFUjsRAig6MBvEY35UygS3g2dL0UcJ5Qx09/2wcXtu6dowlDnWsz2HHk62tS2cklA==", - "dependencies": { - "@babel/runtime": "^7.12.5", - "another-json": "^0.2.0", - "browser-request": "^0.3.3", - "bs58": "^4.0.1", - "content-type": "^1.0.4", - "loglevel": "^1.7.1", - "p-retry": "^4.5.0", - "qs": "^6.9.6", - "request": "^2.88.2", - "unhomoglyph": "^1.0.6" - } - }, - "node_modules/mime-db": { - "version": "1.48.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", - "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.31", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", - "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", - "dependencies": { - "mime-db": "1.48.0" - }, - "engines": { - "node": ">= 0.6" - } + "resolved": "../matrix-js-sdk", + "link": true }, "node_modules/mini-create-react-context": { "version": "0.4.1", @@ -1420,14 +1117,6 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==" }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "engines": { - "node": "*" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -1436,26 +1125,6 @@ "node": ">=0.10.0" } }, - "node_modules/object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/p-retry": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz", - "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==", - "dependencies": { - "@types/retry": "^0.12.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -1505,11 +1174,6 @@ "node": ">=8" } }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, "node_modules/picomatch": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", @@ -1549,33 +1213,6 @@ "react-is": "^16.8.1" } }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", - "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/re-resizable": { "version": "6.9.0", "resolved": "https://registry.npmjs.org/re-resizable/-/re-resizable-6.9.0.tgz", @@ -1689,45 +1326,6 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request/node_modules/qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "engines": { - "node": ">=0.6" - } - }, "node_modules/resolve": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", @@ -1753,14 +1351,6 @@ "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "engines": { - "node": ">= 4" - } - }, "node_modules/rollup": { "version": "2.53.2", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.53.2.tgz", @@ -1780,11 +1370,6 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, "node_modules/scheduler": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", @@ -1802,19 +1387,6 @@ "semver": "bin/semver.js" } }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -1831,30 +1403,6 @@ "node": ">=0.10.0" } }, - "node_modules/sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -1889,74 +1437,11 @@ "node": ">=4" } }, - "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, - "node_modules/unhomoglyph": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/unhomoglyph/-/unhomoglyph-1.0.6.tgz", - "integrity": "sha512-7uvcWI3hWshSADBu4JpnyYbTVc7YlhF5GDW/oPD5AxIxl34k4wXR3WDkPnzLxkN32LiTCTKMQLtKVZiwki3zGg==" - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "bin": { - "uuid": "bin/uuid" - } - }, "node_modules/value-equal": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, "node_modules/vite": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/vite/-/vite-2.4.2.tgz", @@ -2396,11 +1881,6 @@ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, - "@types/retry": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", - "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==" - }, "@vitejs/plugin-react-refresh": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-refresh/-/plugin-react-refresh-1.3.5.tgz", @@ -2414,22 +1894,6 @@ "react-refresh": "^0.10.0" } }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "another-json": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/another-json/-/another-json-0.2.0.tgz", - "integrity": "sha1-tfQBnJc7bdXGUGotk0acttMq7tw=" - }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -2438,55 +1902,6 @@ "color-convert": "^1.9.0" } }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" - }, - "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" - }, - "base-x": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz", - "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "browser-request": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/browser-request/-/browser-request-0.3.3.tgz", - "integrity": "sha1-ns5bWsqJopkyJC4Yv5M975h2zBc=" - }, "browserslist": { "version": "4.16.6", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", @@ -2499,23 +1914,6 @@ "node-releases": "^1.1.71" } }, - "bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", - "requires": { - "base-x": "^3.0.2" - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -2531,11 +1929,6 @@ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001245.tgz", "integrity": "sha512-768fM9j1PKXpOCKws6eTo3RHmvTUsG9UrpT4WoREFeZgJBTi4/X9g565azS/rVUGtqb8nt7FjLeF5u4kukERnA==" }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -2574,19 +1967,6 @@ "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, "convert-source-map": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", @@ -2595,11 +1975,6 @@ "safe-buffer": "~5.1.1" } }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, "cosmiconfig": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", @@ -2612,14 +1987,6 @@ "yaml": "^1.10.0" } }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" - } - }, "debounce": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", @@ -2633,20 +2000,6 @@ "ms": "2.1.2" } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, "electron-to-chromium": { "version": "1.3.777", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.777.tgz", @@ -2686,46 +2039,11 @@ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, "fast-memoize": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz", "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==" }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, "fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", @@ -2742,43 +2060,11 @@ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" - } - }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -2792,11 +2078,6 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" - }, "history": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", @@ -2818,16 +2099,6 @@ "react-is": "^16.7.0" } }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -2850,31 +2121,16 @@ "has": "^1.0.3" } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -2885,21 +2141,6 @@ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, "json5": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", @@ -2908,17 +2149,6 @@ "minimist": "^1.2.5" } }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, "lines-and-columns": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", @@ -2937,11 +2167,6 @@ "lodash": "^4.6.1" } }, - "loglevel": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", - "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==" - }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -2951,35 +2176,58 @@ } }, "matrix-js-sdk": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-12.0.1.tgz", - "integrity": "sha512-HkOWv8QHojceo3kPbC+vAIFUjsRAig6MBvEY35UygS3g2dL0UcJ5Qx09/2wcXtu6dowlDnWsz2HHk62tS2cklA==", + "version": "file:../matrix-js-sdk", "requires": { + "@babel/cli": "^7.12.10", + "@babel/core": "^7.12.10", + "@babel/eslint-parser": "^7.12.10", + "@babel/eslint-plugin": "^7.12.10", + "@babel/plugin-proposal-class-properties": "^7.12.1", + "@babel/plugin-proposal-numeric-separator": "^7.12.7", + "@babel/plugin-proposal-object-rest-spread": "^7.12.1", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.12.10", + "@babel/preset-env": "^7.12.11", + "@babel/preset-typescript": "^7.12.7", + "@babel/register": "^7.12.10", "@babel/runtime": "^7.12.5", + "@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz", + "@types/bs58": "^4.0.1", + "@types/jest": "^26.0.20", + "@types/node": "12", + "@types/request": "^2.48.5", + "@typescript-eslint/eslint-plugin": "^4.17.0", + "@typescript-eslint/parser": "^4.17.0", + "allchange": "^1.0.2", "another-json": "^0.2.0", + "babel-jest": "^26.6.3", + "babelify": "^10.0.0", + "better-docs": "^2.4.0-beta.9", "browser-request": "^0.3.3", + "browserify": "^17.0.0", "bs58": "^4.0.1", "content-type": "^1.0.4", + "docdash": "^1.2.0", + "eslint": "7.18.0", + "eslint-config-google": "^0.14.0", + "eslint-plugin-matrix-org": "github:matrix-org/eslint-plugin-matrix-org#2306b3d4da4eba908b256014b979f1d3d43d2945", + "exorcist": "^1.0.1", + "fake-indexeddb": "^3.1.2", + "jest": "^26.6.3", + "jest-localstorage-mock": "^2.4.6", + "jsdoc": "^3.6.6", "loglevel": "^1.7.1", + "matrix-mock-request": "^1.2.3", "p-retry": "^4.5.0", "qs": "^6.9.6", "request": "^2.88.2", + "rimraf": "^3.0.2", + "terser": "^5.5.1", + "tsify": "^5.0.2", + "typescript": "^4.1.3", "unhomoglyph": "^1.0.6" } }, - "mime-db": { - "version": "1.48.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", - "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==" - }, - "mime-types": { - "version": "2.1.31", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", - "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", - "requires": { - "mime-db": "1.48.0" - } - }, "mini-create-react-context": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", @@ -3009,30 +2257,11 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==" }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, - "object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" - }, - "p-retry": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz", - "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==", - "requires": { - "@types/retry": "^0.12.0", - "retry": "^0.13.1" - } - }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -3070,11 +2299,6 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, "picomatch": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", @@ -3101,24 +2325,6 @@ "react-is": "^16.8.1" } }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "qs": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", - "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", - "requires": { - "side-channel": "^1.0.4" - } - }, "re-resizable": { "version": "6.9.0", "resolved": "https://registry.npmjs.org/re-resizable/-/re-resizable-6.9.0.tgz", @@ -3207,40 +2413,6 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" - } - } - }, "resolve": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", @@ -3260,11 +2432,6 @@ "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" }, - "retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" - }, "rollup": { "version": "2.53.2", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.53.2.tgz", @@ -3278,11 +2445,6 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, "scheduler": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", @@ -3297,16 +2459,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -3317,22 +2469,6 @@ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==" }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -3361,61 +2497,11 @@ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, - "unhomoglyph": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/unhomoglyph/-/unhomoglyph-1.0.6.tgz", - "integrity": "sha512-7uvcWI3hWshSADBu4JpnyYbTVc7YlhF5GDW/oPD5AxIxl34k4wXR3WDkPnzLxkN32LiTCTKMQLtKVZiwki3zGg==" - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "requires": { - "punycode": "^2.1.0" - } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - }, "value-equal": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, "vite": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/vite/-/vite-2.4.2.tgz", diff --git a/package.json b/package.json index 72758fd..b27007b 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "color-hash": "^2.0.1", "events": "^3.3.0", "lodash-move": "^1.1.1", - "matrix-js-sdk": "^12.0.1", + "matrix-js-sdk": "file:../matrix-js-sdk", "re-resizable": "^6.9.0", "react": "^17.0.0", "react-dom": "^17.0.0", diff --git a/src/App.jsx b/src/App.jsx index 383dd7c..41a78d0 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -22,13 +22,14 @@ import { Redirect, useLocation, } from "react-router-dom"; -import { useConferenceCallManager } from "./ConferenceCallManagerHooks"; +import { useClient } from "./ConferenceCallManagerHooks"; import { Home } from "./Home"; -import { Room, RoomAuth } from "./Room"; +import { Room } from "./Room"; import { GridDemo } from "./GridDemo"; import { RegisterPage } from "./RegisterPage"; import { LoginPage } from "./LoginPage"; import { Center } from "./Layout"; +import { GuestAuthPage } from "./GuestAuthPage"; export default function App() { const { protocol, host } = window.location; @@ -37,12 +38,12 @@ export default function App() { const { loading, authenticated, - error, - manager, + client, login, - loginAsGuest, + logout, + registerGuest, register, - } = useConferenceCallManager(homeserverUrl); + } = useClient(homeserverUrl); return ( @@ -54,19 +55,19 @@ export default function App() { ) : ( - + - + - + {authenticated ? ( - + ) : ( - + )} diff --git a/src/ConferenceCallManager.js b/src/ConferenceCallManager.js deleted file mode 100644 index ec36c60..0000000 --- a/src/ConferenceCallManager.js +++ /dev/null @@ -1,981 +0,0 @@ -/* -Copyright 2021 New Vector Ltd - -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. -*/ - -import EventEmitter from "events"; -import { ConferenceCallDebugger } from "./ConferenceCallDebugger"; -import { randomString } from "./randomstring"; - -const CONF_ROOM = "me.robertlong.conf"; -const CONF_PARTICIPANT = "me.robertlong.conf.participant"; -const PARTICIPANT_TIMEOUT = 1000 * 15; -const SPEAKING_THRESHOLD = -80; -const ACTIVE_SPEAKER_INTERVAL = 1000; -const ACTIVE_SPEAKER_SAMPLES = 8; - -function waitForSync(client) { - return new Promise((resolve, reject) => { - const onSync = (state) => { - if (state === "PREPARED") { - resolve(); - client.removeListener("sync", onSync); - } - }; - client.on("sync", onSync); - }); -} - -export class ConferenceCallManager extends EventEmitter { - static async restore(homeserverUrl) { - try { - const authStore = localStorage.getItem("matrix-auth-store"); - - if (authStore) { - const { user_id, device_id, access_token } = JSON.parse(authStore); - - const client = matrixcs.createClient({ - baseUrl: homeserverUrl, - accessToken: access_token, - userId: user_id, - deviceId: device_id, - }); - - const manager = new ConferenceCallManager(client); - - await client.startClient({ - // dirty hack to reduce chance of gappy syncs - // should be fixed by spotting gaps and backpaginating - initialSyncLimit: 50, - }); - - await waitForSync(client); - - return manager; - } - } catch (err) { - localStorage.removeItem("matrix-auth-store"); - throw err; - } - } - - static async login(homeserverUrl, username, password) { - try { - const registrationClient = matrixcs.createClient(homeserverUrl); - - const { user_id, device_id, access_token } = - await registrationClient.loginWithPassword(username, password); - - const client = matrixcs.createClient({ - baseUrl: homeserverUrl, - accessToken: access_token, - userId: user_id, - deviceId: device_id, - }); - - localStorage.setItem( - "matrix-auth-store", - JSON.stringify({ user_id, device_id, access_token }) - ); - - const manager = new ConferenceCallManager(client); - - await client.startClient({ - // dirty hack to reduce chance of gappy syncs - // should be fixed by spotting gaps and backpaginating - initialSyncLimit: 50, - }); - - await waitForSync(client); - - return manager; - } catch (err) { - localStorage.removeItem("matrix-auth-store"); - - throw err; - } - } - - static async loginAsGuest(homeserverUrl, displayName) { - const registrationClient = matrixcs.createClient(homeserverUrl); - - const { user_id, device_id, access_token } = - await registrationClient.registerGuest(); - - const client = matrixcs.createClient({ - baseUrl: homeserverUrl, - accessToken: access_token, - userId: user_id, - deviceId: device_id, - }); - - await client.setDisplayName(displayName); - - client.setGuest(true); - - const manager = new ConferenceCallManager(client); - - await client.startClient({ - // dirty hack to reduce chance of gappy syncs - // should be fixed by spotting gaps and backpaginating - initialSyncLimit: 50, - }); - - await waitForSync(client); - - return manager; - } - - static async register(homeserverUrl, username, password) { - try { - const registrationClient = matrixcs.createClient(homeserverUrl); - - const { user_id, device_id, access_token } = - await registrationClient.register(username, password, null, { - type: "m.login.dummy", - }); - - const client = matrixcs.createClient({ - baseUrl: homeserverUrl, - accessToken: access_token, - userId: user_id, - deviceId: device_id, - }); - - localStorage.setItem( - "matrix-auth-store", - JSON.stringify({ user_id, device_id, access_token }) - ); - - const manager = new ConferenceCallManager(client); - - await client.startClient({ - // dirty hack to reduce chance of gappy syncs - // should be fixed by spotting gaps and backpaginating - initialSyncLimit: 50, - }); - - await waitForSync(client); - - return manager; - } catch (err) { - localStorage.removeItem("matrix-auth-store"); - - throw err; - } - } - - constructor(client) { - super(); - - this.client = client; - - this.room = null; - - // The session id is used to re-initiate calls if the user's participant - // session id has changed - this.sessionId = randomString(16); - - this._memberParticipantStateTimeout = null; - - // Whether or not we have entered the conference call. - this.entered = false; - - this._left = false; - - // The MatrixCalls that were picked up by the Call.incoming listener, - // before the user entered the conference call. - this._incomingCallQueue = []; - - // A representation of the conference call data for each room member - // that has entered the call. - this.participants = []; - - this.localVideoStream = null; - this.localParticipant = null; - this.localCallFeed = null; - - this.audioMuted = false; - this.videoMuted = false; - - this.activeSpeaker = null; - this._speakerMap = new Map(); - this._activeSpeakerLoopTimeout = null; - - this.client.on("RoomState.members", this._onRoomStateMembers); - this.client.on("Call.incoming", this._onIncomingCall); - this.callDebugger = new ConferenceCallDebugger(this); - } - - async enter(roomId, timeout = 30000) { - this._left = false; - - // Ensure that we have joined the provided room. - await this.client.joinRoom(roomId); - - // Get the room info, wait if it hasn't been fetched yet. - // Timeout after 30 seconds or the provided duration. - const room = await new Promise((resolve, reject) => { - const initialRoom = this.client.getRoom(roomId); - - if (initialRoom) { - resolve(initialRoom); - return; - } - - const roomTimeout = setTimeout(() => { - reject(new Error("Room could not be found.")); - }, timeout); - - const roomCallback = (room) => { - if (room && room.roomId === roomId) { - this.client.removeListener("Room", roomCallback); - clearTimeout(roomTimeout); - resolve(room); - } - }; - - this.client.on("Room", roomCallback); - }); - - // Ensure that this room is marked as a conference room so clients can react appropriately - const activeConf = room.currentState - .getStateEvents(CONF_ROOM, "") - ?.getContent()?.active; - - if (!activeConf) { - this._sendStateEventWithRetry( - room.roomId, - CONF_ROOM, - { active: true }, - "" - ); - } - - // Request permissions and get the user's webcam/mic stream if we haven't yet. - const userId = this.client.getUserId(); - const stream = await this.getLocalVideoStream(); - - // It's possible to navigate to another page while the microphone permission prompt is - // open, so check to see if we've left the call. - // Only set class variables below this check so that leaveRoom properly handles - // state cleanup. - if (this._left) { - return; - } - - this.room = room; - - this.localParticipant = { - local: true, - userId, - displayName: this.client.getUser(this.client.getUserId()).rawDisplayName, - sessionId: this.sessionId, - call: null, - stream, - audioMuted: this.audioMuted, - videoMuted: this.videoMuted, - speaking: false, - activeSpeaker: true, - }; - - this.activeSpeaker = this.localParticipant; - - this.participants.push(this.localParticipant); - this.emit("debugstate", userId, null, "you"); - - this.localCallFeed = new matrixcs.CallFeed( - stream, - this.localParticipant.userId, - "m.usermedia", - this.client, - this.room.roomId, - this.audioMuted, - this.videoMuted - ); - this.localCallFeed.on("mute_state_changed", () => - this._onCallFeedMuteStateChanged( - this.localParticipant, - this.localCallFeed - ) - ); - this.localCallFeed.setSpeakingThreshold(SPEAKING_THRESHOLD); - this.localCallFeed.measureVolumeActivity(true); - this.localCallFeed.on("speaking", (speaking) => { - this._onCallFeedSpeaking(this.localParticipant, speaking); - }); - this.localCallFeed.on("volume_changed", (maxVolume) => - this._onCallFeedVolumeChange(this.localParticipant, maxVolume) - ); - - // Announce to the other room members that we have entered the room. - // Continue doing so every PARTICIPANT_TIMEOUT ms - this._updateMemberParticipantState(); - - this.entered = true; - - // Answer any pending incoming calls. - const incomingCallCount = this._incomingCallQueue.length; - - for (let i = 0; i < incomingCallCount; i++) { - const call = this._incomingCallQueue.pop(); - this._onIncomingCall(call); - } - - // Set up participants for the members currently in the room. - // Other members will be picked up by the RoomState.members event. - const initialMembers = room.getMembers(); - - for (const member of initialMembers) { - this._onMemberChanged(member); - } - - this.emit("entered"); - this.emit("participants_changed"); - this._onActiveSpeakerLoop(); - } - - leaveCall() { - if (!this.entered) { - return; - } - - const userId = this.client.getUserId(); - const currentMemberState = this.room.currentState.getStateEvents( - "m.room.member", - userId - ); - - this._sendStateEventWithRetry( - this.room.roomId, - "m.room.member", - { - ...currentMemberState.getContent(), - [CONF_PARTICIPANT]: null, - }, - userId - ); - - for (const participant of this.participants) { - if (!participant.local && participant.call) { - participant.call.hangup("user_hangup", false); - } - } - - this.client.stopLocalMediaStream(); - this.localVideoStream = null; - this.localCallFeed.dispose(); - this.localCallFeed = null; - - this.room = null; - this.entered = false; - this._left = true; - this.participants = []; - this.localParticipant = null; - this.activeSpeaker = null; - this.audioMuted = false; - this.videoMuted = false; - clearTimeout(this._memberParticipantStateTimeout); - clearTimeout(this._activeSpeakerLoopTimeout); - this._speakerMap.clear(); - - this.emit("participants_changed"); - this.emit("left"); - } - - async getLocalVideoStream() { - if (this.localVideoStream) { - return this.localVideoStream; - } - - const stream = await this.client.getLocalVideoStream(); - - this.localVideoStream = stream; - - return stream; - } - - setAudioMuted(muted) { - this.audioMuted = muted; - - if (this.localCallFeed) { - this.localCallFeed.setAudioMuted(muted); - } - - const localStream = this.localVideoStream; - - if (localStream) { - for (const track of localStream.getTracks()) { - if (track.kind === "audio") { - track.enabled = !this.audioMuted; - } - } - } - - for (let participant of this.participants) { - const call = participant.call; - - if ( - call && - call.localUsermediaStream && - call.isMicrophoneMuted() !== this.audioMuted - ) { - call.setMicrophoneMuted(this.audioMuted); - } - } - - this.emit("participants_changed"); - } - - setVideoMuted(muted) { - this.videoMuted = muted; - - if (this.localCallFeed) { - this.localCallFeed.setVideoMuted(muted); - } - - const localStream = this.localVideoStream; - - if (localStream) { - for (const track of localStream.getTracks()) { - if (track.kind === "video") { - track.enabled = !this.videoMuted; - } - } - } - - for (let participant of this.participants) { - const call = participant.call; - - if ( - call && - call.localUsermediaStream && - call.isLocalVideoMuted() !== this.videoMuted - ) { - call.setLocalVideoMuted(this.videoMuted); - } - } - - this.emit("participants_changed"); - } - - logout() { - localStorage.removeItem("matrix-auth-store"); - } - - /** - * Call presence - */ - - _updateMemberParticipantState = () => { - const userId = this.client.getUserId(); - const currentMemberState = this.room.currentState.getStateEvents( - "m.room.member", - userId - ); - - this._sendStateEventWithRetry( - this.room.roomId, - "m.room.member", - { - ...currentMemberState.getContent(), - [CONF_PARTICIPANT]: { - sessionId: this.sessionId, - expiresAt: new Date().getTime() + PARTICIPANT_TIMEOUT * 2, - }, - }, - userId - ); - - const now = new Date().getTime(); - - for (const participant of this.participants) { - if (participant.local) { - continue; - } - - const memberStateEvent = this.room.currentState.getStateEvents( - "m.room.member", - participant.userId - ); - - const memberStateContent = memberStateEvent.getContent(); - - if ( - !memberStateContent || - !memberStateContent[CONF_PARTICIPANT] || - typeof memberStateContent[CONF_PARTICIPANT] !== "object" || - (memberStateContent[CONF_PARTICIPANT].expiresAt && - memberStateContent[CONF_PARTICIPANT].expiresAt < now) - ) { - this.emit("debugstate", participant.userId, null, "inactive"); - - if (participant.call) { - // NOTE: This should remove the participant on the next tick - // since matrix-js-sdk awaits a promise before firing user_hangup - participant.call.hangup("user_hangup", false); - } - } - } - - this._memberParticipantStateTimeout = setTimeout( - this._updateMemberParticipantState, - PARTICIPANT_TIMEOUT - ); - }; - - /** - * Call Setup - * - * There are two different paths for calls to be created: - * 1. Incoming calls triggered by the Call.incoming event. - * 2. Outgoing calls to the initial members of a room or new members - * as they are observed by the RoomState.members event. - */ - - _onIncomingCall = (call) => { - // If we haven't entered yet, add the call to a queue which we'll use later. - if (!this.entered) { - this._incomingCallQueue.push(call); - return; - } - - // The incoming calls may be for another room, which we will ignore. - if (call.roomId !== this.room.roomId) { - return; - } - - if (call.state !== "ringing") { - console.warn("Incoming call no longer in ringing state. Ignoring."); - return; - } - - // Get the remote video stream if it exists. - const remoteFeed = call.getRemoteFeeds()[0]; - const stream = remoteFeed && remoteFeed.stream; - const audioMuted = remoteFeed ? remoteFeed.isAudioMuted() : false; - const videoMuted = remoteFeed ? remoteFeed.isVideoMuted() : false; - - const userId = call.opponentMember.userId; - - const memberStateEvent = this.room.currentState.getStateEvents( - "m.room.member", - userId - ); - - const memberStateContent = memberStateEvent.getContent(); - - if (!memberStateContent || !memberStateContent[CONF_PARTICIPANT]) { - call.reject(); - return; - } - - const { sessionId } = memberStateContent[CONF_PARTICIPANT]; - - // Check if the user calling has an existing participant and use this call instead. - const existingParticipant = this.participants.find( - (p) => p.userId === userId - ); - - let participant; - - console.log(call.opponentMember); - - if (existingParticipant) { - participant = existingParticipant; - // This also fires the hangup event and triggers those side-effects - existingParticipant.call.hangup("replaced", false); - existingParticipant.call = call; - existingParticipant.stream = stream; - existingParticipant.audioMuted = audioMuted; - existingParticipant.videoMuted = videoMuted; - existingParticipant.speaking = false; - existingParticipant.activeSpeaker = false; - existingParticipant.sessionId = sessionId; - } else { - participant = { - local: false, - userId, - displayName: call.opponentMember.rawDisplayName, - sessionId, - call, - stream, - audioMuted, - videoMuted, - speaking: false, - activeSpeaker: false, - }; - this.participants.push(participant); - } - - if (remoteFeed) { - remoteFeed.on("mute_state_changed", () => - this._onCallFeedMuteStateChanged(participant, remoteFeed) - ); - remoteFeed.setSpeakingThreshold(SPEAKING_THRESHOLD); - remoteFeed.measureVolumeActivity(true); - remoteFeed.on("speaking", (speaking) => { - this._onCallFeedSpeaking(participant, speaking); - }); - remoteFeed.on("volume_changed", (maxVolume) => - this._onCallFeedVolumeChange(participant, maxVolume) - ); - } - - call.on("state", (state) => - this._onCallStateChanged(participant, call, state) - ); - call.on("feeds_changed", () => this._onCallFeedsChanged(participant, call)); - call.on("replaced", (newCall) => - this._onCallReplaced(participant, call, newCall) - ); - call.on("hangup", () => this._onCallHangup(participant, call)); - call.answer(); - - this.emit("call", call); - this.emit("participants_changed"); - }; - - _onRoomStateMembers = (_event, _state, member) => { - this._onMemberChanged(member); - }; - - _onMemberChanged = (member) => { - // Don't process new members until we've entered the conference call. - if (!this.entered) { - return; - } - - // The member events may be received for another room, which we will ignore. - if (member.roomId !== this.room.roomId) { - return; - } - - // Don't process your own member. - const localUserId = this.client.getUserId(); - - if (member.userId === localUserId) { - return; - } - - // Get the latest member participant state event. - const memberStateEvent = this.room.currentState.getStateEvents( - "m.room.member", - member.userId - ); - const memberStateContent = memberStateEvent.getContent(); - - if (!memberStateContent) { - return; - } - - const participantInfo = memberStateContent[CONF_PARTICIPANT]; - - if (!participantInfo || typeof participantInfo !== "object") { - return; - } - - const { expiresAt, sessionId } = participantInfo; - - // If the participant state has expired, ignore this user. - const now = new Date().getTime(); - - if (expiresAt < now) { - this.emit("debugstate", member.userId, null, "inactive"); - return; - } - - // If there is an existing participant for this member check the session id. - // If the session id changed then we can hang up the old call and start a new one. - // Otherwise, ignore the member change event because we already have an active participant. - let participant = this.participants.find((p) => p.userId === member.userId); - - if (participant) { - if (participant.sessionId !== sessionId) { - this.emit("debugstate", member.userId, null, "inactive"); - participant.call.hangup("replaced", false); - } else { - return; - } - } - - // Only initiate a call with a user who has a userId that is lexicographically - // less than your own. Otherwise, that user will call you. - if (member.userId < localUserId) { - this.emit("debugstate", member.userId, null, "waiting for invite"); - return; - } - - const call = this.client.createCall(this.room.roomId, member.userId); - - if (participant) { - participant.sessionId = sessionId; - participant.call = call; - participant.stream = null; - participant.audioMuted = false; - participant.videoMuted = false; - participant.speaking = false; - participant.activeSpeaker = false; - } else { - participant = { - local: false, - userId: member.userId, - displayName: member.rawDisplayName, - sessionId, - call, - stream: null, - audioMuted: false, - videoMuted: false, - speaking: false, - activeSpeaker: false, - }; - // TODO: Should we wait until the call has been answered to push the participant? - // Or do we hide the participant until their stream is live? - // Does hiding a participant without a stream present a privacy problem because - // a participant without a stream can still listen in on other user's streams? - this.participants.push(participant); - } - - call.on("state", (state) => - this._onCallStateChanged(participant, call, state) - ); - call.on("feeds_changed", () => this._onCallFeedsChanged(participant, call)); - call.on("replaced", (newCall) => - this._onCallReplaced(participant, call, newCall) - ); - call.on("hangup", () => this._onCallHangup(participant, call)); - - call.placeVideoCall().then(() => { - this.emit("call", call); - }); - - this.emit("participants_changed"); - }; - - /** - * Call Event Handlers - */ - - _onCallStateChanged = (participant, call, state) => { - if ( - call.localUsermediaStream && - call.isMicrophoneMuted() !== this.audioMuted - ) { - call.setMicrophoneMuted(this.audioMuted); - } - - if ( - call.localUsermediaStream && - call.isLocalVideoMuted() !== this.videoMuted - ) { - call.setLocalVideoMuted(this.videoMuted); - } - - this.emit("debugstate", participant.userId, call.callId, state); - }; - - _onCallFeedsChanged = (participant, call) => { - const remoteFeed = call.getRemoteFeeds()[0]; - const stream = remoteFeed && remoteFeed.stream; - const audioMuted = remoteFeed ? remoteFeed.isAudioMuted() : false; - const videoMuted = remoteFeed ? remoteFeed.isVideoMuted() : false; - - if (remoteFeed && participant.stream !== stream) { - participant.stream = stream; - participant.audioMuted = audioMuted; - participant.videoMuted = videoMuted; - remoteFeed.on("mute_state_changed", () => - this._onCallFeedMuteStateChanged(participant, remoteFeed) - ); - remoteFeed.setSpeakingThreshold(SPEAKING_THRESHOLD); - remoteFeed.measureVolumeActivity(true); - remoteFeed.on("speaking", (speaking) => { - this._onCallFeedSpeaking(participant, speaking); - }); - remoteFeed.on("volume_changed", (maxVolume) => - this._onCallFeedVolumeChange(participant, maxVolume) - ); - this._onCallFeedMuteStateChanged(participant, remoteFeed); - } - }; - - _onCallFeedMuteStateChanged = (participant, feed) => { - participant.audioMuted = feed.isAudioMuted(); - participant.videoMuted = feed.isVideoMuted(); - - if (participant.audioMuted) { - this._speakerMap.set( - participant.userId, - Array(ACTIVE_SPEAKER_SAMPLES).fill(-Infinity) - ); - } - - this.emit("participants_changed"); - }; - - _onCallFeedSpeaking = (participant, speaking) => { - participant.speaking = speaking; - this.emit("participants_changed"); - }; - - _onCallFeedVolumeChange = (participant, maxVolume) => { - if (!this._speakerMap.has(participant.userId)) { - this._speakerMap.set( - participant.userId, - Array(ACTIVE_SPEAKER_SAMPLES).fill(-Infinity) - ); - } - - const volumeArr = this._speakerMap.get(participant.userId); - volumeArr.shift(); - volumeArr.push(maxVolume); - }; - - _onActiveSpeakerLoop = () => { - let topAvg; - let activeSpeakerId; - - for (const [userId, volumeArr] of this._speakerMap) { - let total = 0; - - for (let i = 0; i < volumeArr.length; i++) { - const volume = volumeArr[i]; - total += Math.max(volume, SPEAKING_THRESHOLD); - } - - const avg = total / ACTIVE_SPEAKER_SAMPLES; - - if (!topAvg) { - topAvg = avg; - activeSpeakerId = userId; - } else if (avg > topAvg) { - topAvg = avg; - activeSpeakerId = userId; - } - } - - if (activeSpeakerId && topAvg > SPEAKING_THRESHOLD) { - const nextActiveSpeaker = this.participants.find( - (p) => p.userId === activeSpeakerId - ); - - if (nextActiveSpeaker && this.activeSpeaker !== nextActiveSpeaker) { - this.activeSpeaker.activeSpeaker = false; - nextActiveSpeaker.activeSpeaker = true; - this.activeSpeaker = nextActiveSpeaker; - this.emit("participants_changed"); - } - } - - this._activeSpeakerLoopTimeout = setTimeout( - this._onActiveSpeakerLoop, - ACTIVE_SPEAKER_INTERVAL - ); - }; - - _onCallReplaced = (participant, call, newCall) => { - participant.call = newCall; - - newCall.on("state", (state) => - this._onCallStateChanged(participant, newCall, state) - ); - newCall.on("feeds_changed", () => - this._onCallFeedsChanged(participant, newCall) - ); - newCall.on("replaced", (nextCall) => - this._onCallReplaced(participant, newCall, nextCall) - ); - newCall.on("hangup", () => this._onCallHangup(participant, newCall)); - - const remoteFeed = newCall.getRemoteFeeds()[0]; - participant.stream = remoteFeed ? remoteFeed.stream : null; - participant.audioMuted = remoteFeed ? remoteFeed.isAudioMuted() : false; - participant.videoMuted = remoteFeed ? remoteFeed.isVideoMuted() : false; - - if (remoteFeed) { - remoteFeed.on("mute_state_changed", () => - this._onCallFeedMuteStateChanged(participant, remoteFeed) - ); - remoteFeed.setSpeakingThreshold(SPEAKING_THRESHOLD); - remoteFeed.measureVolumeActivity(true); - remoteFeed.on("speaking", (speaking) => { - this._onCallFeedSpeaking(participant, speaking); - }); - remoteFeed.on("volume_changed", (maxVolume) => - this._onCallFeedVolumeChange(participant, maxVolume) - ); - } - - this.emit("call", newCall); - this.emit("participants_changed"); - }; - - _onCallHangup = (participant, call) => { - if (call.hangupReason === "replaced") { - return; - } - - const participantIndex = this.participants.indexOf(participant); - - if (participantIndex === -1) { - return; - } - - this.participants.splice(participantIndex, 1); - - if (this.activeSpeaker === participant && this.participants.length > 0) { - this.activeSpeaker = this.participants[0]; - this.activeSpeaker.activeSpeaker = true; - } - - this._speakerMap.delete(participant.userId); - - this.emit("participants_changed"); - }; - - /** - * Utils - */ - - _sendStateEventWithRetry( - roomId, - eventType, - content, - stateKey, - callback, - maxAttempts = 5 - ) { - const sendStateEventWithRetry = async (attempt = 0) => { - try { - return await this.client.sendStateEvent( - roomId, - eventType, - content, - stateKey, - callback - ); - } catch (error) { - if (attempt >= maxAttempts) { - throw error; - } - - await new Promise((resolve) => setTimeout(resolve(), 5)); - - return sendStateEventWithRetry(attempt + 1); - } - }; - - return sendStateEventWithRetry(); - } -} diff --git a/src/ConferenceCallManagerHooks.js b/src/ConferenceCallManagerHooks.js index e654747..87ed7b9 100644 --- a/src/ConferenceCallManagerHooks.js +++ b/src/ConferenceCallManagerHooks.js @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { useCallback, useEffect, useState } from "react"; -import { ConferenceCallManager } from "./ConferenceCallManager"; +import { useCallback, useEffect, useRef, useState } from "react"; +import matrix from "matrix-js-sdk"; // https://stackoverflow.com/a/9039885 function isIOS() { @@ -33,289 +33,230 @@ function isIOS() { ); } -export function useConferenceCallManager(homeserverUrl) { - const [{ loading, authenticated, manager, error }, setState] = useState({ +function waitForSync(client) { + return new Promise((resolve, reject) => { + const onSync = (state) => { + if (state === "PREPARED") { + resolve(); + client.removeListener("sync", onSync); + } + }; + client.on("sync", onSync); + }); +} + +async function initClient(clientOptions, guest) { + const client = matrix.createClient(clientOptions); + + if (guest) { + client.setGuest(true); + } + + await client.startClient({ + // dirty hack to reduce chance of gappy syncs + // should be fixed by spotting gaps and backpaginating + initialSyncLimit: 50, + }); + + await waitForSync(client); + + return client; +} + +export async function fetchRoom(client, roomId, join, timeout = 5000) { + let room = client.getRoom(roomId); + + if (room) { + return room; + } + + if (join) { + room = await client.joinRoom(roomId); + + if (room) { + return room; + } + } + + return new Promise((resolve, reject) => { + let timeoutId; + + function onRoom(room) { + if (room && room.roomId === roomId) { + clearTimeout(timeoutId); + client.removeListener("Room", onRoom); + resolve(room); + } + } + + const room = client.getRoom(roomId); + + if (room) { + resolve(room); + } + + client.on("Room", onRoom); + + if (timeout) { + timeoutId = setTimeout(() => { + client.removeListener("Room", onRoom); + reject(new Error("Fetching room timed out.")); + }, timeout); + } + }); +} + +export function useClient(homeserverUrl) { + const [{ loading, authenticated, client }, setState] = useState({ loading: true, authenticated: false, - manager: undefined, - error: undefined, + client: undefined, }); useEffect(() => { - ConferenceCallManager.restore(homeserverUrl) - .then((manager) => { - setState({ - manager, - loading: false, - authenticated: !!manager, - error: undefined, - }); - }) - .catch((err) => { - console.error(err); + async function restore() { + try { + const authStore = localStorage.getItem("matrix-auth-store"); - setState({ - manager: undefined, - loading: false, - authenticated: false, - error: err, - }); - }); - }, []); + if (authStore) { + const { user_id, device_id, access_token } = JSON.parse(authStore); - const login = useCallback(async (username, password, cb) => { - setState((prevState) => ({ - ...prevState, - authenticated: false, - error: undefined, - })); + const client = await initClient({ + baseUrl: homeserverUrl, + accessToken: access_token, + userId: user_id, + deviceId: device_id, + }); - ConferenceCallManager.login(homeserverUrl, username, password) - .then((manager) => { - setState({ - manager, - loading: false, - authenticated: true, - error: undefined, - }); + localStorage.setItem( + "matrix-auth-store", + JSON.stringify({ user_id, device_id, access_token }) + ); - if (cb) { - cb(); + return client; + } + } catch (err) { + localStorage.removeItem("matrix-auth-store"); + throw err; + } + } + + restore() + .then((client) => { + if (client) { + setState({ client, loading: false, authenticated: true }); + } else { + setState({ client: undefined, loading: false, authenticated: false }); } }) - .catch((err) => { - console.error(err); - - setState({ - manager: undefined, - loading: false, - authenticated: false, - error: err, - }); + .catch(() => { + setState({ client: undefined, loading: false, authenticated: false }); }); }, []); - const loginAsGuest = useCallback(async (displayName) => { - setState((prevState) => ({ - ...prevState, - authenticated: false, - error: undefined, - })); + const login = useCallback(async (username, password) => { + try { + const registrationClient = matrix.createClient(homeserverUrl); - ConferenceCallManager.loginAsGuest(homeserverUrl, displayName) - .then((manager) => { - setState({ - manager, - loading: false, - authenticated: true, - error: undefined, - }); - }) - .catch((err) => { - console.error(err); + const { user_id, device_id, access_token } = + await registrationClient.loginWithPassword(username, password); - setState({ - manager: undefined, - loading: false, - authenticated: false, - error: err, - }); + const client = await initClient({ + baseUrl: homeserverUrl, + accessToken: access_token, + userId: user_id, + deviceId: device_id, }); + + localStorage.setItem( + "matrix-auth-store", + JSON.stringify({ user_id, device_id, access_token }) + ); + + setState({ client, loading: false, authenticated: true }); + } catch (err) { + localStorage.removeItem("matrix-auth-store"); + setState({ client: undefined, loading: false, authenticated: false }); + throw err; + } }, []); - const register = useCallback(async (username, password, cb) => { - setState((prevState) => ({ - ...prevState, - authenticated: false, - error: undefined, - })); + const registerGuest = useCallback(async (displayName) => { + try { + const registrationClient = matrix.createClient(homeserverUrl); - ConferenceCallManager.register(homeserverUrl, username, password) - .then((manager) => { - setState({ - manager, - loading: false, - authenticated: true, - error: undefined, - }); + const { user_id, device_id, access_token } = + await registrationClient.registerGuest({}); - if (cb) { - cb(); - } - }) - .catch((err) => { - console.error(err); + const client = await initClient( + { + baseUrl: homeserverUrl, + accessToken: access_token, + userId: user_id, + deviceId: device_id, + }, + true + ); - setState({ - manager: undefined, - loading: false, - authenticated: false, - error: err, - }); - }); + localStorage.setItem( + "matrix-auth-store", + JSON.stringify({ user_id, device_id, access_token }) + ); + + setState({ client, loading: false, authenticated: true }); + } catch (err) { + localStorage.removeItem("matrix-auth-store"); + setState({ client: undefined, loading: false, authenticated: false }); + throw err; + } }, []); - useEffect(() => { - window.confManager = manager; + const register = useCallback(async (username, password) => { + try { + const registrationClient = matrix.createClient(homeserverUrl); - return () => { - window.confManager = undefined; - }; - }, [manager]); + const { user_id, device_id, access_token } = + await registrationClient.register(username, password, null, { + type: "m.login.dummy", + }); + + const client = await initClient({ + baseUrl: homeserverUrl, + accessToken: access_token, + userId: user_id, + deviceId: device_id, + }); + + localStorage.setItem( + "matrix-auth-store", + JSON.stringify({ user_id, device_id, access_token }) + ); + + setState({ client, loading: false, authenticated: true }); + } catch (err) { + localStorage.removeItem("matrix-auth-store"); + setState({ client: undefined, loading: false, authenticated: false }); + throw err; + } + }, []); + + const logout = useCallback(() => { + localStorage.removeItem("matrix-auth-store"); + setState({ client: undefined, loading: false, authenticated: false }); + }, []); return { loading, authenticated, - manager, - error, + client, login, - loginAsGuest, + registerGuest, register, + logout, }; } -export function useVideoRoom(manager, roomId, timeout = 5000) { - const [ - { - loading, - joined, - joining, - room, - participants, - error, - videoMuted, - audioMuted, - }, - setState, - ] = useState({ - loading: true, - joining: false, - joined: false, - room: undefined, - participants: [], - error: undefined, - videoMuted: false, - audioMuted: false, - }); - - useEffect(() => { - setState((prevState) => ({ - ...prevState, - loading: true, - room: undefined, - error: undefined, - })); - - const onParticipantsChanged = () => { - setState((prevState) => ({ - ...prevState, - participants: [...manager.participants], - })); - }; - - manager.on("participants_changed", onParticipantsChanged); - - manager.client.joinRoom(roomId).catch((err) => { - setState((prevState) => ({ ...prevState, loading: false, error: err })); - }); - - let timeoutId; - - function roomCallback(room) { - if (room && room.roomId === roomId) { - clearTimeout(timeoutId); - manager.client.removeListener("Room", roomCallback); - setState((prevState) => ({ - ...prevState, - loading: false, - room, - error: undefined, - })); - } - } - - let initialRoom = manager.client.getRoom(roomId); - - if (initialRoom) { - setState((prevState) => ({ - ...prevState, - loading: false, - room: initialRoom, - error: undefined, - })); - } else { - manager.client.on("Room", roomCallback); - - timeoutId = setTimeout(() => { - setState((prevState) => ({ - ...prevState, - loading: false, - room: undefined, - error: new Error("Room could not be found."), - })); - manager.client.removeListener("Room", roomCallback); - }, timeout); - } - - function onLeaveCall() { - setState((prevState) => ({ - ...prevState, - videoMuted: manager.videoMuted, - audioMuted: manager.audioMuted, - })); - } - - manager.on("left", onLeaveCall); - - return () => { - manager.client.removeListener("Room", roomCallback); - manager.removeListener("participants_changed", onParticipantsChanged); - clearTimeout(timeoutId); - manager.leaveCall(); - manager.removeListener("left", onLeaveCall); - }; - }, [manager, roomId]); - - const joinCall = useCallback(() => { - if (joining || joined) { - return; - } - - setState((prevState) => ({ - ...prevState, - joining: true, - })); - - manager - .enter(roomId) - .then(() => { - setState((prevState) => ({ - ...prevState, - joining: false, - joined: true, - })); - }) - .catch((error) => { - setState((prevState) => ({ - ...prevState, - joining: false, - joined: false, - error, - })); - }); - }, [manager, roomId, joining, joined]); - - const leaveCall = useCallback(() => { - manager.leaveCall(); - - setState((prevState) => ({ - ...prevState, - participants: [...manager.participants], - joined: false, - joining: false, - })); - }, [manager]); - +function usePageUnload(callback) { useEffect(() => { let pageVisibilityTimeout; @@ -327,25 +268,11 @@ export function useVideoRoom(manager, roomId, timeout = 5000) { // Wait 5 seconds before closing the page to avoid accidentally leaving // TODO: Make this configurable? pageVisibilityTimeout = setTimeout(() => { - manager.leaveCall(); - - setState((prevState) => ({ - ...prevState, - participants: [...manager.participants], - joined: false, - joining: false, - })); + callback(); }, 5000); } } else { - manager.leaveCall(); - - setState((prevState) => ({ - ...prevState, - participants: [...manager.participants], - joined: false, - joining: false, - })); + callback(); } } @@ -363,31 +290,174 @@ export function useVideoRoom(manager, roomId, timeout = 5000) { window.removeEventListener("beforeunload", onBeforeUnload); clearTimeout(pageVisibilityTimeout); }; - }, [manager]); + }, []); +} - const toggleMuteAudio = useCallback(() => { - manager.setAudioMuted(!manager.audioMuted); - setState((prevState) => ({ ...prevState, audioMuted: manager.audioMuted })); - }, [manager]); +function getParticipants(groupCall) { + return [...groupCall.participants]; +} - const toggleMuteVideo = useCallback(() => { - manager.setVideoMuted(!manager.videoMuted); - setState((prevState) => ({ ...prevState, videoMuted: manager.videoMuted })); - }, [manager]); +export function useGroupCall(client, roomId) { + const groupCallRef = useRef(null); + + const [ + { + loading, + entered, + entering, + room, + participants, + error, + microphoneMuted, + localVideoMuted, + }, + setState, + ] = useState({ + loading: true, + entered: false, + entering: false, + room: null, + participants: [], + error: null, + microphoneMuted: false, + localVideoMuted: false, + }); + + const updateState = (state) => + setState((prevState) => ({ ...prevState, ...state })); + + useEffect(() => { + function onParticipantsChanged(...args) { + console.log(...args); + updateState({ participants: getParticipants(groupCallRef.current) }); + } + + function onLocalMuteStateChanged(microphoneMuted, localVideoMuted) { + updateState({ + microphoneMuted, + localVideoMuted, + }); + } + + async function init() { + const room = await fetchRoom(client, roomId, true); + + const groupCall = client.createGroupCall(roomId, "video"); + groupCallRef.current = groupCall; + groupCall.on("active_speaker_changed", onParticipantsChanged); + groupCall.on("participants_changed", onParticipantsChanged); + groupCall.on("speaking", onParticipantsChanged); + groupCall.on("mute_state_changed", onParticipantsChanged); + groupCall.on("participant_call_replaced", onParticipantsChanged); + groupCall.on("participant_call_feeds_changed", onParticipantsChanged); + groupCall.on("local_mute_state_changed", onLocalMuteStateChanged); + + updateState({ + room, + loading: false, + }); + } + + init().catch((error) => { + if (groupCallRef.current) { + const groupCall = groupCallRef.current; + groupCall.removeListener( + "active_speaker_changed", + onParticipantsChanged + ); + groupCall.removeListener("participants_changed", onParticipantsChanged); + groupCall.removeListener("speaking", onParticipantsChanged); + groupCall.removeListener("mute_state_changed", onParticipantsChanged); + groupCall.removeListener( + "participant_call_replaced", + onParticipantsChanged + ); + groupCall.removeListener( + "participant_call_feeds_changed", + onParticipantsChanged + ); + groupCall.removeListener( + "local_mute_state_changed", + onLocalMuteStateChanged + ); + groupCall.leave(); + } + + updateState({ error, loading: false }); + }); + + return () => { + if (groupCallRef.current) { + groupCallRef.current.leave(); + } + }; + }, [client, roomId]); + + usePageUnload(() => { + if (groupCallRef.current) { + groupCallRef.current.leave(); + } + }); + + const initLocalParticipant = useCallback( + () => groupCallRef.current.initLocalParticipant(), + [] + ); + + const enter = useCallback(() => { + updateState({ entering: true }); + + groupCallRef.current + .enter() + .then(() => { + updateState({ + entered: true, + entering: false, + participants: getParticipants(groupCallRef.current), + }); + }) + .catch((error) => { + updateState({ error, entering: false }); + }); + }, []); + + const leave = useCallback(() => { + groupCallRef.current.leave(); + updateState({ + entered: false, + participants: [], + microphoneMuted: false, + localVideoMuted: false, + }); + }, []); + + const toggleLocalVideoMuted = useCallback(() => { + groupCallRef.current.setLocalVideoMuted( + !groupCallRef.current.isLocalVideoMuted() + ); + }, []); + + const toggleMicrophoneMuted = useCallback(() => { + groupCallRef.current.setMicrophoneMuted( + !groupCallRef.current.isMicrophoneMuted() + ); + }, []); return { loading, - joined, - joining, - room, + entered, + entering, + roomName: room ? room.name : null, participants, + groupCall: groupCallRef.current, + microphoneMuted, + localVideoMuted, error, - joinCall, - leaveCall, - toggleMuteVideo, - toggleMuteAudio, - videoMuted, - audioMuted, + initLocalParticipant, + enter, + leave, + toggleLocalVideoMuted, + toggleMicrophoneMuted, }; } @@ -440,22 +510,22 @@ function sortRooms(client, rooms) { }); } -export function useRooms(manager) { +export function useRooms(client) { const [rooms, setRooms] = useState([]); useEffect(() => { function updateRooms() { - const visibleRooms = manager.client.getVisibleRooms(); - const sortedRooms = sortRooms(manager.client, visibleRooms); + const visibleRooms = client.getVisibleRooms(); + const sortedRooms = sortRooms(client, visibleRooms); setRooms(sortedRooms); } updateRooms(); - manager.client.on("Room", updateRooms); + client.on("Room", updateRooms); return () => { - manager.client.removeListener("Room", updateRooms); + client.removeListener("Room", updateRooms); }; }, []); diff --git a/src/GuestAuthPage.jsx b/src/GuestAuthPage.jsx new file mode 100644 index 0000000..94b1621 --- /dev/null +++ b/src/GuestAuthPage.jsx @@ -0,0 +1,91 @@ +/* +Copyright 2021 New Vector Ltd + +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. +*/ + +import React, { useState, useRef, useCallback } from "react"; +import styles from "./GuestAuthPage.module.css"; +import { useLocation, useHistory, Link } from "react-router-dom"; +import { Header, LeftNav } from "./Header"; +import { Button, FieldRow, InputField, ErrorMessage } from "./Input"; +import { Center, Content, Info, Modal } from "./Layout"; + +export function GuestAuthPage({ onLoginAsGuest }) { + const displayNameRef = useRef(); + const history = useHistory(); + const location = useLocation(); + const [error, setError] = useState(); + + const onSubmitLoginForm = useCallback( + (e) => { + e.preventDefault(); + onLoginAsGuest(displayNameRef.current.value).catch(setError); + }, + [onLoginAsGuest, location, history] + ); + + return ( +
+
+ +
+ +
+ +

Login As Guest

+
+ + + + {error && ( + + {error.message} + + )} + + + +
+ + + Sign in + + {" or "} + + Create account + + +
+
+
+
+ ); +} diff --git a/src/GuestAuthPage.module.css b/src/GuestAuthPage.module.css new file mode 100644 index 0000000..9da730f --- /dev/null +++ b/src/GuestAuthPage.module.css @@ -0,0 +1,8 @@ +.guestAuthPage { + position: relative; + display: flex; + flex-direction: column; + width: 100vw; + height: 100vh; + overflow: hidden; +} \ No newline at end of file diff --git a/src/Home.jsx b/src/Home.jsx index 5ced0f5..4619b27 100644 --- a/src/Home.jsx +++ b/src/Home.jsx @@ -25,12 +25,12 @@ import { Center, Content, Modal } from "./Layout"; const colorHash = new ColorHash({ lightness: 0.3 }); -export function Home({ manager }) { +export function Home({ client, onLogout }) { const history = useHistory(); const roomNameRef = useRef(); const guestAccessRef = useRef(); const [createRoomError, setCreateRoomError] = useState(); - const rooms = useRooms(manager); + const rooms = useRooms(client); const onCreateRoom = useCallback( (e) => { @@ -38,7 +38,7 @@ export function Home({ manager }) { setCreateRoomError(undefined); async function createRoom(name, guestAccess) { - const { room_id } = await manager.client.createRoom({ + const { room_id } = await client.createRoom({ visibility: "private", preset: "public_chat", name, @@ -62,14 +62,14 @@ export function Home({ manager }) { "m.sticker": 50, }, users: { - [manager.client.getUserId()]: 100, + [client.getUserId()]: 100, }, } : undefined, }); if (guestAccess) { - await manager.client.setGuestAccess(room_id, { + await client.setGuestAccess(room_id, { allowJoin: true, allowRead: true, }); @@ -83,27 +83,14 @@ export function Home({ manager }) { guestAccessRef.current.checked ).catch(setCreateRoomError); }, - [manager] - ); - - const onLogout = useCallback( - (e) => { - e.preventDefault(); - manager.logout(); - location.reload(); - }, - [manager] + [client] ); return ( <>
- +
diff --git a/src/LoginPage.jsx b/src/LoginPage.jsx index da54eab..089aecb 100644 --- a/src/LoginPage.jsx +++ b/src/LoginPage.jsx @@ -20,26 +20,25 @@ import { Header, LeftNav } from "./Header"; import { FieldRow, InputField, Button, ErrorMessage } from "./Input"; import { Center, Content, Info, Modal } from "./Layout"; -export function LoginPage({ onLogin, error }) { +export function LoginPage({ onLogin }) { const loginUsernameRef = useRef(); const loginPasswordRef = useRef(); const history = useHistory(); const location = useLocation(); + const [error, setError] = useState(); const onSubmitLoginForm = useCallback( (e) => { e.preventDefault(); - onLogin( - loginUsernameRef.current.value, - loginPasswordRef.current.value, - () => { + onLogin(loginUsernameRef.current.value, loginPasswordRef.current.value) + .then(() => { if (location.state && location.state.from) { history.replace(location.state.from); } else { history.replace("/"); } - } - ); + }) + .catch(setError); }, [onLogin, location, history] ); diff --git a/src/RegisterPage.jsx b/src/RegisterPage.jsx index f12ed68..1802b0e 100644 --- a/src/RegisterPage.jsx +++ b/src/RegisterPage.jsx @@ -14,32 +14,34 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { useCallback, useRef } from "react"; +import React, { useCallback, useRef, useState } from "react"; import { useHistory, useLocation, Link } from "react-router-dom"; import { Header, LeftNav } from "./Header"; import { FieldRow, InputField, Button, ErrorMessage } from "./Input"; import { Center, Content, Info, Modal } from "./Layout"; -export function RegisterPage({ onRegister, error }) { +export function RegisterPage({ onRegister }) { const registerUsernameRef = useRef(); const registerPasswordRef = useRef(); const history = useHistory(); const location = useLocation(); + const [error, setError] = useState(); const onSubmitRegisterForm = useCallback( (e) => { e.preventDefault(); onRegister( registerUsernameRef.current.value, - registerPasswordRef.current.value, - () => { + registerPasswordRef.current.value + ) + .then(() => { if (location.state && location.state.from) { history.replace(location.state.from); } else { history.replace("/"); } - } - ); + }) + .catch(setError); }, [onRegister, location, history] ); diff --git a/src/Room.jsx b/src/Room.jsx index e6b295a..aeb9abc 100644 --- a/src/Room.jsx +++ b/src/Room.jsx @@ -23,7 +23,7 @@ import React, { } from "react"; import styles from "./Room.module.css"; import { useParams, useLocation, useHistory, Link } from "react-router-dom"; -import { useVideoRoom } from "./ConferenceCallManagerHooks"; +import { useGroupCall } from "./ConferenceCallManagerHooks"; import { DevTools } from "./DevTools"; import { VideoGrid } from "./VideoGrid"; import { @@ -42,25 +42,16 @@ function useQuery() { return useMemo(() => new URLSearchParams(location.search), [location.search]); } -export function Room({ manager }) { - const { roomId } = useParams(); +function useDebugMode() { const query = useQuery(); - const { - loading, - joined, - joining, - room, - participants, - error, - joinCall, - leaveCall, - toggleMuteVideo, - toggleMuteAudio, - videoMuted, - audioMuted, - } = useVideoRoom(manager, roomId); const debugStr = query.get("debug"); - const [debug, setDebug] = useState(debugStr === "" || debugStr === "true"); + const [debugMode, setDebugMode] = useState( + debugStr === "" || debugStr === "true" + ); + + const toggleDebugMode = useCallback(() => { + setDebugMode((prevDebugMode) => !prevDebugMode); + }, []); useEffect(() => { function onKeyDown(event) { @@ -68,7 +59,7 @@ export function Room({ manager }) { document.activeElement.tagName !== "input" && event.code === "Backquote" ) { - setDebug((prevDebug) => !prevDebug); + toggleDebugMode(); } } @@ -79,190 +70,237 @@ export function Room({ manager }) { }; }, []); + return [debugMode, toggleDebugMode]; +} + +function useRoomLayout() { const [layout, setLayout] = useState("gallery"); const toggleLayout = useCallback(() => { setLayout(layout === "spotlight" ? "gallery" : "spotlight"); }, [layout]); - return ( -
- {!loading && room && ( -
- - -

{room.name}

-
- - {!loading && room && joined && ( - - )} - setDebug((debug) => !debug)} - /> - -
- )} - {loading && ( -
-

Loading room...

-
- )} - {error &&
{error.message}
} - {!loading && room && !joined && ( - { + if (error) { + return ; + } + + if (loading) { + return ; + } + + if (entering) { + return ; + } + + if (!entered) { + return ( + - )} - {!loading && room && joined && participants.length === 0 && ( -
-

Waiting for other participants...

-
- )} - {!loading && room && joined && participants.length > 0 && ( - - )} - {!loading && room && joined && ( -
- - - -
- )} - {debug && } -
+ ); + } else { + return ( + + ); + } + }; + + return
{content()}
; +} + +export function LoadingRoomView() { + return ( + <> +
+

Loading room...

+
+ ); } -export function RoomAuth({ onLoginAsGuest, error }) { - const displayNameRef = useRef(); - const history = useHistory(); - const location = useLocation(); - - const onSubmitLoginForm = useCallback( - (e) => { - e.preventDefault(); - onLoginAsGuest(displayNameRef.current.value); - }, - [onLoginAsGuest, location, history] +export function EnteringRoomView() { + return ( + <> +
+

Entering room...

+
+ ); +} + +export function LoadingErrorView({ error }) { + return ( + <> +
+ {error.message} +
+ + ); +} + +const PermissionState = { + Waiting: "waiting", + Granted: "granted", + Denied: "denied", +}; + +function RoomSetupView({ + roomName, + onInitLocalParticipant, + onEnter, + microphoneMuted, + localVideoMuted, + toggleLocalVideoMuted, + toggleMicrophoneMuted, + groupCall, +}) { + const videoRef = useRef(); + const [permissionState, setPermissionState] = useState( + PermissionState.Waiting + ); + + useEffect(() => { + onInitLocalParticipant() + .then((localParticipant) => { + if (videoRef.current) { + videoRef.current.srcObject = localParticipant.usermediaStream; + videoRef.current.play(); + setPermissionState(PermissionState.Granted); + } + }) + .catch(() => { + if (videoRef.current) { + setPermissionState(PermissionState.Denied); + } + }); + }, [onInitLocalParticipant]); return ( <>
+ +

{roomName}

+
- -
- -

Login As Guest

-
- - - - {error && ( - - {error.message} - - )} - - - -
- - - Sign in - - {" or "} - - Create account - - -
-
-
+
+
+ {permissionState === PermissionState.Denied && ( +

+ Webcam permissions needed to join the call. +

+ )} +
+ {permissionState === PermissionState.Granted && ( +
+ + +
+ )} + +
); } -function JoinRoom({ - joining, - joinCall, - manager, - toggleMuteVideo, - toggleMuteAudio, - videoMuted, - audioMuted, +function InRoomView({ + roomName, + microphoneMuted, + localVideoMuted, + toggleLocalVideoMuted, + toggleMicrophoneMuted, + participants, + onLeave, + groupCall, }) { - const videoRef = useRef(); - const [hasPermissions, setHasPermissions] = useState(false); - const [needsPermissions, setNeedsPermissions] = useState(false); - - useEffect(() => { - manager - .getLocalVideoStream() - .then((stream) => { - if (videoRef.current) { - videoRef.current.srcObject = stream; - videoRef.current.play(); - setHasPermissions(true); - } - }) - .catch(() => { - if (videoRef.current) { - setNeedsPermissions(true); - } - }); - }, [manager]); + const [debugMode, toggleDebugMode] = useDebugMode(); + const [roomLayout, toggleRoomLayout] = useRoomLayout(); return ( -
-
- {needsPermissions && ( -

- Webcam permissions needed to join the call. -

- )} -
- {hasPermissions && ( -
- - + <> +
+ + +

{roomName}

+
+ + + + +
+ {participants.length === 0 ? ( +
+

Waiting for other participants...

+ ) : ( + )} - -
+
+ + + +
+ {debugMode && } + ); } diff --git a/src/VideoGrid.jsx b/src/VideoGrid.jsx index b552ea7..836ce0d 100644 --- a/src/VideoGrid.jsx +++ b/src/VideoGrid.jsx @@ -422,7 +422,7 @@ export function VideoGrid({ participants, layout }) { for (const tile of tiles) { let participant = participants.find( - (participant) => participant.userId === tile.key + (participant) => participant.member.userId === tile.key ); let remove = false; @@ -442,7 +442,7 @@ export function VideoGrid({ participants, layout }) { } newTiles.push({ - key: participant.userId, + key: participant.member.userId, participant, remove, presenter, @@ -450,13 +450,13 @@ export function VideoGrid({ participants, layout }) { } for (const participant of participants) { - if (newTiles.some(({ key }) => participant.userId === key)) { + if (newTiles.some(({ key }) => participant.member.userId === key)) { continue; } // Added tiles newTiles.push({ - key: participant.userId, + key: participant.member.userId, participant, remove: false, presenter: layout === "spotlight" && participant.activeSpeaker, @@ -719,17 +719,19 @@ function ParticipantTile({ style, participant, remove, presenter, ...rest }) { const videoRef = useRef(); useEffect(() => { - if (participant.stream) { - if (participant.local) { + if (participant.usermediaStream) { + // Mute the local video + // TODO: Should GroupCallParticipant have a local field? + if (!participant.call) { videoRef.current.muted = true; } - videoRef.current.srcObject = participant.stream; + videoRef.current.srcObject = participant.usermediaStream; videoRef.current.play(); } else { videoRef.current.srcObject = null; } - }, [participant.stream]); + }, [participant.usermediaStream]); // Firefox doesn't respect the disablePictureInPicture attribute // https://bugzilla.mozilla.org/show_bug.cgi?id=1611831 @@ -738,15 +740,15 @@ function ParticipantTile({ style, participant, remove, presenter, ...rest }) {
- {participant.speaking ? ( + {participant.usermediaStream?.speaking ? ( - ) : participant.audioMuted ? ( + ) : participant.isAudioMuted() ? ( ) : null} - {participant.displayName} + {participant.member.rawDisplayName}
{participant.videoMuted && (