summaryrefslogtreecommitdiff
path: root/src/main/overleafSocket.ts
diff options
context:
space:
mode:
authorhaoyuren <13851610112@163.com>2026-03-13 18:46:46 -0500
committerhaoyuren <13851610112@163.com>2026-03-13 18:46:46 -0500
commit11166a63affc4e95450f677d860c8bfdb8211bd9 (patch)
tree2ad4b0c81cb4df6e982c0f88fa43b2ed65b972fc /src/main/overleafSocket.ts
parentfa52c3c4d6c21a26c838fa33de2d7fa447f9499e (diff)
Fix Claude Code → Overleaf sync: remove hash from applyOtUpdate, fix OT bugs
Root cause: SHA-1 hash sent with applyOtUpdate didn't match Overleaf's server-side computation, causing "Invalid hash" error, disconnect, and rollback of all synced changes. - Remove hash field from applyOtUpdate to skip server-side hash check - Switch applyOtUpdate from fire-and-forget to emitWithAck for reliable ack - Fix getOldDoc bug: save base doc when changes start accumulating instead of incorrectly using current doc (caused wrong delete ops) - Fix ack handler: only ack when no 'op' field (was acking remote ops too) - Await fileSyncBridge.start() instead of fire-and-forget - Add joinDoc retry logic for transient joinLeaveEpoch mismatch errors - Clear pending ack callbacks on WebSocket close to prevent timeout errors - Add otUpdateError logging for server-side rejections - Add file-based bridge logging for debugging sync issues Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'src/main/overleafSocket.ts')
-rw-r--r--src/main/overleafSocket.ts10
1 files changed, 8 insertions, 2 deletions
diff --git a/src/main/overleafSocket.ts b/src/main/overleafSocket.ts
index 811e433..195eb05 100644
--- a/src/main/overleafSocket.ts
+++ b/src/main/overleafSocket.ts
@@ -155,6 +155,10 @@ export class OverleafSocket extends EventEmitter {
this.ws.on('close', () => {
this.stopHeartbeat()
+ // Clear pending ack callbacks to prevent timeout errors after reconnect
+ for (const [id, cb] of this.ackCallbacks) {
+ this.ackCallbacks.delete(id)
+ }
if (this._state === 'connected' && this.shouldReconnect) {
this.scheduleReconnect()
}
@@ -298,8 +302,10 @@ export class OverleafSocket extends EventEmitter {
}
async applyOtUpdate(docId: string, ops: unknown[], version: number, hash: string): Promise<void> {
- // Fire-and-forget: server responds with otUpdateApplied or otUpdateError event
- this.ws?.send(encodeEvent('applyOtUpdate', [docId, { doc: docId, op: ops, v: version, hash, lastV: version }]))
+ // Use emitWithAck so the server's callback response comes back as a Socket.IO ack
+ // Do NOT send hash — Overleaf's document-updater hash check causes disconnect + rollback on mismatch
+ const result = await this.emitWithAck('applyOtUpdate', [docId, { doc: docId, op: ops, v: version }])
+ if (result) console.log(`[applyOtUpdate] ack for ${docId} v=${version}`)
}
/** Get list of connected users with their cursor positions */