From 3e5bcf96ea16880bf5a2a8b1e9ccb36cd61f6fff Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Mon, 20 Oct 2025 21:15:40 +0200 Subject: [PATCH] =?UTF-8?q?=E2=AC=86=EF=B8=8F(y-provider)=20update=20hocus?= =?UTF-8?q?pocus=20to=203.2.5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The last version of Blocknote seems to have a conflict with hocuspocus 2.15.2, it is a good moment to upgrade to hocuspocus 3.2.5. --- renovate.json | 2 - src/frontend/apps/impress/package.json | 2 +- .../doc-editor/components/BlockNoteEditor.tsx | 9 +- .../docs/doc-editor/components/DocEditor.tsx | 5 +- .../stores/useProviderStore.tsx | 26 +++++ .../docs/doc-share/api/useUpdateDocAccess.ts | 6 +- .../impress/src/pages/docs/[id]/index.tsx | 2 +- .../collaborationResetConnections.test.ts | 2 +- .../getDocumentConnectionInfoHandler.test.ts | 12 +- .../y-provider/__tests__/hocuspocusWS.test.ts | 108 ++++++++---------- src/frontend/servers/y-provider/package.json | 6 +- .../collaborationResetConnectionsHandler.ts | 4 +- .../src/handlers/collaborationWSHandler.ts | 2 +- .../getDocumentConnectionInfoHandler.ts | 2 +- .../src/servers/hocuspocusServer.ts | 6 +- src/frontend/yarn.lock | 42 +++---- 16 files changed, 124 insertions(+), 112 deletions(-) diff --git a/renovate.json b/renovate.json index 7a02e975..4bbb5f61 100644 --- a/renovate.json +++ b/renovate.json @@ -24,8 +24,6 @@ "groupName": "ignored js dependencies", "matchManagers": ["npm"], "matchPackageNames": [ - "@hocuspocus/provider", - "@hocuspocus/server", "docx", "fetch-mock", "node", diff --git a/src/frontend/apps/impress/package.json b/src/frontend/apps/impress/package.json index 2cfbb5c8..3223190b 100644 --- a/src/frontend/apps/impress/package.json +++ b/src/frontend/apps/impress/package.json @@ -35,7 +35,7 @@ "@fontsource/material-icons": "5.2.7", "@gouvfr-lasuite/integration": "1.0.3", "@gouvfr-lasuite/ui-kit": "0.16.2", - "@hocuspocus/provider": "2.15.2", + "@hocuspocus/provider": "3.3.0", "@mantine/core": "8.3.4", "@mantine/hooks": "8.3.4", "@openfun/cunningham-react": "3.2.3", diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx index 7a115cae..80188c33 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx @@ -17,7 +17,11 @@ import { useTranslation } from 'react-i18next'; import * as Y from 'yjs'; import { Box, TextErrors } from '@/components'; -import { Doc, useIsCollaborativeEditable } from '@/docs/doc-management'; +import { + Doc, + useIsCollaborativeEditable, + useProviderStore, +} from '@/docs/doc-management'; import { useAuth } from '@/features/auth'; import { @@ -79,9 +83,10 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => { const { user } = useAuth(); const { setEditor } = useEditorStore(); const { t } = useTranslation(); + const { isSynced } = useProviderStore(); const { isEditable, isLoading } = useIsCollaborativeEditable(doc); - const isConnectedToCollabServer = provider.isSynced; + const isConnectedToCollabServer = isSynced; const readOnly = !doc.abilities.partial_update || !isEditable || isLoading; const isDeletedDoc = !!doc.deleted_at; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx index 94eea99a..c405fe96 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx @@ -4,7 +4,7 @@ import { useEffect, useState } from 'react'; import { css } from 'styled-components'; import * as Y from 'yjs'; -import { Box, Text, TextErrors } from '@/components'; +import { Box, Loading, Text, TextErrors } from '@/components'; import { DocHeader, DocVersionHeader } from '@/docs/doc-header/'; import { Doc, @@ -27,8 +27,9 @@ export const DocEditor = ({ doc, versionId }: DocEditorProps) => { const isVersion = !!versionId && typeof versionId === 'string'; const { provider } = useProviderStore(); + // TODO: Use skeleton instead of loading if (!provider) { - return null; + return ; } return ( diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/stores/useProviderStore.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/stores/useProviderStore.tsx index d6779f21..6971c614 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/stores/useProviderStore.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-management/stores/useProviderStore.tsx @@ -1,3 +1,4 @@ +import { CloseEvent } from '@hocuspocus/common'; import { HocuspocusProvider, WebSocketStatus } from '@hocuspocus/provider'; import * as Y from 'yjs'; import { create } from 'zustand'; @@ -13,6 +14,7 @@ export interface UseCollaborationStore { destroyProvider: () => void; provider: HocuspocusProvider | undefined; isConnected: boolean; + isSynced: boolean; hasLostConnection: boolean; resetLostConnection: () => void; } @@ -20,9 +22,12 @@ export interface UseCollaborationStore { const defaultValues = { provider: undefined, isConnected: false, + isSynced: false, hasLostConnection: false, }; +type ExtendedCloseEvent = CloseEvent & { wasClean: boolean }; + export const useProviderStore = create((set, get) => ({ ...defaultValues, createProvider: (wsUrl, storeId, initialDoc) => { @@ -38,6 +43,12 @@ export const useProviderStore = create((set, get) => ({ url: wsUrl, name: storeId, document: doc, + onDisconnect(data) { + // Attempt to reconnect if the disconnection was clean (initiated by the client or server) + if ((data.event as ExtendedCloseEvent).wasClean) { + provider.connect(); + } + }, onStatus: ({ status }) => { set((state) => { const nextConnected = status === WebSocketStatus.Connected; @@ -50,6 +61,21 @@ export const useProviderStore = create((set, get) => ({ }; }); }, + onSynced: ({ state }) => { + set({ isSynced: state }); + }, + onClose(data) { + /** + * Handle the "Reset Connection" event from the server + * This is triggered when the server wants to reset the connection + * for clients in the room. + * A disconnect is made automatically but it takes time to be triggered, + * so we force the disconnection here. + */ + if (data.event.code === 1000) { + provider.disconnect(); + } + }, }); set({ diff --git a/src/frontend/apps/impress/src/features/docs/doc-share/api/useUpdateDocAccess.ts b/src/frontend/apps/impress/src/features/docs/doc-share/api/useUpdateDocAccess.ts index 05f24947..3f54b7fe 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-share/api/useUpdateDocAccess.ts +++ b/src/frontend/apps/impress/src/features/docs/doc-share/api/useUpdateDocAccess.ts @@ -6,7 +6,6 @@ import { import { APIError, errorCauses, fetchAPI } from '@/api'; import { Access, KEY_DOC, KEY_LIST_DOC, Role } from '@/docs/doc-management'; -import { useBroadcastStore } from '@/stores'; import { KEY_LIST_DOC_ACCESSES } from './useDocAccesses'; @@ -45,7 +44,6 @@ type UseUpdateDocAccessOptions = UseMutationOptions< export const useUpdateDocAccess = (options?: UseUpdateDocAccessOptions) => { const queryClient = useQueryClient(); - const { broadcast } = useBroadcastStore(); return useMutation({ mutationFn: updateDocAccess, @@ -58,12 +56,10 @@ export const useUpdateDocAccess = (options?: UseUpdateDocAccessOptions) => { queryKey: [KEY_DOC], }); - // Broadcast to every user connected to the document - broadcast(`${KEY_DOC}-${variables.docId}`); - void queryClient.invalidateQueries({ queryKey: [KEY_LIST_DOC], }); + if (options?.onSuccess) { void options.onSuccess(data, variables, onMutateResult, context); } diff --git a/src/frontend/apps/impress/src/pages/docs/[id]/index.tsx b/src/frontend/apps/impress/src/pages/docs/[id]/index.tsx index febb27f5..44ef667d 100644 --- a/src/frontend/apps/impress/src/pages/docs/[id]/index.tsx +++ b/src/frontend/apps/impress/src/pages/docs/[id]/index.tsx @@ -147,7 +147,7 @@ const DocPage = ({ id }: DocProps) => { } addTask(`${KEY_DOC}-${doc.id}`, () => { - void queryClient.resetQueries({ + void queryClient.invalidateQueries({ queryKey: [KEY_DOC, { id: doc.id }], }); }); diff --git a/src/frontend/servers/y-provider/__tests__/collaborationResetConnections.test.ts b/src/frontend/servers/y-provider/__tests__/collaborationResetConnections.test.ts index 404d8906..da11b023 100644 --- a/src/frontend/servers/y-provider/__tests__/collaborationResetConnections.test.ts +++ b/src/frontend/servers/y-provider/__tests__/collaborationResetConnections.test.ts @@ -45,7 +45,7 @@ describe('Server Tests', () => { test('POST /collaboration/api/reset-connections?room=[ROOM_ID] with correct API key should reset connections', async () => { const closeConnectionsMock = vi - .spyOn(hocuspocusServer, 'closeConnections') + .spyOn(hocuspocusServer.hocuspocus, 'closeConnections') .mockResolvedValue(); const app = initApp(); diff --git a/src/frontend/servers/y-provider/__tests__/getDocumentConnectionInfoHandler.test.ts b/src/frontend/servers/y-provider/__tests__/getDocumentConnectionInfoHandler.test.ts index c17d9be1..7efe46c3 100644 --- a/src/frontend/servers/y-provider/__tests__/getDocumentConnectionInfoHandler.test.ts +++ b/src/frontend/servers/y-provider/__tests__/getDocumentConnectionInfoHandler.test.ts @@ -70,11 +70,11 @@ describe('Server Tests', () => { }); test('POST /collaboration/api/get-connections?room=[ROOM_ID] returns connection info, session key existing', async () => { - const document = await hocuspocusServer.createDocument( + const document = await hocuspocusServer.hocuspocus.createDocument( 'test-room', {}, uuid(), - { isAuthenticated: true, readOnly: false, requiresAuthentication: true }, + { isAuthenticated: true, readOnly: false }, {}, ); @@ -138,11 +138,11 @@ describe('Server Tests', () => { }); test('POST /collaboration/api/get-connections?room=[ROOM_ID] returns connection info, session key not existing', async () => { - const document = await hocuspocusServer.createDocument( + const document = await hocuspocusServer.hocuspocus.createDocument( 'test-room', {}, uuid(), - { isAuthenticated: true, readOnly: false, requiresAuthentication: true }, + { isAuthenticated: true, readOnly: false }, {}, ); @@ -206,11 +206,11 @@ describe('Server Tests', () => { }); test('POST /collaboration/api/get-connections?room=[ROOM_ID] returns connection info, session key not existing, read only connection', async () => { - const document = await hocuspocusServer.createDocument( + const document = await hocuspocusServer.hocuspocus.createDocument( 'test-room', {}, uuid(), - { isAuthenticated: true, readOnly: false, requiresAuthentication: true }, + { isAuthenticated: true, readOnly: false }, {}, ); diff --git a/src/frontend/servers/y-provider/__tests__/hocuspocusWS.test.ts b/src/frontend/servers/y-provider/__tests__/hocuspocusWS.test.ts index a5624ac9..5642d2a2 100644 --- a/src/frontend/servers/y-provider/__tests__/hocuspocusWS.test.ts +++ b/src/frontend/servers/y-provider/__tests__/hocuspocusWS.test.ts @@ -51,7 +51,7 @@ describe('Server Tests', () => { beforeAll(async () => { server = initApp().listen(port); - await hocuspocusServer.configure({ port: portWS }).listen(); + await hocuspocusServer.listen(portWS); }); afterAll(() => { @@ -62,14 +62,11 @@ describe('Server Tests', () => { test('WebSocket connection with bad origin should be closed', () => { const { promise, done } = promiseDone(); const room = uuidv4(); - const ws = new WebSocket( - `ws://localhost:${port}/collaboration/ws/?room=${room}`, - { - headers: { - Origin: 'http://bad-origin.com', - }, + const ws = new WebSocket(`ws://localhost:${port}/?room=${room}`, { + headers: { + Origin: 'http://bad-origin.com', }, - ); + }); ws.onclose = () => { expect(ws.readyState).toBe(ws.CLOSED); @@ -82,14 +79,11 @@ describe('Server Tests', () => { test('WebSocket connection without cookies header should be closed', () => { const { promise, done } = promiseDone(); const room = uuidv4(); - const ws = new WebSocket( - `ws://localhost:${port}/collaboration/ws/?room=${room}`, - { - headers: { - Origin: origin, - }, + const ws = new WebSocket(`ws://localhost:${port}/?room=${room}`, { + headers: { + Origin: origin, }, - ); + }); ws.onclose = () => { expect(ws.readyState).toBe(ws.CLOSED); @@ -106,17 +100,13 @@ describe('Server Tests', () => { url: `ws://localhost:${portWS}/?room=${room}`, WebSocketPolyfill: WebSocket, maxAttempts: 1, - quiet: true, }); const providerName = uuidv4(); const provider = new HocuspocusProvider({ websocketProvider: wsHocus, name: providerName, - broadcast: false, - quiet: true, - preserveConnection: false, - onClose: (data) => { + onAuthenticationFailed(data) { expect(console.log).toHaveBeenCalledWith( expect.any(String), ' --- ', @@ -126,7 +116,7 @@ describe('Server Tests', () => { ); wsHocus.stopConnectionAttempt(); - expect(data.event.reason).toBe('Forbidden'); + expect(data.reason).toBe('permission-denied'); wsHocus.webSocket?.close(); wsHocus.disconnect(); provider.destroy(); @@ -135,6 +125,8 @@ describe('Server Tests', () => { }, }); + provider.attach(); + return promise; }); @@ -145,16 +137,12 @@ describe('Server Tests', () => { url: `ws://localhost:${portWS}/?room=${room}`, WebSocketPolyfill: WebSocket, maxAttempts: 1, - quiet: true, }); const provider = new HocuspocusProvider({ websocketProvider: wsHocus, name: room, - broadcast: false, - quiet: true, - preserveConnection: false, - onClose: (data) => { + onAuthenticationFailed: (data) => { expect(console.log).toHaveBeenLastCalledWith( expect.any(String), ' --- ', @@ -163,7 +151,7 @@ describe('Server Tests', () => { ); wsHocus.stopConnectionAttempt(); - expect(data.event.reason).toBe('Forbidden'); + expect(data.reason).toBe('permission-denied'); wsHocus.webSocket?.close(); wsHocus.disconnect(); provider.destroy(); @@ -172,6 +160,8 @@ describe('Server Tests', () => { }, }); + provider.attach(); + return promise; }); @@ -182,16 +172,12 @@ describe('Server Tests', () => { url: `ws://localhost:${portWS}/?room=${room}`, WebSocketPolyfill: WebSocket, maxAttempts: 1, - quiet: true, }); const provider = new HocuspocusProvider({ websocketProvider: wsHocus, name: room, - broadcast: false, - quiet: true, - preserveConnection: false, - onClose: (data) => { + onAuthenticationFailed: (data) => { expect(console.log).toHaveBeenLastCalledWith( expect.any(String), ' --- ', @@ -200,7 +186,7 @@ describe('Server Tests', () => { ); wsHocus.stopConnectionAttempt(); - expect(data.event.reason).toBe('Forbidden'); + expect(data.reason).toBe('permission-denied'); wsHocus.webSocket?.close(); wsHocus.disconnect(); provider.destroy(); @@ -209,6 +195,8 @@ describe('Server Tests', () => { }, }); + provider.attach(); + return promise; }); @@ -224,23 +212,19 @@ describe('Server Tests', () => { url: `ws://localhost:${portWS}/?room=${room}`, WebSocketPolyfill: WebSocket, maxAttempts: 1, - quiet: true, }); const provider = new HocuspocusProvider({ websocketProvider: wsHocus, name: room, - broadcast: false, - quiet: true, - preserveConnection: false, - onClose: (data) => { + onAuthenticationFailed: (data) => { expect(console.error).toHaveBeenLastCalledWith( '[onConnect]', 'Backend error: Unauthorized', ); wsHocus.stopConnectionAttempt(); - expect(data.event.reason).toBe('Forbidden'); + expect(data.reason).toBe('permission-denied'); expect(fetchDocumentMock).toHaveBeenCalledExactlyOnceWith( room, expect.any(Object), @@ -253,6 +237,8 @@ describe('Server Tests', () => { }, }); + provider.attach(); + return promise; }); @@ -269,16 +255,12 @@ describe('Server Tests', () => { url: `ws://localhost:${portWS}/?room=${room}`, WebSocketPolyfill: WebSocket, maxAttempts: 1, - quiet: true, }); const provider = new HocuspocusProvider({ websocketProvider: wsHocus, name: room, - broadcast: false, - quiet: true, - preserveConnection: false, - onClose: (data) => { + onAuthenticationFailed: (data) => { expect(console.log).toHaveBeenLastCalledWith( expect.any(String), ' --- ', @@ -287,7 +269,7 @@ describe('Server Tests', () => { ); wsHocus.stopConnectionAttempt(); - expect(data.event.reason).toBe('Forbidden'); + expect(data.reason).toBe('permission-denied'); expect(fetchDocumentMock).toHaveBeenCalledExactlyOnceWith( room, expect.any(Object), @@ -300,6 +282,8 @@ describe('Server Tests', () => { }, }); + provider.attach(); + return promise; }); @@ -322,10 +306,8 @@ describe('Server Tests', () => { const provider = new HocuspocusProvider({ websocketProvider: wsHocus, name: room, - broadcast: false, - quiet: true, onConnect: () => { - void hocuspocusServer + void hocuspocusServer.hocuspocus .openDirectConnection(room) .then((connection) => { connection.document?.getConnections().forEach((connection) => { @@ -347,6 +329,8 @@ describe('Server Tests', () => { }, }); + provider.attach(); + return promise; }); }); @@ -373,30 +357,30 @@ describe('Server Tests', () => { const provider = new HocuspocusProvider({ websocketProvider: wsHocus, name: room, - broadcast: false, - quiet: true, onConnect: () => { - void hocuspocusServer.openDirectConnection(room).then((connection) => { - connection.document?.getConnections().forEach((connection) => { + const document = hocuspocusServer.hocuspocus.documents.get(room); + if (document) { + document.getConnections().forEach((connection) => { expect(connection.context.userId).toBe('test-user-id'); }); + } - void connection.disconnect(); - provider.destroy(); - wsHocus.destroy(); + provider.destroy(); + wsHocus.destroy(); - expect(fetchDocumentMock).toHaveBeenCalledWith( - room, - expect.any(Object), - ); + expect(fetchDocumentMock).toHaveBeenCalledWith( + room, + expect.any(Object), + ); - expect(fetchCurrentUserMock).toHaveBeenCalled(); + expect(fetchCurrentUserMock).toHaveBeenCalled(); - done(); - }); + done(); }, }); + provider.attach(); + return promise; }); }); diff --git a/src/frontend/servers/y-provider/package.json b/src/frontend/servers/y-provider/package.json index 7c1f2010..71aa50d2 100644 --- a/src/frontend/servers/y-provider/package.json +++ b/src/frontend/servers/y-provider/package.json @@ -10,14 +10,14 @@ "dev": "cross-env COLLABORATION_LOGGING=true && nodemon --config nodemon.json", "start": "node ./dist/start-server.js", "lint": "eslint", - "test": "vitest --run --disable-console-intercept" + "test": "vitest" }, "engines": { "node": ">=22" }, "dependencies": { "@blocknote/server-util": "0.41.1", - "@hocuspocus/server": "2.15.2", + "@hocuspocus/server": "3.3.0", "@sentry/node": "10.17.0", "@sentry/profiling-node": "10.17.0", "@tiptap/extensions": "*", @@ -31,7 +31,7 @@ }, "devDependencies": { "@blocknote/core": "0.41.1", - "@hocuspocus/provider": "2.15.2", + "@hocuspocus/provider": "3.3.0", "@types/cors": "2.8.19", "@types/express": "5.0.3", "@types/express-ws": "3.0.5", diff --git a/src/frontend/servers/y-provider/src/handlers/collaborationResetConnectionsHandler.ts b/src/frontend/servers/y-provider/src/handlers/collaborationResetConnectionsHandler.ts index bb2b3040..41dfcee0 100644 --- a/src/frontend/servers/y-provider/src/handlers/collaborationResetConnectionsHandler.ts +++ b/src/frontend/servers/y-provider/src/handlers/collaborationResetConnectionsHandler.ts @@ -25,12 +25,12 @@ export const collaborationResetConnectionsHandler = ( * If no user ID is provided, close all connections in the room */ if (!userId) { - hocuspocusServer.closeConnections(room); + hocuspocusServer.hocuspocus.closeConnections(room); } else { /** * Close connections for the user in the room */ - hocuspocusServer.documents.forEach((doc) => { + hocuspocusServer.hocuspocus.documents.forEach((doc) => { if (doc.name !== room) { return; } diff --git a/src/frontend/servers/y-provider/src/handlers/collaborationWSHandler.ts b/src/frontend/servers/y-provider/src/handlers/collaborationWSHandler.ts index b5d936ad..8890ad0b 100644 --- a/src/frontend/servers/y-provider/src/handlers/collaborationWSHandler.ts +++ b/src/frontend/servers/y-provider/src/handlers/collaborationWSHandler.ts @@ -5,7 +5,7 @@ import { hocuspocusServer } from '@/servers/hocuspocusServer'; export const collaborationWSHandler = (ws: ws.WebSocket, req: Request) => { try { - hocuspocusServer.handleConnection(ws, req); + hocuspocusServer.hocuspocus.handleConnection(ws, req); } catch (error) { console.error('Failed to handle WebSocket connection:', error); ws.close(); diff --git a/src/frontend/servers/y-provider/src/handlers/getDocumentConnectionInfoHandler.ts b/src/frontend/servers/y-provider/src/handlers/getDocumentConnectionInfoHandler.ts index dcf33be5..d015e898 100644 --- a/src/frontend/servers/y-provider/src/handlers/getDocumentConnectionInfoHandler.ts +++ b/src/frontend/servers/y-provider/src/handlers/getDocumentConnectionInfoHandler.ts @@ -27,7 +27,7 @@ export const getDocumentConnectionInfoHandler = ( logger('Getting document connection info for room:', room); - const roomInfo = hocuspocusServer.documents.get(room); + const roomInfo = hocuspocusServer.hocuspocus.documents.get(room); if (!roomInfo) { logger('Room not found:', room); diff --git a/src/frontend/servers/y-provider/src/servers/hocuspocusServer.ts b/src/frontend/servers/y-provider/src/servers/hocuspocusServer.ts index afa6d9cf..d6c58658 100644 --- a/src/frontend/servers/y-provider/src/servers/hocuspocusServer.ts +++ b/src/frontend/servers/y-provider/src/servers/hocuspocusServer.ts @@ -4,13 +4,13 @@ import { validate as uuidValidate, version as uuidVersion } from 'uuid'; import { fetchCurrentUser, fetchDocument } from '@/api/collaborationBackend'; import { logger } from '@/utils'; -export const hocuspocusServer = Server.configure({ +export const hocuspocusServer = new Server({ name: 'docs-collaboration', timeout: 30000, quiet: true, async onConnect({ requestHeaders, - connection, + connectionConfig, documentName, requestParameters, context, @@ -58,7 +58,7 @@ export const hocuspocusServer = Server.configure({ return Promise.reject(new Error('Backend error: Unauthorized')); } - connection.readOnly = !canEdit; + connectionConfig.readOnly = !canEdit; const session = requestHeaders['cookie'] ?.split('; ') diff --git a/src/frontend/yarn.lock b/src/frontend/yarn.lock index 87a9c142..c798f153 100644 --- a/src/frontend/yarn.lock +++ b/src/frontend/yarn.lock @@ -1787,33 +1787,33 @@ dependencies: is-negated-glob "^1.0.0" -"@hocuspocus/common@^2.15.2": - version "2.15.3" - resolved "https://registry.yarnpkg.com/@hocuspocus/common/-/common-2.15.3.tgz#c5e6a326141b2ceaf49d555fd35917211340ceee" - integrity sha512-Rzh1HF0a2o/tf90A3w2XNdXd9Ym3aQzMDfD3lAUONCX9B9QOdqdyiORrj6M25QEaJrEIbXFy8LtAFcL0wRdWzA== +"@hocuspocus/common@^3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@hocuspocus/common/-/common-3.3.0.tgz#73e6489213d4c50c4521f511e2ee3a507035be42" + integrity sha512-BzLFs0Wbwt0RV1kBrtIAf7xludxKMcPBpLGAGX/5TZazx8kW1fmJpjRM3QgRmqO7R6QVyfi6h8MQUw/P43tafw== dependencies: lib0 "^0.2.87" -"@hocuspocus/provider@2.15.2": - version "2.15.2" - resolved "https://registry.yarnpkg.com/@hocuspocus/provider/-/provider-2.15.2.tgz#ce534b90e161cd32fd02928d7296bb38f424c319" - integrity sha512-mdBurviyaUd7bQx4vMIE39WqRJDTpfFelHOVXr7w/jA8G1E7K7lxQ9/DacSrbg+9o8s+1z1+SerZiUjaToaBJg== +"@hocuspocus/provider@3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@hocuspocus/provider/-/provider-3.3.0.tgz#9b1cc15158c74a344fb324c3988b5fd41464c98d" + integrity sha512-gxwWAZ8E55VxwdbFwhpjYxFBOxg96+fxkvkguqSJ59chkieDtrZca/0G9ZO4ct/BBq+FNxxYIdAxwwSaM/EOFg== dependencies: - "@hocuspocus/common" "^2.15.2" + "@hocuspocus/common" "^3.3.0" "@lifeomic/attempt" "^3.0.2" lib0 "^0.2.87" ws "^8.17.1" -"@hocuspocus/server@2.15.2": - version "2.15.2" - resolved "https://registry.yarnpkg.com/@hocuspocus/server/-/server-2.15.2.tgz#77be1e2540843bec313141dad7f39ea65a4221dd" - integrity sha512-+fLRVswg+bkgfHqJ+wFgywivw3H08WMOtVvJF7dJzWT2ZR/Sc3nDMFh2KqMF6Ygh4z6mt23xr7SKIm3eP1zoLA== +"@hocuspocus/server@3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@hocuspocus/server/-/server-3.3.0.tgz#afa0758a96c2d1af759a1166b9e0be05f1656ca9" + integrity sha512-kPsoKfjRD3JvDaViDVz8utK1lI+GvpyubAs9SKNCFOpaTJD7RlTj9bjwUfL8FJ6/tC/p4HuS8etSYOn+WeVwuw== dependencies: - "@hocuspocus/common" "^2.15.2" + "@hocuspocus/common" "^3.3.0" async-lock "^1.3.1" + async-mutex "^0.5.0" kleur "^4.1.4" lib0 "^0.2.47" - uuid "^11.0.3" ws "^8.5.0" "@humanfs/core@^0.19.1": @@ -6560,6 +6560,13 @@ async-lock@^1.3.1: resolved "https://registry.yarnpkg.com/async-lock/-/async-lock-1.4.1.tgz#56b8718915a9b68b10fce2f2a9a3dddf765ef53f" integrity sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ== +async-mutex@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/async-mutex/-/async-mutex-0.5.0.tgz#353c69a0b9e75250971a64ac203b0ebfddd75482" + integrity sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA== + dependencies: + tslib "^2.4.0" + async@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" @@ -14709,11 +14716,6 @@ uuid@13.0.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-13.0.0.tgz#263dc341b19b4d755eb8fe36b78d95a6b65707e8" integrity sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w== -uuid@^11.0.3: - version "11.1.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-11.1.0.tgz#9549028be1753bb934fc96e2bca09bb4105ae912" - integrity sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A== - uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"