@vrtmrz/livesync-commonlib 0.1.0-rc.1 → 0.1.0-rc.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 +87 -19
- package/dist/common/i18n.js +7 -7099
- package/dist/common/messages/combinedMessages.prod.d.ts +3 -0
- package/dist/common/messages/combinedMessages.prod.js +3 -0
- package/dist/common/messages/def.d.ts +1 -0
- package/dist/common/messagesJson/en.json +1 -0
- package/dist/common/models/setting.const.defaults.d.ts +19 -0
- package/dist/common/models/setting.const.defaults.js +20 -2
- package/dist/common/models/setting.lifecycle.d.ts +31 -0
- package/dist/common/models/setting.lifecycle.js +109 -0
- package/dist/common/types.d.ts +4 -2
- package/dist/common/types.js +16 -1
- package/dist/interfaces/Confirm.d.ts +8 -1
- package/dist/interfaces/DatabaseRebuilder.d.ts +12 -2
- package/dist/remoteConfigurations.d.ts +9 -0
- package/dist/remoteConfigurations.js +14 -0
- package/dist/replication/trystero/LiveSyncTrysteroReplicator.d.ts +4 -1
- package/dist/replication/trystero/LiveSyncTrysteroReplicator.js +41 -26
- 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 +8 -6
- 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 +1 -1
- 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/remoteConfig.d.ts +37 -1
- package/dist/serviceFeatures/remoteConfig.js +90 -0
- package/dist/serviceModules/Rebuilder.d.ts +3 -2
- package/dist/serviceModules/Rebuilder.js +21 -9
- package/dist/services/base/IService.d.ts +12 -1
- package/dist/services/base/ReplicationService.d.ts +3 -1
- package/dist/services/base/ReplicationService.js +6 -1
- package/dist/services/base/SettingService.d.ts +14 -1
- package/dist/services/base/SettingService.js +35 -12
- package/dist/services/implements/headless/HeadlessAPIService.d.ts +1 -1
- package/dist/services/implements/headless/HeadlessAPIService.js +1 -1
- 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/development.md +75 -1
- package/docs/p2p-transport-lifecycle.md +52 -0
- package/docs/proven-in-use.md +55 -0
- package/docs/releasing.md +9 -5
- package/docs/remote-configurations.md +63 -0
- package/docs/settings-lifecycle.md +60 -0
- package/package.json +12 -2
|
@@ -8631,6 +8631,9 @@ export declare const allMessages: {
|
|
|
8631
8631
|
readonly def: "Welcome to Self-hosted LiveSync";
|
|
8632
8632
|
readonly zh: "欢迎使用 Self-hosted LiveSync";
|
|
8633
8633
|
};
|
|
8634
|
+
readonly "Ui.SetupWizard.Invitation.Start": {
|
|
8635
|
+
readonly def: "Start setup";
|
|
8636
|
+
};
|
|
8634
8637
|
readonly "Ui.SetupWizard.OutroAskUserMode.CompatibleOption": {
|
|
8635
8638
|
readonly def: "The remote is already set up, and the configuration is compatible (or became compatible through this operation).";
|
|
8636
8639
|
readonly zh: "远程端已配置完成,且当前配置兼容(或已通过本次操作变为兼容)。";
|
|
@@ -8635,6 +8635,9 @@ Note : le QR code n'est pas chiffr\xE9, soyez prudent en l'affichant.
|
|
|
8635
8635
|
def: "Welcome to Self-hosted LiveSync",
|
|
8636
8636
|
zh: "\u6B22\u8FCE\u4F7F\u7528 Self-hosted LiveSync"
|
|
8637
8637
|
},
|
|
8638
|
+
"Ui.SetupWizard.Invitation.Start": {
|
|
8639
|
+
def: "Start setup"
|
|
8640
|
+
},
|
|
8638
8641
|
"Ui.SetupWizard.OutroAskUserMode.CompatibleOption": {
|
|
8639
8642
|
def: "The remote is already set up, and the configuration is compatible (or became compatible through this operation).",
|
|
8640
8643
|
zh: "\u8FDC\u7A0B\u7AEF\u5DF2\u914D\u7F6E\u5B8C\u6210\uFF0C\u4E14\u5F53\u524D\u914D\u7F6E\u517C\u5BB9\uFF08\u6216\u5DF2\u901A\u8FC7\u672C\u6B21\u64CD\u4F5C\u53D8\u4E3A\u517C\u5BB9\uFF09\u3002"
|
|
@@ -1040,6 +1040,7 @@ export declare const PartialMessages: {
|
|
|
1040
1040
|
"Ui.SetupWizard.Intro.ProceedNew": string;
|
|
1041
1041
|
"Ui.SetupWizard.Intro.Question": string;
|
|
1042
1042
|
"Ui.SetupWizard.Intro.Title": string;
|
|
1043
|
+
"Ui.SetupWizard.Invitation.Start": string;
|
|
1043
1044
|
"Ui.SetupWizard.OutroAskUserMode.CompatibleOption": string;
|
|
1044
1045
|
"Ui.SetupWizard.OutroAskUserMode.CompatibleOptionDesc": string;
|
|
1045
1046
|
"Ui.SetupWizard.OutroAskUserMode.ExistingOption": string;
|
|
@@ -1039,6 +1039,7 @@
|
|
|
1039
1039
|
"Ui.SetupWizard.Intro.ProceedNew": "Yes, I want to set up a new synchronisation",
|
|
1040
1040
|
"Ui.SetupWizard.Intro.Question": "First, please select the option that best describes your current situation.",
|
|
1041
1041
|
"Ui.SetupWizard.Intro.Title": "Welcome to Self-hosted LiveSync",
|
|
1042
|
+
"Ui.SetupWizard.Invitation.Start": "Start setup",
|
|
1042
1043
|
"Ui.SetupWizard.OutroAskUserMode.CompatibleOption": "The remote is already set up, and the configuration is compatible (or became compatible through this operation).",
|
|
1043
1044
|
"Ui.SetupWizard.OutroAskUserMode.CompatibleOptionDesc": "Unless you are certain, selecting this option is risky. It assumes the server configuration is compatible with this device. If that is not the case, data loss may occur. Please make sure you understand the consequences.",
|
|
1044
1045
|
"Ui.SetupWizard.OutroAskUserMode.ExistingOption": "My remote server is already set up. I want to join this device.",
|
|
@@ -1,3 +1,22 @@
|
|
|
1
1
|
import { type ObsidianLiveSyncSettings, type P2PSyncSetting } from "./setting.type.js";
|
|
2
2
|
export declare const P2P_DEFAULT_SETTINGS: P2PSyncSetting;
|
|
3
|
+
/**
|
|
4
|
+
* Conservative fallback values used to complete stored settings.
|
|
5
|
+
*
|
|
6
|
+
* Keep these values compatible with existing installations. Defaults intended
|
|
7
|
+
* only for a newly created Vault belong in {@link NEW_VAULT_SETTINGS}.
|
|
8
|
+
*/
|
|
9
|
+
export declare const SETTINGS_SCHEMA_DEFAULTS: ObsidianLiveSyncSettings;
|
|
10
|
+
/**
|
|
11
|
+
* Initial values for a Vault which has never stored Self-hosted LiveSync settings.
|
|
12
|
+
*
|
|
13
|
+
* This object is deliberately separate from schema fallbacks so that future
|
|
14
|
+
* releases can improve new-user defaults without changing existing choices.
|
|
15
|
+
*/
|
|
16
|
+
export declare const NEW_VAULT_SETTINGS: ObsidianLiveSyncSettings;
|
|
17
|
+
/** Create an independently mutable copy of the current new-Vault settings. */
|
|
18
|
+
export declare function createNewVaultSettings(): ObsidianLiveSyncSettings;
|
|
19
|
+
/**
|
|
20
|
+
* Compatibility name for the conservative setting-schema fallbacks.
|
|
21
|
+
*/
|
|
3
22
|
export declare const DEFAULT_SETTINGS: ObsidianLiveSyncSettings;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ChunkAlgorithms, CURRENT_SETTING_VERSION, E2EEAlgorithms, REMOTE_COUCHDB } from "./setting.const.js";
|
|
2
|
+
import { PREFERRED_BASE } from "./setting.const.preferred.js";
|
|
2
3
|
import { AutoAccepting } from "./setting.type.js";
|
|
3
4
|
const P2P_DEFAULT_SETTINGS = {
|
|
4
5
|
P2P_Enabled: false,
|
|
@@ -22,7 +23,7 @@ const P2P_DEFAULT_SETTINGS = {
|
|
|
22
23
|
P2P_turnCredential: "",
|
|
23
24
|
P2P_useDiagRTC: false
|
|
24
25
|
};
|
|
25
|
-
const
|
|
26
|
+
const SETTINGS_SCHEMA_DEFAULTS = {
|
|
26
27
|
remoteType: REMOTE_COUCHDB,
|
|
27
28
|
useCustomRequestHandler: false,
|
|
28
29
|
couchDB_URI: "",
|
|
@@ -179,7 +180,24 @@ const DEFAULT_SETTINGS = {
|
|
|
179
180
|
maxMTimeForReflectEvents: 0,
|
|
180
181
|
tweakModified: void 0
|
|
181
182
|
};
|
|
183
|
+
const NEW_VAULT_SETTINGS = {
|
|
184
|
+
...SETTINGS_SCHEMA_DEFAULTS,
|
|
185
|
+
...PREFERRED_BASE,
|
|
186
|
+
remoteConfigurations: {},
|
|
187
|
+
pluginSyncExtendedSetting: {}
|
|
188
|
+
};
|
|
189
|
+
function createNewVaultSettings() {
|
|
190
|
+
return {
|
|
191
|
+
...NEW_VAULT_SETTINGS,
|
|
192
|
+
remoteConfigurations: {},
|
|
193
|
+
pluginSyncExtendedSetting: {}
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
const DEFAULT_SETTINGS = SETTINGS_SCHEMA_DEFAULTS;
|
|
182
197
|
export {
|
|
183
198
|
DEFAULT_SETTINGS,
|
|
184
|
-
|
|
199
|
+
NEW_VAULT_SETTINGS,
|
|
200
|
+
P2P_DEFAULT_SETTINGS,
|
|
201
|
+
SETTINGS_SCHEMA_DEFAULTS,
|
|
202
|
+
createNewVaultSettings
|
|
185
203
|
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ObsidianLiveSyncSettings } from "./setting.type.js";
|
|
2
|
+
export declare const SettingsMigrationReviewCodes: {
|
|
3
|
+
readonly LegacyUpdatePending: "legacy-update-review-pending";
|
|
4
|
+
readonly FutureSchema: "settings-schema-newer-than-runtime";
|
|
5
|
+
};
|
|
6
|
+
export type SettingsMigrationReviewCode = (typeof SettingsMigrationReviewCodes)[keyof typeof SettingsMigrationReviewCodes];
|
|
7
|
+
export interface SettingsMigrationReviewReason {
|
|
8
|
+
code: SettingsMigrationReviewCode;
|
|
9
|
+
fromVersion: number;
|
|
10
|
+
toVersion: number;
|
|
11
|
+
}
|
|
12
|
+
export interface SettingsMigrationState {
|
|
13
|
+
sourceVersion: number;
|
|
14
|
+
targetVersion: number;
|
|
15
|
+
isNewVault: boolean;
|
|
16
|
+
isFromFutureSchema: boolean;
|
|
17
|
+
changed: boolean;
|
|
18
|
+
requiresSyncReview: boolean;
|
|
19
|
+
reviewReasons: readonly SettingsMigrationReviewReason[];
|
|
20
|
+
}
|
|
21
|
+
export interface PreparedSettings extends SettingsMigrationState {
|
|
22
|
+
settings: ObsidianLiveSyncSettings;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Completes and migrates raw settings before services consume them.
|
|
26
|
+
*
|
|
27
|
+
* Stored settings use conservative schema fallbacks. A blank store uses the
|
|
28
|
+
* independently maintained new-Vault defaults. Explicit stored values always
|
|
29
|
+
* take precedence over both sets of defaults.
|
|
30
|
+
*/
|
|
31
|
+
export declare function prepareSettingsForLoad(storedSettings: Partial<ObsidianLiveSyncSettings> | undefined): PreparedSettings;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { createNewVaultSettings, SETTINGS_SCHEMA_DEFAULTS } from "./setting.const.defaults.js";
|
|
2
|
+
import {
|
|
3
|
+
CURRENT_SETTING_VERSION,
|
|
4
|
+
SETTING_VERSION_INITIAL,
|
|
5
|
+
SETTING_VERSION_SUPPORT_CASE_INSENSITIVE
|
|
6
|
+
} from "./setting.const.js";
|
|
7
|
+
const SettingsMigrationReviewCodes = {
|
|
8
|
+
LegacyUpdatePending: "legacy-update-review-pending",
|
|
9
|
+
FutureSchema: "settings-schema-newer-than-runtime"
|
|
10
|
+
};
|
|
11
|
+
const SETTINGS_MIGRATIONS = [
|
|
12
|
+
{
|
|
13
|
+
toVersion: SETTING_VERSION_SUPPORT_CASE_INSENSITIVE,
|
|
14
|
+
apply: (settings) => settings,
|
|
15
|
+
reviewReason: (settings, fromVersion) => settings.versionUpFlash ? {
|
|
16
|
+
code: SettingsMigrationReviewCodes.LegacyUpdatePending,
|
|
17
|
+
fromVersion,
|
|
18
|
+
toVersion: SETTING_VERSION_SUPPORT_CASE_INSENSITIVE
|
|
19
|
+
} : void 0
|
|
20
|
+
}
|
|
21
|
+
];
|
|
22
|
+
function cloneSettings(source, fallbacks) {
|
|
23
|
+
return {
|
|
24
|
+
...fallbacks,
|
|
25
|
+
...source,
|
|
26
|
+
remoteConfigurations: Object.fromEntries(
|
|
27
|
+
Object.entries(source.remoteConfigurations ?? fallbacks.remoteConfigurations).map(([id, config]) => [
|
|
28
|
+
id,
|
|
29
|
+
{ ...config }
|
|
30
|
+
])
|
|
31
|
+
),
|
|
32
|
+
pluginSyncExtendedSetting: {
|
|
33
|
+
...fallbacks.pluginSyncExtendedSetting,
|
|
34
|
+
...source.pluginSyncExtendedSetting
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function storedSettingVersion(settings) {
|
|
39
|
+
const version = settings.settingVersion;
|
|
40
|
+
return typeof version === "number" && Number.isSafeInteger(version) && version >= SETTING_VERSION_INITIAL ? version : SETTING_VERSION_INITIAL;
|
|
41
|
+
}
|
|
42
|
+
function isBlankSettings(settings) {
|
|
43
|
+
return settings === void 0 || Object.keys(settings).length === 0;
|
|
44
|
+
}
|
|
45
|
+
function prepareSettingsForLoad(storedSettings) {
|
|
46
|
+
if (isBlankSettings(storedSettings)) {
|
|
47
|
+
return {
|
|
48
|
+
settings: createNewVaultSettings(),
|
|
49
|
+
sourceVersion: CURRENT_SETTING_VERSION,
|
|
50
|
+
targetVersion: CURRENT_SETTING_VERSION,
|
|
51
|
+
isNewVault: true,
|
|
52
|
+
isFromFutureSchema: false,
|
|
53
|
+
changed: false,
|
|
54
|
+
requiresSyncReview: false,
|
|
55
|
+
reviewReasons: []
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const source = { ...storedSettings };
|
|
59
|
+
const sourceVersion = storedSettingVersion(source);
|
|
60
|
+
if (sourceVersion > CURRENT_SETTING_VERSION) {
|
|
61
|
+
const reviewReasons2 = [
|
|
62
|
+
{
|
|
63
|
+
code: SettingsMigrationReviewCodes.FutureSchema,
|
|
64
|
+
fromVersion: sourceVersion,
|
|
65
|
+
toVersion: CURRENT_SETTING_VERSION
|
|
66
|
+
}
|
|
67
|
+
];
|
|
68
|
+
return {
|
|
69
|
+
settings: cloneSettings(source, SETTINGS_SCHEMA_DEFAULTS),
|
|
70
|
+
sourceVersion,
|
|
71
|
+
targetVersion: sourceVersion,
|
|
72
|
+
isNewVault: false,
|
|
73
|
+
isFromFutureSchema: true,
|
|
74
|
+
changed: false,
|
|
75
|
+
requiresSyncReview: true,
|
|
76
|
+
reviewReasons: reviewReasons2
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
let migrated = source;
|
|
80
|
+
let targetVersion = sourceVersion;
|
|
81
|
+
const reviewReasons = [];
|
|
82
|
+
for (const migration of SETTINGS_MIGRATIONS) {
|
|
83
|
+
if (targetVersion >= migration.toVersion) continue;
|
|
84
|
+
const reason = migration.reviewReason?.(migrated, targetVersion);
|
|
85
|
+
if (reason) reviewReasons.push(reason);
|
|
86
|
+
migrated = migration.apply(migrated);
|
|
87
|
+
targetVersion = migration.toVersion;
|
|
88
|
+
migrated.settingVersion = targetVersion;
|
|
89
|
+
}
|
|
90
|
+
if (targetVersion !== CURRENT_SETTING_VERSION) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`No setting migration reaches schema ${CURRENT_SETTING_VERSION} from schema ${sourceVersion}.`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
settings: cloneSettings(migrated, SETTINGS_SCHEMA_DEFAULTS),
|
|
97
|
+
sourceVersion,
|
|
98
|
+
targetVersion,
|
|
99
|
+
isNewVault: false,
|
|
100
|
+
isFromFutureSchema: false,
|
|
101
|
+
changed: sourceVersion !== targetVersion,
|
|
102
|
+
requiresSyncReview: reviewReasons.length > 0,
|
|
103
|
+
reviewReasons
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
export {
|
|
107
|
+
SettingsMigrationReviewCodes,
|
|
108
|
+
prepareSettingsForLoad
|
|
109
|
+
};
|
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
|
};
|
|
@@ -12,6 +12,13 @@ export interface Confirm {
|
|
|
12
12
|
defaultAction: T[number];
|
|
13
13
|
timeout?: number;
|
|
14
14
|
}): Promise<T[number] | false>;
|
|
15
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Shows a non-blocking message containing one host-rendered action link.
|
|
17
|
+
*
|
|
18
|
+
* Hosts which can display transient UI should keep the message visible for
|
|
19
|
+
* `durationMs`. Headless hosts may report the message without presenting an
|
|
20
|
+
* interactive action.
|
|
21
|
+
*/
|
|
22
|
+
askInPopup(key: string, dialogText: string, anchorCallback: (anchor: HTMLAnchorElement) => void, durationMs?: number): void;
|
|
16
23
|
confirmWithMessage(title: string, contentMd: string, buttons: string[], defaultAction: (typeof buttons)[number], timeout?: number): Promise<(typeof buttons)[number] | false>;
|
|
17
24
|
}
|
|
@@ -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,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
|
+
};
|
|
@@ -18,6 +18,8 @@ export interface LiveSyncTrysteroReplicatorEnv extends LiveSyncReplicatorEnv {
|
|
|
18
18
|
export declare class LiveSyncTrysteroReplicator extends LiveSyncAbstractReplicator {
|
|
19
19
|
private _p2pHost?;
|
|
20
20
|
private _replicator?;
|
|
21
|
+
private _lifecycleOperation;
|
|
22
|
+
private _shouldBeOpen;
|
|
21
23
|
get openReplicationUI(): (showResult: boolean) => Promise<boolean | void>;
|
|
22
24
|
get rawReplicator(): TrysteroReplicator;
|
|
23
25
|
get rawHost(): P2PHost;
|
|
@@ -25,6 +27,7 @@ export declare class LiveSyncTrysteroReplicator extends LiveSyncAbstractReplicat
|
|
|
25
27
|
getReplicationPBKDF2Salt(_setting: RemoteDBSettings, _refresh?: boolean): Promise<Uint8Array<ArrayBuffer>>;
|
|
26
28
|
terminateSync(): void;
|
|
27
29
|
private _buildEnv;
|
|
30
|
+
private _enqueueLifecycleOperation;
|
|
28
31
|
open(): Promise<void>;
|
|
29
32
|
close(): Promise<void>;
|
|
30
33
|
closeReplication(): void;
|
|
@@ -36,7 +39,7 @@ export declare class LiveSyncTrysteroReplicator extends LiveSyncAbstractReplicat
|
|
|
36
39
|
onNewPeer(peer: Advertisement): Promise<void>;
|
|
37
40
|
onPeerLeaved(peerId: string): void;
|
|
38
41
|
replicateFromCommand(showResult?: boolean): Promise<void>;
|
|
39
|
-
replicateFrom(peerId: string, showNotice?: boolean): Promise<{
|
|
42
|
+
replicateFrom(peerId: string, showNotice?: boolean, skipOrdinaryReplicationPolicy?: boolean): Promise<{
|
|
40
43
|
error: any;
|
|
41
44
|
ok?: undefined;
|
|
42
45
|
} | {
|
|
@@ -18,6 +18,8 @@ import { delay } from "octagonal-wheels/promises";
|
|
|
18
18
|
class LiveSyncTrysteroReplicator extends LiveSyncAbstractReplicator {
|
|
19
19
|
_p2pHost;
|
|
20
20
|
_replicator;
|
|
21
|
+
_lifecycleOperation = Promise.resolve();
|
|
22
|
+
_shouldBeOpen = false;
|
|
21
23
|
get openReplicationUI() {
|
|
22
24
|
return this.env.openReplicationUI;
|
|
23
25
|
}
|
|
@@ -59,6 +61,7 @@ class LiveSyncTrysteroReplicator extends LiveSyncAbstractReplicator {
|
|
|
59
61
|
return services.API.confirm;
|
|
60
62
|
},
|
|
61
63
|
runFiniteReplicationActivity: (task, options) => services.replicator.runFiniteReplicationActivity(task, options),
|
|
64
|
+
canStartOrdinaryReplication: (showMessage = false) => services.replication.onCheckReplicationReady(showMessage),
|
|
62
65
|
processReplicatedDocs: async (docs) => {
|
|
63
66
|
const settings = services.setting.currentSettings();
|
|
64
67
|
if (settings.suspendParseReplicationResult) {
|
|
@@ -75,36 +78,48 @@ class LiveSyncTrysteroReplicator extends LiveSyncAbstractReplicator {
|
|
|
75
78
|
}
|
|
76
79
|
};
|
|
77
80
|
}
|
|
81
|
+
_enqueueLifecycleOperation(operation) {
|
|
82
|
+
const queued = this._lifecycleOperation.catch(() => void 0).then(operation);
|
|
83
|
+
this._lifecycleOperation = queued.catch(() => void 0);
|
|
84
|
+
return queued;
|
|
85
|
+
}
|
|
78
86
|
async open() {
|
|
79
87
|
if (!this.env.services.setting.currentSettings().P2P_Enabled) {
|
|
80
88
|
Logger(this.translate("P2P.NotEnabled"), LOG_LEVEL_NOTICE);
|
|
81
89
|
return;
|
|
82
90
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
return;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
91
|
+
this._shouldBeOpen = true;
|
|
92
|
+
await this._enqueueLifecycleOperation(async () => {
|
|
93
|
+
if (!this._shouldBeOpen) return;
|
|
94
|
+
if (this._replicator && this._p2pHost?.isServing) {
|
|
95
|
+
Logger("P2P replicator is already open.");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
const env = this._buildEnv();
|
|
100
|
+
const host = new P2PHost(env);
|
|
101
|
+
const replicator = new TrysteroReplicator(env, host);
|
|
102
|
+
this._p2pHost = host;
|
|
103
|
+
this._replicator = replicator;
|
|
104
|
+
await replicator.open();
|
|
105
|
+
} catch (e) {
|
|
106
|
+
Logger(e instanceof Error ? e.message : "Error while opening P2P connection", LOG_LEVEL_NOTICE);
|
|
107
|
+
Logger(e, LOG_LEVEL_VERBOSE);
|
|
108
|
+
this._p2pHost = void 0;
|
|
109
|
+
this._replicator = void 0;
|
|
110
|
+
}
|
|
111
|
+
});
|
|
100
112
|
}
|
|
101
113
|
async close() {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
114
|
+
this._shouldBeOpen = false;
|
|
115
|
+
await this._enqueueLifecycleOperation(async () => {
|
|
116
|
+
if (this._replicator) {
|
|
117
|
+
this._replicator.disableBroadcastChanges();
|
|
118
|
+
await this._replicator.close();
|
|
119
|
+
this._replicator = void 0;
|
|
120
|
+
}
|
|
121
|
+
this._p2pHost = void 0;
|
|
122
|
+
});
|
|
108
123
|
}
|
|
109
124
|
closeReplication() {
|
|
110
125
|
this._replicator?.disconnectFromServer();
|
|
@@ -138,11 +153,11 @@ class LiveSyncTrysteroReplicator extends LiveSyncAbstractReplicator {
|
|
|
138
153
|
{ label: "replication" }
|
|
139
154
|
);
|
|
140
155
|
}
|
|
141
|
-
async replicateFrom(peerId, showNotice = false) {
|
|
156
|
+
async replicateFrom(peerId, showNotice = false, skipOrdinaryReplicationPolicy = false) {
|
|
142
157
|
const replicator = this._replicator;
|
|
143
158
|
if (!replicator) throw new Error("P2P replicator is not open");
|
|
144
159
|
return await this.env.services.replicator.runFiniteReplicationActivity(
|
|
145
|
-
() => replicator.replicateFrom(peerId, showNotice),
|
|
160
|
+
() => skipOrdinaryReplicationPolicy ? replicator.replicateFrom(peerId, showNotice, false, true) : replicator.replicateFrom(peerId, showNotice),
|
|
146
161
|
{ label: "replication" }
|
|
147
162
|
);
|
|
148
163
|
}
|
|
@@ -303,7 +318,7 @@ class LiveSyncTrysteroReplicator extends LiveSyncAbstractReplicator {
|
|
|
303
318
|
}
|
|
304
319
|
this.env.services.setting.currentSettings().P2P_RebuildFrom = "";
|
|
305
320
|
Logger("Fetching from peer " + peerId + ".", logLevel);
|
|
306
|
-
const rep = await r.replicateFrom(peerId, showingNotice);
|
|
321
|
+
const rep = await r.replicateFrom(peerId, showingNotice, false, true);
|
|
307
322
|
if (rep.ok) {
|
|
308
323
|
Logger("P2P Fetching has been succeed from " + peerId + ".", logLevel);
|
|
309
324
|
return true;
|
|
@@ -2,11 +2,7 @@ import type { NecessaryServices } from "../../interfaces/ServiceModule.js";
|
|
|
2
2
|
import type { P2PPaneParams } from "./UseP2PReplicatorResult.js";
|
|
3
3
|
export type P2PViewFactory = (leaf: unknown) => unknown;
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* following the same middleware style as useOfflineScanner.
|
|
8
|
-
*
|
|
9
|
-
* @param viewTypeAndFactory Optional [viewType, factory] pair for registering the P2P pane view.
|
|
10
|
-
* When provided, also registers commands and ribbon icon via services.API.
|
|
5
|
+
* @deprecated Compose `useP2PReplicatorFeature` with host-specific commands
|
|
6
|
+
* and UI instead. This wrapper remains for source compatibility.
|
|
11
7
|
*/
|
|
12
8
|
export declare function useP2PReplicator(host: NecessaryServices<"API" | "appLifecycle" | "setting" | "vault" | "database" | "databaseEvents" | "keyValueDB" | "replication" | "config" | "UI" | "replicator" | "remote", never>, viewTypeAndFactory?: [viewType: string, factory: P2PViewFactory]): P2PPaneParams;
|