@vrtmrz/livesync-commonlib 0.2.3 → 0.3.0

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.
Files changed (46) hide show
  1. package/README.md +33 -8
  2. package/dist/API/DirectFileManipulatorV2.d.ts +7 -1
  3. package/dist/API/DirectFileManipulatorV2.js +46 -67
  4. package/dist/API/DirectFileWatchOwner.d.ts +24 -0
  5. package/dist/API/DirectFileWatchOwner.js +256 -0
  6. package/dist/API/processSetting.js +3 -3
  7. package/dist/common/models/setting.type.d.ts +1 -1
  8. package/dist/common/models/shared.definition.configNames.js +1 -2
  9. package/dist/common/models/tweak.definition.d.ts +1 -1
  10. package/dist/common/pathNormalization.d.ts +2 -0
  11. package/dist/common/pathNormalization.js +7 -2
  12. package/dist/managers/ChunkFetcher.d.ts +3 -0
  13. package/dist/managers/ChunkFetcher.js +20 -13
  14. package/dist/managers/LiveSyncManagers.d.ts +2 -0
  15. package/dist/managers/LiveSyncManagers.js +1 -0
  16. package/dist/managers/chunkFetchSource.d.ts +14 -0
  17. package/dist/managers/chunkFetchSource.js +12 -0
  18. package/dist/pouchdb/LiveSyncDBFunctions.js +5 -0
  19. package/dist/pouchdb/LiveSyncLocalDB.d.ts +7 -1
  20. package/dist/pouchdb/LiveSyncLocalDB.js +13 -10
  21. package/dist/pouchdb/pathIdentityCompatibility.d.ts +8 -0
  22. package/dist/pouchdb/pathIdentityCompatibility.js +19 -1
  23. package/dist/replication/RemoteResource.d.ts +3 -0
  24. package/dist/replication/index.d.ts +2 -0
  25. package/dist/replication/index.js +2 -0
  26. package/dist/replication/journal/JournalSyncCore.d.ts +1 -0
  27. package/dist/replication/journal/JournalSyncCore.js +35 -19
  28. package/dist/replication/journal/LiveSyncJournalReplicator.d.ts +11 -3
  29. package/dist/replication/journal/LiveSyncJournalReplicator.js +123 -45
  30. package/dist/replication/trystero/P2PRoomSessionOwner.js +14 -13
  31. package/dist/replication/trystero/TrysteroReplicator.d.ts +7 -5
  32. package/dist/replication/trystero/TrysteroReplicator.js +98 -70
  33. package/dist/replication/trystero/TrysteroReplicator.pathIdentity.d.ts +11 -0
  34. package/dist/replication/trystero/TrysteroReplicator.pathIdentity.js +72 -0
  35. package/dist/replication/trystero/p2pReplicatorConfigurationIdentity.js +2 -0
  36. package/dist/replication/trystero/useP2PReplicatorFeature.js +6 -2
  37. package/dist/serviceModules/Rebuilder.d.ts +1 -0
  38. package/dist/serviceModules/Rebuilder.js +33 -5
  39. package/dist/worker/bgWorker.js +1 -1
  40. package/docs/conflict-resolution.md +1 -1
  41. package/docs/development.md +4 -0
  42. package/docs/proven-in-use.md +30 -13
  43. package/docs/releasing.md +2 -0
  44. package/docs/service-feature-composition.md +7 -1
  45. package/docs/unicode-path-identity.md +64 -3
  46. package/package.json +2 -2
@@ -74,7 +74,7 @@ A host must not apply a dialogue result after either compared revision has cease
74
74
 
75
75
  ## Scheduling conflict checks
76
76
 
77
- The unreleased `@vrtmrz/livesync-commonlib/conflicts` entry exports
77
+ The `@vrtmrz/livesync-commonlib/conflicts` entry, published in Commonlib 0.2.3, exports
78
78
  `createConflictCheckQueue`. The host supplies a `process(path, scope)` callback
79
79
  and may observe pending plus active checks through `onProgress`. Concurrency
80
80
  defaults to ten and includes each item's deferred cleanup. The host continues
