⬆️(y-provider) update hocuspocus to 3.2.5

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.
This commit is contained in:
Anthony LC
2025-10-20 21:15:40 +02:00
parent fe24c00178
commit 3e5bcf96ea
16 changed files with 124 additions and 112 deletions

View File

@@ -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();

View File

@@ -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 },
{},
);

View File

@@ -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;
});
});

View File

@@ -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",

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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);

View File

@@ -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('; ')