mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-03-13 21:38:48 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2fdc7669f3 | ||
|
|
ec8d9785ed | ||
|
|
71a80cacc3 | ||
|
|
38daeca89f | ||
|
|
7ec64a6a93 | ||
|
|
c5c6deb742 | ||
|
|
ef57fbfdda | ||
|
|
bc158e9f2b |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "obsidian-livesync",
|
||||
"name": "Self-hosted LiveSync",
|
||||
"version": "0.17.11",
|
||||
"version": "0.17.16",
|
||||
"minAppVersion": "0.9.12",
|
||||
"description": "Community implementation of self-hosted livesync. Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.",
|
||||
"author": "vorotamoroz",
|
||||
|
||||
33
package-lock.json
generated
33
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "obsidian-livesync",
|
||||
"version": "0.17.11",
|
||||
"version": "0.17.16",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "obsidian-livesync",
|
||||
"version": "0.17.11",
|
||||
"version": "0.17.16",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"diff-match-patch": "^1.0.5",
|
||||
@@ -33,6 +33,7 @@
|
||||
"postcss-load-config": "^4.0.1",
|
||||
"pouchdb-adapter-http": "^8.0.0",
|
||||
"pouchdb-adapter-idb": "^8.0.0",
|
||||
"pouchdb-adapter-indexeddb": "^8.0.0",
|
||||
"pouchdb-core": "^8.0.0",
|
||||
"pouchdb-find": "^8.0.0",
|
||||
"pouchdb-mapreduce": "^8.0.0",
|
||||
@@ -2889,6 +2890,20 @@
|
||||
"pouchdb-utils": "8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pouchdb-adapter-indexeddb": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pouchdb-adapter-indexeddb/-/pouchdb-adapter-indexeddb-8.0.0.tgz",
|
||||
"integrity": "sha512-h+vMPspVF6s4IKzLSys7iGDlANWkow77hJV/MX6JIftrjj/QS5jShSzhGCAR9HpLtuAVwQQM+k4hQodGnoAGWw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"pouchdb-adapter-utils": "8.0.0",
|
||||
"pouchdb-binary-utils": "8.0.0",
|
||||
"pouchdb-errors": "8.0.0",
|
||||
"pouchdb-md5": "8.0.0",
|
||||
"pouchdb-merge": "8.0.0",
|
||||
"pouchdb-utils": "8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pouchdb-adapter-utils": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pouchdb-adapter-utils/-/pouchdb-adapter-utils-8.0.0.tgz",
|
||||
@@ -5841,6 +5856,20 @@
|
||||
"pouchdb-utils": "8.0.0"
|
||||
}
|
||||
},
|
||||
"pouchdb-adapter-indexeddb": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pouchdb-adapter-indexeddb/-/pouchdb-adapter-indexeddb-8.0.0.tgz",
|
||||
"integrity": "sha512-h+vMPspVF6s4IKzLSys7iGDlANWkow77hJV/MX6JIftrjj/QS5jShSzhGCAR9HpLtuAVwQQM+k4hQodGnoAGWw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pouchdb-adapter-utils": "8.0.0",
|
||||
"pouchdb-binary-utils": "8.0.0",
|
||||
"pouchdb-errors": "8.0.0",
|
||||
"pouchdb-md5": "8.0.0",
|
||||
"pouchdb-merge": "8.0.0",
|
||||
"pouchdb-utils": "8.0.0"
|
||||
}
|
||||
},
|
||||
"pouchdb-adapter-utils": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pouchdb-adapter-utils/-/pouchdb-adapter-utils-8.0.0.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "obsidian-livesync",
|
||||
"version": "0.17.11",
|
||||
"version": "0.17.16",
|
||||
"description": "Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.",
|
||||
"main": "main.js",
|
||||
"type": "module",
|
||||
@@ -30,6 +30,7 @@
|
||||
"postcss-load-config": "^4.0.1",
|
||||
"pouchdb-adapter-http": "^8.0.0",
|
||||
"pouchdb-adapter-idb": "^8.0.0",
|
||||
"pouchdb-adapter-indexeddb": "^8.0.0",
|
||||
"pouchdb-core": "^8.0.0",
|
||||
"pouchdb-find": "^8.0.0",
|
||||
"pouchdb-mapreduce": "^8.0.0",
|
||||
|
||||
@@ -6,12 +6,14 @@ import { escapeStringToHTML } from "./lib/src/strbin";
|
||||
export class ConflictResolveModal extends Modal {
|
||||
// result: Array<[number, string]>;
|
||||
result: diff_result;
|
||||
filename: string;
|
||||
callback: (remove_rev: string) => Promise<void>;
|
||||
|
||||
constructor(app: App, diff: diff_result, callback: (remove_rev: string) => Promise<void>) {
|
||||
constructor(app: App, filename: string, diff: diff_result, callback: (remove_rev: string) => Promise<void>) {
|
||||
super(app);
|
||||
this.result = diff;
|
||||
this.callback = callback;
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
onOpen() {
|
||||
@@ -20,6 +22,7 @@ export class ConflictResolveModal extends Modal {
|
||||
contentEl.empty();
|
||||
|
||||
contentEl.createEl("h2", { text: "This document has conflicted changes." });
|
||||
contentEl.createEl("span", this.filename);
|
||||
const div = contentEl.createDiv("");
|
||||
div.addClass("op-scrollable");
|
||||
let diff = "";
|
||||
|
||||
@@ -3,7 +3,7 @@ import { KeyValueDatabase, OpenKeyValueDatabase } from "./KeyValueDB.js";
|
||||
import { LocalPouchDBBase } from "./lib/src/LocalPouchDBBase.js";
|
||||
import { Logger } from "./lib/src/logger.js";
|
||||
import { PouchDB } from "./lib/src/pouchdb-browser.js";
|
||||
import { EntryDoc, LOG_LEVEL } from "./lib/src/types.js";
|
||||
import { EntryDoc, LOG_LEVEL, ObsidianLiveSyncSettings } from "./lib/src/types.js";
|
||||
import { enableEncryption } from "./lib/src/utils_couchdb.js";
|
||||
import { isCloudantURI, isValidRemoteCouchDBURI } from "./lib/src/utils_couchdb.js";
|
||||
import { id2path, path2id } from "./utils.js";
|
||||
@@ -11,6 +11,7 @@ import { id2path, path2id } from "./utils.js";
|
||||
export class LocalPouchDB extends LocalPouchDBBase {
|
||||
|
||||
kvDB: KeyValueDatabase;
|
||||
settings: ObsidianLiveSyncSettings;
|
||||
id2path(filename: string): string {
|
||||
return id2path(filename);
|
||||
}
|
||||
@@ -18,6 +19,10 @@ export class LocalPouchDB extends LocalPouchDBBase {
|
||||
return path2id(filename);
|
||||
}
|
||||
CreatePouchDBInstance<T>(name?: string, options?: PouchDB.Configuration.DatabaseConfiguration): PouchDB.Database<T> {
|
||||
if (this.settings.useIndexedDBAdapter) {
|
||||
options.adapter = "indexeddb";
|
||||
return new PouchDB(name + "-indexeddb", options);
|
||||
}
|
||||
return new PouchDB(name, options);
|
||||
}
|
||||
beforeOnUnload(): void {
|
||||
@@ -52,7 +57,7 @@ export class LocalPouchDB extends LocalPouchDBBase {
|
||||
}
|
||||
|
||||
|
||||
async connectRemoteCouchDB(uri: string, auth: { username: string; password: string }, disableRequestURI: boolean, passphrase: string | boolean, useDynamicIterationCount: boolean): Promise<string | { db: PouchDB.Database<EntryDoc>; info: PouchDB.Core.DatabaseInfo }> {
|
||||
async connectRemoteCouchDB(uri: string, auth: { username: string; password: string }, disableRequestURI: boolean, passphrase: string | false, useDynamicIterationCount: boolean): Promise<string | { db: PouchDB.Database<EntryDoc>; info: PouchDB.Core.DatabaseInfo }> {
|
||||
if (!isValidRemoteCouchDBURI(uri)) return "Remote URI is not valid";
|
||||
if (uri.toLowerCase() != uri) return "Remote URI and database name could not contain capital letters.";
|
||||
if (uri.indexOf(" ") !== -1) return "Remote URI and database name could not contain spaces.";
|
||||
@@ -154,7 +159,7 @@ export class LocalPouchDB extends LocalPouchDBBase {
|
||||
};
|
||||
|
||||
const db: PouchDB.Database<EntryDoc> = new PouchDB<EntryDoc>(uri, conf);
|
||||
if (passphrase && typeof passphrase === "string") {
|
||||
if (passphrase !== "false" && typeof passphrase === "string") {
|
||||
enableEncryption(db, passphrase, useDynamicIterationCount);
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { App, PluginSettingTab, Setting, sanitizeHTMLToDom, RequestUrlParam, requestUrl, TextAreaComponent, MarkdownRenderer, stringifyYaml } from "obsidian";
|
||||
import { DEFAULT_SETTINGS, LOG_LEVEL, ObsidianLiveSyncSettings, RemoteDBSettings } from "./lib/src/types";
|
||||
import { DEFAULT_SETTINGS, LOG_LEVEL, ObsidianLiveSyncSettings, ConfigPassphraseStore, RemoteDBSettings } from "./lib/src/types";
|
||||
import { path2id, id2path } from "./utils";
|
||||
import { delay } from "./lib/src/utils";
|
||||
import { Semaphore } from "./lib/src/semaphore";
|
||||
@@ -43,6 +43,9 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
}
|
||||
display(): void {
|
||||
const { containerEl } = this;
|
||||
let encrypt = this.plugin.settings.encrypt;
|
||||
let passphrase = this.plugin.settings.passphrase;
|
||||
let useDynamicIterationCount = this.plugin.settings.useDynamicIterationCount;
|
||||
|
||||
containerEl.empty();
|
||||
|
||||
@@ -293,68 +296,78 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
)
|
||||
|
||||
);
|
||||
new Setting(containerRemoteDatabaseEl)
|
||||
const e2e = new Setting(containerRemoteDatabaseEl)
|
||||
.setName("End to End Encryption")
|
||||
.setDesc("Encrypt contents on the remote database. If you use the plugin's synchronization feature, enabling this is recommend.")
|
||||
.addToggle((toggle) =>
|
||||
toggle.setValue(this.plugin.settings.workingEncrypt).onChange(async (value) => {
|
||||
toggle.setValue(encrypt).onChange(async (value) => {
|
||||
if (inWizard) {
|
||||
this.plugin.settings.encrypt = value;
|
||||
passphrase.setDisabled(!value);
|
||||
passphraseSetting.setDisabled(!value);
|
||||
dynamicIteration.setDisabled(!value);
|
||||
await this.plugin.saveSettings();
|
||||
} else {
|
||||
this.plugin.settings.workingEncrypt = value;
|
||||
passphrase.setDisabled(!value);
|
||||
encrypt = value;
|
||||
passphraseSetting.setDisabled(!value);
|
||||
dynamicIteration.setDisabled(!value);
|
||||
await this.plugin.saveSettings();
|
||||
markDirtyControl();
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
const passphrase = new Setting(containerRemoteDatabaseEl)
|
||||
|
||||
const markDirtyControl = () => {
|
||||
passphraseSetting.controlEl.toggleClass("sls-item-dirty", passphrase != this.plugin.settings.passphrase);
|
||||
e2e.controlEl.toggleClass("sls-item-dirty", encrypt != this.plugin.settings.encrypt);
|
||||
dynamicIteration.controlEl.toggleClass("sls-item-dirty", useDynamicIterationCount != this.plugin.settings.useDynamicIterationCount)
|
||||
}
|
||||
|
||||
const passphraseSetting = new Setting(containerRemoteDatabaseEl)
|
||||
.setName("Passphrase")
|
||||
.setDesc("Encrypting passphrase. If you change the passphrase of a existing database, overwriting the remote database is strongly recommended.")
|
||||
.addText((text) => {
|
||||
text.setPlaceholder("")
|
||||
.setValue(this.plugin.settings.workingPassphrase)
|
||||
.setValue(passphrase)
|
||||
.onChange(async (value) => {
|
||||
if (inWizard) {
|
||||
this.plugin.settings.passphrase = value;
|
||||
await this.plugin.saveSettings();
|
||||
} else {
|
||||
this.plugin.settings.workingPassphrase = value;
|
||||
passphrase = value;
|
||||
await this.plugin.saveSettings();
|
||||
markDirtyControl();
|
||||
}
|
||||
});
|
||||
text.inputEl.setAttribute("type", "password");
|
||||
});
|
||||
passphrase.setDisabled(!this.plugin.settings.workingEncrypt);
|
||||
passphraseSetting.setDisabled(!encrypt);
|
||||
|
||||
const dynamicIteration = new Setting(containerRemoteDatabaseEl)
|
||||
.setName("Use dynamic iteration count (experimental)")
|
||||
.setDesc("Balancing the encryption/decryption load against the length of the passphrase if toggled. (v0.17.5 or higher required)")
|
||||
.addToggle((toggle) => {
|
||||
toggle.setValue(this.plugin.settings.workingUseDynamicIterationCount)
|
||||
toggle.setValue(useDynamicIterationCount)
|
||||
.onChange(async (value) => {
|
||||
if (inWizard) {
|
||||
this.plugin.settings.useDynamicIterationCount = value;
|
||||
await this.plugin.saveSettings();
|
||||
} else {
|
||||
this.plugin.settings.workingUseDynamicIterationCount = value;
|
||||
useDynamicIterationCount = value;
|
||||
await this.plugin.saveSettings();
|
||||
markDirtyControl();
|
||||
}
|
||||
});
|
||||
})
|
||||
.setClass("wizardHidden");
|
||||
dynamicIteration.setDisabled(!this.plugin.settings.workingEncrypt);
|
||||
dynamicIteration.setDisabled(!encrypt);
|
||||
|
||||
const checkWorkingPassphrase = async (): Promise<boolean> => {
|
||||
const settingForCheck: RemoteDBSettings = {
|
||||
...this.plugin.settings,
|
||||
encrypt: this.plugin.settings.workingEncrypt,
|
||||
passphrase: this.plugin.settings.workingPassphrase,
|
||||
useDynamicIterationCount: this.plugin.settings.workingUseDynamicIterationCount,
|
||||
encrypt: encrypt,
|
||||
passphrase: passphrase,
|
||||
useDynamicIterationCount: useDynamicIterationCount,
|
||||
};
|
||||
console.dir(settingForCheck);
|
||||
const db = await this.plugin.localDatabase.connectRemoteCouchDBWithSetting(settingForCheck, this.plugin.localDatabase.isMobile);
|
||||
@@ -372,19 +385,19 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
}
|
||||
};
|
||||
const applyEncryption = async (sendToServer: boolean) => {
|
||||
if (this.plugin.settings.workingEncrypt && this.plugin.settings.workingPassphrase == "") {
|
||||
if (encrypt && passphrase == "") {
|
||||
Logger("If you enable encryption, you have to set the passphrase", LOG_LEVEL.NOTICE);
|
||||
return;
|
||||
}
|
||||
if (this.plugin.settings.workingEncrypt && !(await testCrypt())) {
|
||||
if (encrypt && !(await testCrypt())) {
|
||||
Logger("WARNING! Your device would not support encryption.", LOG_LEVEL.NOTICE);
|
||||
return;
|
||||
}
|
||||
if (!(await checkWorkingPassphrase()) && !sendToServer) {
|
||||
return;
|
||||
}
|
||||
if (!this.plugin.settings.workingEncrypt) {
|
||||
this.plugin.settings.workingPassphrase = "";
|
||||
if (!encrypt) {
|
||||
passphrase = "";
|
||||
}
|
||||
this.plugin.settings.liveSync = false;
|
||||
this.plugin.settings.periodicReplication = false;
|
||||
@@ -392,11 +405,12 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
this.plugin.settings.syncOnStart = false;
|
||||
this.plugin.settings.syncOnFileOpen = false;
|
||||
this.plugin.settings.syncAfterMerge = false;
|
||||
this.plugin.settings.encrypt = this.plugin.settings.workingEncrypt;
|
||||
this.plugin.settings.passphrase = this.plugin.settings.workingPassphrase;
|
||||
this.plugin.settings.useDynamicIterationCount = this.plugin.settings.workingUseDynamicIterationCount;
|
||||
this.plugin.settings.encrypt = encrypt;
|
||||
this.plugin.settings.passphrase = passphrase;
|
||||
this.plugin.settings.useDynamicIterationCount = useDynamicIterationCount;
|
||||
|
||||
await this.plugin.saveSettings();
|
||||
markDirtyControl();
|
||||
if (sendToServer) {
|
||||
await this.plugin.initializeDatabase(true);
|
||||
await this.plugin.markRemoteLocked();
|
||||
@@ -803,6 +817,23 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
})
|
||||
);
|
||||
|
||||
containerLocalDatabaseEl.createEl("h3", {
|
||||
text: sanitizeHTMLToDom(`Experimental`),
|
||||
cls: "wizardHidden"
|
||||
});
|
||||
|
||||
new Setting(containerLocalDatabaseEl)
|
||||
.setName("Use new adapter")
|
||||
.setDesc("This option is not compatible with a database made by older versions. Changing this configuration will fetch the remote database again.")
|
||||
.setClass("wizardHidden")
|
||||
.addToggle((toggle) =>
|
||||
toggle.setValue(this.plugin.settings.useIndexedDBAdapter).onChange(async (value) => {
|
||||
this.plugin.settings.useIndexedDBAdapter = value;
|
||||
await this.plugin.saveSettings();
|
||||
await rebuildDB("localOnly");
|
||||
})
|
||||
);
|
||||
|
||||
addScreenElement("10", containerLocalDatabaseEl);
|
||||
const containerGeneralSettingsEl = containerEl.createDiv();
|
||||
containerGeneralSettingsEl.createEl("h3", { text: "General Settings" });
|
||||
@@ -852,6 +883,14 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
});
|
||||
text.inputEl.setAttribute("type", "number");
|
||||
});
|
||||
new Setting(containerGeneralSettingsEl)
|
||||
.setName("Monitor changes to hidden files and plugin")
|
||||
.addToggle((toggle) =>
|
||||
toggle.setValue(this.plugin.settings.watchInternalFileChanges).onChange(async (value) => {
|
||||
this.plugin.settings.watchInternalFileChanges = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
addScreenElement("20", containerGeneralSettingsEl);
|
||||
@@ -1025,7 +1064,6 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
new Setting(containerSyncSettingEl)
|
||||
.setName("Sync hidden files")
|
||||
.addToggle((toggle) =>
|
||||
@@ -1034,14 +1072,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
new Setting(containerSyncSettingEl)
|
||||
.setName("Monitor changes to internal files")
|
||||
.addToggle((toggle) =>
|
||||
toggle.setValue(this.plugin.settings.watchInternalFileChanges).onChange(async (value) => {
|
||||
this.plugin.settings.watchInternalFileChanges = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerSyncSettingEl)
|
||||
.setName("Scan for hidden files before replication")
|
||||
.setDesc("This configuration will be ignored if monitoring changes is enabled.")
|
||||
@@ -1326,6 +1357,45 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
})
|
||||
);
|
||||
|
||||
const passphrase_options: Record<ConfigPassphraseStore, string> = {
|
||||
"": "Default",
|
||||
LOCALSTORAGE: "Use a custom passphrase",
|
||||
ASK_AT_LAUNCH: "Ask an passphrase at every launch",
|
||||
}
|
||||
new Setting(containerMiscellaneousEl)
|
||||
.setName("Encrypting sensitive configuration items")
|
||||
.addDropdown((dropdown) =>
|
||||
dropdown
|
||||
.addOptions(passphrase_options)
|
||||
.setValue(this.plugin.settings.configPassphraseStore)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.configPassphraseStore = value as ConfigPassphraseStore;
|
||||
this.plugin.usedPassphrase = "";
|
||||
confPassphraseSetting.setDisabled(this.plugin.settings.configPassphraseStore != "LOCALSTORAGE");
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
)
|
||||
.setClass("wizardHidden");
|
||||
|
||||
|
||||
const confPassphrase = localStorage.getItem("ls-setting-passphrase") || "";
|
||||
const confPassphraseSetting = new Setting(containerMiscellaneousEl)
|
||||
.setName("Passphrase of sensitive configuration items")
|
||||
.setDesc("This passphrase will not be copied to another device. It will be set to `Default` until you configure it again.")
|
||||
.addText((text) => {
|
||||
text.setPlaceholder("")
|
||||
.setValue(confPassphrase)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.usedPassphrase = "";
|
||||
localStorage.setItem("ls-setting-passphrase", value);
|
||||
await this.plugin.saveSettings();
|
||||
markDirtyControl();
|
||||
});
|
||||
text.inputEl.setAttribute("type", "password");
|
||||
})
|
||||
.setClass("wizardHidden");
|
||||
confPassphraseSetting.setDisabled(this.plugin.settings.configPassphraseStore != "LOCALSTORAGE");
|
||||
|
||||
const infoApply = containerMiscellaneousEl.createEl("div", { text: `To finish setup, please select one of the presets` });
|
||||
infoApply.addClass("op-warn-info");
|
||||
infoApply.addClass("wizardOnly")
|
||||
@@ -1367,7 +1437,8 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
|
||||
pluginConfig.couchDB_URI = isCloudantURI(pluginConfig.couchDB_URI) ? "cloudant" : "self-hosted";
|
||||
pluginConfig.couchDB_USER = REDACTED;
|
||||
pluginConfig.passphrase = REDACTED;
|
||||
pluginConfig.workingPassphrase = REDACTED;
|
||||
pluginConfig.encryptedPassphrase = REDACTED;
|
||||
pluginConfig.encryptedCouchDBConnection = REDACTED;
|
||||
|
||||
const msgConfig = `----remote config----
|
||||
${stringifyYaml(responseConfig)}
|
||||
@@ -1497,7 +1568,7 @@ ${stringifyYaml(pluginConfig)}`;
|
||||
|
||||
new Setting(containerPluginSettings)
|
||||
.setName("Scan plugins periodically")
|
||||
.setDesc("Scan plugins every 1 minute.")
|
||||
.setDesc("Scan plugins every 1 minute. This configuration will be ignored if monitoring changes of hidden files has been enabled.")
|
||||
.addToggle((toggle) =>
|
||||
toggle.setValue(this.plugin.settings.autoSweepPluginsPeriodic).onChange(async (value) => {
|
||||
this.plugin.settings.autoSweepPluginsPeriodic = value;
|
||||
|
||||
@@ -52,14 +52,14 @@ export class InputStringDialog extends Modal {
|
||||
const { contentEl } = this;
|
||||
|
||||
contentEl.createEl("h1", { text: this.title });
|
||||
|
||||
new Setting(contentEl).setName(this.key).addText((text) =>
|
||||
// For enter to submit
|
||||
const formEl = contentEl.createEl("form");
|
||||
new Setting(formEl).setName(this.key).addText((text) =>
|
||||
text.onChange((value) => {
|
||||
this.result = value;
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(contentEl).addButton((btn) =>
|
||||
new Setting(formEl).addButton((btn) =>
|
||||
btn
|
||||
.setButtonText("Ok")
|
||||
.setCta()
|
||||
|
||||
2
src/lib
2
src/lib
Submodule src/lib updated: 133bae3607...2567497fa6
616
src/main.ts
616
src/main.ts
File diff suppressed because it is too large
Load Diff
11
src/types.ts
11
src/types.ts
@@ -1,4 +1,4 @@
|
||||
import { PluginManifest } from "obsidian";
|
||||
import { PluginManifest, TFile } from "obsidian";
|
||||
import { DatabaseEntry, EntryBody } from "./lib/src/types";
|
||||
|
||||
export interface PluginDataEntry extends DatabaseEntry {
|
||||
@@ -31,6 +31,15 @@ export interface InternalFileInfo {
|
||||
deleted?: boolean;
|
||||
}
|
||||
|
||||
export interface FileInfo {
|
||||
path: string;
|
||||
mtime: number;
|
||||
ctime: number;
|
||||
size: number;
|
||||
deleted?: boolean;
|
||||
file: TFile;
|
||||
}
|
||||
|
||||
export type queueItem = {
|
||||
entry: EntryBody;
|
||||
missingChildren: string[];
|
||||
|
||||
@@ -247,4 +247,8 @@ div.sls-setting-menu-btn {
|
||||
|
||||
.sls-setting:not(.isWizard) .wizardOnly {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sls-item-dirty::before {
|
||||
content: "✏";
|
||||
}
|
||||
64
updates.md
64
updates.md
@@ -51,37 +51,35 @@
|
||||
- Now `Chunk size` can be set to under one hundred.
|
||||
- New feature:
|
||||
- The number of transfers required before replication stabilises is now displayed.
|
||||
- 0.17.12: Skipped.
|
||||
- 0.17.13
|
||||
- Fixed: Document history is now displayed again.
|
||||
- Reorganised: Many files have been refactored.
|
||||
- 0.17.14: Skipped.
|
||||
- 0.17.15
|
||||
- Improved:
|
||||
- Confidential information has no longer stored in data.json as is.
|
||||
- Synchronising progress has been shown in the notification.
|
||||
- We can commit passphrases with a keyboard.
|
||||
- Configuration which had not been saved yet is marked now.
|
||||
- Now the filename is shown on the Conflict resolving dialog
|
||||
- Fixed:
|
||||
- Hidden files have been synchronised again.
|
||||
- Rename of files has been fixed again.
|
||||
- 0.17.16:
|
||||
- Improved:
|
||||
- Plugins and their settings no longer need scanning if changes are monitored.
|
||||
- Now synchronising plugins and their settings are performed parallelly and faster.
|
||||
- We can place `redflag2.md` to rebuild the database automatically while the boot sequence.
|
||||
- Experimental:
|
||||
- We can use a new adapter on PouchDB. This will make us smoother.
|
||||
- Note: Not compatible with the older version.
|
||||
- Fixed:
|
||||
- The default batch size is smaller again.
|
||||
- Plugins and their setting can be synchronised again.
|
||||
- Hidden files and plugins are correctly scanned while rebuilding.
|
||||
- Files with the name started `_` are also being performed conflict-checking.
|
||||
|
||||
And, minor changes have been included.
|
||||
|
||||
### 0.16.0
|
||||
- Now hidden files need not be scanned. Changes will be detected automatically.
|
||||
- If you want it to back to its previous behaviour, please disable `Monitor changes to internal files`.
|
||||
- Due to using an internal API, this feature may become unusable with a major update. If this happens, please disable this once.
|
||||
|
||||
#### Minors
|
||||
|
||||
- 0.16.1 Added missing log updates.
|
||||
- 0.16.2 Fixed many problems caused by combinations of `Sync On Save` and the tracking logic that changed at 0.15.6.
|
||||
- 0.16.3
|
||||
- Fixed detection of IBM Cloudant (And if there are some issues, be fixed automatically).
|
||||
- A configuration information reporting tool has been implemented.
|
||||
- 0.16.4 Fixed detection failure. Please set the `Chunk size` again when using a self-hosted database.
|
||||
- 0.16.5
|
||||
- Fixed
|
||||
- Conflict detection and merging now be able to treat deleted files.
|
||||
- Logs while the boot-up sequence has been tidied up.
|
||||
- Fixed incorrect log entries.
|
||||
- New Feature
|
||||
- The feature of automatically deleting old expired metadata has been implemented.
|
||||
We can configure it in `Delete old metadata of deleted files on start-up` in the `General Settings` pane.
|
||||
- 0.16.6
|
||||
- Fixed
|
||||
- Automatic (temporary) batch size adjustment has been restored to work correctly.
|
||||
- Chunk splitting has been backed to the previous behaviour for saving them correctly.
|
||||
- Improved
|
||||
- Corrupted chunks will be detected automatically.
|
||||
- Now on the case-insensitive system, `aaa.md` and `AAA.md` will be treated as the same file or path at applying changesets.
|
||||
- 0.16.7 Nothing has been changed except toolsets, framework library, and as like them. Please inform me if something had been getting strange!
|
||||
- 0.16.8 Now we can synchronise without `bad_request:invalid UTF-8 JSON` even while end-to-end encryption has been disabled.
|
||||
|
||||
Note:
|
||||
Before 0.16.5, LiveSync had some issues making chunks. In this case, synchronisation had became been always failing after a corrupted one should be made. After 0.16.6, the corrupted chunk is automatically detected. Sorry for troubling you but please do `rebuild everything` when this plug-in notified so.
|
||||
... To continue on to `updates_old.md`.
|
||||
@@ -1,3 +1,58 @@
|
||||
|
||||
### 0.16.0
|
||||
- Now hidden files need not be scanned. Changes will be detected automatically.
|
||||
- If you want it to back to its previous behaviour, please disable `Monitor changes to internal files`.
|
||||
- Due to using an internal API, this feature may become unusable with a major update. If this happens, please disable this once.
|
||||
|
||||
#### Minors
|
||||
|
||||
- 0.16.1 Added missing log updates.
|
||||
- 0.16.2 Fixed many problems caused by combinations of `Sync On Save` and the tracking logic that changed at 0.15.6.
|
||||
- 0.16.3
|
||||
- Fixed detection of IBM Cloudant (And if there are some issues, be fixed automatically).
|
||||
- A configuration information reporting tool has been implemented.
|
||||
- 0.16.4 Fixed detection failure. Please set the `Chunk size` again when using a self-hosted database.
|
||||
- 0.16.5
|
||||
- Fixed
|
||||
- Conflict detection and merging now be able to treat deleted files.
|
||||
- Logs while the boot-up sequence has been tidied up.
|
||||
- Fixed incorrect log entries.
|
||||
- New Feature
|
||||
- The feature of automatically deleting old expired metadata has been implemented.
|
||||
We can configure it in `Delete old metadata of deleted files on start-up` in the `General Settings` pane.
|
||||
- 0.16.6
|
||||
- Fixed
|
||||
- Automatic (temporary) batch size adjustment has been restored to work correctly.
|
||||
- Chunk splitting has been backed to the previous behaviour for saving them correctly.
|
||||
- Improved
|
||||
- Corrupted chunks will be detected automatically.
|
||||
- Now on the case-insensitive system, `aaa.md` and `AAA.md` will be treated as the same file or path at applying changesets.
|
||||
- 0.16.7 Nothing has been changed except toolsets, framework library, and as like them. Please inform me if something had been getting strange!
|
||||
- 0.16.8 Now we can synchronise without `bad_request:invalid UTF-8 JSON` even while end-to-end encryption has been disabled.
|
||||
|
||||
Note:
|
||||
Before 0.16.5, LiveSync had some issues making chunks. In this case, synchronisation had became been always failing after a corrupted one should be made. After 0.16.6, the corrupted chunk is automatically detected. Sorry for troubling you but please do `rebuild everything` when this plug-in notified so.
|
||||
|
||||
### 0.15.0
|
||||
- Outdated configuration items have been removed.
|
||||
- Setup wizard has been implemented!
|
||||
|
||||
I appreciate for reviewing and giving me advice @Pouhon158!
|
||||
|
||||
#### Minors
|
||||
- 0.15.1 Missed the stylesheet.
|
||||
- 0.15.2 The wizard has been improved and documented!
|
||||
- 0.15.3 Fixed the issue about locking/unlocking remote database while rebuilding in the wizard.
|
||||
- 0.15.4 Fixed issues about asynchronous processing (e.g., Conflict check or hidden file detection)
|
||||
- 0.15.5 Add new features for setting Self-hosted LiveSync up more easier.
|
||||
- 0.15.6 File tracking logic has been refined.
|
||||
- 0.15.7 Fixed bug about renaming file.
|
||||
- 0.15.8 Fixed bug about deleting empty directory, weird behaviour on boot-sequence on mobile devices.
|
||||
- 0.15.9 Improved chunk retrieving, now chunks are retrieved in batch on continuous requests.
|
||||
- 0.15.10 Fixed:
|
||||
- The boot sequence has been corrected and now boots smoothly.
|
||||
- Auto applying of batch save will be processed earlier than before.
|
||||
|
||||
### 0.14.1
|
||||
- The target selecting filter was implemented.
|
||||
Now we can set what files are synchronised by regular expression.
|
||||
|
||||
Reference in New Issue
Block a user