@vrtmrz/livesync-commonlib 0.1.28 → 0.1.30
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.
- package/README.md +5 -1
- package/dist/API/DirectFileManipulatorV2.d.ts +1 -0
- package/dist/API/DirectFileManipulatorV2.js +19 -2
- package/dist/API/processSetting.d.ts +179 -1
- package/dist/API/processSetting.js +5 -1
- package/dist/common/configForDoc.d.ts +1 -0
- package/dist/common/configForDoc.js +24 -7
- package/dist/common/models/db.type.d.ts +1 -0
- package/dist/common/models/setting.const.defaults.js +2 -0
- package/dist/common/models/setting.const.qr.js +2 -1
- package/dist/common/models/setting.lifecycle.js +3 -1
- package/dist/common/models/setting.type.d.ts +2 -0
- package/dist/common/models/shared.definition.configNames.js +4 -0
- package/dist/common/models/tweak.definition.d.ts +6 -0
- package/dist/common/models/tweak.definition.js +1 -0
- package/dist/common/settingConstants.d.ts +1 -0
- package/dist/common/utils.js +2 -1
- package/dist/pouchdb/LiveSyncDBFunctions.d.ts +1 -0
- package/dist/pouchdb/LiveSyncDBFunctions.js +12 -3
- package/dist/pouchdb/StreamingFetch.d.ts +2 -0
- package/dist/pouchdb/StreamingFetch.js +28 -0
- package/dist/pouchdb/encryption.d.ts +2 -2
- package/dist/pouchdb/encryption.js +25 -15
- package/dist/pouchdb/negotiation.d.ts +3 -2
- package/dist/pouchdb/negotiation.js +84 -32
- package/dist/pouchdb/remoteFeatureCompatibility.d.ts +25 -0
- package/dist/pouchdb/remoteFeatureCompatibility.js +52 -0
- package/dist/replication/couchdb/LiveSyncReplicator.js +21 -9
- package/dist/replication/index.d.ts +2 -0
- package/dist/replication/index.js +13 -1
- package/dist/replication/journal/LiveSyncJournalReplicator.js +2 -5
- package/dist/serviceModules/Rebuilder.js +11 -6
- package/dist/services/base/CommonlibMessages.d.ts +2 -0
- package/dist/services/base/CommonlibMessages.js +2 -0
- package/dist/services/base/RemoteConnection.d.ts +2 -0
- package/dist/services/base/RemoteService.js +9 -1
- package/dist/worker/bgWorker.js +1 -1
- package/docs/development.md +2 -0
- package/docs/proven-in-use.md +6 -0
- package/docs/remote-feature-compatibility.md +177 -0
- package/package.json +1 -1
package/docs/development.md
CHANGED
|
@@ -87,6 +87,8 @@ The unreleased watcher deletion checks and the separate database-to-storage refl
|
|
|
87
87
|
|
|
88
88
|
File-path parsing recognises only the leading `i:`, `ix:`, and `ps:` namespaces. Colons elsewhere belong to the path, including the complete remainder after one namespace. Document-ID parsing additionally recognises `h:` and `f:`; those document IDs are not ordinary storage paths. Keep normalisation, selection patterns, and database lookup on the complete path. `pathPrefixes.unit.spec.ts`, `typeUtils.unit.spec.ts`, and `PathService.unit.spec.ts` cover these conversions, and `ServiceFileHandlerBase.colonPaths.unit.spec.ts` exercises storage and reflection with real PouchDB Metadata and Chunks. Host filename restrictions remain a separate contract: a host must not interpret an unsupported name as permission to write a shortened one.
|
|
89
89
|
|
|
90
|
+
Before HKDF decryption, an obfuscated Metadata document's `path` field contains an encrypted payload beginning `/\:` rather than a logical file path or a document ID. Read that field directly for decryption; apply path and ID conversion only after obtaining the decoded path. `encryption.unit.spec.ts` covers this round trip, the legacy V1 path fallback, and decoded PouchDB replication events. `StreamingFetch.unit.spec.ts` covers decryption before the initial fetch writes and checkpoints a document.
|
|
91
|
+
|
|
90
92
|
The revision-tree safety rules are documented in [Conflict resolution and file provenance](conflict-resolution.md). `ConflictManager.unit.spec.ts` owns common-ancestor and conservative merge behaviour, deterministic pair selection for multiple live leaves, and reconstruction from the committed tree between stages. `EntryManagerImpls.unit.spec.ts` owns the distinction between force-writing below an exact revision and conditionally advancing a current live leaf through PouchDB's ordinary revision check. `ServiceDatabaseFileAccessBase.unit.spec.ts` owns all-branch content discovery, short-circuiting history existence checks after an exact match, exact-revision logical deletion, and the public live-base result and event boundary. `ServiceFileHandlerBase.unit.spec.ts` owns the injected provenance policy for edit, deletion, and rename operations, together with user-selected reflection, child creation, strict matching, matching-provenance cleanup after exact branch deletion, and stale-revision refusal. `LiveSyncLocalDB.unit.spec.ts` owns chunk reachability across current winners, shared chunks, live conflicts, available merge ancestry, conflict resolution, and PouchDB replication of collection and recreation. Extend the relevant sides when changing conflict resolution, compaction handling, provenance, chunk collection, or database-to-storage overwrite protection.
|
|
91
93
|
|
|
92
94
|
`LiveSyncReplicator.unit.spec.ts` owns the CouchDB remote-chunk batch contract: a mixed `_all_docs` result must return each available document even when another keyed row reports an error. `ChunkFetcher.unit.spec.ts` owns the consumer behaviour: it writes valid returned chunks and emits `missingChunkRemote` only for requested IDs which are absent from the returned set. Extend both sides when changing remote chunk acquisition or missing-chunk delivery.
|
package/docs/proven-in-use.md
CHANGED
|
@@ -10,6 +10,12 @@ The code paths below identify the maintained Self-hosted LiveSync composition po
|
|
|
10
10
|
|
|
11
11
|
Unreleased colon-path regression tests establish that Commonlib preserves ordinary file paths through Metadata storage, Chunk retrieval, and storage reflection, with path obfuscation enabled or disabled. They use real PouchDB with injected storage. This result does not establish which filenames a host's file-creation API accepts; that boundary requires host runtime verification.
|
|
12
12
|
|
|
13
|
+
Commonlib's encryption tests verify that an obfuscated Metadata document retains its document ID while its HKDF-encrypted path and file properties round-trip, that V1-obfuscated paths remain readable through the fallback, and that PouchDB replication presents a decoded path to both local storage and change events. The Fast Fetch test verifies decryption before storage and checkpointing. On 26th September 2026, a local packed candidate of this fix passed LiveSync 1.0.31's `npm run check` and unit tests, as well as real Obsidian two-Vault synchronisation, encrypted CLI-to-Obsidian transfer, and encrypted Metadata retrieval through Fast Fetch during manual CouchDB onboarding.
|
|
14
|
+
|
|
15
|
+
The unreleased 0.1.30 packed candidate adds encryption of Hidden File Sync and Customisation Sync Metadata when CouchDB, E2EE V2, and Property Encryption are active. Focused Commonlib tests cover the `i:f:`, `ix:f:`, and legacy `ps:f:` representations, legacy and new setting defaults, feature declaration, concurrent version updates, and unknown-feature rejection. With that packed candidate in LiveSync, two real-Obsidian scenarios checked the raw CouchDB Metadata marker, zeroed times and size, empty public Chunk-reference list, and generation 13 feature declaration before restoring the files in a second Vault. The Hidden File Sync scenario also rebuilt the remote and verified the accepted writer's feature declaration and encrypted Metadata before the second Vault fetched them. The CLI-to-Obsidian encrypted note scenario also passed with matching effective settings. A separate real-Obsidian scenario kept continuous CouchDB replication active whilst the remote version document acquired an unknown feature; the local document was observed, the active Replicator retired, another replication was refused, and previously accepted Vault content remained intact. After restarting the Vault, both finite replication and the actual continuous connection attempt were refused by the remote declaration, without a KV feature history. These runs establish the tested local package and host build; they do not validate a published registry artefact or recovery under a future compatible client.
|
|
16
|
+
|
|
17
|
+
Additional real-CouchDB integration tests exercise Fast Fetch admission before local reset, generation 12 acceptance, and generation 13 retrieval with plaintext and encrypted internal Metadata together. A real-Obsidian migration scenario enables the preference through the settings UI without Rebuild, verifies that unchanged Metadata retains its original revision while rewritten entries are encrypted with stable IDs, and checks a second device's mismatch rejection and restoration after alignment. After turning the preference OFF, Fast Fetch still retrieves both representations and their Chunks with matching content; the remote feature declaration remains. These checks use the local packed candidate with LiveSync 1.0.32.
|
|
18
|
+
|
|
13
19
|
The plug-in extends the neutral `ServiceContext` with Obsidian-owned capabilities in `src/modules/services/ObsidianServiceContext.ts`. One context instance carries the LiveSync-owned translator and event hub through the Service Hub rather than placing those dependencies in Commonlib globals. Commonlib supplies its typed English fallback when another host omits the translator.
|
|
14
20
|
|
|
15
21
|
The consumer contract in `test/contracts/serviceContext.ts` checks shared result semantics and exact context identity across the composed services. The real-Obsidian suite documented in `test/e2e-obsidian/README.md` then covers plug-in loading, representative Svelte dialogue mounts, Vault reflection, CouchDB and Object Storage synchronisation, a two-device P2P Setup URI round-trip, two-Vault behaviour, and other Obsidian-owned boundaries.
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
---
|
|
2
|
+
date: 2026-09-27
|
|
3
|
+
commonlib-version: "0.1.30"
|
|
4
|
+
self-hosted-livesync-version: "1.0.32"
|
|
5
|
+
status: unreleased
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Remote feature compatibility
|
|
9
|
+
|
|
10
|
+
This document defines the persisted feature contract for CouchDB databases and
|
|
11
|
+
the checks required of Commonlib consumers. It describes unreleased behaviour
|
|
12
|
+
being implemented in this branch.
|
|
13
|
+
The first feature is encrypted Metadata for Hidden File Sync and Customisation
|
|
14
|
+
Sync. Journal and P2P retain their existing transport contracts.
|
|
15
|
+
|
|
16
|
+
## Ownership and compatibility dimensions
|
|
17
|
+
|
|
18
|
+
Commonlib owns the wire representation, validation, feature identifiers, shared
|
|
19
|
+
assessment, and admission requirements. Hosts own presentation, scheduling, and
|
|
20
|
+
the application of received documents to their files.
|
|
21
|
+
|
|
22
|
+
Keep these independent dimensions separate:
|
|
23
|
+
|
|
24
|
+
- the remote protocol generation states how to interpret the control document;
|
|
25
|
+
- the used-feature set states which representations the database may contain;
|
|
26
|
+
- the supported-feature set belongs to the running client implementation;
|
|
27
|
+
- Tweak values describe settings which participating writers should share; and
|
|
28
|
+
- the existing Chunk version range describes Chunk format compatibility.
|
|
29
|
+
|
|
30
|
+
A feature is supported only when the client can interpret its data and preserve
|
|
31
|
+
its dependencies during applicable operations, including maintenance. Ignoring
|
|
32
|
+
an unfamiliar file path is not sufficient: encrypted Chunk references must not
|
|
33
|
+
be mistaken for an empty reference set.
|
|
34
|
+
|
|
35
|
+
## Control document
|
|
36
|
+
|
|
37
|
+
Extend the existing ordinary document, preserving its existing identifier:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"_id": "obsydian_livesync_version",
|
|
42
|
+
"type": "versioninfo",
|
|
43
|
+
"version": 13,
|
|
44
|
+
"used_features": ["encrypted-internal-metadata-v1"]
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Generation 13 is the introduction boundary. It makes legacy clients
|
|
49
|
+
which understand only generation 12 reject the enabled remote through their
|
|
50
|
+
existing version check. Subsequent independent features use the feature list;
|
|
51
|
+
they do not each require another protocol generation.
|
|
52
|
+
|
|
53
|
+
Generation 12 remains readable without a feature list. Connecting with a newer
|
|
54
|
+
client must not promote a legacy database. The existing local compatibility
|
|
55
|
+
acknowledgement and settings-schema version remain separate concerns; adding
|
|
56
|
+
this remote contract must not implicitly advance those markers for every user.
|
|
57
|
+
|
|
58
|
+
The document remains readable before Metadata decryption and is replicated to
|
|
59
|
+
local databases. The `_local/obsydian_livesync_milestone` document continues to
|
|
60
|
+
hold participant and Tweak information; it is not the sole source of feature
|
|
61
|
+
requirements. The ordinary version document also provides the existing route
|
|
62
|
+
for observing compatibility changes during replication.
|
|
63
|
+
|
|
64
|
+
### Validation and unknown identifiers
|
|
65
|
+
|
|
66
|
+
Read `used_features` as an array of opaque, non-empty strings. Preserve unknown
|
|
67
|
+
strings before comparing them with the client-owned supported set. A closed
|
|
68
|
+
enum must not discard the evidence needed to diagnose an unknown feature.
|
|
69
|
+
Order and duplicates do not change the set's meaning.
|
|
70
|
+
|
|
71
|
+
Assessment returns distinct outcomes for a compatible document, an unsupported
|
|
72
|
+
protocol generation, unknown feature identifiers, and malformed control data.
|
|
73
|
+
Unknown identifiers are included in the result so any host can render a generic
|
|
74
|
+
message such as `Unknown features are in use: example-feature-v2` without a
|
|
75
|
+
feature-specific label or translation. Hosts render identifiers as text.
|
|
76
|
+
|
|
77
|
+
A missing list is accepted as legacy input only in the legacy generation. A
|
|
78
|
+
new-generation document with a missing or invalid list is not silently treated
|
|
79
|
+
as an empty set. Deleting or corrupting the control document does not authorise
|
|
80
|
+
ordinary data operations or recreate a legacy declaration over a non-empty DB.
|
|
81
|
+
|
|
82
|
+
### Updating requirements
|
|
83
|
+
|
|
84
|
+
Declare a feature before writing documents which depend on it. Introduce the
|
|
85
|
+
new generation and its initial feature set in the same control-document update.
|
|
86
|
+
Preserve existing identifiers and unrelated fields when updating the document.
|
|
87
|
+
On a revision conflict, fetch and reassess the current document before merging
|
|
88
|
+
or retrying; never replace another writer's requirements with a stale snapshot.
|
|
89
|
+
|
|
90
|
+
The used-feature set is retained when a writer turns its corresponding setting
|
|
91
|
+
off. Older documents or revisions may still depend on that feature. Removing
|
|
92
|
+
a requirement needs a verified data-history transition, such as an explicit
|
|
93
|
+
reconstruction which removes that representation. Manually shortening the declaration is not a supported migration.
|
|
94
|
+
|
|
95
|
+
This is a client compatibility contract, not CouchDB access control. It cannot
|
|
96
|
+
retrofit checks into legacy direct-access clients or revoke requests which a
|
|
97
|
+
server has already accepted.
|
|
98
|
+
|
|
99
|
+
## Admission and changes during replication
|
|
100
|
+
|
|
101
|
+
Use the same assessment before ordinary replication, Fast Fetch, direct file
|
|
102
|
+
access, and cleaned-remote recovery before counting Chunk references. Declare
|
|
103
|
+
required write features after admission, including for the writer accepted by a
|
|
104
|
+
Rebuild lock. A locked-out device cannot declare or upload a new representation.
|
|
105
|
+
|
|
106
|
+
Fast Fetch reads the version document with its configured HTTP credentials and
|
|
107
|
+
custom headers before opening or resetting the local database, including when
|
|
108
|
+
resuming a checkpoint. Rejection leaves local data and the checkpoint intact.
|
|
109
|
+
An empty remote and legacy generations retain their existing completion and
|
|
110
|
+
migration paths; a missing version document in a populated remote is rejected.
|
|
111
|
+
|
|
112
|
+
The remote document is the source of requirements. The milestone retains its
|
|
113
|
+
participant, Tweak comparison, and lock responsibilities. Hosts do not need a
|
|
114
|
+
second persistent feature list or rejection history in KV storage.
|
|
115
|
+
|
|
116
|
+
The existing received-version handler also uses the shared assessment. An
|
|
117
|
+
unknown identifier, unsupported generation, or malformed document requests
|
|
118
|
+
Replicator retirement and reports the reason. Supported requirements do not
|
|
119
|
+
interrupt the connection merely because the revision or feature list changed.
|
|
120
|
+
Do not await retirement inside the change callback: the owner may be waiting
|
|
121
|
+
for that callback to settle before it can drain and close the operation.
|
|
122
|
+
|
|
123
|
+
A received notification can follow persistence to the local database. The
|
|
124
|
+
handler is a best-effort response to an exceptional live change; it does not
|
|
125
|
+
fence every queued file application or atomically revoke admitted requests.
|
|
126
|
+
Use the established rollout workflow: update every synchronising client, enable
|
|
127
|
+
the preference, and perform the strongly recommended manual Rebuild. Rebuild
|
|
128
|
+
uses the existing remote lock. Merely changing the preference does not lock the
|
|
129
|
+
remote, so continuing without rebuilding requires compatible devices first,
|
|
130
|
+
including those with an active connection.
|
|
131
|
+
|
|
132
|
+
The next connection assesses the current remote declaration, including after
|
|
133
|
+
restart. Existing host snapshot and startup behaviour remain unchanged. After
|
|
134
|
+
updating, use the host's normal reconciliation or Fetch facilities as needed;
|
|
135
|
+
this contract does not add permanent local rejection flags or repair unrelated
|
|
136
|
+
snapshot inconsistencies.
|
|
137
|
+
|
|
138
|
+
## First feature: encrypted internal Metadata
|
|
139
|
+
|
|
140
|
+
`encrypted-internal-metadata-v1` denotes the first specification of this feature,
|
|
141
|
+
not the legacy E2EE V1 algorithm. It uses E2EE V2's existing HKDF Metadata
|
|
142
|
+
representation for obfuscated `i:`, `ix:`, and supported legacy `ps:` entries.
|
|
143
|
+
Document IDs and path-to-ID conversion remain unchanged.
|
|
144
|
+
|
|
145
|
+
Supporting readers decode by the encrypted Metadata marker, independently of
|
|
146
|
+
the current write preference. Existing plaintext and encrypted Metadata may
|
|
147
|
+
coexist. Activating the preference affects subsequent writes; it does not
|
|
148
|
+
rewrite unchanged documents or erase earlier plaintext revisions. Reconstruction
|
|
149
|
+
is strongly recommended for existing-data privacy, and remains a manual choice.
|
|
150
|
+
|
|
151
|
+
Garbage Collection V3 remains a beta, manually initiated operation. Its
|
|
152
|
+
workflow first performs an ordinary bidirectional synchronisation, which checks
|
|
153
|
+
the remote feature contract. It does not add another check at every collection
|
|
154
|
+
step. The separate cleaned-remote recovery path checks the local contract
|
|
155
|
+
before its first Chunk-reference count because that path does not begin with
|
|
156
|
+
ordinary synchronisation.
|
|
157
|
+
|
|
158
|
+
## Verification required before acceptance
|
|
159
|
+
|
|
160
|
+
Protect the wire contract with tests for unknown names, multiple unknown names,
|
|
161
|
+
malformed lists, legacy absence, new-generation absence, duplicate and reordered
|
|
162
|
+
entries, concurrent updates, and preservation of existing fields. Use a made-up
|
|
163
|
+
future identifier so the test does not depend on a known feature's label.
|
|
164
|
+
|
|
165
|
+
Protect runtime behaviour with tests for initial admission, an admitted writer
|
|
166
|
+
on a locked remote, unknown names received at the same generation, and
|
|
167
|
+
retirement without a circular wait. Keep direct access, Fast Fetch, and
|
|
168
|
+
maintenance admission checks covered. Host tests should preserve existing
|
|
169
|
+
startup and queue semantics, including snapshot failures.
|
|
170
|
+
|
|
171
|
+
Use real CouchDB and downstream Obsidian and CLI tests to validate encrypted
|
|
172
|
+
Metadata, file restoration, receipt of a changed declaration, and rejection
|
|
173
|
+
before synchronisation after restart. These checks do not establish atomic
|
|
174
|
+
cancellation timing or automatic recovery under a future compatible client.
|
|
175
|
+
|
|
176
|
+
Related contracts: [local database lifecycle](database-lifecycle.md) and
|
|
177
|
+
[settings lifecycle](settings-lifecycle.md).
|
package/package.json
CHANGED