@vrtmrz/livesync-commonlib 0.1.43 → 0.2.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 (71) hide show
  1. package/README.md +57 -6
  2. package/dist/API/DirectFileManipulatorV2.d.ts +2 -0
  3. package/dist/API/DirectFileManipulatorV2.js +3 -0
  4. package/dist/common/configForDoc.d.ts +1 -0
  5. package/dist/common/configForDoc.js +11 -1
  6. package/dist/common/models/db.definition.d.ts +1 -0
  7. package/dist/common/models/setting.const.preferred.js +1 -3
  8. package/dist/diagnostics/couchdb.js +86 -13
  9. package/dist/diagnostics/index.d.ts +2 -2
  10. package/dist/diagnostics/index.js +2 -0
  11. package/dist/diagnostics/integrity.js +385 -158
  12. package/dist/diagnostics/names.d.ts +16 -0
  13. package/dist/diagnostics/names.js +50 -0
  14. package/dist/diagnostics/reports.d.ts +13 -10
  15. package/dist/diagnostics/reports.js +191 -50
  16. package/dist/diagnostics/types.d.ts +64 -4
  17. package/dist/diagnostics/usage.d.ts +4 -0
  18. package/dist/diagnostics/usage.js +158 -54
  19. package/dist/managers/EntryManager/EntryManagerImpls.js +3 -2
  20. package/dist/pouchdb/LiveSyncDBFunctions.js +4 -0
  21. package/dist/pouchdb/StreamingFetch.d.ts +5 -1
  22. package/dist/pouchdb/StreamingFetch.js +529 -65
  23. package/dist/replication/RemoteResource.d.ts +23 -2
  24. package/dist/replication/RemoteResource.js +6 -2
  25. package/dist/replication/couchdb/LiveSyncReplicator.d.ts +8 -0
  26. package/dist/replication/couchdb/LiveSyncReplicator.js +132 -1
  27. package/dist/replication/couchdb/fastForward.d.ts +19 -0
  28. package/dist/replication/couchdb/fastForward.js +119 -0
  29. package/dist/replication/index.d.ts +3 -1
  30. package/dist/replication/joinedDevices.d.ts +25 -0
  31. package/dist/replication/joinedDevices.js +123 -0
  32. package/dist/replication/journal/JournalSyncCore.d.ts +2 -1
  33. package/dist/replication/journal/JournalSyncCore.js +11 -1
  34. package/dist/replication/journal/LiveSyncJournalReplicator.d.ts +4 -0
  35. package/dist/replication/journal/LiveSyncJournalReplicator.js +56 -1
  36. package/dist/replication/journal/objectstore/JournalStorageAdapter.d.ts +3 -0
  37. package/dist/replication/journal/objectstore/MinioStorageAdapter.d.ts +2 -1
  38. package/dist/replication/journal/objectstore/MinioStorageAdapter.js +27 -1
  39. package/dist/replication/trystero/P2PRoomSessionOwner.d.ts +1 -1
  40. package/dist/replication/trystero/P2PRoomSessionOwner.js +27 -14
  41. package/dist/serviceModules/Rebuilder.js +41 -15
  42. package/dist/services/BrowserServices.d.ts +4 -2
  43. package/dist/services/BrowserServices.js +2 -5
  44. package/dist/services/HeadlessServices.d.ts +3 -0
  45. package/dist/services/HeadlessServices.js +2 -5
  46. package/dist/services/ServiceHub.d.ts +4 -4
  47. package/dist/services/base/IService.d.ts +10 -18
  48. package/dist/services/base/ReplicatorService.remoteResourceResolver.js +1 -1
  49. package/dist/services/base/SettingService.d.ts +8 -18
  50. package/dist/services/base/SettingService.js +28 -46
  51. package/dist/services/implements/base/SvelteDialog.d.ts +2 -2
  52. package/dist/services/implements/base/UIService.d.ts +2 -0
  53. package/dist/services/implements/base/UIService.js +5 -0
  54. package/dist/services/implements/injectable/InjectableServiceHub.d.ts +4 -4
  55. package/dist/services/implements/injectable/InjectableServices.d.ts +2 -2
  56. package/dist/services/implements/injectable/InjectableSettingService.d.ts +0 -3
  57. package/dist/services/implements/injectable/InjectableSettingService.js +0 -11
  58. package/dist/string_and_binary/chunks.js +7 -5
  59. package/dist/uiCommands.d.ts +26 -0
  60. package/dist/uiCommands.js +57 -0
  61. package/dist/worker/bgWorker.js +1 -1
  62. package/docs/database-diagnostics.md +45 -0
  63. package/docs/development.md +15 -3
  64. package/docs/proven-in-use.md +45 -5
  65. package/docs/releasing.md +20 -13
  66. package/docs/settings-lifecycle.md +37 -5
  67. package/package.json +13 -17
  68. package/dist/services/base/ConfigService.d.ts +0 -7
  69. package/dist/services/base/ConfigService.js +0 -6
  70. package/dist/services/implements/browser/ConfigServiceBrowserCompat.d.ts +0 -16
  71. package/dist/services/implements/browser/ConfigServiceBrowserCompat.js +0 -23
@@ -11,14 +11,59 @@ The focused `/diagnostics` entry supplies read-only database usage analysis and
11
11
 
12
12
  Usage retains the existing available-revision selection and incremental chunk accounting. The first processed reference counts a chunk as unique; later references count it as shared. Sizes count JavaScript string units, as in the existing report. These columns do not measure physical database size or establish whether a chunk can be deleted.
13
13
 
14
+ Usage progress emits a `reading` phase while it discovers revisions, with `idsProcessed` and `revisionsProcessed` retained for existing consumers. `processed` counts settled available-revision reads, including failures; `total` grows as available revisions are discovered and is not final until enumeration finishes. The analyser does not pre-scan to calculate a total. The separate `accounting` phase has a fixed work-item total and yields between batches so the host can respond to cancellation. Cancellation during reading retains collected evidence; cancellation during accounting omits incomplete rows and orphan statistics. A failing progress callback does not change the result.
15
+
14
16
  Integrity inspection enumerates actual stored document IDs, including logically deleted normal-file Metadata and current conflict branches. It uses the same identity classifier as the existing Metadata inspector. It reads content only for groups with identity discrepancies, conflicting branches, duplicate path claims, or differences between the inspected local and remote Metadata. Content comparisons use reconstructed bytes, including the Vault file where available. Missing, unreadable, and uninspected content remain distinct outcomes. Equal content within this scope does not establish that an entry is safe to delete.
15
17
 
