perf: multiple peerRoom implementation
This commit is contained in:
parent
ec62b1155e
commit
e373993899
15 changed files with 628 additions and 276 deletions
|
@ -56,8 +56,11 @@
|
||||||
"@radix-ui/react-scroll-area": "^1.1.0",
|
"@radix-ui/react-scroll-area": "^1.1.0",
|
||||||
"@radix-ui/react-slot": "^1.1.0",
|
"@radix-ui/react-slot": "^1.1.0",
|
||||||
"@radix-ui/react-switch": "^1.1.0",
|
"@radix-ui/react-switch": "^1.1.0",
|
||||||
|
"@resreq/event-hub": "^1.6.0",
|
||||||
"@resreq/timer": "^1.1.5",
|
"@resreq/timer": "^1.1.5",
|
||||||
|
"@rtco/client": "^0.2.17",
|
||||||
"@tailwindcss/typography": "^0.5.15",
|
"@tailwindcss/typography": "^0.5.15",
|
||||||
|
"@webext-core/proxy-service": "^1.2.0",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
|
|
219
pnpm-lock.yaml
219
pnpm-lock.yaml
|
@ -44,12 +44,21 @@ importers:
|
||||||
'@radix-ui/react-switch':
|
'@radix-ui/react-switch':
|
||||||
specifier: ^1.1.0
|
specifier: ^1.1.0
|
||||||
version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
'@resreq/event-hub':
|
||||||
|
specifier: ^1.6.0
|
||||||
|
version: 1.6.0
|
||||||
'@resreq/timer':
|
'@resreq/timer':
|
||||||
specifier: ^1.1.5
|
specifier: ^1.1.5
|
||||||
version: 1.1.5
|
version: 1.1.5
|
||||||
|
'@rtco/client':
|
||||||
|
specifier: ^0.2.17
|
||||||
|
version: 0.2.17
|
||||||
'@tailwindcss/typography':
|
'@tailwindcss/typography':
|
||||||
specifier: ^0.5.15
|
specifier: ^0.5.15
|
||||||
version: 0.5.15(tailwindcss@3.4.12)
|
version: 0.5.15(tailwindcss@3.4.12)
|
||||||
|
'@webext-core/proxy-service':
|
||||||
|
specifier: ^1.2.0
|
||||||
|
version: 1.2.0(@webext-core/messaging@1.4.0)(webextension-polyfill@0.12.0)
|
||||||
class-variance-authority:
|
class-variance-authority:
|
||||||
specifier: ^0.7.0
|
specifier: ^0.7.0
|
||||||
version: 0.7.0
|
version: 0.7.0
|
||||||
|
@ -115,7 +124,7 @@ importers:
|
||||||
version: 2.5.2
|
version: 2.5.2
|
||||||
trystero:
|
trystero:
|
||||||
specifier: ^0.20.0
|
specifier: ^0.20.0
|
||||||
version: 0.20.0(@libp2p/interface@1.7.0)(@waku/core@0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4))(@waku/enr@0.0.21)(@waku/interfaces@0.0.22)(@waku/message-hash@0.1.16)(@waku/proto@0.0.7)(@waku/relay@0.0.11(@waku/core@0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4))(@waku/interfaces@0.0.22)(@waku/proto@0.0.7)(@waku/utils@0.0.20))(@waku/utils@0.0.20)
|
version: 0.20.0(@libp2p/interface@1.7.0)(@waku/core@0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4))(@waku/enr@0.0.21)(@waku/interfaces@0.0.22)(@waku/message-hash@0.1.16)(@waku/proto@0.0.7)(@waku/relay@0.0.11(@waku/core@0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4))(@waku/interfaces@0.0.22)(@waku/proto@0.0.7)(@waku/utils@0.0.20))(@waku/utils@0.0.20)(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||||
type-fest:
|
type-fest:
|
||||||
specifier: ^4.26.1
|
specifier: ^4.26.1
|
||||||
version: 4.26.1
|
version: 4.26.1
|
||||||
|
@ -227,7 +236,7 @@ importers:
|
||||||
version: 6.0.1
|
version: 6.0.1
|
||||||
wxt:
|
wxt:
|
||||||
specifier: ^0.19.9
|
specifier: ^0.19.9
|
||||||
version: 0.19.9(@types/node@22.5.5)(rollup@4.21.3)
|
version: 0.19.9(@types/node@22.5.5)(bufferutil@4.0.8)(rollup@4.21.3)(utf-8-validate@6.0.4)
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
|
@ -1741,6 +1750,12 @@ packages:
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
|
'@rtco/client@0.2.17':
|
||||||
|
resolution: {integrity: sha512-nV/KJGBh/j0fK069uADXNr30JBbWe7CZ0xe0cEx1JjuBQIkH10Ny5mQm4WZd/vID+EF7l+tqkCG6QUyCAW5PFg==}
|
||||||
|
|
||||||
|
'@rtco/peer@0.2.17':
|
||||||
|
resolution: {integrity: sha512-jxKQzAIMiofkJ5UHIbeq2JUl+fBOCnWRxgxemzuI7TKw96pbkfaMowr3fj+ElXnKPWwCi5WRX3hwitqjfNkwFQ==}
|
||||||
|
|
||||||
'@sec-ant/readable-stream@0.4.1':
|
'@sec-ant/readable-stream@0.4.1':
|
||||||
resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==}
|
resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==}
|
||||||
|
|
||||||
|
@ -1756,6 +1771,9 @@ packages:
|
||||||
resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==}
|
resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
'@socket.io/component-emitter@3.1.2':
|
||||||
|
resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
|
||||||
|
|
||||||
'@supabase/auth-js@2.65.0':
|
'@supabase/auth-js@2.65.0':
|
||||||
resolution: {integrity: sha512-+wboHfZufAE2Y612OsKeVP4rVOeGZzzMLD/Ac3HrTQkkY4qXNjI6Af9gtmxwccE5nFvTiF114FEbIQ1hRq5uUw==}
|
resolution: {integrity: sha512-+wboHfZufAE2Y612OsKeVP4rVOeGZzzMLD/Ac3HrTQkkY4qXNjI6Af9gtmxwccE5nFvTiF114FEbIQ1hRq5uUw==}
|
||||||
|
|
||||||
|
@ -2105,6 +2123,15 @@ packages:
|
||||||
'@webext-core/match-patterns@1.0.3':
|
'@webext-core/match-patterns@1.0.3':
|
||||||
resolution: {integrity: sha512-NY39ACqCxdKBmHgw361M9pfJma8e4AZo20w9AY+5ZjIj1W2dvXC8J31G5fjfOGbulW9w4WKpT8fPooi0mLkn9A==}
|
resolution: {integrity: sha512-NY39ACqCxdKBmHgw361M9pfJma8e4AZo20w9AY+5ZjIj1W2dvXC8J31G5fjfOGbulW9w4WKpT8fPooi0mLkn9A==}
|
||||||
|
|
||||||
|
'@webext-core/messaging@1.4.0':
|
||||||
|
resolution: {integrity: sha512-gzXQ13HfKR3Yrn9TnrvTC/5seA7uPFvaqxqNFBsFOOdSZa5LyXt58Rhym8BYXarkWUGp+fh8f6AYM3RYuNbS+A==}
|
||||||
|
|
||||||
|
'@webext-core/proxy-service@1.2.0':
|
||||||
|
resolution: {integrity: sha512-MCUadVakeb7L47AvdtlbJfBUDjFdejr5t4E2WrwZagnev3a5I/xh2wHCkE+G0ihO/VUt/m0R1MPX+y4YVFRyPA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@webext-core/messaging': '>=1.3.1'
|
||||||
|
webextension-polyfill: ^0.10.0
|
||||||
|
|
||||||
'@xobotyi/scrollbar-width@1.9.5':
|
'@xobotyi/scrollbar-width@1.9.5':
|
||||||
resolution: {integrity: sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==}
|
resolution: {integrity: sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==}
|
||||||
|
|
||||||
|
@ -2311,6 +2338,10 @@ packages:
|
||||||
buffer@6.0.3:
|
buffer@6.0.3:
|
||||||
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
|
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
|
||||||
|
|
||||||
|
bufferutil@4.0.8:
|
||||||
|
resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==}
|
||||||
|
engines: {node: '>=6.14.2'}
|
||||||
|
|
||||||
bundle-name@3.0.0:
|
bundle-name@3.0.0:
|
||||||
resolution: {integrity: sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==}
|
resolution: {integrity: sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
@ -2825,6 +2856,13 @@ packages:
|
||||||
end-of-stream@1.4.4:
|
end-of-stream@1.4.4:
|
||||||
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
|
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
|
||||||
|
|
||||||
|
engine.io-client@6.6.1:
|
||||||
|
resolution: {integrity: sha512-aYuoak7I+R83M/BBPIOs2to51BmFIpC1wZe6zZzMrT2llVsHy5cvcmdsJgP2Qz6smHu+sD9oexiSUAVd8OfBPw==}
|
||||||
|
|
||||||
|
engine.io-parser@5.2.3:
|
||||||
|
resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
entities@4.5.0:
|
entities@4.5.0:
|
||||||
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
||||||
engines: {node: '>=0.12'}
|
engines: {node: '>=0.12'}
|
||||||
|
@ -3271,6 +3309,10 @@ packages:
|
||||||
resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==}
|
resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
get-value@3.0.1:
|
||||||
|
resolution: {integrity: sha512-mKZj9JLQrwMBtj5wxi6MH8Z5eSKaERpAwjg43dPtlGI1ZVEgH/qC7T8/6R2OBSUA+zzHBZgICsVJaEIV2tKTDA==}
|
||||||
|
engines: {node: '>=6.0'}
|
||||||
|
|
||||||
giget@1.2.3:
|
giget@1.2.3:
|
||||||
resolution: {integrity: sha512-8EHPljDvs7qKykr6uw8b+lqLiUc/vUg+KVTI0uND4s63TdsZM2Xus3mflvF0DDG9SiM4RlCkFGL+7aAjRmV7KA==}
|
resolution: {integrity: sha512-8EHPljDvs7qKykr6uw8b+lqLiUc/vUg+KVTI0uND4s63TdsZM2Xus3mflvF0DDG9SiM4RlCkFGL+7aAjRmV7KA==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
@ -4415,6 +4457,10 @@ packages:
|
||||||
resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==}
|
resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==}
|
||||||
engines: {node: '>= 6.13.0'}
|
engines: {node: '>= 6.13.0'}
|
||||||
|
|
||||||
|
node-gyp-build@4.8.2:
|
||||||
|
resolution: {integrity: sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
node-notifier@10.0.1:
|
node-notifier@10.0.1:
|
||||||
resolution: {integrity: sha512-YX7TSyDukOZ0g+gmzjB6abKu+hTGvO8+8+gIFDsRCU2t8fLV/P2unmt+LGFaIa4y64aX98Qksa97rgz4vMNeLQ==}
|
resolution: {integrity: sha512-YX7TSyDukOZ0g+gmzjB6abKu+hTGvO8+8+gIFDsRCU2t8fLV/P2unmt+LGFaIa4y64aX98Qksa97rgz4vMNeLQ==}
|
||||||
|
|
||||||
|
@ -5128,6 +5174,10 @@ packages:
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
serialize-error@11.0.3:
|
||||||
|
resolution: {integrity: sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==}
|
||||||
|
engines: {node: '>=14.16'}
|
||||||
|
|
||||||
serialize-error@9.1.1:
|
serialize-error@9.1.1:
|
||||||
resolution: {integrity: sha512-6uZQLGyUkNA4N+Zii9fYukmNu9PEA1F5rqcwXzN/3LtBjwl2dFBbVZ1Zyn08/CGkB4H440PIemdOQBt1Wvjbrg==}
|
resolution: {integrity: sha512-6uZQLGyUkNA4N+Zii9fYukmNu9PEA1F5rqcwXzN/3LtBjwl2dFBbVZ1Zyn08/CGkB4H440PIemdOQBt1Wvjbrg==}
|
||||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||||
|
@ -5211,6 +5261,14 @@ packages:
|
||||||
resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==}
|
resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
socket.io-client@4.8.0:
|
||||||
|
resolution: {integrity: sha512-C0jdhD5yQahMws9alf/yvtsMGTaIDBnZ8Rb5HU56svyq0l5LIrGzIDZZD5pHQlmzxLuU91Gz+VpQMKgCTNYtkw==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
|
socket.io-parser@4.2.4:
|
||||||
|
resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
sonner@1.5.0:
|
sonner@1.5.0:
|
||||||
resolution: {integrity: sha512-FBjhG/gnnbN6FY0jaNnqZOMmB73R+5IiyYAw8yBj7L54ER7HB3fOSE5OFiQiE2iXWxeXKvg6fIP4LtVppHEdJA==}
|
resolution: {integrity: sha512-FBjhG/gnnbN6FY0jaNnqZOMmB73R+5IiyYAw8yBj7L54ER7HB3fOSE5OFiQiE2iXWxeXKvg6fIP4LtVppHEdJA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -5756,6 +5814,10 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
|
||||||
|
utf-8-validate@6.0.4:
|
||||||
|
resolution: {integrity: sha512-xu9GQDeFp+eZ6LnCywXN/zBancWvOpUMzgjLPSjy4BRHSmTelvn2E0DG0o1sTiw5hkCKBHo8rwSKncfRfv2EEQ==}
|
||||||
|
engines: {node: '>=6.14.2'}
|
||||||
|
|
||||||
utf8-bytes@0.0.1:
|
utf8-bytes@0.0.1:
|
||||||
resolution: {integrity: sha512-GifWmJAx2qAXT+lZLhbkWhBsy7pr6xWHiPWlVToDiELdWgZwt4Ogjf9tlgvKuALzTFR/d+EPQQI9ogJV3957Jg==}
|
resolution: {integrity: sha512-GifWmJAx2qAXT+lZLhbkWhBsy7pr6xWHiPWlVToDiELdWgZwt4Ogjf9tlgvKuALzTFR/d+EPQQI9ogJV3957Jg==}
|
||||||
|
|
||||||
|
@ -5849,6 +5911,9 @@ packages:
|
||||||
webext-bridge@6.0.1:
|
webext-bridge@6.0.1:
|
||||||
resolution: {integrity: sha512-GruIrN+vNwbxVCi8UW4Dqk5YkcGA9V0ZfJ57jXP9JXHbrsDs5k2N6NNYQR5e+wSCnQpGYOGAGihwUpKlhg8QIw==}
|
resolution: {integrity: sha512-GruIrN+vNwbxVCi8UW4Dqk5YkcGA9V0ZfJ57jXP9JXHbrsDs5k2N6NNYQR5e+wSCnQpGYOGAGihwUpKlhg8QIw==}
|
||||||
|
|
||||||
|
webextension-polyfill@0.10.0:
|
||||||
|
resolution: {integrity: sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==}
|
||||||
|
|
||||||
webextension-polyfill@0.12.0:
|
webextension-polyfill@0.12.0:
|
||||||
resolution: {integrity: sha512-97TBmpoWJEE+3nFBQ4VocyCdLKfw54rFaJ6EVQYLBCXqCIpLSZkwGgASpv4oPt9gdKCJ80RJlcmNzNn008Ag6Q==}
|
resolution: {integrity: sha512-97TBmpoWJEE+3nFBQ4VocyCdLKfw54rFaJ6EVQYLBCXqCIpLSZkwGgASpv4oPt9gdKCJ80RJlcmNzNn008Ag6Q==}
|
||||||
|
|
||||||
|
@ -5941,6 +6006,18 @@ packages:
|
||||||
write-file-atomic@3.0.3:
|
write-file-atomic@3.0.3:
|
||||||
resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==}
|
resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==}
|
||||||
|
|
||||||
|
ws@8.17.1:
|
||||||
|
resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
bufferutil: ^4.0.1
|
||||||
|
utf-8-validate: '>=5.0.2'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
bufferutil:
|
||||||
|
optional: true
|
||||||
|
utf-8-validate:
|
||||||
|
optional: true
|
||||||
|
|
||||||
ws@8.18.0:
|
ws@8.18.0:
|
||||||
resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
|
resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
|
@ -5969,6 +6046,10 @@ packages:
|
||||||
resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==}
|
resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==}
|
||||||
engines: {node: '>=4.0'}
|
engines: {node: '>=4.0'}
|
||||||
|
|
||||||
|
xmlhttprequest-ssl@2.1.1:
|
||||||
|
resolution: {integrity: sha512-ptjR8YSJIXoA3Mbv5po7RtSYHO6mZr8s7i5VGmEk7QY2pQWyT1o0N+W1gKbOyJPUCGXGnuw0wqe8f0L6Y0ny7g==}
|
||||||
|
engines: {node: '>=0.4.0'}
|
||||||
|
|
||||||
y18n@5.0.8:
|
y18n@5.0.8:
|
||||||
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
|
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
@ -7186,7 +7267,7 @@ snapshots:
|
||||||
uint8arraylist: 2.4.8
|
uint8arraylist: 2.4.8
|
||||||
uint8arrays: 5.1.0
|
uint8arrays: 5.1.0
|
||||||
|
|
||||||
'@libp2p/websockets@8.2.0':
|
'@libp2p/websockets@8.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@libp2p/interface': 1.7.0
|
'@libp2p/interface': 1.7.0
|
||||||
'@libp2p/utils': 5.4.9
|
'@libp2p/utils': 5.4.9
|
||||||
|
@ -7194,12 +7275,12 @@ snapshots:
|
||||||
'@multiformats/multiaddr': 12.3.1
|
'@multiformats/multiaddr': 12.3.1
|
||||||
'@multiformats/multiaddr-to-uri': 10.1.0
|
'@multiformats/multiaddr-to-uri': 10.1.0
|
||||||
'@types/ws': 8.5.12
|
'@types/ws': 8.5.12
|
||||||
it-ws: 6.1.5
|
it-ws: 6.1.5(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||||
p-defer: 4.0.1
|
p-defer: 4.0.1
|
||||||
progress-events: 1.0.1
|
progress-events: 1.0.1
|
||||||
race-signal: 1.1.0
|
race-signal: 1.1.0
|
||||||
wherearewe: 2.0.1
|
wherearewe: 2.0.1
|
||||||
ws: 8.18.0
|
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- bufferutil
|
- bufferutil
|
||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
|
@ -7781,6 +7862,21 @@ snapshots:
|
||||||
'@rollup/rollup-win32-x64-msvc@4.21.3':
|
'@rollup/rollup-win32-x64-msvc@4.21.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@rtco/client@0.2.17':
|
||||||
|
dependencies:
|
||||||
|
'@rtco/peer': 0.2.17
|
||||||
|
bufferutil: 4.0.8
|
||||||
|
eventemitter3: 5.0.1
|
||||||
|
nanoid: 5.0.7
|
||||||
|
socket.io-client: 4.8.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||||
|
utf-8-validate: 6.0.4
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@rtco/peer@0.2.17':
|
||||||
|
dependencies:
|
||||||
|
eventemitter3: 5.0.1
|
||||||
|
|
||||||
'@sec-ant/readable-stream@0.4.1': {}
|
'@sec-ant/readable-stream@0.4.1': {}
|
||||||
|
|
||||||
'@sindresorhus/fnv1a@3.1.0': {}
|
'@sindresorhus/fnv1a@3.1.0': {}
|
||||||
|
@ -7789,6 +7885,8 @@ snapshots:
|
||||||
|
|
||||||
'@sindresorhus/merge-streams@4.0.0': {}
|
'@sindresorhus/merge-streams@4.0.0': {}
|
||||||
|
|
||||||
|
'@socket.io/component-emitter@3.1.2': {}
|
||||||
|
|
||||||
'@supabase/auth-js@2.65.0':
|
'@supabase/auth-js@2.65.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@supabase/node-fetch': 2.6.15
|
'@supabase/node-fetch': 2.6.15
|
||||||
|
@ -7805,12 +7903,12 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@supabase/node-fetch': 2.6.15
|
'@supabase/node-fetch': 2.6.15
|
||||||
|
|
||||||
'@supabase/realtime-js@2.10.2':
|
'@supabase/realtime-js@2.10.2(bufferutil@4.0.8)(utf-8-validate@6.0.4)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@supabase/node-fetch': 2.6.15
|
'@supabase/node-fetch': 2.6.15
|
||||||
'@types/phoenix': 1.6.5
|
'@types/phoenix': 1.6.5
|
||||||
'@types/ws': 8.5.12
|
'@types/ws': 8.5.12
|
||||||
ws: 8.18.0
|
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- bufferutil
|
- bufferutil
|
||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
|
@ -7819,13 +7917,13 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@supabase/node-fetch': 2.6.15
|
'@supabase/node-fetch': 2.6.15
|
||||||
|
|
||||||
'@supabase/supabase-js@2.45.4':
|
'@supabase/supabase-js@2.45.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@supabase/auth-js': 2.65.0
|
'@supabase/auth-js': 2.65.0
|
||||||
'@supabase/functions-js': 2.4.1
|
'@supabase/functions-js': 2.4.1
|
||||||
'@supabase/node-fetch': 2.6.15
|
'@supabase/node-fetch': 2.6.15
|
||||||
'@supabase/postgrest-js': 1.16.1
|
'@supabase/postgrest-js': 1.16.1
|
||||||
'@supabase/realtime-js': 2.10.2
|
'@supabase/realtime-js': 2.10.2(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||||
'@supabase/storage-js': 2.7.0
|
'@supabase/storage-js': 2.7.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- bufferutil
|
- bufferutil
|
||||||
|
@ -8213,13 +8311,13 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@waku/sdk@0.0.26(@libp2p/interface@1.7.0)(@waku/core@0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4))(@waku/enr@0.0.21)(@waku/interfaces@0.0.22)(@waku/message-hash@0.1.16)(@waku/relay@0.0.11(@waku/core@0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4))(@waku/interfaces@0.0.22)(@waku/proto@0.0.7)(@waku/utils@0.0.20))(@waku/utils@0.0.20)':
|
'@waku/sdk@0.0.26(@libp2p/interface@1.7.0)(@waku/core@0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4))(@waku/enr@0.0.21)(@waku/interfaces@0.0.22)(@waku/message-hash@0.1.16)(@waku/relay@0.0.11(@waku/core@0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4))(@waku/interfaces@0.0.22)(@waku/proto@0.0.7)(@waku/utils@0.0.20))(@waku/utils@0.0.20)(bufferutil@4.0.8)(utf-8-validate@6.0.4)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@chainsafe/libp2p-noise': 14.1.0
|
'@chainsafe/libp2p-noise': 14.1.0
|
||||||
'@libp2p/identify': 1.0.21
|
'@libp2p/identify': 1.0.21
|
||||||
'@libp2p/mplex': 10.1.5
|
'@libp2p/mplex': 10.1.5
|
||||||
'@libp2p/ping': 1.1.6
|
'@libp2p/ping': 1.1.6
|
||||||
'@libp2p/websockets': 8.2.0
|
'@libp2p/websockets': 8.2.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||||
'@noble/hashes': 1.5.0
|
'@noble/hashes': 1.5.0
|
||||||
'@waku/core': 0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4)
|
'@waku/core': 0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4)
|
||||||
'@waku/discovery': 0.0.3(@libp2p/interface@1.7.0)(@waku/core@0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4))(@waku/enr@0.0.21)(@waku/interfaces@0.0.22)(@waku/proto@0.0.7)(@waku/utils@0.0.20)
|
'@waku/discovery': 0.0.3(@libp2p/interface@1.7.0)(@waku/core@0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4))(@waku/enr@0.0.21)(@waku/interfaces@0.0.22)(@waku/proto@0.0.7)(@waku/utils@0.0.20)
|
||||||
|
@ -8267,6 +8365,17 @@ snapshots:
|
||||||
|
|
||||||
'@webext-core/match-patterns@1.0.3': {}
|
'@webext-core/match-patterns@1.0.3': {}
|
||||||
|
|
||||||
|
'@webext-core/messaging@1.4.0':
|
||||||
|
dependencies:
|
||||||
|
serialize-error: 11.0.3
|
||||||
|
webextension-polyfill: 0.10.0
|
||||||
|
|
||||||
|
'@webext-core/proxy-service@1.2.0(@webext-core/messaging@1.4.0)(webextension-polyfill@0.12.0)':
|
||||||
|
dependencies:
|
||||||
|
'@webext-core/messaging': 1.4.0
|
||||||
|
get-value: 3.0.1
|
||||||
|
webextension-polyfill: 0.12.0
|
||||||
|
|
||||||
'@xobotyi/scrollbar-width@1.9.5': {}
|
'@xobotyi/scrollbar-width@1.9.5': {}
|
||||||
|
|
||||||
JSONStream@1.3.5:
|
JSONStream@1.3.5:
|
||||||
|
@ -8482,6 +8591,10 @@ snapshots:
|
||||||
base64-js: 1.5.1
|
base64-js: 1.5.1
|
||||||
ieee754: 1.2.1
|
ieee754: 1.2.1
|
||||||
|
|
||||||
|
bufferutil@4.0.8:
|
||||||
|
dependencies:
|
||||||
|
node-gyp-build: 4.8.2
|
||||||
|
|
||||||
bundle-name@3.0.0:
|
bundle-name@3.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
run-applescript: 5.0.0
|
run-applescript: 5.0.0
|
||||||
|
@ -9011,6 +9124,20 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
once: 1.4.0
|
once: 1.4.0
|
||||||
|
|
||||||
|
engine.io-client@6.6.1(bufferutil@4.0.8)(utf-8-validate@6.0.4):
|
||||||
|
dependencies:
|
||||||
|
'@socket.io/component-emitter': 3.1.2
|
||||||
|
debug: 4.3.7
|
||||||
|
engine.io-parser: 5.2.3
|
||||||
|
ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||||
|
xmlhttprequest-ssl: 2.1.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- bufferutil
|
||||||
|
- supports-color
|
||||||
|
- utf-8-validate
|
||||||
|
|
||||||
|
engine.io-parser@5.2.3: {}
|
||||||
|
|
||||||
entities@4.5.0: {}
|
entities@4.5.0: {}
|
||||||
|
|
||||||
env-paths@2.2.1: {}
|
env-paths@2.2.1: {}
|
||||||
|
@ -9669,6 +9796,10 @@ snapshots:
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
get-intrinsic: 1.2.4
|
get-intrinsic: 1.2.4
|
||||||
|
|
||||||
|
get-value@3.0.1:
|
||||||
|
dependencies:
|
||||||
|
isobject: 3.0.1
|
||||||
|
|
||||||
giget@1.2.3:
|
giget@1.2.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
citty: 0.1.6
|
citty: 0.1.6
|
||||||
|
@ -10209,13 +10340,13 @@ snapshots:
|
||||||
|
|
||||||
it-take@3.0.6: {}
|
it-take@3.0.6: {}
|
||||||
|
|
||||||
it-ws@6.1.5:
|
it-ws@6.1.5(bufferutil@4.0.8)(utf-8-validate@6.0.4):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/ws': 8.5.12
|
'@types/ws': 8.5.12
|
||||||
event-iterator: 2.0.0
|
event-iterator: 2.0.0
|
||||||
it-stream-types: 2.0.2
|
it-stream-types: 2.0.2
|
||||||
uint8arrays: 5.1.0
|
uint8arrays: 5.1.0
|
||||||
ws: 8.18.0
|
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- bufferutil
|
- bufferutil
|
||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
|
@ -10932,7 +11063,7 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
mqtt@5.10.1:
|
mqtt@5.10.1(bufferutil@4.0.8)(utf-8-validate@6.0.4):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/readable-stream': 4.0.15
|
'@types/readable-stream': 4.0.15
|
||||||
'@types/ws': 8.5.12
|
'@types/ws': 8.5.12
|
||||||
|
@ -10949,7 +11080,7 @@ snapshots:
|
||||||
rfdc: 1.4.1
|
rfdc: 1.4.1
|
||||||
split2: 4.2.0
|
split2: 4.2.0
|
||||||
worker-timers: 7.1.8
|
worker-timers: 7.1.8
|
||||||
ws: 8.18.0
|
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- bufferutil
|
- bufferutil
|
||||||
- supports-color
|
- supports-color
|
||||||
|
@ -11044,6 +11175,8 @@ snapshots:
|
||||||
|
|
||||||
node-forge@1.3.1: {}
|
node-forge@1.3.1: {}
|
||||||
|
|
||||||
|
node-gyp-build@4.8.2: {}
|
||||||
|
|
||||||
node-notifier@10.0.1:
|
node-notifier@10.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
growly: 1.3.0
|
growly: 1.3.0
|
||||||
|
@ -11863,6 +11996,10 @@ snapshots:
|
||||||
|
|
||||||
semver@7.6.3: {}
|
semver@7.6.3: {}
|
||||||
|
|
||||||
|
serialize-error@11.0.3:
|
||||||
|
dependencies:
|
||||||
|
type-fest: 2.19.0
|
||||||
|
|
||||||
serialize-error@9.1.1:
|
serialize-error@9.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
type-fest: 2.19.0
|
type-fest: 2.19.0
|
||||||
|
@ -11945,6 +12082,24 @@ snapshots:
|
||||||
ansi-styles: 6.2.1
|
ansi-styles: 6.2.1
|
||||||
is-fullwidth-code-point: 5.0.0
|
is-fullwidth-code-point: 5.0.0
|
||||||
|
|
||||||
|
socket.io-client@4.8.0(bufferutil@4.0.8)(utf-8-validate@6.0.4):
|
||||||
|
dependencies:
|
||||||
|
'@socket.io/component-emitter': 3.1.2
|
||||||
|
debug: 4.3.7
|
||||||
|
engine.io-client: 6.6.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||||
|
socket.io-parser: 4.2.4
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- bufferutil
|
||||||
|
- supports-color
|
||||||
|
- utf-8-validate
|
||||||
|
|
||||||
|
socket.io-parser@4.2.4:
|
||||||
|
dependencies:
|
||||||
|
'@socket.io/component-emitter': 3.1.2
|
||||||
|
debug: 4.3.7
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
sonner@1.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
sonner@1.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
react: 18.3.1
|
react: 18.3.1
|
||||||
|
@ -12246,16 +12401,16 @@ snapshots:
|
||||||
|
|
||||||
trough@2.2.0: {}
|
trough@2.2.0: {}
|
||||||
|
|
||||||
trystero@0.20.0(@libp2p/interface@1.7.0)(@waku/core@0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4))(@waku/enr@0.0.21)(@waku/interfaces@0.0.22)(@waku/message-hash@0.1.16)(@waku/proto@0.0.7)(@waku/relay@0.0.11(@waku/core@0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4))(@waku/interfaces@0.0.22)(@waku/proto@0.0.7)(@waku/utils@0.0.20))(@waku/utils@0.0.20):
|
trystero@0.20.0(@libp2p/interface@1.7.0)(@waku/core@0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4))(@waku/enr@0.0.21)(@waku/interfaces@0.0.22)(@waku/message-hash@0.1.16)(@waku/proto@0.0.7)(@waku/relay@0.0.11(@waku/core@0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4))(@waku/interfaces@0.0.22)(@waku/proto@0.0.7)(@waku/utils@0.0.20))(@waku/utils@0.0.20)(bufferutil@4.0.8)(utf-8-validate@6.0.4):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@noble/curves': 1.6.0
|
'@noble/curves': 1.6.0
|
||||||
'@supabase/supabase-js': 2.45.4
|
'@supabase/supabase-js': 2.45.4(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||||
'@thaunknown/simple-peer': 10.0.10
|
'@thaunknown/simple-peer': 10.0.10
|
||||||
'@waku/discovery': 0.0.3(@libp2p/interface@1.7.0)(@waku/core@0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4))(@waku/enr@0.0.21)(@waku/interfaces@0.0.22)(@waku/proto@0.0.7)(@waku/utils@0.0.20)
|
'@waku/discovery': 0.0.3(@libp2p/interface@1.7.0)(@waku/core@0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4))(@waku/enr@0.0.21)(@waku/interfaces@0.0.22)(@waku/proto@0.0.7)(@waku/utils@0.0.20)
|
||||||
'@waku/sdk': 0.0.26(@libp2p/interface@1.7.0)(@waku/core@0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4))(@waku/enr@0.0.21)(@waku/interfaces@0.0.22)(@waku/message-hash@0.1.16)(@waku/relay@0.0.11(@waku/core@0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4))(@waku/interfaces@0.0.22)(@waku/proto@0.0.7)(@waku/utils@0.0.20))(@waku/utils@0.0.20)
|
'@waku/sdk': 0.0.26(@libp2p/interface@1.7.0)(@waku/core@0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4))(@waku/enr@0.0.21)(@waku/interfaces@0.0.22)(@waku/message-hash@0.1.16)(@waku/relay@0.0.11(@waku/core@0.0.27(@multiformats/multiaddr@12.3.1)(libp2p@1.9.4))(@waku/interfaces@0.0.22)(@waku/proto@0.0.7)(@waku/utils@0.0.20))(@waku/utils@0.0.20)(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||||
firebase: 10.13.1
|
firebase: 10.13.1
|
||||||
libp2p: 1.9.4
|
libp2p: 1.9.4
|
||||||
mqtt: 5.10.1
|
mqtt: 5.10.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@libp2p/bootstrap'
|
- '@libp2p/bootstrap'
|
||||||
- '@libp2p/interface'
|
- '@libp2p/interface'
|
||||||
|
@ -12541,6 +12696,10 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
react: 18.3.1
|
react: 18.3.1
|
||||||
|
|
||||||
|
utf-8-validate@6.0.4:
|
||||||
|
dependencies:
|
||||||
|
node-gyp-build: 4.8.2
|
||||||
|
|
||||||
utf8-bytes@0.0.1: {}
|
utf8-bytes@0.0.1: {}
|
||||||
|
|
||||||
utf8-codec@1.0.0: {}
|
utf8-codec@1.0.0: {}
|
||||||
|
@ -12614,7 +12773,7 @@ snapshots:
|
||||||
ms: 3.0.0-canary.1
|
ms: 3.0.0-canary.1
|
||||||
supports-color: 9.4.0
|
supports-color: 9.4.0
|
||||||
|
|
||||||
web-ext-run@0.2.1:
|
web-ext-run@0.2.1(bufferutil@4.0.8)(utf-8-validate@6.0.4):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.24.7
|
'@babel/runtime': 7.24.7
|
||||||
'@devicefarmer/adbkit': 3.2.6
|
'@devicefarmer/adbkit': 3.2.6
|
||||||
|
@ -12638,7 +12797,7 @@ snapshots:
|
||||||
tmp: 0.2.3
|
tmp: 0.2.3
|
||||||
update-notifier: 6.0.2
|
update-notifier: 6.0.2
|
||||||
watchpack: 2.4.1
|
watchpack: 2.4.1
|
||||||
ws: 8.18.0
|
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||||
zip-dir: 2.0.0
|
zip-dir: 2.0.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- bufferutil
|
- bufferutil
|
||||||
|
@ -12653,6 +12812,8 @@ snapshots:
|
||||||
tiny-uid: 1.1.2
|
tiny-uid: 1.1.2
|
||||||
webextension-polyfill: 0.9.0
|
webextension-polyfill: 0.9.0
|
||||||
|
|
||||||
|
webextension-polyfill@0.10.0: {}
|
||||||
|
|
||||||
webextension-polyfill@0.12.0: {}
|
webextension-polyfill@0.12.0: {}
|
||||||
|
|
||||||
webextension-polyfill@0.9.0: {}
|
webextension-polyfill@0.9.0: {}
|
||||||
|
@ -12768,9 +12929,17 @@ snapshots:
|
||||||
signal-exit: 3.0.7
|
signal-exit: 3.0.7
|
||||||
typedarray-to-buffer: 3.1.5
|
typedarray-to-buffer: 3.1.5
|
||||||
|
|
||||||
ws@8.18.0: {}
|
ws@8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4):
|
||||||
|
optionalDependencies:
|
||||||
|
bufferutil: 4.0.8
|
||||||
|
utf-8-validate: 6.0.4
|
||||||
|
|
||||||
wxt@0.19.9(@types/node@22.5.5)(rollup@4.21.3):
|
ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4):
|
||||||
|
optionalDependencies:
|
||||||
|
bufferutil: 4.0.8
|
||||||
|
utf-8-validate: 6.0.4
|
||||||
|
|
||||||
|
wxt@0.19.9(@types/node@22.5.5)(bufferutil@4.0.8)(rollup@4.21.3)(utf-8-validate@6.0.4):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@aklinker1/rollup-plugin-visualizer': 5.12.0(rollup@4.21.3)
|
'@aklinker1/rollup-plugin-visualizer': 5.12.0(rollup@4.21.3)
|
||||||
'@types/chrome': 0.0.269
|
'@types/chrome': 0.0.269
|
||||||
|
@ -12814,7 +12983,7 @@ snapshots:
|
||||||
unimport: 3.12.0(rollup@4.21.3)
|
unimport: 3.12.0(rollup@4.21.3)
|
||||||
vite: 5.4.5(@types/node@22.5.5)
|
vite: 5.4.5(@types/node@22.5.5)
|
||||||
vite-node: 2.1.1(@types/node@22.5.5)
|
vite-node: 2.1.1(@types/node@22.5.5)
|
||||||
web-ext-run: 0.2.1
|
web-ext-run: 0.2.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||||
webextension-polyfill: 0.12.0
|
webextension-polyfill: 0.12.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/node'
|
- '@types/node'
|
||||||
|
@ -12840,6 +13009,8 @@ snapshots:
|
||||||
|
|
||||||
xmlbuilder@11.0.1: {}
|
xmlbuilder@11.0.1: {}
|
||||||
|
|
||||||
|
xmlhttprequest-ssl@2.1.1: {}
|
||||||
|
|
||||||
y18n@5.0.8: {}
|
y18n@5.0.8: {}
|
||||||
|
|
||||||
yallist@3.1.1: {}
|
yallist@3.1.1: {}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { EVENT } from '@/constants/event'
|
||||||
import { browser } from 'wxt/browser'
|
import { browser } from 'wxt/browser'
|
||||||
import { defineBackground } from 'wxt/sandbox'
|
import { defineBackground } from 'wxt/sandbox'
|
||||||
|
|
||||||
|
@ -7,8 +8,10 @@ export default defineBackground({
|
||||||
type: 'module',
|
type: 'module',
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
browser.runtime.onMessage.addListener(async () => {
|
browser.runtime.onMessage.addListener(async (event: EVENT) => {
|
||||||
browser.runtime.openOptionsPage()
|
if (event === EVENT.OPEN_OPTIONS_PAGE) {
|
||||||
|
browser.runtime.openOptionsPage()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,15 +5,12 @@ import AppButton from '@/app/content/views/AppButton'
|
||||||
import AppContainer from '@/app/content/views/AppContainer'
|
import AppContainer from '@/app/content/views/AppContainer'
|
||||||
import { useRemeshDomain, useRemeshQuery, useRemeshSend } from 'remesh-react'
|
import { useRemeshDomain, useRemeshQuery, useRemeshSend } from 'remesh-react'
|
||||||
import RoomDomain from '@/domain/Room'
|
import RoomDomain from '@/domain/Room'
|
||||||
import { stringToHex } from '@/utils'
|
|
||||||
import { Toaster } from '@/components/ui/Sonner'
|
import { Toaster } from '@/components/ui/Sonner'
|
||||||
import UserInfoDomain from '@/domain/UserInfo'
|
import UserInfoDomain from '@/domain/UserInfo'
|
||||||
import Setup from '@/app/content/views/Setup'
|
import Setup from '@/app/content/views/Setup'
|
||||||
import MessageListDomain from '@/domain/MessageList'
|
import MessageListDomain from '@/domain/MessageList'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
const hostRoomId = stringToHex(document.location.host)
|
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const send = useRemeshSend()
|
const send = useRemeshSend()
|
||||||
const roomDomain = useRemeshDomain(RoomDomain())
|
const roomDomain = useRemeshDomain(RoomDomain())
|
||||||
|
@ -29,7 +26,7 @@ export default function App() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (userInfoFinished) {
|
if (userInfoFinished) {
|
||||||
if (userInfo) {
|
if (userInfo) {
|
||||||
!roomFinished && send(roomDomain.command.JoinRoomCommand(hostRoomId))
|
!roomFinished && send(roomDomain.command.JoinRoomCommand())
|
||||||
} else {
|
} else {
|
||||||
send(messageListDomain.command.ClearListCommand())
|
send(messageListDomain.command.ClearListCommand())
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ export interface PromptItemProps {
|
||||||
|
|
||||||
const PromptItem: FC<PromptItemProps> = ({ data, className }) => {
|
const PromptItem: FC<PromptItemProps> = ({ data, className }) => {
|
||||||
return (
|
return (
|
||||||
<div className={cn('flex justify-center py-1', className)}>
|
<div className={cn('flex justify-center py-1 px-4', className)}>
|
||||||
<Badge variant="secondary" className="gap-x-2 rounded-full font-medium text-slate-400">
|
<Badge variant="secondary" className="gap-x-2 rounded-full font-medium text-slate-400">
|
||||||
<Avatar className="size-4">
|
<Avatar className="size-4">
|
||||||
<AvatarImage src={data.userAvatar} alt="avatar" />
|
<AvatarImage src={data.userAvatar} alt="avatar" />
|
||||||
|
|
|
@ -8,7 +8,8 @@ import { createShadowRootUi } from 'wxt/client'
|
||||||
|
|
||||||
import App from './App'
|
import App from './App'
|
||||||
import { IndexDBStorageImpl, BrowserSyncStorageImpl } from '@/domain/impls/Storage'
|
import { IndexDBStorageImpl, BrowserSyncStorageImpl } from '@/domain/impls/Storage'
|
||||||
import { PeerRoomImpl } from '@/domain/impls/PeerRoom'
|
// import { PeerRoomImpl } from '@/domain/impls/PeerRoom'
|
||||||
|
import { PeerRoomImpl } from '@/domain/impls/PeerRoom2'
|
||||||
import '@/assets/styles/tailwind.css'
|
import '@/assets/styles/tailwind.css'
|
||||||
import { createElement } from '@/utils'
|
import { createElement } from '@/utils'
|
||||||
import { ToastImpl } from '@/domain/impls/Toast'
|
import { ToastImpl } from '@/domain/impls/Toast'
|
||||||
|
@ -19,7 +20,7 @@ export default defineContentScript({
|
||||||
async main(ctx) {
|
async main(ctx) {
|
||||||
const store = Remesh.store({
|
const store = Remesh.store({
|
||||||
externs: [IndexDBStorageImpl, BrowserSyncStorageImpl, PeerRoomImpl, ToastImpl],
|
externs: [IndexDBStorageImpl, BrowserSyncStorageImpl, PeerRoomImpl, ToastImpl],
|
||||||
inspectors: !__DEV__ ? [RemeshLogger()] : []
|
inspectors: __DEV__ ? [RemeshLogger()] : []
|
||||||
})
|
})
|
||||||
|
|
||||||
const ui = await createShadowRootUi(ctx, {
|
const ui = await createShadowRootUi(ctx, {
|
||||||
|
|
|
@ -6,13 +6,12 @@ import { Button } from '@/components/ui/Button'
|
||||||
import { getSiteInfo } from '@/utils'
|
import { getSiteInfo } from '@/utils'
|
||||||
import { useRemeshDomain, useRemeshQuery } from 'remesh-react'
|
import { useRemeshDomain, useRemeshQuery } from 'remesh-react'
|
||||||
import RoomDomain from '@/domain/Room'
|
import RoomDomain from '@/domain/Room'
|
||||||
import { selfId } from 'trystero'
|
|
||||||
|
|
||||||
const Header: FC = () => {
|
const Header: FC = () => {
|
||||||
const siteInfo = getSiteInfo()
|
const siteInfo = getSiteInfo()
|
||||||
const roomDomain = useRemeshDomain(RoomDomain())
|
const roomDomain = useRemeshDomain(RoomDomain())
|
||||||
const userList = useRemeshQuery(roomDomain.query.UserListQuery())
|
const userList = useRemeshQuery(roomDomain.query.UserListQuery())
|
||||||
console.log('userList', [...userList], userList.length)
|
const peerId = useRemeshQuery(roomDomain.query.PeerIdQuery())
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="z-10 grid h-12 grid-flow-col items-center justify-between gap-x-4 rounded-t-xl bg-white px-4 backdrop-blur-lg">
|
<div className="z-10 grid h-12 grid-flow-col items-center justify-between gap-x-4 rounded-t-xl bg-white px-4 backdrop-blur-lg">
|
||||||
|
@ -27,7 +26,7 @@ const Header: FC = () => {
|
||||||
<Button className="overflow-hidden" variant="link">
|
<Button className="overflow-hidden" variant="link">
|
||||||
<span className="truncate text-lg font-medium text-slate-600">
|
<span className="truncate text-lg font-medium text-slate-600">
|
||||||
{/* {siteInfo.hostname.replace(/^www\./i, '')} */}
|
{/* {siteInfo.hostname.replace(/^www\./i, '')} */}
|
||||||
{selfId}
|
{peerId}
|
||||||
</span>
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
</HoverCardTrigger>
|
</HoverCardTrigger>
|
||||||
|
|
|
@ -21,8 +21,8 @@ const AvatarSelect = React.forwardRef<HTMLInputElement, AvatarSelectProps>(
|
||||||
const handleChange = async (e: ChangeEvent<HTMLInputElement>) => {
|
const handleChange = async (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
const file = e.target.files?.[0]
|
const file = e.target.files?.[0]
|
||||||
if (file) {
|
if (file) {
|
||||||
if (!/image\/(png|jpeg)/.test(file.type)) {
|
if (!/image\/(png|jpeg|webp)/.test(file.type)) {
|
||||||
onWarning?.(new Error('Only PNG and JPEG image are supported.'))
|
onWarning?.(new Error('Only PNG, JPEG and WebP image are supported.'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ const formSchema = v.object({
|
||||||
avatar: v.pipe(
|
avatar: v.pipe(
|
||||||
v.string(),
|
v.string(),
|
||||||
v.notLength(0, 'Please select your avatar.'),
|
v.notLength(0, 'Please select your avatar.'),
|
||||||
v.maxBytes(8 * 1024, 'Your avatar cannot exceed 8kb.')
|
v.maxBytes(8 * 1024, `Your avatar cannot exceed 8kb.`)
|
||||||
),
|
),
|
||||||
themeMode: v.pipe(
|
themeMode: v.pipe(
|
||||||
v.string(),
|
v.string(),
|
||||||
|
@ -92,32 +92,24 @@ const ProfileForm = () => {
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="avatar"
|
name="avatar"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="absolute left-1/2 top-0 grid -translate-x-1/2 -translate-y-1/2 justify-items-center">
|
<FormItem className="absolute inset-x-1 top-0 mx-auto grid w-fit -translate-y-1/2 justify-items-center">
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="grid justify-items-center gap-y-2">
|
<AvatarSelect
|
||||||
<AvatarSelect
|
compressSize={MAX_AVATAR_SIZE}
|
||||||
compressSize={MAX_AVATAR_SIZE}
|
onError={handleError}
|
||||||
onError={handleError}
|
onWarning={handleWarning}
|
||||||
onWarning={handleWarning}
|
className="shadow-lg"
|
||||||
className="shadow-lg"
|
{...field}
|
||||||
{...field}
|
></AvatarSelect>
|
||||||
></AvatarSelect>
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
size="xs"
|
|
||||||
className="mx-auto flex items-center gap-x-2"
|
|
||||||
onClick={handleRefreshAvatar}
|
|
||||||
>
|
|
||||||
<RefreshCcwIcon size={14} />
|
|
||||||
Ugly Avatar
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<Button type="button" size="xs" className="mx-auto flex items-center gap-x-2" onClick={handleRefreshAvatar}>
|
||||||
|
<RefreshCcwIcon size={14} />
|
||||||
|
Ugly Avatar
|
||||||
|
</Button>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="name"
|
name="name"
|
||||||
|
|
|
@ -194,4 +194,4 @@ export const STORAGE_NAME = 'WEB_CHAT' as const
|
||||||
* Image is encoded as base64, and the size is increased by about 33%.
|
* Image is encoded as base64, and the size is increased by about 33%.
|
||||||
* 8kb * (1 - 0.33) = 5488 bytes
|
* 8kb * (1 - 0.33) = 5488 bytes
|
||||||
*/
|
*/
|
||||||
export const MAX_AVATAR_SIZE = 5488 as const
|
export const MAX_AVATAR_SIZE = 5120 as const
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Remesh } from 'remesh'
|
import { Remesh } from 'remesh'
|
||||||
import { map, merge, switchMap, tap, of, EMPTY, mergeMap } from 'rxjs'
|
import { map, merge, of, EMPTY, mergeMap } from 'rxjs'
|
||||||
import { NormalMessage, type MessageUser } from './MessageList'
|
import { NormalMessage, type MessageUser } from './MessageList'
|
||||||
import { PeerRoomExtern } from '@/domain/externs/PeerRoom'
|
import { PeerRoomExtern } from '@/domain/externs/PeerRoom'
|
||||||
import MessageListDomain, { MessageType } from '@/domain/MessageList'
|
import MessageListDomain, { MessageType } from '@/domain/MessageList'
|
||||||
|
@ -51,6 +51,18 @@ const RoomDomain = Remesh.domain({
|
||||||
const userInfoDomain = domain.getDomain(UserInfoDomain())
|
const userInfoDomain = domain.getDomain(UserInfoDomain())
|
||||||
const peerRoom = domain.getExtern(PeerRoomExtern)
|
const peerRoom = domain.getExtern(PeerRoomExtern)
|
||||||
|
|
||||||
|
const PeerIdState = domain.state<string>({
|
||||||
|
name: 'Room.PeerIdState',
|
||||||
|
default: peerRoom.peerId
|
||||||
|
})
|
||||||
|
|
||||||
|
const PeerIdQuery = domain.query({
|
||||||
|
name: 'Room.PeerIdQuery',
|
||||||
|
impl: ({ get }) => {
|
||||||
|
return get(PeerIdState())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const MessageListQuery = messageListDomain.query.ListQuery
|
const MessageListQuery = messageListDomain.query.ListQuery
|
||||||
|
|
||||||
const RoomStatusModule = StatusModule(domain, {
|
const RoomStatusModule = StatusModule(domain, {
|
||||||
|
@ -71,16 +83,17 @@ const RoomDomain = Remesh.domain({
|
||||||
|
|
||||||
const JoinRoomCommand = domain.command({
|
const JoinRoomCommand = domain.command({
|
||||||
name: 'RoomJoinRoomCommand',
|
name: 'RoomJoinRoomCommand',
|
||||||
impl: ({ get }, roomId: string) => {
|
impl: ({ get }) => {
|
||||||
peerRoom.joinRoom(roomId)
|
peerRoom.joinRoom()
|
||||||
const { id: userId, name: username, avatar: userAvatar } = get(userInfoDomain.query.UserInfoQuery())!
|
const { id: userId, name: username, avatar: userAvatar } = get(userInfoDomain.query.UserInfoQuery())!
|
||||||
|
|
||||||
return [
|
return [
|
||||||
JoinRoomEvent(roomId),
|
|
||||||
RoomStatusModule.command.SetFinishedCommand(),
|
|
||||||
UpdateUserListCommand({
|
UpdateUserListCommand({
|
||||||
type: 'create',
|
type: 'create',
|
||||||
user: { peerId: peerRoom.selfId, joinTime: Date.now(), userId, username, userAvatar }
|
user: { peerId: peerRoom.peerId, joinTime: Date.now(), userId, username, userAvatar }
|
||||||
})
|
}),
|
||||||
|
RoomStatusModule.command.SetFinishedCommand(),
|
||||||
|
JoinRoomEvent(peerRoom.roomId)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -91,12 +104,12 @@ const RoomDomain = Remesh.domain({
|
||||||
peerRoom.leaveRoom()
|
peerRoom.leaveRoom()
|
||||||
const { id: userId, name: username, avatar: userAvatar } = get(userInfoDomain.query.UserInfoQuery())!
|
const { id: userId, name: username, avatar: userAvatar } = get(userInfoDomain.query.UserInfoQuery())!
|
||||||
return [
|
return [
|
||||||
LeaveRoomEvent(roomId),
|
|
||||||
RoomStatusModule.command.SetInitialCommand(),
|
|
||||||
UpdateUserListCommand({
|
UpdateUserListCommand({
|
||||||
type: 'delete',
|
type: 'delete',
|
||||||
user: { peerId: peerRoom.selfId, joinTime: Date.now(), userId, username, userAvatar }
|
user: { peerId: peerRoom.peerId, joinTime: Date.now(), userId, username, userAvatar }
|
||||||
})
|
}),
|
||||||
|
RoomStatusModule.command.SetInitialCommand(),
|
||||||
|
LeaveRoomEvent(roomId)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -105,22 +118,26 @@ const RoomDomain = Remesh.domain({
|
||||||
name: 'RoomSendTextMessageCommand',
|
name: 'RoomSendTextMessageCommand',
|
||||||
impl: ({ get }, message: string) => {
|
impl: ({ get }, message: string) => {
|
||||||
const { id: userId, name: username, avatar: userAvatar } = get(userInfoDomain.query.UserInfoQuery())!
|
const { id: userId, name: username, avatar: userAvatar } = get(userInfoDomain.query.UserInfoQuery())!
|
||||||
const id = nanoid()
|
|
||||||
const date = Date.now()
|
const textMessage: TextMessage = {
|
||||||
return [
|
id: nanoid(),
|
||||||
messageListDomain.command.CreateItemCommand({
|
type: SendType.Text,
|
||||||
id,
|
body: message,
|
||||||
type: MessageType.Normal,
|
userId,
|
||||||
body: message,
|
username,
|
||||||
date,
|
userAvatar
|
||||||
userId,
|
}
|
||||||
username,
|
|
||||||
userAvatar,
|
const listMessage: NormalMessage = {
|
||||||
likeUsers: [],
|
...textMessage,
|
||||||
hateUsers: []
|
type: MessageType.Normal,
|
||||||
}),
|
date: Date.now(),
|
||||||
SendTextMessageEvent({ id, body: message, userId, username, userAvatar, type: SendType.Text })
|
likeUsers: [],
|
||||||
]
|
hateUsers: []
|
||||||
|
}
|
||||||
|
|
||||||
|
peerRoom.sendMessage<RoomMessage>(textMessage)
|
||||||
|
return [messageListDomain.command.CreateItemCommand(listMessage), SendTextMessageEvent(textMessage)]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -128,28 +145,23 @@ const RoomDomain = Remesh.domain({
|
||||||
name: 'RoomSendLikeMessageCommand',
|
name: 'RoomSendLikeMessageCommand',
|
||||||
impl: ({ get }, messageId: string) => {
|
impl: ({ get }, messageId: string) => {
|
||||||
const { id: userId, name: username, avatar: userAvatar } = get(userInfoDomain.query.UserInfoQuery())!
|
const { id: userId, name: username, avatar: userAvatar } = get(userInfoDomain.query.UserInfoQuery())!
|
||||||
const _message = get(messageListDomain.query.ItemQuery(messageId)) as NormalMessage
|
const localMessage = get(messageListDomain.query.ItemQuery(messageId)) as NormalMessage
|
||||||
return [
|
|
||||||
messageListDomain.command.UpdateItemCommand({
|
const likeMessage: LikeMessage = {
|
||||||
..._message,
|
id: messageId,
|
||||||
likeUsers: desert(
|
userId,
|
||||||
_message.likeUsers,
|
username,
|
||||||
{
|
userAvatar,
|
||||||
userId,
|
type: SendType.Like
|
||||||
username,
|
}
|
||||||
userAvatar
|
const listMessage: NormalMessage = {
|
||||||
},
|
...localMessage,
|
||||||
'userId'
|
type: MessageType.Normal,
|
||||||
)
|
date: Date.now(),
|
||||||
}),
|
likeUsers: desert(localMessage.likeUsers, likeMessage, 'userId')
|
||||||
SendLikeMessageEvent({
|
}
|
||||||
id: messageId,
|
peerRoom.sendMessage<RoomMessage>(likeMessage)
|
||||||
userId,
|
return [messageListDomain.command.UpdateItemCommand(listMessage), SendLikeMessageEvent(likeMessage)]
|
||||||
username,
|
|
||||||
userAvatar,
|
|
||||||
type: SendType.Like
|
|
||||||
})
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -157,47 +169,55 @@ const RoomDomain = Remesh.domain({
|
||||||
name: 'RoomSendHateMessageCommand',
|
name: 'RoomSendHateMessageCommand',
|
||||||
impl: ({ get }, messageId: string) => {
|
impl: ({ get }, messageId: string) => {
|
||||||
const { id: userId, name: username, avatar: userAvatar } = get(userInfoDomain.query.UserInfoQuery())!
|
const { id: userId, name: username, avatar: userAvatar } = get(userInfoDomain.query.UserInfoQuery())!
|
||||||
const _message = get(messageListDomain.query.ItemQuery(messageId)) as NormalMessage
|
const localMessage = get(messageListDomain.query.ItemQuery(messageId)) as NormalMessage
|
||||||
|
|
||||||
return [
|
const hateMessage: HateMessage = {
|
||||||
messageListDomain.command.UpdateItemCommand({
|
id: messageId,
|
||||||
..._message,
|
userId,
|
||||||
hateUsers: desert(
|
username,
|
||||||
_message.hateUsers,
|
userAvatar,
|
||||||
{
|
type: SendType.Hate
|
||||||
userId,
|
}
|
||||||
username,
|
const listMessage: NormalMessage = {
|
||||||
userAvatar
|
...localMessage,
|
||||||
},
|
type: MessageType.Normal,
|
||||||
'userId'
|
date: Date.now(),
|
||||||
)
|
hateUsers: desert(localMessage.hateUsers, hateMessage, 'userId')
|
||||||
}),
|
}
|
||||||
SendHateMessageEvent({ id: messageId, userId, username, userAvatar, type: SendType.Hate })
|
peerRoom.sendMessage<RoomMessage>(hateMessage)
|
||||||
]
|
return [messageListDomain.command.UpdateItemCommand(listMessage), SendHateMessageEvent(hateMessage)]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const SendUserSyncMessageCommand = domain.command({
|
const SendUserSyncMessageCommand = domain.command({
|
||||||
name: 'RoomSendUserSyncMessageCommand',
|
name: 'RoomSendUserSyncMessageCommand',
|
||||||
impl: ({ get }, targetPeerId: string) => {
|
impl: ({ get }, targetPeerId: string) => {
|
||||||
const { id: userId, name: username, avatar: userAvatar } = get(userInfoDomain.query.UserInfoQuery())!
|
const self = get(UserListQuery()).find((user) => user.peerId === peerRoom.peerId)!
|
||||||
const joinTime = get(UserListQuery()).find((u) => u.peerId === peerRoom.selfId)?.joinTime || Date.now()
|
|
||||||
return [
|
const syncUserMessage: SyncUserMessage = {
|
||||||
SendUserSyncMessageEvent({
|
...self,
|
||||||
id: nanoid(),
|
id: nanoid(),
|
||||||
peerId: peerRoom.selfId,
|
type: SendType.UserSync
|
||||||
targetPeerId,
|
}
|
||||||
userId,
|
|
||||||
joinTime,
|
peerRoom.sendMessage<RoomMessage>(syncUserMessage, targetPeerId)
|
||||||
username,
|
return [SendUserSyncMessageEvent(syncUserMessage)]
|
||||||
userAvatar,
|
|
||||||
type: SendType.UserSync
|
|
||||||
})
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const SendUserSyncMessageEvent = domain.event<SyncUserMessage & { targetPeerId: string }>({
|
const UpdateUserListCommand = domain.command({
|
||||||
|
name: 'RoomUpdateUserListCommand',
|
||||||
|
impl: ({ get }, action: { type: 'create' | 'delete'; user: RoomUser }) => {
|
||||||
|
const userList = get(UserListState())
|
||||||
|
if (action.type === 'create') {
|
||||||
|
return [UserListState().new(upsert(userList, action.user, 'peerId'))]
|
||||||
|
} else {
|
||||||
|
return [UserListState().new(userList.filter(({ peerId }) => peerId !== action.user.peerId))]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const SendUserSyncMessageEvent = domain.event<SyncUserMessage>({
|
||||||
name: 'RoomSendUserSyncMessageEvent'
|
name: 'RoomSendUserSyncMessageEvent'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -233,94 +253,47 @@ const RoomDomain = Remesh.domain({
|
||||||
name: 'RoomOnLeaveRoomEvent'
|
name: 'RoomOnLeaveRoomEvent'
|
||||||
})
|
})
|
||||||
|
|
||||||
const UpdateUserListCommand = domain.command({
|
|
||||||
name: 'RoomUpdateUserListCommand',
|
|
||||||
impl: ({ get }, action: { type: 'create' | 'delete'; user: RoomUser }) => {
|
|
||||||
const userList = get(UserListState())
|
|
||||||
if (action.type === 'create') {
|
|
||||||
return [UserListState().new(upsert(userList, action.user, 'peerId'))]
|
|
||||||
} else {
|
|
||||||
return [UserListState().new(userList.filter(({ peerId }) => peerId !== action.user.peerId))]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
domain.effect({
|
domain.effect({
|
||||||
name: 'RoomSendTextMessageEffect',
|
name: 'RoomOnJoinRoomEffect',
|
||||||
impl: ({ fromEvent }) => {
|
impl: () => {
|
||||||
const sendMessage$ = fromEvent(SendTextMessageEvent).pipe(
|
const onJoinRoom$ = callbackToObservable<string>(peerRoom.onJoinRoom).pipe(
|
||||||
tap(async (message) => {
|
mergeMap((peerId) => {
|
||||||
peerRoom.sendMessage<RoomMessage>(message)
|
console.log('onJoinRoom', peerId)
|
||||||
|
if (peerRoom.peerId === peerId) {
|
||||||
|
return [OnJoinRoomEvent(peerId)]
|
||||||
|
} else {
|
||||||
|
return [SendUserSyncMessageCommand(peerId), OnJoinRoomEvent(peerId)]
|
||||||
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
return merge(sendMessage$).pipe(map(() => null))
|
return onJoinRoom$
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
domain.effect({
|
|
||||||
name: 'RoomSendLikeMessageEffect',
|
|
||||||
impl: ({ fromEvent }) => {
|
|
||||||
const likeMessage$ = fromEvent(SendLikeMessageEvent).pipe(
|
|
||||||
tap(async (message) => {
|
|
||||||
return peerRoom.sendMessage<RoomMessage>(message)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
return merge(likeMessage$).pipe(map(() => null))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
domain.effect({
|
|
||||||
name: 'RoomSendHateMessageEffect',
|
|
||||||
impl: ({ fromEvent }) => {
|
|
||||||
const hateMessage$ = fromEvent(SendHateMessageEvent).pipe(
|
|
||||||
tap(async (message) => {
|
|
||||||
peerRoom.sendMessage<RoomMessage>(message)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
return merge(hateMessage$).pipe(map(() => null))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
domain.effect({
|
|
||||||
name: 'RoomSendUserSyncMessageEffect',
|
|
||||||
impl: ({ fromEvent }) => {
|
|
||||||
const userSyncMessage$ = fromEvent(SendUserSyncMessageEvent).pipe(
|
|
||||||
tap(async (message) => {
|
|
||||||
console.log('sendMessage', message)
|
|
||||||
|
|
||||||
peerRoom.sendMessage<RoomMessage>(message, message.targetPeerId)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
return merge(userSyncMessage$).pipe(map(() => null))
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
domain.effect({
|
domain.effect({
|
||||||
name: 'RoomOnMessageEffect',
|
name: 'RoomOnMessageEffect',
|
||||||
impl: ({ fromEvent, get }) => {
|
impl: ({ get }) => {
|
||||||
const onMessage$ = fromEvent(JoinRoomEvent).pipe(
|
const onMessage$ = callbackToObservable<RoomMessage>(peerRoom.onMessage).pipe(
|
||||||
switchMap(() => callbackToObservable<RoomMessage>(peerRoom.onMessage.bind(peerRoom))),
|
|
||||||
mergeMap((message) => {
|
mergeMap((message) => {
|
||||||
console.log('onMessage', message)
|
console.log('onMessage', message)
|
||||||
|
|
||||||
const messageEvent$ = of(OnMessageEvent(message))
|
const messageEvent$ = of(OnMessageEvent(message))
|
||||||
|
|
||||||
const commandEvent$ = (() => {
|
const commandEvent$ = (() => {
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
case SendType.UserSync: {
|
case SendType.UserSync: {
|
||||||
const self = get(UserListQuery()).find((user) => user.peerId === peerRoom.selfId)!
|
const self = get(UserListQuery()).find((user) => user.peerId === peerRoom.peerId)!
|
||||||
if (self.joinTime > message.joinTime) {
|
const isJoining = self.joinTime < message.joinTime
|
||||||
return EMPTY
|
|
||||||
}
|
|
||||||
return of(
|
return of(
|
||||||
UpdateUserListCommand({ type: 'create', user: message }),
|
UpdateUserListCommand({ type: 'create', user: message }),
|
||||||
messageListDomain.command.CreateItemCommand({
|
isJoining
|
||||||
...message,
|
? messageListDomain.command.CreateItemCommand({
|
||||||
id: nanoid(),
|
...message,
|
||||||
body: `"${message.username}" joined the chat`,
|
id: nanoid(),
|
||||||
type: MessageType.Prompt,
|
body: `"${message.username}" joined the chat`,
|
||||||
date: Date.now()
|
type: MessageType.Prompt,
|
||||||
})
|
date: Date.now()
|
||||||
|
})
|
||||||
|
: null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case SendType.Text:
|
case SendType.Text:
|
||||||
|
@ -356,7 +329,7 @@ const RoomDomain = Remesh.domain({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
console.warn('未知消息类型', message)
|
console.warn('Unsupported message type', message)
|
||||||
return EMPTY
|
return EMPTY
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
|
@ -367,36 +340,14 @@ const RoomDomain = Remesh.domain({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
domain.effect({
|
|
||||||
name: 'RoomOnJoinRoomEffect',
|
|
||||||
impl: ({ fromEvent, get }) => {
|
|
||||||
const onJoinRoom$ = fromEvent(JoinRoomEvent).pipe(
|
|
||||||
switchMap(() => callbackToObservable<string>(peerRoom.onJoinRoom.bind(peerRoom))),
|
|
||||||
mergeMap((peerId) => {
|
|
||||||
console.log('onJoinRoom', peerId)
|
|
||||||
const { id: userId, name: username, avatar: userAvatar } = get(userInfoDomain.query.UserInfoQuery())!
|
|
||||||
return [
|
|
||||||
SendUserSyncMessageCommand(peerId),
|
|
||||||
UpdateUserListCommand({
|
|
||||||
type: 'create',
|
|
||||||
user: { peerId, joinTime: Date.now(), userId, username, userAvatar }
|
|
||||||
}),
|
|
||||||
OnJoinRoomEvent(peerId)
|
|
||||||
]
|
|
||||||
})
|
|
||||||
)
|
|
||||||
return onJoinRoom$
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
domain.effect({
|
domain.effect({
|
||||||
name: 'RoomOnLeaveRoomEffect',
|
name: 'RoomOnLeaveRoomEffect',
|
||||||
impl: ({ fromEvent, get }) => {
|
impl: ({ get }) => {
|
||||||
const onLeaveRoom$ = fromEvent(JoinRoomEvent).pipe(
|
const onLeaveRoom$ = callbackToObservable<string>(peerRoom.onLeaveRoom).pipe(
|
||||||
switchMap(() => callbackToObservable<string>(peerRoom.onLeaveRoom.bind(peerRoom))),
|
|
||||||
map((peerId) => {
|
map((peerId) => {
|
||||||
console.log('onLeaveRoom', peerId)
|
console.log('onLeaveRoom', peerId)
|
||||||
const user = get(UserListQuery()).find((user) => user.peerId === peerId)
|
const user = get(UserListQuery()).find((user) => user.peerId === peerId)
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
return [
|
return [
|
||||||
UpdateUserListCommand({ type: 'delete', user }),
|
UpdateUserListCommand({ type: 'delete', user }),
|
||||||
|
@ -420,6 +371,7 @@ const RoomDomain = Remesh.domain({
|
||||||
|
|
||||||
return {
|
return {
|
||||||
query: {
|
query: {
|
||||||
|
PeerIdQuery,
|
||||||
UserListQuery,
|
UserListQuery,
|
||||||
MessageListQuery,
|
MessageListQuery,
|
||||||
...RoomStatusModule.query
|
...RoomStatusModule.query
|
||||||
|
|
|
@ -1,25 +1,27 @@
|
||||||
import { Remesh } from 'remesh'
|
import { Remesh } from 'remesh'
|
||||||
import { type Promisable } from 'type-fest'
|
|
||||||
|
|
||||||
export type PeerMessage = object | Blob | ArrayBuffer | ArrayBufferView
|
export type PeerMessage = object | Blob | ArrayBuffer | ArrayBufferView
|
||||||
|
|
||||||
export interface PeerRoom {
|
export interface PeerRoom {
|
||||||
readonly selfId: string
|
readonly peerId: string
|
||||||
joinRoom: (roomId: string) => Promise<any>
|
readonly roomId: string
|
||||||
sendMessage: <T extends PeerMessage>(message: T, id?: string) => Promise<any>
|
joinRoom: () => PeerRoom
|
||||||
onMessage: <T extends PeerMessage>(callback: (message: T) => void) => Promisable<void>
|
sendMessage: <T extends PeerMessage>(message: T, id?: string) => PeerRoom
|
||||||
leaveRoom: () => Promisable<void>
|
onMessage: <T extends PeerMessage>(callback: (message: T) => void) => PeerRoom
|
||||||
onJoinRoom: (callback: (id: string) => void) => Promisable<void>
|
leaveRoom: () => PeerRoom
|
||||||
onLeaveRoom: (callback: (id: string) => void) => Promisable<void>
|
onJoinRoom: (callback: (id: string) => void) => PeerRoom
|
||||||
|
onLeaveRoom: (callback: (id: string) => void) => PeerRoom
|
||||||
|
onError: (callback: (error: Error) => void) => PeerRoom
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PeerRoomExtern = Remesh.extern<PeerRoom>({
|
export const PeerRoomExtern = Remesh.extern<PeerRoom>({
|
||||||
default: {
|
default: {
|
||||||
selfId: '',
|
peerId: '',
|
||||||
joinRoom: async () => {
|
roomId: '',
|
||||||
|
joinRoom: () => {
|
||||||
throw new Error('"joinRoom" not implemented.')
|
throw new Error('"joinRoom" not implemented.')
|
||||||
},
|
},
|
||||||
sendMessage: async () => {
|
sendMessage: () => {
|
||||||
throw new Error('"sendMessage" not implemented.')
|
throw new Error('"sendMessage" not implemented.')
|
||||||
},
|
},
|
||||||
onMessage: () => {
|
onMessage: () => {
|
||||||
|
@ -33,6 +35,9 @@ export const PeerRoomExtern = Remesh.extern<PeerRoom>({
|
||||||
},
|
},
|
||||||
onLeaveRoom: () => {
|
onLeaveRoom: () => {
|
||||||
throw new Error('"onLeaveRoom" not implemented.')
|
throw new Error('"onLeaveRoom" not implemented.')
|
||||||
|
},
|
||||||
|
onError: () => {
|
||||||
|
throw new Error('"onError" not implemented.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,64 +1,151 @@
|
||||||
import { type DataPayload, type Room, joinRoom, selfId } from 'trystero'
|
import { type DataPayload, type Room, joinRoom, selfId } from 'trystero'
|
||||||
|
|
||||||
// import { joinRoom } from 'trystero/firebase'
|
// import { joinRoom } from 'trystero/firebase'
|
||||||
|
|
||||||
import { PeerRoomExtern, type PeerMessage } from '@/domain/externs/PeerRoom'
|
import { PeerRoomExtern, type PeerMessage } from '@/domain/externs/PeerRoom'
|
||||||
import { stringToHex } from '@/utils'
|
import { stringToHex } from '@/utils'
|
||||||
|
import EventHub from '@resreq/event-hub'
|
||||||
|
|
||||||
export interface Config {
|
export interface Config {
|
||||||
appId: string
|
peerId?: string
|
||||||
|
roomId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
class PeerRoom {
|
class PeerRoom extends EventHub {
|
||||||
readonly appId: string
|
readonly appId: string
|
||||||
room: Room | null
|
private room?: Room
|
||||||
readonly selfId: string
|
readonly roomId: string
|
||||||
|
readonly peerId: string
|
||||||
constructor(config: Config) {
|
constructor(config: Config) {
|
||||||
this.appId = config.appId
|
super()
|
||||||
this.room = null
|
this.appId = __NAME__
|
||||||
this.selfId = selfId
|
this.roomId = config.roomId
|
||||||
|
this.peerId = selfId
|
||||||
|
this.joinRoom = this.joinRoom.bind(this)
|
||||||
|
this.sendMessage = this.sendMessage.bind(this)
|
||||||
|
this.onMessage = this.onMessage.bind(this)
|
||||||
|
this.onJoinRoom = this.onJoinRoom.bind(this)
|
||||||
|
this.onLeaveRoom = this.onLeaveRoom.bind(this)
|
||||||
|
this.leaveRoom = this.leaveRoom.bind(this)
|
||||||
|
this.onError = this.onError.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
async joinRoom(roomId: string) {
|
joinRoom() {
|
||||||
this.room = joinRoom({ appId: this.appId }, roomId)
|
this.room = joinRoom({ appId: this.appId }, this.roomId)
|
||||||
|
/**
|
||||||
return this.room
|
* If we wait to join, it will result in not being able to listen to our own join event.
|
||||||
|
* This might be related to the fact that:
|
||||||
|
* (If called more than once, only the latest callback registered is ever called.)
|
||||||
|
* Multiple listeners may overwrite each other.
|
||||||
|
* @see: https://github.com/dmotz/trystero?tab=readme-ov-file#onpeerjoincallback
|
||||||
|
*/
|
||||||
|
// this.room.onPeerJoin(() => this.emit('action'))
|
||||||
|
this.emit('action')
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendMessage<T extends PeerMessage>(message: T, id?: string) {
|
sendMessage<T extends PeerMessage>(message: T, id?: string) {
|
||||||
if (!this.room) {
|
if (!this.room) {
|
||||||
throw new Error('Room not joined')
|
this.once('action', () => {
|
||||||
|
if (!this.room) {
|
||||||
|
const error = new Error('Room not joined')
|
||||||
|
this.emit('error', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
const [send] = this.room.makeAction('MESSAGE')
|
||||||
|
send(message as DataPayload, id)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const [send] = this.room.makeAction('MESSAGE')
|
||||||
|
send(message as DataPayload, id)
|
||||||
}
|
}
|
||||||
const [send] = this.room!.makeAction('MESSAGE')
|
|
||||||
return await send(message as DataPayload, id)
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
onMessage<T extends PeerMessage>(callback: (message: T) => void) {
|
onMessage<T extends PeerMessage>(callback: (message: T) => void) {
|
||||||
if (!this.room) {
|
if (!this.room) {
|
||||||
throw new Error('Room not joined')
|
this.once('action', () => {
|
||||||
|
if (!this.room) {
|
||||||
|
const error = new Error('Room not joined')
|
||||||
|
this.emit('error', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
const [, on] = this.room.makeAction('MESSAGE')
|
||||||
|
on((message) => callback(message as T))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const [, on] = this.room.makeAction('MESSAGE')
|
||||||
|
on((message) => callback(message as T))
|
||||||
}
|
}
|
||||||
const [, on] = this.room!.makeAction('MESSAGE')
|
return this
|
||||||
on((message) => callback(message as T))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onJoinRoom(callback: (id: string) => void) {
|
onJoinRoom(callback: (id: string) => void) {
|
||||||
if (!this.room) {
|
if (!this.room) {
|
||||||
throw new Error('Room not joined')
|
this.once('action', () => {
|
||||||
|
if (!this.room) {
|
||||||
|
const error = new Error('Room not joined')
|
||||||
|
this.emit('error', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
this.room.onPeerJoin((peerId) => {
|
||||||
|
callback(peerId)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.room.onPeerJoin((peerId) => {
|
||||||
|
callback(peerId)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
this.room.onPeerJoin((peerId) => callback(peerId))
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
onLeaveRoom(callback: (id: string) => void) {
|
onLeaveRoom(callback: (id: string) => void) {
|
||||||
if (!this.room) {
|
if (!this.room) {
|
||||||
throw new Error('Room not joined')
|
this.once('action', () => {
|
||||||
|
if (!this.room) {
|
||||||
|
const error = new Error('Room not joined')
|
||||||
|
this.emit('error', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
this.room.onPeerLeave((peerId) => callback(peerId))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.room.onPeerLeave((peerId) => callback(peerId))
|
||||||
}
|
}
|
||||||
this.room.onPeerLeave((peerId) => callback(peerId))
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
async leaveRoom() {
|
leaveRoom() {
|
||||||
return await this.room?.leave()
|
if (!this.room) {
|
||||||
|
this.once('action', () => {
|
||||||
|
if (!this.room) {
|
||||||
|
const error = new Error('Room not joined')
|
||||||
|
this.emit('error', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
this.room.leave()
|
||||||
|
this.room = undefined
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.room.leave()
|
||||||
|
this.room = undefined
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
onError(callback: (error: Error) => void) {
|
||||||
|
this.on('error', (error: Error) => callback(error))
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const peerRoom = new PeerRoom({ appId: stringToHex(__NAME__) })
|
const hostRoomId = stringToHex(document.location.host)
|
||||||
|
const peerRoom = new PeerRoom({ roomId: hostRoomId })
|
||||||
|
|
||||||
export const PeerRoomImpl = PeerRoomExtern.impl(peerRoom)
|
export const PeerRoomImpl = PeerRoomExtern.impl(peerRoom)
|
||||||
|
|
||||||
|
// https://github.com/w3c/webextensions/issues/72
|
||||||
|
// https://issues.chromium.org/issues/40251342
|
||||||
|
// https://github.com/w3c/webrtc-extensions/issues/77
|
||||||
|
|
142
src/domain/impls/PeerRoom2.ts
Normal file
142
src/domain/impls/PeerRoom2.ts
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
import { Artico, Room } from '@rtco/client'
|
||||||
|
|
||||||
|
import { PeerRoomExtern, type PeerMessage } from '@/domain/externs/PeerRoom'
|
||||||
|
import { stringToHex } from '@/utils'
|
||||||
|
import { nanoid } from 'nanoid'
|
||||||
|
import EventHub from '@resreq/event-hub'
|
||||||
|
export interface Config {
|
||||||
|
peerId?: string
|
||||||
|
roomId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
class PeerRoom extends EventHub {
|
||||||
|
readonly roomId: string
|
||||||
|
private rtco?: Artico
|
||||||
|
readonly peerId: string
|
||||||
|
private room?: Room
|
||||||
|
|
||||||
|
constructor(config: Config) {
|
||||||
|
super()
|
||||||
|
this.roomId = config.roomId
|
||||||
|
this.peerId = config.peerId || nanoid()
|
||||||
|
this.joinRoom = this.joinRoom.bind(this)
|
||||||
|
this.sendMessage = this.sendMessage.bind(this)
|
||||||
|
this.onMessage = this.onMessage.bind(this)
|
||||||
|
this.onJoinRoom = this.onJoinRoom.bind(this)
|
||||||
|
this.onLeaveRoom = this.onLeaveRoom.bind(this)
|
||||||
|
this.leaveRoom = this.leaveRoom.bind(this)
|
||||||
|
this.onError = this.onError.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
joinRoom() {
|
||||||
|
if (!this.rtco) {
|
||||||
|
this.rtco = new Artico({ id: this.peerId })
|
||||||
|
}
|
||||||
|
if (this.room) {
|
||||||
|
this.room = this.rtco.join(this.roomId)
|
||||||
|
} else {
|
||||||
|
this.rtco!.on('open', () => {
|
||||||
|
this.room = this.rtco!.join(this.roomId)
|
||||||
|
this.emit('action')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessage<T extends PeerMessage>(message: T, id?: string) {
|
||||||
|
if (!this.room) {
|
||||||
|
this.once('action', () => {
|
||||||
|
if (!this.room) {
|
||||||
|
const error = new Error('Room not joined')
|
||||||
|
this.emit('error', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
this.room.send(JSON.stringify(message), id)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.room.send(JSON.stringify(message), id)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
onMessage<T extends PeerMessage>(callback: (message: T) => void) {
|
||||||
|
if (!this.room) {
|
||||||
|
this.once('action', () => {
|
||||||
|
if (!this.room) {
|
||||||
|
const error = new Error('Room not joined')
|
||||||
|
this.emit('error', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
this.room.on('message', (message) => callback(JSON.parse(message) as T))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.room.on('message', (message) => callback(JSON.parse(message) as T))
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
onJoinRoom(callback: (id: string) => void) {
|
||||||
|
if (!this.room) {
|
||||||
|
this.once('action', () => {
|
||||||
|
if (!this.room) {
|
||||||
|
const error = new Error('Room not joined')
|
||||||
|
this.emit('error', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
this.room.on('join', (id) => callback(id))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.room.on('join', (id) => callback(id))
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
onLeaveRoom(callback: (id: string) => void) {
|
||||||
|
if (!this.room) {
|
||||||
|
this.once('action', () => {
|
||||||
|
if (!this.room) {
|
||||||
|
const error = new Error('Room not joined')
|
||||||
|
this.emit('error', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
this.room.on('leave', (id) => callback(id))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.room.on('leave', (id) => callback(id))
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
leaveRoom() {
|
||||||
|
if (!this.room) {
|
||||||
|
this.once('action', () => {
|
||||||
|
if (!this.room) {
|
||||||
|
const error = new Error('Room not joined')
|
||||||
|
this.emit('error', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
this.room.leave()
|
||||||
|
this.room = undefined
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.room.leave()
|
||||||
|
this.room = undefined
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
onError(callback: (error: Error) => void) {
|
||||||
|
this.rtco?.on('error', (error) => callback(error))
|
||||||
|
this.on('error', (error: Error) => callback(error))
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hostRoomId = stringToHex(document.location.host)
|
||||||
|
|
||||||
|
const peerRoom = new PeerRoom({ roomId: hostRoomId })
|
||||||
|
|
||||||
|
export const PeerRoomImpl = PeerRoomExtern.impl(peerRoom)
|
||||||
|
|
||||||
|
// https://github.com/w3c/webextensions/issues/72
|
||||||
|
// https://issues.chromium.org/issues/40251342
|
||||||
|
// https://github.com/w3c/webrtc-extensions/issues/77
|
|
@ -1,11 +1,11 @@
|
||||||
import generateUglyAvatar from '@/lib/uglyAvatar'
|
import generateUglyAvatar from '@/lib/uglyAvatar'
|
||||||
import compressImage from './compressImage'
|
import compressImage from './compressImage'
|
||||||
|
|
||||||
const generateRandomAvatar = async (idealSize: number) => {
|
const generateRandomAvatar = async (targetSize: number) => {
|
||||||
const svgBlob = generateUglyAvatar()
|
const svgBlob = generateUglyAvatar()
|
||||||
|
|
||||||
// compressImage can't directly compress svg, need to convert to jpeg first
|
// compressImage can't directly compress svg, need to convert to jpeg first
|
||||||
const jpegBlob = await new Promise<Blob>((resolve, reject) => {
|
const imageBlob = await new Promise<Blob>((resolve, reject) => {
|
||||||
const image = new Image()
|
const image = new Image()
|
||||||
image.onload = async () => {
|
image.onload = async () => {
|
||||||
const canvas = new OffscreenCanvas(image.width, image.height)
|
const canvas = new OffscreenCanvas(image.width, image.height)
|
||||||
|
@ -17,7 +17,7 @@ const generateRandomAvatar = async (idealSize: number) => {
|
||||||
image.onerror = () => reject(new Error('Failed to load SVG'))
|
image.onerror = () => reject(new Error('Failed to load SVG'))
|
||||||
image.src = URL.createObjectURL(svgBlob)
|
image.src = URL.createObjectURL(svgBlob)
|
||||||
})
|
})
|
||||||
const miniAvatarBlob = await compressImage({ input: jpegBlob, targetSize: idealSize })
|
const miniAvatarBlob = await compressImage({ input: imageBlob, targetSize })
|
||||||
const miniAvatarBase64 = await new Promise<string>((resolve, reject) => {
|
const miniAvatarBase64 = await new Promise<string>((resolve, reject) => {
|
||||||
const reader = new FileReader()
|
const reader = new FileReader()
|
||||||
reader.onload = (e) => resolve(e.target?.result as string)
|
reader.onload = (e) => resolve(e.target?.result as string)
|
||||||
|
|
Loading…
Reference in a new issue