From 5cb76bba7205cfa380da982c5bfe68786797e326 Mon Sep 17 00:00:00 2001 From: vorotamoroz Date: Thu, 18 Jun 2026 11:57:33 +0100 Subject: [PATCH] Add annotations and fix some. --- src/apps/cli/README.md | 8 ++++---- src/apps/cli/adapters/NodeStorageAdapter.ts | 1 + src/apps/cli/adapters/NodeVaultAdapter.ts | 1 + src/apps/cli/commands/utils.ts | 1 + src/apps/cli/main.ts | 10 +++++----- src/apps/cli/node-compat.ts | 6 +++++- src/apps/webapp/README.md | 10 +++++----- src/apps/webapp/main.ts | 2 -- .../FSAPIStorageEventManagerAdapter.ts | 1 - src/apps/webpeer/src/P2PReplicatorShim.ts | 3 +-- .../CmdLocalDatabaseMainte.ts | 4 ++-- src/lib | 2 +- .../DocumentHistory/DocumentHistoryModal.ts | 4 ++++ .../ObsidianVaultAdapter.ts | 20 +++++++++---------- updates.md | 8 ++++++++ 15 files changed, 48 insertions(+), 33 deletions(-) diff --git a/src/apps/cli/README.md b/src/apps/cli/README.md index edb1043..5579ae2 100644 --- a/src/apps/cli/README.md +++ b/src/apps/cli/README.md @@ -1,17 +1,17 @@ # Self-hosted LiveSync CLI -Command-line version of Self-hosted LiveSync plugin for syncing vaults without Obsidian. +Command-line version of Self-hosted LiveSync plug-in for syncing vaults without Obsidian. ## Features - ✅ Sync Obsidian vaults using CouchDB without running Obsidian -- ✅ Compatible with Self-hosted LiveSync plugin settings +- ✅ Compatible with Self-hosted LiveSync plug-in settings - ✅ Supports all core sync features (encryption, conflict resolution, etc.) - ✅ Lightweight and headless operation - ✅ Cross-platform (Windows, macOS, Linux) ## Architecture -This CLI version is built using the same core as the Obsidian plugin: +This CLI version is built using the same core as the Obsidian plug-in: ``` CLI Main @@ -290,7 +290,7 @@ livesync-cli /path/to/your-local-database --settings /path/to/settings.json unlo ### Configuration -The CLI uses the same settings format as the Obsidian plugin. Create a `.livesync/settings.json` file in your vault directory: +The CLI uses the same settings format as the Obsidian plug-in. Create a `.livesync/settings.json` file in your vault directory: ```json { diff --git a/src/apps/cli/adapters/NodeStorageAdapter.ts b/src/apps/cli/adapters/NodeStorageAdapter.ts index c6f4992..3465037 100644 --- a/src/apps/cli/adapters/NodeStorageAdapter.ts +++ b/src/apps/cli/adapters/NodeStorageAdapter.ts @@ -60,6 +60,7 @@ export class NodeStorageAdapter implements IStorageAdapter { async readBinary(p: string): Promise { const buffer = await fs.readFile(this.resolvePath(p)); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- required in environments where Buffer.buffer is ArrayBufferLike return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength) as ArrayBuffer; } diff --git a/src/apps/cli/adapters/NodeVaultAdapter.ts b/src/apps/cli/adapters/NodeVaultAdapter.ts index deb44e5..58a179a 100644 --- a/src/apps/cli/adapters/NodeVaultAdapter.ts +++ b/src/apps/cli/adapters/NodeVaultAdapter.ts @@ -31,6 +31,7 @@ export class NodeVaultAdapter implements IVaultAdapter { const buffer = await fs.readFile(this.resolvePath(file.path)); // Same correction as read() — ensure stat.size matches actual byte length. file.stat.size = buffer.length; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- required in environments where Buffer.buffer is ArrayBufferLike return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength) as ArrayBuffer; } diff --git a/src/apps/cli/commands/utils.ts b/src/apps/cli/commands/utils.ts index abf6b19..cd9b65c 100644 --- a/src/apps/cli/commands/utils.ts +++ b/src/apps/cli/commands/utils.ts @@ -1,6 +1,7 @@ import { path, readline } from "../node-compat"; export function toArrayBuffer(data: Buffer): ArrayBuffer { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- required in environments where Buffer.buffer is ArrayBufferLike return data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength) as ArrayBuffer; } diff --git a/src/apps/cli/main.ts b/src/apps/cli/main.ts index d8c682d..58eea46 100644 --- a/src/apps/cli/main.ts +++ b/src/apps/cli/main.ts @@ -303,7 +303,7 @@ export async function main() { console.error(`Error: ${databasePath} is not a directory`); process.exit(1); } - } catch (error) { + } catch { console.error(`Error: Database directory ${databasePath} does not exist`); process.exit(1); } @@ -324,7 +324,7 @@ export async function main() { ? path.resolve(options.commandArgs[0]) : options.vaultPath ? path.resolve(options.vaultPath) - : databasePath!; + : databasePath; // Check if vault directory exists try { @@ -333,7 +333,7 @@ export async function main() { console.error(`Error: Vault path ${vaultPath} is not a directory`); process.exit(1); } - } catch (error) { + } catch { console.error(`Error: Vault directory ${vaultPath} does not exist`); process.exit(1); } @@ -415,7 +415,7 @@ export async function main() { // Force disable IndexedDB adapter in CLI environment data.useIndexedDBAdapter = false; return data; - } catch (error) { + } catch { if (options.verbose) { console.error(`[Settings] File not found, using defaults`); } @@ -434,7 +434,7 @@ export async function main() { () => [], // No add-ons (core) => { // Register P2P replicator feature. - const _replicator = useP2PReplicatorFeature(core); + useP2PReplicatorFeature(core); // Add target filter to prevent internal files are handled core.services.vault.isTargetFile.addHandler(async (target) => { const targetPath = stripAllPrefixes(getPathFromUXFileInfo(target)); diff --git a/src/apps/cli/node-compat.ts b/src/apps/cli/node-compat.ts index ff6aeac..dc92674 100644 --- a/src/apps/cli/node-compat.ts +++ b/src/apps/cli/node-compat.ts @@ -1,7 +1,11 @@ -/* eslint-disable obsidianmd/no-nodejs-builtins */ +// eslint-disable-next-line obsidianmd/no-nodejs-builtins -- This file is used to provide Node.js built-in modules in the CLI environment, which is not running in a browser context. import * as nodeFs from "node:fs"; +// eslint-disable-next-line obsidianmd/no-nodejs-builtins -- This file is used to provide Node.js built-in modules in the CLI environment, which is not running in a browser context. import * as nodeFsPromises from "node:fs/promises"; +// eslint-disable-next-line obsidianmd/no-nodejs-builtins -- This file is used to provide Node.js built-in modules in the CLI environment, which is not running in a browser context. import * as nodePath from "node:path"; +// eslint-disable-next-line obsidianmd/no-nodejs-builtins -- This file is used to provide Node.js built-in modules in the CLI environment, which is not running in a browser context. import * as nodeReadlinePromises from "node:readline/promises"; +// eslint-disable-next-line obsidianmd/no-nodejs-builtins -- This file is used to provide Node.js built-in modules in the CLI environment, which is not running in a browser context. import type { Stats } from "node:fs"; export { nodeFs as fs, nodeFsPromises as fsPromises, nodePath as path, nodeReadlinePromises as readline, type Stats }; diff --git a/src/apps/webapp/README.md b/src/apps/webapp/README.md index ce1a6cb..28afbf1 100644 --- a/src/apps/webapp/README.md +++ b/src/apps/webapp/README.md @@ -6,7 +6,7 @@ Note: (I vrtmrz have not tested this so much yet). - 🌐 Runs entirely in the browser - 📁 Uses FileSystem API to access your local vault -- 🔄 Syncs with CouchDB, Object Storage server (compatible with Self-hosted LiveSync plugin) +- 🔄 Syncs with CouchDB, Object Storage server (compatible with Self-hosted LiveSync plug-in) - 🚫 No server-side code required!! - 💾 Settings stored in `.livesync/settings.json` within your vault - 👁️ Real-time file watching (Chrome 124+ with FileSystemObserver) @@ -127,7 +127,7 @@ webapp/ 1. **Adapters**: Implement `IFileSystemAdapter` interface using FileSystem API 2. **Managers**: Handle storage events and file watching 3. **Service Modules**: Integrate with LiveSyncBaseCore -4. **Main**: Application initialization and lifecycle management +4. **Main**: Application initialisation and lifecycle management ### Service Hub @@ -154,11 +154,11 @@ Uses `BrowserServiceHub` which provides: - Settings stored in `.livesync/settings.json` in vault - Real-time file watching only with FileSystemObserver (Chrome 124+) -## Differences from Obsidian Plugin +## Differences from Obsidian Plug-in -- No Obsidian-specific modules (UI, settings dialog, etc.) +- No Obsidian-specific modules (UI, settings dialogue, etc.) - Simplified configuration -- No plugin/theme sync features +- No plug-in/theme sync features - No internal file handling (`.obsidian` folder) ## Development Notes diff --git a/src/apps/webapp/main.ts b/src/apps/webapp/main.ts index eb67e04..f508028 100644 --- a/src/apps/webapp/main.ts +++ b/src/apps/webapp/main.ts @@ -23,7 +23,6 @@ import { compatGlobal, _activeDocument } from "@lib/common/coreEnvFunctions.ts"; const SETTINGS_DIR = ".livesync"; const SETTINGS_FILE = "settings.json"; -const DB_NAME = "livesync-webapp"; /** * Default settings for the webapp @@ -65,7 +64,6 @@ class LiveSyncWebApp { console.log(`Vault directory: ${this.rootHandle.name}`); // Create service context and hub - const context = new ServiceContext(); this.serviceHub = new BrowserServiceHub(); // Setup API service diff --git a/src/apps/webapp/managers/FSAPIStorageEventManagerAdapter.ts b/src/apps/webapp/managers/FSAPIStorageEventManagerAdapter.ts index 762903f..4010c5c 100644 --- a/src/apps/webapp/managers/FSAPIStorageEventManagerAdapter.ts +++ b/src/apps/webapp/managers/FSAPIStorageEventManagerAdapter.ts @@ -161,7 +161,6 @@ class FSAPIWatchAdapter implements IStorageEventWatchAdapter { this.observer = new FileSystemObserver(async (records: any[]) => { for (const record of records) { - const handle = record.root; const changedHandle = record.changedHandle; const relativePathComponents = record.relativePathComponents; const type = record.type; // "appeared", "disappeared", "modified", "moved", "unknown", "errored" diff --git a/src/apps/webpeer/src/P2PReplicatorShim.ts b/src/apps/webpeer/src/P2PReplicatorShim.ts index 8048804..d31ac5a 100644 --- a/src/apps/webpeer/src/P2PReplicatorShim.ts +++ b/src/apps/webpeer/src/P2PReplicatorShim.ts @@ -11,7 +11,6 @@ import { eventHub } from "@lib/hub/hub"; import type { Confirm } from "@lib/interfaces/Confirm"; import { LOG_LEVEL_NOTICE, Logger } from "@lib/common/logger"; -import { storeP2PStatusLine } from "./CommandsShim"; import { EVENT_P2P_PEER_SHOW_EXTRA_MENU, type PeerStatus, @@ -87,7 +86,7 @@ export class P2PReplicatorShim implements P2PReplicatorBase { this._liveSyncReplicator = replicator; this.p2pLogCollector = p2pLogCollector; p2pLogCollector.p2pReplicationLine.onChanged((line) => { - storeP2PStatusLine.set(line.value); + p2pStatusLine.value = line.value; }); } diff --git a/src/features/LocalDatabaseMainte/CmdLocalDatabaseMainte.ts b/src/features/LocalDatabaseMainte/CmdLocalDatabaseMainte.ts index 631856b..67cda40 100644 --- a/src/features/LocalDatabaseMainte/CmdLocalDatabaseMainte.ts +++ b/src/features/LocalDatabaseMainte/CmdLocalDatabaseMainte.ts @@ -738,7 +738,7 @@ Success: ${successCount}, Errored: ${errored}`; }); // Probably no need to wait, but just in case. let timeout = 2 * 60 * 1000; // 2 minutes - do { + for (;;) { const status = await remote.db.info(); if ("compact_running" in status && status?.compact_running) { this._notice("Compaction in progress on remote database...", "gc-compact"); @@ -751,7 +751,7 @@ Success: ${successCount}, Errored: ${errored}`; } else { break; } - } while (true); + } if (compactResult && "ok" in compactResult) { this._notice("Compaction on remote database completed successfully.", "gc-compact"); } else { diff --git a/src/lib b/src/lib index 0278343..9aeab51 160000 --- a/src/lib +++ b/src/lib @@ -1 +1 @@ -Subproject commit 0278343fc676ed3b94302eac7249ab0ceeae01ee +Subproject commit 9aeab513b0f98819dc7a420d8ede732e5f6a2cfc diff --git a/src/modules/features/DocumentHistory/DocumentHistoryModal.ts b/src/modules/features/DocumentHistory/DocumentHistoryModal.ts index 8288c7e..25714b5 100644 --- a/src/modules/features/DocumentHistory/DocumentHistoryModal.ts +++ b/src/modules/features/DocumentHistory/DocumentHistoryModal.ts @@ -99,9 +99,11 @@ export class DocumentHistoryModal extends Modal { if (!file && id) { this.file = this.services.path.id2path(id); } + // eslint-disable-next-line obsidianmd/no-unsupported-api -- loadLocalStorage is supported in Obsidian 1.7.2+ if (this.app.loadLocalStorage("ols-history-highlightdiff") == "1") { this.showDiff = true; } + // eslint-disable-next-line obsidianmd/no-unsupported-api -- loadLocalStorage is supported in Obsidian 1.7.2+ if (this.app.loadLocalStorage("ols-history-diffonly") == "1") { this.diffOnly = true; } @@ -552,6 +554,7 @@ export class DocumentHistoryModal extends Modal { } checkbox.addEventListener("input", (evt: Event) => { this.showDiff = checkbox.checked; + // eslint-disable-next-line obsidianmd/no-unsupported-api -- saveLocalStorage is supported in Obsidian 1.7.2+ this.app.saveLocalStorage("ols-history-highlightdiff", this.showDiff == true ? "1" : null); this.updateDiffNavVisibility(); void scheduleOnceIfDuplicated("loadRevs", () => this.loadRevs()); @@ -567,6 +570,7 @@ export class DocumentHistoryModal extends Modal { } checkbox.addEventListener("input", (evt: Event) => { this.diffOnly = checkbox.checked; + // eslint-disable-next-line obsidianmd/no-unsupported-api -- saveLocalStorage is supported in Obsidian 1.7.2+ this.app.saveLocalStorage("ols-history-diffonly", this.diffOnly == true ? "1" : null); void scheduleOnceIfDuplicated("loadRevs", () => this.loadRevs()); }); diff --git a/src/serviceModules/FileSystemAdapters/ObsidianVaultAdapter.ts b/src/serviceModules/FileSystemAdapters/ObsidianVaultAdapter.ts index 5ca9053..42ab566 100644 --- a/src/serviceModules/FileSystemAdapters/ObsidianVaultAdapter.ts +++ b/src/serviceModules/FileSystemAdapters/ObsidianVaultAdapter.ts @@ -38,20 +38,20 @@ export class ObsidianVaultAdapter implements IVaultAdapter { } async delete(file: TFile | TFolder, force = false): Promise { - // if ("trashFile" in this.app.fileManager) { - // // eslint-disable-next-line obsidianmd/no-unsupported-api - // return await this.app.fileManager.trashFile(file); - // } - //TODO: need fix + if ("trashFile" in this.app.fileManager) { + // eslint-disable-next-line obsidianmd/no-unsupported-api + return await this.app.fileManager.trashFile(file); + } + // eslint-disable-next-line obsidianmd/prefer-file-manager-trash-file -- Fallback for older versions of Obsidian without trashFile support return await this.app.vault.delete(file, force); } async trash(file: TFile | TFolder, force = false): Promise { - // if ("trashFile" in this.app.fileManager) { - // // eslint-disable-next-line obsidianmd/no-unsupported-api - // return await this.app.fileManager.trashFile(file); - // } - //TODO: need fix + if ("trashFile" in this.app.fileManager) { + // eslint-disable-next-line obsidianmd/no-unsupported-api + return await this.app.fileManager.trashFile(file); + } + // eslint-disable-next-line obsidianmd/prefer-file-manager-trash-file -- Fallback for older versions of Obsidian without trashFile support return await this.app.vault.trash(file, force); } diff --git a/updates.md b/updates.md index 627aeac..3c110a2 100644 --- a/updates.md +++ b/updates.md @@ -3,6 +3,14 @@ Since 19th July, 2025 (beta1 in 0.25.0-beta1, 13th July, 2025) The head note of 0.25 is now in [updates_old.md](https://github.com/vrtmrz/obsidian-livesync/blob/main/updates_old.md). Because 0.25 got a lot of updates, thankfully, compatibility is kept and we do not need breaking changes! In other words, when get enough stabled. The next version will be v1.0.0. Even though it my hope. +## Unreleased + +18th June, 2026 + +### Improved + +- File deletion now respects the user's deletion preferences (by utilising the `FileManager.trashFile` API) on Obsidian v1.7.2 or newer, regardless of the plug-in's internal trashbin setting. + ## 0.25.76 15th June, 2026