@vrtmrz/livesync-commonlib 0.1.0-rc.0 → 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 +101 -17
- 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 +3 -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/index.d.ts +1 -0
- package/dist/platform/node/index.js +4 -0
- package/dist/platform/node/standardIo.d.ts +24 -0
- package/dist/platform/node/standardIo.js +39 -0
- package/dist/platform/node/storage.d.ts +10 -1
- package/dist/platform/node/storage.js +86 -25
- package/dist/platform/standardIo.d.ts +19 -0
- package/dist/platform/standardIo.js +0 -0
- 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 +108 -8
- package/docs/p2p-transport-lifecycle.md +62 -0
- package/docs/platform-standard-io.md +44 -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,4 +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";
|
|
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
|
};
|
|
@@ -21,3 +21,4 @@ export declare const builtinModules: readonly string[];
|
|
|
21
21
|
/** Returns whether a module specifier refers to a Node built-in. */
|
|
22
22
|
export declare const isBuiltin: typeof nodeIsBuiltin;
|
|
23
23
|
export { NodeStorageAdapter, createNodeStorage, validateStoragePath, type CreateNodeStorageOptions, type NodeStorageStat, } from "./storage.js";
|
|
24
|
+
export { createNodeStandardIo, type CreateNodeStandardIoOptions, type NodeStandardInput, type NodeStandardOutput, } from "./standardIo.js";
|
|
@@ -17,9 +17,13 @@ import {
|
|
|
17
17
|
createNodeStorage,
|
|
18
18
|
validateStoragePath
|
|
19
19
|
} from "./storage.js";
|
|
20
|
+
import {
|
|
21
|
+
createNodeStandardIo
|
|
22
|
+
} from "./standardIo.js";
|
|
20
23
|
export {
|
|
21
24
|
NodeStorageAdapter,
|
|
22
25
|
builtinModules,
|
|
26
|
+
createNodeStandardIo,
|
|
23
27
|
createNodeStorage,
|
|
24
28
|
fileURLToPath,
|
|
25
29
|
fs,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { StandardIo, StandardIoChunk } from "../standardIo.js";
|
|
2
|
+
/** Minimal readable stream shape accepted by the Node standard-I/O adapter. */
|
|
3
|
+
export type NodeStandardInput = AsyncIterable<unknown> & NodeJS.ReadableStream;
|
|
4
|
+
/** Minimal writable stream shape accepted by the Node standard-I/O adapter. */
|
|
5
|
+
export interface NodeStandardOutput extends NodeJS.WritableStream {
|
|
6
|
+
write(chunk: StandardIoChunk): boolean;
|
|
7
|
+
}
|
|
8
|
+
/** Streams used by {@link createNodeStandardIo}. */
|
|
9
|
+
export interface CreateNodeStandardIoOptions {
|
|
10
|
+
/** Defaults to `process.stdin`. */
|
|
11
|
+
stdin?: NodeStandardInput;
|
|
12
|
+
/** Defaults to `process.stdout`. */
|
|
13
|
+
stdout?: NodeStandardOutput;
|
|
14
|
+
/** Defaults to `process.stderr`. */
|
|
15
|
+
stderr?: NodeStandardOutput;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Bind the host-neutral standard-I/O contract to Node streams.
|
|
19
|
+
*
|
|
20
|
+
* Supplying streams is useful for embedded command-line hosts and tests. The
|
|
21
|
+
* caller owns stream lifecycle; this adapter only closes the temporary
|
|
22
|
+
* readline interface created by {@link StandardIo.prompt}.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createNodeStandardIo(options?: CreateNodeStandardIoOptions): StandardIo;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as nodeReadlinePromises from "node:readline/promises";
|
|
2
|
+
function createNodeStandardIo(options = {}) {
|
|
3
|
+
const stdin = options.stdin ?? process.stdin;
|
|
4
|
+
const stdout = options.stdout ?? process.stdout;
|
|
5
|
+
const stderr = options.stderr ?? process.stderr;
|
|
6
|
+
return {
|
|
7
|
+
async readStdin() {
|
|
8
|
+
const decoder = new TextDecoder();
|
|
9
|
+
let content = "";
|
|
10
|
+
for await (const chunk of stdin) {
|
|
11
|
+
if (typeof chunk === "string") {
|
|
12
|
+
content += chunk;
|
|
13
|
+
} else if (chunk instanceof Uint8Array) {
|
|
14
|
+
content += decoder.decode(chunk, { stream: true });
|
|
15
|
+
} else {
|
|
16
|
+
throw new TypeError("Standard input yielded a value which is neither text nor binary data.");
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return content + decoder.decode();
|
|
20
|
+
},
|
|
21
|
+
async prompt(question) {
|
|
22
|
+
const readline = nodeReadlinePromises.createInterface({ input: stdin, output: stdout });
|
|
23
|
+
try {
|
|
24
|
+
return await readline.question(question);
|
|
25
|
+
} finally {
|
|
26
|
+
readline.close();
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
writeStdout(chunk) {
|
|
30
|
+
stdout.write(chunk);
|
|
31
|
+
},
|
|
32
|
+
writeStderr(chunk) {
|
|
33
|
+
stderr.write(chunk);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
createNodeStandardIo
|
|
39
|
+
};
|
|
@@ -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. */
|