diff --git a/package.json b/package.json
index 3e4cd7b4e..15d3c71a9 100644
--- a/package.json
+++ b/package.json
@@ -24,7 +24,6 @@
     "@babel/preset-typescript": "7.14.5",
     "@commitlint/cli": "12.1.4",
     "@commitlint/config-conventional": "12.1.4",
-    "@graasp/websockets": "git://github.com/graasp/graasp-websockets.git#master",
     "@testing-library/jest-dom": "5.11.6",
     "@testing-library/react": "11.2.2",
     "@testing-library/react-hooks": "7.0.0",
diff --git a/src/api/chat.ts b/src/api/chat.ts
new file mode 100644
index 000000000..5b7567a9d
--- /dev/null
+++ b/src/api/chat.ts
@@ -0,0 +1,30 @@
+import { PartialChatMessage, QueryClientConfig, UUID } from '../types';
+import { buildGetItemChatRoute, buildPostItemChatMessageRoute } from './routes';
+import { DEFAULT_GET, DEFAULT_POST, failOnError } from './utils';
+
+export const getItemChat = async (
+  id: UUID,
+  { API_HOST }: QueryClientConfig,
+) => {
+  const res = await fetch(
+    `${API_HOST}/${buildGetItemChatRoute(id)}`,
+    DEFAULT_GET,
+  ).then(failOnError);
+  const itemChat = await res.json();
+  return itemChat;
+};
+
+export const postItemChatMessage = async (
+  { chatId, body }: PartialChatMessage,
+  { API_HOST }: QueryClientConfig,
+) => {
+  const res = await fetch(
+    `${API_HOST}/${buildPostItemChatMessageRoute(chatId)}`,
+    {
+      ...DEFAULT_POST,
+      body: JSON.stringify({ body }),
+    },
+  ).then(failOnError);
+  const publishedMessage = await res.json();
+  return publishedMessage;
+};
diff --git a/src/api/index.ts b/src/api/index.ts
index d56d9e0bd..cbc6efe16 100644
--- a/src/api/index.ts
+++ b/src/api/index.ts
@@ -5,3 +5,4 @@ export * from './authentication';
 export * from './itemTag';
 export * from './itemLogin';
 export * from './itemFlag';
+export * from './chat';
\ No newline at end of file
diff --git a/src/api/routes.ts b/src/api/routes.ts
index 9b739634b..fd941aed9 100644
--- a/src/api/routes.ts
+++ b/src/api/routes.ts
@@ -37,6 +37,9 @@ export const buildShareItemWithRoute = (id: UUID) =>
   `item-memberships?itemId=${id}`;
 export const buildGetItemMembershipsForItemRoute = (id: UUID) =>
   `item-memberships?itemId=${id}`;
+export const buildGetItemChatRoute = (id: UUID) => `${ITEMS_ROUTE}/${id}/chat`;
+export const buildPostItemChatMessageRoute = (id: UUID) =>
+  `${ITEMS_ROUTE}/${id}/chat`;
 
 export const buildGetMemberBy = (email: string) =>
   `${MEMBERS_ROUTE}?email=${email}`;
diff --git a/src/config/keys.ts b/src/config/keys.ts
index 979d6a295..919413bc9 100644
--- a/src/config/keys.ts
+++ b/src/config/keys.ts
@@ -11,6 +11,8 @@ export const CURRENT_MEMBER_KEY = 'currentMember';
 export const MEMBERS_KEY = 'members';
 export const buildMemberKey = (id: UUID) => [MEMBERS_KEY, id];
 export const buildItemParentsKey = (id: UUID) => [ITEMS_KEY, id, 'parents'];
+export const CHATS_KEY = 'chats';
+export const buildItemChatKey = (id: UUID) => [CHATS_KEY, id];
 
 export const getKeyForParentId = (parentId: UUID | null) =>
   parentId ? buildItemChildrenKey(parentId) : OWN_ITEMS_KEY;
@@ -48,4 +50,5 @@ export const MUTATION_KEYS = {
   POST_ITEM_FLAG: 'postItemFlag',
   EDIT_ITEM_MEMBERSHIP: 'editItemMembership',
   DELETE_ITEM_MEMBERSHIP: 'deleteItemMembership',
+  POST_ITEM_CHAT_MESSAGE: 'postChatMessage',
 };
diff --git a/src/hooks/chat.ts b/src/hooks/chat.ts
new file mode 100644
index 000000000..aedc95641
--- /dev/null
+++ b/src/hooks/chat.ts
@@ -0,0 +1,24 @@
+import { useQuery } from 'react-query';
+import * as Api from '../api';
+import { buildItemChatKey } from '../config/keys';
+import { QueryClientConfig, UUID } from '../types';
+
+export default (queryConfig: QueryClientConfig) => {
+  const { retry, cacheTime, staleTime } = queryConfig;
+  const defaultOptions = {
+    retry,
+    cacheTime,
+    staleTime,
+  };
+
+  return {
+    useItemChat: (itemId: UUID) =>
+      useQuery({
+        queryKey: buildItemChatKey(itemId),
+        queryFn: () =>
+          Api.getItemChat(itemId, queryConfig).then((data) => data),
+        ...defaultOptions,
+        enabled: Boolean(itemId),
+      }),
+  };
+};
\ No newline at end of file
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
index 5d2ebfd04..fa52c748a 100644
--- a/src/hooks/index.ts
+++ b/src/hooks/index.ts
@@ -3,6 +3,7 @@ import configureItemHooks from './item';
 import configureMemberHooks from './member';
 import configureItemTagHooks from './itemTag';
 import configureItemFlagHooks from './itemFlag';
