Просмотр исходного кода

Merge branch 'master' into support/148552-replace-tests-with-playwright

Shun Miyazawa 1 год назад
Родитель
Сommit
a13abbdb89

+ 0 - 5
.changeset/tasty-baboons-burn.md

@@ -1,5 +0,0 @@
----
-'@growi/pluginkit': patch
----
-
-Update tsconfig.json module setting

+ 1 - 1
apps/app/package.json

@@ -205,7 +205,7 @@
     "url-join": "^4.0.0",
     "usehooks-ts": "^2.6.0",
     "validator": "^13.7.0",
-    "ws": "^8.3.0",
+    "ws": "^8.17.1",
     "xss": "^1.0.14",
     "y-mongodb-provider": "^0.1.10",
     "y-socket.io": "^1.1.3",

+ 14 - 0
apps/app/playwright/21-basic-features-for-guest/sticky-for-guest.spec.ts

@@ -0,0 +1,14 @@
+import { test, expect } from '@playwright/test';
+
+
+test('Sub navigation sticky changes when scrolling down and up', async({ page }) => {
+  await page.goto('/Sandbox');
+
+  // Sticky
+  await page.evaluate(() => window.scrollTo(0, 250));
+  await expect(page.locator('.sticky-outer-wrapper').first()).toHaveClass(/active/);
+
+  // Not sticky
+  await page.evaluate(() => window.scrollTo(0, 0));
+  await expect(page.locator('.sticky-outer-wrapper').first()).not.toHaveClass(/active/);
+});

+ 4 - 2
apps/app/src/components/Layout/RawLayout.tsx

@@ -2,14 +2,13 @@ import type { ReactNode } from 'react';
 import React, { useState } from 'react';
 
 import type { ColorScheme } from '@growi/core';
+import dynamic from 'next/dynamic';
 import Head from 'next/head';
-import { ToastContainer } from 'react-toastify';
 import { useIsomorphicLayoutEffect } from 'usehooks-ts';
 
 import { useNextThemes, NextThemesProvider } from '~/stores/use-next-themes';
 import loggerFactory from '~/utils/logger';
 
-
 import styles from './RawLayout.module.scss';
 
 const toastContainerClass = styles['grw-toast-container'] ?? '';
@@ -17,6 +16,9 @@ const toastContainerClass = styles['grw-toast-container'] ?? '';
 const logger = loggerFactory('growi:cli:RawLayout');
 
 
