Refactored, please refer updates.md

This commit is contained in:
vorotamoroz
2026-02-13 12:02:31 +00:00
parent 1b5ca9e52c
commit fb59c4a723
22 changed files with 212 additions and 158 deletions

View File

@@ -401,7 +401,6 @@ export function displayRev(rev: string) {
return `${number}-${hash.substring(0, 6)}`;
}
export function getLogLevel(showNotice: boolean) {
return showNotice ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO;
}

Submodule src/lib updated: af0189376f...532f25f947

View File

@@ -126,31 +126,31 @@ export default class ObsidianLiveSyncPlugin
new ModuleRemoteGovernor(this),
new ModuleTargetFilter(this),
new ModulePeriodicProcess(this),
// Obsidian modules
// Essential Modules
new ModuleKeyValueDB(this),
new ModuleInitializerFile(this),
new ModuleObsidianAPI(this, this),
new ModuleObsidianEvents(this, this),
new ModuleFileAccessObsidian(this, this),
new ModuleObsidianSettings(this, this),
new ModuleObsidianSettings(this),
new ModuleResolvingMismatchedTweaks(this),
new ModuleObsidianSettingsAsMarkdown(this, this),
new ModuleObsidianSettingsAsMarkdown(this),
new ModuleObsidianSettingDialogue(this, this),
new ModuleLog(this, this),
new ModuleObsidianMenu(this, this),
new ModuleObsidianMenu(this),
new ModuleRebuilder(this),
new ModuleSetupObsidian(this, this),
new ModuleSetupObsidian(this),
new ModuleObsidianDocumentHistory(this, this),
new ModuleMigration(this),
new ModuleRedFlag(this),
new ModuleInteractiveConflictResolver(this, this),
new ModuleObsidianGlobalHistory(this, this),
new ModuleCheckRemoteSize(this, this),
new ModuleCheckRemoteSize(this),
// Test and Dev Modules
new ModuleDev(this, this),
new ModuleReplicateTest(this, this),
new ModuleIntegratedTest(this, this),
new SetupManager(this, this),
new SetupManager(this),
] as (IObsidianModule | AbstractModule)[];
getModule<T extends IObsidianModule>(constructor: new (...args: any[]) => T): T {

View File

@@ -13,6 +13,11 @@ export abstract class AbstractModule {
Logger(msg, level, key);
};
addCommand = this.services.API.addCommand.bind(this.services.API);
registerView = this.services.API.registerWindow.bind(this.services.API);
addRibbonIcon = this.services.API.addRibbonIcon.bind(this.services.API);
registerObsidianProtocolHandler = this.services.API.registerProtocolHandler.bind(this.services.API);
get localDatabase() {
return this.core.localDatabase;
}

View File

@@ -10,11 +10,6 @@ export type ModuleKeys = keyof IObsidianModule;
export type ChainableModuleProps = ChainableExecuteFunction<ObsidianLiveSyncPlugin>;
export abstract class AbstractObsidianModule extends AbstractModule {
addCommand = this.services.API.addCommand.bind(this.services.API);
registerView = this.services.API.registerWindow.bind(this.services.API);
addRibbonIcon = this.services.API.addRibbonIcon.bind(this.services.API);
registerObsidianProtocolHandler = this.services.API.registerProtocolHandler.bind(this.services.API);
get app() {
return this.plugin.app;
}

View File

@@ -1,146 +1,155 @@
import { LRUCache } from "octagonal-wheels/memory/LRUCache";
import { getStoragePathFromUXFileInfo, useMemo } from "../../common/utils";
import {
LOG_LEVEL_VERBOSE,
type FilePathWithPrefix,
type ObsidianLiveSyncSettings,
type UXFileInfoStub,
} from "../../lib/src/common/types";
import { getStoragePathFromUXFileInfo } from "../../common/utils";
import { LOG_LEVEL_DEBUG, LOG_LEVEL_VERBOSE, type UXFileInfoStub } from "../../lib/src/common/types";
import { isAcceptedAll } from "../../lib/src/string_and_binary/path";
import { AbstractModule } from "../AbstractModule";
import { EVENT_REQUEST_RELOAD_SETTING_TAB, EVENT_SETTING_SAVED, eventHub } from "../../common/events";
import { isDirty } from "../../lib/src/common/utils";
import type { LiveSyncCore } from "../../main";
import { Computed } from "octagonal-wheels/dataobject/Computed";
export class ModuleTargetFilter extends AbstractModule {
reloadIgnoreFiles() {
ignoreFiles: string[] = [];
private refreshSettings() {
this.ignoreFiles = this.settings.ignoreFiles.split(",").map((e) => e.trim());
return Promise.resolve(true);
}
private _everyOnload(): Promise<boolean> {
this.reloadIgnoreFiles();
eventHub.onEvent(EVENT_SETTING_SAVED, (evt: ObsidianLiveSyncSettings) => {
this.reloadIgnoreFiles();
});
eventHub.onEvent(EVENT_REQUEST_RELOAD_SETTING_TAB, () => {
this.reloadIgnoreFiles();
});
void this.refreshSettings();
return Promise.resolve(true);
}
_markFileListPossiblyChanged(): void {
this.totalFileEventCount++;
}
totalFileEventCount = 0;
get fileListPossiblyChanged() {
if (isDirty("totalFileEventCount", this.totalFileEventCount)) {
return true;
}
return false;
}
private async _isTargetFile(file: string | UXFileInfoStub, keepFileCheckList = false) {
const fileCount = useMemo<Record<string, number>>(
{
key: "fileCount", // forceUpdate: !keepFileCheckList,
},
(ctx, prev) => {
if (keepFileCheckList && prev) return prev;
if (!keepFileCheckList && prev && !this.fileListPossiblyChanged) {
return prev;
fileCountMap = new Computed({
evaluation: (fileEventCount: number) => {
const vaultFiles = this.core.storageAccess.getFileNames().sort();
const fileCountMap: Record<string, number> = {};
for (const file of vaultFiles) {
const lc = file.toLowerCase();
if (!fileCountMap[lc]) {
fileCountMap[lc] = 1;
} else {
fileCountMap[lc]++;
}
const fileList = (ctx.get("fileList") ?? []) as FilePathWithPrefix[];
// const fileNameList = (ctx.get("fileNameList") ?? []) as FilePath[];
// const fileNames =
const vaultFiles = this.core.storageAccess.getFileNames().sort();
if (prev && vaultFiles.length == fileList.length) {
const fl3 = new Set([...fileList, ...vaultFiles]);
if (fileList.length == fl3.size && vaultFiles.length == fl3.size) {
return prev;
}
}
ctx.set("fileList", vaultFiles);
const fileCount: Record<string, number> = {};
for (const file of vaultFiles) {
const lc = file.toLowerCase();
if (!fileCount[lc]) {
fileCount[lc] = 1;
} else {
fileCount[lc]++;
}
}
return fileCount;
}
);
return fileCountMap;
},
requiresUpdate: (args, previousArgs, previousResult) => {
if (!previousResult) return true;
if (previousResult instanceof Error) return true;
if (!previousArgs) return true;
if (args[0] === previousArgs[0]) {
return false;
}
return true;
},
});
totalFileEventCount = 0;
private async _isTargetFileByFileNameDuplication(file: string | UXFileInfoStub) {
await this.fileCountMap.updateValue(this.totalFileEventCount);
const fileCountMap = this.fileCountMap.value;
if (!fileCountMap) {
this._log("File count map is not ready yet.");
return false;
}
const filepath = getStoragePathFromUXFileInfo(file);
const lc = filepath.toLowerCase();
if (this.services.vault.shouldCheckCaseInsensitively()) {
if (lc in fileCount && fileCount[lc] > 1) {
if (lc in fileCountMap && fileCountMap[lc] > 1) {
this._log("File is duplicated (case-insensitive): " + filepath);
return false;
}
}
const fileNameLC = getStoragePathFromUXFileInfo(file).split("/").pop()?.toLowerCase();
if (this.settings.useIgnoreFiles) {
if (this.ignoreFiles.some((e) => e.toLowerCase() == fileNameLC)) {
// We must reload ignore files due to the its change.
await this.readIgnoreFile(filepath);
}
if (await this.services.vault.isIgnoredByIgnoreFile(file)) {
return false;
}
}
if (!this.localDatabase?.isTargetFile(filepath)) return false;
this._log("File is not duplicated: " + filepath, LOG_LEVEL_DEBUG);
return true;
}
ignoreFileCache = new LRUCache<string, string[] | false>(300, 250000, true);
ignoreFiles = [] as string[];
async readIgnoreFile(path: string) {
private ignoreFileCacheMap = new Map<string, string[] | undefined | false>();
private invalidateIgnoreFileCache(path: string) {
// This erases `/path/to/.ignorefile` from cache, therefore, next access will reload it.
// When detecting edited the ignore file, this method should be called.
// Do not check whether it exists in cache or not; just delete it.
const key = path.toLowerCase();
this.ignoreFileCacheMap.delete(key);
}
private async getIgnoreFile(path: string): Promise<string[] | false> {
const key = path.toLowerCase();
const cached = this.ignoreFileCacheMap.get(key);
if (cached !== undefined) {
// if cached is not undefined, cache hit (neither exists or not exists, string[] or false).
return cached;
}
try {
// this._log(`[ignore]Reading ignore file: ${path}`, LOG_LEVEL_VERBOSE);
// load the ignore file
if (!(await this.core.storageAccess.isExistsIncludeHidden(path))) {
this.ignoreFileCache.set(path, false);
// this._log(`[ignore]Ignore file not found: ${path}`, LOG_LEVEL_VERBOSE);
// file does not exist, cache as not exists
this.ignoreFileCacheMap.set(key, false);
return false;
}
const file = await this.core.storageAccess.readHiddenFileText(path);
const gitignore = file.split(/\r?\n/g);
this.ignoreFileCache.set(path, gitignore);
this._log(`[ignore]Ignore file loaded: ${path}`, LOG_LEVEL_VERBOSE);
const gitignore = file
.split(/\r?\n/g)
.map((e) => e.replace(/\r$/, ""))
.map((e) => e.trim());
this.ignoreFileCacheMap.set(key, gitignore);
this._log(`[ignore] Ignore file loaded: ${path}`, LOG_LEVEL_VERBOSE);
return gitignore;
} catch (ex) {
this._log(`[ignore]Failed to read ignore file ${path}`);
// Failed to read the ignore file, delete cache.
this._log(`[ignore] Failed to read ignore file ${path}`);
this._log(ex, LOG_LEVEL_VERBOSE);
this.ignoreFileCache.set(path, false);
this.ignoreFileCacheMap.set(key, undefined);
return false;
}
}
async getIgnoreFile(path: string) {
if (this.ignoreFileCache.has(path)) {
return this.ignoreFileCache.get(path) ?? false;
} else {
return await this.readIgnoreFile(path);
}
}
private async _isIgnoredByIgnoreFiles(file: string | UXFileInfoStub): Promise<boolean> {
if (!this.settings.useIgnoreFiles) {
return false;
}
private async _isTargetFileByLocalDB(file: string | UXFileInfoStub) {
const filepath = getStoragePathFromUXFileInfo(file);
if (this.ignoreFileCache.has(filepath)) {
// Renew
await this.readIgnoreFile(filepath);
if (!this.localDatabase?.isTargetFile(filepath)) {
this._log("File is not target by local DB: " + filepath);
return false;
}
if (!(await isAcceptedAll(filepath, this.ignoreFiles, (filename) => this.getIgnoreFile(filename)))) {
this._log("File is target by local DB: " + filepath, LOG_LEVEL_DEBUG);
return await Promise.resolve(true);
}
private async _isTargetFileFinal(file: string | UXFileInfoStub) {
this._log("File is target finally: " + getStoragePathFromUXFileInfo(file), LOG_LEVEL_DEBUG);
return await Promise.resolve(true);
}
private async _isTargetIgnoredByIgnoreFiles(file: string | UXFileInfoStub): Promise<boolean> {
if (!this.settings.useIgnoreFiles) {
return true;
}
return false;
const filepath = getStoragePathFromUXFileInfo(file);
this.invalidateIgnoreFileCache(filepath);
this._log("Checking ignore files for: " + filepath, LOG_LEVEL_DEBUG);
if (!(await isAcceptedAll(filepath, this.ignoreFiles, (filename) => this.getIgnoreFile(filename)))) {
this._log("File is ignored by ignore files: " + filepath);
return false;
}
this._log("File is not ignored by ignore files: " + filepath, LOG_LEVEL_DEBUG);
return true;
}
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
services.vault.markFileListPossiblyChanged.setHandler(this._markFileListPossiblyChanged.bind(this));
services.appLifecycle.onLoaded.addHandler(this._everyOnload.bind(this));
services.vault.isIgnoredByIgnoreFile.setHandler(this._isIgnoredByIgnoreFiles.bind(this));
services.vault.isTargetFile.setHandler(this._isTargetFile.bind(this));
services.vault.isIgnoredByIgnoreFile.setHandler(this._isTargetIgnoredByIgnoreFiles.bind(this));
services.vault.isTargetFile.addHandler(this._isTargetFileByFileNameDuplication.bind(this));
services.vault.isTargetFile.addHandler(this._isTargetIgnoredByIgnoreFiles.bind(this));
services.vault.isTargetFile.addHandler(this._isTargetFileByLocalDB.bind(this));
services.vault.isTargetFile.addHandler(this._isTargetFileFinal.bind(this));
services.setting.onSettingRealised.addHandler(this.refreshSettings.bind(this));
// services.vault.isTargetFile.use((ctx, next) => {
// const [fileName, keepFileCheckList] = ctx.args;
// const file = getS
// });
}
}

View File

@@ -56,10 +56,6 @@ export class ModuleFileAccessObsidian extends AbstractObsidianModule implements
restoreState() {
return this.vaultManager.restoreState();
}
private _everyOnload(): Promise<boolean> {
this.core.storageAccess = this;
return Promise.resolve(true);
}
async _everyOnFirstInitialize(): Promise<boolean> {
await this.vaultManager.beginWatch();
return Promise.resolve(true);
@@ -76,6 +72,7 @@ export class ModuleFileAccessObsidian extends AbstractObsidianModule implements
_everyOnloadStart(): Promise<boolean> {
this.vaultAccess = new SerializedFileAccess(this.app, this.plugin, this);
this.core.storageAccess = this;
return Promise.resolve(true);
}
@@ -379,7 +376,6 @@ export class ModuleFileAccessObsidian extends AbstractObsidianModule implements
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
services.appLifecycle.onFirstInitialise.addHandler(this._everyOnFirstInitialize.bind(this));
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
services.appLifecycle.onLoaded.addHandler(this._everyOnload.bind(this));
services.fileProcessing.commitPendingFileEvents.addHandler(this._everyCommitPendingFileEvent.bind(this));
}
}

View File

@@ -2,10 +2,10 @@ import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-w
import { sizeToHumanReadable } from "octagonal-wheels/number";
import { $msg } from "src/lib/src/common/i18n.ts";
import type { LiveSyncCore } from "../../main.ts";
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
import { EVENT_REQUEST_CHECK_REMOTE_SIZE, eventHub } from "@/common/events.ts";
import { AbstractModule } from "../AbstractModule.ts";
export class ModuleCheckRemoteSize extends AbstractObsidianModule {
export class ModuleCheckRemoteSize extends AbstractModule {
checkRemoteSize(): Promise<boolean> {
this.settings.notifyThresholdOfRemoteStorageSize = 1;
return this._allScanStat();

View File

@@ -31,13 +31,8 @@ export class ModuleObsidianEvents extends AbstractObsidianModule {
return Promise.resolve(true);
}
private _performRestart(): void {
this.__performAppReload();
}
__performAppReload() {
//@ts-ignore
this.app.commands.executeCommandById("app:reload");
this.services.appLifecycle.performRestart();
}
initialCallback: any;
@@ -193,6 +188,7 @@ export class ModuleObsidianEvents extends AbstractObsidianModule {
}
});
}
// TODO: separate
private _scheduleAppReload() {
if (!this.core._totalProcessingCount) {
const __tick = reactiveSource(0);
@@ -246,7 +242,6 @@ export class ModuleObsidianEvents extends AbstractObsidianModule {
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
services.appLifecycle.onLayoutReady.addHandler(this._everyOnLayoutReady.bind(this));
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
services.appLifecycle.performRestart.setHandler(this._performRestart.bind(this));
services.appLifecycle.askRestart.setHandler(this._askReload.bind(this));
services.appLifecycle.scheduleRestart.setHandler(this._scheduleAppReload.bind(this));
}

View File

@@ -1,11 +1,11 @@
import { fireAndForget } from "octagonal-wheels/promises";
import { addIcon, type Editor, type MarkdownFileInfo, type MarkdownView } from "../../deps.ts";
import { LOG_LEVEL_NOTICE, type FilePathWithPrefix } from "../../lib/src/common/types.ts";
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
import { $msg } from "src/lib/src/common/i18n.ts";
import type { LiveSyncCore } from "../../main.ts";
import { AbstractModule } from "../AbstractModule.ts";
export class ModuleObsidianMenu extends AbstractObsidianModule {
export class ModuleObsidianMenu extends AbstractModule {
_everyOnloadStart(): Promise<boolean> {
// UI
addIcon(
@@ -105,16 +105,8 @@ export class ModuleObsidianMenu extends AbstractObsidianModule {
});
return Promise.resolve(true);
}
private __onWorkspaceReady() {
void this.services.appLifecycle.onReady();
}
private _everyOnload(): Promise<boolean> {
this.app.workspace.onLayoutReady(this.__onWorkspaceReady.bind(this));
return Promise.resolve(true);
}
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
services.appLifecycle.onLoaded.addHandler(this._everyOnload.bind(this));
}
}

View File

@@ -63,8 +63,6 @@ function addLog(log: string) {
const showDebugLog = false;
export const MARK_DONE = "\u{2009}\u{2009}";
export class ModuleLog extends AbstractObsidianModule {
registerView = this.plugin.registerView.bind(this.plugin);
statusBar?: HTMLElement;
statusDiv?: HTMLElement;

View File

@@ -1,4 +1,3 @@
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
// import { PouchDB } from "../../lib/src/pouchdb/pouchdb-browser";
import { EVENT_REQUEST_RELOAD_SETTING_TAB, EVENT_SETTING_SAVED, eventHub } from "../../common/events.ts";
import {
@@ -18,7 +17,8 @@ import { getLanguage } from "@/deps.ts";
import { SUPPORTED_I18N_LANGS, type I18N_LANGS } from "../../lib/src/common/rosetta.ts";
import { decryptString, encryptString } from "@/lib/src/encryption/stringEncryption.ts";
import type { LiveSyncCore } from "../../main.ts";
export class ModuleObsidianSettings extends AbstractObsidianModule {
import { AbstractModule } from "../AbstractModule.ts";
export class ModuleObsidianSettings extends AbstractModule {
async _everyOnLayoutReady(): Promise<boolean> {
let isChanged = false;
if (this.settings.displayLanguage == "") {
@@ -105,7 +105,7 @@ export class ModuleObsidianSettings extends AbstractObsidianModule {
}
get appId() {
return `${"appId" in this.app ? this.app.appId : ""}`;
return this.services.API.getAppID();
}
async _saveSettingData() {

View File

@@ -1,4 +1,3 @@
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
// import { PouchDB } from "../../lib/src/pouchdb/pouchdb-browser";
import { isObjectDifferent } from "octagonal-wheels/object";
import { EVENT_SETTING_SAVED, eventHub } from "../../common/events";
@@ -6,9 +5,13 @@ import { fireAndForget } from "octagonal-wheels/promises";
import { DEFAULT_SETTINGS, type FilePathWithPrefix, type ObsidianLiveSyncSettings } from "../../lib/src/common/types";
import { parseYaml, stringifyYaml } from "../../deps";
import { LOG_LEVEL_DEBUG, LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
import { AbstractModule } from "../AbstractModule.ts";
import type { ServiceContext } from "@/lib/src/services/base/ServiceBase.ts";
import type { InjectableServiceHub } from "@/lib/src/services/InjectableServices.ts";
import type { LiveSyncCore } from "@/main.ts";
const SETTING_HEADER = "````yaml:livesync-setting\n";
const SETTING_FOOTER = "\n````";
export class ModuleObsidianSettingsAsMarkdown extends AbstractObsidianModule {
export class ModuleObsidianSettingsAsMarkdown extends AbstractModule {
_everyOnloadStart(): Promise<boolean> {
this.addCommand({
id: "livesync-export-config",
@@ -242,7 +245,8 @@ We can perform a command in this file.
this._log(`Markdown setting: ${filename} has been updated!`, LOG_LEVEL_VERBOSE);
}
}
onBindFunction(core: typeof this.plugin, services: typeof core.services): void {
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub<ServiceContext>): void {
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
}
}

View File

@@ -9,7 +9,6 @@ import {
EVENT_REQUEST_SHOW_SETUP_QR,
eventHub,
} from "../../common/events.ts";
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
import { $msg } from "../../lib/src/common/i18n.ts";
// import { performDoctorConsultation, RebuildOptions } from "@/lib/src/common/configForDoc.ts";
import type { LiveSyncCore } from "../../main.ts";
@@ -20,11 +19,12 @@ import {
OutputFormat,
} from "../../lib/src/API/processSetting.ts";
import { SetupManager, UserMode } from "./SetupManager.ts";
import { AbstractModule } from "../AbstractModule.ts";
export class ModuleSetupObsidian extends AbstractObsidianModule {
export class ModuleSetupObsidian extends AbstractModule {
private _setupManager!: SetupManager;
private _everyOnload(): Promise<boolean> {
this._setupManager = this.plugin.getModule(SetupManager);
this._setupManager = this.core.getModule(SetupManager);
this.registerObsidianProtocolHandler("setuplivesync", async (conf: any) => {
if (conf.settings) {
await this._setupManager.onUseSetupURI(

View File

@@ -8,7 +8,6 @@ import {
REMOTE_P2P,
} from "../../lib/src/common/types.ts";
import { generatePatchObj, isObjectDifferent } from "../../lib/src/common/utils.ts";
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
import Intro from "./SetupWizard/dialogs/Intro.svelte";
import SelectMethodNewUser from "./SetupWizard/dialogs/SelectMethodNewUser.svelte";
import SelectMethodExisting from "./SetupWizard/dialogs/SelectMethodExisting.svelte";
@@ -23,6 +22,7 @@ import SetupRemoteBucket from "./SetupWizard/dialogs/SetupRemoteBucket.svelte";
import SetupRemoteP2P from "./SetupWizard/dialogs/SetupRemoteP2P.svelte";
import SetupRemoteE2EE from "./SetupWizard/dialogs/SetupRemoteE2EE.svelte";
import { decodeSettingsFromQRCodeData } from "../../lib/src/API/processSetting.ts";
import { AbstractModule } from "../AbstractModule.ts";
/**
* User modes for onboarding and setup
@@ -50,7 +50,7 @@ export const enum UserMode {
/**
* Setup Manager to handle onboarding and configuration setup
*/
export class SetupManager extends AbstractObsidianModule {
export class SetupManager extends AbstractModule {
// /**
// * Dialog manager for handling Svelte dialogs
// */

View File

@@ -0,0 +1,21 @@
import { AppLifecycleServiceBase } from "@/lib/src/services/implements/injectable/InjectableAppLifecycleService";
import type { ObsidianServiceContext } from "@/lib/src/services/implements/obsidian/ObsidianServiceContext";
declare module "obsidian" {
interface App {
commands: {
executeCommandById: (id: string) => Promise<void>;
};
}
}
// InjectableAppLifecycleService
export class ObsidianAppLifecycleService<T extends ObsidianServiceContext> extends AppLifecycleServiceBase<T> {
constructor(context: T) {
super(context);
// The main entry point when Obsidian's workspace is ready
const onReady = this.onReady;
this.context.app.workspace.onLayoutReady(onReady);
}
performRestart(): void {
void this.context.plugin.app.commands.executeCommandById("app:reload");
}
}

View File

@@ -4,7 +4,6 @@ import type { ServiceInstances } from "@/lib/src/services/ServiceHub";
import type ObsidianLiveSyncPlugin from "@/main";
import {
ObsidianAPIService,
ObsidianAppLifecycleService,
ObsidianConflictService,
ObsidianDatabaseService,
ObsidianFileProcessingService,
@@ -17,6 +16,7 @@ import {
ObsidianDatabaseEventService,
ObsidianConfigService,
} from "./ObsidianServices";
import { ObsidianAppLifecycleService } from "./ObsidianAppLifecycleService";
import { ObsidianPathService } from "./ObsidianPathService";
import { ObsidianVaultService } from "./ObsidianVaultService";
import { ObsidianUIService } from "./ObsidianUIService";

View File

@@ -1,5 +1,4 @@
import { InjectableAPIService } from "@lib/services/implements/injectable/InjectableAPIService";
import { InjectableAppLifecycleService } from "@lib/services/implements/injectable/InjectableAppLifecycleService";
import { InjectableConflictService } from "@lib/services/implements/injectable/InjectableConflictService";
import { InjectableDatabaseEventService } from "@lib/services/implements/injectable/InjectableDatabaseEventService";
import { InjectableDatabaseService } from "@lib/services/implements/injectable/InjectableDatabaseService";
@@ -123,8 +122,6 @@ export class ObsidianReplicationService extends InjectableReplicationService<Obs
export class ObsidianRemoteService extends InjectableRemoteService<ObsidianServiceContext> {}
// InjectableConflictService
export class ObsidianConflictService extends InjectableConflictService<ObsidianServiceContext> {}
// InjectableAppLifecycleService
export class ObsidianAppLifecycleService extends InjectableAppLifecycleService<ObsidianServiceContext> {}
// InjectableSettingService
export class ObsidianSettingService extends InjectableSettingService<ObsidianServiceContext> {}
// InjectableTweakValueService