Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
fix(sync): send first update without initial document state
Process initial document state as incoming message.
This way it will be tracked as received from the remote server by y-websocket
and the update send to the server will exclude it.

Also use the sync services `opened` event inside WebsocketPolyfill
rather than mixing async `syncService.open().then` and event handling.
This allows us to emit `opened` and then `sync` from `syncService.open()`.

Signed-off-by: Max <[email protected]>
  • Loading branch information
max-nextcloud authored and backportbot[bot] committed Oct 16, 2025
commit f9d50a7f3dcd76185991fda22dd661a209870365
5 changes: 1 addition & 4 deletions src/components/Editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ import { CollaborationCursor } from '../extensions/index.js'
import { exposeForDebugging, removeFromDebugging } from '../helpers/debug.js'
import { logger } from '../helpers/logger.js'
import { setInitialYjsState } from '../helpers/setInitialYjsState.js'
import { applyDocumentState } from '../helpers/yjs.ts'
import { ERROR_TYPE, IDLE_TIMEOUT } from '../services/SyncService.ts'
import { fetchNode } from '../services/WebdavClient.ts'
import {
Expand Down Expand Up @@ -516,9 +515,7 @@ export default defineComponent({
// Fetch the document state after syntax highlights are loaded
this.lowlightLoaded.then(() => {
this.syncService.startSync()
if (documentState) {
applyDocumentState(this.ydoc, documentState, this.syncProvider)
} else {
if (!documentState) {
setInitialYjsState(this.ydoc, content, {
isRichEditor: this.isRichEditor,
})
Expand Down
16 changes: 12 additions & 4 deletions src/services/SyncService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ class SyncService {
this.backend = new PollingBackend(this, this.connection.value, data)
// Make sure to only emit this once the backend is in place.
this.bus.emit('opened', data)
// Emit sync after opened, so websocket onmessage comes after onopen.
if (data.documentState) {
this._emitDocumentStateStep(data.documentState)
}
}

startSync() {
Expand All @@ -198,6 +202,13 @@ class SyncService {
}
}

_emitDocumentStateStep(documentState: string) {
const documentStateStep = documentStateToStep(documentState)
this.bus.emit('sync', {
steps: [documentStateStep],
})
}

sendStep(step: Uint8Array<ArrayBufferLike>) {
this.#outbox.storeStep(step)
this.sendSteps()
Expand Down Expand Up @@ -243,10 +254,7 @@ class SyncService {
documentState: string
}
if (documentState) {
const documentStateStep = documentStateToStep(documentState)
this.bus.emit('sync', {
steps: [documentStateStep],
})
this._emitDocumentStateStep(documentState)
}
this.pushError = 0
this.#sending = false
Expand Down
15 changes: 9 additions & 6 deletions src/services/WebSocketPolyfill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default function initWebSocketPolyfill(
onopen?: () => void
#notifyPushBus
#onSync
#onOpened
#processingVersion = 0

constructor(url: string) {
Expand All @@ -34,6 +35,13 @@ export default function initWebSocketPolyfill(
this.#url = url
logger.debug('WebSocketPolyfill#constructor', { url, fileId })

this.#onOpened = () => {
if (syncService.hasActiveConnection()) {
this.onopen?.()
}
}
syncService.bus.on('opened', this.#onOpened)

this.#onSync = ({ steps }: { steps: Step[] }) => {
if (steps) {
this.#processSteps(steps)
Expand All @@ -43,14 +51,9 @@ export default function initWebSocketPolyfill(
})
}
}

syncService.bus.on('sync', this.#onSync)

syncService.open().then(() => {
if (syncService.hasActiveConnection()) {
this.onopen?.()
}
})
syncService.open()
}

/**
Expand Down