+const ToastContainer = dynamic(() => import('react-toastify').then(mod => mod.ToastContainer), { ssr: false });
+
+
 type Props = {
   className?: string,
   children?: ReactNode,

+ 13 - 6
apps/app/src/stores/alert.tsx

@@ -1,3 +1,5 @@
+import { useCallback } from 'react';
+
 import { useSWRStatic } from '@growi/core/dist/swr';
 import type { SWRResponse } from 'swr';
 
@@ -26,14 +28,19 @@ type PageStatusAlertUtils = {
 export const usePageStatusAlert = (): SWRResponse<PageStatusAlertStatus, Error> & PageStatusAlertUtils => {
   const initialData: PageStatusAlertStatus = { isOpen: false };
   const swrResponse = useSWRStatic<PageStatusAlertStatus, Error>('pageStatusAlert', undefined, { fallbackData: initialData });
+  const { mutate } = swrResponse;
+
+  const open = useCallback(({ ...options }) => {
+    mutate({ isOpen: true, ...options });
+  }, [mutate]);
+
+  const close = useCallback(() => {
+    mutate({ isOpen: false });
+  }, [mutate]);
 
   return {
     ...swrResponse,
-    open({ ...options }) {
-      swrResponse.mutate({ isOpen: true, ...options });
-    },
-    close() {
-      swrResponse.mutate({ isOpen: false });
-    },
+    open,
+    close,
   };
 };

+ 32 - 28
apps/app/src/stores/modal.tsx

@@ -13,8 +13,6 @@ import type {
 } from '~/interfaces/ui';
 import loggerFactory from '~/utils/logger';
 
-import { useStaticSWR } from './use-static-swr';
-
 const logger = loggerFactory('growi:stores:modal');
 
 /*
@@ -32,7 +30,7 @@ type CreateModalStatusUtils = {
 
 export const usePageCreateModal = (status?: CreateModalStatus): SWRResponse<CreateModalStatus, Error> & CreateModalStatusUtils => {
   const initialData: CreateModalStatus = { isOpened: false };
-  const swrResponse = useStaticSWR<CreateModalStatus, Error>('pageCreateModalStatus', status, { fallbackData: initialData });
+  const swrResponse = useSWRStatic<CreateModalStatus, Error>('pageCreateModalStatus', status, { fallbackData: initialData });
 
   return {
     ...swrResponse,
@@ -99,7 +97,7 @@ export const usePageDeleteModal = (status?: DeleteModalStatus): SWRResponse<Dele
     isOpened: false,
     pages: [],
   };
-  const swrResponse = useStaticSWR<DeleteModalStatus, Error>('deleteModalStatus', status, { fallbackData: initialData });
+  const swrResponse = useSWRStatic<DeleteModalStatus, Error>('deleteModalStatus', status, { fallbackData: initialData });
 
   return {
     ...swrResponse,
@@ -140,7 +138,7 @@ export const useEmptyTrashModal = (status?: EmptyTrashModalStatus): SWRResponse<
     isOpened: false,
     pages: [],
   };
-  const swrResponse = useStaticSWR<EmptyTrashModalStatus, Error>('emptyTrashModalStatus', status, { fallbackData: initialData });
+  const swrResponse = useSWRStatic<EmptyTrashModalStatus, Error>('emptyTrashModalStatus', status, { fallbackData: initialData });
 
   return {
     ...swrResponse,
@@ -182,7 +180,7 @@ type DuplicateModalStatusUtils = {
 
 export const usePageDuplicateModal = (status?: DuplicateModalStatus): SWRResponse<DuplicateModalStatus, Error> & DuplicateModalStatusUtils => {
   const initialData: DuplicateModalStatus = { isOpened: false };
-  const swrResponse = useStaticSWR<DuplicateModalStatus, Error>('duplicateModalStatus', status, { fallbackData: initialData });
+  const swrResponse = useSWRStatic<DuplicateModalStatus, Error>('duplicateModalStatus', status, { fallbackData: initialData });
 
   return {
     ...swrResponse,
@@ -218,7 +216,7 @@ type RenameModalStatusUtils = {
 
 export const usePageRenameModal = (status?: RenameModalStatus): SWRResponse<RenameModalStatus, Error> & RenameModalStatusUtils => {
   const initialData: RenameModalStatus = { isOpened: false };
-  const swrResponse = useStaticSWR<RenameModalStatus, Error>('renameModalStatus', status, { fallbackData: initialData });
+  const swrResponse = useSWRStatic<RenameModalStatus, Error>('renameModalStatus', status, { fallbackData: initialData });
 
   return {
     ...swrResponse,
@@ -264,7 +262,7 @@ export const usePutBackPageModal = (status?: PutBackPageModalStatus): SWRRespons
     isOpened: false,
     page: { pageId: '', path: '' },
   }), []);
-  const swrResponse = useStaticSWR<PutBackPageModalStatus, Error>('putBackPageModalStatus', status, { fallbackData: initialData });
+  const swrResponse = useSWRStatic<PutBackPageModalStatus, Error>('putBackPageModalStatus', status, { fallbackData: initialData });
 
   return {
     ...swrResponse,
@@ -296,7 +294,7 @@ export const usePagePresentationModal = (
   const initialData: PresentationModalStatus = {
     isOpened: false,
   };
-  const swrResponse = useStaticSWR<PresentationModalStatus, Error>('presentationModalStatus', status, { fallbackData: initialData });
+  const swrResponse = useSWRStatic<PresentationModalStatus, Error>('presentationModalStatus', status, { fallbackData: initialData });
 
   return {
     ...swrResponse,
@@ -332,7 +330,7 @@ export const usePrivateLegacyPagesMigrationModal = (
     isOpened: false,
     pages: [],
   };
-  const swrResponse = useStaticSWR<PrivateLegacyPagesMigrationModalStatus, Error>('privateLegacyPagesMigrationModal', status, { fallbackData: initialData });
+  const swrResponse = useSWRStatic<PrivateLegacyPagesMigrationModalStatus, Error>('privateLegacyPagesMigrationModal', status, { fallbackData: initialData });
 
   return {
     ...swrResponse,
@@ -362,7 +360,7 @@ export const useDescendantsPageListModal = (
 ): SWRResponse<DescendantsPageListModalStatus, Error> & DescendantsPageListUtils => {
 
   const initialData: DescendantsPageListModalStatus = { isOpened: false };
-  const swrResponse = useStaticSWR<DescendantsPageListModalStatus, Error>('descendantsPageListModalStatus', status, { fallbackData: initialData });
+  const swrResponse = useSWRStatic<DescendantsPageListModalStatus, Error>('descendantsPageListModalStatus', status, { fallbackData: initialData });
 
   return {
     ...swrResponse,
@@ -445,7 +443,7 @@ type UpdateUserGroupConfirmModalUtils = {
 export const useUpdateUserGroupConfirmModal = (): SWRResponse<UpdateUserGroupConfirmModalStatus, Error> & UpdateUserGroupConfirmModalUtils => {
 
   const initialStatus: UpdateUserGroupConfirmModalStatus = { isOpened: false };
-  const swrResponse = useStaticSWR<UpdateUserGroupConfirmModalStatus, Error>('updateParentConfirmModal', undefined, { fallbackData: initialStatus });
+  const swrResponse = useSWRStatic<UpdateUserGroupConfirmModalStatus, Error>('updateParentConfirmModal', undefined, { fallbackData: initialStatus });
 
   return {
     ...swrResponse,
@@ -475,7 +473,7 @@ type ShortcutsModalUtils = {
 export const useShortcutsModal = (): SWRResponse<ShortcutsModalStatus, Error> & ShortcutsModalUtils => {
 
   const initialStatus: ShortcutsModalStatus = { isOpened: false };
-  const swrResponse = useStaticSWR<ShortcutsModalStatus, Error>('shortcutsModal', undefined, { fallbackData: initialStatus });
+  const swrResponse = useSWRStatic<ShortcutsModalStatus, Error>('shortcutsModal', undefined, { fallbackData: initialStatus });
 
   return {
     ...swrResponse,
@@ -514,7 +512,7 @@ export const useDrawioModal = (status?: DrawioModalStatus): SWRResponse<DrawioMo
     isOpened: false,
     drawioMxFile: '',
   };
-  const swrResponse = useStaticSWR<DrawioModalStatus, Error>('drawioModalStatus', status, { fallbackData: initialData });
+  const swrResponse = useSWRStatic<DrawioModalStatus, Error>('drawioModalStatus', status, { fallbackData: initialData });
 
   const { mutate } = swrResponse;
 
@@ -575,7 +573,7 @@ export const useHandsontableModal = (status?: HandsontableModalStatus): SWRRespo
     autoFormatMarkdownTable: false,
   };
 
-  const swrResponse = useStaticSWR<HandsontableModalStatus, Error>('handsontableModalStatus', status, { fallbackData: initialData });
+  const swrResponse = useSWRStatic<HandsontableModalStatus, Error>('handsontableModalStatus', status, { fallbackData: initialData });
 
   const { mutate } = swrResponse;
 
@@ -616,16 +614,22 @@ type ConflictDiffModalUtils = {
 export const useConflictDiffModal = (): SWRResponse<ConflictDiffModalStatus, Error> & ConflictDiffModalUtils => {
 
   const initialStatus: ConflictDiffModalStatus = { isOpened: false };
-  const swrResponse = useStaticSWR<ConflictDiffModalStatus, Error>('conflictDiffModal', undefined, { fallbackData: initialStatus });
+  const swrResponse = useSWRStatic<ConflictDiffModalStatus, Error>('conflictDiffModal', undefined, { fallbackData: initialStatus });
+  const { mutate } = swrResponse;
 
-  return Object.assign(swrResponse, {
-    open: (requestRevisionBody: string, onResolve: ResolveConflictHandler) => {
-      swrResponse.mutate({ isOpened: true, requestRevisionBody, onResolve });
-    },
-    close: () => {
-      swrResponse.mutate({ isOpened: false });
-    },
-  });
+  const open = useCallback((requestRevisionBody: string, onResolve: ResolveConflictHandler) => {
+    mutate({ isOpened: true, requestRevisionBody, onResolve });
+  }, [mutate]);
+
+  const close = useCallback(() => {
+    mutate({ isOpened: false });
+  }, [mutate]);
+
+  return {
+    ...swrResponse,
+    open,
+    close,
+  };
 };
 
 /*
@@ -654,7 +658,7 @@ export const useBookmarkFolderDeleteModal = (status?: DeleteBookmarkFolderModalS
   const initialData: DeleteBookmarkFolderModalStatus = {
     isOpened: false,
   };
-  const swrResponse = useStaticSWR<DeleteBookmarkFolderModalStatus, Error>('deleteBookmarkFolderModalStatus', status, { fallbackData: initialData });
+  const swrResponse = useSWRStatic<DeleteBookmarkFolderModalStatus, Error>('deleteBookmarkFolderModalStatus', status, { fallbackData: initialData });
 
   return {
     ...swrResponse,
@@ -696,7 +700,7 @@ export const useDeleteAttachmentModal = (): SWRResponse<DeleteAttachmentModalSta
     attachment: undefined,
     remove: undefined,
   };
-  const swrResponse = useStaticSWR<DeleteAttachmentModalStatus, Error>('deleteAttachmentModal', undefined, { fallbackData: initialStatus });
+  const swrResponse = useSWRStatic<DeleteAttachmentModalStatus, Error>('deleteAttachmentModal', undefined, { fallbackData: initialStatus });
   const { mutate } = swrResponse;
 
   const open = useCallback((attachment: IAttachmentHasId, remove: Remove) => {
@@ -734,7 +738,7 @@ export const usePageSelectModal = (
     status?: PageSelectModalStatus,
 ): SWRResponse<PageSelectModalStatus, Error> & PageSelectModalStatusUtils => {
   const initialStatus = { isOpened: false };
-  const swrResponse = useStaticSWR<PageSelectModalStatus, Error>('PageSelectModal', status, { fallbackData: initialStatus });
+  const swrResponse = useSWRStatic<PageSelectModalStatus, Error>('PageSelectModal', status, { fallbackData: initialStatus });
 
   return {
     ...swrResponse,
@@ -772,7 +776,7 @@ export const useTagEditModal = (): SWRResponse<TagEditModalStatus, Error> & TagE
     };
   }, []);
 
-  const swrResponse = useStaticSWR<TagEditModalStatus, Error>('TagEditModal', undefined, { fallbackData: initialStatus });
+  const swrResponse = useSWRStatic<TagEditModalStatus, Error>('TagEditModal', undefined, { fallbackData: initialStatus });
   const { mutate } = swrResponse;
 
   const open = useCallback(async(tags: string[], pageId: string, revisionId: string) => {

+ 0 - 30
apps/app/test/cypress/e2e/21-basic-features-for-guest/21-basic-features-for-guest--sticky-for-guest.cy.ts

@@ -1,30 +0,0 @@
-context('Access sticky sub navigation switcher for guest', () => {
-  const ssPrefix = 'access-sticky-by-guest-';
-
-  it('Sub navigation sticky changes when scrolling down and up', () => {
-    cy.visit('/Sandbox');
-    cy.waitUntilSkeletonDisappear();
-    cy.collapseSidebar(true, true);
-
-    // Sticky
-    cy.waitUntil(() => {
-      // do
-      // Scroll page down 250px
-      cy.scrollTo(0, 250);
-      // wait until
-      return cy.get('.sticky-outer-wrapper').should('have.class', 'active');
-    });
-    cy.screenshot(`${ssPrefix}subnav-switcher-is-sticky-on-scroll-down`);
-
-    // Not sticky
-    cy.waitUntil(() => {
-      // do
-      // Scroll page to top
-      cy.scrollTo(0, 0);
-      // wait until
-      return cy.get('.sticky-outer-wrapper').should('not.have.class', 'active');
-    });
-    cy.screenshot(`${ssPrefix}subnav-switcher-is-not-sticky-on-scroll-top`);
-  });
-
-});

+ 34 - 1
packages/editor/src/client/components/CodeMirrorEditorReadOnly.tsx

@@ -1,6 +1,7 @@
 import { useEffect } from 'react';
 
-import { type Extension, EditorState } from '@codemirror/state';
+import { type Extension, EditorState, Prec } from '@codemirror/state';
+import { EditorView, keymap } from '@codemirror/view';
 
 import { GlobalCodeMirrorEditorKey } from '../../consts';
 import { setDataLine } from '../services-internal';
@@ -29,6 +30,38 @@ export const CodeMirrorEditorReadOnly = ({ markdown, onScroll }: Props): JSX.Ele
     return codeMirrorEditor?.appendExtensions?.(additionalExtensions);
   }, [codeMirrorEditor]);
 
+
+  // prevent Ctrl+V and paste
+  useEffect(() => {
+    const extension = keymap.of([
+      {
+        key: 'Mod-v',
+        preventDefault: true,
+        run: () => {
+          return true;
+        },
+      },
+    ]);
+    const cleanupFunction = codeMirrorEditor?.appendExtensions?.(extension);
+
+    return cleanupFunction;
+  }, [codeMirrorEditor]);
+
+  useEffect(() => {
+    const handlePaste = (event: ClipboardEvent) => {
+      event.preventDefault();
+      return;
+    };
+    const extension = EditorView.domEventHandlers({
+      paste: handlePaste,
+    });
+
+    const cleanupFunction = codeMirrorEditor?.appendExtensions?.(Prec.high(extension));
+
+    return cleanupFunction;
+  }, [codeMirrorEditor]);
+
+
   return (
     <CodeMirrorEditor
       hideToolbar

+ 6 - 0
packages/pluginkit/CHANGELOG.md

@@ -1,5 +1,11 @@
 # @growi/pluginkit
 
+## 1.0.1
+
+### Patch Changes
+
+- [#8898](https://github.com/weseek/growi/pull/8898) [`7a50227`](https://github.com/weseek/growi/commit/7a502271b35bae4b419e54a08b2b00c7b140db46) Thanks [@yuki-takei](https://github.com/yuki-takei)! - Update tsconfig.json module setting
+
 ## 1.0.0
 
 ### Major Changes

+ 1 - 1
packages/pluginkit/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/pluginkit",
-  "version": "1.0.0",
+  "version": "1.0.1",
   "description": "Plugin kit for GROWI",
   "license": "MIT",
   "main": "dist/index.cjs",

+ 35 - 5
yarn.lock

@@ -2136,7 +2136,7 @@
     react-dom "^18.2.0"
 
 "@growi/pluginkit@link:packages/pluginkit":
-  version "1.0.0"
+  version "1.0.1"
   dependencies:
     "@growi/core" "^1.0.0"
     extensible-custom-error "^0.0.7"
@@ -17258,7 +17258,7 @@ string-template@>=1.0.0:
   resolved "https://registry.yarnpkg.com/string-template/-/string-template-1.0.0.tgz#9e9f2233dc00f218718ec379a28a5673ecca8b96"
   integrity sha1-np8iM9wA8hhxjsN5oopWc+zKi5Y=
 
-"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
+"string-width-cjs@npm:string-width@^4.2.0":
   version "4.2.3"
   resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
   integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -17276,6 +17276,15 @@ string-width@=4.2.2:
     is-fullwidth-code-point "^3.0.0"
     strip-ansi "^6.0.0"
 
+"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
+  version "4.2.3"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+  integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+  dependencies:
+    emoji-regex "^8.0.0"
+    is-fullwidth-code-point "^3.0.0"
+    strip-ansi "^6.0.1"
+
 string-width@^5.0.1, string-width@^5.1.2:
   version "5.1.2"
   resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
@@ -17359,7 +17368,7 @@ stringify-entities@^4.0.0:
     character-entities-html4 "^2.0.0"
     character-entities-legacy "^3.0.0"
 
-"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
   version "6.0.1"
   resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
   integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -17373,6 +17382,13 @@ strip-ansi@^3.0.0:
   dependencies:
     ansi-regex "^2.0.0"
 
+strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+  integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+  dependencies:
+    ansi-regex "^5.0.1"
+
 strip-ansi@^7.0.1, strip-ansi@^7.1.0:
   version "7.1.0"
   resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
@@ -19204,7 +19220,7 @@ word-wrap@^1.2.3:
   resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
   integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
 
-"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
+"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
   version "7.0.0"
   resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
   integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@@ -19222,6 +19238,15 @@ wrap-ansi@^6.2.0:
     string-width "^4.1.0"
     strip-ansi "^6.0.0"
 
+wrap-ansi@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+  integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+  dependencies:
+    ansi-styles "^4.0.0"
+    string-width "^4.1.0"
+    strip-ansi "^6.0.0"
+
 wrap-ansi@^8.1.0:
   version "8.1.0"
   resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
@@ -19267,7 +19292,12 @@ ws@^7.3.1:
   resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591"
   integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==
 
-ws@^8.3.0, ws@~8.11.0:
+ws@^8.17.1:
+  version "8.17.1"
+  resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b"
+  integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==
+
+ws@~8.11.0:
   version "8.11.0"
   resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143"
   integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==