@vrtmrz/livesync-commonlib 0.1.40 → 0.1.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -247,12 +247,29 @@ async function getDBEntryMetaByPath(host, { localDatabase }, path, opt, includeD
247
247
  const id = await host.services.path.path2id(path);
248
248
  try {
249
249
  let obj = null;
250
- if (opt) {
251
- obj = await localDatabase.get(id, opt);
252
- } else {
253
- obj = await localDatabase.get(id);
250
+ try {
251
+ if (opt) {
252
+ obj = await localDatabase.get(id, opt);
253
+ } else {
254
+ obj = await localDatabase.get(id);
255
+ }
256
+ } catch (ex) {
257
+ if (!includeDeleted || opt?.rev !== void 0 || !isErrorOfMissingDoc(ex)) throw ex;
258
+ for (let attempt = 0; attempt < 3; attempt++) {
259
+ const result = await localDatabase.allDocs({ keys: [id] });
260
+ const row = result.rows[0];
261
+ if (!row || !("value" in row) || !row.value.rev) return false;
262
+ const candidate = await localDatabase.get(id, { ...opt, rev: row.value.rev });
263
+ const current = (await localDatabase.allDocs({ keys: [id] })).rows[0];
264
+ if (!current || !("value" in current) || !current.value.rev) return false;
265
+ if (current.value.rev === candidate._rev) {
266
+ obj = candidate;
267
+ break;
268
+ }
269
+ }
270
+ if (!obj) return false;
254
271
  }
255
- const deleted = obj?.deleted ?? obj._deleted ?? void 0;
272
+ const deleted = obj._deleted || obj.deleted;
256
273
  if (!includeDeleted && deleted) return false;
257
274
  if (obj.type && obj.type == "leaf") {
258
275
  return false;
@@ -18,6 +18,8 @@ A1
18
18
 
19
19
  Resolving a conflict writes the selected or merged result on one branch and deletes every losing live leaf which the resolver has observed. Deleted leaves remain part of the tree until compaction removes their bodies. A stale client can therefore receive the resolved branch and the tombstone for a branch whose old content is still present in its storage.
20
20
 
21
+ Metadata reads which explicitly include deleted entries also return a current PouchDB `_deleted` winner. An ordinary read still excludes deleted entries, and a request for an unavailable specific revision does not fall back to the current winner. A deleted-winner lookup rechecks the winning revision after fetching its body. If it changes, the lookup follows the new winner for at most three attempts and returns no entry if it cannot establish a stable revision. Incoming file reflection uses the current winner and rechecks it before deleting storage, so an older deletion notification does not override a subsequent restoration. Existing conflict and unsynchronised-edit protection still applies.
22
+
21
23
  ## Chunk reachability during conflicts
22
24
 
23
25
  A host which collects unreferenced chunks must include the current winner, every other live conflict leaf, their available divergent revisions, and their nearest available shared ancestor in its reachability scan. This preserves the content and merge base required to review an unresolved conflict. Chunk identifiers are shared across documents, so one reachability set must cover the whole database.
@@ -8,6 +8,8 @@ The code paths below identify the maintained Self-hosted LiveSync composition po
8
8
 
9
9
  ## Obsidian plug-in
10
10
 
11
+ Unreleased deletion tests exercise `deleteMetadataOfDeletedFiles` enabled and disabled with two in-memory PouchDB replicas and injected file storage. They verify deletion and rename reflection, preservation of genuine local edits, and restoration before or during a deleted-winner lookup, including the final revision check before deletion. They also verify that missing provenance or a compacted base preserves local storage, and that continuously advancing deleted revisions do not return stale Metadata. These tests cover the Commonlib file handler and revision lookup, including the latest-revision check before deletion; they do not exercise Obsidian file watchers or a remote CouchDB server.
12
+
11
13
  Unreleased configuration-encryption tests cover changing the wrapper key without changing connection, E2EE, profile, or independent ID values. They also cover custom-key input before loading, failed writes, concurrent saves, cancellation, and unreadable-payload retention. Commonlib owns these service results. LiveSync owns the Apply controls, setting-tab registration, and database startup order; actual Apply and restart behaviour requires its focused real-Obsidian scenario.
12
14
 
13
15
  The CouchDB connection fix bypasses browser HTTP caching so encrypted replication can continue after a remote Rebuild preserves document IDs and revisions. Commonlib's regression tests cover Metadata and Chunks encrypted with a replacement Security Seed while an earlier response remains cached. Self-hosted LiveSync's `couchdb-http-cache` scenario additionally populates the real browser HTTP cache before rebuilding, confirms that the Seed and ciphertext change while the revision remains unchanged, and requires subsequent replication to succeed without clearing that cache. The released LiveSync 1.0.34 fails this scenario; a local checked Commonlib artefact passes in the maintained LiveSync 1.0.34 composition on Linux Obsidian 1.12.7. This establishes the tested build's behaviour, with the reporter's Windows and Obsidian 1.13.7 environment still unverified.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vrtmrz/livesync-commonlib",
3
- "version": "0.1.40",
3
+ "version": "0.1.41",
4
4
  "description": "Shared data, storage, and replication primitives for Self-hosted LiveSync clients.",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",