18
+ Standard integrity observations include recorded document type, size, and total, unique, and embedded Chunk-reference counts. When suspect bytes have already been read, they also include measured decoded-content and Vault sizes, their differences from recorded or reconstructed sizes, and the Vault-to-Metadata modification-time difference. Case-only and NFC-equivalent path group membership is included once for each group. These facts use the normal decoded and decrypted Metadata and reads already needed for inspection; they do not add database, HTTP, or Vault reads. Facts which were not inspected remain absent or `not-checked`.
19
+
20
+ Integrity inspection classifies up to four Metadata documents or processes up to four suspect content groups concurrently. Hosts can set `concurrency` between one and sixteen for comparison or resource limits. Local and remote Metadata scans remain separate, and results retain enumeration order regardless of completion order. Sources with `getMany` fetch current Metadata and required Chunks in groups of up to 64 documents. Metadata classification follows each bulk read; content groups read their Chunk batches and Vault files sequentially. The CouchDB reader separately decodes up to four documents per bulk response, so `concurrency` limits analyser work rather than total concurrent decryption across active groups. Exact conflict revisions still use individual reads. Cancellation stops dispatching new work and drains active reads before releasing the remote source; collected findings remain available.
21
+
22
+ Integrity progress identifies the phase and source. Metadata progress counts completed documents, including excluded IDs, against the source's `doc_count` when available. Content progress counts completed suspect groups against their known total. Missing document totals remain unknown until enumeration finishes. A source changed during inspection can change the total and makes the report partial. Hosts should label these separate units rather than combine them into one percentage.
23
+
24
+ The optional `onLog` callback receives phase start and finish events, with progress events at most once every five seconds while work completes. Events contain counts, elapsed time, the concurrency limit, active and peak reads, read operations, and summed read duration. Read operations count requested documents; a bulk read counts once towards active reads and elapsed read duration. Summed read duration includes overlapping reads. HTTP request counts belong to the host's injected fetch boundary and can differ from document reads. Grouping has its own timing event. These events contain no paths, document identifiers, connection details, or raw errors. Progress and log callback failures do not interrupt inspection.
25
+
16
26
  The first implementation supports the local database and CouchDB. Internal-file, customisation, and plug-in storage Metadata, older revision history, and other remote backends are explicitly outside integrity inspection. Usage continues to cover the revisions available to its local source. A remote failure retains the local findings and marks the integrity report partial.
17
27
 
28
+ `includeRemote` defaults to true. Setting it to false does not open the remote source: local identity, conflict, and duplicate-path checks still run, with content comparisons against the Vault for suspect groups. Remote coverage and cross-source comparisons remain `not-checked`, and `scope.remote` is `excluded` in JSON and Markdown reports. A local-only run can complete within that declared scope; excluding a remote is distinct from a failed connection. Hosts should collect this choice for each run rather than change synchronisation settings.
29
+
18
30
  The CouchDB reader only sends GET requests. It reads existing synchronisation parameters when decryption needs a Security Seed and never creates missing parameters, initialises a database, or invokes replication admission. Local content reads do not fetch or cache remote Chunks. Owned requests are cancelled and released when the run ends; host-native request adapters may finish an already dispatched request after cancellation, but its result is discarded.
19
31
 
32
+ Bulk reads use `_all_docs` with selected `keys`, `include_docs`, and optional `conflicts`. The reader limits each request to 64 documents and a 6,000-character encoded URL; an individual key which exceeds that URL limit uses the existing single-document GET. ID enumeration does not include document bodies, so unrelated Chunks are not downloaded. Embedded Chunks require no request, and repeated Chunk IDs within one batch share a read. Missing rows, deleted documents, unreadable results, and failed HTTP requests retain distinct evidence; a failed batch does not establish that its documents are absent. Bulk results use the same decryption and decompression as individual reads and are released after each batch.
33
+
20
34
  Database update sequences and the host's configuration identity are checked again before completion. Storage readers must detect changes while reading a file. These observations can detect concurrent changes; they do not provide an atomic snapshot or prevent a file from changing later.
21
35
 
22
36
  Reports project a whitelist of facts. Pseudonyms preserve exact path equality across sources and keep document, revision, and Chunk identifiers separate. Case and Unicode normalisation facts are computed before projection. Maps are local to one run and are not persisted. Original-name mode still excludes credentials, connection addresses, encryption keys, raw errors, and file contents. JSON and Markdown use the same projected integrity result; TSV uses the same name mapper for Usage.
23
37
 
38
+ Each pseudonym report uses a random eight-character public salt. Path tokens have the form `<salt>$<hash>`; `<hash>` is the first 128 bits of a SHA-256 digest, shown as 32 lowercase hexadecimal characters. The digest is domain-separated by name kind and uses the exact stored Vault-relative path, without lower-casing or Unicode NFC normalisation. The mapper keeps no persistent salt or correspondence table. A consumer can parse a complete path token with `parseDiagnosticPathToken` and pass its salt to `createDiagnosticNameMapper('pseudonym', parsed.salt)` to reproduce path, document, revision, and Chunk pseudonyms for a targeted follow-up. Revision pseudonyms retain a valid generation prefix, such as `7-psu…`.
39
+
40
+ The salt is public, so someone with the report can test guessed path values against a token; pseudonyms are not encryption. Earlier ordinal pseudonyms cannot be looked up this way. The path-token parser only extracts a salt and hash from a complete token; it does not recover the original path.
41
+
42
+ ### Compact Integrity Markdown report
43
+
44
+ Integrity Markdown retains its status, name mode, versions, settings, scope, coverage, and count summary, with separate counts for content and Vault checks which were not performed. **State counts** count observations, not unique files; each local or remote observation contributes to its state total. The **Review index** lists references to observations which match review conditions, before **Findings**. Those conditions are identity mismatches, current conflicts, case- or NFC-equivalent paths, non-NFC paths, a missing group in the other inspected source, missing or unreadable content or Vault files, unavailable Chunks, different or unavailable comparisons, non-zero measured differences, and absent Metadata. These are review candidates, not findings of corruption. An observation outside the index is still present in **Findings**, and unchecked content or Vault state is not evidence of health.
45
+
46
+ Each observation uses a compact field order while preserving every observation and its complete path, document ID, revision, and reference values:
47
+
48
+ ```text
49
+ ### `remote:4410` source=remote
50
+ path: `<salt>$<hash>`
51
+ doc: `<document-id>` rev=`<revision>` expected=self
52
+ state: consistent-winner-logicallyLive-NFC-newnote conflicts=0
53
+ paths: case=none nfcPeers=none | otherDB=present
54
+ data: recorded=47584B chunks=1/1/0 read=0
55
+ check: content=not-checked vault=not-checked@`vault:remote:4410`
56
+ measure: content=47584B vault=47584B deltaContent=0B deltaVault=0B deltaMtime=0ms
57
+ ```
58
+
59
+ The `state` value orders identity, current branch, logical deletion, exact stored-path NFC status, and Metadata type. Identity is `consistent`, `documentIdMismatch`, or `namespaceMismatch`; JSON keeps the values `document-id-mismatch` and `namespace-mismatch` for the latter two states. The branch is `winner` or `conflict`; `winner` can coexist with a non-zero conflict count. `logicallyLive` and `logicallyDeleted` describe the deletion marker. `NFC` means the stored path is normalised to Unicode NFC; `nonNFC` means it is not. The type is `plain`, `newnote`, `notes`, or `unknown`, and is `notRecorded` when Metadata is absent. `consistent` confirms the identity check only; it does not establish readable or equal content.
60
+
61
+ `expected=self` means the actual document ID exactly matches the expected ID. Otherwise, the field contains the expected ID, or `?` if it was not recorded. In `paths`, `case` and `nfcPeers` report case-equivalent and NFC-equivalent path groups: `none` means no equivalent path was found, `yes` means one was found, and `yes@case:1` or `yes@nfc:1` adds the group reference when available. `otherDB` describes whether the same identity and path group is present in the other inspected source; it does not compare content. An excluded or unavailable source is `not-checked`.
62
+
63
+ In `data`, `chunks` is the total/unique/embedded Chunk-reference count, and `read` is the number of Chunk reads, not HTTP requests. When Metadata is absent, its recorded size and Chunk counts are `?`. A `?` means a value was not recorded; it is distinct from zero, missing, unreadable, and `not-checked`. The `check` line distinguishes `available`, `missing`, `unreadable`, and `not-checked` for content and Vault evidence; a recorded reason follows the status in parentheses. The optional `measure` line includes only available values: decoded content size and Vault size in bytes, `deltaContent` (decoded content minus recorded Metadata size), `deltaVault` (Vault size minus decoded content size), and `deltaMtime` (Vault modification time minus Metadata modification time) in milliseconds. Positive differences have a `+` prefix, negative differences retain `-`, and zero is `0`; these measurements describe collected evidence and do not select an authoritative version.
64
+
65
+ Unavailable Chunk entries, comparisons, case/NFC equivalence groups, and errors retain their names, reasons, and references. The collapsible details section and fenced text copy remain available for sharing the report. The compact Markdown representation does not change the JSON data or schema.
66
+
67
+ Integrity Markdown wraps the complete report in a `details` element and a fenced text block for pasting into an issue. The fence is longer than any backtick run in the report, including original names. This keeps the full evidence together without expanding every observation in the issue body.
68
+
24
69
  Hosts may pass Commonlib, plug-in, and application versions to either report projector through its optional third argument. Only those three version fields are retained. Integrity reports also retain the five identity-related settings used for the inspection; credentials and the active connection configuration remain outside the report.
