diff --git a/packages/desktop/package.json b/packages/desktop/package.json
index f8dc8ec..68aa981 100644
--- a/packages/desktop/package.json
+++ b/packages/desktop/package.json
@@ -93,6 +93,7 @@
"typescript": "~4.5.4"
},
"dependencies": {
+ "@100mslive/react-sdk": "^0.1.0",
"@emotion/react": "^11.9.0",
"@emotion/styled": "^11.8.1",
"@getstation/electron-google-oauth2": "^2.1.0",
diff --git a/packages/desktop/src/app.tsx b/packages/desktop/src/app.tsx
index 670cf93..d802760 100644
--- a/packages/desktop/src/app.tsx
+++ b/packages/desktop/src/app.tsx
@@ -6,6 +6,7 @@ import { ElectronProvider } from './providers/ElectronProvider';
import ErrorParent from './providers/ErrorBoundary';
import { NirvanaTheme } from './mui/NirvanaTheme';
import ReactDOM from 'react-dom/client';
+import { SearchProvider } from './providers/SearchProvider';
import { SnackbarProvider } from 'notistack';
import { TerminalProvider } from './components/Terminal';
import { ThemeProvider } from '@mui/material';
@@ -29,9 +30,11 @@ root.render(
-
- <>>
-
+
+
+ <>>
+
+
diff --git a/packages/desktop/src/components/Navbar.tsx b/packages/desktop/src/components/Navbar.tsx
index 51c08f0..f9aab4f 100644
--- a/packages/desktop/src/components/Navbar.tsx
+++ b/packages/desktop/src/components/Navbar.tsx
@@ -1,41 +1,23 @@
-import {
- Avatar,
- CircularProgress,
- Divider,
- IconButton,
- Input,
- ListItemIcon,
- Menu,
- Stack,
- Tooltip,
- Typography,
-} from '@mui/material';
-import { FiHeadphones, FiLogOut, FiMonitor, FiSearch, FiUsers, FiWind } from 'react-icons/fi';
+import { CircularProgress, IconButton, Input, Stack, Tooltip } from '@mui/material';
+import { FiSearch, FiUsers } from 'react-icons/fi';
import React, { useCallback, useRef } from 'react';
import { useKeyPressEvent, useRendersCount } from 'react-use';
import KeyboardShortcutLabel from './KeyboardShortcutLabel';
import { KeyboardShortcuts } from '../util/keyboard';
-import MenuItem from '@mui/material/MenuItem';
import NirvanaLogo from './NirvanaLogo';
import { blueGrey } from '@mui/material/colors';
-import useAuth from '../providers/AuthProvider';
+import useSearch from '../providers/SearchProvider';
import { useSnackbar } from 'notistack';
import useTerminal from './Terminal';
-const Navbar = ({
- handleChangeSearchInput,
- searchVal,
- isSearching,
-}: {
- handleChangeSearchInput: React.ChangeEventHandler;
- searchVal: string;
- isSearching: boolean;
-}) => {
+const Navbar = () => {
const { enqueueSnackbar } = useSnackbar();
const { handleShowCreateConvoForm } = useTerminal();
+ const { searchQuery, omniSearch, conversationResults, userResults, isSearching } = useSearch();
+
const searchRef = useRef(null);
const onSearchFocus = useCallback(() => {
if (searchRef?.current) searchRef.current.focus();
@@ -46,6 +28,13 @@ const Navbar = ({
const rendersCount = useRendersCount();
console.warn('RENDER COUNT | NAVBAR | ', rendersCount);
+ const handleSearchChange = useCallback(
+ (e: React.ChangeEvent) => {
+ omniSearch(e.target.value);
+ },
+ [omniSearch],
+ );
+
return (
{isSearching && }
- {searchVal ? (
+ {searchQuery ? (
) : (
diff --git a/packages/desktop/src/components/OmniSearchResults.tsx b/packages/desktop/src/components/OmniSearchResults.tsx
index 617401b..93d5727 100644
--- a/packages/desktop/src/components/OmniSearchResults.tsx
+++ b/packages/desktop/src/components/OmniSearchResults.tsx
@@ -17,18 +17,15 @@ import { FiZap } from 'react-icons/fi';
import React from 'react';
import { User } from '@nirvana/core/src/models/user.model';
import useConversations from '../providers/ConversationProvider';
+import useSearch from '../providers/SearchProvider';
import useTerminal from './Terminal';
-export default function OmniSearchResults({
- people,
- conversations,
-}: {
- people: User[];
- conversations: Conversation[];
-}) {
+export default function OmniSearchResults() {
const { handleQuickDial } = useTerminal();
const { selectConversation } = useConversations();
+ const { userResults: people, conversationResults: conversations } = useSearch();
+
return (
<>
void;
@@ -70,13 +58,13 @@ export function TerminalProvider({ children }: { children?: React.ReactNode }) {
const { conversationMap, conversationContentMap, selectConversation, selectedConversation } =
useConversations();
- const { searchRelevantConversations } = useSearchConversations(conversationMap);
+ const { clearSearch, searchQuery } = useSearch();
// handle create or open existing conversation
// not 100% consistent to the second, but still works...don't need atomicity
const handleQuickDial = useCallback(
async (otherUser: User) => {
- setSearchVal('');
+ clearSearch();
try {
// check all current conversations which should be live listened to
@@ -105,7 +93,7 @@ export function TerminalProvider({ children }: { children?: React.ReactNode }) {
enqueueSnackbar('Something went wrong, please try again', { variant: 'error' });
}
},
- [conversationMap, enqueueSnackbar, nirvanaUser, selectConversation],
+ [conversationMap, enqueueSnackbar, nirvanaUser, selectConversation, clearSearch],
);
const [isUserSpeaking, setIsUserSpeaking] = useState(false);
@@ -235,54 +223,6 @@ export function TerminalProvider({ children }: { children?: React.ReactNode }) {
useKeyPressEvent('`', handleBroadcast, handleStopBroadcast);
- const [searchVal, setSearchVal] = useState('');
- const [searchUsersResults, setSearchUsersResults] = useState([]);
- const [searchConversationsResults, setSearchConversationsResults] = useState([]);
- const [searching, setSearching] = useState(false);
-
- // debounce user search
- const [, cancel] = useDebounce(
- async () => {
- if (searchVal) {
- let results = await searchUsers(searchVal);
- results = results.filter((userResult) => userResult.id !== user.uid);
- setSearchUsersResults(results);
-
- console.warn('searched users', results);
- }
-
- setSearching(false);
- },
- 1000,
- [searchVal, setSearchUsersResults, user],
- );
-
- const handleOmniSearch = useCallback(
- async (searchQuery: string) => {
- searchQuery = searchQuery.replace('/', '');
- setSearchVal(searchQuery);
-
- if (!searchQuery) {
- return;
- }
-
- // user search
- setSearching(true);
-
- // client side conversation search
- const relevantConversations = await searchRelevantConversations(searchQuery);
- setSearchConversationsResults(relevantConversations);
- },
- [setSearching, setSearchVal, setSearchConversationsResults, searchRelevantConversations],
- );
-
- const handleChangeSearchInput = useCallback(
- (e: React.ChangeEvent) => {
- handleOmniSearch(e.target.value);
- },
- [handleOmniSearch],
- );
-
const [createConversationMode, setCreateConversationMode] = useState(false);
const handleStartConversation = useCallback(
@@ -329,8 +269,8 @@ export function TerminalProvider({ children }: { children?: React.ReactNode }) {
const handleEscape = useCallback(() => {
setCreateConversationMode(false);
selectConversation(undefined);
- setSearchVal('');
- }, [selectConversation, setCreateConversationMode, setSearchVal]);
+ clearSearch();
+ }, [selectConversation, setCreateConversationMode, clearSearch]);
useKeyPressEvent(KeyboardShortcuts.escape.shortcutKey, handleEscape);
@@ -343,7 +283,6 @@ export function TerminalProvider({ children }: { children?: React.ReactNode }) {
createConversationMode,
handleShowCreateConvoForm,
handleEscape,
- handleOmniSearch,
}}
>
@@ -362,22 +301,9 @@ export function TerminalProvider({ children }: { children?: React.ReactNode }) {
flexDirection: 'column',
}}
>
-
+
-
- {searchVal ? (
-
- ) : (
-
- )}
-
+ {searchQuery ? : }
diff --git a/packages/desktop/src/providers/SearchProvider.tsx b/packages/desktop/src/providers/SearchProvider.tsx
index e69de29..dc1e0cd 100644
--- a/packages/desktop/src/providers/SearchProvider.tsx
+++ b/packages/desktop/src/providers/SearchProvider.tsx
@@ -0,0 +1,147 @@
+import React, { useCallback, useContext, useState } from 'react';
+
+import Conversation from '@nirvana/core/src/models/conversation.model';
+import { ConversationMap } from '../util/types';
+import { User } from '@nirvana/core/src/models/user.model';
+import { searchUsers as firestoreSearchUsers } from '../firebase/firestore';
+import useAuth from './AuthProvider';
+import useConversations from './ConversationProvider';
+import { useDebounce } from 'react-use';
+
+interface ISearchContext {
+ searchUsers?: (searchQuery: string) => void;
+ omniSearch?: (searchQuery: string) => void;
+ searchConversations?: (searchQuery: string) => void;
+
+ conversationResults: Conversation[];
+ userResults: User[];
+
+ isSearching: boolean;
+
+ // transparency into what our search is searching for
+ searchQuery: string;
+ clearSearch?: () => void;
+}
+
+const SearchContext = React.createContext({
+ isSearching: false,
+ conversationResults: [],
+ userResults: [],
+ searchQuery: '',
+});
+
+export function SearchProvider({ children }: { children: React.ReactNode }) {
+ const { user } = useAuth();
+ const { conversationMap } = useConversations();
+
+ const [searchQuery, setSearchQuery] = useState('');
+
+ const [userResults, setUserResultsResults] = useState([]);
+ const [conversationResults, setConversationResultsResults] = useState([]);
+ const [isSearching, setIsSearching] = useState(false);
+
+ // debounce user search and any other async ones
+ const [, cancel] = useDebounce(
+ async () => {
+ if (searchQuery) {
+ let results = await firestoreSearchUsers(searchQuery);
+ results = results.filter((userResult) => userResult.id !== user.uid);
+ setUserResultsResults(results);
+
+ console.warn('searched users', results);
+ }
+
+ setIsSearching(false);
+ },
+ 1000,
+ [searchQuery, setUserResultsResults, user, setIsSearching],
+ );
+
+ // any view will hit this when they want and start the debounce process
+ const searchUsers = useCallback(
+ (searchQuery: string) => {
+ setSearchQuery(searchQuery);
+ setIsSearching(true);
+ },
+ [setSearchQuery, setIsSearching],
+ );
+
+ /**
+ *
+ * @param searchQuery
+ * given a search query, finds conversations
+ */
+
+ const searchRelevantConversations = useCallback(
+ async (searchQuery: string): Promise => {
+ const relevantConversations: Conversation[] = [];
+
+ Object.values(conversationMap).forEach((conversation) => {
+ for (const cachedConversationUser of conversation.userCache) {
+ if (
+ cachedConversationUser.email
+ .toLocaleLowerCase()
+ .includes(searchQuery.toLocaleLowerCase())
+ ) {
+ relevantConversations.push(conversation);
+ return;
+ }
+
+ if (
+ cachedConversationUser.displayName
+ .toLocaleLowerCase()
+ .includes(searchQuery.toLocaleLowerCase())
+ ) {
+ relevantConversations.push(conversation);
+ return;
+ }
+ }
+
+ if (conversation.name?.toLocaleLowerCase().includes(searchQuery.toLocaleLowerCase())) {
+ relevantConversations.push(conversation);
+ return;
+ }
+ });
+
+ return relevantConversations;
+ },
+ [conversationMap],
+ );
+
+ const omniSearch = useCallback(
+ async (searchQuery: string) => {
+ searchQuery = searchQuery.replace('/', '');
+ setSearchQuery(searchQuery);
+
+ // user search
+ setIsSearching(true);
+
+ // client side conversation search
+ const relevantConversations = await searchRelevantConversations(searchQuery);
+ setConversationResultsResults(relevantConversations);
+ },
+ [setIsSearching, setSearchQuery, setConversationResultsResults, searchRelevantConversations],
+ );
+
+ const clearSearch = useCallback(() => setSearchQuery(''), [setSearchQuery]);
+
+ return (
+
+ {children}
+
+ );
+}
+
+export default function useSearch() {
+ return useContext(SearchContext);
+}
diff --git a/packages/desktop/src/util/clientSearch.ts b/packages/desktop/src/util/clientSearch.ts
deleted file mode 100644
index 2418680..0000000
--- a/packages/desktop/src/util/clientSearch.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import React, { useCallback } from 'react';
-
-import Conversation from '@nirvana/core/src/models/conversation.model';
-import { ConversationMap } from './types';
-
-/**
- *
- * @param searchQuery
- * given a search query, finds conversations
- */
-
-export function useSearchConversations(conversationMap: ConversationMap) {
- const searchRelevantConversations = useCallback(
- async (searchQuery: string): Promise => {
- const relevantConversations: Conversation[] = [];
-
- Object.values(conversationMap).forEach((conversation) => {
- for (const cachedConversationUser of conversation.userCache) {
- if (
- cachedConversationUser.email
- .toLocaleLowerCase()
- .includes(searchQuery.toLocaleLowerCase())
- ) {
- relevantConversations.push(conversation);
- return;
- }
-
- if (
- cachedConversationUser.displayName
- .toLocaleLowerCase()
- .includes(searchQuery.toLocaleLowerCase())
- ) {
- relevantConversations.push(conversation);
- return;
- }
- }
-
- if (conversation.name?.toLocaleLowerCase().includes(searchQuery.toLocaleLowerCase())) {
- relevantConversations.push(conversation);
- return;
- }
- });
-
- return relevantConversations;
- },
- [conversationMap],
- );
-
- return { searchRelevantConversations };
-}
diff --git a/yarn.lock b/yarn.lock
index ce4de56..de04a97 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,6 +2,38 @@
# yarn lockfile v1
+"@100mslive/hms-video-store@0.3.0":
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/@100mslive/hms-video-store/-/hms-video-store-0.3.0.tgz#8f586d5b318d690ebdd99ea20ed380a944470e5d"
+ integrity sha512-c14K0/QqVVe46afSR0oKpDCSw6PXNdyCaeqmi5IhQuCAO7LuqBOX0gnP9XlPUjHZJYvXKLIDGRn+scAzje8B0A==
+ dependencies:
+ "@100mslive/hms-video" "0.2.0"
+ eventemitter2 "^6.4.5"
+ immer "^9.0.6"
+ reselect "4.0.0"
+ zustand "3.5.7"
+
+"@100mslive/hms-video@0.2.0":
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/@100mslive/hms-video/-/hms-video-0.2.0.tgz#defbb00c0a766adf9a1a61eb1ac64be11ef77dc9"
+ integrity sha512-YlDuquSY5qh6Lff/ff3hWPe4VtByCXoNH1sGberlAZWOkj6cynHuOYfzzmFH0xtdg/JGxrdL/TdLZoGe1kdSRQ==
+ dependencies:
+ eventemitter2 "^6.4.5"
+ sdp-transform "^2.14.1"
+ ua-parser-js "^1.0.1"
+ uuid "^8.3.2"
+ webrtc-adapter "^8.0.0"
+
+"@100mslive/react-sdk@^0.1.0":
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/@100mslive/react-sdk/-/react-sdk-0.1.0.tgz#ffef682bb689430465529b1ee2095e8fede6b791"
+ integrity sha512-zBTdgSvvdhfd3RCT0SnIUrUSWbS3fTNvMqMxZEUxqhlvPAwTzL8+IBXZYmv1gxszdyNFxze8Fa0/vnE05RX1mw==
+ dependencies:
+ "@100mslive/hms-video-store" "0.3.0"
+ react-intersection-observer "^8.33.1"
+ react-resize-detector "^7.0.0"
+ zustand "^3.6.2"
+
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789"
@@ -3414,6 +3446,11 @@ event-target-shim@^5.0.0:
resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
+eventemitter2@^6.4.5:
+ version "6.4.5"
+ resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.5.tgz#97380f758ae24ac15df8353e0cc27f8b95644655"
+ integrity sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==
+
eventemitter3@^4.0.0:
version "4.0.7"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
@@ -4473,7 +4510,7 @@ immediate@~3.0.5:
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=
-immer@^9.0.14:
+immer@^9.0.14, immer@^9.0.6:
version "9.0.14"
resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.14.tgz#e05b83b63999d26382bb71676c9d827831248a48"
integrity sha512-ubBeqQutOSLIFCUBN03jGeOS6a3DoYlSYwYJTa+gSKEZKU5redJIqkIdZ3JVv/4RZpfcXdAWH5zCNLWPRv2WDw==
@@ -6295,6 +6332,11 @@ react-icons@^4.3.1:
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.3.1.tgz#2fa92aebbbc71f43d2db2ed1aed07361124e91ca"
integrity sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ==
+react-intersection-observer@^8.33.1:
+ version "8.34.0"
+ resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-8.34.0.tgz#6f6e67831c52e6233f6b6cc7eb55814820137c42"
+ integrity sha512-TYKh52Zc0Uptp5/b4N91XydfSGKubEhgZRtcg1rhTKABXijc4Sdr1uTp5lJ8TN27jwUsdXxjHXtHa0kPj704sw==
+
react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
@@ -6305,6 +6347,13 @@ react-is@^17.0.2:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
+react-resize-detector@^7.0.0:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/react-resize-detector/-/react-resize-detector-7.1.1.tgz#18d5b84909d5ab13abe0a68ddf0fb8e80c553dfc"
+ integrity sha512-rU54VTstNzFLZAmMNHqt8xINjDWP7SQR05A2HUW0OGvl4vcrXzgaxrrqAY5tZMfkLkoYm5u0i0qGqCjdc2jyAA==
+ dependencies:
+ lodash "^4.17.21"
+
react-transition-group@^4.4.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470"
@@ -6484,6 +6533,11 @@ requires-port@^1.0.0:
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
+reselect@4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7"
+ integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==
+
resize-observer-polyfill@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
@@ -6682,6 +6736,16 @@ screenfull@^5.1.0:
resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba"
integrity sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==
+sdp-transform@^2.14.1:
+ version "2.14.1"
+ resolved "https://registry.yarnpkg.com/sdp-transform/-/sdp-transform-2.14.1.tgz#2bb443583d478dee217df4caa284c46b870d5827"
+ integrity sha512-RjZyX3nVwJyCuTo5tGPx+PZWkDMCg7oOLpSlhjDdZfwUoNqG1mM8nyj31IGHyaPWXhjbP7cdK3qZ2bmkJ1GzRw==
+
+sdp@^3.0.2:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/sdp/-/sdp-3.0.3.tgz#669958d54663ea9f4a46cc66518c9d980c52c61e"
+ integrity sha512-8EkfckS+XZQaPLyChu4ey7PghrdcraCVNpJe2Gfdi2ON1ylQ7OasuKX+b37R9slnRChwIAiQgt+oj8xXGD8x+A==
+
select-hose@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
@@ -7500,6 +7564,11 @@ typescript@~4.5.4:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3"
integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==
+ua-parser-js@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.2.tgz#e2976c34dbfb30b15d2c300b2a53eac87c57a775"
+ integrity sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg==
+
unbox-primitive@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
@@ -7738,6 +7807,13 @@ webpack@^5.37.0:
watchpack "^2.3.1"
webpack-sources "^3.2.3"
+webrtc-adapter@^8.0.0:
+ version "8.1.1"
+ resolved "https://registry.yarnpkg.com/webrtc-adapter/-/webrtc-adapter-8.1.1.tgz#e4a4dfd1b5085d119da40c4efc0147f7d0961cba"
+ integrity sha512-1yXevP7TeZGmklEXkvQVrZp3fOSJlLeXNGCA7NovQokxgP3/e2T3EVGL0eKU87S9vKppWjvRWqnJeSANEspOBg==
+ dependencies:
+ sdp "^3.0.2"
+
websocket-driver@>=0.5.1, websocket-driver@^0.7.4:
version "0.7.4"
resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760"
@@ -7987,3 +8063,13 @@ yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
+
+zustand@3.5.7:
+ version "3.5.7"
+ resolved "https://registry.yarnpkg.com/zustand/-/zustand-3.5.7.tgz#add5e8d0ba031ce6e0ddf9cb76ef15306efb665f"
+ integrity sha512-DlVFXJavIHyXTOGz6dB+8QHZsPyJcGJSEBtlp2Ivmd5SwtlCnhPo3L8LB6YRfAOJC2PbqzgoD8NMjk+y+vIF0g==
+
+zustand@^3.6.2:
+ version "3.7.2"
+ resolved "https://registry.yarnpkg.com/zustand/-/zustand-3.7.2.tgz#7b44c4f4a5bfd7a8296a3957b13e1c346f42514d"
+ integrity sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==