@vrtmrz/livesync-commonlib 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -0
- package/dist/API/processSetting.d.ts +2 -0
- package/dist/common/models/setting.const.defaults.js +2 -0
- package/dist/common/models/setting.const.qr.js +3 -0
- package/dist/common/models/setting.policy.d.ts +8 -0
- package/dist/common/models/setting.policy.js +2 -0
- package/dist/common/models/setting.type.d.ts +6 -0
- package/dist/common/models/shared.definition.d.ts +20 -0
- package/dist/common/models/tweak.definition.d.ts +2 -0
- package/dist/common/settingConstants.d.ts +2 -0
- package/dist/common/settingConstants.js +10 -2
- package/dist/interfaces/FileHandler.d.ts +7 -1
- package/dist/interfaces/StorageAccess.d.ts +2 -0
- package/dist/interfaces/StorageEventManager.d.ts +7 -0
- package/dist/interfaces/StorageEventManager.js +11 -0
- package/dist/managers/StorageEventManager.d.ts +20 -10
- package/dist/managers/StorageEventManager.js +268 -189
- package/dist/replication/LiveSyncAbstractReplicator.d.ts +2 -0
- package/dist/replication/LiveSyncAbstractReplicator.js +5 -2
- package/dist/replication/couchdb/LiveSyncReplicator.d.ts +6 -0
- package/dist/replication/couchdb/LiveSyncReplicator.js +39 -2
- package/dist/replication/couchdb/replicationProgress.d.ts +6 -0
- package/dist/replication/couchdb/replicationProgress.js +105 -0
- package/dist/replication/index.d.ts +1 -0
- package/dist/replication/trystero/TrysteroReplicator.d.ts +4 -0
- package/dist/serviceFeatures/offlineScanner.d.ts +4 -4
- package/dist/serviceFeatures/offlineScanner.js +30 -13
- package/dist/serviceFeatures/prepareDatabaseForUse.d.ts +3 -2
- package/dist/serviceFeatures/prepareDatabaseForUse.js +5 -4
- package/dist/serviceModules/ServiceFileAccessBase.d.ts +1 -0
- package/dist/serviceModules/ServiceFileAccessBase.js +8 -0
- package/dist/serviceModules/ServiceFileHandlerBase.d.ts +9 -5
- package/dist/serviceModules/ServiceFileHandlerBase.js +96 -38
- package/dist/services/base/AppLifecycleService.js +1 -1
- package/dist/services/base/ControlService.js +6 -2
- package/dist/services/base/DatabaseEventService.d.ts +1 -1
- package/dist/services/base/FileProcessingService.d.ts +7 -1
- package/dist/services/base/FileProcessingService.js +9 -1
- package/dist/services/base/IService.d.ts +12 -4
- package/dist/services/base/ReplicatorService.d.ts +1 -0
- package/dist/services/base/VaultScanResult.d.ts +5 -0
- package/dist/services/base/VaultService.d.ts +1 -1
- package/dist/services/lib/HandlerUtils.d.ts +60 -0
- package/dist/services/lib/HandlerUtils.js +46 -0
- package/dist/worker/bgWorker.js +1 -1
- package/docs/offline-scanner.md +23 -13
- package/docs/settings-lifecycle.md +2 -0
- package/docs/storage-events-and-reflection.md +113 -10
- package/package.json +2 -2
package/docs/offline-scanner.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
date: 2026-
|
|
3
|
-
commonlib-version: "0.1
|
|
4
|
-
self-hosted-livesync-version: "1.0.
|
|
2
|
+
date: 2026-10-26
|
|
3
|
+
commonlib-version: "0.2.1"
|
|
4
|
+
self-hosted-livesync-version: "1.0.40"
|
|
5
5
|
status: unreleased
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -29,17 +29,25 @@ The tables below cover only paths which remain after identity validation, the ho
|
|
|
29
29
|
6. after the first permitted invocation reaches its aggregate-result boundary, record `initialized = true`; and
|
|
30
30
|
7. return the aggregate pair result under the caller's selected handling of file failures.
|
|
31
31
|
|
|
32
|
+
### Startup content checking
|
|
33
|
+
|
|
34
|
+
`VaultScanOptions.strictContentCheck` is optional. `initialiseDatabase` accepts `VaultScanOptions` as its optional fifth argument, and `scanVault` accepts it as its optional fourth argument and forwards it. `performFullScan` exposes the same option through `FullScanOptions`. Omitting the option, or setting it to `true`, retains strict content comparison. Only an explicit `false` permits the scanner to pass the `canSkipUnchangedFile` hint to the file handler. Commonlib does not read a host setting or global storage; a host may select this option from a per-installation startup preference.
|
|
35
|
+
|
|
36
|
+
The hint is considered only when the normal freshness comparison reaches `EVEN`, replacing the additional body comparison at that point. It never bypasses `BASE_IS_NEW` or `TARGET_IS_NEW`; those branches retain their timestamp-directed reflection and last-seen bookkeeping. Inside `EVEN`, the hint is allowed only for a tracked file whose raw modification time exactly equals the recorded provenance mtime (not merely a value in the same platform comparison bucket), whose byte size matches the recorded value, whose tracked revision is the current live database revision, and which has no live conflicts or related queued, running, or failed file work. If tracking evidence is missing, or the host cannot establish pending-work state, the existing strict byte-comparison path remains. When the hint is accepted, the pair result is `SKIPPED`; it does not compare or claim equal bytes, write provenance, or introduce Commonlib persistent state. Incoming content, conflict handling, and logical-deletion protection retain their existing rules.
|
|
37
|
+
|
|
38
|
+
A local edit which preserves the tracked modification time and byte size may be missed by a scan using explicit `false`. Existing same-stat edit checks exercise the omitted-option strict path.
|
|
39
|
+
|
|
32
40
|
The `initialized` marker records that a full-scan invocation has reached its aggregate-result boundary and that later invocations may restore stored storage-event operations. It is not a successful-scan marker: the first invocation records it after an aggregate `false` result, `true`, or an accepted partial result. An exception before the aggregate result is produced does not reach that write.
|
|
33
41
|
|
|
34
|
-
Storage-event restoration is a bounded start-up recovery step. Restored events bypass their former batch delay, but `restoreState()` waits for their actual
|
|
42
|
+
Storage-event restoration is a bounded start-up recovery step. Restored events bypass their former batch delay, but `restoreState()` waits for their actual handler outcomes and snapshot ordering before the file collections are compared. Saved events run first because a deletion or rename can carry operation intent which is no longer visible in the current storage listing. An individual restored operation failure remains in the pending snapshot and is logged; it does not prevent the scan from examining current state or independent paths. The following full scan then makes the final reconciliation decision.
|
|
35
43
|
|
|
36
|
-
This ordering does not mean that storage unconditionally overwrites the replay result. The action matrix remains authoritative: when a replayed operation leaves an ambiguous pair, such as a storage file alongside a deleted database entry, the selected policy may deliberately return `skipped` rather than guess which side is intended.
|
|
44
|
+
This ordering does not mean that storage unconditionally overwrites the replay result. The action matrix remains authoritative: when a replayed operation leaves an ambiguous pair, such as a storage file alongside a deleted database entry, the selected policy may deliberately return `skipped` rather than guess which side is intended. A failed replay does not become a completed operation; a later scan may still reconcile its current pair. This start-up recovery boundary is separate from later watcher work and a host's replication-result queue.
|
|
37
45
|
|
|
38
46
|
### Stored event interpretation
|
|
39
47
|
|
|
40
|
-
The storage-event snapshot
|
|
48
|
+
The storage-event snapshot retains every accepted operation while it is buffered, waiting for a batch boundary, or in a handler. It remains there until the operation has a durable local result, is proved already represented or safely covered by a successful successor, or ends in a skip explicitly allowed by policy. A `false` handler result or exception leaves the saved operation pending. A failed initial snapshot prevents the handler from starting; a later snapshot failure is reported and cannot be treated as completion. Ordered snapshot writes prevent an older asynchronous save from replacing a newer pending view. The snapshot records operation intent, not file content, and cannot recover bytes or events which the host never persisted or delivered; the full scan continues to observe current storage state.
|
|
41
49
|
|
|
42
|
-
A restored event is an operation intent which must be revalidated against the current exact storage path before it can cause a database side effect. Its saved file stub, timestamps, and optional editor cache describe the earlier observation; they are not authoritative file content after a restart. Whenever an inclusion is still applicable, the handler reads a fresh stub and content
|
|
50
|
+
A restored event is an operation intent which must be revalidated against the current exact storage path before it can cause a database side effect. Its saved file stub, timestamps, and optional editor cache describe the earlier observation; they are not authoritative file content after a restart. Whenever an inclusion is still applicable, the handler reads a fresh stub and current content when the operation runs. Whenever an ordinary deletion's expected absence is contradicted by a current storage item, that deletion is suppressed and the full scan evaluates that current item instead.
|
|
43
51
|
|
|
44
52
|
For this check, an exact path means that the canonical path returned by storage has the saved spelling after ordinary separator normalisation. A file returned only through a case-insensitive lookup does not prove the saved inclusion path. A same-ID rename remains the explicit case-change path described below.
|
|
45
53
|
|
|
@@ -58,7 +66,7 @@ The standard-file revalidation contract is:
|
|
|
58
66
|
| Case-only or otherwise same-ID `RENAME` | A current selected file resolves to the renamed canonical path | Update that single document's path and current content without a separate deletion |
|
|
59
67
|
| Case-only or otherwise same-ID `RENAME` | The current identity does not support the saved rename | Do not replay the rename; let the full scan evaluate the current path |
|
|
60
68
|
|
|
61
|
-
An inability to inspect the current path is not proof of absence. Revalidation
|
|
69
|
+
An inability to inspect the current path is not proof of absence. Revalidation suppresses a destructive half when storage inspection fails, records the failure, and leaves the operation pending. The full scan can still examine the current state and reports any selected-pair failure under its strict or explicitly partial completion policy. Target-file policy and file-size limits are evaluated from current settings rather than inherited from the saved event.
|
|
62
70
|
|
|
63
71
|
The unreleased rename-exclusion guard retains `renameTarget` when a rename is converted to deletion during target filtering. Unlike an ordinary deletion, this intent can remove a file from synchronisation without removing it from storage. The guard distinguishes deliberate exclusion from transient case-collision rejection, preserves a recreated source, and permits a deliberately excluded same-ID destination without requiring that destination to disappear. Older snapshots without this optional field retain the absence-only rule. See [Storage events and database-to-storage reflection](storage-events-and-reflection.md) for the exact admission conditions and the separate ordinary watcher boundary.
|
|
64
72
|
|
|
@@ -138,11 +146,13 @@ By default, the complete scan returns `false` when any pair is `failed`, and ret
|
|
|
138
146
|
|
|
139
147
|
Self-hosted LiveSync enables this policy only for ordinary Obsidian start-up, where one unavailable path must not prevent unaffected files from synchronising. Fast Setup, Fetch, Rebuild, direct scans, and CLI mirror or daemon paths retain the strict default.
|
|
140
148
|
|
|
141
|
-
##
|
|
149
|
+
## Files in the same timestamp bucket
|
|
150
|
+
|
|
151
|
+
For a `both` pair which selects `NEWER_WINS` (`sync-newer`), the normal freshness comparison can reach `EVEN` for equal raw modification times or distinct times within the platform tolerance; those timestamps alone do not establish that the storage file is unchanged. Under the omitted-option strict path, the scanner asks the file handler to record provenance for the current database revision only when current storage and one unambiguous live revision have matching content. The handler checks the storage bytes and database revision under the document lock, then revalidates the storage snapshot, current revision, and absent provenance before writing the record. This check writes neither storage content nor a database revision. With explicit `strictContentCheck: false`, the scanner may request `canSkipUnchangedFile` only in the `EVEN` branch, and only when the raw mtime exactly matches the recorded provenance mtime; a value merely in the same tolerance bucket does not qualify. The `BASE_IS_NEW` and `TARGET_IS_NEW` branches retain their existing timestamp-directed reflection and last-seen bookkeeping. The existing selection, file-size, and conflict policies still apply, and the `DB_APPLY` action remains unchanged.
|
|
142
152
|
|
|
143
|
-
|
|
153
|
+
The result of `tryRecordUntrackedFileRevision()` is not an edit predicate. Its `false` can mean that provenance already exists, content differs, history conflicts, required content or provenance is unavailable, or state changed during verification. When it returns `false`, the scanner uses the ordinary, non-forced `storeFileToDB` path with bounded storage revalidation; it does not force the Vault file into the current database winner. The file handler retains a known branch when readable provenance identifies it, applies newer database state when the storage bytes match that recorded older revision, and saves a genuine edit on its recorded branch.
|
|
144
154
|
|
|
145
|
-
|
|
155
|
+
A valid saved content hash can prove that unchanged bytes still represent a recorded revision whose database content has been pruned. A hash cannot reconstruct ancestry for edited bytes. If the recorded base is pruned and the current bytes do not match its saved hash, the handler may preserve readable storage as an independent branch when it matches no current live leaf; it must not attach those bytes to an arbitrary database winner. This unknown-origin case is distinct from an unavailable comparison: if required storage, provenance, database content, or revalidation cannot be read, the operation remains unresolved and the pair fails for retry. Repeated storage changes are bounded and also remain failed rather than being reported as reconciled.
|
|
146
156
|
|
|
147
157
|
## Result-state verification
|
|
148
158
|
|
|
@@ -156,12 +166,12 @@ Focused two-pass coverage starts with a `DB_APPLY` reflection whose file handler
|
|
|
156
166
|
|
|
157
167
|
Full-scan coverage also verifies that the strict default returns `false`, an ordinary-start-up scan which explicitly continues returns `completed-with-file-failures` while logging the affected path at verbose level, and a later clean scan returns `true`.
|
|
158
168
|
|
|
159
|
-
The equal-time regression uses real in-memory PouchDB and the file handler. It checks missing and recorded provenance with unchanged files and genuine local edits, then advances the database and
|
|
169
|
+
The equal-time regression uses real in-memory PouchDB and the file handler with `strictContentCheck` omitted, keeping its same-stat edit assertions on the strict default path. It checks missing and recorded provenance with unchanged files and genuine local edits at both identical raw timestamps and distinct raw timestamps within one comparison bucket. It verifies that edits are preserved during the scan, then advances the database and checks that an incoming revision retains the local branch. It also verifies that a matching saved hash remains useful after its database revision is pruned, while edited bytes with an unhashed pruned base and no matching live leaf are preserved independently. Focused scanner tests verify that a failed ordinary save returns a failed pair. Focused handler tests cover provenance read and write failures, unavailable recorded-base content, an existing conflict, and storage or database changes during verification.
|
|
160
170
|
|
|
161
171
|
A second two-pass case starts with a `db-only` entry skipped by the size limit. It then removes that limit and verifies that the entry is reflected to storage rather than misclassified as an offline local deletion. Coverage for an existing storage file verifies that a failed `sync-newer` reflection retains the observed storage mtime, and full-scan coverage verifies that the aggregate failure reaches its caller after scanner initialisation completes.
|
|
162
172
|
|
|
163
173
|
Identity coverage verifies early quarantine when no consistent target exists, continued processing when consistent Metadata represents the same logical path, expired-deletion retention, special-namespace routing, actual-ID-first inspection, stale and ambiguous repair rejection, target-first ordering, exact-target retry, source preservation after failure, and last-seen clearing.
|
|
164
174
|
|
|
165
|
-
Stored-event coverage verifies that current storage content replaces saved observations, a recreated path suppresses a stale deletion, distinct-ID rename halves are admitted independently from current path state, and a same-ID rename never performs a separate deletion. It also verifies that a storage-inspection failure does not become evidence for a destructive operation and that an individual replay failure does not prevent the full scan from running.
|
|
175
|
+
Stored-event coverage verifies that current storage content replaces saved observations, a recreated path suppresses a stale deletion, distinct-ID rename halves are admitted independently from current path state, and a same-ID rename never performs a separate deletion. It also verifies that a storage-inspection failure does not become evidence for a destructive operation, that failed work remains pending, and that an individual replay failure does not prevent the full scan from running.
|
|
166
176
|
|
|
167
177
|
Maintain that interaction boundary when changing file-handler results, last-seen persistence, Fast Setup reflection, or offline deletion detection.
|
|
@@ -68,6 +68,8 @@ if (prepared.requiresSyncReview) {
|
|
|
68
68
|
|
|
69
69
|
Explicit stored values take precedence over every fallback. A migration therefore preserves synchronisation switches and other user choices unless a migration step documents a deliberate transformation.
|
|
70
70
|
|
|
71
|
+
`batchSaveInLiveSync` is a separate explicit choice for bounded local database batching in LiveSync mode. Both new and existing settings default to `false`; the legacy pair `liveSync: true, batchSave: true` does not enable it. The public setting property is optional for existing host settings shapes, and a missing value remains disabled. Other modes continue to use `batchSave`. Markdown settings and QR data preserve the explicit choice, while older imports without the property do not infer it from `batchSave`. Hosts should preserve both choices during ordinary mode changes and use the shared minimum and maximum delays.
|
|
72
|
+
|
|
71
73
|
The sleep preferences are included in Setup URI encoding. When an older Setup URI or stored setting does not contain either key, `allowSleepDuringSynchronisation` defaults to `false`, while `allowSleepDuringSynchronisationOnDesktop` defaults to `true`. The maintained Obsidian host therefore retains best-effort screen-awake protection on mobile but allows normal automatic sleep on desktop unless the user selects otherwise.
|
|
72
74
|
|
|
73
75
|
An existing settings store without an explicit `handleFilenameCaseSensitive` value is normalised to `false` and saved. This preserves the effective behaviour of earlier releases, where an absent value followed the case-insensitive branch. An explicit `true` or `false` value is preserved. New Vaults also select case-insensitive handling (`false`).
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
---
|
|
2
|
-
date: 2026-
|
|
3
|
-
commonlib-version: "0.1
|
|
4
|
-
self-hosted-livesync-version: "1.0.
|
|
2
|
+
date: 2026-10-26
|
|
3
|
+
commonlib-version: "0.2.1"
|
|
4
|
+
self-hosted-livesync-version: "1.0.40"
|
|
5
|
+
status: unreleased
|
|
5
6
|
---
|
|
6
7
|
|
|
7
8
|
# Storage events and database-to-storage reflection
|
|
8
9
|
|
|
9
10
|
This note separates storage-to-database event handling from
|
|
10
|
-
database-to-storage reflection. It
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
versions
|
|
11
|
+
database-to-storage reflection. It documents the current guard against a stale
|
|
12
|
+
`DELETE` notification logically deleting Metadata while the same file is still
|
|
13
|
+
present in storage, and the accepted local completion contract for queued file
|
|
14
|
+
operations. The version fields identify the reviewed source versions; these
|
|
15
|
+
changes remain unreleased.
|
|
14
16
|
|
|
15
17
|
## Processing directions
|
|
16
18
|
|
|
@@ -46,6 +48,105 @@ and unsynchronised storage content retain their existing reflection rules.
|
|
|
46
48
|
The watcher guard does not intercept this path or general explicit database
|
|
47
49
|
deletion operations.
|
|
48
50
|
|
|
51
|
+
## Startup scans and pending operations
|
|
52
|
+
|
|
53
|
+
The full scanner's optional `strictContentCheck: false` path is gated by the host's file-operation state. Any related queued, running, or failed operation blocks the `canSkipUnchangedFile` hint. The host must provide an available query before the scanner can establish that no related work exists; without that query or other required evidence, strict content comparison remains active. The hint is considered only after normal freshness comparison reaches `EVEN`, and requires the raw mtime to exactly match the recorded provenance value; a match within the platform comparison bucket is insufficient. `BASE_IS_NEW` and `TARGET_IS_NEW` retain their timestamp-directed reflection and last-seen bookkeeping. A pair returned as `SKIPPED` by this hint does not acknowledge or remove a saved event. Event work continues to follow the snapshot and handler-completion contract below. This option affects only the full-scan same-stat check; ordinary watcher `CREATE` and `CHANGED` handling, replicated writes, and logical-deletion protection retain their existing rules. See [Full offline scan](offline-scanner.md#startup-content-checking) for the full option and eligibility conditions.
|
|
54
|
+
|
|
55
|
+
## Pending operations and local completion
|
|
56
|
+
|
|
57
|
+
Once admitted, a file operation remains pending while buffered, waiting for its
|
|
58
|
+
batch boundary, or running in a handler. The manager includes all three states
|
|
59
|
+
in its existing event snapshot. It saves snapshots in order, so an older write
|
|
60
|
+
cannot replace a newer view of pending work. The manager acknowledges an
|
|
61
|
+
ordinary file operation only after its effect is durable locally, current state proves the
|
|
62
|
+
effect is already represented or safely covered by a successful successor, or
|
|
63
|
+
the handler returns a skip explicitly allowed by policy. A handler
|
|
64
|
+
failure or exception leaves the saved operation pending. A failed initial
|
|
65
|
+
snapshot prevents the handler from starting; a later snapshot failure is
|
|
66
|
+
reported and cannot be treated as completion. Completion of an older operation
|
|
67
|
+
cannot remove a newer operation for the same path.
|
|
68
|
+
|
|
69
|
+
The event snapshot records operation intent, not authoritative current file
|
|
70
|
+
content. Admission does not read a file body merely to wait. When a `CREATE` or
|
|
71
|
+
`CHANGED` operation becomes eligible, the handler rechecks the current path and
|
|
72
|
+
obtains its current content for processing. Restored events are revalidated
|
|
73
|
+
against current storage and selection before they can affect the database. The
|
|
74
|
+
saved stub and any optional cache are not used as a historical file version.
|
|
75
|
+
The current-storage deletion checks and rename-exclusion rules below continue to
|
|
76
|
+
apply.
|
|
77
|
+
|
|
78
|
+
A restored deletion whose database entry is already absent or deleted completes
|
|
79
|
+
without another revision. A restored rename whose source deletion is already
|
|
80
|
+
represented reconciles the current target through the ordinary non-forced
|
|
81
|
+
handler. The same applies to a case-only rename when Metadata already records
|
|
82
|
+
the target spelling. Replaying either completed operation preserves later local
|
|
83
|
+
edits. If the source is still live and a target already exists, the existing
|
|
84
|
+
collision refusal remains in force: the snapshot does not prove that this
|
|
85
|
+
rename created that target, so the unresolved operation remains pending.
|
|
86
|
+
|
|
87
|
+
`commitPendingFileEvents()` requests immediate processing of the finite set of
|
|
88
|
+
operations accepted before the call, including work which is buffered,
|
|
89
|
+
waiting, or already in a handler. It waits for each actual handler result and
|
|
90
|
+
for the ordered snapshot update which records that result; releasing a timer is
|
|
91
|
+
not completion. Later events do not extend that captured boundary. A newer
|
|
92
|
+
coalesced operation satisfies an earlier one only when its successful result
|
|
93
|
+
covers the earlier intent. A failed handler or snapshot update is reported to
|
|
94
|
+
the caller and leaves unresolved work in the snapshot. This boundary covers
|
|
95
|
+
local completion under the selected handler contract only; it does not prove replication or receipt by another
|
|
96
|
+
Vault.
|
|
97
|
+
|
|
98
|
+
A `DELETE` or `RENAME` ordering sentinel waits for its predecessors only. It
|
|
99
|
+
must not wait for itself or events which follow it in the dispatch queue. Batch
|
|
100
|
+
timers make work eligible to run; they do not perform it. The quiet period
|
|
101
|
+
follows the latest eligible content update, while the maximum intentional delay
|
|
102
|
+
is measured from the first uncommitted update, starting when the queue call is
|
|
103
|
+
accepted and before asynchronous filtering or the touched-file check. Waiting
|
|
104
|
+
timers do not occupy a processing slot, and time spent waiting for a slot does
|
|
105
|
+
not restart the maximum delay. Once due, the operation acquires a slot and reads
|
|
106
|
+
current content for processing.
|
|
107
|
+
|
|
108
|
+
## Optional file handlers
|
|
109
|
+
|
|
110
|
+
`INTERNAL` events and files marked `isInternal` use their owning feature's
|
|
111
|
+
contract. Hosts can register `processOptionalFileEventWithResult` handlers with
|
|
112
|
+
`firstHandled`. `HandlerOutcome<TValue = void, TVetoReason = void>` carries a
|
|
113
|
+
success value and a veto reason independently; a non-void payload is required
|
|
114
|
+
in its branch. Dispatch follows priority and registration order:
|
|
115
|
+
|
|
116
|
+
| Outcome | Dispatch and completion |
|
|
117
|
+
| --- | --- |
|
|
118
|
+
| `not-applicable` | Try the next provider. If none applies, complete the policy-approved skip. |
|
|
119
|
+
| `completed` | Stop and complete the event after the provider's actual save or verified no-op. |
|
|
120
|
+
| `veto` | Stop and retain the event with a reported refusal reason. |
|
|
121
|
+
| Exception or rejection | Propagate the original error and retain the event. |
|
|
122
|
+
|
|
123
|
+
A completed result stops dispatch immediately; a later provider cannot veto
|
|
124
|
+
it. Empty registration returns `not-applicable`. False or zero payloads remain
|
|
125
|
+
valid values. Providers must resolve their promise only after the operation
|
|
126
|
+
finishes. Snapshot acknowledgement still follows the handler result, and a
|
|
127
|
+
snapshot failure keeps the event recoverable.
|
|
128
|
+
|
|
129
|
+
The optional `whenFlushRequested` promise resolves when a finite completion
|
|
130
|
+
boundary includes this event. A provider which debounces saves uses it to
|
|
131
|
+
release that event's captured delay. It must wait for the corresponding save,
|
|
132
|
+
settle all notifications coalesced into that save, and keep later groups outside
|
|
133
|
+
the captured boundary. This signal is runtime state; it does not change the
|
|
134
|
+
persisted snapshot format.
|
|
135
|
+
|
|
136
|
+
Migrate all optional providers in a host together. Once the first typed provider
|
|
137
|
+
is registered, the manager uses the typed chain exclusively, even when every
|
|
138
|
+
provider returns `not-applicable`. A host without a registered typed provider
|
|
139
|
+
retains `processOptionalFileEvent` as a legacy notification contract. Its
|
|
140
|
+
boolean does not confirm persistence: a resolved notification completes only
|
|
141
|
+
that dispatch, while a rejection which reaches the manager is still retained.
|
|
142
|
+
The existing boolean aggregators and ordinary file contract are unchanged.
|
|
143
|
+
|
|
144
|
+
During start-up replay and settings or unload flushes, providers use actual
|
|
145
|
+
database readiness and initialise their required local state before saving.
|
|
146
|
+
They must not wait for an application-ready or resume event which occurs only
|
|
147
|
+
after that same flush. An unavailable prerequisite returns a veto; the manager
|
|
148
|
+
does not introduce an automatic retry loop for a failed operation.
|
|
149
|
+
|
|
49
150
|
## Event intent and current storage state
|
|
50
151
|
|
|
51
152
|
| Event intent | Current storage observation | Admitted operation |
|
|
@@ -92,9 +193,11 @@ incoming logical deletion can still remove unchanged storage content.
|
|
|
92
193
|
|
|
93
194
|
These tests do not establish the native watcher event sequence reported in
|
|
94
195
|
Issue 1168. Real-runtime verification belongs to the host and must distinguish
|
|
95
|
-
observed events from inferred causes.
|
|
96
|
-
convergence or full folder-rename support.
|
|
97
|
-
|
|
196
|
+
observed events from inferred causes. The watcher guard does not promise
|
|
197
|
+
path-case convergence or full folder-rename support. Focused manager tests cover
|
|
198
|
+
finite completion boundaries, ordered snapshots, retained failures, replay, and
|
|
199
|
+
batch timing. This work adds no second journal, unbounded retry loop, or
|
|
200
|
+
database-schema change.
|
|
98
201
|
|
|
99
202
|
The maintained host's real-runtime comparison is recorded in
|
|
100
203
|
[Proven in maintained hosts](proven-in-use.md#obsidian-plug-in), separately
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vrtmrz/livesync-commonlib",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
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",
|
|
@@ -1010,7 +1010,7 @@
|
|
|
1010
1010
|
"events": "^3.3.0",
|
|
1011
1011
|
"fflate": "^0.8.2",
|
|
1012
1012
|
"idb": "^8.0.3",
|
|
1013
|
-
"markdown-it": "^14.3.
|
|
1013
|
+
"markdown-it": "^14.3.3",
|
|
1014
1014
|
"minimatch": "^10.2.6",
|
|
1015
1015
|
"octagonal-wheels": "^0.1.55",
|
|
1016
1016
|
"pouchdb-adapter-http": "^9.0.0",
|