@@ -111,6 +111,10 @@ The revision-tree safety rules are documented in [Conflict resolution and file p
111
111
 
112
112
  `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.
113
113
 
114
+ Direct CouchDB hosts supply a database-bound `ChunkFetchSource` through the optional `LiveSyncLocalDB` runtime factory. `LiveSyncManagers` passes it to the shared `ChunkFetcher`; application hosts omit it and retain active-replicator retrieval and local persistence. The direct source reads the prepared database and accepts results without writing them back. Recreate it with each database instance so reopening cannot retain a closed connection. `ChunkFetcher.source.unit.spec.ts` covers direct retrieval, delayed availability without change notifications, bounded failure, and teardown. `DirectFileManipulatorV2.integration.spec.ts` covers encrypted arrival before and during an outstanding read, with assertions that the reader does not write Chunks back.
115
+
116
+ `DirectFileWatchOwner` owns the direct watch lifecycle. Its per-client state retains unfinished reads, same-document delivery ownership, and pending checkpoint persistence across stop and restart. Each watch session separately owns its pending documents, connection generation, and timers. Named operations receive explicit contexts through Octagonal Wheels `bindContext`; per-file and per-delivery scopes release their bookkeeping after the operation settles. Feed cancellation and timer cancellation remain synchronous in `endWatch()`, independently of unfinished reads or host callbacks. The owner tests cover retries, safe checkpoint positions, replacement sessions, and failure handling; `DirectFileManipulatorV2.unit.spec.ts` retains the public state, database binding, and close-order checks.
117
+
114
118
  `RemoteService.connect()` returns an owned CouchDB connection as the existing flat `{ db, info }` result with an idempotent `close()` method. `close()` first aborts outstanding abort-capable requests in that connection, then closes the PouchDB handle. The owner must transfer or close the complete connection; passing only `db` loses the cancellation boundary. A skipped information request retains the established placeholder in `info` for compatibility. `OwnedCouchDBConnection`, its opening options, and the checked `CouchDBReplicationConnection` are Commonlib-owned types exported by the existing CouchDB replicator module. The legacy `_ensureConnection()` helper continues to return a raw PouchDB handle for source compatibility; new Commonlib code must retain and close the complete owned connection instead.
115
119
 
116
120
  The one-shot CouchDB connectivity preflight is the first bounded consumer. It applies an internal 60-second safety fuse to the complete preflight on the web-compatible fetch path, disables fallback into the non-abortable native request adapter, and clears the fuse before transferring the connection to replication. The fuse is a last-resort wall-clock bound on an owner which would otherwise remain pending indefinitely; it is not the expected completion time, a per-request inactivity timeout, a user setting, or the `useTimeouts` changes-feed setting. The explicitly selected native Request API retains its previous unbounded behaviour because its current host adapter cannot honour `AbortSignal`. Extend `RemoteService.unit.spec.ts` and the one-shot ownership table in `LiveSyncReplicator.unit.spec.ts` when changing this boundary. Do not use `Promise.race()` to report a mutating native request as cancelled while it can still complete remotely.
@@ -6,9 +6,23 @@ The useful evidence is host- and contract-specific. Focused Commonlib tests esta
6
6
 
7
7
  The code paths below identify maintained Self-hosted LiveSync composition points as examples. The reviewed downstream revision and compatibility imports are recorded in [`migration/downstream-imports.json`](migration/downstream-imports.json), which is regenerated by the package-boundary tooling rather than copied into prose links. These snapshots may become historical as the maintained downstream changes; this page is optional context, not a support entitlement or release or adoption gate.
8
8
 
9
- ## Blob construction and comparison: candidate integration
9
+ ## Published shared-runtime integration
10
10
 
11
- The unreleased Blob extraction delegates construction to
11
+ Commonlib [0.2.3](https://github.com/vrtmrz/livesync-commonlib/releases/tag/0.2.3)
12
+ is published on npm through `latest` and `next`, with an exact dependency on
13
+ Octagonal Wheels 0.1.56. Self-hosted LiveSync
14
+ [1.0.44](https://github.com/vrtmrz/obsidian-livesync/releases/tag/1.0.44)
15
+ adopts the published Commonlib package. Its
16
+ [integration record](https://github.com/vrtmrz/obsidian-livesync/pull/1307)
17
+ separates the final source checks from the focused browser, CLI, and real-Obsidian
18
+ results for unchanged consumer boundaries. The earlier candidate measurements
19
+ below remain historical evidence at their recorded versions.
20
+
21
+ <a id="blob-construction-and-comparison-candidate-integration"></a>
22
+
23
+ ## Blob construction and comparison: published integration
24
+
25
+ Commonlib 0.2.3 delegates Blob construction to
12
26
  `octagonal-wheels/binary/blob`. Commonlib retains the old creation imports and
13
27
  wraps `toBlob` as `createBlob`, while document classification, binary decoding,
14
28
  and content-comparison policy remain in Commonlib. The legacy
@@ -31,13 +45,12 @@ absence on the native path. The
31
45
  the existing Commonlib imports after packaging.
32
46
 
33
47
  Earlier candidate checks explicitly installed the selected unpublished Octagonal
34
- Wheels tarball in the disposable consumer. The current unreleased Commonlib
35
- integration pins the published Octagonal Wheels 0.1.56 dependency and uses the
36
- ordinary package gate without a candidate override. Self-hosted LiveSync tests its hidden-file
37
- loading and revision handling through the legacy entry with matching
38
- candidate tarballs. Those consumer checks are distinct from Commonlib-owned
39
- compatibility contracts; real-Obsidian and mobile validation of this extraction
40
- remain pending.
48
+ Wheels tarball in the disposable consumer. Commonlib 0.2.3 pins the published
49
+ Octagonal Wheels 0.1.56 dependency and uses the ordinary package gate without a
50
+ candidate override. The subsequent Self-hosted LiveSync integration uses the
51
+ exact published Commonlib package. Its recorded application builds and focused
52
+ real-Obsidian conflict and catalogue checks complement the Commonlib-owned
53
+ compatibility contracts; they do not establish physical mobile-device behaviour.
41
54
 
42
55
  ## Obsidian plug-in
43
56
 
@@ -254,7 +267,9 @@ Use the named consumer paths as integration examples, while retaining the owners
254
267
  This optional page preserves examples, current integration evidence, and history. It does not define supported behaviour or create a release or adoption gate; package guarantees are described by the published contracts and release policy. When this page is updated, distinguish current use, historical use, Commonlib-owned tests, downstream tests, and real-runtime observations, and keep each claim within its evidence.
255
268
 
256
269
 
257
- ## Shared value helpers: candidate integration
270
+ <a id="shared-value-helpers-candidate-integration"></a>
271
+
272
+ ## Shared value helpers: published integration
258
273
 
259
274
  The [runtime helper tests](../src/common/utils.runtime-tools.unit.spec.ts)
260
275
  characterise duration thresholds, delimiter empty parts, and JSON conversion
@@ -264,16 +279,18 @@ to detach settings before an operation. The shared package owns the value
264
279
  operations. The packed [type fixture](../_tools/fixtures/runtime-tools-types.ts) and
265
280
  [runtime fixture](../_tools/fixtures/runtime-tools-runtime.mjs) exercise those
266
281
  public duration and delimiter compatibility entries. The original checks used an
267
- unpublished dependency candidate; the current integration pins the published
282
+ unpublished dependency candidate; Commonlib 0.2.3 pins the published
268
283
  Octagonal Wheels 0.1.56 release. Source tests cover the internal copy adapter.
269
284
  LiveSync continues to use the existing compatibility entry points, including
270
285
  duration labels in ConfigSync and tagged lists in settings. Source and packed
271
286
  checks do not establish real-Obsidian rendering or device behaviour.
272
287
 
273
288
 
274
- ## Shared multi-key locking: candidate integration
289
+ <a id="shared-multi-key-locking-candidate-integration"></a>
290
+
291
+ ## Shared multi-key locking: published integration
275
292
 
276
- The unreleased candidate imports `withLocks` directly from
293
+ Commonlib 0.2.3 imports `withLocks` directly from
277
294
  `octagonal-wheels/concurrency/lock` for offline Metadata repair and file-event
278
295
  processing. Commonlib retains the `processFileEvent-` namespace, unique sorted
279
296
  document IDs, and conflict hooks deferred until every lock has been released.
package/docs/releasing.md CHANGED
@@ -40,6 +40,8 @@ The Commonlib 0.2 policy begins with 0.2.0 and does not retroactively change com
40
40
 
41
41
  For 0.2.3, the documented exceptions are the `HandlerFunction.setHandler` and `LazyHandlerFunction.setHandler` return types changing from `void` to `UnregisterFunction`, and `timeDeltaToHumanReadable(Infinity)` returning `∞y` instead of `Infinityy`. The setter types now describe the existing runtime return. Custom implementations and test doubles whose setters return `void` must provide an unregister function; ordinary callers may continue to ignore the result. These are the specific 0.2.3 exceptions to the policy.
42
42
 
43
+ Version 0.3.0 introduces a source compatibility change: the custom client passed to `LiveSyncJournalReplicator.ensureBucketIsCompatible` must provide `hasRemoteJournals(): Promise<boolean>`. The operation distinguishes an empty bucket from Journal files left without an identifying milestone. Keeping it required makes missing client capability a type error. The standard `JournalSyncCore` client already supplies it. This change uses the next minor version under the policy above.
44
+
43
45
  ## Preparing a release
44
46
 
45
47
  Choose the version explicitly. For the 0.2 line, start at 0.2.0. A stable candidate can use its final version on the `next` dist-tag, then be checked by exact source revision and tarball SHA-256 before the same version is promoted to `latest`. No `-next.N` or `-rc.N` version is required; use a separate prerelease version only when it is useful for a distinct candidate. Package-proof versions are local artefacts and cannot be staged.
@@ -2,11 +2,17 @@
2
2
  date: 2026-10-25
3
3
  commonlib-version: "0.2.0"
4
4
  self-hosted-livesync-version: "1.0.40"
5
- status: unreleased
5
+ status: published
6
6
  ---
7
7
 
8
8
  # Service feature composition
9
9
 
10
+ Publication update, 2nd November, 2026: the Service Hub source selection, narrowed
11
+ host dependencies, and signature-preserving composition helpers are published
12
+ in Commonlib [0.2.3](https://github.com/vrtmrz/livesync-commonlib/releases/tag/0.2.3)
13
+ and used by Self-hosted LiveSync 1.0.44. The front matter retains the original
14
+ review date and version baseline.
15
+
10
16
  This guide is for Commonlib and maintained-host developers who are adding behaviour to the Service Hub composition. It explains when to extend a Service, create a serviceFeature, share a ServiceModule, or introduce a class which owns a resource.
11
17
 
12
18
  The choice is primarily about dependency direction and ownership. Mutable state alone does not require a class or a ServiceModule.
@@ -14,7 +14,8 @@ does not alter the Metadata path or require physical files to be renamed.
14
14
  Unsupported values are rejected.
15
15
 
16
16
  NFC identity shipped in Commonlib `0.1.42` and Self-hosted LiveSync `1.0.38`.
17
- The deletion handling below is an unreleased refinement of reconstruction.
17
+ The Journal and P2P extension described below is unreleased. The original
18
+ CouchDB release remains the published baseline for this document.
18
19
 
19
20
  ## Package contract
20
21
 
@@ -25,6 +26,24 @@ implementation for Metadata IDs rather than add a host-specific normalisation
25
26
  rule. Host storage adapters remain responsible for mapping a logical path back
26
27
  to its existing physical entry.
27
28
 
29
+ ## Initial host settings
30
+
31
+ Commonlib's shared new-Vault and stored-setting defaults retain version `0`.
32
+ The maintained CLI and Obsidian hosts use version `1` for newly created
33
+ synchronisation settings in the unreleased extension, while retaining `0` for
34
+ old settings and Setup URIs which omit the field. This policy does not enable
35
+ NFC for WebApp or WebPeer, and does not migrate existing databases.
36
+
37
+ The focused replication entry exports `inspectDatabasePathIdentity` and
38
+ `PathIdentityInspection`. The existing `RemoteConnectionProbe` may expose
39
+ `inspectPathIdentity` for read-only initial setup. Inspection distinguishes a
40
+ confirmed empty remote from an existing declaration; unavailable or unsupported
41
+ state rejects. Hosts use the existing declaration before first participation,
42
+ and keep source Rebuild and configured startup explicit. Journal inspection
43
+ reads milestone evidence without writing a node, Security Seed, or checkpoint.
44
+ A P2P signalling probe does not establish peer database identity; Setup URIs
45
+ carry the selected mode, and manual configuration must match the source.
46
+
28
47
  ## Database compatibility
29
48
 
30
49
  Version `1` uses `nfc-path-identity-v1` in the existing generation-13
@@ -78,14 +97,56 @@ does not itself perform the required reconstruction.
78
97
 
79
98
  ## Supported hosts
80
99
 
81
- The initial support boundary is the maintained CLI and Obsidian with CouchDB.
100
+ The maintained CLI and Obsidian support NFC identity with CouchDB, Journal,
101
+ and P2P in this unreleased extension.
82
102
  `PathService` owns logical ID derivation. The CLI resolves NFC-equivalent names
83
103
  against directory entries while preserving the actual entry spelling; its
84
104
  generic Node storage contract remains exact-path access. Obsidian supplies its
85
105
  normalised storage paths and preserves an existing physical spelling when it
86
106
  is NFC-equivalent to the received path.
87
107
 
88
- Journal and P2P refuse version `1`. Direct file access refuses a remote which
108
+ Journal uses compatibility range `4` for NFC identity, independently of
109
+ encryption and path obfuscation. Legacy ranges remain unchanged. The existing
110
+ stored node ranges and required Tweak reject a different identity even when
111
+ ordinary mismatch warnings are disabled. Removing preferred Tweaks does not
112
+ remove the range check or an existing document-ID agreement proof. The existing
113
+ ID check is also reused before Fetch and ordinary milestone updates. A missing
114
+ milestone over existing journals requires Rebuild in both legacy and NFC modes;
115
+ it is not permission to declare a new identity. Older clients must be updated
116
+ before migration; their explicit version-check override is outside this
117
+ compatibility guarantee.
118
+
119
+ The same read-only identity assessment runs before a Journal Fetch resets the
120
+ local database and before ordinary milestone updates. It does not publish a
121
+ node, create a Security Seed, or change a checkpoint. Rebuild first locks the
122
+ existing milestone for the rebuilding node, retaining an existing compatibility
123
+ range for that node and preserving the old identity evidence and Tweaks until
124
+ the journals are deleted. Deletion lists the keys once, retaining skipped control
125
+ document keys until all Journal pages have been processed. It then removes those
126
+ control documents, including the milestone and Security Seed, in finite batches.
127
+ A repeated or backwards listing cursor stops the reset before those control
128
+ documents are removed. A partial failure or interrupted request during Journal
129
+ deletion retains those control documents and the transfer checkpoint for a retry. Checkpoints reset only after control
130
+ document deletion also succeeds. A missing milestone stays absent during this
131
+ step. The replacement identity is declared after deletion succeeds, so a failed
132
+ or interrupted deletion cannot label the old journals with the new identity.
133
+
134
+ P2P uses its existing Tweak exchange and version document to check both peers
135
+ before ordinary data replication. Missing path settings mean version `0`.
136
+ Local Metadata without the matching feature requires Rebuild. A fresh database
137
+ with only control documents may declare the existing NFC feature. Connection
138
+ state is renewed when the selected identity changes. This adds no
139
+ authentication protocol or persistent admission store; all participating peers
140
+ must be updated and migrated.
141
+
142
+ Journal migration rebuilds the source local database and remote journals. P2P
143
+ Rebuild prepares only the source local database. Other devices replace their
144
+ local databases through Fetch. The existing local reset destroys Journal KV
145
+ checkpoints; the P2P source mark and target checkpoint handle database
146
+ replacement. These operations do not rewrite IDs or merge histories in place.
147
+ P2P retains its existing source selection during Fetch.
148
+
149
+ Direct file access refuses a remote which
89
150
  declares the NFC feature. Other host adapters must establish physical path
90
151
  resolution before offering this setting. The regression tests cover ASCII,
91
152
  NFC, NFD, and mixed paths through in-memory PouchDB Metadata lookup, with and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vrtmrz/livesync-commonlib",
3
- "version": "0.2.3",
3
+ "version": "0.3.0",
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",
@@ -1019,7 +1019,7 @@
1019
1019
  "fflate": "^0.8.2",
1020
1020
  "idb": "^8.0.3",
1021
1021
  "markdown-it": "^14.3.3",
1022
- "minimatch": "^10.2.6",
1022
+ "minimatch": "^11.0.3",
1023
1023
  "octagonal-wheels": "0.1.56",
1024
1024
  "pouchdb-adapter-http": "^9.0.0",
1025
1025
  "pouchdb-adapter-idb": "^9.0.0",