@vrtmrz/livesync-commonlib 0.1.25 → 0.1.26
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/dist/interfaces/DatabaseFileAccess.d.ts +31 -3
- package/dist/interfaces/FileReflectionProvenance.d.ts +2 -2
- package/dist/managers/EntryManager/EntryManager.d.ts +4 -2
- package/dist/managers/EntryManager/EntryManager.js +9 -4
- package/dist/managers/EntryManager/EntryManagerImpls.d.ts +12 -4
- package/dist/managers/EntryManager/EntryManagerImpls.js +27 -9
- package/dist/pouchdb/LiveSyncLocalDB.d.ts +4 -2
- package/dist/pouchdb/LiveSyncLocalDB.js +8 -4
- package/dist/serviceModules/ServiceDatabaseFileAccessBase.d.ts +26 -2
- package/dist/serviceModules/ServiceDatabaseFileAccessBase.js +57 -5
- package/dist/serviceModules/ServiceFileHandlerBase.d.ts +119 -1
- package/dist/serviceModules/ServiceFileHandlerBase.js +450 -70
- package/docs/conflict-resolution.md +28 -15
- package/docs/proven-in-use.md +1 -1
- package/package.json +1 -1
|
@@ -44,6 +44,7 @@ export declare abstract class ServiceFileHandlerBase extends ServiceModuleBase<S
|
|
|
44
44
|
private setting;
|
|
45
45
|
private vault;
|
|
46
46
|
private fileReflectionProvenance?;
|
|
47
|
+
private readonly deferredConflictChecks;
|
|
47
48
|
constructor(services: ServiceFileHandlerDependencies);
|
|
48
49
|
get db(): DatabaseFileAccess;
|
|
49
50
|
get storage(): StorageAccess;
|
|
@@ -52,31 +53,148 @@ export declare abstract class ServiceFileHandlerBase extends ServiceModuleBase<S
|
|
|
52
53
|
private deleteProvenance;
|
|
53
54
|
private findUniqueContentRevision;
|
|
54
55
|
private getProvenBaseRevision;
|
|
56
|
+
/**
|
|
57
|
+
* Classify a storage read against its displayed database branch.
|
|
58
|
+
*
|
|
59
|
+
* A recorded revision identifies the branch and therefore takes precedence
|
|
60
|
+
* over byte matches. Without a readable base, only current live leaves are
|
|
61
|
+
* considered. Any match avoids a duplicate write, but only a unique match
|
|
62
|
+
* identifies provenance; no match is `unknown`.
|
|
63
|
+
* `preferredPath` selects the provenance key during a rename, and
|
|
64
|
+
* `currentLoaded` supplies an already decoded candidate body when available.
|
|
65
|
+
* Missing chunks do not clear provenance unless their metadata is also
|
|
66
|
+
* missing or deleted.
|
|
67
|
+
*/
|
|
68
|
+
private classifyStorageContent;
|
|
69
|
+
/** Record provenance only when storage matches one unambiguous live leaf. */
|
|
70
|
+
private rememberMatchingLeaf;
|
|
71
|
+
/**
|
|
72
|
+
* Read the raw provenance value used by an optimistic storage snapshot.
|
|
73
|
+
* Unlike `getProvenance`, this does not validate or remove the referenced
|
|
74
|
+
* database revision; an unreadable value is represented as `undefined`.
|
|
75
|
+
*/
|
|
76
|
+
private readProvenanceSnapshot;
|
|
77
|
+
/**
|
|
78
|
+
* Check that storage still has the same path, bytes, timestamp, and
|
|
79
|
+
* provenance as a previously captured snapshot.
|
|
80
|
+
*/
|
|
81
|
+
private currentStorageSnapshotMatches;
|
|
82
|
+
/**
|
|
83
|
+
* Publish provenance after a durable database write if storage is unchanged.
|
|
84
|
+
* A failed revalidation leaves the database revision stored and asks the
|
|
85
|
+
* caller to reread storage before proceeding.
|
|
86
|
+
*/
|
|
87
|
+
private finaliseStoredRevision;
|
|
88
|
+
/**
|
|
89
|
+
* Reread storage after a restored startup snapshot changed and retry a save.
|
|
90
|
+
* The bounded counter prevents an unstable file from causing an endless
|
|
91
|
+
* startup loop; the next event or scan can reconcile a final refusal.
|
|
92
|
+
*/
|
|
93
|
+
private retryCurrentStorage;
|
|
55
94
|
getPath(entry: AnyEntry): FilePathWithPrefix;
|
|
56
95
|
getPathWithoutPrefix(entry: AnyEntry): FilePathWithPrefix;
|
|
57
96
|
readFileFromStub(file: UXFileInfoStub | UXFileInfo): Promise<UXFileInfo>;
|
|
58
97
|
private infoToStub;
|
|
59
98
|
storeFileToDB(info: UXFileInfoStub | UXFileInfo | UXInternalFileInfoStub | FilePathWithPrefix, force?: boolean, onlyChunks?: boolean): Promise<boolean>;
|
|
60
99
|
storeFileToDBWithBaseRevision(info: UXFileInfoStub | UXFileInfo | FilePathWithPrefix, baseRevision: string, createIfDifferent?: boolean): Promise<boolean>;
|
|
100
|
+
/**
|
|
101
|
+
* Store current storage content below an exact live revision. A differing
|
|
102
|
+
* body is rejected when `createIfDifferent` is false; callers hold the
|
|
103
|
+
* document lock for this core operation.
|
|
104
|
+
*/
|
|
105
|
+
private storeFileToDBWithBaseRevisionCore;
|
|
106
|
+
/**
|
|
107
|
+
* Save one storage snapshot while the caller holds its document lock.
|
|
108
|
+
* Ordinary saves read once inside the lock and leave retries disabled.
|
|
109
|
+
* Restored startup events retain bounded rereads because file watching has
|
|
110
|
+
* not yet started and cannot supply a new event for a concurrent edit.
|
|
111
|
+
*/
|
|
61
112
|
private storeFileToDBFromRevision;
|
|
62
113
|
deleteFileFromDB(info: UXFileInfoStub | UXInternalFileInfoStub | FilePath): Promise<boolean>;
|
|
114
|
+
/**
|
|
115
|
+
* Record a storage deletion under the caller's document lock, preserving
|
|
116
|
+
* the displayed conflict branch when its provenance is known.
|
|
117
|
+
*/
|
|
118
|
+
private deleteFileFromDBCore;
|
|
63
119
|
renameFileInDB(info: UXFileInfoStub | UXFileInfo, oldPath: FilePath | FilePathWithPrefix): Promise<boolean>;
|
|
120
|
+
/**
|
|
121
|
+
* Record a rename under the caller's source and target locks. Case-only
|
|
122
|
+
* renames retain the source provenance while other renames handle the
|
|
123
|
+
* source conflict before deleting its old path.
|
|
124
|
+
*/
|
|
125
|
+
private renameFileInDBCore;
|
|
64
126
|
deleteRevisionFromDB(info: UXFileInfoStub | FilePath | FilePathWithPrefix, rev: string): Promise<boolean | undefined>;
|
|
127
|
+
/** Delete one selected revision and clear matching provenance under the caller's document lock. */
|
|
128
|
+
private deleteRevisionFromDBCore;
|
|
65
129
|
resolveConflictedByDeletingRevision(info: UXFileInfoStub | FilePath, rev: string): Promise<boolean | undefined>;
|
|
130
|
+
/**
|
|
131
|
+
* Apply the legacy resolve-by-delete sequence while holding one document
|
|
132
|
+
* lock; metadata is captured before the selected revision is removed.
|
|
133
|
+
*/
|
|
134
|
+
private resolveConflictedByDeletingRevisionCore;
|
|
66
135
|
dbToStorageWithSpecificRev(info: UXFileInfoStub | UXFileInfo | FilePath | FilePathWithPrefix | null, rev: string, force?: boolean): Promise<boolean>;
|
|
136
|
+
/**
|
|
137
|
+
* Reflect a selected live revision under the caller's document lock.
|
|
138
|
+
* The public wrapper performs the same lock acquisition before entering here.
|
|
139
|
+
*/
|
|
140
|
+
private dbToStorageWithSpecificRevCore;
|
|
67
141
|
dbToStorage(entryInfo: MetaEntry | FilePathWithPrefix, info: UXFileInfoStub | UXFileInfo | FilePath | null, force?: boolean): Promise<boolean>;
|
|
142
|
+
/** Fetch the current metadata and reflect it while the caller holds its lock. */
|
|
143
|
+
private dbToStorageCore;
|
|
144
|
+
/**
|
|
145
|
+
* Reflect one database revision while protecting concurrent storage edits.
|
|
146
|
+
* Overwrite and deletion paths preserve changed bytes first, then revalidate
|
|
147
|
+
* their snapshot and the current database revision immediately before the
|
|
148
|
+
* destructive operation.
|
|
149
|
+
*/
|
|
68
150
|
private applyDatabaseEntryToStorage;
|
|
151
|
+
/**
|
|
152
|
+
* Preserve storage bytes before an incoming reflection can replace them.
|
|
153
|
+
*
|
|
154
|
+
* The initial read and provenance form one candidate snapshot. Classification
|
|
155
|
+
* gives a recorded branch priority, deduplicates matching live leaves, or
|
|
156
|
+
* creates an independent root for unknown origin. Optional `incomingContent` avoids
|
|
157
|
+
* re-reading an already loaded incoming body. Storage is revalidated before
|
|
158
|
+
* and after the database write; `preserved: true` stops the incoming write,
|
|
159
|
+
* while a returned `snapshot` lets the caller continue only after revalidation.
|
|
160
|
+
*/
|
|
69
161
|
private preserveUnsyncedStorageAsConflict;
|
|
162
|
+
/**
|
|
163
|
+
* Repeat overwrite protection from a fresh storage read after a snapshot
|
|
164
|
+
* becomes stale. Existing conflicts may defer reflection and request an
|
|
165
|
+
* open-only check while leaving the current storage untouched.
|
|
166
|
+
*/
|
|
167
|
+
private recheckIncomingStorage;
|
|
168
|
+
/**
|
|
169
|
+
* Re-read database metadata immediately before reflecting an incoming entry.
|
|
170
|
+
* If the current revision advanced, recurse with fresh storage; force and
|
|
171
|
+
* explicitly allowed conflict writes retain the caller's selected entry.
|
|
172
|
+
* `incomingRetry` bounds repeated database churn.
|
|
173
|
+
*/
|
|
174
|
+
private reconcileAdvancedIncomingRevision;
|
|
70
175
|
private _anyHandlerProcessesFileEvent;
|
|
71
176
|
private canRecordStorageDeletion;
|
|
177
|
+
/**
|
|
178
|
+
* Serialise work by every document ID represented by the supplied paths.
|
|
179
|
+
* IDs are deduplicated and sorted so aliases take one lock and cross-document renames have one order.
|
|
180
|
+
* The callback runs under those locks and must use core methods; conflict
|
|
181
|
+
* hooks requested inside it are deferred until all locks have been released.
|
|
182
|
+
*/
|
|
72
183
|
private serializedByFileEventPaths;
|
|
184
|
+
/**
|
|
185
|
+
* Queue a conflict hook while its document lock is held, or run it directly
|
|
186
|
+
* when no matching lock is active. Preserve `ifOpen` across deferral.
|
|
187
|
+
*/
|
|
188
|
+
private queueConflictCheckFor;
|
|
73
189
|
/**
|
|
74
190
|
* Revalidate a persisted storage operation against the current storage state.
|
|
75
191
|
*
|
|
76
192
|
* Snapshot entries preserve operation intent and ordering only. Their file
|
|
77
193
|
* stub, timestamps, and existence assumptions can be stale after a restart.
|
|
78
194
|
* Current inclusion is therefore read from storage, while destructive work
|
|
79
|
-
* is allowed only after current absence has been observed.
|
|
195
|
+
* is allowed only after current absence has been observed. Store and rename
|
|
196
|
+
* actions use the fresh reread with bounded retry because no later watcher
|
|
197
|
+
* event is guaranteed after startup reconciliation.
|
|
80
198
|
*/
|
|
81
199
|
private _processRestoredFileEvent;
|
|
82
200
|
private _planRestoredFileEvent;
|