full integration
This commit is contained in:
parent
8da838e893
commit
d8e993842a
308
package-lock.json
generated
308
package-lock.json
generated
@ -20,6 +20,7 @@
|
||||
"decentraland-ui": "^4.0.0",
|
||||
"ethers": "^6.6.5",
|
||||
"livekit-client": "^1.12.3",
|
||||
"livekit-server-sdk": "^1.2.5",
|
||||
"p-queue": "^6.6.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
@ -7256,6 +7257,11 @@
|
||||
"resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
|
||||
"integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg=="
|
||||
},
|
||||
"node_modules/buffer-equal-constant-time": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
|
||||
},
|
||||
"node_modules/buffer-fill": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
|
||||
@ -7366,6 +7372,45 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/camelcase-keys": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-7.0.2.tgz",
|
||||
"integrity": "sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==",
|
||||
"dependencies": {
|
||||
"camelcase": "^6.3.0",
|
||||
"map-obj": "^4.1.0",
|
||||
"quick-lru": "^5.1.1",
|
||||
"type-fest": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/camelcase-keys/node_modules/camelcase": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
|
||||
"integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/camelcase-keys/node_modules/type-fest": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz",
|
||||
"integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001514",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001514.tgz",
|
||||
@ -8692,6 +8737,14 @@
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ecdsa-sig-formatter": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
@ -14179,6 +14232,21 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonwebtoken": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz",
|
||||
"integrity": "sha512-K8wx7eJ5TPvEjuiVSkv167EVboBDv9PZdDoF7BgeQnBLVvZWW9clr2PsQHVJDTKaEIH5JBIwHujGcHp7GgI2eg==",
|
||||
"dependencies": {
|
||||
"jws": "^3.2.2",
|
||||
"lodash": "^4.17.21",
|
||||
"ms": "^2.1.1",
|
||||
"semver": "^7.3.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12",
|
||||
"npm": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/jsprim": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
|
||||
@ -14193,6 +14261,25 @@
|
||||
"node": ">=0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jwa": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
|
||||
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
|
||||
"dependencies": {
|
||||
"buffer-equal-constant-time": "1.0.1",
|
||||
"ecdsa-sig-formatter": "1.0.11",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/jws": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
|
||||
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
|
||||
"dependencies": {
|
||||
"jwa": "^1.4.1",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/keccak": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.3.tgz",
|
||||
@ -14417,6 +14504,73 @@
|
||||
"webrtc-adapter": "^8.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/livekit-server-sdk": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/livekit-server-sdk/-/livekit-server-sdk-1.2.5.tgz",
|
||||
"integrity": "sha512-QYHGEoilSAXUQQBAZE2SXU1oXW8z08VFp2UxcZzXdPt3u4E9xamghTMhgniLMWmpSCl7oqVObQ6XXnK9rkr0Pg==",
|
||||
"dependencies": {
|
||||
"axios": "^1.3.6",
|
||||
"camelcase-keys": "^7.0.0",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"protobufjs": "^7.2.4"
|
||||
}
|
||||
},
|
||||
"node_modules/livekit-server-sdk/node_modules/@types/node": {
|
||||
"version": "20.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.7.tgz",
|
||||
"integrity": "sha512-bUBrPjEry2QUTsnuEjzjbS7voGWCc30W0qzgMf90GPeDGFRakvrz47ju+oqDAKCXLUCe39u57/ORMl/O/04/9g=="
|
||||
},
|
||||
"node_modules/livekit-server-sdk/node_modules/axios": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz",
|
||||
"integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.0",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/livekit-server-sdk/node_modules/form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/livekit-server-sdk/node_modules/long": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
|
||||
"integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
|
||||
},
|
||||
"node_modules/livekit-server-sdk/node_modules/protobufjs": {
|
||||
"version": "7.2.4",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.4.tgz",
|
||||
"integrity": "sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@protobufjs/aspromise": "^1.1.2",
|
||||
"@protobufjs/base64": "^1.1.2",
|
||||
"@protobufjs/codegen": "^2.0.4",
|
||||
"@protobufjs/eventemitter": "^1.1.0",
|
||||
"@protobufjs/fetch": "^1.1.0",
|
||||
"@protobufjs/float": "^1.0.2",
|
||||
"@protobufjs/inquire": "^1.1.0",
|
||||
"@protobufjs/path": "^1.1.2",
|
||||
"@protobufjs/pool": "^1.1.0",
|
||||
"@protobufjs/utf8": "^1.1.0",
|
||||
"@types/node": ">=13.7.0",
|
||||
"long": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/locate-path": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||
@ -14608,6 +14762,17 @@
|
||||
"tmpl": "1.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/map-obj": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
|
||||
"integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/matchmediaquery": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/matchmediaquery/-/matchmediaquery-0.3.1.tgz",
|
||||
@ -16017,6 +16182,11 @@
|
||||
"resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.5.1.tgz",
|
||||
"integrity": "sha512-oyfc0Tx87Cpwva5ZXezSp5V9vht1c7dZBhvuV/y3ctkgMVUmiAGDVeeB0dKhGSyT0v1ZTEQYpe/RXlBVBNuCLA=="
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"node_modules/prr": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
|
||||
@ -25071,6 +25241,11 @@
|
||||
"resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
|
||||
"integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg=="
|
||||
},
|
||||
"buffer-equal-constant-time": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
|
||||
},
|
||||
"buffer-fill": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
|
||||
@ -25153,6 +25328,29 @@
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
|
||||
},
|
||||
"camelcase-keys": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-7.0.2.tgz",
|
||||
"integrity": "sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==",
|
||||
"requires": {
|
||||
"camelcase": "^6.3.0",
|
||||
"map-obj": "^4.1.0",
|
||||
"quick-lru": "^5.1.1",
|
||||
"type-fest": "^1.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"camelcase": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
|
||||
"integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="
|
||||
},
|
||||
"type-fest": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz",
|
||||
"integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001514",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001514.tgz",
|
||||
@ -26172,6 +26370,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"ecdsa-sig-formatter": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
||||
"requires": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
@ -30320,6 +30526,17 @@
|
||||
"through": ">=2.2.7 <3"
|
||||
}
|
||||
},
|
||||
"jsonwebtoken": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz",
|
||||
"integrity": "sha512-K8wx7eJ5TPvEjuiVSkv167EVboBDv9PZdDoF7BgeQnBLVvZWW9clr2PsQHVJDTKaEIH5JBIwHujGcHp7GgI2eg==",
|
||||
"requires": {
|
||||
"jws": "^3.2.2",
|
||||
"lodash": "^4.17.21",
|
||||
"ms": "^2.1.1",
|
||||
"semver": "^7.3.8"
|
||||
}
|
||||
},
|
||||
"jsprim": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
|
||||
@ -30331,6 +30548,25 @@
|
||||
"verror": "1.10.0"
|
||||
}
|
||||
},
|
||||
"jwa": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
|
||||
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
|
||||
"requires": {
|
||||
"buffer-equal-constant-time": "1.0.1",
|
||||
"ecdsa-sig-formatter": "1.0.11",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"jws": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
|
||||
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
|
||||
"requires": {
|
||||
"jwa": "^1.4.1",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"keccak": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.3.tgz",
|
||||
@ -30542,6 +30778,68 @@
|
||||
"webrtc-adapter": "^8.1.1"
|
||||
}
|
||||
},
|
||||
"livekit-server-sdk": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/livekit-server-sdk/-/livekit-server-sdk-1.2.5.tgz",
|
||||
"integrity": "sha512-QYHGEoilSAXUQQBAZE2SXU1oXW8z08VFp2UxcZzXdPt3u4E9xamghTMhgniLMWmpSCl7oqVObQ6XXnK9rkr0Pg==",
|
||||
"requires": {
|
||||
"axios": "^1.3.6",
|
||||
"camelcase-keys": "^7.0.0",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"protobufjs": "^7.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "20.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.7.tgz",
|
||||
"integrity": "sha512-bUBrPjEry2QUTsnuEjzjbS7voGWCc30W0qzgMf90GPeDGFRakvrz47ju+oqDAKCXLUCe39u57/ORMl/O/04/9g=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz",
|
||||
"integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.15.0",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"long": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
|
||||
"integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
|
||||
},
|
||||
"protobufjs": {
|
||||
"version": "7.2.4",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.4.tgz",
|
||||
"integrity": "sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ==",
|
||||
"requires": {
|
||||
"@protobufjs/aspromise": "^1.1.2",
|
||||
"@protobufjs/base64": "^1.1.2",
|
||||
"@protobufjs/codegen": "^2.0.4",
|
||||
"@protobufjs/eventemitter": "^1.1.0",
|
||||
"@protobufjs/fetch": "^1.1.0",
|
||||
"@protobufjs/float": "^1.0.2",
|
||||
"@protobufjs/inquire": "^1.1.0",
|
||||
"@protobufjs/path": "^1.1.2",
|
||||
"@protobufjs/pool": "^1.1.0",
|
||||
"@protobufjs/utf8": "^1.1.0",
|
||||
"@types/node": ">=13.7.0",
|
||||
"long": "^5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||
@ -30701,6 +30999,11 @@
|
||||
"tmpl": "1.0.5"
|
||||
}
|
||||
},
|
||||
"map-obj": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
|
||||
"integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ=="
|
||||
},
|
||||
"matchmediaquery": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/matchmediaquery/-/matchmediaquery-0.3.1.tgz",
|
||||
@ -31771,6 +32074,11 @@
|
||||
"resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.5.1.tgz",
|
||||
"integrity": "sha512-oyfc0Tx87Cpwva5ZXezSp5V9vht1c7dZBhvuV/y3ctkgMVUmiAGDVeeB0dKhGSyT0v1ZTEQYpe/RXlBVBNuCLA=="
|
||||
},
|
||||
"proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"prr": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
"decentraland-ui": "^4.0.0",
|
||||
"ethers": "^6.6.5",
|
||||
"livekit-client": "^1.12.3",
|
||||
"livekit-server-sdk": "^1.2.5",
|
||||
"p-queue": "^6.6.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
|
||||
24
src/components/Pages/Conference/Conference.container.ts
Normal file
24
src/components/Pages/Conference/Conference.container.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { connect } from "react-redux"
|
||||
import { getAddress, isConnecting } from "decentraland-dapps/dist/modules/wallet/selectors"
|
||||
import { isLoggingIn } from "../../../modules/identity/selector"
|
||||
import { getServer, getToken } from "../../../modules/conference/selector"
|
||||
import { RootState } from "../../../modules/reducer"
|
||||
import withRouter from "../../../utils/WithRouter"
|
||||
import Conference from "./Conference"
|
||||
import { MapDispatch, MapStateProps, OwnProps } from "./Conference.types"
|
||||
|
||||
const mapStateToProps = (state: RootState, ownProps: OwnProps): MapStateProps => {
|
||||
const addressFromPath = ownProps.router.params.profileAddress
|
||||
|
||||
return {
|
||||
profileAddress: addressFromPath?.toLowerCase(),
|
||||
isLoading: isLoggingIn(state) || isConnecting(state),
|
||||
loggedInAddress: getAddress(state)?.toLowerCase(),
|
||||
server: getServer(state),
|
||||
token: getToken(state),
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatch = (dispatch: MapDispatch): any => ({})
|
||||
|
||||
export default withRouter(connect(mapStateToProps, mapDispatch)(Conference))
|
||||
15
src/components/Pages/Conference/Conference.tsx
Normal file
15
src/components/Pages/Conference/Conference.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import React from "react"
|
||||
import { Props } from "./Conference.types"
|
||||
import { LiveKitRoom, VideoConference } from "@livekit/components-react"
|
||||
|
||||
export default function Conference(props: Props) {
|
||||
const { token, server } = props
|
||||
|
||||
return (
|
||||
<>
|
||||
<LiveKitRoom token={token} serverUrl={server} connect={true}>
|
||||
<VideoConference />
|
||||
</LiveKitRoom>
|
||||
</>
|
||||
)
|
||||
}
|
||||
19
src/components/Pages/Conference/Conference.types.ts
Normal file
19
src/components/Pages/Conference/Conference.types.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { Dispatch } from "redux"
|
||||
import { RouterProps } from "../../../utils/WithRouter"
|
||||
|
||||
export type Props = {
|
||||
loggedInAddress?: string
|
||||
profileAddress?: string
|
||||
isLoading: boolean
|
||||
server?: string
|
||||
token?: string
|
||||
}
|
||||
|
||||
export type MapStateProps = Pick<Props, "loggedInAddress" | "isLoading" | "profileAddress" | "server" | "token">
|
||||
export type MapDispatch = Dispatch
|
||||
type Params = {
|
||||
profileAddress?: string
|
||||
}
|
||||
export type OwnProps = {
|
||||
router: RouterProps<Params>
|
||||
}
|
||||
2
src/components/Pages/Conference/index.ts
Normal file
2
src/components/Pages/Conference/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
import Conference from "./Conference.container"
|
||||
export default Conference
|
||||
@ -1,24 +1,29 @@
|
||||
import { connect } from "react-redux"
|
||||
import { loadProfileRequest } from "decentraland-dapps/dist/modules/profile/actions"
|
||||
import { getAddress, isConnecting } from "decentraland-dapps/dist/modules/wallet/selectors"
|
||||
import { isLoggingIn } from "../../../modules/identity/selector"
|
||||
import { getCurrentIdentity, isLoggingIn } from "../../../modules/identity/selector"
|
||||
import { RootState } from "../../../modules/reducer"
|
||||
import withRouter from "../../../utils/WithRouter"
|
||||
import MainPage from "./MainPage"
|
||||
import { MapDispatch, MapDispatchProps, MapStateProps, OwnProps } from "./MainPage.types"
|
||||
import { setServer, setToken } from "../../../modules/conference/action"
|
||||
|
||||
const mapStateToProps = (state: RootState, ownProps: OwnProps): MapStateProps => {
|
||||
const addressFromPath = ownProps.router.params.profileAddress
|
||||
const identity = getCurrentIdentity(state)
|
||||
|
||||
return {
|
||||
profileAddress: addressFromPath?.toLowerCase(),
|
||||
isLoading: isLoggingIn(state) || isConnecting(state),
|
||||
loggedInAddress: getAddress(state)?.toLowerCase(),
|
||||
identity,
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatch = (dispatch: MapDispatch): MapDispatchProps => ({
|
||||
onFetchProfile: (address) => dispatch(loadProfileRequest(address)),
|
||||
onSubmitConnectForm: (server: string, token:string) => {
|
||||
dispatch(setServer({ server }))
|
||||
dispatch(setToken({ token }))
|
||||
},
|
||||
})
|
||||
|
||||
export default withRouter(connect(mapStateToProps, mapDispatch)(MainPage))
|
||||
|
||||
@ -1,30 +1,26 @@
|
||||
import React, { useCallback, useEffect, useState } from "react"
|
||||
import React, { ChangeEvent, useEffect, useState } from "react"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
import Divider from "semantic-ui-react/dist/commonjs/elements/Divider/Divider"
|
||||
import { t } from "decentraland-dapps/dist/modules/translation/utils"
|
||||
import { Tabs } from "decentraland-ui/dist/components/Tabs/Tabs"
|
||||
import { Loader } from "decentraland-ui"
|
||||
import { locations } from "../../../modules/routing/locations"
|
||||
import { getView } from "../../../utils/view"
|
||||
import { PageLayout } from "../../PageLayout"
|
||||
import { Props } from "./MainPage.types"
|
||||
import styles from "./MainPage.module.css"
|
||||
import { LiveKitRoom, VideoConference } from "@livekit/components-react"
|
||||
import { flatFetch } from "../../../utils/flat-fetch"
|
||||
import { signedFetch } from "../../../utils/auth"
|
||||
import { AuthIdentity } from "@dcl/crypto"
|
||||
|
||||
function MainPage(props: Props) {
|
||||
const { isLoading, onFetchProfile, profileAddress, loggedInAddress } = props
|
||||
const [selectedServer, setSelectedServer] = useState("")
|
||||
const [isConnectingToServer, setIsConnectingToServer] = useState(false)
|
||||
|
||||
const { isLoading, onFetchProfile, profileAddress, loggedInAddress, identity, onSubmitConnectForm } = props
|
||||
const tabs: { displayValue: string; value: string }[] = [
|
||||
{ displayValue: t("tabs.overview"), value: t("tabs.overview") },
|
||||
]
|
||||
|
||||
const [selectedTab, setSelectedTab] = useState<string>(tabs[0].value)
|
||||
|
||||
const handleTabChange = useCallback(
|
||||
(tab: string) => {
|
||||
setSelectedTab(tab)
|
||||
},
|
||||
[setSelectedTab]
|
||||
)
|
||||
const navigate = useNavigate()
|
||||
|
||||
useEffect(() => {
|
||||
@ -40,24 +36,73 @@ function MainPage(props: Props) {
|
||||
}, [isLoading, loggedInAddress, profileAddress])
|
||||
const view = getView(loggedInAddress, profileAddress)
|
||||
|
||||
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setSelectedServer(e.target.value)
|
||||
}
|
||||
|
||||
async function livekitConnect(identity: AuthIdentity, worldServer: string, worldName: string) {
|
||||
const aboutResponse = await flatFetch(`${worldServer}/world/${worldName}/about`)
|
||||
console.log(aboutResponse.text)
|
||||
if (aboutResponse.status === 200) {
|
||||
const url = JSON.parse(aboutResponse.text!)
|
||||
["comms"]["fixedAdapter"].replace("signed-login:", "")
|
||||
.replace("get-comms-adapter", "cast-adapter")
|
||||
const response = await signedFetch(
|
||||
url,
|
||||
identity,
|
||||
{
|
||||
method: "POST",
|
||||
},
|
||||
{
|
||||
signer: "dcl:explorer",
|
||||
intent: "dcl:explorer:comms-handshake",
|
||||
}
|
||||
)
|
||||
|
||||
if (response.status === 200) {
|
||||
console.log(response.text)
|
||||
return JSON.parse(response.text!)
|
||||
} else {
|
||||
let message = ""
|
||||
try {
|
||||
message = JSON.parse(response.text || "")?.message
|
||||
} catch (e) {
|
||||
message = response.text || ""
|
||||
}
|
||||
throw Error(message)
|
||||
}
|
||||
// throw Error(`Failed to connect to LiveKit: ${JSON.stringify(response.text || response.json?.message)}`)
|
||||
} else if (aboutResponse.status === 404) {
|
||||
throw Error(`World ${worldName} not found`)
|
||||
}
|
||||
throw Error("An error has occurred")
|
||||
}
|
||||
|
||||
const handleClick = () => {
|
||||
livekitConnect(identity!, "https://worlds-content-server.decentraland.zone", selectedServer)
|
||||
.then((response: { url: string; token: string }) => {
|
||||
onSubmitConnectForm(response.url, response.token)
|
||||
navigate(`/meet/${encodeURIComponent(response.url)}?token=${encodeURIComponent(response.token)}`)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("ERROR livekit connect", err)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<PageLayout>
|
||||
{isLoading ? (
|
||||
{isLoading || isConnectingToServer ? (
|
||||
<Loader active />
|
||||
) : (
|
||||
<div className={styles.MainPage}>
|
||||
<div className={styles.infoContainer}>
|
||||
<Divider />
|
||||
<Tabs>
|
||||
{tabs.map((tab) => (
|
||||
<Tabs.Tab key={tab.value} active={selectedTab === tab.value} onClick={() => handleTabChange(tab.value)}>
|
||||
<span className={styles.tab}>{tab.displayValue}</span>
|
||||
</Tabs.Tab>
|
||||
))}
|
||||
</Tabs>
|
||||
<LiveKitRoom token="" serverUrl="wss://dcl.livekit.cloud" connect={true}>
|
||||
<VideoConference />
|
||||
</LiveKitRoom>
|
||||
|
||||
<div>
|
||||
<input name="server" value={selectedServer} onChange={handleChange} />
|
||||
|
||||
<button onClick={handleClick}>Connect</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -1,17 +1,20 @@
|
||||
import { Dispatch } from 'redux'
|
||||
import { LoadProfileRequestAction, loadProfileRequest } from 'decentraland-dapps/dist/modules/profile/actions'
|
||||
import { RouterProps } from '../../../utils/WithRouter'
|
||||
import { Dispatch } from "redux"
|
||||
import { loadProfileRequest } from "decentraland-dapps/dist/modules/profile/actions"
|
||||
import { RouterProps } from "../../../utils/WithRouter"
|
||||
import { AuthIdentity } from "@dcl/crypto"
|
||||
|
||||
export type Props = {
|
||||
onFetchProfile: typeof loadProfileRequest
|
||||
loggedInAddress?: string
|
||||
profileAddress?: string
|
||||
isLoading: boolean
|
||||
onSubmitConnectForm: (server: string, token: string) => void
|
||||
identity: AuthIdentity | null
|
||||
}
|
||||
|
||||
export type MapStateProps = Pick<Props, 'loggedInAddress' | 'isLoading' | 'profileAddress'>
|
||||
export type MapDispatchProps = Pick<Props, 'onFetchProfile'>
|
||||
export type MapDispatch = Dispatch<LoadProfileRequestAction>
|
||||
export type MapStateProps = Pick<Props, "loggedInAddress" | "isLoading" | "profileAddress" | "identity">
|
||||
export type MapDispatchProps = Pick<Props, "onSubmitConnectForm">
|
||||
export type MapDispatch = Dispatch
|
||||
type Params = {
|
||||
profileAddress?: string
|
||||
}
|
||||
|
||||
@ -15,6 +15,7 @@ import * as locales from "./modules/translation/locales"
|
||||
// These CSS styles must be defined last to avoid overriding other styles
|
||||
import "decentraland-ui/dist/themes/alternative/dark-theme.css"
|
||||
import "./index.css"
|
||||
import Conference from "./components/Pages/Conference"
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
@ -29,6 +30,10 @@ const router = createBrowserRouter([
|
||||
path: "sign-in",
|
||||
element: <SignInPage />,
|
||||
},
|
||||
{
|
||||
path: "/meet/:server",
|
||||
element: <Conference />,
|
||||
},
|
||||
])
|
||||
|
||||
const component = (
|
||||
|
||||
9
src/modules/conference/action.ts
Normal file
9
src/modules/conference/action.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { createAction } from "@reduxjs/toolkit"
|
||||
|
||||
export const setServer = createAction<{ server: string }>("Set Server")
|
||||
|
||||
export type SetServerAction = ReturnType<typeof setServer>
|
||||
|
||||
export const setToken = createAction<{ token: string }>("Set Token")
|
||||
|
||||
export type SetTokenAction = ReturnType<typeof setToken>
|
||||
22
src/modules/conference/reducer.ts
Normal file
22
src/modules/conference/reducer.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { createReducer } from "@reduxjs/toolkit"
|
||||
import { setServer, setToken } from "./action"
|
||||
|
||||
export type ConferenceState = {
|
||||
token: string
|
||||
server: string
|
||||
}
|
||||
|
||||
export const INITIAL_STATE: ConferenceState = {
|
||||
token: "",
|
||||
server: "",
|
||||
}
|
||||
|
||||
export const conferenceReducer = createReducer<ConferenceState>(INITIAL_STATE, (builder) =>
|
||||
builder
|
||||
.addCase(setServer, (state, action) => {
|
||||
state.server = action.payload.server
|
||||
})
|
||||
.addCase(setToken, (state, action) => {
|
||||
state.token = action.payload.token
|
||||
})
|
||||
)
|
||||
9
src/modules/conference/selector.ts
Normal file
9
src/modules/conference/selector.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { createSelector } from "@reduxjs/toolkit"
|
||||
import { RootState } from "../reducer"
|
||||
|
||||
const getState = (state: RootState) => state.conference
|
||||
|
||||
export const getToken = (state: RootState) => getState(state).token
|
||||
export const getServer = (state: RootState) => getState(state).server
|
||||
|
||||
export const isLoading = createSelector([getToken], (token) => !!token)
|
||||
@ -13,6 +13,7 @@ import {
|
||||
} from "decentraland-dapps/dist/modules/translation/reducer"
|
||||
import { WalletState, walletReducer as wallet } from "decentraland-dapps/dist/modules/wallet/reducer"
|
||||
import { IdentityState, identityReducer as identity } from "./identity/reducer"
|
||||
import { ConferenceState, conferenceReducer as conference } from "./conference/reducer"
|
||||
|
||||
export const createRootReducer = (middlewares: Middleware[], preloadedState = {}) =>
|
||||
configureStore({
|
||||
@ -25,6 +26,7 @@ export const createRootReducer = (middlewares: Middleware[], preloadedState = {}
|
||||
translation: translation as Reducer<TranslationState, AnyAction>,
|
||||
profile,
|
||||
identity,
|
||||
conference,
|
||||
})
|
||||
),
|
||||
preloadedState,
|
||||
@ -54,6 +56,7 @@ export type RootState = {
|
||||
translation: TranslationState
|
||||
wallet: WalletState
|
||||
features: FeaturesState
|
||||
conference: ConferenceState
|
||||
}
|
||||
|
||||
export type RootStore = Store<RootState>
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
export const locations = {
|
||||
root: () => '/',
|
||||
root: () => "/",
|
||||
account: (address: string) => `/accounts/${address}`,
|
||||
signIn: (redirectTo?: string) => {
|
||||
return `/sign-in${redirectTo ? `?redirectTo=${encodeURIComponent(redirectTo)}` : ''}`
|
||||
}
|
||||
return `/sign-in${redirectTo ? `?redirectTo=${encodeURIComponent(redirectTo)}` : ""}`
|
||||
},
|
||||
meet: (server: string, token: string) => `/meet/${server}?token${token}`,
|
||||
}
|
||||
|
||||
121
src/utils/auth.ts
Normal file
121
src/utils/auth.ts
Normal file
@ -0,0 +1,121 @@
|
||||
import { RequestManager } from "eth-connect"
|
||||
import { createUnsafeIdentity } from "@dcl/crypto/dist/crypto"
|
||||
import { FlatFetchInit, flatFetch } from "./flat-fetch"
|
||||
import { AuthChain, AuthIdentity, Authenticator } from "@dcl/crypto"
|
||||
|
||||
const ephemeralLifespanMinutes = 10_000
|
||||
|
||||
export type ExplorerIdentity = {
|
||||
// public address of the first elemement of the authChain
|
||||
address: string
|
||||
// is the address an ephemeral address? used to determine if the user is a guest
|
||||
isGuest: boolean
|
||||
// the authChain is the chain of signatures that prove the ownership of the address
|
||||
authChain: AuthIdentity
|
||||
// the signer function will be used to sign messages using the last element of the authChain
|
||||
signer: (message: string) => Promise<string>
|
||||
}
|
||||
|
||||
export async function getUserAccount(
|
||||
requestManager: RequestManager,
|
||||
returnChecksum: boolean
|
||||
): Promise<string | undefined> {
|
||||
try {
|
||||
const accounts = await requestManager.eth_accounts()
|
||||
|
||||
if (!accounts || accounts.length === 0) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return returnChecksum ? accounts[0] : accounts[0].toLowerCase()
|
||||
} catch (error: any) {
|
||||
throw new Error(`Could not access eth_accounts: "${error.message}"`)
|
||||
}
|
||||
}
|
||||
|
||||
const AUTH_CHAIN_HEADER_PREFIX = "x-identity-auth-chain-"
|
||||
const AUTH_TIMESTAMP_HEADER = "x-identity-timestamp"
|
||||
const AUTH_METADATA_HEADER = "x-identity-metadata"
|
||||
|
||||
export function getAuthChainSignature(
|
||||
method: string,
|
||||
path: string,
|
||||
metadata: string,
|
||||
chainProvider: (payload: string) => AuthChain
|
||||
) {
|
||||
const timestamp = Date.now()
|
||||
const payloadParts = [method.toLowerCase(), path.toLowerCase(), timestamp.toString(), metadata]
|
||||
const payloadToSign = payloadParts.join(":").toLowerCase()
|
||||
const authChain = chainProvider(payloadToSign)
|
||||
|
||||
return {
|
||||
authChain,
|
||||
metadata,
|
||||
timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
export function getSignedHeaders(
|
||||
method: string,
|
||||
path: string,
|
||||
metadata: Record<string, any>,
|
||||
chainProvider: (payload: string) => AuthChain
|
||||
) {
|
||||
const headers: Record<string, string> = {}
|
||||
const signature = getAuthChainSignature(method, path, JSON.stringify(metadata), chainProvider)
|
||||
signature.authChain.forEach((link, index) => {
|
||||
headers[`${AUTH_CHAIN_HEADER_PREFIX}${index}`] = JSON.stringify(link)
|
||||
})
|
||||
|
||||
headers[AUTH_TIMESTAMP_HEADER] = signature.timestamp.toString()
|
||||
headers[AUTH_METADATA_HEADER] = signature.metadata
|
||||
return headers
|
||||
}
|
||||
|
||||
export function signedFetch(
|
||||
url: string,
|
||||
identity: AuthIdentity,
|
||||
init?: FlatFetchInit,
|
||||
additionalMetadata: Record<string, any> = {}
|
||||
) {
|
||||
const path = new URL(url).pathname
|
||||
|
||||
const actualInit = {
|
||||
...init,
|
||||
headers: {
|
||||
...getSignedHeaders(
|
||||
init?.method ?? "get",
|
||||
path,
|
||||
{
|
||||
origin: location.origin,
|
||||
...additionalMetadata,
|
||||
},
|
||||
(payload) => Authenticator.signPayload(identity, payload)
|
||||
),
|
||||
...init?.headers,
|
||||
},
|
||||
} as FlatFetchInit
|
||||
|
||||
return flatFetch(url, actualInit)
|
||||
}
|
||||
|
||||
// this function creates a Decentraland AuthChain using a signer function.
|
||||
// the signer function is only used once, to sign the ephemeral private key. after that,
|
||||
// the ephemeral private key is used to sign the rest of the authChain and subsequent
|
||||
// messages. this is a good way to not over-expose the real user accounts to excessive
|
||||
// signing requests.
|
||||
export async function identityFromSigner(
|
||||
address: string,
|
||||
signer: (message: string) => Promise<string>
|
||||
): Promise<ExplorerIdentity> {
|
||||
const ephemeral = createUnsafeIdentity()
|
||||
|
||||
const authChain = await Authenticator.initializeAuthChain(address, ephemeral, ephemeralLifespanMinutes, signer)
|
||||
|
||||
return {
|
||||
address,
|
||||
signer,
|
||||
authChain,
|
||||
isGuest: true,
|
||||
}
|
||||
}
|
||||
21
src/utils/client-utils.ts
Normal file
21
src/utils/client-utils.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { useEffect, useState } from "react"
|
||||
|
||||
export function useServerUrl(region?: string) {
|
||||
const [serverUrl, setServerUrl] = useState<string | undefined>()
|
||||
useEffect(() => {
|
||||
let endpoint = `/api/url`
|
||||
if (region) {
|
||||
endpoint += `?region=${region}`
|
||||
}
|
||||
fetch(endpoint).then(async (res) => {
|
||||
if (res.ok) {
|
||||
const body = await res.json()
|
||||
console.log(body)
|
||||
setServerUrl(body.url)
|
||||
} else {
|
||||
throw Error("Error fetching server url, check server logs")
|
||||
}
|
||||
})
|
||||
})
|
||||
return serverUrl
|
||||
}
|
||||
40
src/utils/flat-fetch.ts
Normal file
40
src/utils/flat-fetch.ts
Normal file
@ -0,0 +1,40 @@
|
||||
type FlatFetchResponse = {
|
||||
ok: boolean
|
||||
status: number
|
||||
statusText: string
|
||||
headers: Record<string, string>
|
||||
json?: any
|
||||
text?: string
|
||||
}
|
||||
|
||||
type BodyType = "json" | "text"
|
||||
|
||||
export type FlatFetchInit = RequestInit & { responseBodyType?: BodyType }
|
||||
|
||||
export async function flatFetch(url: string, init?: FlatFetchInit): Promise<FlatFetchResponse> {
|
||||
const response = await fetch(url, init)
|
||||
|
||||
const responseBodyType = init?.responseBodyType || "text"
|
||||
|
||||
const headers: Record<string, string> = {}
|
||||
|
||||
response.headers.forEach((value, key) => (headers[key] = value))
|
||||
|
||||
const flatFetchResponse: FlatFetchResponse = {
|
||||
ok: response.ok,
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
headers,
|
||||
}
|
||||
|
||||
switch (responseBodyType) {
|
||||
case "json":
|
||||
flatFetchResponse.json = await response.json()
|
||||
break
|
||||
case "text":
|
||||
flatFetchResponse.text = await response.text()
|
||||
break
|
||||
}
|
||||
|
||||
return flatFetchResponse
|
||||
}
|
||||
27
src/utils/server-utils.ts
Normal file
27
src/utils/server-utils.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { RoomServiceClient } from "livekit-server-sdk"
|
||||
|
||||
export function getRoomClient(): RoomServiceClient {
|
||||
checkKeys()
|
||||
return new RoomServiceClient(getLiveKitURL())
|
||||
}
|
||||
|
||||
export function getLiveKitURL(region?: string | string[]): string {
|
||||
let targetKey = "LIVEKIT_URL"
|
||||
if (region && !Array.isArray(region)) {
|
||||
targetKey = `LIVEKIT_URL_${region}`.toUpperCase()
|
||||
}
|
||||
const url = process.env[targetKey]
|
||||
if (!url) {
|
||||
throw new Error(`${targetKey} is not defined`)
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
function checkKeys() {
|
||||
if (typeof process.env.LIVEKIT_API_KEY === "undefined") {
|
||||
throw new Error("LIVEKIT_API_KEY is not defined")
|
||||
}
|
||||
if (typeof process.env.LIVEKIT_API_SECRET === "undefined") {
|
||||
throw new Error("LIVEKIT_API_SECRET is not defined")
|
||||
}
|
||||
}
|
||||
16
src/utils/types.ts
Normal file
16
src/utils/types.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { LocalAudioTrack, LocalVideoTrack } from "livekit-client"
|
||||
|
||||
export interface SessionProps {
|
||||
roomName: string
|
||||
identity: string
|
||||
audioTrack?: LocalAudioTrack
|
||||
videoTrack?: LocalVideoTrack
|
||||
region?: string
|
||||
turnServer?: RTCIceServer
|
||||
forceRelay?: boolean
|
||||
}
|
||||
|
||||
export interface TokenResult {
|
||||
identity: string
|
||||
accessToken: string
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user