diff --git a/frontend/history-ui/src/lib/types/DocumentUpdateMergedContent.ts b/frontend/history-ui/src/lib/types/DocumentUpdateMergedContent.ts new file mode 100644 index 00000000..5fca495f --- /dev/null +++ b/frontend/history-ui/src/lib/types/DocumentUpdateMergedContent.ts @@ -0,0 +1,9 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Like [`DocumentVersion`] but without the `relative_path`. + * Used only in create/update responses when the server had to merge the + * client's content with a newer remote version and therefore must echo + * the merged content back. + */ +export type DocumentUpdateMergedContent = { vaultUpdateId: number, documentId: string, updatedDate: string, contentBase64: string, isDeleted: boolean, userId: string, deviceId: string, }; diff --git a/frontend/history-ui/src/lib/types/DocumentUpdateMetadata.ts b/frontend/history-ui/src/lib/types/DocumentUpdateMetadata.ts new file mode 100644 index 00000000..393713fb --- /dev/null +++ b/frontend/history-ui/src/lib/types/DocumentUpdateMetadata.ts @@ -0,0 +1,9 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Like [`DocumentVersionWithoutContent`] but without the `relative_path`. + * Used only in create/update responses where the client already tracks + * the path locally (the server is the source of truth for the + * document identity, not its path). + */ +export type DocumentUpdateMetadata = { vaultUpdateId: number, documentId: string, updatedDate: string, isDeleted: boolean, userId: string, deviceId: string, contentSize: number, }; diff --git a/frontend/history-ui/src/lib/types/DocumentUpdateResponse.ts b/frontend/history-ui/src/lib/types/DocumentUpdateResponse.ts index 418117e6..48f0fd1c 100644 --- a/frontend/history-ui/src/lib/types/DocumentUpdateResponse.ts +++ b/frontend/history-ui/src/lib/types/DocumentUpdateResponse.ts @@ -1,8 +1,12 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { DocumentVersion } from "./DocumentVersion"; -import type { DocumentVersionWithoutContent } from "./DocumentVersionWithoutContent"; +import type { DocumentUpdateMergedContent } from "./DocumentUpdateMergedContent"; +import type { DocumentUpdateMetadata } from "./DocumentUpdateMetadata"; /** - * Response to an update document request. + * Response to a create/update document request. + * + * Neither variant contains `relative_path`: the client tracks the document's + * on-disk path locally and the server is the authority on document identity + * (`document_id`), not on its path. */ -export type DocumentUpdateResponse = { "type": "FastForwardUpdate" } & DocumentVersionWithoutContent | { "type": "MergingUpdate" } & DocumentVersion; +export type DocumentUpdateResponse = { "type": "FastForwardUpdate" } & DocumentUpdateMetadata | { "type": "MergingUpdate" } & DocumentUpdateMergedContent; diff --git a/frontend/history-ui/src/lib/types/WebSocketServerMessage.ts b/frontend/history-ui/src/lib/types/WebSocketServerMessage.ts index 45e37358..09bd3e86 100644 --- a/frontend/history-ui/src/lib/types/WebSocketServerMessage.ts +++ b/frontend/history-ui/src/lib/types/WebSocketServerMessage.ts @@ -1,5 +1,6 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { CursorPositionFromServer } from "./CursorPositionFromServer"; +import type { WebSocketVaultPathChange } from "./WebSocketVaultPathChange"; import type { WebSocketVaultUpdate } from "./WebSocketVaultUpdate"; -export type WebSocketServerMessage = { "type": "vaultUpdate" } & WebSocketVaultUpdate | { "type": "cursorPositions" } & CursorPositionFromServer; +export type WebSocketServerMessage = { "type": "vaultUpdate" } & WebSocketVaultUpdate | { "type": "pathChange" } & WebSocketVaultPathChange | { "type": "cursorPositions" } & CursorPositionFromServer; diff --git a/frontend/history-ui/src/lib/types/WebSocketVaultPathChange.ts b/frontend/history-ui/src/lib/types/WebSocketVaultPathChange.ts new file mode 100644 index 00000000..5079b14b --- /dev/null +++ b/frontend/history-ui/src/lib/types/WebSocketVaultPathChange.ts @@ -0,0 +1,12 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * A rename notification. Emitted whenever a write commits a document at + * a path that differs from what the origin client sent and/or from the + * document's previous stored path. Unlike [`WebSocketVaultUpdate`] this + * event is delivered to all subscribers *including the origin device*, + * because the create/update HTTP response no longer carries the path and + * the origin needs this event to learn the server-canonical path + * (e.g. when the server deduped or rejected a rename). + */ +export type WebSocketVaultPathChange = { vaultUpdateId: number, documentId: string, relativePath: string, }; diff --git a/frontend/sync-client/src/services/types/DocumentUpdateMergedContent.ts b/frontend/sync-client/src/services/types/DocumentUpdateMergedContent.ts new file mode 100644 index 00000000..4e0e4af4 --- /dev/null +++ b/frontend/sync-client/src/services/types/DocumentUpdateMergedContent.ts @@ -0,0 +1,9 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Like [`DocumentVersion`] but without the `relative_path`. + * Used only in create/update responses when the server had to merge the + * client's content with a newer remote version and therefore must echo + * the merged content back. + */ +export interface DocumentUpdateMergedContent { vaultUpdateId: number, documentId: string, updatedDate: string, contentBase64: string, isDeleted: boolean, userId: string, deviceId: string, } diff --git a/frontend/sync-client/src/services/types/DocumentUpdateMetadata.ts b/frontend/sync-client/src/services/types/DocumentUpdateMetadata.ts new file mode 100644 index 00000000..325d896a --- /dev/null +++ b/frontend/sync-client/src/services/types/DocumentUpdateMetadata.ts @@ -0,0 +1,9 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Like [`DocumentVersionWithoutContent`] but without the `relative_path`. + * Used only in create/update responses where the client already tracks + * the path locally (the server is the source of truth for the + * document identity, not its path). + */ +export interface DocumentUpdateMetadata { vaultUpdateId: number, documentId: string, updatedDate: string, isDeleted: boolean, userId: string, deviceId: string, contentSize: number, } diff --git a/frontend/sync-client/src/services/types/DocumentUpdateResponse.ts b/frontend/sync-client/src/services/types/DocumentUpdateResponse.ts index 418117e6..48f0fd1c 100644 --- a/frontend/sync-client/src/services/types/DocumentUpdateResponse.ts +++ b/frontend/sync-client/src/services/types/DocumentUpdateResponse.ts @@ -1,8 +1,12 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { DocumentVersion } from "./DocumentVersion"; -import type { DocumentVersionWithoutContent } from "./DocumentVersionWithoutContent"; +import type { DocumentUpdateMergedContent } from "./DocumentUpdateMergedContent"; +import type { DocumentUpdateMetadata } from "./DocumentUpdateMetadata"; /** - * Response to an update document request. + * Response to a create/update document request. + * + * Neither variant contains `relative_path`: the client tracks the document's + * on-disk path locally and the server is the authority on document identity + * (`document_id`), not on its path. */ -export type DocumentUpdateResponse = { "type": "FastForwardUpdate" } & DocumentVersionWithoutContent | { "type": "MergingUpdate" } & DocumentVersion; +export type DocumentUpdateResponse = { "type": "FastForwardUpdate" } & DocumentUpdateMetadata | { "type": "MergingUpdate" } & DocumentUpdateMergedContent; diff --git a/frontend/sync-client/src/services/types/WebSocketServerMessage.ts b/frontend/sync-client/src/services/types/WebSocketServerMessage.ts index 45e37358..09bd3e86 100644 --- a/frontend/sync-client/src/services/types/WebSocketServerMessage.ts +++ b/frontend/sync-client/src/services/types/WebSocketServerMessage.ts @@ -1,5 +1,6 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { CursorPositionFromServer } from "./CursorPositionFromServer"; +import type { WebSocketVaultPathChange } from "./WebSocketVaultPathChange"; import type { WebSocketVaultUpdate } from "./WebSocketVaultUpdate"; -export type WebSocketServerMessage = { "type": "vaultUpdate" } & WebSocketVaultUpdate | { "type": "cursorPositions" } & CursorPositionFromServer; +export type WebSocketServerMessage = { "type": "vaultUpdate" } & WebSocketVaultUpdate | { "type": "pathChange" } & WebSocketVaultPathChange | { "type": "cursorPositions" } & CursorPositionFromServer; diff --git a/frontend/sync-client/src/services/types/WebSocketVaultPathChange.ts b/frontend/sync-client/src/services/types/WebSocketVaultPathChange.ts new file mode 100644 index 00000000..337eb135 --- /dev/null +++ b/frontend/sync-client/src/services/types/WebSocketVaultPathChange.ts @@ -0,0 +1,12 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * A rename notification. Emitted whenever a write commits a document at + * a path that differs from what the origin client sent and/or from the + * document's previous stored path. Unlike [`WebSocketVaultUpdate`] this + * event is delivered to all subscribers *including the origin device*, + * because the create/update HTTP response no longer carries the path and + * the origin needs this event to learn the server-canonical path + * (e.g. when the server deduped or rejected a rename). + */ +export interface WebSocketVaultPathChange { vaultUpdateId: number, documentId: string, relativePath: string, } diff --git a/frontend/sync-client/src/services/websocket-manager.ts b/frontend/sync-client/src/services/websocket-manager.ts index 5cceec72..9263142a 100644 --- a/frontend/sync-client/src/services/websocket-manager.ts +++ b/frontend/sync-client/src/services/websocket-manager.ts @@ -283,7 +283,7 @@ export class WebSocketManager { if (message.type === "vaultUpdate") { await this.onRemoteVaultUpdateReceived.triggerAsync(message); - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + } else if (message.type === "cursorPositions") { this.logger.debug( `Received cursor positions for ${JSON.stringify(message.clients)}` diff --git a/frontend/sync-client/src/sync-operations/offline-change-detector.ts b/frontend/sync-client/src/sync-operations/offline-change-detector.ts index 96b1126d..e6bc2b51 100644 --- a/frontend/sync-client/src/sync-operations/offline-change-detector.ts +++ b/frontend/sync-client/src/sync-operations/offline-change-detector.ts @@ -45,7 +45,7 @@ export async function scheduleOfflineChanges( const allDocuments = new Map(queue.allSettledDocuments()); const locallyRenamedPaths = enqueueRenamedDocuments(deps, allDocuments); - let deletedCandidates = await findLocallyDeletedFiles(operations, allDocuments); + const deletedCandidates = await findLocallyDeletedFiles(operations, allDocuments); const instructions = await buildSyncInstructions( deps, diff --git a/frontend/sync-client/src/sync-operations/sync-event-queue.ts b/frontend/sync-client/src/sync-operations/sync-event-queue.ts index b2cebb1f..9e10ba94 100644 --- a/frontend/sync-client/src/sync-operations/sync-event-queue.ts +++ b/frontend/sync-client/src/sync-operations/sync-event-queue.ts @@ -197,7 +197,7 @@ export class SyncEventQueue { e.documentId === docId) || (e.type === SyncEventType.SyncRemote && // we care about the local path not the remote - this.getDocumentByDocumentId(e.remoteVersion.documentId as DocumentId)?.path === path) + this.getDocumentByDocumentId(e.remoteVersion.documentId)?.path === path) ); } diff --git a/frontend/sync-client/src/sync-operations/syncer.ts b/frontend/sync-client/src/sync-operations/syncer.ts index 7a461b9c..17458cbe 100644 --- a/frontend/sync-client/src/sync-operations/syncer.ts +++ b/frontend/sync-client/src/sync-operations/syncer.ts @@ -199,9 +199,9 @@ export class Syncer { private async internalScheduleSyncForOfflineChanges(): Promise { await scheduleOfflineChanges( { logger: this.logger, operations: this.operations, queue: this.queue }, - (path) => this.syncLocallyCreatedFile(path), - (args) => this.syncLocallyUpdatedFile(args), - (path) => this.syncLocallyDeletedFile(path), + (path) => { this.syncLocallyCreatedFile(path); }, + (args) => { this.syncLocallyUpdatedFile(args); }, + (path) => { this.syncLocallyDeletedFile(path); }, ); await this.scheduleDrain();