@@ -18,6 +18,16 @@ The source tree is larger than the supported package surface. Consumers may impo
18
18
 
19
19
  Files elsewhere under `src` are implementation details unless a focused entry re-exports them or the compatibility inventory names them. Do not use the source layout, TypeScript path aliases, or the presence of generated declarations as evidence of a supported consumer import.
20
20
 
21
+ ## Module filenames
22
+
23
+ For new or renamed TypeScript and JavaScript source modules, start the filename
24
+ with an upper-case letter when the file contains a class with the same name,
25
+ such as `ServiceHub.ts`. Use a lower-case initial when the module primarily
26
+ exports functions, such as `fastForward.ts`. Follow the surrounding filename
27
+ style for the rest of the basename. Corresponding test files use the same
28
+ basename, such as `fastForward.unit.spec.ts`. Retain established names for
29
+ unrelated files and separate conventions for components or other file types.
30
+
21
31
  ## Service composition and state ownership
22
32
 
23
33
  Commonlib uses four related forms of composition. Choose between them by ownership and dependency direction, not merely by whether an implementation has mutable state.
@@ -29,6 +39,8 @@ Commonlib uses four related forms of composition. Choose between them by ownersh
29
39
 
30
40
  When a feature needs state, separate the component which owns that state, its transitions, and its invariants from the code which connects it to application lifecycle events and downstream effects. Give the stateful component narrow collaborators or callbacks rather than the complete Service Hub or application core. Keep application-level handler registration and host-specific presentation in the surrounding serviceFeature. A handler or effect which is part of the state contract, such as querying unresolved errors or reporting their first occurrence, may remain inside the stateful component when its input and output ports are explicit and bounded.
31
41
 
42
+ Settings storage follows the same ownership boundary. Each host selects one exact-key asynchronous `ValueStore & ValueDeleter` at its composition root and supplies it as the setting service's required `deviceValues` dependency. `setting.deviceValues` is that root; `setting.config` wraps it with the existing Vault and database-suffix scope, and the Service Hub `config` property aliases the same view. Commonlib does not discover browser globals or provide a module-global fallback. Keep existing local keys on the exact-key root, preserve configuration key names, and await Value Store operations. See [Settings lifecycle](settings-lifecycle.md#host-storage-for-device-values-and-configuration) for the key mapping and host example.
43
+
32
44
  Existing features illustrate this direction:
33
45
 
34
46
  - `targetFilter.ts` keeps each cache or readiness gate inside the factory which owns the corresponding predicate. `useTargetFilters` composes those predicates and registers them in the required order.
@@ -127,15 +139,15 @@ The compatibility event bridge delegates lifecycle and status requests to the st
127
139
 
128
140
  The physical room, WebRTC peer, and relay-socket boundaries are documented in [P2P transport lifecycle](p2p-transport-lifecycle.md). In particular, normal shutdown leaves the Trystero room without closing raw peer connections directly.
129
141
 
130
- Self-hosted LiveSync remains the principal downstream consumer. A Commonlib change is not ready for publication until the exact packed artefact has also passed the applicable LiveSync type checks, unit and integration tests, application builds, CLI E2E, and focused real-Obsidian E2E.
142
+ Self-hosted LiveSync remains a principal maintained consumer. Commonlib's normal publication gate is its own type, unit, integration, and packed-boundary checks, as described in [the release runbook](releasing.md). Run targeted downstream or real-runtime checks against the exact packed artefact when a named host-specific risk is not established by those owner tests; consumer adoption and downstream test completion are not general release prerequisites.
131
143
 
132
144
  Commonlib owner tests exercise the real implementation behind each focused result and lifecycle contract. A consumer-owned unit test may inject the smallest structural capability it uses and provide its own fake or spy when that current test needs isolation. Do not publish Vitest-specific mocks, expose private service constructors, or refactor a production boundary merely to create possible future test infrastructure. Mock and spy helpers are not a prerequisite for the LiveSync 1.0 package-boundary work; add them only with the consumer test which requires them, or after that release work.
133
145
 
134
- Prefer an object or callback injected at the host composition boundary over replacing an ESM module namespace. If a proposed focused API would require global mutation, import-order coupling, hidden construction, or private nominal types to substitute later, stop and review the production design before stabilising it. Exact-package downstream checks and focused real-runtime E2E remain responsible for proving the real package and host composition together.
146
+ Prefer an object or callback injected at the host composition boundary over replacing an ESM module namespace. If a proposed focused API would require global mutation, import-order coupling, hidden construction, or private nominal types to substitute later, stop and review the production design before stabilising it. Use exact-package downstream checks and focused real-runtime E2E for named host-specific risks which the owner tests cannot establish.
135
147
 
136
148
  Commonlib publishes the typed English messages which it owns and uses them when a host does not provide a translator. A host may inject a translator through `ServiceContext`; the full multilingual catalogue and language-selection state belong to that host and are not part of the Commonlib package.
137
149
 
138
- Keep [the maintained-host evidence](proven-in-use.md) aligned with the downstream source and gates. If a host no longer consumes a focused entry, a test is retired, or a compatibility path receives a reviewed replacement, update the consumer-facing account as part of the same maintenance rather than leaving historical adoption as a current support claim.
150
+ The [maintained-host examples and evidence](proven-in-use.md) are optional context, not a support entitlement or release or adoption gate. When that page is updated, distinguish current use, historical use, Commonlib-owned results, downstream tests, and real-runtime observations, and keep each claim within the evidence.
139
151
 
140
152
  ## Integration tests
141
153
 
@@ -1,14 +1,50 @@
1
- # Proven in maintained hosts
1
+ # Maintained-host examples and evidence
2
2
 
