### Fixed

- Unexpected errors no longer occurred when the plug-in was unloaded.
- Hidden File Sync now respects selectors.
- Registering protocol-handlers now works safely without causing unexpected errors.

### Refactored
- LiveSyncManagers has now explicit dependencies.
- LiveSyncLocalDB is now responsible for LiveSyncManagers, not accepting the managers as dependencies.
    - This is to avoid circular dependencies and clarify the ownership of the managers.
- ChangeManager has been refactored. This had a potential issue, so something had been fixed, possibly.
- Some tests have been ported from Deno's test runner to Vitest to accumulate coverage.
This commit is contained in:
vorotamoroz
2026-02-26 11:30:57 +00:00
parent 392f76fd36
commit 646f8af680
5 changed files with 39 additions and 27 deletions
@@ -92,7 +92,7 @@ export class HiddenFileSync extends LiveSyncCommands {
return this.plugin.kvDB; return this.plugin.kvDB;
} }
getConflictedDoc(path: FilePathWithPrefix, rev: string) { getConflictedDoc(path: FilePathWithPrefix, rev: string) {
return this.plugin.managers.conflictManager.getConflictedDoc(path, rev); return this.localDatabase.managers.conflictManager.getConflictedDoc(path, rev);
} }
onunload() { onunload() {
this.periodicInternalFileScanProcessor?.disable(); this.periodicInternalFileScanProcessor?.disable();
@@ -244,13 +244,23 @@ export class HiddenFileSync extends LiveSyncCommands {
if (this.isThisModuleEnabled()) { if (this.isThisModuleEnabled()) {
//system file //system file
const filename = this.getPath(doc); const filename = this.getPath(doc);
if (await this.services.vault.isTargetFile(filename)) { const unprefixedPath = stripAllPrefixes(filename);
// this.procInternalFile(filename); // No need to check via vaultService
await this.processReplicationResult(doc); // if (!await this.services.vault.isTargetFile(unprefixedPath)) {
// this._log(`Skipped processing sync file:${unprefixedPath} (Not target)`, LOG_LEVEL_VERBOSE);
// return true;
// }
if (!(await this.isTargetFile(stripAllPrefixes(unprefixedPath)))) {
this._log(
`Skipped processing sync file:${unprefixedPath} (Not Hidden File Sync target)`,
LOG_LEVEL_VERBOSE
);
// We should return true, we made sure that document is a internalMetadata.
return true; return true;
} else { }
this._log(`Skipped (Not target:${filename})`, LOG_LEVEL_VERBOSE); if (!(await this.processReplicationResult(doc))) {
return false; this._log(`Failed to process sync file:${unprefixedPath}`, LOG_LEVEL_NOTICE);
// Do not yield false, this file had been processed.
} }
} }
return true; return true;
@@ -700,7 +710,7 @@ Offline Changed files: ${processFiles.length}`;
revFrom._revs_info revFrom._revs_info
?.filter((e) => e.status == "available" && Number(e.rev.split("-")[0]) < conflictedRevNo) ?.filter((e) => e.status == "available" && Number(e.rev.split("-")[0]) < conflictedRevNo)
.first()?.rev ?? ""; .first()?.rev ?? "";
const result = await this.plugin.managers.conflictManager.mergeObject( const result = await this.localDatabase.managers.conflictManager.mergeObject(
doc.path, doc.path,
commonBase, commonBase,
doc._rev, doc._rev,
+1 -1
Submodule src/lib updated: 1335a01744...29f2a6aa4f
-7
View File
@@ -239,13 +239,6 @@ export default class ObsidianLiveSyncPlugin
return this.services.database.localDatabase; return this.services.database.localDatabase;
} }
/**
* @obsolete Use services.database.managers instead. The database managers, including entry manager, revision manager, etc.
*/
get managers() {
return this.services.database.managers;
}
/** /**
* @obsolete Use services.database.localDatabase instead. Get the PouchDB database instance. Note that this is not the same as the local database instance, which is a wrapper around the PouchDB database. * @obsolete Use services.database.localDatabase instead. Get the PouchDB database instance. Note that this is not the same as the local database instance, which is a wrapper around the PouchDB database.
* @returns The PouchDB database instance. * @returns The PouchDB database instance.
+19 -11
View File
@@ -1,4 +1,4 @@
import { type ObsidianLiveSyncSettings, LOG_LEVEL_NOTICE } from "../../lib/src/common/types.ts"; import { type ObsidianLiveSyncSettings, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "../../lib/src/common/types.ts";
import { configURIBase } from "../../common/types.ts"; import { configURIBase } from "../../common/types.ts";
// import { PouchDB } from "../../lib/src/pouchdb/pouchdb-browser.js"; // import { PouchDB } from "../../lib/src/pouchdb/pouchdb-browser.js";
import { fireAndForget } from "../../lib/src/common/utils.ts"; import { fireAndForget } from "../../lib/src/common/utils.ts";
@@ -25,16 +25,24 @@ export class ModuleSetupObsidian extends AbstractModule {
private _setupManager!: SetupManager; private _setupManager!: SetupManager;
private _everyOnload(): Promise<boolean> { private _everyOnload(): Promise<boolean> {
this._setupManager = this.core.getModule(SetupManager); this._setupManager = this.core.getModule(SetupManager);
this.registerObsidianProtocolHandler("setuplivesync", async (conf: any) => { try {
if (conf.settings) { this.registerObsidianProtocolHandler("setuplivesync", async (conf: any) => {
await this._setupManager.onUseSetupURI( if (conf.settings) {
UserMode.Unknown, await this._setupManager.onUseSetupURI(
`${configURIBase}${encodeURIComponent(conf.settings)}` UserMode.Unknown,
); `${configURIBase}${encodeURIComponent(conf.settings)}`
} else if (conf.settingsQR) { );
await this._setupManager.decodeQR(conf.settingsQR); } else if (conf.settingsQR) {
} await this._setupManager.decodeQR(conf.settingsQR);
}); }
});
} catch (e) {
this._log(
"Failed to register protocol handler. This feature may not work in some environments.",
LOG_LEVEL_NOTICE
);
this._log(e, LOG_LEVEL_VERBOSE);
}
this.addCommand({ this.addCommand({
id: "livesync-setting-qr", id: "livesync-setting-qr",
name: "Show settings as a QR code", name: "Show settings as a QR code",
@@ -59,6 +59,7 @@ export class ObsidianServiceHub extends InjectableServiceHub<ObsidianServiceCont
path: path, path: path,
vault: vault, vault: vault,
setting: setting, setting: setting,
API: API,
}); });
const keyValueDB = new ObsidianKeyValueDBService(context, { const keyValueDB = new ObsidianKeyValueDBService(context, {
appLifecycle: appLifecycle, appLifecycle: appLifecycle,