mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-06-11 00:40:14 +00:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 27e9b68510 | |||
| e4b36602ec | |||
| 36827d4799 | |||
| f596e7dd68 | |||
| b0ac01e52f | |||
| b4077bd1f5 | |||
| 675de883e9 | |||
| 4b8de7c915 | |||
| 4f8a74107c | |||
| 42ed0d8795 | |||
| 54c2b1c6db | |||
| 0856693aac |
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
Generated
+443
-905
File diff suppressed because it is too large
Load Diff
+6
-7
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, {
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
@@ -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,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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,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 {
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,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> {
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user