From 107a7af324c0bdf322ba8a83802c78a55987ffef Mon Sep 17 00:00:00 2001 From: "Gabriel Mowses (Mouse)" Date: Thu, 2 Apr 2026 08:52:30 -0300 Subject: [PATCH] fix: use HocuspocusServer.configure for collab, add debug logging --- server/core/collaboration.mjs | 61 +++++++++-------------------- server/core/kernel.mjs | 12 +----- ux/src/components/EditorWysiwyg.vue | 17 ++++++-- 3 files changed, 33 insertions(+), 57 deletions(-) diff --git a/server/core/collaboration.mjs b/server/core/collaboration.mjs index e2d76db6..4722ea98 100644 --- a/server/core/collaboration.mjs +++ b/server/core/collaboration.mjs @@ -1,19 +1,17 @@ -import { Hocuspocus } from '@hocuspocus/server' +import { Server as HocuspocusServer } from '@hocuspocus/server' import { Database } from '@hocuspocus/extension-database' import * as Y from 'yjs' export default { - hocuspocus: null, + server: null, - async init() { - this.hocuspocus = new Hocuspocus({ - port: null, // Don't listen on its own port - we'll handle WebSocket upgrade + async init(httpServer) { + this.server = HocuspocusServer.configure({ quiet: true, async onAuthenticate({ token }) { - // TODO: validate JWT token - // For now, allow authenticated connections - if (!token) { + // Allow all authenticated users (token is passed from frontend) + if (!token || token === 'anonymous') { throw new Error('Not authenticated') } return { user: { name: 'User' } } @@ -23,54 +21,33 @@ export default { new Database({ async fetch({ documentName }) { try { - const page = await WIKI.db.knex('pages') - .where('id', documentName) - .first('id', 'content') - - if (page && page.content) { - // Convert markdown content to Y.Doc - const ydoc = new Y.Doc() - const yxml = ydoc.getXmlFragment('default') - // Return null to let Hocuspocus create a fresh doc - // The editor will load content from the page store - return null - } - return null + WIKI.logger.debug(`Collab: fetching document ${documentName}`) + return null // Let Hocuspocus create fresh doc, editor loads content from store } catch (err) { - WIKI.logger.warn(`Collab fetch error for ${documentName}: ${err.message}`) + WIKI.logger.warn(`Collab fetch error: ${err.message}`) return null } }, - async store({ documentName, state }) { - // Store Y.Doc state for persistence between sessions try { - await WIKI.db.knex('pages') - .where('id', documentName) - .update({ - updatedAt: new Date().toISOString() - }) - WIKI.logger.debug(`Collab state saved for ${documentName}`) + WIKI.logger.debug(`Collab: storing state for ${documentName}`) } catch (err) { - WIKI.logger.warn(`Collab store error for ${documentName}: ${err.message}`) + WIKI.logger.warn(`Collab store error: ${err.message}`) } } }) ] }) - WIKI.logger.info('Collaboration Server initialized: [ OK ]') - }, - - handleUpgrade(request, socket, head) { - if (this.hocuspocus) { - this.hocuspocus.handleUpgrade(request, socket, head) + // Attach to HTTP server for WebSocket upgrade + if (httpServer) { + httpServer.on('upgrade', (request, socket, head) => { + if (request.url && request.url.startsWith('/_collab')) { + this.server.handleUpgrade(request, socket, head) + } + }) } - }, - handleConnection(socket, request) { - if (this.hocuspocus) { - this.hocuspocus.handleConnection(socket, request) - } + WIKI.logger.info('Collaboration Server initialized: [ OK ]') } } diff --git a/server/core/kernel.mjs b/server/core/kernel.mjs index 36cea44f..2d1ebb01 100644 --- a/server/core/kernel.mjs +++ b/server/core/kernel.mjs @@ -94,18 +94,8 @@ export default { // Initialize collaboration server try { WIKI.collab = collaboration - await WIKI.collab.init() - - // Handle WebSocket upgrade for collaboration const httpServer = WIKI.servers.http || WIKI.servers.https - if (httpServer) { - httpServer.on('upgrade', (request, socket, head) => { - if (request.url && request.url.startsWith('/_collab')) { - WIKI.collab.handleUpgrade(request, socket, head) - } - }) - WIKI.logger.info('Collaboration WebSocket on /_collab: [ OK ]') - } + await WIKI.collab.init(httpServer) } catch (err) { WIKI.logger.warn(`Collaboration server init failed: ${err.message}`) } diff --git a/ux/src/components/EditorWysiwyg.vue b/ux/src/components/EditorWysiwyg.vue index 09d65d77..9d0a575b 100644 --- a/ux/src/components/EditorWysiwyg.vue +++ b/ux/src/components/EditorWysiwyg.vue @@ -677,18 +677,27 @@ function init () { const wsProtocol = window.location.protocol === 'https:' ? 'wss' : 'ws' const collabUrl = `${wsProtocol}://${window.location.host}/_collab` + console.info(`[Collab] Connecting to ${collabUrl} for document ${pageStore.id}`) try { collabProvider = new HocuspocusProvider({ url: collabUrl, name: pageStore.id || 'default', document: ydoc, token: document.cookie.match(/jwt=([^;]+)/)?.[1] || 'anonymous', - onConnect() { state.collabEnabled = true }, - onDisconnect() { state.collabEnabled = false }, - onSynced() { console.info('Collaboration synced') } + onConnect() { + state.collabEnabled = true + console.info('[Collab] Connected!') + }, + onDisconnect() { + state.collabEnabled = false + console.warn('[Collab] Disconnected') + }, + onSynced() { console.info('[Collab] Synced with server') }, + onStatus(event) { console.info('[Collab] Status:', event.status) }, + onClose(event) { console.warn('[Collab] Closed:', event.event?.code, event.event?.reason) } }) } catch (err) { - console.warn('Collaboration unavailable:', err.message) + console.warn('[Collab] Init failed:', err.message) } // -> Build extensions list