@vrtmrz/livesync-commonlib 0.1.44 → 0.2.0
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 +37 -4
- package/dist/API/DirectFileManipulatorV2.d.ts +2 -0
- package/dist/API/DirectFileManipulatorV2.js +3 -0
- package/dist/common/configForDoc.d.ts +1 -0
- package/dist/common/configForDoc.js +11 -1
- package/dist/common/models/db.definition.d.ts +1 -0
- package/dist/common/models/setting.const.preferred.js +1 -3
- package/dist/managers/EntryManager/EntryManagerImpls.js +3 -2
- package/dist/pouchdb/LiveSyncDBFunctions.js +4 -0
- package/dist/pouchdb/StreamingFetch.d.ts +5 -1
- package/dist/pouchdb/StreamingFetch.js +529 -65
- package/dist/replication/RemoteResource.d.ts +23 -2
- package/dist/replication/RemoteResource.js +6 -2
- package/dist/replication/couchdb/LiveSyncReplicator.d.ts +8 -0
- package/dist/replication/couchdb/LiveSyncReplicator.js +132 -1
- package/dist/replication/couchdb/fastForward.d.ts +19 -0
- package/dist/replication/couchdb/fastForward.js +119 -0
- package/dist/replication/index.d.ts +3 -1
- package/dist/replication/joinedDevices.d.ts +25 -0
- package/dist/replication/joinedDevices.js +123 -0
- package/dist/replication/journal/JournalSyncCore.d.ts +2 -1
- package/dist/replication/journal/JournalSyncCore.js +11 -1
- package/dist/replication/journal/LiveSyncJournalReplicator.d.ts +4 -0
- package/dist/replication/journal/LiveSyncJournalReplicator.js +56 -1
- package/dist/replication/journal/objectstore/JournalStorageAdapter.d.ts +3 -0
- package/dist/replication/journal/objectstore/MinioStorageAdapter.d.ts +2 -1
- package/dist/replication/journal/objectstore/MinioStorageAdapter.js +27 -1
- package/dist/replication/trystero/P2PRoomSessionOwner.d.ts +1 -1
- package/dist/replication/trystero/P2PRoomSessionOwner.js +27 -14
- package/dist/serviceModules/Rebuilder.js +41 -15
- package/dist/services/BrowserServices.d.ts +4 -2
- package/dist/services/BrowserServices.js +2 -5
- package/dist/services/HeadlessServices.d.ts +3 -0
- package/dist/services/HeadlessServices.js +2 -5
- package/dist/services/ServiceHub.d.ts +4 -4
- package/dist/services/base/IService.d.ts +10 -18
- package/dist/services/base/ReplicatorService.remoteResourceResolver.js +1 -1
- package/dist/services/base/SettingService.d.ts +8 -18
- package/dist/services/base/SettingService.js +28 -46
- package/dist/services/implements/base/SvelteDialog.d.ts +2 -2
- package/dist/services/implements/base/UIService.d.ts +2 -0
- package/dist/services/implements/base/UIService.js +5 -0
- package/dist/services/implements/injectable/InjectableServiceHub.d.ts +4 -4
- package/dist/services/implements/injectable/InjectableServices.d.ts +2 -2
- package/dist/services/implements/injectable/InjectableSettingService.d.ts +0 -3
- package/dist/services/implements/injectable/InjectableSettingService.js +0 -11
- package/dist/string_and_binary/chunks.js +7 -5
- package/dist/uiCommands.d.ts +26 -0
- package/dist/uiCommands.js +57 -0
- package/dist/worker/bgWorker.js +1 -1
- package/docs/development.md +15 -3
- package/docs/proven-in-use.md +38 -4
- package/docs/releasing.md +20 -13
- package/docs/settings-lifecycle.md +37 -5
- package/package.json +12 -17
- package/dist/services/base/ConfigService.d.ts +0 -7
- package/dist/services/base/ConfigService.js +0 -6
- package/dist/services/implements/browser/ConfigServiceBrowserCompat.d.ts +0 -16
- package/dist/services/implements/browser/ConfigServiceBrowserCompat.js +0 -23
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ValueStore, type ValueDeleter } from "@vrtmrz/value-store";
|
|
1
2
|
import { type ConfigPassphraseStore, type ObsidianLiveSyncSettings, type SettingsMigrationState } from "../../common/types.js";
|
|
2
3
|
import type { IAPIService, ISettingService } from "./IService.js";
|
|
3
4
|
import { ServiceBase, type ServiceContext } from "./ServiceBase.js";
|
|
@@ -5,6 +6,8 @@ import { createInstanceLogFunction } from "../lib/logUtils.js";
|
|
|
5
6
|
import { type PersistedSettings } from "../../common/models/setting.policy.js";
|
|
6
7
|
export interface SettingServiceDependencies {
|
|
7
8
|
APIService: IAPIService;
|
|
9
|
+
/** Host-owned exact-key storage, created once for this application instance. */
|
|
10
|
+
deviceValues: ValueStore & ValueDeleter;
|
|
8
11
|
/** Optional host hook for applying the loaded display language to its catalogue. */
|
|
9
12
|
onDisplayLanguageChanged?: (language: ObsidianLiveSyncSettings["displayLanguage"]) => void;
|
|
10
13
|
}
|
|
@@ -12,9 +15,10 @@ export declare abstract class SettingService<T extends ServiceContext = ServiceC
|
|
|
12
15
|
deviceAndVaultName: string;
|
|
13
16
|
protected APIService: IAPIService;
|
|
14
17
|
private readonly onDisplayLanguageChanged?;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
/** Exact-key device values, including legacy keys outside the Vault namespace. */
|
|
19
|
+
readonly deviceValues: ValueStore & ValueDeleter;
|
|
20
|
+
/** Device values scoped by the current Vault name and database suffix. */
|
|
21
|
+
readonly config: ValueStore & ValueDeleter;
|
|
18
22
|
_settings: ObsidianLiveSyncSettings;
|
|
19
23
|
get settings(): ObsidianLiveSyncSettings;
|
|
20
24
|
set settings(value: ObsidianLiveSyncSettings);
|
|
@@ -43,23 +47,9 @@ export declare abstract class SettingService<T extends ServiceContext = ServiceC
|
|
|
43
47
|
/**
|
|
44
48
|
* Save the current device and vault name to settings, aside from the main settings.
|
|
45
49
|
*/
|
|
46
|
-
saveDeviceAndVaultName(): void
|
|
47
|
-
/**
|
|
48
|
-
* Read an exact key from the host's device-local configuration store.
|
|
49
|
-
*
|
|
50
|
-
* Unlike the main settings document, this state is not synchronised. Callers
|
|
51
|
-
* which need Vault namespacing should normally use {@link getSmallConfig}.
|
|
52
|
-
*/
|
|
53
|
-
getDeviceLocalConfig(key: string): string | null;
|
|
54
|
-
/** Store an exact key in the host's non-synchronised configuration store. */
|
|
55
|
-
setDeviceLocalConfig(key: string, value: string): void;
|
|
56
|
-
/** Delete an exact key from the host's non-synchronised configuration store. */
|
|
57
|
-
deleteDeviceLocalConfig(key: string): void;
|
|
50
|
+
saveDeviceAndVaultName(): Promise<void>;
|
|
58
51
|
private additionalSuffixOfDatabaseName;
|
|
59
52
|
private getKey;
|
|
60
|
-
setSmallConfig(key: string, value: string): void;
|
|
61
|
-
getSmallConfig(key: string): string;
|
|
62
|
-
deleteSmallConfig(key: string): void;
|
|
63
53
|
/**
|
|
64
54
|
* Save the current settings to storage.
|
|
65
55
|
*/
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createDeletableValueStore } from "@vrtmrz/value-store";
|
|
1
2
|
import {
|
|
2
3
|
ChunkAlgorithmNames,
|
|
3
4
|
LOG_LEVEL_NOTICE,
|
|
@@ -42,6 +43,10 @@ class SettingService extends ServiceBase {
|
|
|
42
43
|
deviceAndVaultName = "";
|
|
43
44
|
APIService;
|
|
44
45
|
onDisplayLanguageChanged;
|
|
46
|
+
/** Exact-key device values, including legacy keys outside the Vault namespace. */
|
|
47
|
+
deviceValues;
|
|
48
|
+
/** Device values scoped by the current Vault name and database suffix. */
|
|
49
|
+
config;
|
|
45
50
|
_settings;
|
|
46
51
|
get settings() {
|
|
47
52
|
return this._settings;
|
|
@@ -59,6 +64,12 @@ class SettingService extends ServiceBase {
|
|
|
59
64
|
constructor(context, dependencies) {
|
|
60
65
|
super(context);
|
|
61
66
|
this.APIService = dependencies.APIService;
|
|
67
|
+
this.deviceValues = dependencies.deviceValues;
|
|
68
|
+
this.config = createDeletableValueStore({
|
|
69
|
+
get: (key) => this.deviceValues.getValue(this.getKey(key)),
|
|
70
|
+
set: (key, value) => this.deviceValues.setValue(this.getKey(key), value),
|
|
71
|
+
delete: (key) => this.deviceValues.delete(this.getKey(key))
|
|
72
|
+
});
|
|
62
73
|
this.onDisplayLanguageChanged = dependencies.onDisplayLanguageChanged;
|
|
63
74
|
this._log = createInstanceLogFunction("SettingService", this.APIService);
|
|
64
75
|
}
|
|
@@ -111,26 +122,9 @@ class SettingService extends ServiceBase {
|
|
|
111
122
|
/**
|
|
112
123
|
* Save the current device and vault name to settings, aside from the main settings.
|
|
113
124
|
*/
|
|
114
|
-
saveDeviceAndVaultName() {
|
|
125
|
+
async saveDeviceAndVaultName() {
|
|
115
126
|
const lsKey = "obsidian-live-sync-vaultanddevicename-" + this.APIService.getSystemVaultName() + this.additionalSuffixOfDatabaseName();
|
|
116
|
-
this.
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Read an exact key from the host's device-local configuration store.
|
|
120
|
-
*
|
|
121
|
-
* Unlike the main settings document, this state is not synchronised. Callers
|
|
122
|
-
* which need Vault namespacing should normally use {@link getSmallConfig}.
|
|
123
|
-
*/
|
|
124
|
-
getDeviceLocalConfig(key) {
|
|
125
|
-
return this.getItem(key);
|
|
126
|
-
}
|
|
127
|
-
/** Store an exact key in the host's non-synchronised configuration store. */
|
|
128
|
-
setDeviceLocalConfig(key, value) {
|
|
129
|
-
this.setItem(key, value);
|
|
130
|
-
}
|
|
131
|
-
/** Delete an exact key from the host's non-synchronised configuration store. */
|
|
132
|
-
deleteDeviceLocalConfig(key) {
|
|
133
|
-
this.deleteItem(key);
|
|
127
|
+
await this.deviceValues.setValue(lsKey, this.deviceAndVaultName);
|
|
134
128
|
}
|
|
135
129
|
additionalSuffixOfDatabaseName() {
|
|
136
130
|
const suffix = this.settings?.additionalSuffixOfDatabaseName;
|
|
@@ -145,18 +139,6 @@ class SettingService extends ServiceBase {
|
|
|
145
139
|
const addSuffix = this.additionalSuffixOfDatabaseName();
|
|
146
140
|
return `${keyMain}${addSuffix}-${key}`;
|
|
147
141
|
}
|
|
148
|
-
setSmallConfig(key, value) {
|
|
149
|
-
const dbKey = this.getKey(key);
|
|
150
|
-
this.setDeviceLocalConfig(dbKey, value);
|
|
151
|
-
}
|
|
152
|
-
getSmallConfig(key) {
|
|
153
|
-
const dbKey = this.getKey(key);
|
|
154
|
-
return this.getDeviceLocalConfig(dbKey) ?? "";
|
|
155
|
-
}
|
|
156
|
-
deleteSmallConfig(key) {
|
|
157
|
-
const dbKey = this.getKey(key);
|
|
158
|
-
this.deleteDeviceLocalConfig(dbKey);
|
|
159
|
-
}
|
|
160
142
|
/**
|
|
161
143
|
* Save the current settings to storage.
|
|
162
144
|
*/
|
|
@@ -178,7 +160,7 @@ class SettingService extends ServiceBase {
|
|
|
178
160
|
if (store !== "" && store !== "LOCALSTORAGE" && store !== "ASK_AT_LAUNCH") {
|
|
179
161
|
throw new Error("The configuration passphrase storage mode is unsupported.");
|
|
180
162
|
}
|
|
181
|
-
const oldLocalKey = this.
|
|
163
|
+
const oldLocalKey = await this.deviceValues.getValue("ls-setting-passphrase");
|
|
182
164
|
const settings = this.cloneSettings(this.settings);
|
|
183
165
|
let targetKey;
|
|
184
166
|
if (store === "LOCALSTORAGE") {
|
|
@@ -196,10 +178,10 @@ class SettingService extends ServiceBase {
|
|
|
196
178
|
const prepared = await this.prepareSettingSave(settings, targetKey);
|
|
197
179
|
const changesLocalKey = store === "LOCALSTORAGE" && targetKey !== oldLocalKey;
|
|
198
180
|
try {
|
|
199
|
-
if (changesLocalKey) this.
|
|
181
|
+
if (changesLocalKey) await this.deviceValues.setValue("ls-setting-passphrase", targetKey);
|
|
200
182
|
await this.writePreparedSettings(prepared);
|
|
201
183
|
} catch (error) {
|
|
202
|
-
if (changesLocalKey) this.restoreConfigurationPassphrase(oldLocalKey, error);
|
|
184
|
+
if (changesLocalKey) await this.restoreConfigurationPassphrase(oldLocalKey, error);
|
|
203
185
|
throw error;
|
|
204
186
|
}
|
|
205
187
|
this.settings.configPassphraseStore = store;
|
|
@@ -210,10 +192,10 @@ class SettingService extends ServiceBase {
|
|
|
210
192
|
throw error;
|
|
211
193
|
});
|
|
212
194
|
}
|
|
213
|
-
restoreConfigurationPassphrase(previous, cause) {
|
|
195
|
+
async restoreConfigurationPassphrase(previous, cause) {
|
|
214
196
|
try {
|
|
215
|
-
if (previous) this.
|
|
216
|
-
else this.
|
|
197
|
+
if (previous) await this.deviceValues.setValue("ls-setting-passphrase", previous);
|
|
198
|
+
else await this.deviceValues.delete("ls-setting-passphrase");
|
|
217
199
|
} catch {
|
|
218
200
|
const message = this.context.translate("SettingService.ConfigurationPassphraseRollbackFailed");
|
|
219
201
|
this._log(message, LOG_LEVEL_URGENT);
|
|
@@ -344,9 +326,9 @@ class SettingService extends ServiceBase {
|
|
|
344
326
|
return { persisted, runtime, patch: savedPatch, passphrase: configurationPassphrase };
|
|
345
327
|
}
|
|
346
328
|
async writePreparedSettings(prepared) {
|
|
347
|
-
this.saveDeviceAndVaultName();
|
|
329
|
+
await this.saveDeviceAndVaultName();
|
|
348
330
|
if (prepared.runtime.P2P_DevicePeerName?.trim()) {
|
|
349
|
-
this.
|
|
331
|
+
await this.config.setValue(SETTING_KEY_P2P_DEVICE_NAME, prepared.runtime.P2P_DevicePeerName.trim());
|
|
350
332
|
}
|
|
351
333
|
await this.saveData(prepared.persisted);
|
|
352
334
|
}
|
|
@@ -528,7 +510,7 @@ class SettingService extends ServiceBase {
|
|
|
528
510
|
getPassphrase(settings) {
|
|
529
511
|
const methods = {
|
|
530
512
|
"": () => Promise.resolve("*"),
|
|
531
|
-
LOCALSTORAGE: () =>
|
|
513
|
+
LOCALSTORAGE: () => this.deviceValues.getValue("ls-setting-passphrase", ""),
|
|
532
514
|
ASK_AT_LAUNCH: () => this.APIService.confirm.askString(
|
|
533
515
|
this.context.translate("SettingService.ConfigurationPassphraseTitle"),
|
|
534
516
|
"passphrase",
|
|
@@ -700,7 +682,7 @@ class SettingService extends ServiceBase {
|
|
|
700
682
|
} else {
|
|
701
683
|
configuredIdKey(settings);
|
|
702
684
|
}
|
|
703
|
-
const previous = this.
|
|
685
|
+
const previous = await this.deviceValues.getValue("ls-setting-passphrase");
|
|
704
686
|
let candidate = previous || false;
|
|
705
687
|
let retry = false;
|
|
706
688
|
while (true) {
|
|
@@ -710,9 +692,9 @@ class SettingService extends ServiceBase {
|
|
|
710
692
|
if (result.verified) {
|
|
711
693
|
if (candidate !== previous) {
|
|
712
694
|
try {
|
|
713
|
-
this.
|
|
695
|
+
await this.deviceValues.setValue("ls-setting-passphrase", candidate);
|
|
714
696
|
} catch (error) {
|
|
715
|
-
this.restoreConfigurationPassphrase(previous, error);
|
|
697
|
+
await this.restoreConfigurationPassphrase(previous, error);
|
|
716
698
|
throw error;
|
|
717
699
|
}
|
|
718
700
|
}
|
|
@@ -788,9 +770,9 @@ class SettingService extends ServiceBase {
|
|
|
788
770
|
}
|
|
789
771
|
const lsKey = "obsidian-live-sync-vaultanddevicename-" + this.APIService.getSystemVaultName() + this.additionalSuffixOfDatabaseName();
|
|
790
772
|
if (this.settings.deviceAndVaultName != "") {
|
|
791
|
-
if (!this.
|
|
773
|
+
if (!await this.deviceValues.getValue(lsKey)) {
|
|
792
774
|
this.setDeviceAndVaultName(this.settings.deviceAndVaultName);
|
|
793
|
-
this.saveDeviceAndVaultName();
|
|
775
|
+
await this.saveDeviceAndVaultName();
|
|
794
776
|
this.settings.deviceAndVaultName = "";
|
|
795
777
|
}
|
|
796
778
|
}
|
|
@@ -801,7 +783,7 @@ class SettingService extends ServiceBase {
|
|
|
801
783
|
);
|
|
802
784
|
this.settings.customChunkSize = 0;
|
|
803
785
|
}
|
|
804
|
-
this.setDeviceAndVaultName(this.
|
|
786
|
+
this.setDeviceAndVaultName(await this.deviceValues.getValue(lsKey) || "");
|
|
805
787
|
if (this.getDeviceAndVaultName() == "") {
|
|
806
788
|
if (this.settings.usePluginSync) {
|
|
807
789
|
this._log("Device name missing. Disabling plug-in sync.", LOG_LEVEL_NOTICE);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { IConfigService } from "../../base/IService.js";
|
|
2
2
|
import type { AppLifecycleService } from "../../base/AppLifecycleService.js";
|
|
3
3
|
import type { ReplicatorService } from "../../base/ReplicatorService.js";
|
|
4
4
|
import type { Confirm } from "../../../interfaces/Confirm.js";
|
|
@@ -9,7 +9,7 @@ import type { Constructor } from "../../../common/utils.type.js";
|
|
|
9
9
|
export type SvelteDialogManagerDependencies<T extends ServiceContext = ServiceContext> = {
|
|
10
10
|
appLifecycle: AppLifecycleService<T>;
|
|
11
11
|
replicator: ReplicatorService<T>;
|
|
12
|
-
config:
|
|
12
|
+
config: IConfigService;
|
|
13
13
|
confirm: Confirm;
|
|
14
14
|
control: IControlService;
|
|
15
15
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Confirm } from "../../../interfaces/Confirm.js";
|
|
2
|
+
import { UICommandRegistry } from "../../../uiCommands.js";
|
|
2
3
|
import type { ComponentHasResult, SvelteDialogManager } from "./SvelteDialog.js";
|
|
3
4
|
import type { IAPIService, IUIService } from "../../base/IService.js";
|
|
4
5
|
import { ServiceBase, type ServiceContext } from "../../base/ServiceBase.js";
|
|
@@ -12,6 +13,7 @@ type DialogParams = {
|
|
|
12
13
|
dataToCopy: string;
|
|
13
14
|
};
|
|
14
15
|
export declare abstract class UIService<T extends ServiceContext = ServiceContext> extends ServiceBase<T> implements IUIService {
|
|
16
|
+
readonly commands: UICommandRegistry;
|
|
15
17
|
private _dialogManager;
|
|
16
18
|
protected _APIService: IAPIService;
|
|
17
19
|
abstract get dialogToCopy(): ComponentHasResult<DialogResult, DialogParams>;
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
import { EVENT_PLUGIN_UNLOADED } from "../../../events/coreEvents.js";
|
|
2
|
+
import { UICommandRegistry } from "../../../uiCommands.js";
|
|
1
3
|
import { ServiceBase } from "../../base/ServiceBase.js";
|
|
2
4
|
class UIService extends ServiceBase {
|
|
5
|
+
commands;
|
|
3
6
|
_dialogManager;
|
|
4
7
|
_APIService;
|
|
5
8
|
constructor(context, dependents) {
|
|
6
9
|
super(context);
|
|
10
|
+
this.commands = new UICommandRegistry();
|
|
11
|
+
this.context.events.once(EVENT_PLUGIN_UNLOADED, () => this.commands.dispose());
|
|
7
12
|
this._dialogManager = dependents.dialogManager;
|
|
8
13
|
this._APIService = dependents.APIService;
|
|
9
14
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { IConfigService } from "../../base/IService.js";
|
|
2
2
|
import { ControlService } from "../../base/ControlService.js";
|
|
3
3
|
import type { KeyValueDBService } from "../../base/KeyValueDBService.js";
|
|
4
4
|
import { PathService } from "../../base/PathService.js";
|
|
@@ -35,7 +35,7 @@ export declare class InjectableServiceHub<T extends ServiceContext = ServiceCont
|
|
|
35
35
|
protected readonly _vault: InjectableVaultService<T>;
|
|
36
36
|
protected readonly _test: InjectableTestService<T>;
|
|
37
37
|
protected readonly _ui: UIService<T>;
|
|
38
|
-
protected readonly _config:
|
|
38
|
+
protected readonly _config: IConfigService;
|
|
39
39
|
protected readonly _keyValueDB: KeyValueDBService<T>;
|
|
40
40
|
protected readonly _control: ControlService<T>;
|
|
41
41
|
get API(): InjectableAPIService<T>;
|
|
@@ -55,14 +55,14 @@ export declare class InjectableServiceHub<T extends ServiceContext = ServiceCont
|
|
|
55
55
|
get control(): ControlService<T>;
|
|
56
56
|
get keyValueDB(): KeyValueDBService<T>;
|
|
57
57
|
get UI(): UIService<T>;
|
|
58
|
-
get config():
|
|
58
|
+
get config(): IConfigService;
|
|
59
59
|
constructor(context: T, services: InjectableServiceInstances<T> & {
|
|
60
60
|
setting: SettingService<T>;
|
|
61
61
|
appLifecycle: AppLifecycleServiceBase<T>;
|
|
62
62
|
path: PathService<T>;
|
|
63
63
|
API: InjectableAPIService<T>;
|
|
64
64
|
ui: UIService<T>;
|
|
65
|
-
config:
|
|
65
|
+
config: IConfigService;
|
|
66
66
|
database: DatabaseService<T>;
|
|
67
67
|
remote: InjectableRemoteService<T>;
|
|
68
68
|
vault: InjectableVaultService<T>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import type { IConfigService } from "../../base/IService.js";
|
|
1
2
|
import { type ServiceInstances } from "../../ServiceHub.js";
|
|
2
3
|
import type { UIService } from "../base/UIService.js";
|
|
3
|
-
import type { ConfigService } from "../../base/ConfigService.js";
|
|
4
4
|
import type { ServiceContext } from "../../base/ServiceBase.js";
|
|
5
5
|
import type { InjectableAPIService } from "./InjectableAPIService.js";
|
|
6
6
|
import type { InjectableDatabaseEventService } from "./InjectableDatabaseEventService.js";
|
|
@@ -32,5 +32,5 @@ export type InjectableServiceInstances<T extends ServiceContext> = ServiceInstan
|
|
|
32
32
|
vault?: InjectableVaultService<T>;
|
|
33
33
|
test?: InjectableTestService<T>;
|
|
34
34
|
ui?: UIService<T>;
|
|
35
|
-
config?:
|
|
35
|
+
config?: IConfigService;
|
|
36
36
|
};
|
|
@@ -4,9 +4,6 @@ import type { ObsidianLiveSyncSettings } from "../../../common/types.js";
|
|
|
4
4
|
import type { PersistedSettings } from "../../../common/models/setting.policy.js";
|
|
5
5
|
export declare class InjectableSettingService<T extends ServiceContext> extends SettingService<T> {
|
|
6
6
|
constructor(context: T, dependencies: SettingServiceDependencies);
|
|
7
|
-
protected setItem(key: string, value: string): void;
|
|
8
|
-
protected getItem(key: string): string;
|
|
9
|
-
protected deleteItem(key: string): void;
|
|
10
7
|
saveData: import("../../lib/HandlerUtils.js").HandlerFunction<(data: PersistedSettings) => Promise<void>, unknown>;
|
|
11
8
|
loadData: import("../../lib/HandlerUtils.js").HandlerFunction<() => Promise<ObsidianLiveSyncSettings | undefined>, unknown>;
|
|
12
9
|
}
|
|
@@ -2,7 +2,6 @@ import { EVENT_SETTING_SAVED } from "../../../events/coreEvents.js";
|
|
|
2
2
|
import { SettingService } from "../../base/SettingService.js";
|
|
3
3
|
import { EVENT_REQUEST_RELOAD_SETTING_TAB } from "../../../events/coreEvents.js";
|
|
4
4
|
import { handlers } from "../../lib/HandlerUtils.js";
|
|
5
|
-
import { compatGlobal } from "../../../common/coreEnvFunctions.js";
|
|
6
5
|
class InjectableSettingService extends SettingService {
|
|
7
6
|
constructor(context, dependencies) {
|
|
8
7
|
super(context, dependencies);
|
|
@@ -15,16 +14,6 @@ class InjectableSettingService extends SettingService {
|
|
|
15
14
|
return Promise.resolve(true);
|
|
16
15
|
});
|
|
17
16
|
}
|
|
18
|
-
setItem(key, value) {
|
|
19
|
-
return compatGlobal.localStorage.setItem(key, value);
|
|
20
|
-
}
|
|
21
|
-
getItem(key) {
|
|
22
|
-
return compatGlobal.localStorage.getItem(key) ?? "";
|
|
23
|
-
}
|
|
24
|
-
deleteItem(key) {
|
|
25
|
-
compatGlobal.localStorage.removeItem(key);
|
|
26
|
-
}
|
|
27
|
-
// override currentSettings = handlers<SettingService<T>>().binder("currentSettings");
|
|
28
17
|
saveData = handlers().binder("saveData");
|
|
29
18
|
loadData = handlers().binder("loadData");
|
|
30
19
|
}
|
|
@@ -404,14 +404,16 @@ async function splitPiecesRabinKarp(dataSrc, absoluteMaxPieceSize, doPlainSplit,
|
|
|
404
404
|
}
|
|
405
405
|
}
|
|
406
406
|
const chunkUnitBinary = 256 * 1024;
|
|
407
|
-
const fixedAvgChunkSize = plainSplit ? chunkUnitPlain * 4 : chunkUnitBinary * 4;
|
|
408
407
|
const fixedMaxChunkSize = plainSplit ? chunkUnitPlain * 16 : chunkUnitBinary * 16;
|
|
409
|
-
const fixedMinChunkSize = plainSplit ? chunkUnitPlain * 2 : chunkUnitBinary;
|
|
410
408
|
const rkAbsoluteMaxPieceSizeFloor = 30 * 1024;
|
|
411
409
|
const effectiveAbsoluteMaxPieceSize = Math.max(absoluteMaxPieceSize, rkAbsoluteMaxPieceSizeFloor);
|
|
412
410
|
const maxChunkSize = Math.min(fixedMaxChunkSize, effectiveAbsoluteMaxPieceSize);
|
|
413
|
-
const
|
|
414
|
-
const
|
|
411
|
+
const proportionalGap = Math.max(1, Math.floor(maxChunkSize / 4));
|
|
412
|
+
const minChunkSize = Math.min(
|
|
413
|
+
Math.max(plainSplit ? chunkUnitPlain * 2 : proportionalGap, minimumChunkSize),
|
|
414
|
+
maxChunkSize
|
|
415
|
+
);
|
|
416
|
+
const avgChunkSize = plainSplit ? Math.min(Math.max(chunkUnitPlain * 4, minChunkSize), maxChunkSize) : proportionalGap;
|
|
415
417
|
const windowSize = 48;
|
|
416
418
|
const hashModulus = avgChunkSize;
|
|
417
419
|
const boundaryPattern = 1;
|
|
@@ -429,7 +431,7 @@ async function splitPiecesRabinKarp(dataSrc, absoluteMaxPieceSize, doPlainSplit,
|
|
|
429
431
|
return async function* piecesBlob() {
|
|
430
432
|
while (pos < length) {
|
|
431
433
|
const byte = buffer[pos];
|
|
432
|
-
if (pos >=
|
|
434
|
+
if (pos >= windowSize) {
|
|
433
435
|
const oldByte = buffer[pos - windowSize];
|
|
434
436
|
const oldByteTerm = Math.imul(oldByte, P_pow_w);
|
|
435
437
|
hash = hash - oldByteTerm | 0;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
declare const commandTypes: unique symbol;
|
|
2
|
+
/** An immutable declaration which associates a stable name with request and result types. */
|
|
3
|
+
export interface UICommand<Request, Result> {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly [commandTypes]?: {
|
|
6
|
+
readonly request: (value: Request) => Request;
|
|
7
|
+
readonly result: (value: Result) => Result;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
/** Declare a command without registering it in any global state. */
|
|
11
|
+
export declare function declareUICommand<Request, Result>(id: string): UICommand<Request, Result>;
|
|
12
|
+
/** Instance-owned command handlers for one host or service composition. */
|
|
13
|
+
export declare class UICommandRegistry {
|
|
14
|
+
private readonly definitions;
|
|
15
|
+
private readonly handlers;
|
|
16
|
+
private disposed;
|
|
17
|
+
register<Request, Result>(command: UICommand<Request, Result>, handler: (request: NoInfer<Request>) => NoInfer<Result> | Promise<NoInfer<Result>>): () => void;
|
|
18
|
+
invoke<Request, Result>(command: UICommand<Request, Result>, input: NoInfer<Request>): Promise<{
|
|
19
|
+
status: "handled";
|
|
20
|
+
value: Result;
|
|
21
|
+
} | {
|
|
22
|
+
status: "unavailable";
|
|
23
|
+
}>;
|
|
24
|
+
dispose(): void;
|
|
25
|
+
}
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
function declareUICommand(id) {
|
|
2
|
+
return Object.freeze({ id });
|
|
3
|
+
}
|
|
4
|
+
class UICommandRegistry {
|
|
5
|
+
definitions = /* @__PURE__ */ new Map();
|
|
6
|
+
handlers = /* @__PURE__ */ new Map();
|
|
7
|
+
disposed = false;
|
|
8
|
+
register(command, handler) {
|
|
9
|
+
if (this.disposed) {
|
|
10
|
+
throw new Error("Cannot register a UI command on a disposed registry");
|
|
11
|
+
}
|
|
12
|
+
const knownDefinition = this.definitions.get(command.id);
|
|
13
|
+
if (knownDefinition !== void 0 && knownDefinition !== command) {
|
|
14
|
+
throw new Error(`A conflicting command definition is already known for '${command.id}'`);
|
|
15
|
+
}
|
|
16
|
+
if (this.handlers.has(command.id)) {
|
|
17
|
+
throw new Error(`A handler is already registered for '${command.id}'`);
|
|
18
|
+
}
|
|
19
|
+
this.definitions.set(command.id, command);
|
|
20
|
+
const entry = {
|
|
21
|
+
command,
|
|
22
|
+
handler: (input) => handler(input)
|
|
23
|
+
};
|
|
24
|
+
this.handlers.set(command.id, entry);
|
|
25
|
+
let active = true;
|
|
26
|
+
return () => {
|
|
27
|
+
if (!active) return;
|
|
28
|
+
active = false;
|
|
29
|
+
if (this.handlers.get(command.id) === entry) {
|
|
30
|
+
this.handlers.delete(command.id);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
async invoke(command, input) {
|
|
35
|
+
if (this.disposed) {
|
|
36
|
+
return { status: "unavailable" };
|
|
37
|
+
}
|
|
38
|
+
const entry = this.handlers.get(command.id);
|
|
39
|
+
if (entry === void 0 || entry.command !== command) {
|
|
40
|
+
return { status: "unavailable" };
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
status: "handled",
|
|
44
|
+
value: await entry.handler(input)
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
dispose() {
|
|
48
|
+
if (this.disposed) return;
|
|
49
|
+
this.disposed = true;
|
|
50
|
+
this.handlers.clear();
|
|
51
|
+
this.definitions.clear();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export {
|
|
55
|
+
UICommandRegistry,
|
|
56
|
+
declareUICommand
|
|
57
|
+
};
|