diff --git a/manifest.json b/manifest.json index f61fa95..1f1f1a5 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "obsync", "name": "S3 Vault Sync", - "version": "0.1.1", + "version": "0.1.2", "minAppVersion": "1.6.6", "description": "Sync vault files through OSS / S3-compatible object storage.", "author": "Chaly", diff --git a/package.json b/package.json index d806346..c0f24f6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obsync", - "version": "0.1.1", + "version": "0.1.2", "description": "Plugin for OSS / S3-compatible vault sync.", "main": "main.js", "scripts": { diff --git a/src/sync/engine.test.ts b/src/sync/engine.test.ts index 1be5a8e..4dd818b 100644 --- a/src/sync/engine.test.ts +++ b/src/sync/engine.test.ts @@ -589,6 +589,41 @@ describe("sync engine", () => { expect(store.manifest.paths["notes/today.md"]?.contentHash).toBe(await hashText("local")); }); + test("does not create a conflict when local and remote content match", async () => { + const baseHash = await hashText("base"); + const sameHash = await hashText("same"); + const vault = new FakeVault({ "notes/today.md": "same" }); + const store = new FakeObjectStore(); + const state: LocalSyncState = { + files: { + "notes/today.md": { + lastSyncedHash: baseHash, + remoteHash: baseHash, + deleted: false, + version: "ver_base", + }, + }, + }; + await store.putText(blobObjectKey(sameHash), "same"); + store.manifest.paths["notes/today.md"] = { + contentHash: sameHash, + size: 4, + updatedAt: 2000, + updatedBy: "dev_other", + revision: 2, + version: "ver_remote", + }; + + const result = await sync(vault, store, state, 3000); + + expect(result.conflicts).toBe(0); + expect(result.downloaded).toBe(1); + expect(await vault.readText("notes/today.md")).toBe("same"); + expect(await vault.readText("notes/today.conflict.Mac.19700101-000003.md")).toBe(""); + expect(state.files["notes/today.md"]?.lastSyncedHash).toBe(sameHash); + expect(state.files["notes/today.md"]?.version).toBe("ver_remote"); + }); + test("releaseDeletedContent removes deleted tombstones and unreferenced blobs", async () => { const keptHash = await hashText("kept"); const deletedHash = await hashText("deleted"); diff --git a/src/sync/engine.ts b/src/sync/engine.ts index decfc0e..49ee33b 100644 --- a/src/sync/engine.ts +++ b/src/sync/engine.ts @@ -504,6 +504,10 @@ function planPathAction(input: { const localChanged = !input.previous || input.previous.deleted || input.local.hash !== input.previous.lastSyncedHash; const remoteChanged = input.remote.version !== input.previous?.version || input.remote.contentHash !== input.previous?.remoteHash; + if (input.local.hash === input.remote.contentHash) { + return remoteChanged ? "download" : "noop"; + } + if (!localChanged && !remoteChanged) { return "noop"; } diff --git a/versions.json b/versions.json index 6f0ede7..eab14d1 100644 --- a/versions.json +++ b/versions.json @@ -1,3 +1,4 @@ { - "0.1.1": "1.6.6" + "0.1.1": "1.6.6", + "0.1.2": "1.6.6" }