feat: opt-in desktop setting to keep replication active in the background

Replication is suspended when the Obsidian window becomes hidden (document.hidden),
so LiveSync and Periodic stop syncing while minimised until the window is focused.

Add keepReplicationActiveInBackground (default off, desktop only). When enabled, the
window-visibility handler no longer suspends on hide, so replication keeps running while
minimised. Becoming visible forces a teardown before reopen (LiveSync only) so a stalled,
half-open channel is always replaced.

Includes the setting definition (src/lib submodule), a desktop-only toggle in the Sync
pane shown for LiveSync and Periodic, a docs/settings.md entry, and unit tests for the
visibility handler.
This commit is contained in:
Miguel Ferreira
2026-06-04 21:09:45 +01:00
parent 31050c9cb8
commit c78e583399
5 changed files with 220 additions and 4 deletions
@@ -11,6 +11,7 @@ import { EVENT_REQUEST_COPY_SETUP_URI, eventHub } from "../../../common/events.t
import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts";
import type { PageFunctions } from "./SettingPane.ts";
import { visibleOnly } from "./SettingPane.ts";
import { Platform } from "../../../deps.ts";
export function paneSyncSettings(
this: ObsidianLiveSyncSettingTab,
paneEl: HTMLElement,
@@ -189,6 +190,16 @@ export function paneSyncSettings(
new Setting(paneEl).setClass("wizardHidden").autoWireToggle("syncOnFileOpen", { onUpdate: onlyOnNonLiveSync });
new Setting(paneEl).setClass("wizardHidden").autoWireToggle("syncOnStart", { onUpdate: onlyOnNonLiveSync });
new Setting(paneEl).setClass("wizardHidden").autoWireToggle("syncAfterMerge", { onUpdate: onlyOnNonLiveSync });
// Desktop app only, and only for the sync modes that keep a background replication channel
// (LiveSync and Periodic). Ignored on mobile, where suspending preserves battery. The
// visibility predicate mirrors the runtime guard in ModuleObsidianEvents.
if (Platform.isDesktopApp) {
new Setting(paneEl).setClass("wizardHidden").autoWireToggle("keepReplicationActiveInBackground", {
onUpdate: visibleOnly(
() => this.isConfiguredAs("syncMode", "LIVESYNC") || this.isConfiguredAs("syncMode", "PERIODIC")
),
});
}
});
void addPanel(