Compare commits

..

12 Commits

Author SHA1 Message Date
vorotamoroz 27e9b68510 (chore): Resolving circular references 2026-06-10 11:45:41 +01:00
vorotamoroz e4b36602ec (chore): split utils 2026-06-10 11:22:34 +01:00
vorotamoroz 36827d4799 update submodule 2026-06-10 10:38:59 +01:00
vorotamoroz f596e7dd68 (chore): fix import paths 2026-06-10 10:33:41 +01:00
vorotamoroz b0ac01e52f append exclude 2026-06-10 10:31:40 +01:00
vorotamoroz b4077bd1f5 (chore): add utility for refactoring 2026-06-10 10:29:56 +01:00
vorotamoroz 675de883e9 (chore): fix import paths 2026-06-10 09:40:55 +01:00
vorotamoroz 4b8de7c915 Add importAlias 2026-06-10 09:40:43 +01:00
vorotamoroz 4f8a74107c remove unnecessary package 2026-06-09 08:11:05 +01:00
vorotamoroz 42ed0d8795 update dir notation 2026-06-09 07:25:41 +01:00
vorotamoroz 54c2b1c6db reduce no-explicit-any 2026-06-09 05:59:02 +01:00
vorotamoroz 0856693aac Add instruction 2026-06-09 02:26:07 +01:00
111 changed files with 1723 additions and 1876 deletions
+12 -29
View File
@@ -8,8 +8,6 @@ name: Build and Push CLI Docker Image
on:
push:
branches:
- main
tags:
- "*.*.*-cli"
workflow_dispatch:
@@ -43,32 +41,14 @@ jobs:
id: meta
run: |
VERSION=$(jq -r '.version' manifest.json)
SHORT_SHA=$(git rev-parse --short HEAD)
EPOCH=$(date +%s)
TAG="${VERSION}-${EPOCH}-cli"
IMAGE="ghcr.io/${{ github.repository_owner }}/livesync-cli"
# Build tag list based on the event and git ref
TAGS=""
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
# Stable release builds
TAGS="${IMAGE}:${VERSION}-cli,${IMAGE}:latest,${IMAGE}:${VERSION}-sha-${SHORT_SHA}-cli"
elif [[ "${{ github.ref }}" == refs/heads/main ]]; then
# Bleeding-edge / nightly builds
TAGS="${IMAGE}:edge,${IMAGE}:${VERSION}-dev-sha-${SHORT_SHA}-cli"
else
# Other branches / manual run fallback
TAGS="${IMAGE}:${VERSION}-dev-sha-${SHORT_SHA}-cli"
fi
# Determine if the image should be pushed
PUSH="true"
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
if [[ "${{ inputs.dry_run }}" == "true" ]]; then
PUSH="false"
fi
fi
echo "tags=${TAGS}" >> $GITHUB_OUTPUT
echo "push=${PUSH}" >> $GITHUB_OUTPUT
echo "tag=${TAG}" >> $GITHUB_OUTPUT
echo "image=${IMAGE}" >> $GITHUB_OUTPUT
echo "full=${IMAGE}:${TAG}" >> $GITHUB_OUTPUT
echo "version=${IMAGE}:${VERSION}-cli" >> $GITHUB_OUTPUT
echo "latest=${IMAGE}:latest" >> $GITHUB_OUTPUT
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
@@ -112,7 +92,10 @@ jobs:
with:
context: .
file: src/apps/cli/Dockerfile
push: ${{ steps.meta.outputs.push }}
tags: ${{ steps.meta.outputs.tags }}
push: ${{ !(github.event_name == 'workflow_dispatch' && inputs.dry_run) }}
tags: |
${{ steps.meta.outputs.full }}
${{ steps.meta.outputs.version }}
${{ steps.meta.outputs.latest }}
cache-from: type=gha
cache-to: type=gha,mode=max
+3
View File
@@ -32,6 +32,9 @@ Always adhere to the following stylistic and spelling rules:
- Use **'dialogue'** in documentation, user-facing messages, and general text. Use **'dialog'** only inside source code (e.g. class names, methods).
- Use the hyphenated form **'plug-in'** in user-facing text. Use **'plugin'** only in codebase files, configuration settings, or technical contexts.
5. **User Communication Language**:
- Always reply to the user in the language in which they asked the question.
---
## Technical & Architecture Rules
+35 -2
View File
@@ -19,11 +19,15 @@ const packageJson = JSON.parse(fs.readFileSync("./package.json") + "");
const updateInfo = JSON.stringify(fs.readFileSync("./updates.md") + "");
const PATHS_TEST_INSTALL = process.env?.PATHS_TEST_INSTALL || "";
const PATH_TEST_INSTALL = PATHS_TEST_INSTALL.split(path.delimiter).map(p => p.trim()).filter(p => p.length);
const PATH_TEST_INSTALL = PATHS_TEST_INSTALL.split(path.delimiter)
.map((p) => p.trim())
.filter((p) => p.length);
if (PATH_TEST_INSTALL) {
console.log(`Built files will be copied to ${PATH_TEST_INSTALL}`);
} else {
console.log("Development build: You can install the plug-in to Obsidian for testing by exporting the PATHS_TEST_INSTALL environment variable with the paths to your vault plugins directories separated by your system path delimiter (':' on Unix, ';' on Windows).");
console.log(
"Development build: You can install the plug-in to Obsidian for testing by exporting the PATHS_TEST_INSTALL environment variable with the paths to your vault plugins directories separated by your system path delimiter (':' on Unix, ';' on Windows)."
);
}
const moduleAliasPlugin = {
@@ -66,6 +70,34 @@ const moduleAliasPlugin = {
},
};
const removePragmaCommentsPlugin = {
name: "remove-pragma-comments",
setup(build) {
// Filter target extensions (e.g., JavaScript and TypeScript)
build.onLoad({ filter: /\.[jt]s?$/ }, async (args) => {
const source = await fs.promises.readFile(args.path, "utf8");
// Regex targeting both single-line and multi-line comments
// This regex looks for:
// - /* eslint ... */ (multi-line)
// const esLintPragmaRegexBlock = /\/\*[\s\S]*?eslint[\s\S]*?\*\/|([^\\:]|^)\/\/.*eslint.*$/gm;
// - // eslint-disable-next-line
let cleanedSource = source;
const tsIgnoreRegex = /\/\*\s*@ts-ignore\s*\*\/|([^\\:]|^)\/\/.*?@ts-ignore.*$/gm;
const esLintPragmaRegexLine = /([^\\:]|^)\/\/.*?eslint-.*$/gm;
const exps = [tsIgnoreRegex, esLintPragmaRegexLine];
for (const exp of exps) {
cleanedSource = cleanedSource.replace(exp, "$1");
}
return {
contents: cleanedSource,
loader: args.path.endsWith("ts") ? "ts" : "js",
};
});
},
};
/** @type esbuild.Plugin[] */
const plugins = [
{
@@ -177,6 +209,7 @@ const context = await esbuild.context({
preprocess: sveltePreprocess(),
compilerOptions: { css: "injected", preserveComments: false },
}),
removePragmaCommentsPlugin,
...plugins,
],
});
+31 -5
View File
@@ -4,6 +4,7 @@ import globals from "globals";
import { defineConfig, globalIgnores } from "eslint/config";
import * as sveltePlugin from "eslint-plugin-svelte";
import svelteParser from "svelte-eslint-parser";
import importAlias from "@dword-design/eslint-plugin-import-alias";
const warnWhileDev = "off"; // Change to "warn" to enable warnings for rules that are currently disabled.
export default defineConfig([
globalIgnores([
@@ -18,11 +19,11 @@ export default defineConfig([
"**/*.json",
"**/.eslintrc.js.bak",
// Files from linked dependencies (those files should not exist for most people).
"modules/octagonal-wheels/dist/**/*",
"modules/octagonal-wheels/dist",
// Sub-projects (Exclude from root linting as they have different environments)
"src/apps/**/*",
"utils/**/*",
"src/apps",
"utils",
// Specific exclusions from common library (src/lib)
"src/lib/coverage",
@@ -54,6 +55,7 @@ export default defineConfig([
]),
...sveltePlugin.configs["flat/base"],
...obsidianmd.configs.recommended,
importAlias.configs.recommended,
{
files: ["**/*.ts"],
// ignores:["src/lib/**/*.ts"], // Exclude library files from root linting (they have different environments and rules).
@@ -64,7 +66,7 @@ export default defineConfig([
project: "./tsconfig.json",
},
},
linterOptions:{
linterOptions: {
reportUnusedDisableDirectives: false,
},
rules: {
@@ -73,11 +75,13 @@ export default defineConfig([
"no-unused-labels": "off",
"no-prototype-builtins": "off",
"require-await": "off",
// -- TypeScript specific rules (Gradual adoption of stricter rules, currently set to 'warn' for a while).
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-redundant-type-constituents": "warn",
// -- TypeScript specific rules
// @typescript-eslint/no-unsafe-* rules and @typescript-eslint/no-explicit-any:
// This project contains a lot of library-sh code where the use of `any` is often necessary and justified.
// Rules is now set to 'off' for a while.
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unsafe-argument": "off",
"@typescript-eslint/no-unsafe-call": "off",
"@typescript-eslint/no-unsafe-member-access": "off",
@@ -111,6 +115,18 @@ export default defineConfig([
// -- Temporary overrides for migration
"obsidianmd/no-static-styles-assignment": "off",
// -- Project specific rules
"@dword-design/import-alias/prefer-alias": [
"error",
{
aliasForSubpaths: true,
alias: {
"@": "./src",
"@lib": "./src/lib/src",
},
},
],
},
},
{
@@ -129,6 +145,16 @@ export default defineConfig([
"no-unused-vars": "off",
"obsidianmd/no-plugin-as-component": "off",
"obsidianmd/ui/sentence-case": "off",
"@dword-design/import-alias/prefer-alias": [
"error",
{
aliasForSubpaths: true,
alias: {
"@": "./src",
"@lib": "./src/lib/src",
},
},
],
},
},
]);
+443 -905
View File
File diff suppressed because it is too large Load Diff
+6 -7
View File
@@ -61,7 +61,7 @@
"author": "vorotamoroz",
"license": "MIT",
"devDependencies": {
"@chialab/esbuild-plugin-worker": "^0.19.0",
"@dword-design/eslint-plugin-import-alias": "^8.1.8",
"@eslint/js": "^9.39.3",
"@sveltejs/vite-plugin-svelte": "^6.2.4",
"@tsconfig/svelte": "^5.0.8",
@@ -78,8 +78,8 @@
"@types/pouchdb-mapreduce": "^6.1.10",
"@types/pouchdb-replication": "^6.4.7",
"@types/transform-pouch": "^1.0.6",
"@typescript-eslint/eslint-plugin": "8.56.1",
"@typescript-eslint/parser": "8.56.1",
"@typescript-eslint/eslint-plugin": "^8.61.0",
"@typescript-eslint/parser": "8.61.0",
"@vitest/browser": "^4.1.8",
"@vitest/browser-playwright": "^4.1.8",
"@vitest/coverage-v8": "^4.1.8",
@@ -94,7 +94,6 @@
"globals": "^14.0.0",
"playwright": "^1.58.2",
"postcss": "^8.5.6",
"postcss-load-config": "^6.0.1",
"pouchdb-adapter-http": "^9.0.0",
"pouchdb-adapter-idb": "^9.0.0",
"pouchdb-adapter-indexeddb": "^9.0.0",
@@ -110,13 +109,14 @@
"rollup-plugin-copy": "^3.5.0",
"svelte": "5.41.1",
"svelte-check": "^4.4.3",
"svelte-eslint-parser": "^1.8.0",
"svelte-preprocess": "^6.0.3",
"terser": "^5.39.0",
"tinyglobby": "^0.2.15",
"transform-pouch": "^2.0.0",
"tslib": "^2.8.1",
"tsx": "^4.21.0",
"typescript": "5.9.3",
"typescript-eslint": "^8.61.0",
"vite": "^7.3.1",
"vite-plugin-istanbul": "^8.0.0",
"vitest": "^4.1.8",
@@ -130,15 +130,14 @@
"@smithy/middleware-apply-body-checksum": "^4.3.9",
"@smithy/protocol-http": "^5.3.9",
"@smithy/querystring-builder": "^4.2.9",
"@smithy/types": "^4.14.3",
"@smithy/util-retry": "^4.4.5",
"@trystero-p2p/nostr": "^0.24.0",
"chokidar": "^4.0.0",
"commander": "^14.0.3",
"diff-match-patch": "^1.0.5",
"fflate": "^0.8.2",
"idb": "^8.0.3",
"markdown-it": "^14.1.1",
"micromatch": "^4.0.0",
"minimatch": "^10.2.2",
"obsidian": "^1.12.3",
"octagonal-wheels": "^0.1.46",
+1
View File
@@ -120,6 +120,7 @@ export class LiveSyncBaseCore<
* @param constructor
* @returns
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
getModule<T extends AbstractModule>(constructor: new (...args: any[]) => T): T {
for (const module of this.modules) {
if (module.constructor === constructor) return module as T;
+5 -1
View File
@@ -109,7 +109,11 @@ Deno.test("daemon: ignore rules behaviour", async (t) => {
await runCliOrFail(vaultDir, "--settings", settingsFile, "mirror");
const dbList = await runCliOrFail(vaultDir, "--settings", settingsFile, "ls");
assertNotContains(dbList, "debug.log", "debug.log (ignored via .gitignore import) was unexpectedly synced to database");
assertNotContains(
dbList,
"debug.log",
"debug.log (ignored via .gitignore import) was unexpectedly synced to database"
);
assertContains(dbList, "regular.md", "regular.md was not synced normally alongside .gitignore import rules");
console.log("[PASS] Case 3 verified successfully");
});
+4 -31
View File
@@ -46,9 +46,7 @@ Deno.test("decoupled database and vault", async () => {
console.log("[INFO] applying CouchDB environment variables to settings");
await applyCouchdbSettings(settingsFile, uri, user, password, dbname);
} else {
console.warn(
"[WARN] CouchDB environment variables are not fully set. Push and pull operations may fail."
);
console.warn("[WARN] CouchDB environment variables are not fully set. Push and pull operations may fail.");
await markSettingsConfigured(settingsFile);
}
@@ -59,29 +57,11 @@ Deno.test("decoupled database and vault", async () => {
// 1. Test push command with decoupled vault directory
console.log(`[INFO] push with decoupled vault -> ${REMOTE_PATH}`);
await runCliOrFail(
dbDir,
"--vault",
vaultDir,
"--settings",
settingsFile,
"push",
srcFile,
REMOTE_PATH
);
await runCliOrFail(dbDir, "--vault", vaultDir, "--settings", settingsFile, "push", srcFile, REMOTE_PATH);
// 2. Test pull command with decoupled vault directory
console.log(`[INFO] pull with decoupled vault <- ${REMOTE_PATH}`);
await runCliOrFail(
dbDir,
"--vault",
vaultDir,
"--settings",
settingsFile,
"pull",
REMOTE_PATH,
pulledFile
);
await runCliOrFail(dbDir, "--vault", vaultDir, "--settings", settingsFile, "pull", REMOTE_PATH, pulledFile);
const pulled = await Deno.readTextFile(pulledFile);
assertEquals(pulled, content, "push/pull roundtrip with decoupled vault content mismatch");
@@ -93,14 +73,7 @@ Deno.test("decoupled database and vault", async () => {
// 4. Test mirror command with decoupled vault directory
console.log("[INFO] mirror with decoupled vault");
await runCliOrFail(
dbDir,
"--vault",
vaultDir,
"--settings",
settingsFile,
"mirror"
);
await runCliOrFail(dbDir, "--vault", vaultDir, "--settings", settingsFile, "mirror");
const restoredFile = join(vaultDir, REMOTE_PATH);
const restored = await Deno.readTextFile(restoredFile);
@@ -14,7 +14,7 @@ import { getOptimalLoopbackIp } from "./helpers/net.ts";
Deno.test("p2p-peers: discovers host through local relay", async () => {
const loopbackIp = await getOptimalLoopbackIp();
const loopbackHost = loopbackIp === "::1" ? "[::1]" : loopbackIp;
const relay = Deno.env.get("RELAY") ?? `ws://${loopbackHost}:4000/`;
const roomId = Deno.env.get("ROOM_ID") ?? `room-${Date.now()}`;
const passphrase = Deno.env.get("PASSPHRASE") ?? "test";
+1 -1
View File
@@ -15,7 +15,7 @@ import { getOptimalLoopbackIp } from "./helpers/net.ts";
Deno.test("p2p-sync: discovers peer and completes sync", async () => {
const loopbackIp = await getOptimalLoopbackIp();
const loopbackHost = loopbackIp === "::1" ? "[::1]" : loopbackIp;
const relay = Deno.env.get("RELAY") ?? `ws://${loopbackHost}:4000/`;
const roomId = Deno.env.get("ROOM_ID") ?? `room-${Date.now()}`;
const passphrase = Deno.env.get("PASSPHRASE") ?? "test";
@@ -15,7 +15,7 @@ import { getOptimalLoopbackIp } from "./helpers/net.ts";
Deno.test("p2p: three nodes detect and resolve conflicts", async () => {
const loopbackIp = await getOptimalLoopbackIp();
const loopbackHost = loopbackIp === "::1" ? "[::1]" : loopbackIp;
const relay = Deno.env.get("RELAY") ?? `ws://${loopbackHost}:4000/`;
const roomId = Deno.env.get("ROOM_ID") ?? `room-${Date.now()}`;
const passphrase = Deno.env.get("PASSPHRASE") ?? "test";
@@ -61,11 +61,7 @@ Deno.test("remote management commands", async () => {
// 1. remote-status outputs valid JSON with CouchDB details
console.log("[CASE] remote-status outputs valid JSON with CouchDB details");
const statusOutput = await runCliCombinedOrFail(vaultDir, "--settings", settingsFile, "remote-status");
assertContains(
statusOutput,
`"db_name": "${dbname}"`,
"remote-status should return JSON containing db_name"
);
assertContains(statusOutput, `"db_name": "${dbname}"`, "remote-status should return JSON containing db_name");
console.log("[PASS] remote-status verified");
// 2. lock-remote locks and verifies state
+3 -3
View File
@@ -1,8 +1,8 @@
import { deleteDB, type IDBPDatabase, openDB } from "idb";
import type { KeyValueDatabase } from "../lib/src/interfaces/KeyValueDatabase.ts";
import type { KeyValueDatabase } from "@lib/interfaces/KeyValueDatabase.ts";
import { serialized } from "octagonal-wheels/concurrency/lock";
import { Logger } from "octagonal-wheels/common/logger";
const databaseCache: { [key: string]: IDBPDatabase<any> } = {};
const databaseCache: { [key: string]: IDBPDatabase<unknown> } = {};
export { OpenKeyValueDatabase } from "./KeyValueDBv2.ts";
export const _OpenKeyValueDatabase = async (dbKey: string): Promise<KeyValueDatabase> => {
@@ -11,7 +11,7 @@ export const _OpenKeyValueDatabase = async (dbKey: string): Promise<KeyValueData
delete databaseCache[dbKey];
}
const storeKey = dbKey;
let db: IDBPDatabase<any> | null = null;
let db: IDBPDatabase<unknown> | null = null;
const _openDB = () => {
return serialized("keyvaluedb-" + dbKey, async () => {
const dbInstance = await openDB(dbKey, 1, {
+2 -2
View File
@@ -28,7 +28,7 @@ export async function OpenKeyValueDatabase(dbKey: string): Promise<KeyValueDatab
}
export class IDBKeyValueDatabase implements KeyValueDatabase {
protected _dbPromise: Promise<IDBPDatabase<any>> | null = null;
protected _dbPromise: Promise<IDBPDatabase<unknown>> | null = null;
protected dbKey: string;
protected storeKey: string;
protected _isDestroyed: boolean = false;
@@ -104,7 +104,7 @@ export class IDBKeyValueDatabase implements KeyValueDatabase {
this.destroyedPromise = Promise.resolve();
}
}
get DB(): Promise<IDBPDatabase<any>> {
get DB(): Promise<IDBPDatabase<unknown>> {
if (this._isDestroyed) {
return Promise.reject(new Error("Database is destroyed"));
}
+2 -2
View File
@@ -4,10 +4,10 @@ import { eventHub, EVENT_PLUGIN_UNLOADED } from "./events";
import type { NecessaryServices } from "@lib/interfaces/ServiceModule";
type PeriodicProcessorHost = NecessaryServices<"API" | "control", never>;
export class PeriodicProcessor {
_process: () => Promise<any>;
_process: () => Promise<unknown>;
_timer?: number = undefined;
_core: PeriodicProcessorHost;
constructor(core: PeriodicProcessorHost, process: () => Promise<any>) {
constructor(core: PeriodicProcessorHost, process: () => Promise<unknown>) {
// this._plugin = plugin;
this._core = core;
this._process = process;
+1 -1
View File
@@ -1,4 +1,4 @@
import { eventHub } from "../lib/src/hub/hub";
import { eventHub } from "@lib/hub/hub";
// import type ObsidianLiveSyncPlugin from "../main";
export const EVENT_PLUGIN_LOADED = "plugin-loaded";
+2 -2
View File
@@ -1,5 +1,5 @@
import type { TFile } from "../deps";
import type { FilePathWithPrefix, LoadedEntry } from "../lib/src/common/types";
import type { TFile } from "@/deps";
import type { FilePathWithPrefix, LoadedEntry } from "@lib/common/types";
export const EVENT_REQUEST_SHOW_HISTORY = "show-history";
+6 -7
View File
@@ -1,7 +1,7 @@
import { REMOTE_COUCHDB, REMOTE_MINIO } from "@lib/common/models/setting.const";
import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type";
import { generateCredentialObject } from "@lib/replication/httplib";
import { parseHeaderValues } from "@lib/common/utils";
import { parseHeaderValues } from "@lib/common/utils.misc";
import { requestToCouchDBWithCredentials } from "./utils";
import { LOG_LEVEL_VERBOSE, Logger } from "@lib/common/logger";
import { DEFAULT_SETTINGS } from "@lib/common/models/setting.const.defaults";
@@ -9,16 +9,15 @@ import { isCloudantURI } from "@lib/pouchdb/utils_couchdb";
import { compatGlobal } from "@lib/common/coreEnvFunctions";
import { manifestVersion, packageVersion } from "@lib/common/coreEnvVars";
import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore";
function redactObject(obj: Record<string, any>, dotted: string, redactedValue = "REDACTED") {
function redactObject(obj: Record<string, unknown>, dotted: string, redactedValue = "REDACTED") {
const keys = dotted.split(".");
let current = obj;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (!(key in current)) {
current[key] = {} as Record<string, any>;
current[key] = {};
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
current = current[key];
current = current[key] as Record<string, unknown>;
}
const lastKey = keys[keys.length - 1];
if (lastKey in current) {
@@ -27,7 +26,7 @@ function redactObject(obj: Record<string, any>, dotted: string, redactedValue =
return obj;
}
export async function generateReport(settings: ObsidianLiveSyncSettings, core: LiveSyncBaseCore) {
let responseConfig: Record<string, any> = {};
let responseConfig: Record<string, unknown> = {};
const REDACTED = "𝑅𝐸𝐷𝐴𝐶𝑇𝐸𝐷";
if (settings.remoteType == REMOTE_COUCHDB) {
try {
@@ -42,7 +41,7 @@ export async function generateReport(settings: ObsidianLiveSyncSettings, core: L
undefined,
customHeaders
);
responseConfig = r.json as Record<string, any>;
responseConfig = r.json as Record<string, unknown>;
redactObject(responseConfig, "couch_httpd_auth.secret");
redactObject(responseConfig, "couch_httpd_auth.authentication_db");
redactObject(responseConfig, "couch_httpd_auth.authentication_redirect");
+3 -2
View File
@@ -1,5 +1,6 @@
import { type PluginManifest, TFile } from "../deps.ts";
import { type DatabaseEntry, type EntryBody, type FilePath } from "../lib/src/common/types.ts";
import { type PluginManifest, TFile } from "@/deps.ts";
import type { DatabaseEntry, FilePath } from "@lib/common/models/db.type";
import type { EntryBody } from "@lib/common/models/db.definition";
export type { CacheData, FileEventItem } from "../lib/src/common/types.ts";
export interface PluginDataEntry extends DatabaseEntry {
+25 -34
View File
@@ -1,4 +1,4 @@
import { normalizePath, Platform, TAbstractFile, type RequestUrlParam, requestUrl } from "../deps.ts";
import { normalizePath, Platform, TAbstractFile, type RequestUrlParam, requestUrl } from "@/deps.ts";
import {
path2id_base,
id2path_base,
@@ -7,29 +7,20 @@ import {
isValidFilenameInWidows,
isValidFilenameInAndroid,
stripAllPrefixes,
} from "../lib/src/string_and_binary/path.ts";
} from "@lib/string_and_binary/path.ts";
import { Logger } from "../lib/src/common/logger.ts";
import {
LOG_LEVEL_INFO,
LOG_LEVEL_NOTICE,
LOG_LEVEL_VERBOSE,
type AnyEntry,
type CouchDBCredentials,
type DocumentID,
type EntryHasPath,
type FilePath,
type FilePathWithPrefix,
type UXFileInfo,
type UXFileInfoStub,
} from "../lib/src/common/types.ts";
import { Logger } from "@lib/common/logger.ts";
import type { AnyEntry, DocumentID, EntryHasPath, FilePath, FilePathWithPrefix } from "@lib/common/models/db.type";
import type { CouchDBCredentials } from "@lib/common/models/auth.type";
import type { UXFileInfo, UXFileInfoStub } from "@lib/common/models/fileaccess.type";
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "@lib/common/logger";
export { ICHeader, ICXHeader } from "./types.ts";
import { writeString } from "../lib/src/string_and_binary/convert.ts";
import { writeString } from "@lib/string_and_binary/convert.ts";
import { sameChangePairs } from "./stores.ts";
import { scheduleTask } from "octagonal-wheels/concurrency/task";
import { AuthorizationHeaderGenerator } from "../lib/src/replication/httplib.ts";
import type { KeyValueDatabase } from "../lib/src/interfaces/KeyValueDatabase.ts";
import { AuthorizationHeaderGenerator } from "@lib/replication/httplib.ts";
import type { KeyValueDatabase } from "@lib/interfaces/KeyValueDatabase.ts";
export { scheduleTask, cancelTask, cancelAllTasks } from "octagonal-wheels/concurrency/task";
@@ -72,7 +63,7 @@ import {
} from "@lib/common/typeUtils.ts";
export { isInternalFile, getPathFromUXFileInfo, getStoragePathFromUXFileInfo, getDatabasePathFromUXFileInfo };
const memos: { [key: string]: any } = {};
const memos: Record<string, unknown> = {};
export function memoObject<T>(key: string, obj: T): T {
memos[key] = obj;
return memos[key] as T;
@@ -87,7 +78,7 @@ export async function memoIfNotExist<T>(key: string, func: () => T | Promise<T>)
}
export function retrieveMemoObject<T>(key: string): T | false {
if (key in memos) {
return memos[key];
return memos[key] as T;
} else {
return false;
}
@@ -128,7 +119,7 @@ export const _requestToCouchDBFetch = async (
username: string,
password: string,
path?: string,
body?: any,
body?: unknown,
method?: string
) => {
const utf8str = String.fromCharCode.apply(null, [...writeString(`${username}:${password}`)]);
@@ -154,7 +145,7 @@ export const _requestToCouchDB = async (
credentials: CouchDBCredentials,
origin: string,
path?: string,
body?: any,
body?: unknown,
method?: string,
customHeaders?: Record<string, string>
) => {
@@ -213,7 +204,7 @@ export function requestToCouchDBWithCredentials(
import { BASE_IS_NEW, EVEN, TARGET_IS_NEW } from "@lib/common/models/shared.const.symbols.ts";
export { BASE_IS_NEW, EVEN, TARGET_IS_NEW };
// Why 2000? : ZIP FILE Does not have enough resolution.
import { compareMTime } from "@lib/common/utils.ts";
import { compareMTime } from "@lib/common/utils.database.ts";
import { _fetch } from "@/lib/src/common/coreEnvFunctions.ts";
export { compareMTime };
function getKey(file: AnyEntry | string | UXFileInfoStub) {
@@ -263,27 +254,27 @@ export function compareFileFreshness(
const _cached = new Map<
string,
{
value: any;
context: Map<string, any>;
value: unknown;
context: Map<string, unknown>;
}
>();
export type MemoOption = {
key: string;
forceUpdate?: boolean;
validator?: (context: Map<string, any>) => boolean;
validator?: (context: Map<string, unknown>) => boolean;
};
export function useMemo<T>(
{ key, forceUpdate, validator }: MemoOption,
updateFunc: (context: Map<string, any>, prev: T) => T
updateFunc: (context: Map<string, unknown>, prev: T) => T
): T {
const cached = _cached.get(key);
const context = cached?.context || new Map<string, any>();
const context = cached?.context || new Map<string, unknown>();
if (cached && !forceUpdate && (!validator || (validator && !validator(context)))) {
return cached.value;
return cached.value as T;
}
const value = updateFunc(context, cached?.value);
const value = updateFunc(context, cached?.value as T);
if (value !== cached?.value) {
_cached.set(key, { value, context });
}
@@ -294,7 +285,7 @@ export function useMemo<T>(
const _staticObj = new Map<
string,
{
value: any;
value: unknown;
}
>();
@@ -306,7 +297,7 @@ export function useStatic<T>(key: string, initial?: T) {
// }
const obj = _staticObj.get(key);
if (obj !== undefined) {
return obj;
return obj as { value: T };
} else {
// let buf = initial;
const obj = {
@@ -390,7 +381,7 @@ export async function autosaveCache<K, V>(db: KeyValueDatabase, mapKey: string):
};
}
export function onlyInNTimes(n: number, proc: (progress: number) => any) {
export function onlyInNTimes(n: number, proc: (progress: number) => unknown) {
let counter = 0;
return function () {
if (counter++ % n == 0) {
+1 -2
View File
@@ -1,5 +1,4 @@
import { type FilePath } from "./lib/src/common/types.ts";
import type { FilePath } from "@lib/common/models/db.type";
export {
addIcon,
App,
+45 -43
View File
@@ -8,46 +8,38 @@ import {
diff_match_patch,
Platform,
addIcon,
} from "../../deps.ts";
type App,
} from "@/deps.ts";
import type { EntryDoc } from "@lib/common/models/db.definition";
import type {
EntryDoc,
LoadedEntry,
InternalFileEntry,
FilePathWithPrefix,
FilePath,
AnyEntry,
SavingEntry,
diff_result,
} from "../../lib/src/common/types.ts";
import {
CANCELLED,
LEAVE_TO_SUBSEQUENT,
LOG_LEVEL_DEBUG,
LOG_LEVEL_INFO,
LOG_LEVEL_NOTICE,
LOG_LEVEL_VERBOSE,
MODE_SELECTIVE,
MODE_SHINY,
} from "../../lib/src/common/types.ts";
import { ICXHeader, PERIODIC_PLUGIN_SWEEP } from "../../common/types.ts";
} from "@lib/common/models/db.type";
import type { diff_result } from "@lib/common/models/diff.definition";
import { CANCELLED, LEAVE_TO_SUBSEQUENT } from "@lib/common/models/shared.const.symbols";
import { MODE_SELECTIVE, MODE_SHINY } from "@lib/common/models/setting.const";
import { LOG_LEVEL_DEBUG, LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "@lib/common/logger";
import { ICXHeader } from "@lib/common/models/fileaccess.const";
import { PERIODIC_PLUGIN_SWEEP } from "@/common/types.ts";
import {
createBlob,
createSavingEntryFromLoadedEntry,
createTextBlob,
delay,
fireAndForget,
getDocData,
getDocDataAsArray,
isDocContentSame,
isLoadedEntry,
isObjectDifferent,
} from "../../lib/src/common/utils.ts";
import { digestHash } from "../../lib/src/string_and_binary/hash.ts";
import { arrayBufferToBase64, decodeBinary, readString } from "../../lib/src/string_and_binary/convert.ts";
} from "@lib/common/utils.database.ts";
import { delay, fireAndForget, isObjectDifferent } from "@lib/common/utils.ts";
import { digestHash } from "@lib/string_and_binary/hash.ts";
import { arrayBufferToBase64, decodeBinary, readString } from "@lib/string_and_binary/convert.ts";
import { serialized, shareRunningResult } from "octagonal-wheels/concurrency/lock";
import { LiveSyncCommands } from "../LiveSyncCommands.ts";
import { stripAllPrefixes } from "../../lib/src/string_and_binary/path.ts";
import { LiveSyncCommands } from "@/features/LiveSyncCommands.ts";
import { stripAllPrefixes } from "@lib/string_and_binary/path.ts";
import {
EVEN,
disposeMemoObject,
@@ -57,20 +49,20 @@ import {
memoObject,
retrieveMemoObject,
scheduleTask,
} from "../../common/utils.ts";
} from "@/common/utils.ts";
import { PeriodicProcessor } from "@/common/PeriodicProcessor.ts";
import { JsonResolveModal } from "../HiddenFileCommon/JsonResolveModal.ts";
import { JsonResolveModal } from "@/features/HiddenFileCommon/JsonResolveModal.ts";
import { QueueProcessor } from "octagonal-wheels/concurrency/processor";
import { pluginScanningCount } from "../../lib/src/mock_and_interop/stores.ts";
import type ObsidianLiveSyncPlugin from "../../main.ts";
import { pluginScanningCount } from "@lib/mock_and_interop/stores.ts";
import type ObsidianLiveSyncPlugin from "@/main.ts";
import { base64ToArrayBuffer, base64ToString } from "octagonal-wheels/binary/base64";
import { ConflictResolveModal } from "../../modules/features/InteractiveConflictResolving/ConflictResolveModal.ts";
import { ConflictResolveModal } from "@/modules/features/InteractiveConflictResolving/ConflictResolveModal.ts";
import { Semaphore } from "octagonal-wheels/concurrency/semaphore";
import { EVENT_REQUEST_OPEN_PLUGIN_SYNC_DIALOG, eventHub } from "../../common/events.ts";
import { PluginDialogModal } from "./PluginDialogModal.ts";
import { EVENT_REQUEST_OPEN_PLUGIN_SYNC_DIALOG, eventHub } from "@/common/events.ts";
import type { PluginDialogModal } from "./PluginDialogModal.ts";
import { $msg } from "@/lib/src/common/i18n.ts";
import type { InjectableServiceHub } from "../../lib/src/services/InjectableServices.ts";
import type { LiveSyncCore } from "../../main.ts";
import type { InjectableServiceHub } from "@lib/services/InjectableServices.ts";
import type { LiveSyncCore } from "@/main.ts";
import { LiveSyncError } from "@lib/common/LSError.ts";
const d = "\u200b";
@@ -393,8 +385,14 @@ export type PluginDataEx = {
};
export class ConfigSync extends LiveSyncCommands {
constructor(plugin: ObsidianLiveSyncPlugin, core: LiveSyncCore) {
pluginDialogClass: new (app: App, plugin: ObsidianLiveSyncPlugin) => PluginDialogModal;
constructor(
plugin: ObsidianLiveSyncPlugin,
core: LiveSyncCore,
pluginDialogClass: new (app: App, plugin: ObsidianLiveSyncPlugin) => PluginDialogModal
) {
super(plugin, core);
this.pluginDialogClass = pluginDialogClass;
pluginScanningCount.onChanged((e) => {
const total = e.value;
pluginIsEnumerating.set(total != 0);
@@ -428,7 +426,7 @@ export class ConfigSync extends LiveSyncCommands {
if (this.pluginDialog) {
this.pluginDialog.open();
} else {
this.pluginDialog = new PluginDialogModal(this.app, this.plugin);
this.pluginDialog = new this.pluginDialogClass(this.app, this.plugin);
this.pluginDialog.open();
}
}
@@ -1100,10 +1098,16 @@ export class ConfigSync extends LiveSyncCommands {
await delay(100);
this._log(`Config ${data.displayName || data.name} has been applied`, LOG_LEVEL_NOTICE);
if (data.category == "PLUGIN_DATA" || data.category == "PLUGIN_MAIN") {
//@ts-ignore
const manifests = Object.values(this.app.plugins.manifests) as any as PluginManifest[];
//@ts-ignore
const enabledPlugins = this.app.plugins.enabledPlugins as Set<string>;
const appWithPlugins = this.app as unknown as {
plugins: {
manifests: Record<string, PluginManifest>;
enabledPlugins: Set<string>;
unloadPlugin(id: string): Promise<void>;
loadPlugin(id: string): Promise<void>;
};
};
const manifests = Object.values(appWithPlugins.plugins.manifests);
const enabledPlugins = appWithPlugins.plugins.enabledPlugins;
const pluginManifest = manifests.find(
(manifest) => enabledPlugins.has(manifest.id) && manifest.dir == `${baseDir}/plugins/${data.name}`
);
@@ -1113,10 +1117,8 @@ export class ConfigSync extends LiveSyncCommands {
LOG_LEVEL_NOTICE,
"plugin-reload-" + pluginManifest.id
);
// @ts-ignore
await this.app.plugins.unloadPlugin(pluginManifest.id);
// @ts-ignore
await this.app.plugins.loadPlugin(pluginManifest.id);
await appWithPlugins.plugins.unloadPlugin(pluginManifest.id);
await appWithPlugins.plugins.loadPlugin(pluginManifest.id);
this._log(
`Plugin reloaded: ${pluginManifest.name}`,
LOG_LEVEL_NOTICE,
+4 -4
View File
@@ -5,10 +5,10 @@
type IPluginDataExDisplay,
type PluginDataExFile,
} from "./CmdConfigSync.ts";
import { Logger } from "../../lib/src/common/logger";
import { type FilePath, LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "../../lib/src/common/types";
import { getDocData, timeDeltaToHumanReadable, unique } from "../../lib/src/common/utils";
import type ObsidianLiveSyncPlugin from "../../main";
import { Logger } from "@lib/common/logger";
import { type FilePath, LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "@lib/common/types";
import { getDocData, timeDeltaToHumanReadable, unique } from "@lib/common/utils";
import type ObsidianLiveSyncPlugin from "@/main";
// import { askString } from "../../common/utils";
import { Menu } from "@/deps.ts";
+2 -2
View File
@@ -1,6 +1,6 @@
import { mount, unmount } from "svelte";
import { App, Modal } from "../../deps.ts";
import ObsidianLiveSyncPlugin from "../../main.ts";
import { App, Modal } from "@/deps.ts";
import type ObsidianLiveSyncPlugin from "@/main.ts";
import PluginPane from "./PluginPane.svelte";
export class PluginDialogModal extends Modal {
plugin: ObsidianLiveSyncPlugin;
+5 -5
View File
@@ -1,6 +1,6 @@
<script lang="ts">
import { onMount } from "svelte";
import ObsidianLiveSyncPlugin from "../../main";
import type ObsidianLiveSyncPlugin from "@/main";
import {
ConfigSync,
type IPluginDataExDisplay,
@@ -11,16 +11,16 @@
} from "./CmdConfigSync.ts";
import PluginCombo from "./PluginCombo.svelte";
import { Menu, type PluginManifest } from "@/deps.ts";
import { unique } from "../../lib/src/common/utils";
import { unique } from "@lib/common/utils";
import {
MODE_SELECTIVE,
MODE_AUTOMATIC,
MODE_PAUSED,
type SYNC_MODE,
MODE_SHINY,
} from "../../lib/src/common/types";
import { normalizePath } from "../../deps";
import { HiddenFileSync } from "../HiddenFileSync/CmdHiddenFileSync.ts";
} from "@lib/common/types";
import { normalizePath } from "@/deps";
import { HiddenFileSync } from "@/features/HiddenFileSync/CmdHiddenFileSync.ts";
import { LOG_LEVEL_NOTICE, Logger } from "octagonal-wheels/common/logger";
import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore.ts";
export let plugin: ObsidianLiveSyncPlugin;
@@ -1,7 +1,7 @@
import { App, Modal } from "../../deps.ts";
import { type FilePath, type LoadedEntry } from "../../lib/src/common/types.ts";
import { App, Modal } from "@/deps.ts";
import type { FilePath, LoadedEntry } from "@lib/common/models/db.type";
import JsonResolvePane from "./JsonResolvePane.svelte";
import { waitForSignal } from "../../lib/src/common/utils.ts";
import { waitForSignal } from "@lib/common/utils.ts";
import { mount, unmount } from "svelte";
export class JsonResolveModal extends Modal {
@@ -1,8 +1,8 @@
<script lang="ts">
import { type Diff, DIFF_DELETE, DIFF_INSERT, diff_match_patch } from "../../deps.ts";
import type { FilePath, LoadedEntry } from "../../lib/src/common/types.ts";
import { decodeBinary, readString } from "../../lib/src/string_and_binary/convert.ts";
import { getDocData, isObjectDifferent, mergeObject } from "../../lib/src/common/utils.ts";
import { type Diff, DIFF_DELETE, DIFF_INSERT, diff_match_patch } from "@/deps.ts";
import type { FilePath, LoadedEntry } from "@lib/common/types.ts";
import { decodeBinary, readString } from "@lib/string_and_binary/convert.ts";
import { getDocData, isObjectDifferent, mergeObject } from "@lib/common/utils.ts";
interface Props {
docs?: LoadedEntry[];
@@ -1,34 +1,24 @@
import { type PluginManifest, type ListedFiles } from "../../deps.ts";
import { type PluginManifest, type ListedFiles } from "@/deps.ts";
import type {
LoadedEntry,
FilePathWithPrefix,
FilePath,
SavingEntry,
DocumentID,
MetaEntry,
} from "@lib/common/models/db.type";
import { MODE_SELECTIVE, MODE_PAUSED } from "@lib/common/models/setting.const";
import type { UXFileInfo, UXStat, UXDataWriteOptions } from "@lib/common/models/fileaccess.type";
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE, LOG_LEVEL_DEBUG } from "@lib/common/logger";
import { ICHeader, ICHeaderEnd } from "@lib/common/models/fileaccess.const";
import { type InternalFileInfo } from "@/common/types.ts";
import { readAsBlob, isDocContentSame, readContent, createBlob } from "@lib/common/utils.database.ts";
import type { CustomRegExp } from "@lib/common/utils.regexp.ts";
import { getFileRegExp } from "@lib/common/utils.regexp.ts";
import { sendSignal, fireAndForget } from "@lib/common/utils.ts";
import { compareMTime } from "@lib/common/utils.database.ts";
import { displayRev } from "@lib/common/utils.notations.ts";
import {
type LoadedEntry,
type FilePathWithPrefix,
type FilePath,
LOG_LEVEL_INFO,
LOG_LEVEL_NOTICE,
LOG_LEVEL_VERBOSE,
MODE_SELECTIVE,
MODE_PAUSED,
type SavingEntry,
type DocumentID,
type UXFileInfo,
type UXStat,
LOG_LEVEL_DEBUG,
type MetaEntry,
type UXDataWriteOptions,
} from "../../lib/src/common/types.ts";
import { type InternalFileInfo, ICHeader, ICHeaderEnd } from "../../common/types.ts";
import {
readAsBlob,
isDocContentSame,
sendSignal,
readContent,
createBlob,
fireAndForget,
type CustomRegExp,
getFileRegExp,
} from "../../lib/src/common/utils.ts";
import {
compareMTime,
isInternalMetadata,
TARGET_IS_NEW,
scheduleTask,
@@ -38,18 +28,17 @@ import {
onlyInNTimes,
BASE_IS_NEW,
EVEN,
displayRev,
} from "../../common/utils.ts";
} from "@/common/utils.ts";
import { PeriodicProcessor } from "@/common/PeriodicProcessor.ts";
import { serialized, skipIfDuplicated } from "octagonal-wheels/concurrency/lock";
import { JsonResolveModal } from "../HiddenFileCommon/JsonResolveModal.ts";
import { LiveSyncCommands } from "../LiveSyncCommands.ts";
import { addPrefix, stripAllPrefixes } from "../../lib/src/string_and_binary/path.ts";
import { JsonResolveModal } from "@/features/HiddenFileCommon/JsonResolveModal.ts";
import { LiveSyncCommands } from "@/features/LiveSyncCommands.ts";
import { addPrefix, stripAllPrefixes } from "@lib/string_and_binary/path.ts";
import { QueueProcessor } from "octagonal-wheels/concurrency/processor";
import { hiddenFilesEventCount, hiddenFilesProcessingCount } from "../../lib/src/mock_and_interop/stores.ts";
import { EVENT_SETTING_SAVED, eventHub } from "../../common/events.ts";
import { hiddenFilesEventCount, hiddenFilesProcessingCount } from "@lib/mock_and_interop/stores.ts";
import { EVENT_SETTING_SAVED, eventHub } from "@/common/events.ts";
import { Semaphore } from "octagonal-wheels/concurrency/semaphore";
import type { LiveSyncCore } from "../../main.ts";
import type { LiveSyncCore } from "@/main.ts";
import { tryGetFilePath } from "@lib/common/utils.doc.ts";
type SyncDirection = "push" | "pull" | "safe" | "pullForce" | "pushForce";
@@ -1224,10 +1213,16 @@ Offline Changed files: ${files.length}`;
const updatedFolders = [...this.queuedNotificationFiles];
this.queuedNotificationFiles.clear();
try {
//@ts-ignore
const manifests = Object.values(this.app.plugins.manifests) as any as PluginManifest[];
//@ts-ignore
const enabledPlugins = this.app.plugins.enabledPlugins as Set<string>;
const appWithPlugins = this.app as unknown as {
plugins: {
manifests: Record<string, PluginManifest>;
enabledPlugins: Set<string>;
unloadPlugin(id: string): Promise<void>;
loadPlugin(id: string): Promise<void>;
};
};
const manifests = Object.values(appWithPlugins.plugins.manifests);
const enabledPlugins = appWithPlugins.plugins.enabledPlugins;
const enabledPluginManifests = manifests.filter((e) => enabledPlugins.has(e.id));
const modifiedManifests = enabledPluginManifests.filter((e) => updatedFolders.indexOf(e?.dir ?? "") >= 0);
for (const manifest of modifiedManifests) {
@@ -1246,10 +1241,8 @@ Offline Changed files: ${files.length}`;
LOG_LEVEL_NOTICE,
"plugin-reload-" + updatePluginId
);
// @ts-ignore
await this.app.plugins.unloadPlugin(updatePluginId);
// @ts-ignore
await this.app.plugins.loadPlugin(updatePluginId);
await appWithPlugins.plugins.unloadPlugin(updatePluginId);
await appWithPlugins.plugins.loadPlugin(updatePluginId);
this._log(
`Plugin reloaded: ${updatePluginName}`,
LOG_LEVEL_NOTICE,
+15 -21
View File
@@ -1,17 +1,11 @@
import { LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
import {
LOG_LEVEL_INFO,
LOG_LEVEL_NOTICE,
type AnyEntry,
type DocumentID,
type FilePath,
type FilePathWithPrefix,
type LOG_LEVEL,
} from "../lib/src/common/types.ts";
import type ObsidianLiveSyncPlugin from "../main.ts";
import { MARK_DONE } from "../modules/features/ModuleLog.ts";
import type { LiveSyncCore } from "../main.ts";
import { __$checkInstanceBinding } from "../lib/src/dev/checks.ts";
import type { AnyEntry, DocumentID, FilePath, FilePathWithPrefix } from "@lib/common/models/db.type";
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE } from "@lib/common/logger";
import type { LOG_LEVEL } from "@lib/common/logger";
import type ObsidianLiveSyncPlugin from "@/main.ts";
import { MARK_DONE } from "@/modules/features/ModuleLog.ts";
import type { LiveSyncCore } from "@/main.ts";
import { __$checkInstanceBinding } from "@lib/dev/checks.ts";
import { createInstanceLogFunction } from "@/lib/src/services/lib/logUtils.ts";
let noticeIndex = 0;
@@ -67,25 +61,25 @@ export abstract class LiveSyncCommands {
_log: ReturnType<typeof createInstanceLogFunction>;
_verbose = (msg: any, key?: string) => {
_verbose = (msg: unknown, key?: string) => {
this._log(msg, LOG_LEVEL_VERBOSE, key);
};
_info = (msg: any, key?: string) => {
_info = (msg: unknown, key?: string) => {
this._log(msg, LOG_LEVEL_INFO, key);
};
_notice = (msg: any, key?: string) => {
_notice = (msg: unknown, key?: string) => {
this._log(msg, LOG_LEVEL_NOTICE, key);
};
_progress = (prefix: string = "", level: LOG_LEVEL = LOG_LEVEL_NOTICE) => {
const key = `keepalive-progress-${noticeIndex++}`;
return {
log: (msg: any) => {
this._log(prefix + msg, level, key);
log: (msg: unknown) => {
this._log(prefix + String(msg), level, key);
},
once: (msg: any) => {
this._log(prefix + msg, level);
once: (msg: unknown) => {
this._log(prefix + String(msg), level);
},
done: (msg: string = "Done") => {
this._log(prefix + msg + MARK_DONE, level, key);
@@ -93,7 +87,7 @@ export abstract class LiveSyncCommands {
};
};
_debug = (msg: any, key?: string) => {
_debug = (msg: unknown, key?: string) => {
this._log(msg, LOG_LEVEL_VERBOSE, key);
};
@@ -9,14 +9,15 @@ import {
type EntryLeaf,
type FilePathWithPrefix,
type MetaEntry,
} from "../../lib/src/common/types";
import { getNoFromRev } from "../../lib/src/pouchdb/LiveSyncLocalDB";
import { LiveSyncCommands } from "../LiveSyncCommands";
} from "@lib/common/types";
import { getNoFromRev } from "@lib/pouchdb/LiveSyncLocalDB";
import { LiveSyncCommands } from "@/features/LiveSyncCommands";
import { serialized } from "octagonal-wheels/concurrency/lock_v2";
import { arrayToChunkedArray } from "octagonal-wheels/collection";
import { EVENT_ANALYSE_DB_USAGE, EVENT_REQUEST_PERFORM_GC_V3, eventHub } from "@/common/events";
import type { LiveSyncCouchDBReplicator } from "@/lib/src/replication/couchdb/LiveSyncReplicator";
import { delay } from "@/lib/src/common/utils";
import { isNotFoundError } from "@lib/common/utils.doc.ts";
// import { _requestToCouchDB } from "@/common/utils";
const DB_KEY_SEQ = "gc-seq";
const DB_KEY_CHUNK_SET = "chunk-set";
@@ -393,8 +394,8 @@ Note: **Make sure to synchronise all devices before deletion.**
await processDoc(oldDoc, false);
}
}
} catch (ex) {
if ((ex as any)?.status == 404) {
} catch (ex: unknown) {
if (ex && typeof ex === "object" && isNotFoundError(ex)) {
this._log(`No revisions found for ${doc._id}`, LOG_LEVEL_VERBOSE);
} else {
this._log(`Error finding revisions for ${doc._id}`);
@@ -473,15 +474,23 @@ Are you ready to delete unused chunks?`;
keys: [...unusedSet],
include_docs: true,
});
interface PouchDBRow {
id: string;
key: string;
value: { rev: string; deleted?: boolean };
doc?: EntryDoc;
}
for (const chunk of deleteChunks.rows) {
if ((chunk as any)?.value?.deleted) {
chunkSet.delete(chunk.key as DocumentID);
const c = chunk as unknown as PouchDBRow;
if (c.value?.deleted) {
chunkSet.delete(c.key as DocumentID);
}
}
const deleteDocs = deleteChunks.rows
.filter((e) => "doc" in e)
.map((e) => e as unknown as PouchDBRow)
.filter((e) => e.doc != null)
.map((e) => ({
...(e as any).doc!,
...e.doc!,
_deleted: true,
}));
@@ -625,8 +634,19 @@ Success: ${successCount}, Errored: ${errored}`;
}
}
}
interface DatabaseAnalysisResultItem {
title: string;
path: string;
rev: string;
revHash: string;
id?: string;
uniqueChunkCount: number;
sharedChunkCount: number;
uniqueChunkSize: number;
sharedChunkSize: number;
}
// Prepare results
const result = [];
const result: DatabaseAnalysisResultItem[] = [];
// Calculate total size of chunks in the given set.
const getTotalSize = (ids: Set<DocumentID>) => {
return [...ids].reduce((acc, chunkId) => {
@@ -698,7 +718,7 @@ Success: ${successCount}, Errored: ${errored}`;
sharedChunkCount: 0,
uniqueChunkSize: orphanChunkSize,
sharedChunkSize: 0,
} as any);
});
const csvSrc = result.map((e) => {
return [
@@ -1,13 +1,13 @@
<script lang="ts">
import { onMount, setContext } from "svelte";
import { AutoAccepting, DEFAULT_SETTINGS, type P2PSyncSetting } from "../../../lib/src/common/types";
import { AutoAccepting, DEFAULT_SETTINGS, type P2PSyncSetting } from "@lib/common/types";
import {
AcceptedStatus,
ConnectionStatus,
type PeerStatus,
} from "@lib/replication/trystero/P2PReplicatorPaneCommon";
import type { LiveSyncTrysteroReplicator } from "@lib/replication/trystero/LiveSyncTrysteroReplicator";
import PeerStatusRow from "../P2PReplicator/PeerStatusRow.svelte";
import PeerStatusRow from "@/features/P2PSync/P2PReplicator/PeerStatusRow.svelte";
import { EVENT_LAYOUT_READY, eventHub } from "@/common/events";
import {
type PeerInfo,
@@ -5,7 +5,8 @@ import { SvelteItemView } from "@/common/SvelteItemView.ts";
import { eventHub } from "@/common/events.ts";
import { unique } from "octagonal-wheels/collection";
import { LOG_LEVEL_NOTICE, REMOTE_P2P } from "@lib/common/types.ts";
import { REMOTE_P2P } from "@lib/common/models/setting.const";
import { LOG_LEVEL_NOTICE } from "@lib/common/logger";
import { Logger } from "@lib/common/logger.ts";
import { EVENT_P2P_PEER_SHOW_EXTRA_MENU, type PeerStatus } from "@lib/replication/trystero/P2PReplicatorPaneCommon.ts";
import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore.ts";
@@ -1,9 +1,9 @@
<script lang="ts">
import { getContext } from "svelte";
import { AcceptedStatus, type PeerStatus } from "../../../lib/src/replication/trystero/P2PReplicatorPaneCommon";
import type { LiveSyncTrysteroReplicator } from "../../../lib/src/replication/trystero/LiveSyncTrysteroReplicator";
import { eventHub } from "../../../common/events";
import { EVENT_P2P_PEER_SHOW_EXTRA_MENU } from "../../../lib/src/replication/trystero/P2PReplicatorPaneCommon";
import { AcceptedStatus, type PeerStatus } from "@lib/replication/trystero/P2PReplicatorPaneCommon";
import type { LiveSyncTrysteroReplicator } from "@lib/replication/trystero/LiveSyncTrysteroReplicator";
import { eventHub } from "@/common/events";
import { EVENT_P2P_PEER_SHOW_EXTRA_MENU } from "@lib/replication/trystero/P2PReplicatorPaneCommon";
interface Props {
peerStatus: PeerStatus;
+1 -1
Submodule src/lib updated: 53804cbaec...66c9ebaa1e
+16 -15
View File
@@ -4,6 +4,7 @@ setGetLanguage(getLanguage);
import { LiveSyncCommands } from "./features/LiveSyncCommands.ts";
import { HiddenFileSync } from "./features/HiddenFileSync/CmdHiddenFileSync.ts";
import { ConfigSync } from "./features/ConfigSync/CmdConfigSync.ts";
import { PluginDialogModal } from "./features/ConfigSync/PluginDialogModal.ts";
import { ModuleDev } from "./modules/extras/ModuleDev.ts";
import { ModuleInteractiveConflictResolver } from "./modules/features/ModuleInteractiveConflictResolver.ts";
@@ -13,34 +14,34 @@ import { ModuleObsidianSettingDialogue } from "./modules/features/ModuleObsidian
import { ModuleObsidianDocumentHistory } from "./modules/features/ModuleObsidianDocumentHistory.ts";
import { ModuleObsidianGlobalHistory } from "./modules/features/ModuleGlobalHistory.ts";
import { LocalDatabaseMaintenance } from "./features/LocalDatabaseMainte/CmdLocalDatabaseMainte.ts";
import type { InjectableServiceHub } from "@lib/services/implements/injectable/InjectableServiceHub.ts";
import type { InjectableServiceHub } from "./lib/src/services/implements/injectable/InjectableServiceHub.ts";
import { ObsidianServiceHub } from "./modules/services/ObsidianServiceHub.ts";
import { ServiceRebuilder } from "@lib/serviceModules/Rebuilder.ts";
import { ServiceDatabaseFileAccess } from "@/serviceModules/DatabaseFileAccess.ts";
import { ServiceFileAccessObsidian } from "@/serviceModules/ServiceFileAccessImpl.ts";
import { StorageAccessManager } from "@lib/managers/StorageProcessingManager.ts";
import { ServiceRebuilder } from "./lib/src/serviceModules/Rebuilder.ts";
import { ServiceDatabaseFileAccess } from "./serviceModules/DatabaseFileAccess.ts";
import { ServiceFileAccessObsidian } from "./serviceModules/ServiceFileAccessImpl.ts";
import { StorageAccessManager } from "./lib/src/managers/StorageProcessingManager.ts";
import { ServiceFileHandler } from "./serviceModules/FileHandler.ts";
import { FileAccessObsidian } from "./serviceModules/FileAccessObsidian.ts";
import { StorageEventManagerObsidian } from "./managers/StorageEventManagerObsidian.ts";
import type { ServiceModules } from "./types.ts";
import { setNoticeClass } from "@lib/mock_and_interop/wrapper.ts";
import type { ObsidianServiceContext } from "@lib/services/implements/obsidian/ObsidianServiceContext.ts";
import { setNoticeClass } from "./lib/src/mock_and_interop/wrapper.ts";
import type { ObsidianServiceContext } from "./lib/src/services/implements/obsidian/ObsidianServiceContext.ts";
import { LiveSyncBaseCore } from "./LiveSyncBaseCore.ts";
import { ModuleObsidianMenu } from "./modules/essentialObsidian/ModuleObsidianMenu.ts";
import { ModuleObsidianSettingsAsMarkdown } from "./modules/features/ModuleObsidianSettingAsMarkdown.ts";
import { SetupManager } from "./modules/features/SetupManager.ts";
import { ModuleMigration } from "./modules/essential/ModuleMigration.ts";
import { enableI18nFeature } from "./serviceFeatures/onLayoutReady/enablei18n.ts";
import { useOfflineScanner } from "@lib/serviceFeatures/offlineScanner.ts";
import { useRemoteConfiguration } from "@lib/serviceFeatures/remoteConfig.ts";
import { useCheckRemoteSize } from "@lib/serviceFeatures/checkRemoteSize.ts";
import { useOfflineScanner } from "./lib/src/serviceFeatures/offlineScanner.ts";
import { useRemoteConfiguration } from "./lib/src/serviceFeatures/remoteConfig.ts";
import { useCheckRemoteSize } from "./lib/src/serviceFeatures/checkRemoteSize.ts";
import { useRedFlagFeatures } from "./serviceFeatures/redFlag.ts";
import { useSetupProtocolFeature } from "./serviceFeatures/setupObsidian/setupProtocol.ts";
import { useSetupQRCodeFeature } from "@lib/serviceFeatures/setupObsidian/qrCode";
import { useSetupURIFeature } from "@lib/serviceFeatures/setupObsidian/setupUri";
import { useSetupQRCodeFeature } from "./lib/src/serviceFeatures/setupObsidian/qrCode";
import { useSetupURIFeature } from "./lib/src/serviceFeatures/setupObsidian/setupUri";
import { useSetupManagerHandlersFeature } from "./serviceFeatures/setupObsidian/setupManagerHandlers.ts";
import { useP2PReplicatorFeature } from "@lib/replication/trystero/useP2PReplicatorFeature.ts";
import { useP2PReplicatorCommands } from "@lib/replication/trystero/useP2PReplicatorCommands.ts";
import { useP2PReplicatorFeature } from "./lib/src/replication/trystero/useP2PReplicatorFeature.ts";
import { useP2PReplicatorCommands } from "./lib/src/replication/trystero/useP2PReplicatorCommands.ts";
import { useP2PReplicatorUI } from "./serviceFeatures/useP2PReplicatorUI.ts";
import { createOpenReplicationUI, createOpenRebuildUI } from "./features/P2PSync/P2PReplicator/P2PReplicationUI.ts";
export type LiveSyncCore = LiveSyncBaseCore<ObsidianServiceContext, LiveSyncCommands>;
@@ -161,7 +162,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin {
},
(core) => {
const addOns = [
new ConfigSync(this, core),
new ConfigSync(this, core, PluginDialogModal),
new HiddenFileSync(this, core),
new LocalDatabaseMaintenance(this, core),
];
@@ -20,7 +20,7 @@ import { InternalFileToUXFileInfoStub, TFileToUXFileInfoStub } from "@/modules/c
* Obsidian-specific type guard adapter
*/
class ObsidianTypeGuardAdapter implements IStorageEventTypeGuardAdapter<TFile, TFolder> {
isFile(file: any): file is TFile {
isFile(file: unknown): file is TFile {
if (file instanceof TFile) {
return true;
}
@@ -30,7 +30,7 @@ class ObsidianTypeGuardAdapter implements IStorageEventTypeGuardAdapter<TFile, T
return false;
}
isFolder(item: any): item is TFolder {
isFolder(item: unknown): item is TFolder {
if (item instanceof TFolder) {
return true;
}
+7 -6
View File
@@ -61,18 +61,19 @@ export abstract class AbstractModule<
return this.testDone(false);
}
async _test(key: string, process: () => Promise<any>) {
async _test(key: string, process: () => Promise<unknown>) {
this._log(`Testing ${key}`, LOG_LEVEL_VERBOSE);
try {
const ret = await process();
if (ret !== true) {
this.addTestResult(key, false, ret.toString());
return this.testFail(`${key} failed: ${ret}`);
this.addTestResult(key, false, String(ret));
return this.testFail(`${key} failed: ${String(ret)}`);
}
this.addTestResult(key, true, "");
} catch (ex: any) {
this.addTestResult(key, false, "Failed by Exception", ex.toString());
return this.testFail(`${key} failed: ${ex}`);
} catch (ex) {
const exStr = String(ex);
this.addTestResult(key, false, "Failed by Exception", exStr);
return this.testFail(`${key} failed: ${exStr}`);
}
return this.testDone();
}
+3 -3
View File
@@ -1,6 +1,6 @@
import { type Prettify } from "../lib/src/common/types";
import type { LiveSyncCore } from "../main";
import type ObsidianLiveSyncPlugin from "../main";
import { type Prettify } from "@lib/common/types";
import type { LiveSyncCore } from "@/main";
import type ObsidianLiveSyncPlugin from "@/main";
import { AbstractModule } from "./AbstractModule.ts";
import type { ChainableExecuteFunction, OverridableFunctionsKeys } from "./ModuleTypes";
+11 -6
View File
@@ -1,5 +1,5 @@
import type { Prettify } from "../lib/src/common/types";
import type { LiveSyncCore } from "../main";
import type { Prettify } from "@lib/common/types";
import type { LiveSyncCore } from "@/main";
export type OverridableFunctionsKeys<T> = {
[K in keyof T as K extends `$${string}` ? K : never]: T[K];
@@ -7,7 +7,8 @@ export type OverridableFunctionsKeys<T> = {
export type ChainableExecuteFunction<T> = {
[K in keyof T as K extends `$${string}`
? T[K] extends (...args: any) => ChainableFunctionResult
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
T[K] extends (...args: any) => ChainableFunctionResult
? K
: never
: never]: T[K];
@@ -26,26 +27,30 @@ export type ChainableFunctionResultOrAll = Promise<boolean | undefined | string
type AllExecuteFunction<T> = {
[K in keyof T as K extends `$all${string}`
? T[K] extends (...args: any[]) => ChainableFunctionResultOrAll
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
T[K] extends (...args: any[]) => ChainableFunctionResultOrAll
? K
: never
: never]: T[K];
};
type EveryExecuteFunction<T> = {
[K in keyof T as K extends `$every${string}`
? T[K] extends (...args: any[]) => ChainableFunctionResult
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
T[K] extends (...args: any[]) => ChainableFunctionResult
? K
: never
: never]: T[K];
};
type AnyExecuteFunction<T> = {
[K in keyof T as K extends `$any${string}`
? T[K] extends (...args: any[]) => ChainableFunctionResult
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
T[K] extends (...args: any[]) => ChainableFunctionResult
? K
: never
: never]: T[K];
};
type InjectableFunction<T> = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[K in keyof T as K extends `$$${string}` ? (T[K] extends (...args: any[]) => any ? K : never) : never]: T[K];
};
export type AllExecuteProps = AllExecuteFunction<LiveSyncCore>;
+2 -2
View File
@@ -1,6 +1,6 @@
import { PeriodicProcessor } from "@/common/PeriodicProcessor";
import type { LiveSyncCore } from "../../main";
import { AbstractModule } from "../AbstractModule";
import type { LiveSyncCore } from "@/main";
import { AbstractModule } from "@/modules/AbstractModule";
export class ModulePeriodicProcess extends AbstractModule {
periodicSyncProcessor = new PeriodicProcessor(this.core, async () => await this.services.replication.replicate());
+8 -8
View File
@@ -1,18 +1,18 @@
import type PouchDB from "pouchdb-core";
import { fireAndForget } from "octagonal-wheels/promises";
import { AbstractModule } from "../AbstractModule";
import { AbstractModule } from "@/modules/AbstractModule";
import { Logger, LOG_LEVEL_NOTICE, LOG_LEVEL_INFO } from "octagonal-wheels/common/logger";
import { skipIfDuplicated } from "octagonal-wheels/concurrency/lock";
import { balanceChunkPurgedDBs } from "@lib/pouchdb/chunks";
import { purgeUnreferencedChunks } from "@lib/pouchdb/chunks";
import { LiveSyncCouchDBReplicator } from "../../lib/src/replication/couchdb/LiveSyncReplicator";
import { type EntryDoc, type RemoteType } from "../../lib/src/common/types";
import { LiveSyncCouchDBReplicator } from "@lib/replication/couchdb/LiveSyncReplicator";
import { type EntryDoc, type RemoteType } from "@lib/common/types";
import { scheduleTask } from "octagonal-wheels/concurrency/task";
import { EVENT_FILE_SAVED, EVENT_SETTING_SAVED, eventHub } from "../../common/events";
import { EVENT_FILE_SAVED, EVENT_SETTING_SAVED, eventHub } from "@/common/events";
import { $msg } from "../../lib/src/common/i18n";
import type { LiveSyncCore } from "../../main";
import { $msg } from "@lib/common/i18n";
import type { LiveSyncCore } from "@/main";
import { ReplicateResultProcessor } from "./ReplicateResultProcessor";
import { UnresolvedErrorManager } from "@lib/services/base/UnresolvedErrorManager";
import { clearHandlers } from "@lib/replication/SyncParamsHandler";
@@ -21,7 +21,7 @@ import { MARK_LOG_NETWORK_ERROR } from "@lib/services/lib/logUtils";
function isOnlineAndCanReplicate(
errorManager: UnresolvedErrorManager,
host: NecessaryServices<"API", any>,
host: NecessaryServices<"API", never>,
showMessage: boolean
): Promise<boolean> {
const errorMessage = "Network is offline";
@@ -34,7 +34,7 @@ function isOnlineAndCanReplicate(
}
async function canReplicateWithPBKDF2(
errorManager: UnresolvedErrorManager,
host: NecessaryServices<"replicator" | "setting", any>,
host: NecessaryServices<"replicator" | "setting", never>,
showMessage: boolean
): Promise<boolean> {
const currentSettings = host.services.setting.currentSettings();
+5 -5
View File
@@ -1,9 +1,9 @@
import { fireAndForget } from "octagonal-wheels/promises";
import { REMOTE_MINIO, REMOTE_P2P, type RemoteDBSettings } from "../../lib/src/common/types";
import { LiveSyncCouchDBReplicator } from "../../lib/src/replication/couchdb/LiveSyncReplicator";
import type { LiveSyncAbstractReplicator } from "../../lib/src/replication/LiveSyncAbstractReplicator";
import { AbstractModule } from "../AbstractModule";
import type { LiveSyncCore } from "../../main";
import { REMOTE_MINIO, REMOTE_P2P, type RemoteDBSettings } from "@lib/common/types";
import { LiveSyncCouchDBReplicator } from "@lib/replication/couchdb/LiveSyncReplicator";
import type { LiveSyncAbstractReplicator } from "@lib/replication/LiveSyncAbstractReplicator";
import { AbstractModule } from "@/modules/AbstractModule";
import type { LiveSyncCore } from "@/main";
export class ModuleReplicatorCouchDB extends AbstractModule {
_anyNewReplicator(settingOverride: Partial<RemoteDBSettings> = {}): Promise<LiveSyncAbstractReplicator | false> {
+5 -5
View File
@@ -1,8 +1,8 @@
import { REMOTE_MINIO, type RemoteDBSettings } from "../../lib/src/common/types";
import { LiveSyncJournalReplicator } from "../../lib/src/replication/journal/LiveSyncJournalReplicator";
import type { LiveSyncAbstractReplicator } from "../../lib/src/replication/LiveSyncAbstractReplicator";
import type { LiveSyncCore } from "../../main";
import { AbstractModule } from "../AbstractModule";
import { REMOTE_MINIO, type RemoteDBSettings } from "@lib/common/types";
import { LiveSyncJournalReplicator } from "@lib/replication/journal/LiveSyncJournalReplicator";
import type { LiveSyncAbstractReplicator } from "@lib/replication/LiveSyncAbstractReplicator";
import type { LiveSyncCore } from "@/main";
import { AbstractModule } from "@/modules/AbstractModule";
export class ModuleReplicatorMinIO extends AbstractModule {
_anyNewReplicator(settingOverride: Partial<RemoteDBSettings> = {}): Promise<LiveSyncAbstractReplicator | false> {
+6 -4
View File
@@ -17,7 +17,9 @@ import {
Logger,
type LOG_LEVEL,
} from "@lib/common/logger";
import { fireAndForget, isAnyNote, throttle } from "@lib/common/utils";
import { isAnyNote } from "@lib/common/utils.database";
import { fireAndForget, throttle } from "@lib/common/utils";
import { isNotFoundError } from "@lib/common/utils.doc.ts";
import { Semaphore } from "octagonal-wheels/concurrency/semaphore_v2";
import { serialized } from "octagonal-wheels/concurrency/lock";
import type { ReactiveSource } from "octagonal-wheels/dataobject/reactive_v2";
@@ -39,7 +41,7 @@ export class ReplicateResultProcessor {
private log(message: string, level: LOG_LEVEL = LOG_LEVEL_INFO) {
Logger(`[ReplicateResultProcessor] ${message}`, level);
}
private logError(e: any) {
private logError(e: unknown) {
Logger(e, LOG_LEVEL_VERBOSE);
}
private replicator: ModuleReplicator;
@@ -466,8 +468,8 @@ export class ReplicateResultProcessor {
return false; // This means that the document already processed (While no conflict existed).
}
return true; // This mostly should not happen, but we have to process it just in case.
} catch (e: any) {
if ("status" in e && e.status == 404) {
} catch (e: unknown) {
if (e && typeof e === "object" && isNotFoundError(e)) {
// getRaw failed due to not existing, it may not be happened normally especially on replication.
// If the process caused by some other reason, we **probably** have to process it.
// Note that this is not a common case.
@@ -1,9 +1,9 @@
import { AbstractModule } from "../AbstractModule.ts";
import { LOG_LEVEL_NOTICE, type FilePathWithPrefix } from "../../lib/src/common/types";
import { AbstractModule } from "@/modules/AbstractModule.ts";
import { LOG_LEVEL_NOTICE, type FilePathWithPrefix } from "@lib/common/types";
import { QueueProcessor } from "octagonal-wheels/concurrency/processor";
import { sendValue } from "octagonal-wheels/messagepassing/signal";
import type { InjectableServiceHub } from "../../lib/src/services/InjectableServices.ts";
import type { LiveSyncCore } from "../../main.ts";
import type { InjectableServiceHub } from "@lib/services/InjectableServices.ts";
import type { LiveSyncCore } from "@/main.ts";
export class ModuleConflictChecker extends AbstractModule {
async _queueConflictCheckIfOpen(file: FilePathWithPrefix): Promise<void> {
@@ -1,5 +1,5 @@
import { serialized } from "octagonal-wheels/concurrency/lock";
import { AbstractModule } from "../AbstractModule.ts";
import { AbstractModule } from "@/modules/AbstractModule.ts";
import {
AUTO_MERGED,
CANCELLED,
@@ -10,15 +10,16 @@ import {
NOT_CONFLICTED,
type diff_check_result,
type FilePathWithPrefix,
} from "../../lib/src/common/types";
} from "@lib/common/types";
import { isCustomisationSyncMetadata, isPluginMetadata } from "@lib/common/typeUtils.ts";
import { TARGET_IS_NEW } from "@lib/common/models/shared.const.symbols.ts";
import { compareMTime, displayRev } from "@lib/common/utils.ts";
import { compareMTime } from "@lib/common/utils.database.ts";
import { displayRev } from "@lib/common/utils.notations.ts";
import diff_match_patch from "diff-match-patch";
import { stripAllPrefixes, isPlainText } from "../../lib/src/string_and_binary/path";
import { eventHub } from "../../common/events.ts";
import type { InjectableServiceHub } from "../../lib/src/services/InjectableServices.ts";
import type { LiveSyncCore } from "../../main.ts";
import { stripAllPrefixes, isPlainText } from "@lib/string_and_binary/path";
import { eventHub } from "@/common/events.ts";
import type { InjectableServiceHub } from "@lib/services/InjectableServices.ts";
import type { LiveSyncCore } from "@/main.ts";
declare global {
interface LSEvents {
@@ -1,31 +1,30 @@
import { Logger, LOG_LEVEL_NOTICE } from "octagonal-wheels/common/logger";
import { extractObject } from "octagonal-wheels/object";
import type { TweakValues } from "@lib/common/models/tweak.definition";
import {
TweakValuesShouldMatchedTemplate,
TweakValuesTemplate,
IncompatibleChanges,
confName,
type TweakValues,
type ObsidianLiveSyncSettings,
type RemoteDBSettings,
IncompatibleChangesInSpecificPattern,
CompatibleButLossyChanges,
} from "../../lib/src/common/types.ts";
import { escapeMarkdownValue } from "../../lib/src/common/utils.ts";
import { AbstractModule } from "../AbstractModule.ts";
import { $msg } from "../../lib/src/common/i18n.ts";
import type { InjectableServiceHub } from "../../lib/src/services/InjectableServices.ts";
import type { LiveSyncCore } from "../../main.ts";
} from "@lib/common/models/tweak.definition";
import { confName } from "@lib/common/models/shared.definition.configNames";
import type { ObsidianLiveSyncSettings, RemoteDBSettings } from "@lib/common/models/setting.type";
import { escapeMarkdownValue } from "@lib/common/utils.notations.ts";
import { AbstractModule } from "@/modules/AbstractModule.ts";
import { $msg } from "@lib/common/i18n.ts";
import type { InjectableServiceHub } from "@lib/services/InjectableServices.ts";
import type { LiveSyncCore } from "@/main.ts";
import { REMOTE_P2P } from "@lib/common/models/setting.const.ts";
function valueToString(value: any) {
function valueToString(value: unknown) {
if (typeof value === "boolean") {
return value ? "true" : "false";
}
if (typeof value === "object") {
if (typeof value === "object" && value !== null) {
return JSON.stringify(value);
}
return `${value}`;
return String(value);
}
export class ModuleResolvingMismatchedTweaks extends AbstractModule {
+2 -2
View File
@@ -1,6 +1,6 @@
import { ButtonComponent } from "@/deps.ts";
import { App, FuzzySuggestModal, MarkdownRenderer, Modal, Plugin, Setting } from "../../../deps.ts";
import { EVENT_PLUGIN_UNLOADED, eventHub } from "../../../common/events.ts";
import { App, FuzzySuggestModal, MarkdownRenderer, Modal, Plugin, Setting } from "@/deps.ts";
import { EVENT_PLUGIN_UNLOADED, eventHub } from "@/common/events.ts";
import { compatGlobal, type CompatIntervalHandle } from "@lib/common/coreEnvFunctions.ts";
class AutoClosableModal extends Modal {
@@ -1,19 +1,18 @@
// Obsidian to LiveSync Utils
import { TFile, type TAbstractFile, type TFolder } from "../../../deps.ts";
import { ICHeader } from "../../../common/types.ts";
import { addPrefix, isPlainText } from "../../../lib/src/string_and_binary/path.ts";
import { TFile, type TAbstractFile, type TFolder } from "@/deps.ts";
import { ICHeader } from "@lib/common/models/fileaccess.const";
import { addPrefix, isPlainText } from "@lib/string_and_binary/path.ts";
import { LOG_LEVEL_VERBOSE, Logger } from "octagonal-wheels/common/logger";
import { createBlob } from "../../../lib/src/common/utils.ts";
import { createBlob } from "@lib/common/utils.database.ts";
import type { FilePath, FilePathWithPrefix } from "@lib/common/models/db.type";
import type {
FilePath,
FilePathWithPrefix,
UXFileInfo,
UXFileInfoStub,
UXFolderInfo,
UXInternalFileInfoStub,
} from "../../../lib/src/common/types.ts";
import type { LiveSyncCore } from "../../../main.ts";
} from "@lib/common/models/fileaccess.type";
import type { LiveSyncCore } from "@/main.ts";
import type { FileAccessObsidian } from "@/serviceModules/FileAccessObsidian.ts";
export async function TFileToUXFileInfo(
+1 -1
View File
@@ -1,7 +1,7 @@
import type { LiveSyncCore } from "@/main";
import { LOG_LEVEL_NOTICE } from "octagonal-wheels/common/logger";
import { fireAndForget } from "octagonal-wheels/promises";
import { AbstractModule } from "../AbstractModule";
import { AbstractModule } from "@/modules/AbstractModule";
// Separated Module for basic menu commands, which are not related to obsidian specific features. It is expected to be used in other platforms with minimal changes.
// However, it is odd that it has here at all; it really ought to be in each respective feature. It will likely be moved eventually. Until now, addCommand pointed to Obsidian's version.
export class ModuleBasicMenu extends AbstractModule {
+10 -10
View File
@@ -1,4 +1,4 @@
import { LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE, Logger } from "../../lib/src/common/logger.ts";
import { LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE, Logger } from "@lib/common/logger.ts";
import {
EVENT_REQUEST_OPEN_P2P,
EVENT_REQUEST_OPEN_SETTING_WIZARD,
@@ -6,16 +6,16 @@ import {
EVENT_REQUEST_RUN_DOCTOR,
EVENT_REQUEST_RUN_FIX_INCOMPLETE,
eventHub,
} from "../../common/events.ts";
import { AbstractModule } from "../AbstractModule.ts";
} from "@/common/events.ts";
import { AbstractModule } from "@/modules/AbstractModule.ts";
import { $msg } from "@lib/common/i18n.ts";
import { performDoctorConsultation, RebuildOptions } from "../../lib/src/common/configForDoc.ts";
import { isValidPath } from "../../common/utils.ts";
import { isMetaEntry } from "../../lib/src/common/types.ts";
import { isDeletedEntry, isDocContentSame, isLoadedEntry, readAsBlob } from "../../lib/src/common/utils.ts";
import { countCompromisedChunks } from "../../lib/src/pouchdb/negotiation.ts";
import type { LiveSyncCore } from "../../main.ts";
import { SetupManager } from "../features/SetupManager.ts";
import { performDoctorConsultation, RebuildOptions } from "@lib/common/configForDoc.ts";
import { isValidPath } from "@/common/utils.ts";
import { isMetaEntry } from "@lib/common/models/db.definition";
import { isDeletedEntry, isDocContentSame, isLoadedEntry, readAsBlob } from "@lib/common/utils.database.ts";
import { countCompromisedChunks } from "@lib/pouchdb/negotiation.ts";
import type { LiveSyncCore } from "@/main.ts";
import { SetupManager } from "@/modules/features/SetupManager.ts";
type ErrorInfo = {
path: string;
@@ -8,7 +8,7 @@ import { HttpRequest, HttpResponse, type HttpHandlerOptions } from "@smithy/prot
//@ts-ignore
import { requestTimeout } from "@smithy/fetch-http-handler/dist-es/request-timeout";
import { buildQueryString } from "@smithy/querystring-builder";
import { requestUrl, type RequestUrlParam } from "../../../deps.ts";
import { requestUrl, type RequestUrlParam } from "@/deps.ts";
////////////////////////////////////////////////////////////////////////////////
// special handler using Obsidian requestUrl
////////////////////////////////////////////////////////////////////////////////
@@ -68,9 +68,13 @@ export class ObsHttpHandler extends FetchHttpHandler {
contentType = transformedHeaders["content-type"];
}
let transformedBody: any = body;
if (ArrayBuffer.isView(body)) {
transformedBody = new Uint8Array(body.buffer).buffer;
let transformedBody: string | ArrayBuffer | undefined = undefined;
if (typeof body === "string" || body instanceof ArrayBuffer) {
transformedBody = body;
} else if (ArrayBuffer.isView(body)) {
transformedBody = body.buffer as ArrayBuffer;
} else if (body != null) {
transformedBody = body as string | ArrayBuffer;
}
const param: RequestUrlParam = {
@@ -1,18 +1,18 @@
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
import { EVENT_FILE_RENAMED, EVENT_LEAF_ACTIVE_CHANGED, eventHub } from "../../common/events.js";
import { AbstractObsidianModule } from "@/modules/AbstractObsidianModule.ts";
import { EVENT_FILE_RENAMED, EVENT_LEAF_ACTIVE_CHANGED, eventHub } from "@/common/events.js";
import { LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
import { scheduleTask } from "octagonal-wheels/concurrency/task";
import { type TFile } from "../../deps.ts";
import { type TFile } from "@/deps.ts";
import { fireAndForget } from "octagonal-wheels/promises";
import { type FilePathWithPrefix } from "../../lib/src/common/types.ts";
import type { FilePathWithPrefix } from "@lib/common/models/db.type";
import { reactive, reactiveSource, type ReactiveSource } from "octagonal-wheels/dataobject/reactive";
import {
collectingChunks,
pluginScanningCount,
hiddenFilesEventCount,
hiddenFilesProcessingCount,
} from "../../lib/src/mock_and_interop/stores.ts";
import type { LiveSyncCore } from "../../main.ts";
} from "@lib/mock_and_interop/stores.ts";
import type { LiveSyncCore } from "@/main.ts";
import { compatGlobal } from "@lib/common/coreEnvFunctions.ts";
export class ModuleObsidianEvents extends AbstractObsidianModule {
@@ -36,13 +36,14 @@ export class ModuleObsidianEvents extends AbstractObsidianModule {
this.services.appLifecycle.performRestart();
}
initialCallback: any;
initialCallback: (() => unknown) | undefined;
swapSaveCommand() {
this._log("Modifying callback of the save command", LOG_LEVEL_VERBOSE);
const saveCommandDefinition = (this.app as any).commands?.commands?.["editor:save-file"];
const app = this.app as unknown as { commands?: { commands?: Record<string, { callback?: () => unknown }> } };
const saveCommandDefinition = app.commands?.commands?.["editor:save-file"];
const save = saveCommandDefinition?.callback;
if (typeof save === "function") {
if (typeof save === "function" && saveCommandDefinition) {
this.initialCallback = save;
saveCommandDefinition.callback = () => {
scheduleTask("syncOnEditorSave", 250, () => {
@@ -1,9 +1,9 @@
import { type Editor, type MarkdownFileInfo, type MarkdownView } from "@/deps.ts";
import { addIcon } from "@/deps.ts";
import { type FilePathWithPrefix } from "@lib/common/types.ts";
import type { FilePathWithPrefix } from "@lib/common/models/db.type";
import { $msg } from "@lib/common/i18n.ts";
import type { LiveSyncCore } from "@/main.ts";
import { AbstractModule } from "../AbstractModule.ts";
import { AbstractModule } from "@/modules/AbstractModule.ts";
// Obsidian specific menu commands.
export class ModuleObsidianMenu extends AbstractModule {
_everyOnloadStart(): Promise<boolean> {
+5 -50
View File
@@ -1,13 +1,12 @@
import { delay, fireAndForget } from "octagonal-wheels/promises";
import { __onMissingTranslation } from "../../lib/src/common/i18n";
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
import { delay } from "octagonal-wheels/promises";
import { __onMissingTranslation } from "@lib/common/i18n";
import { AbstractObsidianModule } from "@/modules/AbstractObsidianModule.ts";
import { LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
import { eventHub } from "../../common/events";
import { enableTestFunction } from "./devUtil/testUtils.ts";
import { TestPaneView, VIEW_TYPE_TEST } from "./devUtil/TestPaneView.ts";
import { writable } from "svelte/store";
import type { FilePathWithPrefix } from "../../lib/src/common/types.ts";
import type { LiveSyncCore } from "../../main.ts";
import type { FilePathWithPrefix } from "@lib/common/models/db.type";
import type { LiveSyncCore } from "@/main.ts";
export class ModuleDev extends AbstractObsidianModule {
_everyOnloadStart(): Promise<boolean> {
__onMissingTranslation(() => {});
@@ -41,50 +40,6 @@ export class ModuleDev extends AbstractObsidianModule {
__onMissingTranslation((key) => {
void this.onMissingTranslation(key);
});
type STUB = {
toc: Set<string>;
stub: { [key: string]: { [key: string]: Map<string, Record<string, string>> } };
};
eventHub.onEvent("document-stub-created", (detail: STUB) => {
fireAndForget(async () => {
const stub = detail.stub;
const toc = detail.toc;
const stubDocX = Object.entries(stub)
.map(([key, value]) => {
return [
`## ${key}`,
Object.entries(value)
.map(([key2, value2]) => {
return [
`### ${key2}`,
[...value2.entries()].map(([key3, value3]) => {
// return `#### ${key3}` + "\n" + JSON.stringify(value3);
const isObsolete = value3["is_obsolete"] ? " (obsolete)" : "";
const desc = value3["desc"] ?? "";
const key = value3["key"] ? "Setting key: " + value3["key"] + "\n" : "";
return `#### ${key3}${isObsolete}\n${key}${desc}\n`;
}),
].flat();
})
.flat(),
].flat();
})
.flat();
const stubDocMD =
`
| Icon | Description |
| :---: | ----------------------------------------------------------------- |
` +
[...toc.values()].map((e) => `${e}`).join("\n") +
"\n\n" +
stubDocX.join("\n");
await this.core.storageAccess.writeHiddenFileAuto(
this.app.vault.configDir + "/ls-debug/stub-doc.md",
stubDocMD
);
});
});
enableTestFunction(this.plugin);
this.registerView(VIEW_TYPE_TEST, (leaf) => new TestPaneView(leaf, this.plugin, this));
+4 -4
View File
@@ -1,11 +1,11 @@
<script lang="ts">
import { onMount } from "svelte";
import type ObsidianLiveSyncPlugin from "../../../main.ts";
import type ObsidianLiveSyncPlugin from "@/main.ts";
import { perf_trench } from "./tests.ts";
import { MarkdownRenderer, Notice } from "../../../deps.ts";
import type { ModuleDev } from "../ModuleDev.ts";
import { MarkdownRenderer, Notice } from "@/deps.ts";
import type { ModuleDev } from "@/modules/extras/ModuleDev.ts";
import { fireAndForget } from "octagonal-wheels/promises";
import { EVENT_LAYOUT_READY, eventHub } from "../../../common/events.ts";
import { EVENT_LAYOUT_READY, eventHub } from "@/common/events.ts";
export let plugin: ObsidianLiveSyncPlugin;
export let moduleDev: ModuleDev;
$: core = plugin.core;
+2 -2
View File
@@ -1,7 +1,7 @@
import { ItemView, WorkspaceLeaf } from "@/deps.ts";
import TestPaneComponent from "./TestPane.svelte";
import type ObsidianLiveSyncPlugin from "../../../main.ts";
import type { ModuleDev } from "../ModuleDev.ts";
import type ObsidianLiveSyncPlugin from "@/main.ts";
import type { ModuleDev } from "@/modules/extras/ModuleDev.ts";
export const VIEW_TYPE_TEST = "ols-pane-test";
declare global {
interface LSEvents {
+4 -4
View File
@@ -1,12 +1,12 @@
import { fireAndForget } from "../../../lib/src/common/utils.ts";
import { fireAndForget } from "@lib/common/utils.ts";
import { serialized } from "octagonal-wheels/concurrency/lock";
import type ObsidianLiveSyncPlugin from "../../../main.ts";
import type ObsidianLiveSyncPlugin from "@/main.ts";
let plugin: ObsidianLiveSyncPlugin;
export function enableTestFunction(plugin_: ObsidianLiveSyncPlugin) {
plugin = plugin_;
}
export function addDebugFileLog(message: any, stackLog = false) {
export function addDebugFileLog(message: unknown, stackLog = false) {
fireAndForget(
serialized("debug-log", async () => {
const now = new Date();
@@ -16,7 +16,7 @@ export function addDebugFileLog(message: any, stackLog = false) {
// const messageContent = typeof message == "string" ? message : message instanceof Error ? `${message.name}:${message.message}` : JSON.stringify(message, null, 2);
const timestamp = now.toLocaleString();
const timestampEpoch = now;
let out = { timestamp: timestamp, epoch: timestampEpoch } as Record<string, any>;
let out = { timestamp: timestamp, epoch: timestampEpoch } as Record<string, unknown>;
if (message instanceof Error) {
// debugger;
// console.dir(message.stack);
@@ -1,19 +1,14 @@
import { TFile, Modal, App, DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch } from "../../../deps.ts";
import { getPathFromTFile, isValidPath } from "../../../common/utils.ts";
import { decodeBinary, readString } from "../../../lib/src/string_and_binary/convert.ts";
import ObsidianLiveSyncPlugin from "../../../main.ts";
import {
type DocumentID,
type FilePathWithPrefix,
type LoadedEntry,
LOG_LEVEL_INFO,
LOG_LEVEL_NOTICE,
LOG_LEVEL_VERBOSE,
} from "../../../lib/src/common/types.ts";
import { Logger } from "../../../lib/src/common/logger.ts";
import { isErrorOfMissingDoc } from "../../../lib/src/pouchdb/utils_couchdb.ts";
import { fireAndForget, getDocData, readContent } from "../../../lib/src/common/utils.ts";
import { isPlainText, stripPrefix } from "../../../lib/src/string_and_binary/path.ts";
import { TFile, Modal, App, DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch } from "@/deps.ts";
import { getPathFromTFile, isValidPath } from "@/common/utils.ts";
import { decodeBinary, readString } from "@lib/string_and_binary/convert.ts";
import type ObsidianLiveSyncPlugin from "@/main.ts";
import type { DocumentID, FilePathWithPrefix, LoadedEntry } from "@lib/common/models/db.type";
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "@lib/common/logger";
import { Logger } from "@lib/common/logger.ts";
import { isErrorOfMissingDoc } from "@lib/pouchdb/utils_couchdb.ts";
import { getDocData, readContent } from "@lib/common/utils.database.ts";
import { fireAndForget } from "@lib/common/utils.ts";
import { isPlainText, stripPrefix } from "@lib/string_and_binary/path.ts";
import { scheduleOnceIfDuplicated } from "octagonal-wheels/concurrency/lock";
import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore.ts";
import { compatGlobal } from "@lib/common/coreEnvFunctions.ts";
@@ -139,7 +134,7 @@ export class DocumentHistoryModal extends Modal {
this.range.value = `${this.revs_info.length - 1 - rIndex}`;
}
}
const index = this.revs_info.length - 1 - (this.range.value as any) / 1;
const index = this.revs_info.length - 1 - Number(this.range.value);
const rev = this.revs_info[index];
await this.showExactRev(rev.rev);
}
@@ -251,7 +246,7 @@ export class DocumentHistoryModal extends Modal {
}
let rendered = false;
if (this.showDiff) {
const prevRevIdx = this.revs_info.length - 1 - ((this.range.value as any) / 1 - 1);
const prevRevIdx = this.revs_info.length - 1 - (Number(this.range.value) - 1);
if (prevRevIdx >= 0 && prevRevIdx < this.revs_info.length) {
const oldRev = this.revs_info[prevRevIdx].rev;
const w2 = await db.getDBEntry(this.file, { rev: oldRev }, false, false, true);
@@ -550,7 +545,7 @@ export class DocumentHistoryModal extends Modal {
if (this.showDiff) {
checkbox.checked = true;
}
checkbox.addEventListener("input", (evt: any) => {
checkbox.addEventListener("input", (evt) => {
this.showDiff = checkbox.checked;
this.app.saveLocalStorage("ols-history-highlightdiff", this.showDiff == true ? "1" : null);
this.updateDiffNavVisibility();
@@ -565,7 +560,7 @@ export class DocumentHistoryModal extends Modal {
if (this.diffOnly) {
checkbox.checked = true;
}
checkbox.addEventListener("input", (evt: any) => {
checkbox.addEventListener("input", (evt) => {
this.diffOnly = checkbox.checked;
this.app.saveLocalStorage("ols-history-diffonly", this.diffOnly == true ? "1" : null);
void scheduleOnceIfDuplicated("loadRevs", () => this.loadRevs());
@@ -1,11 +1,11 @@
<script lang="ts">
import ObsidianLiveSyncPlugin from "../../../main.ts";
import type ObsidianLiveSyncPlugin from "@/main.ts";
import { onDestroy, onMount } from "svelte";
import type { AnyEntry, FilePathWithPrefix } from "../../../lib/src/common/types.ts";
import { getDocData, isAnyNote, isDocContentSame, readAsBlob } from "../../../lib/src/common/utils.ts";
import { diff_match_patch } from "../../../deps.ts";
import { DocumentHistoryModal } from "../DocumentHistory/DocumentHistoryModal.ts";
import { isPlainText, stripAllPrefixes } from "../../../lib/src/string_and_binary/path.ts";
import type { AnyEntry, FilePathWithPrefix } from "@lib/common/types.ts";
import { getDocData, isAnyNote, isDocContentSame, readAsBlob } from "@lib/common/utils.ts";
import { diff_match_patch } from "@/deps.ts";
import { DocumentHistoryModal } from "@/modules/features/DocumentHistory/DocumentHistoryModal.ts";
import { isPlainText, stripAllPrefixes } from "@lib/string_and_binary/path.ts";
import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore.ts";
export let plugin: ObsidianLiveSyncPlugin;
export let core: LiveSyncBaseCore;
@@ -1,7 +1,7 @@
import { WorkspaceLeaf } from "../../../deps.ts";
import { WorkspaceLeaf } from "@/deps.ts";
import GlobalHistoryComponent from "./GlobalHistory.svelte";
import type ObsidianLiveSyncPlugin from "../../../main.ts";
import { SvelteItemView } from "../../../common/SvelteItemView.ts";
import type ObsidianLiveSyncPlugin from "@/main.ts";
import { SvelteItemView } from "@/common/SvelteItemView.ts";
import { mount } from "svelte";
export const VIEW_TYPE_GLOBAL_HISTORY = "global-history";
@@ -1,9 +1,10 @@
import { App, Modal } from "../../../deps.ts";
import { App, Modal } from "@/deps.ts";
import { DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT } from "diff-match-patch";
import { CANCELLED, LEAVE_TO_SUBSEQUENT, type diff_result } from "../../../lib/src/common/types.ts";
import { delay } from "../../../lib/src/common/utils.ts";
import { eventHub } from "../../../common/events.ts";
import { globalSlipBoard } from "../../../lib/src/bureau/bureau.ts";
import { CANCELLED, LEAVE_TO_SUBSEQUENT } from "@lib/common/models/shared.const.symbols";
import type { diff_result } from "@lib/common/models/diff.definition";
import { delay } from "@lib/common/utils.ts";
import { eventHub } from "@/common/events.ts";
import { globalSlipBoard } from "@lib/bureau/bureau.ts";
export type MergeDialogResult = typeof CANCELLED | typeof LEAVE_TO_SUBSEQUENT | string;
+3 -3
View File
@@ -1,9 +1,9 @@
<script lang="ts">
import { onDestroy, onMount } from "svelte";
import { logMessages } from "../../../lib/src/mock_and_interop/stores";
import { logMessages } from "@lib/mock_and_interop/stores";
import { reactive, type ReactiveInstance } from "octagonal-wheels/dataobject/reactive";
import { Logger } from "../../../lib/src/common/logger";
import { $msg as msg, currentLang as lang } from "../../../lib/src/common/i18n.ts";
import { Logger } from "@lib/common/logger";
import { $msg as msg, currentLang as lang } from "@lib/common/i18n.ts";
import { compatGlobal } from "@lib/common/coreEnvFunctions.ts";
let unsubscribe: () => void;
+2 -2
View File
@@ -1,7 +1,7 @@
import { WorkspaceLeaf } from "@/deps.ts";
import LogPaneComponent from "./LogPane.svelte";
import type ObsidianLiveSyncPlugin from "../../../main.ts";
import { SvelteItemView } from "../../../common/SvelteItemView.ts";
import type ObsidianLiveSyncPlugin from "@/main.ts";
import { SvelteItemView } from "@/common/SvelteItemView.ts";
import { $msg } from "@lib/common/i18n.ts";
import { mount } from "svelte";
export const VIEW_TYPE_LOG = "log-log";
+1 -1
View File
@@ -1,4 +1,4 @@
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
import { AbstractObsidianModule } from "@/modules/AbstractObsidianModule.ts";
import { VIEW_TYPE_GLOBAL_HISTORY, GlobalHistoryView } from "./GlobalHistory/GlobalHistoryView.ts";
export class ModuleObsidianGlobalHistory extends AbstractObsidianModule {
@@ -1,20 +1,13 @@
import {
CANCELLED,
LEAVE_TO_SUBSEQUENT,
LOG_LEVEL_INFO,
LOG_LEVEL_NOTICE,
LOG_LEVEL_VERBOSE,
MISSING_OR_ERROR,
type DocumentID,
type FilePathWithPrefix,
type diff_result,
} from "../../lib/src/common/types.ts";
import { CANCELLED, LEAVE_TO_SUBSEQUENT, MISSING_OR_ERROR } from "@lib/common/models/shared.const.symbols";
import type { DocumentID, FilePathWithPrefix } from "@lib/common/models/db.type";
import type { diff_result } from "@lib/common/models/diff.definition";
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "@lib/common/logger";
import { ConflictResolveModal } from "./InteractiveConflictResolving/ConflictResolveModal.ts";
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
import { displayRev } from "../../common/utils.ts";
import { AbstractObsidianModule } from "@/modules/AbstractObsidianModule.ts";
import { displayRev } from "@lib/common/utils.notations.ts";
import { fireAndForget } from "octagonal-wheels/promises";
import { serialized } from "octagonal-wheels/concurrency/lock";
import type { LiveSyncCore } from "../../main.ts";
import type { LiveSyncCore } from "@/main.ts";
export class ModuleInteractiveConflictResolver extends AbstractObsidianModule {
_everyOnloadStart(): Promise<boolean> {
+14 -17
View File
@@ -1,14 +1,11 @@
import { computed, reactive, reactiveSource, type ReactiveValue } from "octagonal-wheels/dataobject/reactive";
import {
LOG_LEVEL_DEBUG,
LOG_LEVEL_INFO,
LOG_LEVEL_VERBOSE,
PREFIXMD_LOGFILE,
type DatabaseConnectingStatus,
type LOG_LEVEL,
} from "../../lib/src/common/types.ts";
import { PREFIXMD_LOGFILE } from "@lib/common/models/redflag.const";
import type { DatabaseConnectingStatus } from "@lib/common/models/shared.definition";
import { LOG_LEVEL_DEBUG, LOG_LEVEL_INFO, LOG_LEVEL_VERBOSE } from "@lib/common/logger";
import type { LOG_LEVEL } from "@lib/common/logger";
import { cancelTask, scheduleTask } from "octagonal-wheels/concurrency/task";
import { fireAndForget, isDirty, throttle } from "../../lib/src/common/utils.ts";
import { isDirty } from "@lib/common/utils.misc.ts";
import { fireAndForget, throttle } from "@lib/common/utils.ts";
import {
collectingChunks,
pluginScanningCount,
@@ -16,22 +13,22 @@ import {
hiddenFilesProcessingCount,
type LogEntry,
logMessages,
} from "../../lib/src/mock_and_interop/stores.ts";
import { eventHub } from "../../lib/src/hub/hub.ts";
} from "@lib/mock_and_interop/stores.ts";
import { eventHub } from "@lib/hub/hub.ts";
import {
EVENT_FILE_RENAMED,
EVENT_LAYOUT_READY,
EVENT_LEAF_ACTIVE_CHANGED,
EVENT_ON_UNRESOLVED_ERROR,
} from "../../common/events.ts";
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
import { addIcon, debounce, normalizePath, Notice, stringifyYaml, type WorkspaceLeaf } from "../../deps.ts";
} from "@/common/events.ts";
import { AbstractObsidianModule } from "@/modules/AbstractObsidianModule.ts";
import { addIcon, debounce, normalizePath, Notice, stringifyYaml, type WorkspaceLeaf } from "@/deps.ts";
import { LOG_LEVEL_NOTICE, setGlobalLogFunction } from "octagonal-wheels/common/logger";
import { LogPaneView, VIEW_TYPE_LOG } from "./Log/LogPaneView.ts";
import { serialized } from "octagonal-wheels/concurrency/lock";
import { $msg } from "@lib/common/i18n.ts";
import { P2PLogCollector } from "@/lib/src/replication/trystero/P2PLogCollector.ts";
import type { LiveSyncCore } from "../../main.ts";
import type { LiveSyncCore } from "@/main.ts";
import { LiveSyncError } from "@lib/common/LSError.ts";
import { isValidPath } from "@/common/utils.ts";
import {
@@ -48,7 +45,7 @@ import { generateReport } from "@/common/reportTool.ts";
// DI the log again.
const recentLogEntries = reactiveSource<LogEntry[]>([]);
const globalLogFunction = (message: any, level?: number, key?: string) => {
const globalLogFunction = (message: unknown, level?: number, key?: string) => {
const messageX =
message instanceof Error
? new LiveSyncError("[Error Logged]: " + message.message, { cause: message })
@@ -501,7 +498,7 @@ ${stringifyYaml(info)}
})
);
}
__addLog(message: any, level: LOG_LEVEL = LOG_LEVEL_INFO, key = ""): void {
__addLog(message: unknown, level: LOG_LEVEL = LOG_LEVEL_INFO, key = ""): void {
if (level == LOG_LEVEL_DEBUG && !showDebugLog) {
return;
}
@@ -1,8 +1,8 @@
import { type TFile } from "@/deps.ts";
import { eventHub } from "../../common/events.ts";
import { EVENT_REQUEST_SHOW_HISTORY } from "../../common/obsidianEvents.ts";
import type { FilePathWithPrefix, LoadedEntry, DocumentID } from "../../lib/src/common/types.ts";
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
import { eventHub } from "@/common/events.ts";
import { EVENT_REQUEST_SHOW_HISTORY } from "@/common/obsidianEvents.ts";
import type { FilePathWithPrefix, LoadedEntry, DocumentID } from "@lib/common/models/db.type";
import { AbstractObsidianModule } from "@/modules/AbstractObsidianModule.ts";
import { DocumentHistoryModal } from "./DocumentHistory/DocumentHistoryModal.ts";
import { fireAndForget } from "octagonal-wheels/promises";
@@ -1,11 +1,11 @@
// import { PouchDB } from "../../lib/src/pouchdb/pouchdb-browser";
import { isObjectDifferent } from "octagonal-wheels/object";
import { EVENT_SETTING_SAVED, eventHub } from "../../common/events";
import { EVENT_SETTING_SAVED, eventHub } from "@/common/events";
import { fireAndForget } from "octagonal-wheels/promises";
import { DEFAULT_SETTINGS, type FilePathWithPrefix, type ObsidianLiveSyncSettings } from "../../lib/src/common/types";
import { parseYaml, stringifyYaml } from "../../deps";
import { DEFAULT_SETTINGS, type FilePathWithPrefix, type ObsidianLiveSyncSettings } from "@lib/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 { AbstractModule } from "@/modules/AbstractModule.ts";
import type { ServiceContext } from "@lib/services/base/ServiceBase.ts";
import type { InjectableServiceHub } from "@lib/services/InjectableServices.ts";
import type { LiveSyncCore } from "@/main.ts";
@@ -1,7 +1,7 @@
import { ObsidianLiveSyncSettingTab } from "./SettingDialogue/ObsidianLiveSyncSettingTab.ts";
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
import { AbstractObsidianModule } from "@/modules/AbstractObsidianModule.ts";
// import { PouchDB } from "../../lib/src/pouchdb/pouchdb-browser";
import { EVENT_REQUEST_OPEN_SETTING_WIZARD, EVENT_REQUEST_OPEN_SETTINGS, eventHub } from "../../common/events.ts";
import { EVENT_REQUEST_OPEN_SETTING_WIZARD, EVENT_REQUEST_OPEN_SETTINGS, eventHub } from "@/common/events.ts";
import type { LiveSyncCore } from "@/main.ts";
export class ModuleObsidianSettingDialogue extends AbstractObsidianModule {
@@ -8,8 +8,9 @@ import {
type ValueComponent,
} from "@/deps.ts";
import { unique } from "octagonal-wheels/collection";
import { LEVEL_ADVANCED, LEVEL_POWER_USER, statusDisplay, type ConfigurationItem } from "@lib/common/types.ts";
import { createStub, type ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts";
import type { ConfigurationItem } from "@lib/common/models/shared.definition.configNames";
import { LEVEL_ADVANCED, LEVEL_POWER_USER, statusDisplay } from "@lib/common/models/shared.definition.configNames";
import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts";
import {
type AllSettingItemKey,
getConfig,
@@ -19,7 +20,7 @@ import {
type AllBooleanItemKey,
} from "./settingConstants.ts";
import { $msg } from "@lib/common/i18n.ts";
import { findAttrFromParent, wrapMemo, type AutoWireOption, type OnUpdateResult } from "./SettingPane.ts";
import { wrapMemo, type AutoWireOption, type OnUpdateResult } from "./SettingPane.ts";
export class LiveSyncSetting extends Setting {
autoWiredComponent?: TextComponent | ToggleComponent | DropdownComponent | ButtonComponent | TextAreaComponent;
@@ -35,37 +36,19 @@ export class LiveSyncSetting extends Setting {
hasPassword: boolean = false;
invalidateValue?: () => void;
setValue?: (value: any) => void;
setValue?: (value: unknown) => void;
constructor(containerEl: HTMLElement) {
super(containerEl);
LiveSyncSetting.env.settingComponents.push(this);
}
_createDocStub(key: string, value: string | DocumentFragment) {
DEV: {
const paneName = findAttrFromParent(this.settingEl, "data-pane");
const panelName = findAttrFromParent(this.settingEl, "data-panel");
const itemName =
typeof this.nameBuf == "string" ? this.nameBuf : (this.nameBuf.textContent?.toString() ?? "");
const strValue = typeof value == "string" ? value : (value.textContent?.toString() ?? "");
createStub(itemName, key, strValue, panelName, paneName);
}
}
override setDesc(desc: string | DocumentFragment): this {
this.descBuf = desc;
DEV: {
this._createDocStub("desc", desc);
}
super.setDesc(desc);
return this;
}
override setName(name: string | DocumentFragment): this {
this.nameBuf = name;
DEV: {
this._createDocStub("name", name);
}
super.setName(name);
return this;
}
@@ -84,11 +67,6 @@ export class LiveSyncSetting extends Setting {
if (conf.desc) {
this.setDesc(conf.desc);
}
DEV: {
this._createDocStub("key", key);
if (conf.obsolete) this._createDocStub("is_obsolete", "true");
if (conf.level) this._createDocStub("level", conf.level);
}
this.holdValue = opt?.holdValue || this.holdValue;
this.selfKey = key;
@@ -102,6 +80,7 @@ export class LiveSyncSetting extends Setting {
}
return conf;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
autoWireComponent(component: ValueComponent<any>, conf?: ConfigurationItem, opt?: AutoWireOption) {
this.placeHolderBuf = conf?.placeHolder || opt?.placeHolder || "";
if (conf?.level == LEVEL_ADVANCED) {
@@ -1,6 +1,6 @@
<script lang="ts">
import type { CustomRegExpSource } from "../../../lib/src/common/types";
import { isInvertedRegExp, isValidRegExp } from "../../../lib/src/common/utils";
import type { CustomRegExpSource } from "@lib/common/types";
import { isInvertedRegExp, isValidRegExp } from "@lib/common/utils";
export let patterns = [] as CustomRegExpSource[];
export let originals = [] as CustomRegExpSource[];
@@ -1,26 +1,18 @@
import { App, PluginSettingTab } from "../../../deps.ts";
import {
type ObsidianLiveSyncSettings,
type RemoteDBSettings,
LOG_LEVEL_NOTICE,
FLAGMD_REDFLAG2_HR,
FLAGMD_REDFLAG3_HR,
REMOTE_COUCHDB,
REMOTE_MINIO,
type ConfigLevel,
LEVEL_POWER_USER,
LEVEL_ADVANCED,
LEVEL_EDGE_CASE,
REMOTE_P2P,
} from "../../../lib/src/common/types.ts";
import { delay, isObjectDifferent, sizeToHumanReadable } from "../../../lib/src/common/utils.ts";
import { versionNumberString2Number } from "../../../lib/src/string_and_binary/convert.ts";
import { Logger } from "../../../lib/src/common/logger.ts";
import { App, PluginSettingTab } from "@/deps.ts";
import type { ObsidianLiveSyncSettings, RemoteDBSettings } from "@lib/common/models/setting.type";
import { FLAGMD_REDFLAG2_HR, FLAGMD_REDFLAG3_HR } from "@lib/common/models/redflag.const";
import { REMOTE_COUCHDB, REMOTE_MINIO, REMOTE_P2P } from "@lib/common/models/setting.const";
import type { ConfigLevel } from "@lib/common/models/shared.definition.configNames";
import { LEVEL_POWER_USER, LEVEL_ADVANCED, LEVEL_EDGE_CASE } from "@lib/common/models/shared.definition.configNames";
import { LOG_LEVEL_NOTICE } from "@lib/common/logger";
import { delay, isObjectDifferent, sizeToHumanReadable } from "@lib/common/utils.ts";
import { versionNumberString2Number } from "@lib/string_and_binary/convert.ts";
import { Logger } from "@lib/common/logger.ts";
import { checkSyncInfo } from "@lib/pouchdb/negotiation.ts";
import { testCrypt } from "octagonal-wheels/encryption/encryption";
import ObsidianLiveSyncPlugin from "../../../main.ts";
import { scheduleTask } from "../../../common/utils.ts";
import { LiveSyncCouchDBReplicator } from "../../../lib/src/replication/couchdb/LiveSyncReplicator.ts";
import type ObsidianLiveSyncPlugin from "@/main.ts";
import { scheduleTask } from "@/common/utils.ts";
import { LiveSyncCouchDBReplicator } from "@lib/replication/couchdb/LiveSyncReplicator.ts";
import {
type AllSettingItemKey,
type AllStringItemKey,
@@ -31,17 +23,15 @@ import {
type OnDialogSettings,
getConfName,
} from "./settingConstants.ts";
import { $msg } from "../../../lib/src/common/i18n.ts";
import { $msg } from "@lib/common/i18n.ts";
import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts";
import { fireAndForget, yieldNextAnimationFrame } from "octagonal-wheels/promises";
import { confirmWithMessage } from "../../coreObsidian/UILib/dialogs.ts";
import { EVENT_REQUEST_RELOAD_SETTING_TAB, eventHub } from "../../../common/events.ts";
import { JournalSyncMinio } from "../../../lib/src/replication/journal/objectstore/JournalSyncMinio.ts";
import { confirmWithMessage } from "@/modules/coreObsidian/UILib/dialogs.ts";
import { EVENT_REQUEST_RELOAD_SETTING_TAB, eventHub } from "@/common/events.ts";
import { JournalSyncMinio } from "@lib/replication/journal/objectstore/JournalSyncMinio.ts";
import { paneChangeLog } from "./PaneChangeLog.ts";
import {
enableOnly,
findAttrFromParent,
getLevelStr,
setLevelClass,
setStyle,
visibleOnly,
@@ -64,27 +54,6 @@ import { panePatches } from "./PanePatches.ts";
import { paneMaintenance } from "./PaneMaintenance.ts";
import { compatGlobal } from "@lib/common/coreEnvFunctions.ts";
// For creating a document
const toc = new Set<string>();
const stubs = {} as {
[key: string]: { [key: string]: Map<string, Record<string, string>> };
};
export function createStub(name: string, key: string, value: string, panel: string, pane: string) {
DEV: {
if (!(pane in stubs)) {
stubs[pane] = {};
}
if (!(panel in stubs[pane])) {
stubs[pane][panel] = new Map<string, Record<string, string>>();
}
const old = stubs[pane][panel].get(name) ?? {};
stubs[pane][panel].set(name, { ...old, [key]: value });
scheduleTask("update-stub", 100, () => {
eventHub.emitEvent("document-stub-created", { toc: toc, stub: stubs });
});
}
}
export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
plugin: ObsidianLiveSyncPlugin;
get core() {
@@ -287,6 +256,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
// UI Element Wrapper -->
settingComponents = [] as Setting[];
controlledElementFunc = [] as UpdateFunction[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onSavedHandlers = [] as OnSavedHandler<any>[];
inWizard: boolean = false;
@@ -718,7 +688,6 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
visibleOnly(() => this.isNeedRebuildLocal() || this.isNeedRebuildRemote())
);
let paneNo = 0;
const addPane = (
parentEl: HTMLElement,
title: string,
@@ -728,16 +697,6 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
level?: ConfigLevel
) => {
const el = this.createEl(parentEl, "div", { text: "" });
DEV: {
const mdTitle = `${paneNo++}. ${title}${getLevelStr(level ?? "")}`;
el.setAttribute("data-pane", mdTitle);
toc.add(
`| ${icon} | [${mdTitle}](#${mdTitle
.toLowerCase()
.replace(/ /g, "-")
.replace(/[^\w\s-]/g, "")}) | `
);
}
setLevelClass(el, level);
// TODO: Refactor to use Obsidian's recommended way to create heading.
// eslint-disable-next-line obsidianmd/settings-tab/no-manual-html-headings
@@ -772,7 +731,6 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
// });
return p;
};
const panelNoMap = {} as { [key: string]: number };
const addPanel = (
parentEl: HTMLElement,
title: string,
@@ -781,15 +739,6 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
level?: ConfigLevel
) => {
const el = this.createEl(parentEl, "div", { text: "" }, callback, func);
DEV: {
const paneNo = findAttrFromParent(parentEl, "data-pane");
if (!(paneNo in panelNoMap)) {
panelNoMap[paneNo] = 0;
}
panelNoMap[paneNo] += 1;
const panelNo = panelNoMap[paneNo];
el.setAttribute("data-panel", `${panelNo}. ${title}${getLevelStr(level ?? "")}`);
}
setLevelClass(el, level);
this.createEl(el, "h4", { text: title, cls: "sls-setting-panel-title" });
const p = Promise.resolve(el);
@@ -1,4 +1,4 @@
import { ChunkAlgorithmNames } from "../../../lib/src/common/types.ts";
import { ChunkAlgorithmNames } from "@lib/common/models/setting.const";
import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts";
import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts";
import type { PageFunctions } from "./SettingPane.ts";
@@ -1,6 +1,6 @@
import { MarkdownRenderer } from "../../../deps.ts";
import { versionNumberString2Number } from "../../../lib/src/string_and_binary/convert.ts";
import { $msg } from "../../../lib/src/common/i18n.ts";
import { MarkdownRenderer } from "@/deps.ts";
import { versionNumberString2Number } from "@lib/string_and_binary/convert.ts";
import { $msg } from "@lib/common/i18n.ts";
import { fireAndForget } from "octagonal-wheels/promises";
import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts";
import { visibleOnly } from "./SettingPane.ts";
@@ -1,5 +1,5 @@
import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts";
import { EVENT_REQUEST_OPEN_PLUGIN_SYNC_DIALOG, eventHub } from "../../../common/events.ts";
import { EVENT_REQUEST_OPEN_PLUGIN_SYNC_DIALOG, eventHub } from "@/common/events.ts";
import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts";
import type { PageFunctions } from "./SettingPane.ts";
import { enableOnly, visibleOnly } from "./SettingPane.ts";
@@ -1,5 +1,5 @@
import { $msg, $t } from "../../../lib/src/common/i18n.ts";
import { SUPPORTED_I18N_LANGS, type I18N_LANGS } from "../../../lib/src/common/rosetta.ts";
import { $msg, $t } from "@lib/common/i18n.ts";
import { SUPPORTED_I18N_LANGS, type I18N_LANGS } from "@lib/common/rosetta.ts";
import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts";
import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts";
import type { PageFunctions } from "./SettingPane.ts";
@@ -1,13 +1,7 @@
import {
type FilePathWithPrefix,
type DocumentID,
LOG_LEVEL_NOTICE,
LOG_LEVEL_VERBOSE,
type LoadedEntry,
type MetaEntry,
type FilePath,
} from "@lib/common/types.ts";
import { createBlob, getFileRegExp, isDocContentSame, readAsBlob } from "@lib/common/utils.ts";
import type { FilePathWithPrefix, DocumentID, LoadedEntry, MetaEntry, FilePath } from "@lib/common/models/db.type";
import { LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "@lib/common/logger";
import { createBlob, isDocContentSame, readAsBlob } from "@lib/common/utils.database.ts";
import { getFileRegExp } from "@lib/common/utils.regexp.ts";
import { Logger } from "@lib/common/logger.ts";
import { addPrefix, shouldBeIgnored, stripAllPrefixes } from "@lib/string_and_binary/path.ts";
import { $msg } from "@lib/common/i18n.ts";
@@ -20,7 +14,7 @@ import {
EVENT_REQUEST_RUN_FIX_INCOMPLETE,
eventHub,
} from "@/common/events.ts";
import { ICHeader, ICXHeader, PSCHeader } from "@/common/types.ts";
import { ICHeader, ICXHeader, PSCHeader } from "@lib/common/models/fileaccess.const";
import { HiddenFileSync } from "@/features/HiddenFileSync/CmdHiddenFileSync.ts";
import { EVENT_REQUEST_SHOW_HISTORY } from "@/common/obsidianEvents.ts";
import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts";
@@ -442,7 +436,9 @@ export function paneHatch(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElement,
...e.doc,
_deleted: true,
}));
const r = await this.core.localDatabase.bulkDocsRaw(newData as any[]);
const r = await this.core.localDatabase.bulkDocsRaw(
newData as Parameters<typeof this.core.localDatabase.bulkDocsRaw>[0]
);
// Do not care about the result.
Logger(
`${r.length} items have been removed, to confirm how many items are left, please perform it again.`,
@@ -1,8 +1,8 @@
import { EVENT_REQUEST_PERFORM_GC_V3, eventHub } from "@/common/events.ts";
import { LOG_LEVEL_NOTICE, Logger } from "../../../lib/src/common/logger.ts";
import { FlagFilesHumanReadable, FLAGMD_REDFLAG } from "../../../lib/src/common/types.ts";
import { fireAndForget } from "../../../lib/src/common/utils.ts";
import { LiveSyncCouchDBReplicator } from "../../../lib/src/replication/couchdb/LiveSyncReplicator.ts";
import { LOG_LEVEL_NOTICE, Logger } from "@lib/common/logger.ts";
import { FlagFilesHumanReadable, FLAGMD_REDFLAG } from "@lib/common/models/redflag.const";
import { fireAndForget } from "@lib/common/utils.ts";
import { LiveSyncCouchDBReplicator } from "@lib/replication/couchdb/LiveSyncReplicator.ts";
import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts";
import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab";
import { visibleOnly, type PageFunctions } from "./SettingPane";
@@ -1,17 +1,14 @@
import {
E2EEAlgorithmNames,
E2EEAlgorithms,
type HashAlgorithm,
LOG_LEVEL_NOTICE,
SuffixDatabaseName,
} from "../../../lib/src/common/types.ts";
import { Logger } from "../../../lib/src/common/logger.ts";
import { E2EEAlgorithmNames, E2EEAlgorithms } from "@lib/common/models/setting.const";
import type { HashAlgorithm } from "@lib/common/models/setting.type";
import { SuffixDatabaseName } from "@lib/common/models/shared.const";
import { LOG_LEVEL_NOTICE } from "@lib/common/logger";
import { Logger } from "@lib/common/logger.ts";
import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts";
import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts";
import type { PageFunctions } from "./SettingPane.ts";
import { visibleOnly } from "./SettingPane.ts";
import { PouchDB } from "../../../lib/src/pouchdb/pouchdb-browser";
import { ExtraSuffixIndexedDB } from "../../../lib/src/common/types.ts";
import { PouchDB } from "@lib/pouchdb/pouchdb-browser";
import { ExtraSuffixIndexedDB } from "@lib/common/models/shared.const";
import { migrateDatabases } from "./settingUtils.ts";
export function panePatches(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElement, { addPanel }: PageFunctions): void {
@@ -1,4 +1,4 @@
import { type ConfigPassphraseStore } from "../../../lib/src/common/types.ts";
import type { ConfigPassphraseStore } from "@lib/common/models/setting.type";
import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts";
import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts";
import type { PageFunctions } from "./SettingPane.ts";
@@ -1,14 +1,9 @@
import {
REMOTE_COUCHDB,
REMOTE_MINIO,
REMOTE_P2P,
DEFAULT_SETTINGS,
LOG_LEVEL_NOTICE,
type ObsidianLiveSyncSettings,
LOG_LEVEL_VERBOSE,
} from "../../../lib/src/common/types.ts";
import { Menu } from "@/deps.ts";
import { $msg } from "../../../lib/src/common/i18n.ts";
import { REMOTE_COUCHDB, REMOTE_MINIO, REMOTE_P2P } from "@lib/common/models/setting.const";
import { DEFAULT_SETTINGS } from "@lib/common/models/setting.const.defaults";
import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type";
import { LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "@lib/common/logger";
import { Menu, ButtonComponent } from "@/deps.ts";
import { $msg } from "@lib/common/i18n.ts";
import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts";
import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts";
import type { PageFunctions } from "./SettingPane.ts";
@@ -22,24 +17,24 @@ import {
getCouchDBConfigSummary,
getE2EEConfigSummary,
} from "./settingUtils.ts";
import { SETTING_KEY_P2P_DEVICE_NAME } from "../../../lib/src/common/types.ts";
import { SetupManager, UserMode } from "../SetupManager.ts";
import { SETTING_KEY_P2P_DEVICE_NAME } from "@lib/common/models/shared.const";
import { SetupManager, UserMode } from "@/modules/features/SetupManager.ts";
import { OnDialogSettingsDefault, type AllSettings } from "./settingConstants.ts";
import { activateRemoteConfiguration } from "../../../lib/src/serviceFeatures/remoteConfig.ts";
import { ConnectionStringParser } from "../../../lib/src/common/ConnectionString.ts";
import type { RemoteConfigurationResult } from "../../../lib/src/common/ConnectionString.ts";
import type { RemoteConfiguration } from "../../../lib/src/common/models/setting.type.ts";
import SetupRemote from "../SetupWizard/dialogs/SetupRemote.svelte";
import SetupRemoteCouchDB from "../SetupWizard/dialogs/SetupRemoteCouchDB.svelte";
import SetupRemoteBucket from "../SetupWizard/dialogs/SetupRemoteBucket.svelte";
import SetupRemoteP2P from "../SetupWizard/dialogs/SetupRemoteP2P.svelte";
import { activateRemoteConfiguration } from "@lib/serviceFeatures/remoteConfig.ts";
import { ConnectionStringParser } from "@lib/common/ConnectionString.ts";
import type { RemoteConfigurationResult } from "@lib/common/ConnectionString.ts";
import type { RemoteConfiguration } from "@lib/common/models/setting.type.ts";
import SetupRemote from "@/modules/features/SetupWizard/dialogs/SetupRemote.svelte";
import SetupRemoteCouchDB from "@/modules/features/SetupWizard/dialogs/SetupRemoteCouchDB.svelte";
import SetupRemoteBucket from "@/modules/features/SetupWizard/dialogs/SetupRemoteBucket.svelte";
import SetupRemoteP2P from "@/modules/features/SetupWizard/dialogs/SetupRemoteP2P.svelte";
import { syncActivatedRemoteSettings } from "./remoteConfigBuffer.ts";
function getSettingsFromEditingSettings(editingSettings: AllSettings): ObsidianLiveSyncSettings {
const workObj = { ...editingSettings } as ObsidianLiveSyncSettings;
const keys = Object.keys(OnDialogSettingsDefault);
for (const k of keys) {
delete (workObj as any)[k];
delete (workObj as unknown as Record<string, unknown>)[k];
}
return workObj;
}
@@ -72,7 +67,7 @@ function serializeRemoteConfiguration(settings: ObsidianLiveSyncSettings): strin
return ConnectionStringParser.serialize({ type: "couchdb", settings });
}
function setEmojiButton(button: any, emoji: string, tooltip: string) {
function setEmojiButton(button: ButtonComponent, emoji: string, tooltip: string) {
button.setButtonText(emoji);
button.setTooltip(tooltip, { delay: 10, placement: "top" });
// button.buttonEl.addClass("clickable-icon");
@@ -1,5 +1,6 @@
import { LEVEL_ADVANCED, type CustomRegExpSource } from "../../../lib/src/common/types.ts";
import { constructCustomRegExpList, splitCustomRegExpList } from "../../../lib/src/common/utils.ts";
import { LEVEL_ADVANCED } from "@lib/common/models/shared.definition.configNames";
import type { CustomRegExpSource } from "@lib/common/models/shared.type.util";
import { constructCustomRegExpList, splitCustomRegExpList } from "@lib/common/utils.regexp.ts";
import MultipleRegExpControl from "./MultipleRegExpControl.svelte";
import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts";
import { mount } from "svelte";
@@ -1,5 +1,5 @@
import { MarkdownRenderer } from "../../../deps.ts";
import { $msg } from "../../../lib/src/common/i18n.ts";
import { MarkdownRenderer } from "@/deps.ts";
import { $msg } from "@lib/common/i18n.ts";
import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts";
import { fireAndForget } from "octagonal-wheels/promises";
import {
@@ -7,13 +7,13 @@ import {
EVENT_REQUEST_OPEN_SETUP_URI,
EVENT_REQUEST_SHOW_SETUP_QR,
eventHub,
} from "../../../common/events.ts";
} from "@/common/events.ts";
import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts";
import type { PageFunctions } from "./SettingPane.ts";
import { visibleOnly } from "./SettingPane.ts";
import { DEFAULT_SETTINGS } from "../../../lib/src/common/types.ts";
import { DEFAULT_SETTINGS } from "@lib/common/models/setting.const.defaults";
import { request } from "@/deps.ts";
import { SetupManager, UserMode } from "../SetupManager.ts";
import { SetupManager, UserMode } from "@/modules/features/SetupManager.ts";
export function paneSetup(
this: ObsidianLiveSyncSettingTab,
paneEl: HTMLElement,
@@ -145,8 +145,8 @@ export function paneSetup(
let remoteTroubleShootMDSrc = "";
try {
remoteTroubleShootMDSrc = await request(`${rawRepoURI}${basePath}/${filename}`);
} catch (ex: any) {
remoteTroubleShootMDSrc = `${$msg("obsidianLiveSyncSettingTab.logErrorOccurred")}\n${ex.toString()}`;
} catch (ex) {
remoteTroubleShootMDSrc = `${$msg("obsidianLiveSyncSettingTab.logErrorOccurred")}\n${String(ex)}`;
}
const remoteTroubleShootMD = remoteTroubleShootMDSrc.replace(
/\((.*?(.png)|(.jpg))\)/g,
@@ -1,13 +1,11 @@
import {
type ObsidianLiveSyncSettings,
LOG_LEVEL_NOTICE,
REMOTE_COUCHDB,
LEVEL_ADVANCED,
} from "../../../lib/src/common/types.ts";
import { Logger } from "../../../lib/src/common/logger.ts";
import { $msg } from "../../../lib/src/common/i18n.ts";
import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type";
import { REMOTE_COUCHDB } from "@lib/common/models/setting.const";
import { LEVEL_ADVANCED } from "@lib/common/models/shared.definition.configNames";
import { LOG_LEVEL_NOTICE } from "@lib/common/logger";
import { Logger } from "@lib/common/logger.ts";
import { $msg } from "@lib/common/i18n.ts";
import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts";
import { EVENT_REQUEST_COPY_SETUP_URI, eventHub } from "../../../common/events.ts";
import { EVENT_REQUEST_COPY_SETUP_URI, eventHub } from "@/common/events.ts";
import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts";
import type { PageFunctions } from "./SettingPane.ts";
import { visibleOnly } from "./SettingPane.ts";
@@ -1,5 +1,5 @@
import { $msg } from "../../../lib/src/common/i18n";
import { LEVEL_ADVANCED, LEVEL_EDGE_CASE, LEVEL_POWER_USER, type ConfigLevel } from "../../../lib/src/common/types";
import { $msg } from "@lib/common/i18n";
import { LEVEL_ADVANCED, LEVEL_EDGE_CASE, LEVEL_POWER_USER, type ConfigLevel } from "@lib/common/types";
import type { AllSettingItemKey, AllSettings } from "./settingConstants";
export const combineOnUpdate = (func1: OnUpdateFunc, func2: OnUpdateFunc): OnUpdateFunc => {
@@ -5,7 +5,7 @@ import { type Writable, writable, get } from "svelte/store";
* Props passed to Svelte panels, containing a writable port
* to communicate with the panel
*/
export type SveltePanelProps<T = any> = {
export type SveltePanelProps<T = unknown> = {
port: Writable<T | undefined>;
};
@@ -13,7 +13,7 @@ export type SveltePanelProps<T = any> = {
* A class to manage a Svelte panel within Obsidian
* Especially useful for settings panels
*/
export class SveltePanel<T = any> {
export class SveltePanel<T = unknown> {
private _mountedComponent: ReturnType<typeof mount>;
private _componentValue = writable<T | undefined>(undefined);
/**
@@ -1,6 +1,5 @@
import { pickBucketSyncSettings, pickCouchDBSyncSettings, pickP2PSyncSettings } from "@lib/common/utils.ts";
import type { ObsidianLiveSyncSettings } from "@lib/common/types.ts";
import { pickBucketSyncSettings, pickCouchDBSyncSettings, pickP2PSyncSettings } from "@lib/common/utils.settings.ts";
import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type";
// Keep the setting dialogue buffer aligned with the current core settings before persisting other dirty keys.
// This also clears stale dirty values left from editing a different remote type before switching active remotes.
export function syncActivatedRemoteSettings(
@@ -1,18 +1,15 @@
import { escapeStringToHTML } from "octagonal-wheels/string";
import {
E2EEAlgorithmNames,
MILESTONE_DOCID,
NODEINFO_DOCID,
type ObsidianLiveSyncSettings,
} from "../../../lib/src/common/types";
import { E2EEAlgorithmNames, MILESTONE_DOCID, NODEINFO_DOCID, type ObsidianLiveSyncSettings } from "@lib/common/types";
import {
pickCouchDBSyncSettings,
pickBucketSyncSettings,
pickP2PSyncSettings,
pickEncryptionSettings,
} from "../../../lib/src/common/utils";
} from "@lib/common/utils.settings";
import { getConfig, type AllSettingItemKey } from "./settingConstants";
import { LOG_LEVEL_NOTICE, Logger } from "octagonal-wheels/common/logger";
import { isNotFoundError } from "@lib/common/utils.doc.ts";
import { LiveSyncError } from "@lib/common/LSError.ts";
/**
* Generates a summary of P2P configuration settings
@@ -95,13 +92,13 @@ export function getSummaryFromPartialSettings(setting: Partial<ObsidianLiveSyncS
export async function copyMigrationDocs(docName: string, dbFrom: PouchDB.Database, dbTo: PouchDB.Database) {
try {
const doc = await dbFrom.get(docName);
delete (doc as any)._rev;
delete (doc as { _rev?: string })._rev;
await dbTo.put(doc);
} catch (e) {
if ((e as any).status === 404) {
} catch (e: unknown) {
if (e && typeof e === "object" && isNotFoundError(e)) {
return;
}
throw e;
throw LiveSyncError.fromError(e);
}
}
@@ -1,10 +1,11 @@
import { requestToCouchDBWithCredentials } from "../../../common/utils";
import { $msg } from "../../../lib/src/common/i18n";
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE, Logger } from "../../../lib/src/common/logger";
import type { ObsidianLiveSyncSettings } from "../../../lib/src/common/types";
import { fireAndForget, parseHeaderValues } from "../../../lib/src/common/utils";
import { isCloudantURI } from "../../../lib/src/pouchdb/utils_couchdb";
import { generateCredentialObject } from "../../../lib/src/replication/httplib";
import { requestToCouchDBWithCredentials } from "@/common/utils";
import { $msg } from "@lib/common/i18n";
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE, Logger } from "@lib/common/logger";
import type { ObsidianLiveSyncSettings } from "@lib/common/types";
import { parseHeaderValues } from "@lib/common/utils.misc";
import { fireAndForget } from "@lib/common/utils";
import { isCloudantURI } from "@lib/pouchdb/utils_couchdb";
import { generateCredentialObject } from "@lib/replication/httplib";
export const checkConfig = async (
checkResultDiv: HTMLDivElement | undefined,
@@ -259,8 +260,8 @@ export const checkConfig = async (
addResult($msg("obsidianLiveSyncSettingTab.msgDone"), ["ob-btn-config-head"]);
addResult($msg("obsidianLiveSyncSettingTab.msgConnectionProxyNote"), ["ob-btn-config-info"]);
Logger($msg("obsidianLiveSyncSettingTab.logCheckingConfigDone"), LOG_LEVEL_INFO);
} catch (ex: any) {
if (ex?.status == 401) {
} catch (ex) {
if (ex && typeof ex === "object" && "status" in ex && ex.status == 401) {
isSuccessful = false;
addResult($msg("obsidianLiveSyncSettingTab.errAccessForbidden"));
addResult($msg("obsidianLiveSyncSettingTab.errCannotContinueTest"));
+11 -14
View File
@@ -1,16 +1,13 @@
import {
type BucketSyncSetting,
type CouchDBConnection,
type EncryptionSettings,
type ObsidianLiveSyncSettings,
type P2PSyncSetting,
DEFAULT_SETTINGS,
LOG_LEVEL_NOTICE,
LOG_LEVEL_VERBOSE,
REMOTE_COUCHDB,
REMOTE_MINIO,
REMOTE_P2P,
} from "@lib/common/types.ts";
import type {
BucketSyncSetting,
CouchDBConnection,
EncryptionSettings,
ObsidianLiveSyncSettings,
P2PSyncSetting,
} from "@lib/common/models/setting.type";
import { DEFAULT_SETTINGS } from "@lib/common/models/setting.const.defaults";
import { REMOTE_COUCHDB, REMOTE_MINIO, REMOTE_P2P } from "@lib/common/models/setting.const";
import { LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "@lib/common/logger";
import { isObjectDifferent } from "@lib/common/utils.ts";
import Intro from "./SetupWizard/dialogs/Intro.svelte";
import SelectMethodNewUser from "./SetupWizard/dialogs/SelectMethodNewUser.svelte";
@@ -26,7 +23,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/API/processSetting.ts";
import { AbstractModule } from "../AbstractModule.ts";
import { AbstractModule } from "@/modules/AbstractModule.ts";
import { ConnectionStringParser } from "@lib/common/ConnectionString.ts";
import type {
OutroAskUserModeResultType,
@@ -1,14 +1,20 @@
import { requestToCouchDBWithCredentials } from "../../../../common/utils";
import { $msg } from "../../../../lib/src/common/i18n";
import { Logger } from "../../../../lib/src/common/logger";
import type { ObsidianLiveSyncSettings } from "../../../../lib/src/common/types";
import { parseHeaderValues } from "../../../../lib/src/common/utils";
import { isCloudantURI } from "../../../../lib/src/pouchdb/utils_couchdb";
import { generateCredentialObject } from "../../../../lib/src/replication/httplib";
import { requestToCouchDBWithCredentials } from "@/common/utils";
import { $msg } from "@lib/common/i18n";
import { Logger } from "@lib/common/logger";
import type { ObsidianLiveSyncSettings } from "@lib/common/types";
import { parseHeaderValues } from "@lib/common/utils.misc";
import { isCloudantURI } from "@lib/pouchdb/utils_couchdb";
import { generateCredentialObject } from "@lib/replication/httplib";
export type ResultMessage = { message: string; classes: string[] };
export type ResultErrorMessage = { message: string; result: "error"; classes: string[] };
export type ResultOk = { message: string; result: "ok"; value?: any };
export type ResultError = { message: string; result: "error"; value: any; fixMessage: string; fix(): Promise<void> };
export type ResultOk = { message: string; result: "ok"; value?: unknown };
export type ResultError = {
message: string;
result: "error";
value?: string;
fixMessage: string;
fix(): Promise<void>;
};
export type ConfigCheckResult = ResultOk | ResultError | ResultMessage | ResultErrorMessage;
/**
* Compares two version strings to determine if the baseVersion is greater than or equal to the version.
@@ -35,7 +41,7 @@ function isGreaterThanOrEqual(baseVersion: string, version: string) {
* @param value setting value to update
* @returns true if the update was successful, false otherwise
*/
async function updateRemoteSetting(setting: ObsidianLiveSyncSettings, key: string, value: any) {
async function updateRemoteSetting(setting: ObsidianLiveSyncSettings, key: string, value: string) {
const customHeaders = parseHeaderValues(setting.couchDB_CustomHeaders);
const credential = generateCredentialObject(setting);
const res = await requestToCouchDBWithCredentials(
@@ -64,17 +70,17 @@ export const checkConfig = async (editingSettings: ObsidianLiveSyncSettings) =>
const addMessage = (msg: string, classes: string[] = []) => {
result.push({ message: msg, classes });
};
const addSuccess = (msg: string, value?: any) => {
const addSuccess = (msg: string, value?: unknown) => {
result.push({ message: msg, result: "ok", value });
};
const _addError = (message: string, fixMessage: string, fix: () => Promise<void>, value?: any) => {
const _addError = (message: string, fixMessage: string, fix: () => Promise<void>, value?: string) => {
result.push({ message, result: "error", fixMessage, fix, value });
};
const addErrorMessage = (msg: string, classes: string[] = []) => {
result.push({ message: msg, result: "error", classes });
};
const addError = (message: string, fixMessage: string, key: string, expected: any) => {
const addError = (message: string, fixMessage: string, key: string, expected: string) => {
_addError(message, fixMessage, async () => {
await updateRemoteSetting(editingSettings, key, expected);
});
@@ -279,8 +285,8 @@ export const checkConfig = async (editingSettings: ObsidianLiveSyncSettings) =>
addMessage($msg("obsidianLiveSyncSettingTab.msgDone"), ["ob-btn-config-head"]);
addMessage($msg("obsidianLiveSyncSettingTab.msgConnectionProxyNote"), ["ob-btn-config-info"]);
addMessage($msg("obsidianLiveSyncSettingTab.logCheckingConfigDone"));
} catch (ex: any) {
if (ex?.status == 401) {
} catch (ex) {
if (ex && typeof ex === "object" && "status" in ex && ex.status == 401) {
addErrorMessage($msg("obsidianLiveSyncSettingTab.errAccessForbidden"));
addErrorMessage($msg("obsidianLiveSyncSettingTab.errCannotContinueTest"));
addMessage($msg("obsidianLiveSyncSettingTab.logCheckingConfigDone"));
+8 -6
View File
@@ -1,17 +1,19 @@
import { fireAndForget } from "octagonal-wheels/promises";
import { LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE, VER, type ObsidianLiveSyncSettings } from "../../lib/src/common/types.ts";
import { VER } from "@lib/common/models/shared.const.behabiour";
import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type";
import { LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "@lib/common/logger";
import {
EVENT_LAYOUT_READY,
EVENT_PLUGIN_LOADED,
EVENT_REQUEST_RELOAD_SETTING_TAB,
EVENT_SETTING_SAVED,
eventHub,
} from "../../common/events.ts";
import { $msg, setLang } from "../../lib/src/common/i18n.ts";
import { versionNumberString2Number } from "../../lib/src/string_and_binary/convert.ts";
import { AbstractModule } from "../AbstractModule.ts";
} from "@/common/events.ts";
import { $msg, setLang } from "@lib/common/i18n.ts";
import { versionNumberString2Number } from "@lib/string_and_binary/convert.ts";
import { AbstractModule } from "@/modules/AbstractModule.ts";
import type { InjectableServiceHub } from "@lib/services/implements/injectable/InjectableServiceHub.ts";
import type { LiveSyncCore } from "../../main.ts";
import type { LiveSyncCore } from "@/main.ts";
import { initialiseWorkerModule } from "@lib/worker/bgWorker.ts";
import { manifestVersion, packageVersion } from "@lib/common/coreEnvVars.ts";
import { compatGlobal } from "@lib/common/coreEnvFunctions.ts";
+3 -3
View File
@@ -1,7 +1,7 @@
import { InjectableAPIService } from "@lib/services/implements/injectable/InjectableAPIService";
import type { ObsidianServiceContext } from "@lib/services/implements/obsidian/ObsidianServiceContext";
import { Platform, type Command, type ViewCreator } from "obsidian";
import { ObsHttpHandler } from "../essentialObsidian/APILib/ObsHttpHandler";
import { ObsHttpHandler } from "@/modules/essentialObsidian/APILib/ObsHttpHandler";
import { ObsidianConfirm } from "./ObsidianConfirm";
import type { Confirm } from "@lib/interfaces/Confirm";
import { requestUrl, type RequestUrlParam } from "@/deps";
@@ -125,11 +125,11 @@ export class ObsidianAPIService extends InjectableAPIService<ObsidianServiceCont
registerWindow(type: string, factory: ViewCreator): void {
return this.context.plugin.registerView(type, factory);
}
addRibbonIcon(icon: string, title: string, callback: (evt: MouseEvent) => any): HTMLElement {
addRibbonIcon(icon: string, title: string, callback: (evt: MouseEvent) => void): HTMLElement {
return this.context.plugin.addRibbonIcon(icon, title, callback);
}
registerProtocolHandler(action: string, handler: (params: Record<string, string>) => any): void {
registerProtocolHandler(action: string, handler: (params: Record<string, string>) => void): void {
return this.context.plugin.registerObsidianProtocolHandler(action, handler);
}
+1 -1
View File
@@ -9,7 +9,7 @@ import {
confirmWithMessageWithWideButton,
askSelectString,
confirmWithMessage,
} from "../coreObsidian/UILib/dialogs";
} from "@/modules/coreObsidian/UILib/dialogs";
export class ObsidianConfirm<T extends ObsidianServiceContext = ObsidianServiceContext> implements Confirm {
private _context: T;
+1 -1
View File
@@ -10,7 +10,7 @@ import {
synchroniseAllFilesBetweenDBandStorage,
type FullScanOptions,
} from "@lib/serviceFeatures/offlineScanner";
import { adjustSettingToRemoteIfNeeded, processVaultInitialisation } from "./redFlag";
import { adjustSettingToRemoteIfNeeded, processVaultInitialisation } from "./redFlag.utils";
export const SIMPLE_FETCH_STAGE1_REMOTE_WINS = "Overwrite all with remote files";
export const SIMPLE_FETCH_STAGE1_NEWER_WINS = "Compare time and take newer";
+12 -176
View File
@@ -1,13 +1,10 @@
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE } from "octagonal-wheels/common/logger";
import type { NecessaryServices } from "@lib/interfaces/ServiceModule";
import { createInstanceLogFunction, type LogFunction } from "@lib/services/lib/logUtils";
import { FlagFilesHumanReadable, FlagFilesOriginal } from "@lib/common/models/redflag.const";
import FetchEverything from "../modules/features/SetupWizard/dialogs/FetchEverything.svelte";
import RebuildEverything from "../modules/features/SetupWizard/dialogs/RebuildEverything.svelte";
import { extractObject } from "octagonal-wheels/object";
import { REMOTE_MINIO, REMOTE_P2P } from "@lib/common/models/setting.const";
import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type";
import { TweakValuesShouldMatchedTemplate } from "@lib/common/models/tweak.definition";
import FetchEverything from "@/modules/features/SetupWizard/dialogs/FetchEverything.svelte";
import RebuildEverything from "@/modules/features/SetupWizard/dialogs/RebuildEverything.svelte";
import { REMOTE_MINIO } from "@lib/common/models/setting.const";
import type {
FetchEverythingResult,
RebuildEverythingResult,
@@ -15,6 +12,13 @@ import type {
import { askAndPerformFastSetupOnScheduledFetchAll } from "./redFlag.simpleFetch";
import { ConnectionStringParser } from "@lib/common/ConnectionString";
import { activateRemoteConfiguration } from "@lib/serviceFeatures/remoteConfig";
import {
isFlagFileExist,
deleteFlagFile,
adjustSettingToRemoteIfNeeded,
processVaultInitialisation,
verifyAndUnlockSuspension,
} from "./redFlag.utils";
/**
* Flag file handler interface, similar to target filter pattern.
@@ -25,32 +29,9 @@ interface FlagFileHandler {
handle: () => Promise<boolean>;
}
export async function isFlagFileExist(host: NecessaryServices<never, "storageAccess">, path: string) {
const redFlagExist = await host.serviceModules.storageAccess.isExists(
host.serviceModules.storageAccess.normalisePath(path)
);
if (redFlagExist) {
return true;
}
return false;
}
export async function deleteFlagFile(host: NecessaryServices<never, "storageAccess">, log: LogFunction, path: string) {
try {
const isFlagged = await host.serviceModules.storageAccess.isExists(
host.serviceModules.storageAccess.normalisePath(path)
);
if (isFlagged) {
await host.serviceModules.storageAccess.delete(path, true);
}
} catch (ex) {
log(`Could not delete ${path}`);
log(ex, LOG_LEVEL_VERBOSE);
}
}
const REMOTE_KEEP_CURRENT = "Use active remote";
const REMOTE_CANCEL = "Cancel";
async function askAndActivateRemoteDatabase(host: NecessaryServices<"UI" | "setting", any>, log: LogFunction) {
async function askAndActivateRemoteDatabase(host: NecessaryServices<"UI" | "setting", never>, log: LogFunction) {
const settings = host.services.setting.currentSettings();
if (settings.remoteConfigurations && Object.keys(settings.remoteConfigurations).length > 1) {
const message =
@@ -215,151 +196,6 @@ export function createFetchAllFlagHandler(
* @param config current configuration to retrieve remote preferred config
* @returns updated configuration if applied, otherwise null.
*/
export async function adjustSettingToRemote(
host: NecessaryServices<"tweakValue" | "UI" | "setting", any>,
log: LogFunction,
config: ObsidianLiveSyncSettings
) {
// Fetch remote configuration unless prevented.
const SKIP_FETCH = "Skip and proceed";
const RETRY_FETCH = "Retry (recommended)";
let canProceed = false;
do {
const remoteTweaks = await host.services.tweakValue.fetchRemotePreferred(config);
if (!remoteTweaks) {
const choice = await host.services.UI.confirm.askSelectStringDialogue(
"Could not fetch configuration from remote. If you are new to the Self-hosted LiveSync, this might be expected. If not, you should check your network or server settings.",
[SKIP_FETCH, RETRY_FETCH] as const,
{
defaultAction: RETRY_FETCH,
timeout: 0,
title: "Fetch Remote Configuration Failed",
}
);
if (choice === SKIP_FETCH) {
canProceed = true;
}
} else {
const necessary = extractObject(TweakValuesShouldMatchedTemplate, remoteTweaks);
// Check if any necessary tweak value is different from current config.
const differentItems = Object.entries(necessary).filter(([key, value]) => {
return (config as any)[key] !== value;
});
if (differentItems.length === 0) {
log("Remote configuration matches local configuration. No changes applied.", LOG_LEVEL_NOTICE);
} else {
await host.services.UI.confirm.askSelectStringDialogue(
"Your settings differed slightly from the server's. The plug-in has supplemented the incompatible parts with the server settings!",
["OK"] as const,
{
defaultAction: "OK",
timeout: 0,
}
);
}
config = {
...config,
...Object.fromEntries(differentItems),
} satisfies ObsidianLiveSyncSettings;
await host.services.setting.applyExternalSettings(config, true);
log("Remote configuration applied.", LOG_LEVEL_NOTICE);
canProceed = true;
const updatedConfig = host.services.setting.currentSettings();
return updatedConfig;
}
} while (!canProceed);
}
/**
* Adjust setting to remote if needed.
* @param extra result of dialogues that may contain preventFetchingConfig flag (e.g, from FetchEverything or RebuildEverything)
* @param config current configuration to retrieve remote preferred config
*/
export async function adjustSettingToRemoteIfNeeded(
host: NecessaryServices<"tweakValue" | "UI" | "setting", any>,
log: LogFunction,
extra: { preventFetchingConfig: boolean },
config: ObsidianLiveSyncSettings
) {
if (extra && extra.preventFetchingConfig) {
return;
}
// P2P has no centralised remote configuration; skip to avoid a spurious
// "Failed to connect to the remote server" error dialog.
if (config.remoteType === REMOTE_P2P) {
log("Remote configuration fetch skipped (P2P mode).", LOG_LEVEL_INFO);
return;
}
// Remote configuration fetched and applied.
if (await adjustSettingToRemote(host, log, config)) {
config = host.services.setting.currentSettings();
} else {
log("Remote configuration not applied.", LOG_LEVEL_NOTICE);
}
// log(JSON.stringify(config), LOG_LEVEL_VERBOSE);
}
/**
* Process vault initialisation with suspending file watching and sync.
* @param proc process to be executed during initialisation, should return true if can be continued, false if app is unable to continue the process.
* @param keepSuspending whether to keep suspending file watching after the process.
* @returns result of the process, or false if error occurs.
*/
export async function processVaultInitialisation(
host: NecessaryServices<"setting", any>,
log: LogFunction,
proc: () => Promise<boolean>,
keepSuspending = false
) {
try {
// Disable batch saving and file watching during initialisation.
await host.services.setting.applyPartial({ batchSave: false }, false);
await host.services.setting.suspendAllSync();
await host.services.setting.suspendExtraSync();
await host.services.setting.applyPartial({ suspendFileWatching: true }, true);
try {
const result = await proc();
return result;
} catch (ex) {
log("Error during vault initialisation process.", LOG_LEVEL_NOTICE);
log(ex, LOG_LEVEL_VERBOSE);
return false;
}
} catch (ex) {
log("Error during vault initialisation.", LOG_LEVEL_NOTICE);
log(ex, LOG_LEVEL_VERBOSE);
return false;
} finally {
if (!keepSuspending) {
// Re-enable file watching after initialisation.
await host.services.setting.applyPartial({ suspendFileWatching: false }, true);
}
}
}
export async function verifyAndUnlockSuspension(
host: NecessaryServices<"setting" | "appLifecycle" | "UI", any>,
log: LogFunction
) {
if (!host.services.setting.currentSettings().suspendFileWatching) {
return true;
}
if (
(await host.services.UI.confirm.askYesNoDialog(
"Do you want to resume file and database processing, and restart obsidian now?",
{ defaultOption: "Yes", timeout: 15 }
)) != "yes"
) {
// TODO: Confirm actually proceed to next process.
return true;
}
await host.services.setting.applyPartial({ suspendFileWatching: false }, true);
host.services.appLifecycle.performRestart();
return false;
}
/**
* Factory function to create a rebuild flag handler.
+4 -2
View File
@@ -6,14 +6,16 @@ import {
createFetchAllFlagHandler,
createRebuildFlagHandler,
createSuspendFlagHandler,
flagHandlerToEventHandler,
} from "./redFlag";
import {
isFlagFileExist,
deleteFlagFile,
adjustSettingToRemote,
adjustSettingToRemoteIfNeeded,
processVaultInitialisation,
verifyAndUnlockSuspension,
flagHandlerToEventHandler,
} from "./redFlag";
} from "./redFlag.utils";
import {
TweakValuesRecommendedTemplate,
TweakValuesShouldMatchedTemplate,
+181
View File
@@ -0,0 +1,181 @@
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
import type { NecessaryServices } from "@lib/interfaces/ServiceModule";
import { type LogFunction } from "@lib/services/lib/logUtils";
import { extractObject } from "octagonal-wheels/object";
import { REMOTE_P2P } from "@lib/common/models/setting.const";
import type { ObsidianLiveSyncSettings } from "@lib/common/models/setting.type";
import { TweakValuesShouldMatchedTemplate } from "@lib/common/models/tweak.definition";
export async function isFlagFileExist(host: NecessaryServices<never, "storageAccess">, path: string) {
const redFlagExist = await host.serviceModules.storageAccess.isExists(
host.serviceModules.storageAccess.normalisePath(path)
);
if (redFlagExist) {
return true;
}
return false;
}
export async function deleteFlagFile(host: NecessaryServices<never, "storageAccess">, log: LogFunction, path: string) {
try {
const isFlagged = await host.serviceModules.storageAccess.isExists(
host.serviceModules.storageAccess.normalisePath(path)
);
if (isFlagged) {
await host.serviceModules.storageAccess.delete(path, true);
}
} catch (ex) {
log(`Could not delete ${path}`);
log(ex, LOG_LEVEL_VERBOSE);
}
}
/**
* Adjust setting to remote configuration.
* @param config current configuration to retrieve remote preferred config
* @returns updated configuration if applied, otherwise null.
*/
export async function adjustSettingToRemote(
host: NecessaryServices<"tweakValue" | "UI" | "setting", never>,
log: LogFunction,
config: ObsidianLiveSyncSettings
) {
// Fetch remote configuration unless prevented.
const SKIP_FETCH = "Skip and proceed";
const RETRY_FETCH = "Retry (recommended)";
let canProceed = false;
do {
const remoteTweaks = await host.services.tweakValue.fetchRemotePreferred(config);
if (!remoteTweaks) {
const choice = await host.services.UI.confirm.askSelectStringDialogue(
"Could not fetch configuration from remote. If you are new to the Self-hosted LiveSync, this might be expected. If not, you should check your network or server settings.",
[SKIP_FETCH, RETRY_FETCH] as const,
{
defaultAction: RETRY_FETCH,
timeout: 0,
title: "Fetch Remote Configuration Failed",
}
);
if (choice === SKIP_FETCH) {
canProceed = true;
}
} else {
const necessary = extractObject(TweakValuesShouldMatchedTemplate, remoteTweaks);
// Check if any necessary tweak value is different from current config.
const differentItems = Object.entries(necessary).filter(([key, value]) => {
return config[key as keyof ObsidianLiveSyncSettings] !== value;
});
if (differentItems.length === 0) {
log("Remote configuration matches local configuration. No changes applied.", LOG_LEVEL_NOTICE);
} else {
await host.services.UI.confirm.askSelectStringDialogue(
"Your settings differed slightly from the server's. The plug-in has supplemented the incompatible parts with the server settings!",
["OK"] as const,
{
defaultAction: "OK",
timeout: 0,
}
);
}
config = {
...config,
...Object.fromEntries(differentItems),
};
await host.services.setting.applyExternalSettings(config, true);
log("Remote configuration applied.", LOG_LEVEL_NOTICE);
canProceed = true;
const updatedConfig = host.services.setting.currentSettings();
return updatedConfig;
}
} while (!canProceed);
}
/**
* Adjust setting to remote if needed.
* @param extra result of dialogues that may contain preventFetchingConfig flag (e.g, from FetchEverything or RebuildEverything)
* @param config current configuration to retrieve remote preferred config
*/
export async function adjustSettingToRemoteIfNeeded(
host: NecessaryServices<"tweakValue" | "UI" | "setting", never>,
log: LogFunction,
extra: { preventFetchingConfig: boolean },
config: ObsidianLiveSyncSettings
) {
if (extra && extra.preventFetchingConfig) {
return;
}
// P2P has no centralised remote configuration; skip to avoid a spurious
// "Failed to connect to the remote server" error dialog.
if (config.remoteType === REMOTE_P2P) {
log("Remote configuration fetch skipped (P2P mode).", LOG_LEVEL_INFO);
return;
}
// Remote configuration fetched and applied.
if (await adjustSettingToRemote(host, log, config)) {
config = host.services.setting.currentSettings();
} else {
log("Remote configuration not applied.", LOG_LEVEL_NOTICE);
}
}
/**
* Process vault initialisation with suspending file watching and sync.
* @param proc process to be executed during initialisation, should return true if can be continued, false if app is unable to continue the process.
* @param keepSuspending whether to keep suspending file watching after the process.
* @returns result of the process, or false if error occurs.
*/
export async function processVaultInitialisation(
host: NecessaryServices<"setting", never>,
log: LogFunction,
proc: () => Promise<boolean>,
keepSuspending = false
) {
try {
// Disable batch saving and file watching during initialisation.
await host.services.setting.applyPartial({ batchSave: false }, false);
await host.services.setting.suspendAllSync();
await host.services.setting.suspendExtraSync();
await host.services.setting.applyPartial({ suspendFileWatching: true }, true);
try {
const result = await proc();
return result;
} catch (ex) {
log("Error during vault initialisation process.", LOG_LEVEL_NOTICE);
log(ex, LOG_LEVEL_VERBOSE);
return false;
}
} catch (ex) {
log("Error during vault initialisation.", LOG_LEVEL_NOTICE);
log(ex, LOG_LEVEL_VERBOSE);
return false;
} finally {
if (!keepSuspending) {
// Re-enable file watching after initialisation.
await host.services.setting.applyPartial({ suspendFileWatching: false }, true);
}
}
}
export async function verifyAndUnlockSuspension(
host: NecessaryServices<"setting" | "appLifecycle" | "UI", never>,
log: LogFunction
) {
if (!host.services.setting.currentSettings().suspendFileWatching) {
return true;
}
if (
(await host.services.UI.confirm.askYesNoDialog(
"Do you want to resume file and database processing, and restart obsidian now?",
{ defaultOption: "Yes", timeout: 15 }
)) != "yes"
) {
// TODO: Confirm actually proceed to next process.
return true;
}
await host.services.setting.applyPartial({ suspendFileWatching: false }, true);
host.services.appLifecycle.performRestart();
return false;
}

Some files were not shown because too many files have changed in this diff Show More