3
3
  Commonlib is extracted from the implementation shared by [Self-hosted LiveSync](https://github.com/vrtmrz/obsidian-livesync) and its host applications. The package is therefore exercised by a substantial maintained consumer, but it does not yet claim a separate ecosystem of independent applications or a stable end-to-end SDK.
4
4
 
5
5
  The useful evidence is host- and contract-specific. Focused Commonlib tests establish reusable result semantics; Self-hosted LiveSync tests establish how those contracts compose into the Obsidian plug-in, CLI, WebApp, and WebPeer. The Obsidian plug-in and CLI retain the strongest device and long-running synchronisation evidence. The browser applications add focused adapter and runtime tests, browser smoke tests, a cross-application P2P scenario ending at the production CLI, and public Pages smoke validation.
6
6
 
7
- The code paths below identify the maintained Self-hosted LiveSync composition points used to establish this package boundary. The exact 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. The integration descriptions must still be reviewed when the maintained downstream changes.
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
9
  ## Obsidian plug-in
10
10
 
11
- Unreleased [database diagnostics](database-diagnostics.md) tests cover preserved Usage accounting, normal-file identity classification, current conflict branches, byte comparisons, embedded Chunks, missing and unreadable content, cancellation, concurrent changes, and consistent pseudonyms. Real in-memory PouchDB tests verify pagination and conflict revision reads while retaining the original database handle. A CouchDB 3.5.0 integration test verifies GET-only access, encrypted Metadata and Chunk reads with an existing Security Seed, missing-seed failure without initialisation, and unchanged database update sequences and Seed documents. Focused tests also reject ciphertext which remains undecoded after an ID mismatch. Self-hosted LiveSync owns the serviceFeature, run-time name choice, dialogue lifecycle, and report copy and download controls. Its real Obsidian 1.12.7 test on Linux verifies cancellation before a run, both name modes, the nine-column Usage report, copy and download payloads, local integrity findings when CouchDB is unavailable, and unchanged settings, database update sequences, and Vault file names. Mobile emulation verifies the choice dialogue's viewport, safe-area, and touch-target layout; native iOS and Android behaviour remains unverified.
11
+ The unreleased V3 Rabin–Karp correction uses proportional binary thresholds,
12
+ including at values 0 and 1. Regression tests cover natural boundaries, suffix
13
+ reuse, forced caps, explicit minima, EOF tails, and large UTF-8 text. The packed
14
+ old/new CLI matrix verifies 810 file-stage digests over CouchDB, Journal, and
15
+ P2P in both directions. Separate revision tests retain conflict coverage.
16
+ The Linux Obsidian manual-setup workflow verifies value 0, eight 32 KiB binary
17
+ pieces, unchanged Metadata revision and complete local Chunk inventory after
18
+ restart, exact binary reception through Fast Fetch, and a bidirectional note
19
+ round-trip. These checks use the unpublished local candidate with LiveSync
20
+ 1.0.39; they do not establish mobile or Cloudant-service behaviour.
21
+
22
+ Unreleased Fast Fetch tests verify all current conflict leaves, including deleted
23
+ leaves, before advancing the durable stream cursor. CouchDB 3.5.0 integration
24
+ tests exercise revision ancestry retrieval and a fresh-import handoff to the
25
+ ordinary PouchDB checkpoints, followed by a batch-size change and receipt of a
26
+ new revision in LiveSync mode. Unit tests cover unimported local writes, missing
27
+ or replaced checkpoint guards, partial publication, and exclusion of persisted
28
+ resume cursors. A controlled connection delay also verifies that disposing the
29
+ resource during preparation closes the connection when it arrives. Rebuilder
30
+ tests also delay and reject device-local checkpoint
31
+ writes, verifying that handoff, completion, and checkpoint removal wait for
32
+ successful persistence. The handoff requires an empty local database, suspended local
33
+ writers, and a remote database which is not replaced during the operation.
34
+ These package-owned tests do not establish arbitrary-time fast-forwarding,
35
+ On Demand repair, or real Obsidian runtime behaviour.
36
+
37
+ The unreleased joined-device resource and UI-command work adds instance-owned typed UI handlers, legacy-compatible device projections, and device-record removal. Focused unit tests cover missing records, preservation of other devices and unknown fields, self-removal rejection, conflict retries, unsupported writes, verification failures, and handler disposal. CouchDB 3.5.0 integration tests verify that reading or forgetting never creates a missing database, and verify removal and preservation while retaining a fixture which demonstrates that local documents accept stale revisions. Object Storage integration tests against RustFS verify conditional removal and rejection of stale ETags. These checks do not make concurrent CouchDB updates atomic.
38
+
39
+ Before integration with Commonlib 0.2.0, a local packed candidate based on 0.1.44 passed Self-hosted LiveSync 1.0.39 checks, unit tests, and production build. Its focused real-Obsidian 1.12.7 scenario on Linux verifies the settings entry, self-first and locked-out records, current metadata, manual refresh, confirmed removal, and preservation of other records and remote state. Mobile emulation verifies the command-palette entry, scrolling, viewport and safe-area bounds, and touch targets. Self-hosted LiveSync owns the dialogue and advisory version Notices. These results establish the tested build's behaviour; publication and native iOS and Android behaviour remain unverified.
40
+
41
+ Unreleased remote-inspection tests compare individual and bulk reads against CouchDB 3.5.0. A fixture with 65 Metadata documents and 130 Chunks produces identical integrity reports while reducing HTTP requests from 198 to 8. Encrypted bulk reads preserve current conflicts, exact revision access, missing-document evidence, and unchanged database and Security Seed state. Unit tests cover bounded GET batches, encoded URL limits, per-document failures, cancellation, and explicitly excluded remote coverage. These counts describe the fixture; they do not establish large-Vault elapsed-time improvements.
42
+
43
+ Unreleased [database diagnostics](database-diagnostics.md) tests cover preserved Usage accounting, normal-file identity classification, current conflict branches, byte comparisons, embedded Chunks, missing and unreadable content, cancellation, concurrent changes, and consistent pseudonyms. Real in-memory PouchDB tests verify pagination and conflict revision reads while retaining the original database handle. A CouchDB 3.5.0 integration test verifies GET-only access, encrypted Metadata and Chunk reads with an existing Security Seed, missing-seed failure without initialisation, and unchanged database update sequences and Seed documents. Focused tests also reject ciphertext which remains undecoded after an ID mismatch. Commonlib owns the result contract and compact Integrity Markdown formatter; Self-hosted LiveSync owns the serviceFeature, run-time name choice, dialogue lifecycle, and report copy and download controls. Its real Obsidian 1.12.7 test on Linux verifies cancellation before a run, both name modes, the nine-column Usage report, copy and download payloads, local integrity findings when CouchDB is unavailable, and unchanged settings, database update sequences, and Vault file names. Mobile emulation verifies the choice dialogue's viewport, safe-area, and touch-target layout; native iOS and Android behaviour remains unverified.
44
+
45
+ The Commonlib `/diagnostics` entry provides a path-token parser and a mapper which can reuse a report's public salt to reproduce path, document, revision, and Chunk pseudonyms for a targeted follow-up. Its Usage progress contract separates revision reading from cancellable accounting. Self-hosted LiveSync owns the current-Vault lookup, local-only candidate display, follow-up choice, and dialogue lifecycle; the public salt permits guessed-path checks, while older ordinal pseudonyms cannot be looked up.
46
+
47
+ Self-hosted LiveSync's real Obsidian 1.12.7 test on Linux also verifies local lookup, selection between distinct document IDs for one path, and a follow-up report which reuses the selected ID and original salt. It checks that compact Markdown retains every JSON observation reference and pseudonym, and that copy and save preserve the complete Markdown output. Desktop and mobile-mode viewports verify the candidate list, report controls, and horizontal overflow. These host tests complement the package contracts; they do not establish native iOS or Android behaviour.
12
48
 
13
49
  Unreleased content-evidence tests replicate 99, 100, and 599 updates between real in-memory PouchDB databases, including a receiver with `revs_limit: 100`. They verify unchanged reflection after the recorded revision is pruned, including a recreated handler, and preserve same-size edits, intentional reverts, and records without valid content evidence. Separate tests verify legacy upgrades and changes during hashing. These are package-owned tests; they do not establish Windows, mobile, or remote CouchDB behaviour.
14
50
 
@@ -22,10 +58,14 @@ The CouchDB connection fix bypasses browser HTTP caching so encrypted replicatio
22
58
 
23
59
  Unreleased settings tests verify that Object Storage-only credentials, JWT values, and authentication headers reach the host persistence handler only after connection encryption, and that unavailable or failed required encryption preserves the previous persisted settings. The focused `/settings` entry also supplies conditional whole-profile Markdown preparation and import preservation. A clean packed consumer checks the exhaustive property policy and prepared output types with an ES2018 compile fixture. Commonlib owns these result and type contracts; Self-hosted LiveSync owns Markdown file writes, its settings interface, and restoration through a real Obsidian restart.
24
60
 
61
+ The setting-service tests also cover the injected device-value boundary: exact local keys remain unchanged, the existing Vault and database-suffix configuration key layout is preserved, and separately injected stores remain isolated. These are Commonlib-owned asynchronous store contracts. Each host owns selecting its persistent adapter and verifying host storage across restart; this evidence does not claim additional real-runtime coverage.
62
+
25
63
  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.
26
64
 
27
65
  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.
28
66
 
67
+ The EntryManager selection tests distinguish Hidden File Sync documents by their original `i:` prefix. They check that the normal-file allow-list applies to ordinary paths while prefixed hidden documents remain eligible, that the normal-file ignore-list still excludes matching hidden documents, and that hidden-file disablement and the Customisation Sync exceptions retain their behaviour. Hidden File Sync owns its additional target and ignore patterns in Self-hosted LiveSync; storage reflection and native Obsidian behaviour remain downstream verification boundaries.
68
+
29
69
  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.
30
70
 
31
71
  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.
@@ -176,6 +216,6 @@ A new integration should start with the focused entries, not by reproducing Self
176
216
 
177
217
  Use the named consumer paths as integration examples, while retaining the ownership and limitations stated in the [root README](../readme.md), [storage guide](platform-storage.md), [standard-I/O guide](platform-standard-io.md), and [remote configuration profile guide](remote-configurations.md).
178
218
 
179
- ## Maintenance rule
219
+ ## Scope and maintenance
180
220
 
181
- This page records current evidence rather than historical adoption. When a host stops using an entry point, a verification path is retired, or a compatibility import moves to a focused contract, update the description and links instead of retaining a stronger claim than the maintained consumer establishes.
221
+ 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.
package/docs/releasing.md CHANGED
@@ -2,16 +2,19 @@
2
2
 
3
3
  This document is the developer and maintainer runbook for preparing and publishing `@vrtmrz/livesync-commonlib`. Package-consumer guidance belongs in the root README.
4
4
 
5
- ## Release gate
5
+ ## Commonlib-owned release checks
6
6
 
7
- Run the complete owner gate from a clean checkout:
7
+ Run the normal owner checks from a clean checkout:
8
8
 
9
9
  ```bash
10
10
  npm ci
11
11
  npm run verify:package
12
+ npm run test:integration:managed
12
13
  ```
13
14
 
14
- The gate type-checks Commonlib, runs its complete unit suite, verifies the source boundary, builds the distributable package, installs its exact tarball into a clean consumer, and bundles representative browser and Node entry points. The source `package.json` remains private to prevent publishing the repository root. Only the generated `.package` directory is publishable, and its manifest defaults to public publication on the `next` dist-tag.
15
+ Together these checks type-check Commonlib, run its unit and integration suites, verify the source boundary, build the distributable package, install its exact tarball into a clean consumer, and bundle representative browser and Node entry points. These Commonlib-owned checks are the normal publication criteria. The source `package.json` remains private to prevent publishing the repository root. Only the generated `.package` directory is publishable, and its manifest defaults to public publication on the `next` dist-tag.
16
+
17
+ Downstream or real-runtime checks are appropriate when a named host-specific risk is not established by the owner tests; run those checks against the exact packed artefact and record the risk and result. LiveSync adoption and downstream validation are not general publication prerequisites. The [maintained-host examples and evidence](proven-in-use.md) page is optional context, not a release or update gate.
15
18
 
16
19
  The package builder normalises generated directories to `0755`, ordinary files to `0644`, and declared `bin` targets to `0755` before validation. `test:package` uses a restrictive umask and verifies the packed modes, so local and hosted builds do not differ only because their caller environments use different umasks.
17
20
 
@@ -29,13 +32,17 @@ npm run verify:package
29
32
 
30
33
  Inspect the lockfile diff before committing it. A dependency-only maintenance change must not alter the source package version, and lockfile normalisation must not be described as a package upgrade when resolved versions and integrity values are unchanged. When the workflow selects a newer reviewed npm CLI, update this example in the same change.
31
34
 
32
- Before publication, run the downstream workflow against an exact Self-hosted LiveSync ref which already consumes the package. The workflow installs the tarball produced from the selected Commonlib commit, then runs LiveSync type checks, unit tests, plug-in and application builds, and CLI E2E. Real Obsidian E2E remains local-only and is required when the changed boundary affects actual plug-in composition, storage, UI, or platform behaviour.
35
+ When a named host-specific risk is not established by the Commonlib owner checks, run the relevant downstream workflow against an exact Self-hosted LiveSync ref which consumes the package. It installs the tarball produced from the selected Commonlib commit and runs LiveSync type checks, unit tests, plug-in and application builds, and CLI E2E. Real Obsidian E2E remains local-only and is appropriate when the named risk concerns actual plug-in composition, storage, UI, or platform behaviour. These checks are conditional on the risk; LiveSync adoption is not a general release prerequisite.
36
+
37
+ ## Version compatibility policy
38
+
39
+ The Commonlib 0.2 policy begins with 0.2.0 and does not retroactively change compatibility expectations for published 0.1.x versions. Within 0.2.x, preserve published APIs, types, behaviour, supported persisted data, and exported `compat/*` paths. Intentional breaking changes belong in 0.3.0. Consumers may declare a range such as `^0.2.0`; lockfiles and `npm ci` remain the reproducible install path.
33
40
 
34
41
  ## Preparing a release
35
42
 
36
- Choose the version explicitly. Prefer a `-next.N` prerelease, such as `0.1.32-next.0`, when registry installation must be validated before the stable version. Reserve `-rc.N` for an explicitly chosen release candidate. Package-proof versions are local artefacts and cannot be staged.
43
+ 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.
37
44
 
38
- Prepare both stable releases and pre-releases on a reviewed pull request based on `main`. A pre-release may be staged from the exact reviewed pull-request branch commit so that the registry artefact can be validated in Self-hosted LiveSync before the Commonlib change is merged. A stable release must be staged only after its exact reviewed release commit is present on `main`.
45
+ Prepare stable releases and any optional prereleases on a reviewed pull request based on `main`. An optional prerelease may be staged from the exact reviewed pull-request branch commit. A stable release must be staged only after its exact reviewed release commit is present on `main`.
39
46
 
40
47
  ```bash
41
48
  npm ci
@@ -44,7 +51,7 @@ npm run verify:package
44
51
  npm publish --dry-run .package --tag next --access public
45
52
  ```
46
53
 
47
- Review `package.json`, `package-lock.json`, the generated manifest, the tarball contents, the test results, and the downstream evidence. Commit only the source manifest and lockfile for the version change; `.package`, `.package-consumer`, and `artifacts` are generated and ignored. Push and open a release pull request only after the usual user checkpoint. Keep a pre-release pull request in draft while its exact registry artefact is validated in Self-hosted LiveSync. Merge and stable publication remain separate later checkpoints.
54
+ Review `package.json`, `package-lock.json`, the generated manifest, the tarball contents, and the Commonlib-owned test results. Add downstream evidence when a named host-specific risk requires it. Commit only the source manifest and lockfile for the version change; `.package`, `.package-consumer`, and `artifacts` are generated and ignored. Push and open a release pull request only after the usual user checkpoint. Keep a pull request in draft while a specifically planned downstream check is in progress; that check is not required when no such risk remains. Merge and publication remain separate later checkpoints.
48
55
 
49
56
  ## Historical initial npm bootstrap
50
57
 
@@ -58,9 +65,9 @@ npm run verify:package
58
65
  npm publish .package --tag next --access public
59
66
  ```
60
67
 
61
- Confirm the authenticated npm account, `@vrtmrz` scope ownership, package name, version, tarball checksum, packed contents, source commit, and target tag immediately before publication. Treat bootstrap publication as a separate user-authorised operation. npm may assign `latest` to the first published version even when `next` is requested; leave the immutable version in place and replace `latest` only after a stable release has passed consumer validation.
68
+ Confirm the authenticated npm account, `@vrtmrz` scope ownership, package name, version, tarball checksum, packed contents, source commit, and target tag immediately before publication. Treat bootstrap publication as a separate user-authorised operation. npm may assign `latest` to the first published version even when `next` is requested; leave the immutable version in place and replace `latest` only after a stable release has passed the Commonlib owner checks and any applicable targeted host checks.
62
69
 
63
- Bootstrap publication was the one historical exception which used direct `npm publish`. Do not repeat that operation for routine releases. Current pre-releases use protected staged publishing and may select an exact reviewed branch commit; stable releases use an exact `main` commit. If validation fails, leave the published version immutable and prepare a new pre-release version.
70
+ Bootstrap publication was the one historical exception which used direct `npm publish`. Do not repeat that operation for routine releases. Optional prereleases use protected staged publishing and may select an exact reviewed branch commit; stable releases use an exact `main` commit. If the owner checks or an applicable targeted host check fails, leave the published version immutable and prepare a new version.
64
71
 
65
72
  ## Trusted staged publishing
66
73
 
@@ -73,9 +80,9 @@ After bootstrap, configure the npm Trusted Publisher for:
73
80
 
74
81
  Protect the GitHub `npm` environment with a required reviewer and permit only `main`. The trusted workflow definition always runs from `main`. A pre-release may package an exact commit from a reviewed draft branch, while a stable release also requires the package source and workflow-triggering commit to be the exact current `main` commit. The workflow confirms that the selected source branch still points to the requested full commit SHA, checks out that SHA, runs `verify:package`, validates the requested version and confirmation text, packs the reviewed output, records its checksum, and passes the same tarball to the protected staging job.
75
82
 
76
- npm's automatic provenance identifies the `main` commit which triggered the trusted workflow. For a pre-release selected from a draft branch, this identifies the trusted workflow source rather than the packaged source commit. Record and verify the separate `source_ref`, exact package SHA, and tarball checksum before approving the staged version. This provenance distinction is accepted for an immutable pre-release used to validate the consumer before merge. A stable release requires the workflow and package source to be the same exact `main` commit.
83
+ npm's automatic provenance identifies the `main` commit which triggered the trusted workflow. For an optional prerelease selected from a draft branch, this identifies the trusted workflow source rather than the packaged source commit. Record and verify the separate `source_ref`, exact package SHA, and tarball checksum before approving the staged version. This provenance distinction is accepted for an immutable prerelease when a consumer check is planned before merge. A stable release requires the workflow and package source to be the same exact `main` commit.
77
84
 
78
- Dispatch a pre-release from its exact reviewed draft branch commit:
85
+ When using an optional pre-release, dispatch it from its exact reviewed draft branch commit:
79
86
 
80
87
  ```bash
81
88
  source_ref=separate-setting-lifecycle
@@ -91,11 +98,11 @@ gh workflow run publish-npm.yml \
91
98
 
92
99
  For a stable release, use `source_ref=main`. The workflow rejects a stable release selected from another branch, rejects a stable release without its trusted workflow commit, and requires the workflow-triggering SHA to equal the packaged `main` SHA. The workflow dispatch itself uses `--ref main` for every release, so an unmerged branch cannot change the trusted publication job or acquire access to the `npm` environment.
93
100
 
94
- The workflow always stages to `next`. Inspect the staged package name, version, access, dist-tag, provenance, checksum, files, selected source branch, and source commit before approving it through npm. Approval and later promotion to `latest` are separate user-authorised operations. Keep the Commonlib and Self-hosted LiveSync consumer pull requests in draft while validating the exact registry pre-release. If validation fails, leave that published version immutable and prepare a new pre-release. After successful consumer validation, merge Commonlib only through its separate maintainer gate. Validate a stable release in Self-hosted LiveSync before promoting it to `latest`.
101
+ The workflow always stages to `next`. Inspect the staged package name, version, access, dist-tag, provenance, checksum, files, selected source branch, and source commit before approving publication to npm. After approval publishes the version, fetch that exact registry version and compare its SHA-256, package name and version, and provenance with the reviewed staged artefact and source revision; confirm that `next` points to that version. Install the fetched registry artefact in a clean consumer and run the relevant package checks before requesting promotion. Stage approval and later promotion to `latest` are separate user-authorised operations. Promote the same version only after those registry checks pass and any applicable targeted host checks are complete. If a check fails, leave the published version immutable and prepare a new version. Keep consumer pull requests in draft only while a specifically planned host check is in progress; consumer adoption is not a precondition for Commonlib merge or release.
95
102
 
96
103
  ## Publishing a GitHub Release
97
104
 
98
- Create a GitHub Release for each stable Commonlib release after the exact registry artefact has passed downstream validation and the version has been promoted to `latest`. Target the exact `main` commit used to build the published package.
105
+ Create a GitHub Release for each stable Commonlib release after the exact registry artefact has passed the Commonlib owner checks and the version has been promoted to `latest`. Complete any applicable targeted host checks before release. Target the exact `main` commit used to build the published package.
99
106
 
100
107
  Protect the GitHub `github-release` environment with a required reviewer and permit only `main`. The manually dispatched workflow first verifies the release with read-only repository access. Only its protected publication job receives `contents: write` access.
101
108
 
@@ -18,7 +18,7 @@ import { createNewVaultSettings } from "@vrtmrz/livesync-commonlib/settings";
18
18
  const initialSettings = createNewVaultSettings();
19
19
  ```
20
20
 
21
- The recommended base currently selects a 50 MB maximum synchronised file size, Rabin–Karp chunk splitting, Plug-in Sync V2, case-insensitive file-name handling, and E2EE V2. Chunk revisions are always derived from their content; the obsolete `doNotUseFixedRevisionForChunks` stored key is retained only for compatibility and is not a recommendation or tweak. The recommended base does not enable synchronisation or encryption on behalf of the user.
21
+ The recommended base currently selects a 50 MB maximum synchronised file size, a `customChunkSize` value of 0, Rabin–Karp chunk splitting, Plug-in Sync V2, case-insensitive file-name handling, and E2EE V2. Chunk revisions are always derived from their content; the obsolete `doNotUseFixedRevisionForChunks` stored key is retained only for compatibility and is not a recommendation or tweak. The recommended base does not enable synchronisation or encryption on behalf of the user.
22
22
 
23
23
  Compared with the conservative stored-setting fallbacks, the current new-Vault object has exactly two semantic differences:
24
24
 
@@ -27,15 +27,23 @@ Compared with the conservative stored-setting fallbacks, the current new-Vault o
27
27
  | `usePluginSyncV2` | `false` | `true` |
28
28
  | `handleFilenameCaseSensitive` | normalised from the legacy absent value to `false` | `false` |
29
29
 
30
- The other headline recommendations are already the conservative fallbacks: `syncMaxSizeInMB` is 50, `chunkSplitterVersion` is `v3-rabin-karp`, and `E2EEAlgorithm` is `v2`. Data Compression, Eden, V1 dynamic iteration, the legacy IndexedDB adapter, Hidden File Sync, and automatic synchronisation remain disabled when their stored values are absent. Explicit stored values take precedence.
30
+ The other headline recommendations are already the conservative fallbacks: `syncMaxSizeInMB` is 50, `customChunkSize` is 0, `chunkSplitterVersion` is `v3-rabin-karp`, and `E2EEAlgorithm` is `v2`. Data Compression, Eden, V1 dynamic iteration, the legacy IndexedDB adapter, Hidden File Sync, and automatic synchronisation remain disabled when their stored values are absent. Explicit stored values take precedence.
31
31
 
32
- Apply a remote-specific preferred object only while configuring that remote. Do not merge it into an existing stored configuration merely because the remote type can be inferred. The self-hosted CouchDB profile uses a chunk-size coefficient of 60, matching the Doctor check for Rabin–Karp databases; Cloudant retains its service-specific value of 0.
32
+ Apply a remote-specific preferred object only while configuring that remote. Do not merge it into an existing stored configuration merely because the remote type can be inferred. Cloudant, self-hosted CouchDB, and Journal Sync setup all use the common `customChunkSize` value of 0. Their unrelated request and bulk settings remain service-specific. The current Doctor regulation no longer recommends changing the value to 60 universally, and existing explicit values remain valid.
33
+
34
+ The new Doctor rule set inherits 1.0.33 and withdraws the Chunk-size rule with
35
+ `customChunkSize: undefined`. Historical regulations keep their original rules.
36
+ This removes the recommendation, rather than deleting a stored setting or
37
+ forcing it to 0. Its consultation version deliberately remains 1.0.33: removing
38
+ a recommendation does not require users to review unchanged recommendations
39
+ again. Existing dismissals remain effective; an explicit forced rescan still
40
+ checks the remaining rules.
33
41
 
34
42
  | Explicitly selected remote | `customChunkSize` | `concurrencyOfReadChunksOnline` | `minimumIntervalOfReadChunksOnline` |
35
43
  | --- | ---: | ---: | ---: |
36
44
  | Cloudant | 0 | 100 | 333 |
37
- | Self-hosted CouchDB | 60 | 30 | 25 |
38
- | Object Storage | 10 | 30 | 25 |
45
+ | Self-hosted CouchDB | 0 | 30 | 25 |
46
+ | Journal Sync (Object Storage) | 0 | 30 | 25 |
39
47
 
40
48
  These are setup-time recommendations, not upgrade migrations. Selecting or detecting a remote does not apply them to an existing configuration unless the person is actively configuring that remote.
41
49
 
@@ -72,6 +80,30 @@ Two other values deliberately remain unset until their owning lifecycle supplies
72
80
 
73
81
  The standard Commonlib `SettingService` performs this preparation automatically. Hosts which use that service can inspect `getSettingsMigrationState()` after `loadSettings()` instead of calling the function themselves.
74
82
 
83
+ ## Host storage for device values and configuration
84
+
85
+ The host selects an asynchronous `ValueStore & ValueDeleter` for each application instance and injects it into the setting service as `deviceValues`. Commonlib does not discover `globalThis.localStorage`, create module-global storage, or fall back to another store. `setting.deviceValues` exposes the injected exact-key root. `setting.config` is an asynchronous view over the same root, scoped to the current Vault name and `additionalSuffixOfDatabaseName`; the Service Hub `config` property refers to that same view.
86
+
87
+ For an existing Web Storage layout, pass the selected storage object explicitly and use an empty adapter prefix so the service can address existing raw keys:
88
+
89
+ ```ts
90
+ import { createWebStorageValueStore } from "@vrtmrz/value-store/web-storage";
91
+
92
+ const deviceValues = createWebStorageValueStore(window.localStorage, { prefix: "" });
93
+ // Supply deviceValues as the setting service's required composition dependency.
94
+ ```
95
+
96
+ Use `deviceValues` for exact device-local keys, including existing keys such as `ls-setting-passphrase`. Use `config` for logical configuration keys; the service retains the established Vault and database-suffix key format. For example, the `checkpoint` key for Vault `notes` remains `notes--checkpoint` with an empty suffix and `notes-team-checkpoint` with suffix `team`. Keep the existing key names and await every read, write, and deletion:
97
+
98
+ ```ts
99
+ const passphrase = await setting.deviceValues.getValue("ls-setting-passphrase");
100
+ const checkpoint = await setting.config.getValue("checkpoint");
101
+ await setting.config.setValue("checkpoint", "revision-42");
102
+ await setting.config.delete("checkpoint");
103
+ ```
104
+
105
+ `getValue` returns `null` when a key is absent. Use `getObject` and `setObject` for values stored as JSON; Commonlib does not automatically reinterpret old strings or migrate entries between the exact-key root and the scoped view.
106
+
75
107
  ## Preparing settings for persistence and Markdown
76
108
 
77
109
  The existing `SettingService` provides `changeConfigurationEncryption(store, passphrase?)` for hosts which edit the configuration encryption mode or device-local custom key. Await it before marking those edits as saved. It prepares one wrapper key for connection credentials, the E2EE passphrase, remote profile URIs, and the independent ID key, and serialises the change with ordinary settings saves. It rejects empty keys and unreadable existing protected items. A failed write attempts to restore the previous device key and does not send a success event. The device key and settings document use separate host writes, so this is not a guarantee of rollback after process termination or an uncertain persistence error.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vrtmrz/livesync-commonlib",
3
- "version": "0.1.43",
3
+ "version": "0.2.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",
@@ -92,6 +92,11 @@
92
92
  "import": "./dist/setupUri.js",
93
93
  "default": "./dist/setupUri.js"
94
94
  },
95
+ "./ui-commands": {
96
+ "types": "./dist/uiCommands.d.ts",
97
+ "import": "./dist/uiCommands.js",
98
+ "default": "./dist/uiCommands.js"
99
+ },
95
100
  "./compat/API/processSetting": {
96
101
  "types": "./dist/API/processSetting.d.ts",
97
102
  "import": "./dist/API/processSetting.js",
@@ -457,11 +462,6 @@
457
462
  "import": "./dist/services/base/AppLifecycleService.js",
458
463
  "default": "./dist/services/base/AppLifecycleService.js"
459
464
  },
460
- "./compat/services/base/ConfigService": {
461
- "types": "./dist/services/base/ConfigService.d.ts",
462
- "import": "./dist/services/base/ConfigService.js",
463
- "default": "./dist/services/base/ConfigService.js"
464
- },
465
465
  "./compat/services/base/ControlService": {
466
466
  "types": "./dist/services/base/ControlService.d.ts",
467
467
  "import": "./dist/services/base/ControlService.js",
@@ -522,11 +522,6 @@
522
522
  "import": "./dist/services/implements/base/UIService.js",
523
523
  "default": "./dist/services/implements/base/UIService.js"
524
524
  },
525
- "./compat/services/implements/browser/ConfigServiceBrowserCompat": {
526
- "types": "./dist/services/implements/browser/ConfigServiceBrowserCompat.d.ts",
527
- "import": "./dist/services/implements/browser/ConfigServiceBrowserCompat.js",
528
- "default": "./dist/services/implements/browser/ConfigServiceBrowserCompat.js"
529
- },
530
525
  "./compat/services/implements/headless/HeadlessAPIService": {
531
526
  "types": "./dist/services/implements/headless/HeadlessAPIService.d.ts",
532
527
  "import": "./dist/services/implements/headless/HeadlessAPIService.js",
@@ -675,6 +670,9 @@
675
670
  "setup-uri": [
676
671
  "dist/setupUri.d.ts"
677
672
  ],
673
+ "ui-commands": [
674
+ "dist/uiCommands.d.ts"
675
+ ],
678
676
  "compat/API/processSetting": [
679
677
  "dist/API/processSetting.d.ts"
680
678
  ],
@@ -894,9 +892,6 @@
894
892
  "compat/services/base/AppLifecycleService": [
895
893
  "dist/services/base/AppLifecycleService.d.ts"
896
894
  ],
897
- "compat/services/base/ConfigService": [
898
- "dist/services/base/ConfigService.d.ts"
899
- ],
900
895
  "compat/services/base/ControlService": [
901
896
  "dist/services/base/ControlService.d.ts"
902
897
  ],
@@ -933,9 +928,6 @@
933
928
  "compat/services/implements/base/UIService": [
934
929
  "dist/services/implements/base/UIService.d.ts"
935
930
  ],
936
- "compat/services/implements/browser/ConfigServiceBrowserCompat": [
937
- "dist/services/implements/browser/ConfigServiceBrowserCompat.d.ts"
938
- ],
939
931
  "compat/services/implements/headless/HeadlessAPIService": [
940
932
  "dist/services/implements/headless/HeadlessAPIService.d.ts"
941
933
  ],
@@ -1005,6 +997,7 @@
1005
997
  }
1006
998
  },
1007
999
  "dependencies": {
1000
+ "@aws-crypto/sha256-js": "5.2.0",
1008
1001
  "@aws-sdk/client-s3": "^3.808.0",
1009
1002
  "@smithy/fetch-http-handler": "^5.3.10",
1010
1003
  "@smithy/md5-js": "^4.2.9",
@@ -1012,6 +1005,7 @@
1012
1005
  "@smithy/types": "^4.14.3",
1013
1006
  "@smithy/util-retry": "^4.4.5",
1014
1007
  "@trystero-p2p/nostr": "0.25.3",
1008
+ "@vrtmrz/value-store": "0.1.0",
1015
1009
  "diff-match-patch": "^1.0.5",
1016
1010
  "events": "^3.3.0",
1017
1011
  "fflate": "^0.8.2",
@@ -1023,9 +1017,11 @@
1023
1017
  "pouchdb-adapter-idb": "^9.0.0",
1024
1018
  "pouchdb-adapter-indexeddb": "^9.0.0",
1025
1019
  "pouchdb-adapter-memory": "^9.0.0",
1020
+ "pouchdb-checkpointer": "9.0.0",
1026
1021
  "pouchdb-core": "^9.0.0",
1027
1022
  "pouchdb-errors": "^9.0.0",
1028
1023
  "pouchdb-find": "^9.0.0",
1024
+ "pouchdb-generate-replication-id": "9.0.0",
1029
1025
  "pouchdb-mapreduce": "^9.0.0",
1030
1026
  "pouchdb-merge": "^9.0.0",
1031
1027
  "pouchdb-replication": "^9.0.0",
@@ -1,7 +0,0 @@
1
- import type { IConfigService } from "./IService.js";
2
- import { ServiceBase, type ServiceContext } from "./ServiceBase.js";
3
- export declare abstract class ConfigService<T extends ServiceContext = ServiceContext> extends ServiceBase<T> implements IConfigService {
4
- abstract getSmallConfig(key: string): string | null;
5
- abstract setSmallConfig(key: string, value: string): void;
6
- abstract deleteSmallConfig(key: string): void;
7
- }
@@ -1,6 +0,0 @@
1
- import { ServiceBase } from "./ServiceBase.js";
2
- class ConfigService extends ServiceBase {
3
- }
4
- export {
5
- ConfigService
6
- };
@@ -1,16 +0,0 @@
1
- import { ConfigService } from "../../base/ConfigService.js";
2
- import type { IAPIService, ISettingService } from "../../base/IService.js";
3
- import type { ServiceContext } from "../../base/ServiceBase.js";
4
- import { createInstanceLogFunction } from "../../lib/logUtils.js";
5
- export interface ConfigServiceBrowserCompatDependencies {
6
- settingService: ISettingService;
7
- APIService: IAPIService;
8
- }
9
- export declare class ConfigServiceBrowserCompat<T extends ServiceContext = ServiceContext> extends ConfigService<T> {
10
- private _settingService;
11
- _log: ReturnType<typeof createInstanceLogFunction>;
12
- constructor(context: T, dependencies: ConfigServiceBrowserCompatDependencies);
13
- getSmallConfig(key: string): string;
14
- setSmallConfig(key: string, value: string): void;
15
- deleteSmallConfig(key: string): void;
16
- }
@@ -1,23 +0,0 @@
1
- import { ConfigService } from "../../base/ConfigService.js";
2
- import { createInstanceLogFunction } from "../../lib/logUtils.js";
3
- class ConfigServiceBrowserCompat extends ConfigService {
4
- _settingService;
5
- _log;
6
- constructor(context, dependencies) {
7
- super(context);
8
- this._settingService = dependencies.settingService;
9
- this._log = createInstanceLogFunction("ConfigService", dependencies.APIService);
10
- }
11
- getSmallConfig(key) {
12
- return this._settingService.getSmallConfig(key);
13
- }
14
- setSmallConfig(key, value) {
15
- return this._settingService.setSmallConfig(key, value);
16
- }
17
- deleteSmallConfig(key) {
18
- return this._settingService.deleteSmallConfig(key);
19
- }
20
- }
21
- export {
22
- ConfigServiceBrowserCompat
23
- };