+import configureChatHooks from './chat';
 import { QueryClientConfig } from '../types';
 
 export default (queryClient: QueryClient, queryConfig: QueryClientConfig) => ({
@@ -10,4 +11,5 @@ export default (queryClient: QueryClient, queryConfig: QueryClientConfig) => ({
   ...configureMemberHooks(queryConfig),
   ...configureItemTagHooks(queryConfig),
   ...configureItemFlagHooks(queryConfig),
+  ...configureChatHooks(queryConfig),
 });
diff --git a/src/mutations/chat.ts b/src/mutations/chat.ts
new file mode 100644
index 000000000..e4bba1db1
--- /dev/null
+++ b/src/mutations/chat.ts
@@ -0,0 +1,12 @@
+import { QueryClient } from 'react-query';
+import * as Api from '../api'
+import { MUTATION_KEYS } from '../config/keys';
+import { QueryClientConfig } from '../types';
+
+const { POST_ITEM_CHAT_MESSAGE } = MUTATION_KEYS;
+
+export default (queryClient: QueryClient, queryConfig: QueryClientConfig) => {
+  queryClient.setMutationDefaults(POST_ITEM_CHAT_MESSAGE, {
+      mutationFn: (chatMsg) => Api.postItemChatMessage(chatMsg, queryConfig),
+  });
+};
\ No newline at end of file
diff --git a/src/mutations/index.ts b/src/mutations/index.ts
index 76fbfbcf2..160f0e80e 100644
--- a/src/mutations/index.ts
+++ b/src/mutations/index.ts
@@ -4,6 +4,7 @@ import memberMutations from './member';
 import tagsMutations from './itemTag';
 import flagsMutations from './itemFlag';
 import itemMembershipMutations from './membership';
+import chatMutations from './chat';
 import { QueryClientConfig } from '../types';
 
 const configureMutations = (
@@ -15,6 +16,7 @@ const configureMutations = (
   memberMutations(queryClient, queryConfig);
   tagsMutations(queryClient, queryConfig);
   flagsMutations(queryClient, queryConfig);
+  chatMutations(queryClient, queryConfig);
 };
 
 export default configureMutations;
diff --git a/src/types.ts b/src/types.ts
index a15bf42eb..ce6b18bab 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -77,3 +77,20 @@ export enum PERMISSION_LEVELS {
   WRITE = 'write',
   ADMIN = 'admin',
 }
+
+export type PartialChatMessage = {
+  chatId: string;
+  body: string;
+};
+
+export type ChatMessage = {
+  chatId: string;
+  creator: string;
+  createdAt: string;
+  body: string;
+};
+
+export interface Chat {
+  id: string;
+  messages: Array<ChatMessage>;
+}
diff --git a/src/ws/constants.ts b/src/ws/constants.ts
new file mode 100644
index 000000000..1ba5e7ffa
--- /dev/null
+++ b/src/ws/constants.ts
@@ -0,0 +1,27 @@
+/**
+ * TODO: use types from graasp-websockets
+ */
+
+/** Namespace for notifications realm */
+export const REALM_NOTIF = 'notif';
+
+/** Client actions */
+export const CLIENT_ACTION_SUBSCRIBE = 'subscribe';
+export const CLIENT_ACTION_UNSUBSCRIBE = 'unsubscribe';
+export const CLIENT_ACTION_SUBSCRIBE_ONLY = 'subscribeOnly';
+export const CLIENT_ACTION_DISCONNECT = 'disconnect';
+
+/** Server message types */
+export const SERVER_TYPE_RESPONSE = 'response';
+export const SERVER_TYPE_UPDATE = 'update';
+export const SERVER_TYPE_INFO = 'info';
+
+/** Server response status */
+export const RESPONSE_STATUS_SUCCESS = 'success';
+export const RESPONSE_STATUS_ERROR = 'error';
+
+/** Error names */
+export const ERROR_ACCESS_DENIED = 'ACCESS_DENIED';
+export const ERROR_BAD_REQUEST = 'BAD_REQUEST';
+export const ERROR_NOT_FOUND = 'NOT_FOUND';
+export const ERROR_SERVER_ERROR = 'SERVER_ERROR';
diff --git a/src/ws/hooks.ts b/src/ws/hooks.ts
deleted file mode 100644
index fff85f1b5..000000000
--- a/src/ws/hooks.ts
+++ /dev/null
@@ -1,134 +0,0 @@
-/**
- * Graasp websocket client
- * React effect hooks to subscribe to real-time updates and mutate query client
- *
- * @author Alexandre CHAU
- */
-
-import {
-  WS_ENTITY_ITEM,
-  WS_ENTITY_MEMBER,
-  WS_SERVER_TYPE_UPDATE,
-  WS_UPDATE_KIND_CHILD_ITEM,
-  WS_UPDATE_KIND_SHARED_WITH,
-  WS_UPDATE_OP_CREATE,
-  WS_UPDATE_OP_DELETE,
-} from '@graasp/websockets/src/interfaces/constants';
-import { ServerMessage } from '@graasp/websockets/src/interfaces/message';
-import { List } from 'immutable';
-import { useEffect } from 'react';
-import { QueryClient } from 'react-query';
-import {
-  buildItemChildrenKey,
-  buildItemKey,
-  SHARED_ITEMS_KEY,
-} from '../config/keys';
-import { Item, UUID } from '../types';
-import { Channel, GraaspWebsocketClient } from './ws-client';
-
-export default (
-  websocketClient: GraaspWebsocketClient,
-  queryClient: QueryClient,
-) => ({
-  /**
-   * React hook to subscribe to the children updates of the give parent item ID
-   *
-   * @param parentId The ID of the parent on which to observe children updates
-   */
-  useChildrenUpdates: (parentId: UUID) => {
-    useEffect(() => {
-      if (!parentId) {
-        return;
-      }
-
-      const channel: Channel = { name: parentId, entity: WS_ENTITY_ITEM };
-      const parentChildrenKey = buildItemChildrenKey(parentId);
-
-      const handler = (data: ServerMessage) => {
-        if (
-          data.type === WS_SERVER_TYPE_UPDATE &&
-          data.body.kind === WS_UPDATE_KIND_CHILD_ITEM &&
-          data.body.entity === WS_ENTITY_ITEM
-        ) {
-          const current: List<Item> | undefined = queryClient.getQueryData(
-            parentChildrenKey,
-          );
-          const value = data.body.value as Item;
-          let mutation;
-          switch (data.body.op) {
-            case WS_UPDATE_OP_CREATE: {
-              if (current && !current.find((i) => i.id === value.id)) {
-                mutation = current.push(value);
-                queryClient.setQueryData(parentChildrenKey, mutation);
-                queryClient.setQueryData(buildItemKey(value.id), value);
-              }
-              break;
-            }
-            case WS_UPDATE_OP_DELETE: {
-              if (current) {
-                mutation = current.filter((i) => i.id !== value.id);
-                queryClient.setQueryData(parentChildrenKey, mutation);
-              }
-              break;
-            }
-            default:
-              break;
-          }
-        }
-      };
-
-      websocketClient.subscribe(channel, handler);
-
-      return function cleanup() {
-        websocketClient.unsubscribe(channel, handler);
-      };
-    }, [parentId]);
-  },
-
-  useSharedItemsUpdates: (userId: UUID) => {
-    useEffect(() => {
-      if (!userId) {
-        return;
-      }
-
-      const channel: Channel = { name: userId, entity: WS_ENTITY_MEMBER };
-
-      const handler = (data: ServerMessage) => {
-        if (
-          data.type === WS_SERVER_TYPE_UPDATE &&
-          data.body.kind === WS_UPDATE_KIND_SHARED_WITH &&
-          data.body.entity === WS_ENTITY_MEMBER
-        ) {
-          const current: List<Item> | undefined = queryClient.getQueryData(
-            SHARED_ITEMS_KEY,
-          );
-          const value = data.body.value as Item;
-          let mutation;
-          switch (data.body.op) {
-            case WS_UPDATE_OP_CREATE: {
-              if (current && !current.find((i) => i.id === value.id)) {
-                mutation = current.push(value);
-                queryClient.setQueryData(SHARED_ITEMS_KEY, mutation);
-                queryClient.setQueryData(buildItemKey(value.id), value);
-              }
-              break;
-            }
-            case WS_UPDATE_OP_DELETE: {
-              if (current) {
-                mutation = current.filter((i) => i.id !== value.id);
-                queryClient.setQueryData(SHARED_ITEMS_KEY, mutation);
-              }
-              break;
-            }
-          }
-        }
-      };
-
-      websocketClient.subscribe(channel, handler);
-
-      return function cleanup() {
-        websocketClient.unsubscribe(channel, handler);
-      };
-    }, [userId]);
-  },
-});
diff --git a/src/ws/hooks/chat.ts b/src/ws/hooks/chat.ts
new file mode 100644
index 000000000..88af95e9c
--- /dev/null
+++ b/src/ws/hooks/chat.ts
@@ -0,0 +1,54 @@
+import { QueryClient } from 'react-query';
+import { buildItemChatKey } from '../../config/keys';
+import { Chat, ChatMessage, UUID } from '../../types';
+import { Channel, GraaspWebsocketClient } from '../ws-client';
+
+// todo: use graasp-types?
+interface ChatEvent {
+  kind: string;
+  op: string;
+  message: ChatMessage;
+}
+
+export default (
+  websocketClient: GraaspWebsocketClient,
+  queryClient: QueryClient,
+) => ({
+  /**
+   * React hook to subscribe to the updates of the given chat ID
+   * @param chatId The ID of the chat of which to observves updates
+   */
+  useItemChatUpdates: (chatId: UUID) => {
+    if (!chatId) {
+      return;
+    }
+
+    const channel: Channel = { name: chatId, topic: 'chat/item' };
+
+    const handler = (event: ChatEvent) => {
+      if (event.kind === 'item') {
+        const chatKey = buildItemChatKey(chatId);
+        const current: Chat | undefined = queryClient.getQueryData(chatKey);
+
+        if (current) {
+          switch (event.op) {
+            case 'publish': {
+              const msg = event.message;
+              const newChat = Object.assign({}, current);
+              newChat.messages = [...current.messages];
+              newChat.messages.push(msg);
+              queryClient.setQueryData(chatKey, newChat);
+              break;
+            }
+          }
+        }
+      }
+    };
+
+    websocketClient.subscribe(channel, handler);
+
+    return function cleanup() {
+      websocketClient.unsubscribe(channel, handler);
+    };
+  },
+});
diff --git a/src/ws/hooks/index.ts b/src/ws/hooks/index.ts
new file mode 100644
index 000000000..6f3ae14d7
--- /dev/null
+++ b/src/ws/hooks/index.ts
@@ -0,0 +1,16 @@
+import { QueryClient } from 'react-query';
+import { GraaspWebsocketClient } from '../ws-client';
+import configureChatHooks from './chat';
+import configureItemHooks from './item';
+import configureMembershipHooks from './membership';
+
+export default (
+  websocketClient: GraaspWebsocketClient,
+  queryClient: QueryClient,
+) => {
+  return {
+    ...configureItemHooks(websocketClient, queryClient),
+    ...configureMembershipHooks(websocketClient, queryClient),
+    ...configureChatHooks(websocketClient, queryClient),
+  };
+};
diff --git a/src/ws/hooks/item.ts b/src/ws/hooks/item.ts
new file mode 100644
index 000000000..0ac6d6e90
--- /dev/null
+++ b/src/ws/hooks/item.ts
@@ -0,0 +1,245 @@
+/**
+ * Graasp websocket client
+ * React effect hooks to subscribe to real-time updates and mutate query client
+ */
+
+import { List, Record } from 'immutable';
+import { useEffect } from 'react';
+import { QueryClient } from 'react-query';
+import {
+  buildItemChildrenKey,
+  buildItemKey,
+  OWN_ITEMS_KEY,
+  SHARED_ITEMS_KEY,
+} from '../../config/keys';
+import { Item, UUID } from '../../types';
+import { Channel, GraaspWebsocketClient } from '../ws-client';
+
+// TODO: use graasp-types?
+interface ItemEvent {
+  kind: string;
+  op: string;
+  item: Item;
+}
+
+export default (
+  websocketClient: GraaspWebsocketClient,
+  queryClient: QueryClient,
+) => ({
+  /**
+   * React hook to subscribe to the updates of the given item ID
+   * @param itemId The ID of the item of which to observe updates
+   */
+  useItemUpdates: (itemId: UUID) => {
+    useEffect(() => {
+      if (!itemId) {
+        return;
+      }
+
+      const channel: Channel = { name: itemId, topic: 'item' };
+      const itemKey = buildItemKey(itemId);
+
+      const handler = (event: ItemEvent) => {
+        if (event.kind === 'self') {
+          const current: Record<Item> | undefined = queryClient.getQueryData(
+            itemKey,
+          );
+          const item = event.item;
+
+          if (current?.get('id') === item.id) {
+            switch (event.op) {
+              case 'update': {
+                queryClient.setQueryData(itemKey, item);
+                break;
+              }
+              case 'delete': {
+                queryClient.setQueryData(itemKey, null);
+                break;
+              }
+            }
+          }
+        }
+      };
+
+      websocketClient.subscribe(channel, handler);
+
+      return function cleanup() {
+        websocketClient.unsubscribe(channel, handler);
+      };
+    }, [itemId]);
+  },
+
+  /**
+   * React hook to subscribe to the children updates of the given parent item ID
+   * @param parentId The ID of the parent on which to observe children updates
+   */
+  useChildrenUpdates: (parentId: UUID) => {
+    useEffect(() => {
+      if (!parentId) {
+        return;
+      }
+
+      const channel: Channel = { name: parentId, topic: 'item' };
+      const parentChildrenKey = buildItemChildrenKey(parentId);
+
+      const handler = (event: ItemEvent) => {
+        if (event.kind === 'child') {
+          const current: List<Item> | undefined = queryClient.getQueryData(
+            parentChildrenKey,
+          );
+
+          if (current) {
+            const item = event.item;
+            let mutation;
+
+            switch (event.op) {
+              case 'create': {
+                if (!current.find((i) => i.id === item.id)) {
+                  mutation = current.push(item);
+                  queryClient.setQueryData(parentChildrenKey, mutation);
+                  queryClient.setQueryData(buildItemKey(item.id), item);
+                }
+                break;
+              }
+              case 'update': {
+                // replace value if it exists
+                mutation = current.map((i) => (i.id === item.id ? item : i));
+                queryClient.setQueryData(parentChildrenKey, mutation);
+                queryClient.setQueryData(buildItemKey(item.id), item);
+
+                break;
+              }
+              case 'delete': {
+                mutation = current.filter((i) => i.id !== item.id);
+                queryClient.setQueryData(parentChildrenKey, mutation);
+                break;
+              }
+            }
+          }
+        }
+      };
+
+      websocketClient.subscribe(channel, handler);
+
+      return function cleanup() {
+        websocketClient.unsubscribe(channel, handler);
+      };
+    }, [parentId]);
+  },
+
+  /**
+   * React hook to subscribe to the owned items updates of the given user ID
+   * @param userId The ID of the user on which to observe owned items updates
+   */
+  useOwnItemsUpdates: (userId: UUID) => {
+    useEffect(() => {
+      if (!userId) {
+        return;
+      }
+
+      const channel: Channel = { name: userId, topic: 'item/member' };
+
+      const handler = (event: ItemEvent) => {
+        if (event.kind === 'own') {
+          const current: List<Item> | undefined = queryClient.getQueryData(
+            OWN_ITEMS_KEY,
+          );
+
+          if (current) {
+            const item = event.item;
+            let mutation;
+
+            switch (event.op) {
+              case 'create': {
+                if (!current.find((i) => i.id === item.id)) {
+                  mutation = current.push(item);
+                  queryClient.setQueryData(OWN_ITEMS_KEY, mutation);
+                  queryClient.setQueryData(buildItemKey(item.id), item);
+                }
+                break;
+              }
+              case 'update': {
+                // replace value if it exists
+                mutation = current.map((i) => (i.id === item.id ? item : i));
+                queryClient.setQueryData(OWN_ITEMS_KEY, mutation);
+                queryClient.setQueryData(buildItemKey(item.id), item);
+
+                break;
+              }
+              case 'delete': {
+                mutation = current.filter((i) => i.id !== item.id);
+                queryClient.setQueryData(OWN_ITEMS_KEY, mutation);
+
+                break;
+              }
+            }
+          }
+        }
+      };
+
+      websocketClient.subscribe(channel, handler);
+
+      return function cleanup() {
+        websocketClient.unsubscribe(channel, handler);
+      };
+    }, [userId]);
+  },
+
+  /**
+   * React hook to subscribe to the shared items updates of the given user ID
+   * @param parentId The ID of the user on which to observe shared items updates
+   */
+  useSharedItemsUpdates: (userId: UUID) => {
+    useEffect(() => {
+      if (!userId) {
+        return;
+      }
+
+      const channel: Channel = { name: userId, topic: 'item/member' };
+
+      const handler = (event: ItemEvent) => {
+        if (event.kind === 'shared') {
+          const current: List<Item> | undefined = queryClient.getQueryData(
+            SHARED_ITEMS_KEY,
+          );
+
+          if (current) {
+            const item = event.item;
+            let mutation;
+
+            switch (event.op) {
+              case 'create': {
+                if (!current.find((i) => i.id === item.id)) {
+                  mutation = current.push(item);
+                  queryClient.setQueryData(SHARED_ITEMS_KEY, mutation);
+                  queryClient.setQueryData(buildItemKey(item.id), item);
+                }
+                break;
+              }
+              case 'update': {
+                // replace value if it exists
+                mutation = current.map((i) => (i.id === item.id ? item : i));
+                queryClient.setQueryData(SHARED_ITEMS_KEY, mutation);
+                queryClient.setQueryData(buildItemKey(item.id), item);
+
+                break;
+              }
+              case 'delete': {
+                mutation = current.filter((i) => i.id !== item.id);
+                queryClient.setQueryData(SHARED_ITEMS_KEY, mutation);
+
+                break;
+              }
+            }
+          }
+        }
+      };
+
+      websocketClient.subscribe(channel, handler);
+
+      return function cleanup() {
+        websocketClient.unsubscribe(channel, handler);
+      };
+    }, [userId]);
+  },
+});
diff --git a/src/ws/hooks/membership.ts b/src/ws/hooks/membership.ts
new file mode 100644
index 000000000..b4591e86e
--- /dev/null
+++ b/src/ws/hooks/membership.ts
@@ -0,0 +1,73 @@
+import { List } from 'immutable';
+import { useEffect } from 'react';
+import { QueryClient } from 'react-query';
+import { buildItemMembershipsKey } from '../../config/keys';
+import { Membership, UUID } from '../../types';
+import { Channel, GraaspWebsocketClient } from '../ws-client';
+
+// todo: use graasp-types?
+interface MembershipEvent {
+  kind: string;
+  op: string;
+  membership: Membership;
+}
+
+export default (
+  websocketClient: GraaspWebsocketClient,
+  queryClient: QueryClient,
+) => ({
+  /**
+   * React hooks to subscribe to membership updates for a given item ID
+   * @param itemId The ID of the item of which to observe memberships updates
+   */
+  useItemMembershipsUpdates: (itemId: UUID) => {
+    useEffect(() => {
+      if (!itemId) {
+        return;
+      }
+
+      const channel: Channel = { name: itemId, topic: 'memberships/item' };
+      const itemMembershipsKey = buildItemMembershipsKey(itemId);
+
+      const handler = (event: MembershipEvent) => {
+        if (event.kind === 'item') {
+          const current:
+            | List<Membership>
+            | undefined = queryClient.getQueryData(itemMembershipsKey);
+          const membership = event.membership;
+
+          if (current && membership.itemId === itemId) {
+            let mutation;
+            switch (event.op) {
+              case 'create': {
+                if (!current.find((m) => m.id === membership.id)) {
+                  mutation = current.push(membership);
+                  queryClient.setQueryData(itemMembershipsKey, mutation);
+                }
+                break;
+              }
+              case 'update': {
+                mutation = current.map((m) =>
+                  m.id === membership.id ? membership : m,
+                );
+                queryClient.setQueryData(itemMembershipsKey, mutation);
+                break;
+              }
+              case 'delete': {
+                mutation = current.filter((m) => m.id !== membership.id);
+                queryClient.setQueryData(itemMembershipsKey, mutation);
+                break;
+              }
+            }
+          }
+        }
+      };
+
+      websocketClient.subscribe(channel, handler);
+
+      return function cleanup() {
+        websocketClient.unsubscribe(channel, handler);
+      };
+    }, [itemId]);
+  },
+});
diff --git a/src/ws/index.ts b/src/ws/index.ts
index c65ca75ef..e835522bb 100644
--- a/src/ws/index.ts
+++ b/src/ws/index.ts
@@ -1,8 +1,6 @@
 /**
  * Graasp websocket client top-level file
  * Entry point to use the Graasp WebSocket client in front-end applications
- *
- * @author Alexandre CHAU
  */
 
 import { QueryClient } from 'react-query';
diff --git a/src/ws/protocol.ts b/src/ws/protocol.ts
new file mode 100644
index 000000000..b523626b2
--- /dev/null
+++ b/src/ws/protocol.ts
@@ -0,0 +1,102 @@
+/**
+ * TODO: use types from graasp-websockets
+ */
+
+import {
+  CLIENT_ACTION_DISCONNECT,
+  CLIENT_ACTION_SUBSCRIBE,
+  CLIENT_ACTION_SUBSCRIBE_ONLY,
+  CLIENT_ACTION_UNSUBSCRIBE,
+  REALM_NOTIF,
+  RESPONSE_STATUS_ERROR,
+  RESPONSE_STATUS_SUCCESS,
+  SERVER_TYPE_INFO,
+  SERVER_TYPE_RESPONSE,
+  SERVER_TYPE_UPDATE,
+} from './constants';
+
+/**
+ * Default message shape
+ * Must have the REALM_NOTIF type to allow future message types unrelated to notifications
+ */
+interface Message {
+  realm: typeof REALM_NOTIF;
+}
+
+/**
+ * Message sent by client to disconnect
+ */
+export interface ClientDisconnect extends Message {
+  action: typeof CLIENT_ACTION_DISCONNECT;
+}
+
+/**
+ * Message sent by client to subscribe to some channel
+ */
+export interface ClientSubscribe extends Message {
+  action: typeof CLIENT_ACTION_SUBSCRIBE;
+  topic: string;
+  channel: string;
+}
+
+/**
+ * Message sent by client to unsubscribe from some channel
+ */
+export interface ClientUnsubscribe extends Message {
+  action: typeof CLIENT_ACTION_UNSUBSCRIBE;
+  topic: string;
+  channel: string;
+}
+
+/**
+ * Message sent by client to subscribe to a single channel
+ * (i.e. it also unsubscribes it from any other channel)
+ */
+export interface ClientSubscribeOnly extends Message {
+  action: typeof CLIENT_ACTION_SUBSCRIBE_ONLY;
+  topic: string;
+  channel: string;
+}
+
+/**
+ * Message sent by server as a response to a {@link ClientMessage}
+ */
+export interface ServerResponse extends Message {
+  type: typeof SERVER_TYPE_RESPONSE;
+  status: typeof RESPONSE_STATUS_SUCCESS | typeof RESPONSE_STATUS_ERROR;
+  error?: Error;
+  request?: ClientMessage;
+}
+
+/**
+ * Message sent by server for misc broadcasts unrelated to a channel
+ */
+export interface ServerInfo extends Message {
+  type: typeof SERVER_TYPE_INFO;
+  message: string;
+  extra?: unknown;
+}
+
+/**
+ * Message sent by server for update notifications sent over a channel
+ */
+export interface ServerUpdate extends Message {
+  type: typeof SERVER_TYPE_UPDATE;
+  topic: string;
+  channel: string;
+  body: unknown;
+}
+
+/**
+ * Client message type is union type of all client message subtypes
+ */
+export type ClientMessage =
+  | ClientDisconnect
+  | ClientSubscribe
+  | ClientUnsubscribe
+  | ClientSubscribeOnly;
+
+/**
+ * Server message type is union type of all server message subtypes
+ */
+export type ServerMessage = ServerResponse | ServerInfo | ServerUpdate;
diff --git a/src/ws/ws-client.ts b/src/ws/ws-client.ts
index a7c622ed8..57b1077ad 100644
--- a/src/ws/ws-client.ts
+++ b/src/ws/ws-client.ts
@@ -2,35 +2,26 @@
  * Graasp websocket client
  * Provides front-end integration for real-time updates using WebSocket
  * Implements the client protocol from https://github.com/graasp/graasp-websockets
- *
- * @author Alexandre CHAU
  */
 
-import {
-  EntityName,
-  WS_CLIENT_ACTION_SUBSCRIBE,
-  WS_CLIENT_ACTION_UNSUBSCRIBE,
-  WS_REALM_NOTIF,
-  WS_RESPONSE_STATUS_SUCCESS,
-  WS_SERVER_TYPE_INFO,
-  WS_SERVER_TYPE_RESPONSE,
-  WS_SERVER_TYPE_UPDATE,
-} from '@graasp/websockets/src/interfaces/constants';
-import {
-  ClientMessage,
-  ServerMessage,
-} from '@graasp/websockets/src/interfaces/message';
 import { QueryClientConfig } from '../types';
+import {
+  CLIENT_ACTION_SUBSCRIBE,
+  CLIENT_ACTION_UNSUBSCRIBE,
+  REALM_NOTIF,
+  RESPONSE_STATUS_SUCCESS,
+  SERVER_TYPE_INFO,
+  SERVER_TYPE_RESPONSE,
+  SERVER_TYPE_UPDATE,
+} from './constants';
+import { ClientMessage, ServerMessage } from './protocol';
 
 export type Channel = {
-  entity: EntityName;
+  topic: string;
   name: string;
 };
 
-// client-side representation of unsollicited server info messages channel
-export const INFO_CHANNEL_NAME = 'info';
-
-type UpdateHandlerFn = (data: ServerMessage) => void;
+type UpdateHandlerFn = (data: any) => void;
 
 /**
  * Helper to remove the first element in an array that
@@ -69,8 +60,8 @@ function addToMappedArray<S, T>(map: Map<S, Array<T>>, key: S, value: T) {
 function buildChannelKey(channel: Channel): string {
   // ensure serialized key is always identical (properties + order)
   const rebuiltChannel: Channel = {
+    topic: channel.topic,
     name: channel.name,
-    entity: channel.entity,
   };
   return JSON.stringify(rebuiltChannel);
 }
@@ -87,14 +78,14 @@ export interface GraaspWebsocketClient {
    * @param channel Channel to which to subscribe to
    * @param handler Handler function to register
    */
-  subscribe(channel: Channel, handler: UpdateHandlerFn): void;
+  subscribe<T>(channel: Channel, handler: (data: T) => void): void;
 
   /**
    * Unsubscribe a handler from a channel, THE HANDLER MUST === THE ONE PASSED TO SUBSCRIBE
    * @param channel Channel from wihch to unsubscribe the provided handler from
    * @param handler Handler function to unregster, MUST BE EQUAL (===) TO PREVIOUSLY REGISTERED HANDLE WITH @see subscribe !
    */
-  unsubscribe(channel: Channel, handler: UpdateHandlerFn): void;
+  unsubscribe<T>(channel: Channel, handler: (data: T) => void): void;
 }
 
 export const configureWebsocketClient = (
@@ -119,17 +110,18 @@ export const configureWebsocketClient = (
 
   const sendSubscribeRequest = (channel: Channel) => {
     send({
-      realm: WS_REALM_NOTIF,
-      action: WS_CLIENT_ACTION_SUBSCRIBE,
-      entity: channel.entity,
+      realm: REALM_NOTIF,
+      action: CLIENT_ACTION_SUBSCRIBE,
+      topic: channel.topic,
       channel: channel.name,
     });
   };
 
   const sendUnsubscribeRequest = (channel: Channel) => {
     send({
-      realm: WS_REALM_NOTIF,
-      action: WS_CLIENT_ACTION_UNSUBSCRIBE,
+      realm: REALM_NOTIF,
+      action: CLIENT_ACTION_UNSUBSCRIBE,
+      topic: channel.topic,
       channel: channel.name,
     });
   };
@@ -140,82 +132,65 @@ export const configureWebsocketClient = (
     current: new Map<string, Array<UpdateHandlerFn>>(),
     info: new Array<UpdateHandlerFn>(),
 
-    add: (
-      channel: Channel | typeof INFO_CHANNEL_NAME,
-      handler: UpdateHandlerFn,
-    ): boolean => {
-      if (channel === INFO_CHANNEL_NAME) {
-        // if subscribed to info, no ack to wait for
-        subscriptions.info.push(handler);
+    add: (channel: Channel, handler: UpdateHandlerFn): boolean => {
+      const channelKey = buildChannelKey(channel);
+      const maybeCurrent = subscriptions.current.get(channelKey);
+      if (maybeCurrent !== undefined && maybeCurrent.length > 0) {
+        // if already subscribed, don't subscribe again, simply register handler in current
+        addToMappedArray(subscriptions.current, channelKey, handler);
         return false;
       } else {
-        const channelKey = buildChannelKey(channel);
-        const maybeCurrent = subscriptions.current.get(channelKey);
-        if (maybeCurrent !== undefined && maybeCurrent.length > 0) {
-          // if already subscribed, don't subscribe again, simply register handler in current
-          addToMappedArray(subscriptions.current, channelKey, handler);
-          return false;
-        } else {
-          // if WS not ready, add to early, otherwise add to waiting ack
-          const map =
-            ws.readyState === ws.OPEN
-              ? subscriptions.waitingAck
-              : subscriptions.early;
-          // create queue if doesn't exist for this channel, otherwise push to it
-          addToMappedArray(map, channelKey, handler);
-          return true;
-        }
+        // if WS not ready, add to early, otherwise add to waiting ack
+        const map =
+          ws.readyState === ws.OPEN
+            ? subscriptions.waitingAck
+            : subscriptions.early;
+        // create queue if doesn't exist for this channel, otherwise push to it
+        addToMappedArray(map, channelKey, handler);
+        return true;
       }
     },
 
-    remove: (
-      channel: Channel | typeof INFO_CHANNEL_NAME,
-      handler: UpdateHandlerFn,
-    ): boolean => {
-      if (channel === INFO_CHANNEL_NAME) {
-        arrayRemoveFirstEqual(subscriptions.info, handler);
-        return false;
-      } else {
-        // helper to remove from a subscription map
-        const _remove = (
-          map: Map<string, Array<UpdateHandlerFn>>,
-          channelKey: string,
-          handler: UpdateHandlerFn,
-        ): boolean => {
-          const queue = map.get(channelKey);
-          if (queue !== undefined) {
-            return arrayRemoveFirstEqual(queue, handler);
-          } else {
-            return false;
-          }
-        };
-        // helper to cleanup mapped array if it is empty
-        const _cleanup = (
-          map: Map<string, Array<UpdateHandlerFn>>,
-          channelKey: string,
-        ): boolean => {
-          const isNowEmpty = map.get(channelKey)?.length === 0;
-          if (isNowEmpty) {
-            // cleanup array
-            map.delete(channelKey);
-          }
-          return isNowEmpty;
-        };
-
-        const channelKey = buildChannelKey(channel);
-        // find first map from which to remove from
-        if (_remove(subscriptions.early, channelKey, handler)) {
-          // no need to send unsubscribe if still in early
-          return false;
-        } else if (_remove(subscriptions.waitingAck, channelKey, handler)) {
-          // if in waitingAck must send unsubscribe if just got emptied
-          return _cleanup(subscriptions.waitingAck, channelKey);
-        } else if (_remove(subscriptions.current, channelKey, handler)) {
-          // if in current must send unsubscribe if just got emptied
-          return _cleanup(subscriptions.current, channelKey);
+    remove: (channel: Channel, handler: UpdateHandlerFn): boolean => {
+      // helper to remove from a subscription map
+      const _remove = (
+        map: Map<string, Array<UpdateHandlerFn>>,
+        channelKey: string,
+        handler: UpdateHandlerFn,
+      ): boolean => {
+        const queue = map.get(channelKey);
+        if (queue !== undefined) {
+          return arrayRemoveFirstEqual(queue, handler);
         } else {
           return false;
         }
+      };
+      // helper to cleanup mapped array if it is empty
+      const _cleanup = (
+        map: Map<string, Array<UpdateHandlerFn>>,
+        channelKey: string,
+      ): boolean => {
+        const isNowEmpty = map.get(channelKey)?.length === 0;
+        if (isNowEmpty) {
+          // cleanup array
+          map.delete(channelKey);
+        }
+        return isNowEmpty;
+      };
+
+      const channelKey = buildChannelKey(channel);
+      // find first map from which to remove from
+      if (_remove(subscriptions.early, channelKey, handler)) {
+        // no need to send unsubscribe if still in early
+        return false;
+      } else if (_remove(subscriptions.waitingAck, channelKey, handler)) {
+        // if in waitingAck must send unsubscribe if just got emptied
+        return _cleanup(subscriptions.waitingAck, channelKey);
+      } else if (_remove(subscriptions.current, channelKey, handler)) {
+        // if in current must send unsubscribe if just got emptied
+        return _cleanup(subscriptions.current, channelKey);
+      } else {
+        return false;
       }
     },
 
@@ -250,17 +225,19 @@ export const configureWebsocketClient = (
     const update = serdes.parse(event.data);
 
     switch (update.type) {
-      case WS_SERVER_TYPE_INFO: {
-        subscriptions.info.forEach((fn) => fn(update));
+      case SERVER_TYPE_INFO: {
+        subscriptions.info.forEach((fn) =>
+          fn({ message: update.message, extra: update.extra }),
+        );
         break;
       }
 
-      case WS_SERVER_TYPE_RESPONSE: {
-        if (update.status === WS_RESPONSE_STATUS_SUCCESS) {
+      case SERVER_TYPE_RESPONSE: {
+        if (update.status === RESPONSE_STATUS_SUCCESS) {
           const req = update.request;
-          if (req?.action === WS_CLIENT_ACTION_SUBSCRIBE) {
+          if (req?.action === CLIENT_ACTION_SUBSCRIBE) {
             // when ack, move all from waiting acks to current
-            subscriptions.ack({ name: req?.channel, entity: req?.entity });
+            subscriptions.ack({ name: req?.channel, topic: req?.topic });
           }
         } else {
           console.debug(
@@ -270,12 +247,12 @@ export const configureWebsocketClient = (
         break;
       }
 
-      case WS_SERVER_TYPE_UPDATE: {
+      case SERVER_TYPE_UPDATE: {
         // send update to all handlers of this channel
-        const channel = { name: update.channel, entity: update.body.entity };
+        const channel = { name: update.channel, topic: update.topic };
         const channelKey = buildChannelKey(channel);
         const handlers = subscriptions.current.get(channelKey);
-        handlers?.forEach((fn) => fn(update));
+        handlers?.forEach((fn) => fn(update.body));
         break;
       }
 
@@ -285,25 +262,13 @@ export const configureWebsocketClient = (
   });
 
   return {
-    subscribe: (
-      channel: Channel | typeof INFO_CHANNEL_NAME,
-      handler: UpdateHandlerFn,
-    ) => {
-      if (
-        subscriptions.add(channel, handler) &&
-        channel !== INFO_CHANNEL_NAME
-      ) {
+    subscribe: <T>(channel: Channel, handler: (data: T) => void) => {
+      if (subscriptions.add(channel, handler)) {
         sendSubscribeRequest(channel);
       }
     },
-    unsubscribe: (
-      channel: Channel | typeof INFO_CHANNEL_NAME,
-      handler: UpdateHandlerFn,
-    ) => {
-      if (
-        subscriptions.remove(channel, handler) &&
-        channel !== INFO_CHANNEL_NAME
-      ) {
+    unsubscribe: <T>(channel: Channel, handler: (data: T) => void) => {
+      if (subscriptions.remove(channel, handler)) {
         sendUnsubscribeRequest(channel);
       }
     },
diff --git a/yarn.lock b/yarn.lock
index c9d8145c0..bd32edc7c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2044,15 +2044,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@fastify/ajv-compiler@npm:^1.0.0":
-  version: 1.1.0
-  resolution: "@fastify/ajv-compiler@npm:1.1.0"
-  dependencies:
-    ajv: ^6.12.6
-  checksum: b8a2522ead00a01ab7ff2921f00aa8e4aeb943949191ce2a617c88e4679db1358a70e4099791828a397a50e5d6f6bd75184ad0ac75a12dffeb9df4c089986a32
-  languageName: node
-  linkType: hard
-
 "@graasp/query-client@link:..::locator=graasp-query-client-example%40workspace%3Aexample":
   version: 0.0.0-use.local
   resolution: "@graasp/query-client@link:..::locator=graasp-query-client-example%40workspace%3Aexample"
@@ -2068,7 +2059,6 @@ __metadata:
     "@babel/preset-typescript": 7.14.5
     "@commitlint/cli": 12.1.4
     "@commitlint/config-conventional": 12.1.4
-    "@graasp/websockets": "git://github.com/graasp/graasp-websockets.git#master"
     "@testing-library/jest-dom": 5.11.6
     "@testing-library/react": 11.2.2
     "@testing-library/react-hooks": 7.0.0
@@ -2115,20 +2105,6 @@ __metadata:
   languageName: unknown
   linkType: soft
 
-"@graasp/websockets@git://github.com/graasp/graasp-websockets.git#master":
-  version: 0.1.0
-  resolution: "@graasp/websockets@git://github.com/graasp/graasp-websockets.git#commit=da4b355456dff8cb908e5fc2e5f5cf0d2aa033d5"
-  dependencies:
-    ajv-latest: "npm:ajv@^8.6.0"
-    dotenv: ^9.0.2
-    fastify: ^3.18.1
-    fastify-plugin: ^3.0.0
-    fastify-websocket: ^3.2.0
-    ioredis: ^4.27.6
-  checksum: 128f7d7e9496d92981a8f2a8073f92bce65fbc65a8b9f02ded6a411eefef2c598a32d2cc513fbe9d61789f58027fbc8880bcbdcb0b885bc8295640be97e983f5
-  languageName: node
-  linkType: hard
-
 "@hapi/address@npm:2.x.x":
   version: 2.1.4
   resolution: "@hapi/address@npm:2.1.4"
@@ -4160,13 +4136,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"abstract-logging@npm:^2.0.0":
-  version: 2.0.1
-  resolution: "abstract-logging@npm:2.0.1"
-  checksum: 6967d15e5abbafd17f56eaf30ba8278c99333586fa4f7935fd80e93cfdc006c37fcc819c5d63ee373a12e6cb2d0417f7c3c6b9e42b957a25af9937d26749415e
-  languageName: node
-  linkType: hard
-
 "accepts@npm:~1.3.4, accepts@npm:~1.3.5, accepts@npm:~1.3.7":
   version: 1.3.7
   resolution: "accepts@npm:1.3.7"
@@ -4302,27 +4271,27 @@ __metadata:
   languageName: node
   linkType: hard
 
-"ajv-latest@npm:ajv@^8.6.0, ajv@npm:^8.0.1":
-  version: 8.6.2
-  resolution: "ajv@npm:8.6.2"
+"ajv@npm:^6.1.0, ajv@npm:^6.10.0, ajv@npm:^6.10.2, ajv@npm:^6.12.4, ajv@npm:^6.12.5":
+  version: 6.12.6
+  resolution: "ajv@npm:6.12.6"
   dependencies:
     fast-deep-equal: ^3.1.1
-    json-schema-traverse: ^1.0.0
-    require-from-string: ^2.0.2
+    fast-json-stable-stringify: ^2.0.0
+    json-schema-traverse: ^0.4.1
     uri-js: ^4.2.2
-  checksum: b86d6cb86c69abbd8ce71ab7d4ff272660bf6d34fa9fbe770f73e54da59d531b2546692e36e2b35bbcfb11d20db774b4c09189671335185b8c799d65194e5169
+  checksum: 874972efe5c4202ab0a68379481fbd3d1b5d0a7bd6d3cc21d40d3536ebff3352a2a1fabb632d4fd2cc7fe4cbdcd5ed6782084c9bbf7f32a1536d18f9da5007d4
   languageName: node
   linkType: hard
 
-"ajv@npm:^6.1.0, ajv@npm:^6.10.0, ajv@npm:^6.10.2, ajv@npm:^6.11.0, ajv@npm:^6.12.2, ajv@npm:^6.12.4, ajv@npm:^6.12.5, ajv@npm:^6.12.6":
-  version: 6.12.6
-  resolution: "ajv@npm:6.12.6"
+"ajv@npm:^8.0.1":
+  version: 8.6.2
+  resolution: "ajv@npm:8.6.2"
   dependencies:
     fast-deep-equal: ^3.1.1
-    fast-json-stable-stringify: ^2.0.0
-    json-schema-traverse: ^0.4.1
+    json-schema-traverse: ^1.0.0
+    require-from-string: ^2.0.2
     uri-js: ^4.2.2
-  checksum: 874972efe5c4202ab0a68379481fbd3d1b5d0a7bd6d3cc21d40d3536ebff3352a2a1fabb632d4fd2cc7fe4cbdcd5ed6782084c9bbf7f32a1536d18f9da5007d4
+  checksum: b86d6cb86c69abbd8ce71ab7d4ff272660bf6d34fa9fbe770f73e54da59d531b2546692e36e2b35bbcfb11d20db774b4c09189671335185b8c799d65194e5169
   languageName: node
   linkType: hard
 
@@ -4452,13 +4421,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"archy@npm:^1.0.0":
-  version: 1.0.0
-  resolution: "archy@npm:1.0.0"
-  checksum: 504ae7af655130bab9f471343cfdb054feaec7d8e300e13348bc9fe9e660f83d422e473069584f73233c701ae37d1c8452ff2522f2a20c38849e0f406f1732ac
-  languageName: node
-  linkType: hard
-
 "are-we-there-yet@npm:~1.1.2":
   version: 1.1.5
   resolution: "are-we-there-yet@npm:1.1.5"
@@ -4741,13 +4703,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"atomic-sleep@npm:^1.0.0":
-  version: 1.0.0
-  resolution: "atomic-sleep@npm:1.0.0"
-  checksum: b95275afb2f80732f22f43a60178430c468906a415a7ff18bcd0feeebc8eec3930b51250aeda91a476062a90e07132b43a1794e8d8ffcf9b650e8139be75fa36
-  languageName: node
-  linkType: hard
-
 "autoprefixer@npm:^9.6.1, autoprefixer@npm:^9.7.3":
   version: 9.8.6
   resolution: "autoprefixer@npm:9.8.6"
@@ -4765,18 +4720,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"avvio@npm:^7.1.2":
-  version: 7.2.2
-  resolution: "avvio@npm:7.2.2"
-  dependencies:
-    archy: ^1.0.0
-    debug: ^4.0.0
-    fastq: ^1.6.1
-    queue-microtask: ^1.1.2
-  checksum: ece793dd148dbb50e24f40dacf4852b804405fc1cd34ce794659ffc020c6de41695d87999edc0bb2573c802eaa7766493859dbc432d5dc0079381f318c2705a1
-  languageName: node
-  linkType: hard
-
 "axe-core@npm:^4.0.2":
   version: 4.3.2
   resolution: "axe-core@npm:4.3.2"
@@ -5939,13 +5882,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"cluster-key-slot@npm:^1.1.0":
-  version: 1.1.0
-  resolution: "cluster-key-slot@npm:1.1.0"
-  checksum: fc953c75209b1ef9088081bab4e40a0b2586491c974ab93460569c014515ca5a2e31c043f185285e177007162fc353d07836d98f570c171dbe055775430e495b
-  languageName: node
-  linkType: hard
-
 "co@npm:^4.6.0":
   version: 4.6.0
   resolution: "co@npm:4.6.0"
@@ -6486,13 +6422,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"cookie@npm:^0.4.0":
-  version: 0.4.1
-  resolution: "cookie@npm:0.4.1"
-  checksum: bd7c47f5d94ab70ccdfe8210cde7d725880d2fcda06d8e375afbdd82de0c8d3b73541996e9ce57d35f67f672c4ee6d60208adec06b3c5fc94cebb85196084cf8
-  languageName: node
-  linkType: hard
-
 "copy-concurrently@npm:^1.0.0":
   version: 1.0.5
   resolution: "copy-concurrently@npm:1.0.5"
@@ -7114,7 +7043,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"debug@npm:4, debug@npm:^4.0.0, debug@npm:^4.0.1, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1":
+"debug@npm:4, debug@npm:^4.0.1, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1":
   version: 4.3.2
   resolution: "debug@npm:4.3.2"
   dependencies:
@@ -7277,13 +7206,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"denque@npm:^1.1.0":
-  version: 1.5.0
-  resolution: "denque@npm:1.5.0"
-  checksum: 9c0d07a3a6789bccc24f7023a54c83b8850b36c8fbc3aff4bf43b01b76a93ae11c88139502913534fe913bac1b0418dbc30e487ce3d176cbbc001a7a18627c56
-  languageName: node
-  linkType: hard
-
 "depd@npm:^1.1.2, depd@npm:~1.1.2":
   version: 1.1.2
   resolution: "depd@npm:1.1.2"
@@ -7577,13 +7499,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"dotenv@npm:^9.0.2":
-  version: 9.0.2
-  resolution: "dotenv@npm:9.0.2"
-  checksum: 6b7980330a653089bc9b83362248547791151ee74f9881eb223ac2f4d641b174b708f77315d88708b551d45b4177afd3ba71bca4832f8807e003f71c2a0f83e7
-  languageName: node
-  linkType: hard
-
 "dotgitignore@npm:^2.1.0":
   version: 2.1.0
   resolution: "dotgitignore@npm:2.1.0"
@@ -8612,13 +8527,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"fast-decode-uri-component@npm:^1.0.1":
-  version: 1.0.1
-  resolution: "fast-decode-uri-component@npm:1.0.1"
-  checksum: 427a48fe0907e76f0e9a2c228e253b4d8a8ab21d130ee9e4bb8339c5ba4086235cf9576831f7b20955a752eae4b525a177ff9d5825dd8d416e7726939194fbee
-  languageName: node
-  linkType: hard
-
 "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3":
   version: 3.1.3
   resolution: "fast-deep-equal@npm:3.1.3"
@@ -8646,18 +8554,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"fast-json-stringify@npm:^2.5.2":
-  version: 2.7.8
-  resolution: "fast-json-stringify@npm:2.7.8"
-  dependencies:
-    ajv: ^6.11.0
-    deepmerge: ^4.2.2
-    rfdc: ^1.2.0
-    string-similarity: ^4.0.1
-  checksum: 78699673bf2852aa3d0984d697de745fca7c5515a79ee13cfc0c754e579807e1fc0a9aa0c18e7b1e8b3378facf6045bc67a4b28b59c6f6048256043a3fbd2c68
-  languageName: node
-  linkType: hard
-
 "fast-levenshtein@npm:^2.0.6, fast-levenshtein@npm:~2.0.6":
   version: 2.0.6
   resolution: "fast-levenshtein@npm:2.0.6"
@@ -8665,75 +8561,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"fast-redact@npm:^3.0.0":
-  version: 3.0.1
-  resolution: "fast-redact@npm:3.0.1"
-  checksum: 89de97ea5cdb32c8ba127c48cf789dd9011dcca72513aa5bb268262fdc6402834b8060782821559c5891bd049c53572f3c6fdb1f4cd26d788614f1dcb01ba39a
-  languageName: node
-  linkType: hard
-
-"fast-safe-stringify@npm:^2.0.8":
-  version: 2.0.8
-  resolution: "fast-safe-stringify@npm:2.0.8"
-  checksum: be8a07f342817e80c37286509355f91170bd89be9c1df9512ba0c5a61ce20ccf9bdae42ccf65e1fa3834734c78fc524121f709303ebbb97d22df3cb03ff9d7a5
-  languageName: node
-  linkType: hard
-
-"fastify-error@npm:^0.3.0":
-  version: 0.3.1
-  resolution: "fastify-error@npm:0.3.1"
-  checksum: fd6a0f6f87b5e4ab59a4d3d66124bd13830a1cf85cf1987259dfb1175fc6a4bcae68b076ad78f6bb06654f72af133b44813090e9ce5502d2ef56ddcb2b0fa867
-  languageName: node
-  linkType: hard
-
-"fastify-plugin@npm:^3.0.0":
-  version: 3.0.0
-  resolution: "fastify-plugin@npm:3.0.0"
-  checksum: 00324690789ee02f977ab58ba70d937e2e420a6813a6aa7ae3ba47e34022dc8ac40e15a36ab14a67d94474de984398b1c8b30279fb51d92966f5d3d3ebd1b6fa
-  languageName: node
-  linkType: hard
-
-"fastify-warning@npm:^0.2.0":
-  version: 0.2.0
-  resolution: "fastify-warning@npm:0.2.0"
-  checksum: c19ebccf54a3122877d2248400772ca98bacbabdf97826211ede29246c640d47431a2eebed1f52f9421139ed5e52e42d3bd4aefc46e27b6f34add3507529fd97
-  languageName: node
-  linkType: hard
-
-"fastify-websocket@npm:^3.2.0":
-  version: 3.2.0
-  resolution: "fastify-websocket@npm:3.2.0"
-  dependencies:
-    fastify-plugin: ^3.0.0
-    ws: ^7.4.2
-  checksum: 1aa0d5d797616daad626cc0bef3b47b0113137f97f0414249970ddb8c98e6e08570f9cf4257322e5aa23aabe44e9147997a91f906a0f79e65e8cf26d062bd0d9
-  languageName: node
-  linkType: hard
-
-"fastify@npm:^3.18.1":
-  version: 3.20.1
-  resolution: "fastify@npm:3.20.1"
-  dependencies:
-    "@fastify/ajv-compiler": ^1.0.0
-    abstract-logging: ^2.0.0
-    avvio: ^7.1.2
-    fast-json-stringify: ^2.5.2
-    fastify-error: ^0.3.0
-    fastify-warning: ^0.2.0
-    find-my-way: ^4.1.0
-    flatstr: ^1.0.12
-    light-my-request: ^4.2.0
-    pino: ^6.13.0
-    proxy-addr: ^2.0.7
-    readable-stream: ^3.4.0
-    rfdc: ^1.1.4
-    secure-json-parse: ^2.0.0
-    semver: ^7.3.2
-    tiny-lru: ^7.0.0
-  checksum: e6742daf0ff7aa95c21ee5ca3dc46c39f270d708981c8952b0e7cb35285c41f3b53ff59933e90169a6c813bbe65e34d0eed722b734dcad1681c1f9c5e691248e
-  languageName: node
-  linkType: hard
-
 "fastparse@npm:^1.1.2":
   version: 1.1.2
   resolution: "fastparse@npm:1.1.2"
@@ -8741,7 +8568,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"fastq@npm:^1.6.0, fastq@npm:^1.6.1":
+"fastq@npm:^1.6.0":
   version: 1.11.1
   resolution: "fastq@npm:1.11.1"
   dependencies:
@@ -8894,18 +8721,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"find-my-way@npm:^4.1.0":
-  version: 4.3.3
-  resolution: "find-my-way@npm:4.3.3"
-  dependencies:
-    fast-decode-uri-component: ^1.0.1
-    fast-deep-equal: ^3.1.3
-    safe-regex2: ^2.0.0
-    semver-store: ^0.3.0
-  checksum: c5f212d2d2a5e76be91a86409b2de9391a1c3cf5210d357facf0fe91d1e46608865aa2396a98a8d4772116bfae2eb0b05abe4efa725d5cf3cc9b9554bb34e048
-  languageName: node
-  linkType: hard
-
 "find-up@npm:4.1.0, find-up@npm:^4.0.0, find-up@npm:^4.1.0":
   version: 4.1.0
   resolution: "find-up@npm:4.1.0"
@@ -8954,13 +8769,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"flatstr@npm:^1.0.12":
-  version: 1.0.12
-  resolution: "flatstr@npm:1.0.12"
-  checksum: e1bb562c94b119e958bf37e55738b172b5f8aaae6532b9660ecd877779f8559dbbc89613ba6b29ccc13447e14c59277d41450f785cf75c30df9fce62f459e9a8
-  languageName: node
-  linkType: hard
-
 "flatted@npm:^3.1.0":
   version: 3.2.2
   resolution: "flatted@npm:3.2.2"
@@ -10274,25 +10082,6 @@ fsevents@^1.2.7:
   languageName: node
   linkType: hard
 
-"ioredis@npm:^4.27.6":
-  version: 4.27.7
-  resolution: "ioredis@npm:4.27.7"
-  dependencies:
-    cluster-key-slot: ^1.1.0
-    debug: ^4.3.1
-    denque: ^1.1.0
-    lodash.defaults: ^4.2.0
-    lodash.flatten: ^4.4.0
-    lodash.isarguments: ^3.1.0
-    p-map: ^2.1.0
-    redis-commands: 1.7.0
-    redis-errors: ^1.2.0
-    redis-parser: ^3.0.0
-    standard-as-callback: ^2.1.0
-  checksum: 42c2f242b3c91202578415dc39fbc9e9ecff58f19acbd91b654cbe12877181e18dbeb6c12b3e71225a7cc928cc4e34f536953375978093c7c1a6f7417a9dfd84
-  languageName: node
-  linkType: hard
-
 "ip-regex@npm:^2.1.0":
   version: 2.1.0
   resolution: "ip-regex@npm:2.1.0"
@@ -12308,19 +12097,6 @@ fsevents@^1.2.7:
   languageName: node
   linkType: hard
 
-"light-my-request@npm:^4.2.0":
-  version: 4.4.1
-  resolution: "light-my-request@npm:4.4.1"
-  dependencies:
-    ajv: ^6.12.2
-    cookie: ^0.4.0
-    fastify-warning: ^0.2.0
-    readable-stream: ^3.6.0
-    set-cookie-parser: ^2.4.1
-  checksum: f701296c0ec67c400ee3b6dcb6320fdca2816eed64abd7a6a20a12afa70b0d8843737eda3c548f64838399ea30f1f938462815158854c83f9ff8266dee40d129
-  languageName: node
-  linkType: hard
-
 "lines-and-columns@npm:^1.1.6":
   version: 1.1.6
   resolution: "lines-and-columns@npm:1.1.6"
@@ -12458,27 +12234,6 @@ fsevents@^1.2.7:
   languageName: node
   linkType: hard
 
-"lodash.defaults@npm:^4.2.0":
-  version: 4.2.0
-  resolution: "lodash.defaults@npm:4.2.0"
-  checksum: 84923258235592c8886e29de5491946ff8c2ae5c82a7ac5cddd2e3cb697e6fbdfbbb6efcca015795c86eec2bb953a5a2ee4016e3735a3f02720428a40efbb8f1
-  languageName: node
-  linkType: hard
-
-"lodash.flatten@npm:^4.4.0":
-  version: 4.4.0
-  resolution: "lodash.flatten@npm:4.4.0"
-  checksum: 0ac34a393d4b795d4b7421153d27c13ae67e08786c9cbb60ff5b732210d46f833598eee3fb3844bb10070e8488efe390ea53bb567377e0cb47e9e630bf0811cb
-  languageName: node
-  linkType: hard
-
-"lodash.isarguments@npm:^3.1.0":
-  version: 3.1.0
-  resolution: "lodash.isarguments@npm:3.1.0"
-  checksum: ae1526f3eb5c61c77944b101b1f655f846ecbedcb9e6b073526eba6890dc0f13f09f72e11ffbf6540b602caee319af9ac363d6cdd6be41f4ee453436f04f13b5
-  languageName: node
-  linkType: hard
-
 "lodash.ismatch@npm:^4.4.0":
   version: 4.4.0
   resolution: "lodash.ismatch@npm:4.4.0"
@@ -14025,7 +13780,7 @@ fsevents@^1.2.7:
   languageName: node
   linkType: hard
 
-"p-map@npm:^2.0.0, p-map@npm:^2.1.0":
+"p-map@npm:^2.0.0":
   version: 2.1.0
   resolution: "p-map@npm:2.1.0"
   checksum: 9e3ad3c9f6d75a5b5661bcad78c91f3a63849189737cd75e4f1225bf9ac205194e5c44aac2ef6f09562b1facdb9bd1425584d7ac375bfaa17b3f1a142dab936d
@@ -14370,29 +14125,6 @@ fsevents@^1.2.7:
   languageName: node
   linkType: hard
 
-"pino-std-serializers@npm:^3.1.0":
-  version: 3.2.0
-  resolution: "pino-std-serializers@npm:3.2.0"
-  checksum: 77e29675b116e42ae9fe6d4ef52ef3a082ffc54922b122d85935f93ddcc20277f0b0c873c5c6c5274a67b0409c672aaae3de6bcea10a2d84699718dda55ba95b
-  languageName: node
-  linkType: hard
-
-"pino@npm:^6.13.0":
-  version: 6.13.0
-  resolution: "pino@npm:6.13.0"
-  dependencies:
-    fast-redact: ^3.0.0
-    fast-safe-stringify: ^2.0.8
-    flatstr: ^1.0.12
-    pino-std-serializers: ^3.1.0
-    quick-format-unescaped: ^4.0.3
-    sonic-boom: ^1.0.2
-  bin:
-    pino: bin.js
-  checksum: 7145de4287f03bc3f7ff4de0cdacfcfea9d843e5759c90f95f6a245b6898964387f6bd24813749333c23684186bc79d91a2d03f28512f2c4a3f8bc6773316a1c
-  languageName: node
-  linkType: hard
-
 "pirates@npm:^4.0.1":
   version: 4.0.1
   resolution: "pirates@npm:4.0.1"
@@ -15555,7 +15287,7 @@ fsevents@^1.2.7:
   languageName: node
   linkType: hard
 
-"proxy-addr@npm:^2.0.7, proxy-addr@npm:~2.0.5":
+"proxy-addr@npm:~2.0.5":
   version: 2.0.7
   resolution: "proxy-addr@npm:2.0.7"
   dependencies:
@@ -15706,20 +15438,13 @@ fsevents@^1.2.7:
   languageName: node
   linkType: hard
 
-"queue-microtask@npm:^1.1.2, queue-microtask@npm:^1.2.2":
+"queue-microtask@npm:^1.2.2":
   version: 1.2.3
   resolution: "queue-microtask@npm:1.2.3"
   checksum: b676f8c040cdc5b12723ad2f91414d267605b26419d5c821ff03befa817ddd10e238d22b25d604920340fd73efd8ba795465a0377c4adf45a4a41e4234e42dc4
   languageName: node
   linkType: hard
 
-"quick-format-unescaped@npm:^4.0.3":
-  version: 4.0.3
-  resolution: "quick-format-unescaped@npm:4.0.3"
-  checksum: 28dd3f3fbfec385cdca779e905d48c1a4623ee1f8071f060c7b38625eded5b5472433ae38ec09b8f8d968b443dfda7aa156811c59c4dfe0b52b73c3bc6d714ed
-  languageName: node
-  linkType: hard
-
 "quick-lru@npm:^1.0.0":
   version: 1.1.0
   resolution: "quick-lru@npm:1.1.0"
@@ -16108,7 +15833,7 @@ fsevents@^1.2.7:
   languageName: node
   linkType: hard
 
-"readable-stream@npm:3, readable-stream@npm:^3.0.0, readable-stream@npm:^3.0.2, readable-stream@npm:^3.0.6, readable-stream@npm:^3.4.0, readable-stream@npm:^3.6.0":
+"readable-stream@npm:3, readable-stream@npm:^3.0.0, readable-stream@npm:^3.0.2, readable-stream@npm:^3.0.6, readable-stream@npm:^3.6.0":
   version: 3.6.0
   resolution: "readable-stream@npm:3.6.0"
   dependencies:
@@ -16168,29 +15893,6 @@ fsevents@^1.2.7:
   languageName: node
   linkType: hard
 
-"redis-commands@npm:1.7.0":
-  version: 1.7.0
-  resolution: "redis-commands@npm:1.7.0"
-  checksum: d1ff7fbcb5e54768c77f731f1d49679d2a62c3899522c28addb4e2e5813aea8bcac3f22519d71d330224c3f2937f935dfc3d8dc65e90db0f5fe22dc2c1515aa7
-  languageName: node
-  linkType: hard
-
-"redis-errors@npm:^1.0.0, redis-errors@npm:^1.2.0":
-  version: 1.2.0
-  resolution: "redis-errors@npm:1.2.0"
-  checksum: f28ac2692113f6f9c222670735aa58aeae413464fd58ccf3fce3f700cae7262606300840c802c64f2b53f19f65993da24dc918afc277e9e33ac1ff09edb394f4
-  languageName: node
-  linkType: hard
-
-"redis-parser@npm:^3.0.0":
-  version: 3.0.0
-  resolution: "redis-parser@npm:3.0.0"
-  dependencies:
-    redis-errors: ^1.0.0
-  checksum: 89290ae530332f2ae37577647fa18208d10308a1a6ba750b9d9a093e7398f5e5253f19855b64c98757f7129cccce958e4af2573fdc33bad41405f87f1943459a
-  languageName: node
-  linkType: hard
-
 "redux@npm:^3.6.0 || ^4.0.0":
   version: 4.1.0
   resolution: "redux@npm:4.1.0"
@@ -16539,13 +16241,6 @@ resolve@^2.0.0-next.3:
   languageName: node
   linkType: hard
 
-"ret@npm:~0.2.0":
-  version: 0.2.2
-  resolution: "ret@npm:0.2.2"
-  checksum: 774964bb413a3525e687bca92d81c1cd75555ec33147c32ecca22f3d06409e35df87952cfe3d57afff7650a0f7e42139cf60cb44e94c29dde390243bc1941f16
-  languageName: node
-  linkType: hard
-
 "retry@npm:^0.12.0":
   version: 0.12.0
   resolution: "retry@npm:0.12.0"
@@ -16577,13 +16272,6 @@ resolve@^2.0.0-next.3:
   languageName: node
   linkType: hard
 
-"rfdc@npm:^1.1.4, rfdc@npm:^1.2.0":
-  version: 1.3.0
-  resolution: "rfdc@npm:1.3.0"
-  checksum: fb2ba8512e43519983b4c61bd3fa77c0f410eff6bae68b08614437bc3f35f91362215f7b4a73cbda6f67330b5746ce07db5dd9850ad3edc91271ad6deea0df32
-  languageName: node
-  linkType: hard
-
 "rgb-regex@npm:^1.0.1":
   version: 1.0.1
   resolution: "rgb-regex@npm:1.0.1"
@@ -16825,15 +16513,6 @@ resolve@^2.0.0-next.3:
   languageName: node
   linkType: hard
 
-"safe-regex2@npm:^2.0.0":
-  version: 2.0.0
-  resolution: "safe-regex2@npm:2.0.0"
-  dependencies:
-    ret: ~0.2.0
-  checksum: f5e182fca040dedd50ae052ea0eb035d9903b2db71243d5d8b43299735857288ef2ab52546a368d9c6fd1333b2a0d039297925e78ffc14845354f3f6158af7c2
-  languageName: node
-  linkType: hard
-
 "safe-regex@npm:^1.1.0":
   version: 1.1.0
   resolution: "safe-regex@npm:1.1.0"
@@ -16970,13 +16649,6 @@ resolve@^2.0.0-next.3:
   languageName: node
   linkType: hard
 
-"secure-json-parse@npm:^2.0.0":
-  version: 2.4.0
-  resolution: "secure-json-parse@npm:2.4.0"
-  checksum: efaafcaa08a4646ca829b29168474f57fb289a0ca7a1d77b66b55a0292785bc6eb9143b21cfc50b37dd12a823c25b12aa1771f18314ed5a616a1f8f12a318533
-  languageName: node
-  linkType: hard
-
 "select-hose@npm:^2.0.0":
   version: 2.0.0
   resolution: "select-hose@npm:2.0.0"
@@ -16993,13 +16665,6 @@ resolve@^2.0.0-next.3:
   languageName: node
   linkType: hard
 
-"semver-store@npm:^0.3.0":
-  version: 0.3.0
-  resolution: "semver-store@npm:0.3.0"
-  checksum: b38f747123e850191526a912657c653c7e5963d164a8daf99e52aa30bc8c5bdac176dc6dab714e17a1a8489ac138c18ff7161b1961f1882888bce637990442dd
-  languageName: node
-  linkType: hard
-
 "semver@npm:2 || 3 || 4 || 5, semver@npm:^5.4.1, semver@npm:^5.5.0, semver@npm:^5.5.1, semver@npm:^5.6.0":
   version: 5.7.1
   resolution: "semver@npm:5.7.1"
@@ -17120,13 +16785,6 @@ resolve@^2.0.0-next.3:
   languageName: node
   linkType: hard
 
-"set-cookie-parser@npm:^2.4.1":
-  version: 2.4.8
-  resolution: "set-cookie-parser@npm:2.4.8"
-  checksum: e15b5df9a56ab06d4895286033a6aff7b318ad024310df058b5821b3539cc06f716ef529618cac0dd78df40e37830de715f388c0f97f84062dd9be2326efcd0c
-  languageName: node
-  linkType: hard
-
 "set-value@npm:^2.0.0, set-value@npm:^2.0.1":
   version: 2.0.1
   resolution: "set-value@npm:2.0.1"
@@ -17359,16 +17017,6 @@ resolve@^2.0.0-next.3:
   languageName: node
   linkType: hard
 
-"sonic-boom@npm:^1.0.2":
-  version: 1.4.1
-  resolution: "sonic-boom@npm:1.4.1"
-  dependencies:
-    atomic-sleep: ^1.0.0
-    flatstr: ^1.0.12
-  checksum: 189fa8fe5c2dc05d3513fc1a4926a2f16f132fa6fa0b511745a436010cdcd9c1d3b3cb6a9d7c05bd32a965dc77673a5ac0eb0992e920bdedd16330d95323124f
-  languageName: node
-  linkType: hard
-
 "sort-keys@npm:^1.0.0":
   version: 1.1.2
   resolution: "sort-keys@npm:1.1.2"
@@ -17605,13 +17253,6 @@ resolve@^2.0.0-next.3:
   languageName: node
   linkType: hard
 
-"standard-as-callback@npm:^2.1.0":
-  version: 2.1.0
-  resolution: "standard-as-callback@npm:2.1.0"
-  checksum: 88bec83ee220687c72d94fd86a98d5272c91d37ec64b66d830dbc0d79b62bfa6e47f53b71646011835fc9ce7fae62739545d13124262b53be4fbb3e2ebad551c
-  languageName: node
-  linkType: hard
-
 "standard-version@npm:9.1.0":
   version: 9.1.0
   resolution: "standard-version@npm:9.1.0"
@@ -17725,13 +17366,6 @@ resolve@^2.0.0-next.3:
   languageName: node
   linkType: hard
 
-"string-similarity@npm:^4.0.1":
-  version: 4.0.4
-  resolution: "string-similarity@npm:4.0.4"
-  checksum: 797b41b24e1eb6b3b0ab896950b58c295a19a82933479c75f7b5279ffb63e0b456a8c8d10329c02f607ca1a50370e961e83d552aa468ff3b0fa15809abc9eff7
-  languageName: node
-  linkType: hard
-
 "string-width@npm:^1.0.1":
   version: 1.0.2
   resolution: "string-width@npm:1.0.2"
@@ -18309,13 +17943,6 @@ resolve@^2.0.0-next.3:
   languageName: node
   linkType: hard
 
-"tiny-lru@npm:^7.0.0":
-  version: 7.0.6
-  resolution: "tiny-lru@npm:7.0.6"
-  checksum: 36a786a9111a3a358a698c9404783ad3f5396f6ed891672ffa4cd7dec4617abb8dfed6af7611bbaf8a3942a9475534c8b80f9bd58d7efa9aa594f395c9805f09
-  languageName: node
-  linkType: hard
-
 "tiny-warning@npm:^1.0.2":
   version: 1.0.3
   resolution: "tiny-warning@npm:1.0.3"
@@ -19692,7 +19319,7 @@ typescript@^3.8.3:
   languageName: node
   linkType: hard
 
-"ws@npm:^7.4.2, ws@npm:^7.4.6":
+"ws@npm:^7.4.6":
   version: 7.5.3
   resolution: "ws@npm:7.5.3"
   peerDependencies: