@vrtmrz/livesync-commonlib 0.1.0-rc.1 → 0.1.0-rc.10
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 +90 -20
- package/dist/API/DirectFileManipulatorV2.d.ts +3 -0
- package/dist/common/configForDoc.d.ts +1 -0
- package/dist/common/configForDoc.js +24 -7
- package/dist/common/models/setting.const.defaults.d.ts +19 -0
- package/dist/common/models/setting.const.defaults.js +21 -2
- package/dist/common/models/setting.const.preferred.js +1 -2
- package/dist/common/models/setting.lifecycle.d.ts +33 -0
- package/dist/common/models/setting.lifecycle.js +121 -0
- package/dist/common/models/setting.type.d.ts +10 -4
- package/dist/common/models/shared.definition.configNames.js +3 -3
- package/dist/common/models/tweak.definition.d.ts +1 -1
- package/dist/common/models/tweak.definition.js +1 -6
- package/dist/common/settingConstants.d.ts +3 -2
- package/dist/common/settingConstants.js +6 -6
- package/dist/common/types.d.ts +4 -2
- package/dist/common/types.js +16 -1
- package/dist/context.d.ts +2 -1
- package/dist/context.js +4 -0
- package/dist/interfaces/Confirm.d.ts +10 -2
- package/dist/interfaces/DatabaseFileAccess.d.ts +8 -0
- package/dist/interfaces/DatabaseRebuilder.d.ts +12 -2
- package/dist/interfaces/FileReflectionProvenance.d.ts +32 -0
- package/dist/interfaces/FileReflectionProvenance.js +25 -0
- package/dist/managers/ConflictManager.js +16 -7
- package/dist/managers/EntryManager/EntryManager.d.ts +1 -0
- package/dist/managers/EntryManager/EntryManager.js +5 -1
- package/dist/managers/EntryManager/EntryManagerImpls.d.ts +1 -0
- package/dist/managers/EntryManager/EntryManagerImpls.js +29 -1
- package/dist/platform/node/storage.d.ts +10 -1
- package/dist/platform/node/storage.js +86 -25
- package/dist/pouchdb/LiveSyncLocalDB.d.ts +1 -0
- package/dist/pouchdb/LiveSyncLocalDB.js +3 -0
- package/dist/remoteConfigurations.d.ts +9 -0
- package/dist/remoteConfigurations.js +14 -0
- package/dist/replication/LiveSyncAbstractReplicator.d.ts +3 -3
- package/dist/replication/couchdb/LiveSyncReplicator.d.ts +0 -1
- package/dist/replication/couchdb/LiveSyncReplicator.js +0 -3
- package/dist/replication/journal/LiveSyncJournalReplicator.d.ts +0 -1
- package/dist/replication/journal/LiveSyncJournalReplicator.js +0 -3
- package/dist/replication/trystero/LiveSyncTrysteroReplicator.d.ts +5 -3
- package/dist/replication/trystero/LiveSyncTrysteroReplicator.js +42 -30
- package/dist/replication/trystero/P2PReplicatorCore.d.ts +2 -6
- package/dist/replication/trystero/P2PReplicatorCore.js +16 -86
- package/dist/replication/trystero/TrysteroReplicator.d.ts +2 -1
- package/dist/replication/trystero/TrysteroReplicator.js +10 -4
- package/dist/replication/trystero/TrysteroReplicatorP2PServer.d.ts +4 -5
- package/dist/replication/trystero/TrysteroReplicatorP2PServer.js +22 -30
- package/dist/replication/trystero/UseP2PReplicatorResult.d.ts +10 -2
- package/dist/replication/trystero/addP2PEventHandlers.d.ts +4 -2
- package/dist/replication/trystero/addP2PEventHandlers.js +9 -10
- package/dist/replication/trystero/types.d.ts +2 -0
- package/dist/replication/trystero/useP2PReplicatorCommands.d.ts +1 -1
- package/dist/replication/trystero/useP2PReplicatorCommands.js +3 -1
- package/dist/replication/trystero/useP2PReplicatorFeature.js +25 -15
- package/dist/rpc/RpcRoom.d.ts +1 -1
- package/dist/rpc/RpcRoom.js +22 -16
- package/dist/rpc/transports/TrysteroTransport.d.ts +2 -0
- package/dist/rpc/transports/TrysteroTransport.js +24 -17
- package/dist/rpc/transports/trysteroRoomEvents.d.ts +14 -0
- package/dist/rpc/transports/trysteroRoomEvents.js +34 -0
- package/dist/serviceFeatures/checkRemoteSize.d.ts +5 -3
- package/dist/serviceFeatures/checkRemoteSize.js +51 -11
- package/dist/serviceFeatures/remoteConfig.d.ts +37 -1
- package/dist/serviceFeatures/remoteConfig.js +90 -0
- package/dist/serviceModules/Rebuilder.d.ts +3 -6
- package/dist/serviceModules/Rebuilder.js +31 -22
- package/dist/serviceModules/ServiceDatabaseFileAccessBase.d.ts +5 -0
- package/dist/serviceModules/ServiceDatabaseFileAccessBase.js +69 -13
- package/dist/serviceModules/ServiceFileHandlerBase.d.ts +20 -0
- package/dist/serviceModules/ServiceFileHandlerBase.js +224 -40
- package/dist/services/BrowserServices.d.ts +2 -0
- package/dist/services/BrowserServices.js +4 -1
- package/dist/services/HeadlessServices.d.ts +2 -0
- package/dist/services/HeadlessServices.js +2 -1
- package/dist/services/base/CommonlibMessages.d.ts +318 -0
- package/dist/services/base/CommonlibMessages.js +313 -0
- package/dist/services/base/IService.d.ts +13 -6
- package/dist/services/base/KeyValueDBService.d.ts +1 -1
- package/dist/services/base/KeyValueDBService.js +3 -1
- package/dist/services/base/MessageTranslator.d.ts +5 -2
- package/dist/services/base/MessageTranslator.js +21 -0
- package/dist/services/base/ReplicationService.d.ts +4 -2
- package/dist/services/base/ReplicationService.js +11 -16
- package/dist/services/base/ServiceBase.d.ts +1 -1
- package/dist/services/base/ServiceBase.js +2 -4
- package/dist/services/base/SettingService.d.ts +17 -9
- package/dist/services/base/SettingService.js +38 -19
- package/dist/services/implements/headless/HeadlessAPIService.d.ts +3 -3
- package/dist/services/implements/headless/HeadlessAPIService.js +2 -2
- package/dist/services/implements/injectable/InjectableTweakValueService.d.ts +3 -3
- package/dist/settings.d.ts +10 -0
- package/dist/settings.js +32 -0
- package/dist/worker/bgWorker.js +1 -1
- package/docs/conflict-resolution.md +153 -0
- package/docs/development.md +106 -7
- package/docs/p2p-transport-lifecycle.md +62 -0
- package/docs/platform-storage.md +4 -0
- package/docs/proven-in-use.md +65 -0
- package/docs/releasing.md +26 -6
- package/docs/remote-configurations.md +63 -0
- package/docs/settings-lifecycle.md +85 -0
- package/package.json +17 -27
- package/dist/common/i18n.d.ts +0 -18
- package/dist/common/i18n.js +0 -7193
- package/dist/common/messages/combinedMessages.dev.d.ts +0 -7
- package/dist/common/messages/combinedMessages.dev.js +0 -44
- package/dist/common/messages/combinedMessages.prod.d.ts +0 -9264
- package/dist/common/messages/combinedMessages.prod.js +0 -9271
- package/dist/common/messages/de.d.ts +0 -297
- package/dist/common/messages/de.js +0 -7
- package/dist/common/messages/def.d.ts +0 -1119
- package/dist/common/messages/def.js +0 -7
- package/dist/common/messages/es.d.ts +0 -689
- package/dist/common/messages/es.js +0 -7
- package/dist/common/messages/fr.d.ts +0 -582
- package/dist/common/messages/fr.js +0 -7
- package/dist/common/messages/he.d.ts +0 -583
- package/dist/common/messages/he.js +0 -7
- package/dist/common/messages/ja.d.ts +0 -838
- package/dist/common/messages/ja.js +0 -7
- package/dist/common/messages/ko.d.ts +0 -800
- package/dist/common/messages/ko.js +0 -7
- package/dist/common/messages/ru.d.ts +0 -858
- package/dist/common/messages/ru.js +0 -7
- package/dist/common/messages/zh-tw.d.ts +0 -384
- package/dist/common/messages/zh-tw.js +0 -7
- package/dist/common/messages/zh.d.ts +0 -1093
- package/dist/common/messages/zh.js +0 -7
- package/dist/common/messagesJson/de.json +0 -295
- package/dist/common/messagesJson/en.json +0 -1117
- package/dist/common/messagesJson/es.json +0 -687
- package/dist/common/messagesJson/fr.json +0 -580
- package/dist/common/messagesJson/he.json +0 -581
- package/dist/common/messagesJson/ja.json +0 -836
- package/dist/common/messagesJson/ko.json +0 -798
- package/dist/common/messagesJson/ru.json +0 -856
- package/dist/common/messagesJson/zh-tw.json +0 -382
- package/dist/common/messagesJson/zh.json +0 -1091
- package/dist/common/rosetta.d.ts +0 -42
- package/dist/common/rosetta.js +0 -57
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { englishMessageTranslator } from "../services/base/MessageTranslator.js";
|
|
2
2
|
import {
|
|
3
3
|
DEFAULT_SETTINGS,
|
|
4
4
|
configurationNames
|
|
@@ -324,12 +324,12 @@ const SettingInformation = {
|
|
|
324
324
|
desc: "If this enabled, All files are handled as case-Sensitive (Previous behaviour)."
|
|
325
325
|
},
|
|
326
326
|
doNotUseFixedRevisionForChunks: {
|
|
327
|
-
name: "
|
|
328
|
-
desc: "
|
|
327
|
+
name: "Content-derived chunk revisions (obsolete setting)",
|
|
328
|
+
desc: "Chunk revisions are always derived from their content. This stored key is retained only for compatibility."
|
|
329
329
|
},
|
|
330
330
|
sendChunksBulkMaxSize: {
|
|
331
|
-
name: "Maximum size
|
|
332
|
-
desc: "MB"
|
|
331
|
+
name: "Maximum request size for manually resending chunks",
|
|
332
|
+
desc: "MB per request"
|
|
333
333
|
},
|
|
334
334
|
useAdvancedMode: {
|
|
335
335
|
name: "Enable advanced features"
|
|
@@ -399,7 +399,7 @@ const SettingInformation = {
|
|
|
399
399
|
desc: "Files with modification times greater than this value (in seconds since the Unix epoch) will not have their events reflected. Set to 0 to disable this limit."
|
|
400
400
|
}
|
|
401
401
|
};
|
|
402
|
-
function translateInfo(infoSrc, translate =
|
|
402
|
+
function translateInfo(infoSrc, translate = englishMessageTranslator) {
|
|
403
403
|
if (!infoSrc) return false;
|
|
404
404
|
const info = { ...infoSrc };
|
|
405
405
|
info.name = translate(info.name);
|
package/dist/common/types.d.ts
CHANGED
|
@@ -10,7 +10,8 @@ import { IDPrefixes, LEAF_WAIT_ONLY_REMOTE, LEAF_WAIT_TIMEOUT, LEAF_WAIT_TIMEOUT
|
|
|
10
10
|
import { AutoAccepting, type BucketSyncSetting, type ChunkSplitterVersion, type ConfigPassphraseStore, type CouchDBConnection, type E2EEAlgorithm, type EncryptionSettings, type HashAlgorithm, type HasSettings, type LocalDBSettings, type ObsidianLiveSyncSettings, type P2PConnectionInfo, type P2PSyncSetting, type PluginSyncSettingEntry, type RemoteDBSettings, type RemoteType, type RemoteTypeSettings, type SYNC_MODE } from "./models/setting.type.js";
|
|
11
11
|
import { ChunkAlgorithmNames, ChunkAlgorithms, CURRENT_SETTING_VERSION, E2EEAlgorithmNames, E2EEAlgorithms, HashAlgorithms, REMOTE_COUCHDB, REMOTE_MINIO, REMOTE_P2P, RemoteTypes, SETTING_VERSION_INITIAL, SETTING_VERSION_SUPPORT_CASE_INSENSITIVE, MODE_AUTOMATIC, MODE_PAUSED, MODE_SELECTIVE, MODE_SHINY } from "./models/setting.const.js";
|
|
12
12
|
import { PREFERRED_BASE, PREFERRED_JOURNAL_SYNC, PREFERRED_SETTING_CLOUDANT, PREFERRED_SETTING_SELF_HOSTED } from "./models/setting.const.preferred.js";
|
|
13
|
-
import { P2P_DEFAULT_SETTINGS, DEFAULT_SETTINGS } from "./models/setting.const.defaults.js";
|
|
13
|
+
import { P2P_DEFAULT_SETTINGS, DEFAULT_SETTINGS, NEW_VAULT_SETTINGS, SETTINGS_SCHEMA_DEFAULTS, createNewVaultSettings } from "./models/setting.const.defaults.js";
|
|
14
|
+
import { prepareSettingsForLoad, SettingsMigrationReviewCodes, type PreparedSettings, type SettingsMigrationReviewCode, type SettingsMigrationReviewReason, type SettingsMigrationState } from "./models/setting.lifecycle.js";
|
|
14
15
|
import { KeyIndexOfSettings } from "./models/setting.const.qr.js";
|
|
15
16
|
import type { DeviceInfo, EntryBody, EntryDoc, EntryDocResponse, EntryMilestoneInfo, EntryNodeInfo, NodeData, NodeKey } from "./models/db.definition.js";
|
|
16
17
|
import { isMetaEntry } from "./models/db.definition.js";
|
|
@@ -42,7 +43,8 @@ export type { EncryptionSettings };
|
|
|
42
43
|
export { HashAlgorithms, type HashAlgorithm, ChunkAlgorithmNames, ChunkAlgorithms, type ChunkSplitterVersion };
|
|
43
44
|
export type { RemoteDBSettings };
|
|
44
45
|
export type { ObsidianLiveSyncSettings };
|
|
45
|
-
export { DEFAULT_SETTINGS };
|
|
46
|
+
export { DEFAULT_SETTINGS, NEW_VAULT_SETTINGS, SETTINGS_SCHEMA_DEFAULTS, createNewVaultSettings };
|
|
47
|
+
export { prepareSettingsForLoad, SettingsMigrationReviewCodes, type PreparedSettings, type SettingsMigrationReviewCode, type SettingsMigrationReviewReason, type SettingsMigrationState, };
|
|
46
48
|
export { KeyIndexOfSettings };
|
|
47
49
|
export { type HasSettings };
|
|
48
50
|
export { PREFERRED_BASE, PREFERRED_SETTING_CLOUDANT, PREFERRED_SETTING_SELF_HOSTED, PREFERRED_JOURNAL_SYNC };
|
package/dist/common/types.js
CHANGED
|
@@ -67,7 +67,17 @@ import {
|
|
|
67
67
|
PREFERRED_SETTING_CLOUDANT,
|
|
68
68
|
PREFERRED_SETTING_SELF_HOSTED
|
|
69
69
|
} from "./models/setting.const.preferred.js";
|
|
70
|
-
import {
|
|
70
|
+
import {
|
|
71
|
+
P2P_DEFAULT_SETTINGS,
|
|
72
|
+
DEFAULT_SETTINGS,
|
|
73
|
+
NEW_VAULT_SETTINGS,
|
|
74
|
+
SETTINGS_SCHEMA_DEFAULTS,
|
|
75
|
+
createNewVaultSettings
|
|
76
|
+
} from "./models/setting.const.defaults.js";
|
|
77
|
+
import {
|
|
78
|
+
prepareSettingsForLoad,
|
|
79
|
+
SettingsMigrationReviewCodes
|
|
80
|
+
} from "./models/setting.lifecycle.js";
|
|
71
81
|
import { KeyIndexOfSettings } from "./models/setting.const.qr.js";
|
|
72
82
|
import { isMetaEntry } from "./models/db.definition.js";
|
|
73
83
|
import {
|
|
@@ -165,6 +175,7 @@ export {
|
|
|
165
175
|
MODE_PAUSED,
|
|
166
176
|
MODE_SELECTIVE,
|
|
167
177
|
MODE_SHINY,
|
|
178
|
+
NEW_VAULT_SETTINGS,
|
|
168
179
|
NODEINFO_DOCID,
|
|
169
180
|
NOT_CONFLICTED,
|
|
170
181
|
NoteTypes,
|
|
@@ -190,10 +201,12 @@ export {
|
|
|
190
201
|
SALT_OF_ID,
|
|
191
202
|
SALT_OF_PASSPHRASE,
|
|
192
203
|
SEED_MURMURHASH,
|
|
204
|
+
SETTINGS_SCHEMA_DEFAULTS,
|
|
193
205
|
SETTING_KEY_P2P_DEVICE_NAME,
|
|
194
206
|
SETTING_VERSION_INITIAL,
|
|
195
207
|
SETTING_VERSION_SUPPORT_CASE_INSENSITIVE,
|
|
196
208
|
SYNCINFO_ID,
|
|
209
|
+
SettingsMigrationReviewCodes,
|
|
197
210
|
SuffixDatabaseName,
|
|
198
211
|
TIME_ARGUMENT_INFINITY,
|
|
199
212
|
TweakValuesDefault,
|
|
@@ -207,6 +220,8 @@ export {
|
|
|
207
220
|
configURIBase,
|
|
208
221
|
configURIBaseQR,
|
|
209
222
|
configurationNames,
|
|
223
|
+
createNewVaultSettings,
|
|
210
224
|
isMetaEntry,
|
|
225
|
+
prepareSettingsForLoad,
|
|
211
226
|
statusDisplay
|
|
212
227
|
};
|
package/dist/context.d.ts
CHANGED
|
@@ -5,5 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { ServiceContext, createServiceContext, type ServiceContextContract, type ServiceContextOptions, } from "./services/base/ServiceBase.js";
|
|
7
7
|
export { createLiveSyncEventHub, type LiveSyncEventHub } from "./hub/hub.js";
|
|
8
|
-
export { passthroughMessageTranslator, type MessageTranslator, type TranslationParameters, } from "./services/base/MessageTranslator.js";
|
|
8
|
+
export { englishMessageTranslator, passthroughMessageTranslator, type MessageTranslator, type TranslationParameters, } from "./services/base/MessageTranslator.js";
|
|
9
|
+
export { commonlibEnglishMessages, type CommonlibMessageKey } from "./services/base/CommonlibMessages.js";
|
|
9
10
|
export type { StandardIo, StandardIoChunk } from "./platform/standardIo.js";
|
package/dist/context.js
CHANGED
|
@@ -4,11 +4,15 @@ import {
|
|
|
4
4
|
} from "./services/base/ServiceBase.js";
|
|
5
5
|
import { createLiveSyncEventHub } from "./hub/hub.js";
|
|
6
6
|
import {
|
|
7
|
+
englishMessageTranslator,
|
|
7
8
|
passthroughMessageTranslator
|
|
8
9
|
} from "./services/base/MessageTranslator.js";
|
|
10
|
+
import { commonlibEnglishMessages } from "./services/base/CommonlibMessages.js";
|
|
9
11
|
export {
|
|
10
12
|
ServiceContext,
|
|
13
|
+
commonlibEnglishMessages,
|
|
11
14
|
createLiveSyncEventHub,
|
|
12
15
|
createServiceContext,
|
|
16
|
+
englishMessageTranslator,
|
|
13
17
|
passthroughMessageTranslator
|
|
14
18
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export type ConfirmActionLayout = "auto" | "vertical";
|
|
1
2
|
export interface Confirm {
|
|
2
3
|
askYesNo(message: string): Promise<"yes" | "no">;
|
|
3
4
|
askString(title: string, key: string, placeholder: string, isPassword?: boolean): Promise<string | false>;
|
|
@@ -12,6 +13,13 @@ export interface Confirm {
|
|
|
12
13
|
defaultAction: T[number];
|
|
13
14
|
timeout?: number;
|
|
14
15
|
}): Promise<T[number] | false>;
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Shows a non-blocking message containing one host-rendered action link.
|
|
18
|
+
*
|
|
19
|
+
* Hosts which can display transient UI should keep the message visible for
|
|
20
|
+
* `durationMs`. Headless hosts may report the message without presenting an
|
|
21
|
+
* interactive action.
|
|
22
|
+
*/
|
|
23
|
+
askInPopup(key: string, dialogText: string, anchorCallback: (anchor: HTMLAnchorElement) => void, durationMs?: number): void;
|
|
24
|
+
confirmWithMessage(title: string, contentMd: string, buttons: string[], defaultAction: (typeof buttons)[number], timeout?: number, actionLayout?: ConfirmActionLayout): Promise<(typeof buttons)[number] | false>;
|
|
17
25
|
}
|
|
@@ -2,10 +2,18 @@ import type { FilePathWithPrefix, LoadedEntry, MetaEntry, UXFileInfo, UXFileInfo
|
|
|
2
2
|
export interface DatabaseFileAccess {
|
|
3
3
|
delete: (file: UXFileInfoStub | FilePathWithPrefix, rev?: string) => Promise<boolean>;
|
|
4
4
|
store: (file: UXFileInfo, force?: boolean, skipCheck?: boolean) => Promise<boolean>;
|
|
5
|
+
/** Store a file as a child of an exact revision and return the created revision. */
|
|
6
|
+
storeWithBaseRevision: (file: UXFileInfo, baseRevision: string | undefined, skipCheck?: boolean) => Promise<string | false>;
|
|
5
7
|
storeAsConflictedRevision: (file: UXFileInfo, currentRev: string, skipCheck?: boolean) => Promise<boolean>;
|
|
8
|
+
/** Preserve unknown storage content as a conflict and return its exact revision. */
|
|
9
|
+
storeAsConflictedRevisionWithResult: (file: UXFileInfo, currentRev: string, skipCheck?: boolean) => Promise<string | false>;
|
|
10
|
+
/** Store a user deletion as a visible logical-deletion child of an exact revision. */
|
|
11
|
+
storeDeletionWithBaseRevision: (file: UXFileInfoStub | FilePathWithPrefix, baseRevision: string) => Promise<string | false>;
|
|
6
12
|
storeContent(path: FilePathWithPrefix, content: string): Promise<boolean>;
|
|
7
13
|
createChunks: (file: UXFileInfo, force?: boolean, skipCheck?: boolean) => Promise<boolean>;
|
|
8
14
|
hasContentInRevisionHistory: (file: UXFileInfoStub | FilePathWithPrefix, content: string | string[] | Blob | ArrayBuffer, currentRev?: string) => Promise<boolean>;
|
|
15
|
+
/** Return every available revision whose content exactly matches the supplied bytes. */
|
|
16
|
+
findContentRevisions: (file: UXFileInfoStub | FilePathWithPrefix, content: string | string[] | Blob | ArrayBuffer, currentRev?: string) => Promise<string[]>;
|
|
9
17
|
fetch: (file: UXFileInfoStub | FilePathWithPrefix, rev?: string, waitForReady?: boolean, skipCheck?: boolean) => Promise<UXFileInfo | false>;
|
|
10
18
|
fetchEntryFromMeta: (meta: MetaEntry, waitForReady?: boolean, skipCheck?: boolean) => Promise<LoadedEntry | false>;
|
|
11
19
|
fetchEntryMeta: (file: UXFileInfoStub | FilePathWithPrefix, rev?: string, skipCheck?: boolean) => Promise<MetaEntry | false>;
|
|
@@ -4,8 +4,18 @@ export interface Rebuilder {
|
|
|
4
4
|
$rebuildEverything(): Promise<void>;
|
|
5
5
|
$fetchLocal(makeLocalChunkBeforeSync?: boolean, preventMakeLocalFilesBeforeSync?: boolean): Promise<void>;
|
|
6
6
|
$fetchLocalDBFast(autoResume: boolean): Promise<void>;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Writes the Rebuild flag, suspends the current runtime, optionally prepares
|
|
9
|
+
* persisted state, and requests a restart, in that order.
|
|
10
|
+
*
|
|
11
|
+
* The preparation callback runs only after the flag exists. If it fails,
|
|
12
|
+
* the flag is removed, the current runtime is resumed, and the error is
|
|
13
|
+
* rethrown. A false result means that the flag could not be written and no
|
|
14
|
+
* restart was requested.
|
|
15
|
+
*/
|
|
16
|
+
scheduleRebuild(prepareBeforeRestart?: () => Promise<void>): Promise<boolean>;
|
|
17
|
+
/** See {@link scheduleRebuild}; this variant writes the Fetch flag. */
|
|
18
|
+
scheduleFetch(prepareBeforeRestart?: () => Promise<void>): Promise<boolean>;
|
|
9
19
|
/**
|
|
10
20
|
* Declares the finish of the rebuild process and unlock remote, resume reflecting the changes.
|
|
11
21
|
*/
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { FilePathWithPrefix } from "../common/types.js";
|
|
2
|
+
import type { SimpleStore } from "../common/utils.js";
|
|
3
|
+
export type FileReflectionProvenanceRecord = {
|
|
4
|
+
/** Exact database revision which most recently produced the storage state. */
|
|
5
|
+
revision: string;
|
|
6
|
+
/** Raw modification time observed from this device's storage after reflection. */
|
|
7
|
+
observedStorageMtime?: number;
|
|
8
|
+
};
|
|
9
|
+
export interface FileReflectionProvenance {
|
|
10
|
+
get(path: FilePathWithPrefix): Promise<FileReflectionProvenanceRecord | undefined>;
|
|
11
|
+
set(path: FilePathWithPrefix, record: FileReflectionProvenanceRecord): Promise<void>;
|
|
12
|
+
delete(path: FilePathWithPrefix): Promise<void>;
|
|
13
|
+
move(from: FilePathWithPrefix, to: FilePathWithPrefix): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Device-local provenance backed by an existing host-owned key-value store.
|
|
17
|
+
*
|
|
18
|
+
* The revision is authoritative. The raw storage mtime is diagnostic and may
|
|
19
|
+
* be used as a fast change hint, but it never proves content or branch identity.
|
|
20
|
+
* The host may construct this object before opening its store, but it must not
|
|
21
|
+
* invoke provenance operations until its normal storage lifecycle is ready.
|
|
22
|
+
* Store failures are reported to the caller rather than hidden by readiness
|
|
23
|
+
* waits, so lifecycle violations and reset races cannot hang file processing.
|
|
24
|
+
*/
|
|
25
|
+
export declare class StoredFileReflectionProvenance implements FileReflectionProvenance {
|
|
26
|
+
private readonly store;
|
|
27
|
+
constructor(store: SimpleStore<FileReflectionProvenanceRecord>);
|
|
28
|
+
get(path: FilePathWithPrefix): Promise<FileReflectionProvenanceRecord | undefined>;
|
|
29
|
+
set(path: FilePathWithPrefix, record: FileReflectionProvenanceRecord): Promise<void>;
|
|
30
|
+
delete(path: FilePathWithPrefix): Promise<void>;
|
|
31
|
+
move(from: FilePathWithPrefix, to: FilePathWithPrefix): Promise<void>;
|
|
32
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
class StoredFileReflectionProvenance {
|
|
2
|
+
constructor(store) {
|
|
3
|
+
this.store = store;
|
|
4
|
+
}
|
|
5
|
+
store;
|
|
6
|
+
async get(path) {
|
|
7
|
+
return await this.store.get(path) ?? void 0;
|
|
8
|
+
}
|
|
9
|
+
async set(path, record) {
|
|
10
|
+
await this.store.set(path, record);
|
|
11
|
+
}
|
|
12
|
+
async delete(path) {
|
|
13
|
+
await this.store.delete(path);
|
|
14
|
+
}
|
|
15
|
+
async move(from, to) {
|
|
16
|
+
const record = await this.get(from);
|
|
17
|
+
if (record) {
|
|
18
|
+
await this.set(to, record);
|
|
19
|
+
}
|
|
20
|
+
await this.delete(from);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
StoredFileReflectionProvenance
|
|
25
|
+
};
|
|
@@ -258,13 +258,22 @@ class ConflictManager {
|
|
|
258
258
|
}
|
|
259
259
|
async tryAutoMergeSensibly(path, test, conflicts) {
|
|
260
260
|
const conflictedRev = conflicts[0];
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
261
|
+
let commonBase = "";
|
|
262
|
+
try {
|
|
263
|
+
const documentId = await this.options.pathService.path2id(path);
|
|
264
|
+
const [currentBranch, conflictedBranch] = await Promise.all([
|
|
265
|
+
this.database.get(documentId, { rev: test._rev, revs_info: true }),
|
|
266
|
+
this.database.get(documentId, { rev: conflictedRev, revs_info: true })
|
|
267
|
+
]);
|
|
268
|
+
const currentAvailable = new Set(
|
|
269
|
+
(currentBranch._revs_info || []).filter((revision) => revision.status === "available").map((revision) => revision.rev)
|
|
270
|
+
);
|
|
271
|
+
commonBase = (conflictedBranch._revs_info || []).filter((revision) => revision.status === "available" && currentAvailable.has(revision.rev)).sort((left, right) => Number(right.rev.split("-")[0]) - Number(left.rev.split("-")[0]))[0]?.rev ?? "";
|
|
272
|
+
} catch (ex) {
|
|
273
|
+
Logger(`Could not determine the common revision for ${path}`, LOG_LEVEL_VERBOSE);
|
|
274
|
+
Logger(ex, LOG_LEVEL_VERBOSE);
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
268
277
|
let p = void 0;
|
|
269
278
|
if (commonBase) {
|
|
270
279
|
if (isSensibleMargeApplicable(path)) {
|
|
@@ -33,5 +33,6 @@ export declare class EntryManager {
|
|
|
33
33
|
getDBEntry(path: FilePathWithPrefix | FilePath, opt?: PouchDB.Core.GetOptions, dump?: boolean, waitForReady?: boolean, includeDeleted?: boolean): Promise<false | LoadedEntry>;
|
|
34
34
|
getDBEntryFromMeta(meta: LoadedEntry | MetaEntry, dump?: boolean, waitForReady?: boolean): Promise<false | LoadedEntry>;
|
|
35
35
|
deleteDBEntry(path: FilePathWithPrefix | FilePath, opt?: PouchDB.Core.GetOptions): Promise<boolean>;
|
|
36
|
+
storeDeletionAtRevision(path: FilePathWithPrefix | FilePath, baseRevision: string): Promise<false | PouchDB.Core.Response>;
|
|
36
37
|
putDBEntry(note: SavingEntry, onlyChunks?: boolean, conflictBaseRev?: string): Promise<false | PouchDB.Core.Response>;
|
|
37
38
|
}
|
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
getDBEntryMetaByPath,
|
|
9
9
|
isTargetFile,
|
|
10
10
|
prepareChunk,
|
|
11
|
-
putDBEntry
|
|
11
|
+
putDBEntry,
|
|
12
|
+
storeDeletionByPathAtRevision
|
|
12
13
|
} from "./EntryManagerImpls.js";
|
|
13
14
|
class EntryManager {
|
|
14
15
|
options;
|
|
@@ -64,6 +65,9 @@ class EntryManager {
|
|
|
64
65
|
async deleteDBEntry(path, opt) {
|
|
65
66
|
return await deleteDBEntryByPath(this.serviceHost, this, path, opt);
|
|
66
67
|
}
|
|
68
|
+
async storeDeletionAtRevision(path, baseRevision) {
|
|
69
|
+
return await storeDeletionByPathAtRevision(this.serviceHost, this, path, baseRevision);
|
|
70
|
+
}
|
|
67
71
|
async putDBEntry(note, onlyChunks, conflictBaseRev) {
|
|
68
72
|
return await putDBEntry(this.serviceHost, this, note, onlyChunks, conflictBaseRev);
|
|
69
73
|
}
|
|
@@ -71,4 +71,5 @@ export declare function getDBEntryByPath(host: NecessaryServicesInterfaces<"path
|
|
|
71
71
|
datatype: import("../../common/types.js").EntryTypeNotes;
|
|
72
72
|
} & PouchDB.Core.IdMeta)>;
|
|
73
73
|
export declare function deleteDBEntryByPath(host: NecessaryServicesInterfaces<"path" | "setting", never>, { localDatabase }: NecessaryManagers<"localDatabase">, path: FilePathWithPrefix | FilePath, opt?: PouchDB.Core.GetOptions): Promise<boolean>;
|
|
74
|
+
export declare function storeDeletionByPathAtRevision(host: NecessaryServicesInterfaces<"path" | "setting", never>, { localDatabase }: NecessaryManagers<"localDatabase">, path: FilePathWithPrefix | FilePath, baseRevision: string): Promise<PouchDB.Core.Response | false>;
|
|
74
75
|
export {};
|
|
@@ -484,6 +484,33 @@ async function deleteDBEntryByPath(host, { localDatabase }, path, opt) {
|
|
|
484
484
|
throw ex;
|
|
485
485
|
}
|
|
486
486
|
}
|
|
487
|
+
async function storeDeletionByPathAtRevision(host, { localDatabase }, path, baseRevision) {
|
|
488
|
+
if (!isTargetFile(host, path)) {
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
const id = await host.services.path.path2id(path);
|
|
492
|
+
try {
|
|
493
|
+
return await serialized("file:" + path, async () => {
|
|
494
|
+
const obj = await localDatabase.get(id, {
|
|
495
|
+
rev: baseRevision
|
|
496
|
+
});
|
|
497
|
+
if (obj.type === "leaf") {
|
|
498
|
+
return false;
|
|
499
|
+
}
|
|
500
|
+
delete obj._deleted;
|
|
501
|
+
obj.deleted = true;
|
|
502
|
+
obj.mtime = Date.now();
|
|
503
|
+
const result = await localDatabase.put(obj, { force: true });
|
|
504
|
+
Logger(`Entry soft-deleted from revision: ${path} (${obj._id.substring(0, 8)}-${result.rev})`);
|
|
505
|
+
return result;
|
|
506
|
+
}) ?? false;
|
|
507
|
+
} catch (ex) {
|
|
508
|
+
if (isErrorOfMissingDoc(ex)) {
|
|
509
|
+
return false;
|
|
510
|
+
}
|
|
511
|
+
throw ex;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
487
514
|
export {
|
|
488
515
|
canUseOnDemandChunking,
|
|
489
516
|
computeChunkRetrievalMethod,
|
|
@@ -495,5 +522,6 @@ export {
|
|
|
495
522
|
isLegacyNote,
|
|
496
523
|
isTargetFile,
|
|
497
524
|
prepareChunk,
|
|
498
|
-
putDBEntry
|
|
525
|
+
putDBEntry,
|
|
526
|
+
storeDeletionByPathAtRevision
|
|
499
527
|
};
|
|
@@ -2,7 +2,12 @@ import type { UXDataWriteOptions, UXStat } from "../../common/types.js";
|
|
|
2
2
|
import type { IStorageAdapter } from "../../serviceModules/adapters/IStorageAdapter.js";
|
|
3
3
|
export type NodeStorageStat = UXStat;
|
|
4
4
|
export interface CreateNodeStorageOptions {
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* Host-selected root directory. Adapter paths are resolved relative to this root.
|
|
7
|
+
*
|
|
8
|
+
* The host owns this trust boundary. The adapter is not a filesystem sandbox against
|
|
9
|
+
* an untrusted local process which can replace path components concurrently.
|
|
10
|
+
*/
|
|
6
11
|
rootPath: string;
|
|
7
12
|
}
|
|
8
13
|
/** Rooted storage adapter backed by Node's file-system APIs. */
|
|
@@ -10,6 +15,7 @@ export declare class NodeStorageAdapter implements IStorageAdapter<NodeStorageSt
|
|
|
10
15
|
private readonly rootPath;
|
|
11
16
|
constructor(rootPath: string);
|
|
12
17
|
private resolvePath;
|
|
18
|
+
private assertNoSymbolicLinks;
|
|
13
19
|
exists(path: string): Promise<boolean>;
|
|
14
20
|
trystat(path: string): Promise<NodeStorageStat | null>;
|
|
15
21
|
stat(path: string): Promise<NodeStorageStat | null>;
|
|
@@ -20,10 +26,13 @@ export declare class NodeStorageAdapter implements IStorageAdapter<NodeStorageSt
|
|
|
20
26
|
write(path: string, data: string, options?: UXDataWriteOptions): Promise<void>;
|
|
21
27
|
writeBinary(path: string, data: ArrayBuffer, options?: UXDataWriteOptions): Promise<void>;
|
|
22
28
|
append(path: string, data: string, options?: UXDataWriteOptions): Promise<void>;
|
|
29
|
+
/** Atomically rename or move an entry without leaving the injected root. */
|
|
30
|
+
rename(sourcePath: string, targetPath: string): Promise<void>;
|
|
23
31
|
list(basePath: string): Promise<{
|
|
24
32
|
files: string[];
|
|
25
33
|
folders: string[];
|
|
26
34
|
}>;
|
|
35
|
+
private writeFile;
|
|
27
36
|
private applyTimes;
|
|
28
37
|
}
|
|
29
38
|
/** Bind a Node storage adapter to an explicitly selected root directory. */
|
|
@@ -1,16 +1,40 @@
|
|
|
1
|
+
import { constants as nodeFsConstants } from "node:fs";
|
|
1
2
|
import * as nodeFsPromises from "node:fs/promises";
|
|
2
3
|
import * as nodePath from "node:path";
|
|
3
4
|
import { validateStoragePath } from "../storagePath.js";
|
|
5
|
+
const NO_FOLLOW = nodeFsConstants.O_NOFOLLOW ?? 0;
|
|
6
|
+
class SymbolicLinkStoragePathError extends Error {
|
|
7
|
+
constructor(path) {
|
|
8
|
+
super(`Storage paths must not contain symbolic links: ${path}`);
|
|
9
|
+
this.name = "SymbolicLinkStoragePathError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
4
12
|
class NodeStorageAdapter {
|
|
13
|
+
rootPath;
|
|
5
14
|
constructor(rootPath) {
|
|
6
|
-
this.rootPath = rootPath;
|
|
15
|
+
this.rootPath = nodePath.resolve(rootPath);
|
|
7
16
|
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
17
|
+
async resolvePath(path, allowRoot = true) {
|
|
18
|
+
const fullPath = nodePath.join(this.rootPath, validateStoragePath(path, allowRoot));
|
|
19
|
+
await this.assertNoSymbolicLinks(fullPath);
|
|
20
|
+
return fullPath;
|
|
21
|
+
}
|
|
22
|
+
async assertNoSymbolicLinks(fullPath) {
|
|
23
|
+
const relativePath = nodePath.relative(this.rootPath, fullPath);
|
|
24
|
+
let currentPath = this.rootPath;
|
|
25
|
+
for (const segment of relativePath.split(nodePath.sep).filter(Boolean)) {
|
|
26
|
+
currentPath = nodePath.join(currentPath, segment);
|
|
27
|
+
try {
|
|
28
|
+
const stat = await nodeFsPromises.lstat(currentPath);
|
|
29
|
+
if (stat.isSymbolicLink()) throw new SymbolicLinkStoragePathError(currentPath);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (error.code === "ENOENT") return;
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
11
35
|
}
|
|
12
36
|
async exists(path) {
|
|
13
|
-
const fullPath = this.resolvePath(path);
|
|
37
|
+
const fullPath = await this.resolvePath(path);
|
|
14
38
|
try {
|
|
15
39
|
await nodeFsPromises.access(fullPath);
|
|
16
40
|
return true;
|
|
@@ -20,14 +44,15 @@ class NodeStorageAdapter {
|
|
|
20
44
|
}
|
|
21
45
|
async trystat(path) {
|
|
22
46
|
try {
|
|
23
|
-
const stat = await nodeFsPromises.stat(this.resolvePath(path));
|
|
47
|
+
const stat = await nodeFsPromises.stat(await this.resolvePath(path));
|
|
24
48
|
return {
|
|
25
49
|
size: stat.size,
|
|
26
50
|
mtime: Math.floor(stat.mtimeMs),
|
|
27
51
|
ctime: Math.floor(stat.ctimeMs),
|
|
28
52
|
type: stat.isDirectory() ? "folder" : "file"
|
|
29
53
|
};
|
|
30
|
-
} catch {
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (error instanceof SymbolicLinkStoragePathError) throw error;
|
|
31
56
|
return null;
|
|
32
57
|
}
|
|
33
58
|
}
|
|
@@ -35,10 +60,12 @@ class NodeStorageAdapter {
|
|
|
35
60
|
return await this.trystat(path);
|
|
36
61
|
}
|
|
37
62
|
async mkdir(path) {
|
|
38
|
-
await
|
|
63
|
+
const fullPath = await this.resolvePath(path);
|
|
64
|
+
await nodeFsPromises.mkdir(fullPath, { recursive: true });
|
|
65
|
+
await this.assertNoSymbolicLinks(fullPath);
|
|
39
66
|
}
|
|
40
67
|
async remove(path) {
|
|
41
|
-
const fullPath = this.resolvePath(path, false);
|
|
68
|
+
const fullPath = await this.resolvePath(path, false);
|
|
42
69
|
const stat = await nodeFsPromises.stat(fullPath);
|
|
43
70
|
if (stat.isDirectory()) {
|
|
44
71
|
await nodeFsPromises.rm(fullPath, { recursive: true, force: true });
|
|
@@ -47,33 +74,55 @@ class NodeStorageAdapter {
|
|
|
47
74
|
}
|
|
48
75
|
}
|
|
49
76
|
async read(path) {
|
|
50
|
-
|
|
77
|
+
const handle = await nodeFsPromises.open(
|
|
78
|
+
await this.resolvePath(path, false),
|
|
79
|
+
nodeFsConstants.O_RDONLY | NO_FOLLOW
|
|
80
|
+
);
|
|
81
|
+
try {
|
|
82
|
+
return await handle.readFile("utf-8");
|
|
83
|
+
} finally {
|
|
84
|
+
await handle.close();
|
|
85
|
+
}
|
|
51
86
|
}
|
|
52
87
|
async readBinary(path) {
|
|
53
|
-
const
|
|
54
|
-
|
|
88
|
+
const handle = await nodeFsPromises.open(
|
|
89
|
+
await this.resolvePath(path, false),
|
|
90
|
+
nodeFsConstants.O_RDONLY | NO_FOLLOW
|
|
91
|
+
);
|
|
92
|
+
try {
|
|
93
|
+
const buffer = await handle.readFile();
|
|
94
|
+
return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
|
|
95
|
+
} finally {
|
|
96
|
+
await handle.close();
|
|
97
|
+
}
|
|
55
98
|
}
|
|
56
99
|
async write(path, data, options) {
|
|
57
|
-
const fullPath = this.resolvePath(path, false);
|
|
100
|
+
const fullPath = await this.resolvePath(path, false);
|
|
58
101
|
await nodeFsPromises.mkdir(nodePath.dirname(fullPath), { recursive: true });
|
|
59
|
-
await
|
|
60
|
-
await this.applyTimes(fullPath, options);
|
|
102
|
+
await this.writeFile(fullPath, data, options, false);
|
|
61
103
|
}
|
|
62
104
|
async writeBinary(path, data, options) {
|
|
63
|
-
const fullPath = this.resolvePath(path, false);
|
|
105
|
+
const fullPath = await this.resolvePath(path, false);
|
|
64
106
|
await nodeFsPromises.mkdir(nodePath.dirname(fullPath), { recursive: true });
|
|
65
|
-
await
|
|
66
|
-
await this.applyTimes(fullPath, options);
|
|
107
|
+
await this.writeFile(fullPath, new Uint8Array(data), options, false);
|
|
67
108
|
}
|
|
68
109
|
async append(path, data, options) {
|
|
69
|
-
const fullPath = this.resolvePath(path, false);
|
|
110
|
+
const fullPath = await this.resolvePath(path, false);
|
|
70
111
|
await nodeFsPromises.mkdir(nodePath.dirname(fullPath), { recursive: true });
|
|
71
|
-
await
|
|
72
|
-
|
|
112
|
+
await this.writeFile(fullPath, data, options, true);
|
|
113
|
+
}
|
|
114
|
+
/** Atomically rename or move an entry without leaving the injected root. */
|
|
115
|
+
async rename(sourcePath, targetPath) {
|
|
116
|
+
const fullSourcePath = await this.resolvePath(sourcePath, false);
|
|
117
|
+
const fullTargetPath = await this.resolvePath(targetPath, false);
|
|
118
|
+
await nodeFsPromises.mkdir(nodePath.dirname(fullTargetPath), { recursive: true });
|
|
119
|
+
await this.assertNoSymbolicLinks(fullSourcePath);
|
|
120
|
+
await this.assertNoSymbolicLinks(fullTargetPath);
|
|
121
|
+
await nodeFsPromises.rename(fullSourcePath, fullTargetPath);
|
|
73
122
|
}
|
|
74
123
|
async list(basePath) {
|
|
75
124
|
try {
|
|
76
|
-
const entries = await nodeFsPromises.readdir(this.resolvePath(basePath), { withFileTypes: true });
|
|
125
|
+
const entries = await nodeFsPromises.readdir(await this.resolvePath(basePath), { withFileTypes: true });
|
|
77
126
|
const files = [];
|
|
78
127
|
const folders = [];
|
|
79
128
|
for (const entry of entries) {
|
|
@@ -82,15 +131,27 @@ class NodeStorageAdapter {
|
|
|
82
131
|
else if (entry.isFile()) files.push(entryPath);
|
|
83
132
|
}
|
|
84
133
|
return { files, folders };
|
|
85
|
-
} catch {
|
|
134
|
+
} catch (error) {
|
|
135
|
+
if (error instanceof SymbolicLinkStoragePathError) throw error;
|
|
86
136
|
return { files: [], folders: [] };
|
|
87
137
|
}
|
|
88
138
|
}
|
|
89
|
-
async
|
|
139
|
+
async writeFile(fullPath, data, options, append) {
|
|
140
|
+
await this.assertNoSymbolicLinks(fullPath);
|
|
141
|
+
const flags = nodeFsConstants.O_WRONLY | nodeFsConstants.O_CREAT | NO_FOLLOW | (append ? nodeFsConstants.O_APPEND : nodeFsConstants.O_TRUNC);
|
|
142
|
+
const handle = await nodeFsPromises.open(fullPath, flags, 438);
|
|
143
|
+
try {
|
|
144
|
+
await handle.writeFile(data, typeof data === "string" ? "utf-8" : void 0);
|
|
145
|
+
await this.applyTimes(handle, options);
|
|
146
|
+
} finally {
|
|
147
|
+
await handle.close();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async applyTimes(handle, options) {
|
|
90
151
|
if (!options?.mtime && !options?.ctime) return;
|
|
91
152
|
const accessTime = options.mtime ? new Date(options.mtime) : /* @__PURE__ */ new Date();
|
|
92
153
|
const modificationTime = options.mtime ? new Date(options.mtime) : /* @__PURE__ */ new Date();
|
|
93
|
-
await
|
|
154
|
+
await handle.utimes(accessTime, modificationTime);
|
|
94
155
|
}
|
|
95
156
|
}
|
|
96
157
|
function createNodeStorage({ rootPath }) {
|
|
@@ -190,6 +190,7 @@ export declare class LiveSyncLocalDB {
|
|
|
190
190
|
getDBEntry(path: FilePathWithPrefix | FilePath, opt?: PouchDB.Core.GetOptions, dump?: boolean, waitForReady?: boolean, includeDeleted?: boolean): Promise<false | LoadedEntry>;
|
|
191
191
|
getDBEntryFromMeta(meta: LoadedEntry | MetaEntry, dump?: boolean, waitForReady?: boolean): Promise<false | LoadedEntry>;
|
|
192
192
|
deleteDBEntry(path: FilePathWithPrefix | FilePath, opt?: PouchDB.Core.GetOptions): Promise<boolean>;
|
|
193
|
+
storeDeletionAtRevision(path: FilePathWithPrefix | FilePath, baseRevision: string): Promise<false | PouchDB.Core.Response>;
|
|
193
194
|
putDBEntry(note: SavingEntry, onlyChunks?: boolean, conflictBaseRev?: string): Promise<false | PouchDB.Core.Response>;
|
|
194
195
|
getConflictedDoc(path: FilePathWithPrefix, rev: string): Promise<false | diff_result_leaf>;
|
|
195
196
|
tryAutoMerge(path: FilePathWithPrefix, enableMarkdownAutoMerge: boolean): AutoMergeResult;
|
|
@@ -364,6 +364,9 @@ class LiveSyncLocalDB {
|
|
|
364
364
|
async deleteDBEntry(path, opt) {
|
|
365
365
|
return await this.managers.entryManager.deleteDBEntry(path, opt);
|
|
366
366
|
}
|
|
367
|
+
async storeDeletionAtRevision(path, baseRevision) {
|
|
368
|
+
return await this.managers.entryManager.storeDeletionAtRevision(path, baseRevision);
|
|
369
|
+
}
|
|
367
370
|
async putDBEntry(note, onlyChunks, conflictBaseRev) {
|
|
368
371
|
return await this.managers.entryManager.putDBEntry(note, onlyChunks, conflictBaseRev);
|
|
369
372
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Focused public primitives for storing and selecting multiple remote connection profiles.
|
|
3
|
+
*
|
|
4
|
+
* The compatibility fields remain available to existing hosts, but new profile-management code
|
|
5
|
+
* should use this entry point instead of importing the wider service feature module.
|
|
6
|
+
*/
|
|
7
|
+
export { activateP2PRemoteConfiguration, activateRemoteConfiguration, createRemoteConfigurationId, suggestRemoteConfigurationName, upsertRemoteConfigurationInPlace, } from "./serviceFeatures/remoteConfig.js";
|
|
8
|
+
export type { SerializableRemoteConfigurationType, UpsertRemoteConfigurationOptions, } from "./serviceFeatures/remoteConfig.js";
|
|
9
|
+
export type { RemoteConfiguration } from "./common/models/setting.type.js";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
activateP2PRemoteConfiguration,
|
|
3
|
+
activateRemoteConfiguration,
|
|
4
|
+
createRemoteConfigurationId,
|
|
5
|
+
suggestRemoteConfigurationName,
|
|
6
|
+
upsertRemoteConfigurationInPlace
|
|
7
|
+
} from "./serviceFeatures/remoteConfig.js";
|
|
8
|
+
export {
|
|
9
|
+
activateP2PRemoteConfiguration,
|
|
10
|
+
activateRemoteConfiguration,
|
|
11
|
+
createRemoteConfigurationId,
|
|
12
|
+
suggestRemoteConfigurationName,
|
|
13
|
+
upsertRemoteConfigurationInPlace
|
|
14
|
+
};
|