mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-03-07 10:28:48 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4af4d9c4bd | ||
|
|
1b7a25598a | ||
|
|
e2a01c14cc | ||
|
|
b2fbbb38f5 |
@@ -28,7 +28,7 @@ openssl ecparam -name secp521r1 -genkey -noout | openssl pkcs8 -topk8 -inform PE
|
||||
openssl ec -in private_key.pem -pubout -outform PEM -out public_key.pem
|
||||
```
|
||||
|
||||
> [!More tip]
|
||||
> [!TIP]
|
||||
> A key generator will be provided again in a future version of the user interface.
|
||||
|
||||
### 2. Configure CouchDB to accept JWT tokens
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "obsidian-livesync",
|
||||
"name": "Self-hosted LiveSync",
|
||||
"version": "0.25.26",
|
||||
"version": "0.25.27",
|
||||
"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",
|
||||
|
||||
18
package-lock.json
generated
18
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "obsidian-livesync",
|
||||
"version": "0.25.26",
|
||||
"version": "0.25.27",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "obsidian-livesync",
|
||||
"version": "0.25.26",
|
||||
"version": "0.25.27",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.808.0",
|
||||
@@ -20,7 +20,7 @@
|
||||
"idb": "^8.0.3",
|
||||
"minimatch": "^10.0.2",
|
||||
"octagonal-wheels": "^0.1.44",
|
||||
"qrcode-generator": "^2.0.4",
|
||||
"qrcode-generator": "^1.4.4",
|
||||
"trystero": "^0.22.0",
|
||||
"xxhash-wasm-102": "npm:xxhash-wasm@^1.0.2"
|
||||
},
|
||||
@@ -10019,9 +10019,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode-generator": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/qrcode-generator/-/qrcode-generator-2.0.4.tgz",
|
||||
"integrity": "sha512-mZSiP6RnbHl4xL2Ap5HfkjLnmxfKcPWpWe/c+5XxCuetEenqmNFf1FH/ftXPCtFG5/TDobjsjz6sSNL0Sr8Z9g==",
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/qrcode-generator/-/qrcode-generator-1.5.2.tgz",
|
||||
"integrity": "sha512-pItrW0Z9HnDBnFmgiNrY1uxRdri32Uh9EjNYLPVC2zZ3ZRIIEqBoDgm4DkvDwNNDHTK7FNkmr8zAa77BYc9xNw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/querystringify": {
|
||||
@@ -18967,9 +18967,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"qrcode-generator": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/qrcode-generator/-/qrcode-generator-2.0.4.tgz",
|
||||
"integrity": "sha512-mZSiP6RnbHl4xL2Ap5HfkjLnmxfKcPWpWe/c+5XxCuetEenqmNFf1FH/ftXPCtFG5/TDobjsjz6sSNL0Sr8Z9g=="
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/qrcode-generator/-/qrcode-generator-1.5.2.tgz",
|
||||
"integrity": "sha512-pItrW0Z9HnDBnFmgiNrY1uxRdri32Uh9EjNYLPVC2zZ3ZRIIEqBoDgm4DkvDwNNDHTK7FNkmr8zAa77BYc9xNw=="
|
||||
},
|
||||
"querystringify": {
|
||||
"version": "2.2.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "obsidian-livesync",
|
||||
"version": "0.25.26",
|
||||
"version": "0.25.27",
|
||||
"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",
|
||||
@@ -95,7 +95,7 @@
|
||||
"idb": "^8.0.3",
|
||||
"minimatch": "^10.0.2",
|
||||
"octagonal-wheels": "^0.1.44",
|
||||
"qrcode-generator": "^2.0.4",
|
||||
"qrcode-generator": "^1.4.4",
|
||||
"trystero": "^0.22.0",
|
||||
"xxhash-wasm-102": "npm:xxhash-wasm@^1.0.2"
|
||||
}
|
||||
|
||||
2
src/lib
2
src/lib
Submodule src/lib updated: b8fb5e5e63...f99e662309
@@ -1,6 +1,7 @@
|
||||
import { AbstractModule } from "../AbstractModule";
|
||||
import { PouchDB } from "../../lib/src/pouchdb/pouchdb-browser";
|
||||
import type { LiveSyncCore } from "../../main";
|
||||
import { ExtraSuffixIndexedDB } from "../../lib/src/common/types";
|
||||
|
||||
export class ModulePouchDB extends AbstractModule {
|
||||
_createPouchDBInstance<T extends object>(
|
||||
@@ -12,7 +13,7 @@ export class ModulePouchDB extends AbstractModule {
|
||||
optionPass.adapter = "indexeddb";
|
||||
//@ts-ignore :missing def
|
||||
optionPass.purged_infos_limit = 1;
|
||||
return new PouchDB(name + "-indexeddb", optionPass);
|
||||
return new PouchDB(name + ExtraSuffixIndexedDB, optionPass);
|
||||
}
|
||||
return new PouchDB(name, optionPass);
|
||||
}
|
||||
|
||||
@@ -3,12 +3,16 @@ import {
|
||||
E2EEAlgorithms,
|
||||
type HashAlgorithm,
|
||||
LOG_LEVEL_NOTICE,
|
||||
SuffixDatabaseName,
|
||||
} from "../../../lib/src/common/types.ts";
|
||||
import { Logger } from "../../../lib/src/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 { migrateDatabases } from "./settingUtils.ts";
|
||||
|
||||
export function panePatches(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElement, { addPanel }: PageFunctions): void {
|
||||
void addPanel(paneEl, "Compatibility (Metadata)").then((paneEl) => {
|
||||
@@ -26,17 +30,88 @@ export function panePatches(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElemen
|
||||
});
|
||||
|
||||
void addPanel(paneEl, "Compatibility (Database structure)").then((paneEl) => {
|
||||
new Setting(paneEl).autoWireToggle("useIndexedDBAdapter", { invert: true, holdValue: true });
|
||||
|
||||
// new Setting(paneEl)
|
||||
// .autoWireToggle("doNotUseFixedRevisionForChunks", { holdValue: true })
|
||||
// .setClass("wizardHidden");
|
||||
const migrateAllToIndexedDB = async () => {
|
||||
const dbToName = this.plugin.localDatabase.dbname + SuffixDatabaseName + ExtraSuffixIndexedDB;
|
||||
const options = {
|
||||
adapter: "indexeddb",
|
||||
//@ts-ignore :missing def
|
||||
purged_infos_limit: 1,
|
||||
auto_compaction: false,
|
||||
deterministic_revs: true,
|
||||
};
|
||||
const openTo = () => {
|
||||
return new PouchDB(dbToName, options);
|
||||
};
|
||||
if (await migrateDatabases("to IndexedDB", this.plugin.localDatabase.localDatabase, openTo)) {
|
||||
Logger(
|
||||
"Migration to IndexedDB completed. Obsidian will be restarted with new configuration immediately.",
|
||||
LOG_LEVEL_NOTICE
|
||||
);
|
||||
this.plugin.settings.useIndexedDBAdapter = true;
|
||||
await this.services.setting.saveSettingData();
|
||||
this.services.appLifecycle.performRestart();
|
||||
}
|
||||
};
|
||||
const migrateAllToIDB = async () => {
|
||||
const dbToName = this.plugin.localDatabase.dbname + SuffixDatabaseName;
|
||||
const options = {
|
||||
adapter: "idb",
|
||||
auto_compaction: false,
|
||||
deterministic_revs: true,
|
||||
};
|
||||
const openTo = () => {
|
||||
return new PouchDB(dbToName, options);
|
||||
};
|
||||
if (await migrateDatabases("to IDB", this.plugin.localDatabase.localDatabase, openTo)) {
|
||||
Logger(
|
||||
"Migration to IDB completed. Obsidian will be restarted with new configuration immediately.",
|
||||
LOG_LEVEL_NOTICE
|
||||
);
|
||||
this.plugin.settings.useIndexedDBAdapter = false;
|
||||
await this.services.setting.saveSettingData();
|
||||
this.services.appLifecycle.performRestart();
|
||||
}
|
||||
};
|
||||
{
|
||||
const infoClass = this.editingSettings.useIndexedDBAdapter ? "op-warn" : "op-warn-info";
|
||||
paneEl.createDiv({
|
||||
text: "The IndexedDB adapter often offers superior performance in certain scenarios, but it has been found to cause memory leaks when used with LiveSync mode. When using LiveSync mode, please use IDB adapter instead.",
|
||||
cls: infoClass,
|
||||
});
|
||||
paneEl.createDiv({
|
||||
text: "Changing this setting requires migrating existing data (a bit time may be taken) and restarting Obsidian. Please make sure to back up your data before proceeding.",
|
||||
cls: "op-warn-info",
|
||||
});
|
||||
const setting = new Setting(paneEl)
|
||||
.setName("Database Adapter")
|
||||
.setDesc("Select the database adapter to use. ");
|
||||
const el = setting.controlEl.createDiv({});
|
||||
el.setText(`Current adapter: ${this.editingSettings.useIndexedDBAdapter ? "IndexedDB" : "IDB"}`);
|
||||
if (!this.editingSettings.useIndexedDBAdapter) {
|
||||
setting.addButton((button) => {
|
||||
button.setButtonText("Switch to IndexedDB").onClick(async () => {
|
||||
Logger("Migrating all data to IndexedDB...", LOG_LEVEL_NOTICE);
|
||||
await migrateAllToIndexedDB();
|
||||
Logger(
|
||||
"Migration to IndexedDB completed. Please switch the adapter and restart Obsidian.",
|
||||
LOG_LEVEL_NOTICE
|
||||
);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
setting.addButton((button) => {
|
||||
button.setButtonText("Switch to IDB").onClick(async () => {
|
||||
Logger("Migrating all data to IDB...", LOG_LEVEL_NOTICE);
|
||||
await migrateAllToIDB();
|
||||
Logger(
|
||||
"Migration to IDB completed. Please switch the adapter and restart Obsidian.",
|
||||
LOG_LEVEL_NOTICE
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
new Setting(paneEl).autoWireToggle("handleFilenameCaseSensitive", { holdValue: true }).setClass("wizardHidden");
|
||||
|
||||
this.addOnSaved("useIndexedDBAdapter", async () => {
|
||||
await this.saveAllDirtySettings();
|
||||
await this.rebuildDB("localOnly");
|
||||
});
|
||||
});
|
||||
|
||||
void addPanel(paneEl, "Compatibility (Internal API Usage)").then((paneEl) => {
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { escapeStringToHTML } from "octagonal-wheels/string";
|
||||
import { E2EEAlgorithmNames, type ObsidianLiveSyncSettings } from "../../../lib/src/common/types";
|
||||
import {
|
||||
E2EEAlgorithmNames,
|
||||
MILESTONE_DOCID,
|
||||
NODEINFO_DOCID,
|
||||
type ObsidianLiveSyncSettings,
|
||||
} from "../../../lib/src/common/types";
|
||||
import {
|
||||
pickCouchDBSyncSettings,
|
||||
pickBucketSyncSettings,
|
||||
@@ -7,6 +12,7 @@ import {
|
||||
pickEncryptionSettings,
|
||||
} from "../../../lib/src/common/utils";
|
||||
import { getConfig, type AllSettingItemKey } from "./settingConstants";
|
||||
import { LOG_LEVEL_NOTICE, Logger } from "octagonal-wheels/common/logger";
|
||||
|
||||
/**
|
||||
* Generates a summary of P2P configuration settings
|
||||
@@ -76,3 +82,73 @@ export function getSummaryFromPartialSettings(setting: Partial<ObsidianLiveSyncS
|
||||
}
|
||||
return outputSummary;
|
||||
}
|
||||
|
||||
// Migration or de-migration helper functions
|
||||
|
||||
/**
|
||||
* Copy document from one database to another for migration purposes
|
||||
* @param docName document ID
|
||||
* @param dbFrom source database
|
||||
* @param dbTo destination database
|
||||
* @returns
|
||||
*/
|
||||
export async function copyMigrationDocs(docName: string, dbFrom: PouchDB.Database, dbTo: PouchDB.Database) {
|
||||
try {
|
||||
const doc = await dbFrom.get(docName);
|
||||
delete (doc as any)._rev;
|
||||
await dbTo.put(doc);
|
||||
} catch (e) {
|
||||
if ((e as any).status === 404) {
|
||||
return;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
type PouchDBOpenFunction = () => Promise<PouchDB.Database> | PouchDB.Database;
|
||||
|
||||
/**
|
||||
* Migrate databases from one to another
|
||||
* @param operationName Name of the migration operation
|
||||
* @param from source database
|
||||
* @param openTo function to open destination database
|
||||
* @returns True if migration succeeded
|
||||
*/
|
||||
export async function migrateDatabases(operationName: string, from: PouchDB.Database, openTo: PouchDBOpenFunction) {
|
||||
const dbTo = await openTo();
|
||||
await dbTo.info(); // ensure created
|
||||
Logger(`Opening destination database for migration: ${operationName}.`, LOG_LEVEL_NOTICE, "migration");
|
||||
// destroy existing data
|
||||
await dbTo.destroy();
|
||||
Logger(`Destroyed existing destination database for migration: ${operationName}.`, LOG_LEVEL_NOTICE, "migration");
|
||||
|
||||
const dbTo2 = await openTo();
|
||||
const info2 = await dbTo2.info(); // ensure created
|
||||
console.log(info2);
|
||||
Logger(`Re-created destination database for migration: ${operationName}.`, LOG_LEVEL_NOTICE, "migration");
|
||||
|
||||
const info = await from.info();
|
||||
const totalDocs = info.doc_count || 0;
|
||||
const result = await from.replicate
|
||||
.to(dbTo2, {
|
||||
//@ts-ignore Missing in typedefs
|
||||
style: "all_docs",
|
||||
})
|
||||
.on("change", (info) => {
|
||||
Logger(
|
||||
`Replicating... Docs replicated: ${info.docs_written} / ${totalDocs}`,
|
||||
LOG_LEVEL_NOTICE,
|
||||
"migration"
|
||||
);
|
||||
});
|
||||
if (result.ok) {
|
||||
Logger(`Replication completed for migration: ${operationName}.`, LOG_LEVEL_NOTICE, "migration");
|
||||
} else {
|
||||
throw new Error(`Replication failed for migration: ${operationName}.`);
|
||||
}
|
||||
await copyMigrationDocs(MILESTONE_DOCID, from, dbTo2);
|
||||
await copyMigrationDocs(NODEINFO_DOCID, from, dbTo2);
|
||||
Logger(`Copied migration documents for migration: ${operationName}.`, LOG_LEVEL_NOTICE, "migration");
|
||||
await dbTo2.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
19
updates.md
19
updates.md
@@ -4,6 +4,25 @@ Since 19th July, 2025 (beta1 in 0.25.0-beta1, 13th July, 2025)
|
||||
|
||||
The head note of 0.25 is now in [updates_old.md](https://github.com/vrtmrz/obsidian-livesync/blob/main/updates_old.md). Because 0.25 got a lot of updates, thankfully, compatibility is kept and we do not need breaking changes! In other words, when get enough stabled. The next version will be v1.0.0. Even though it my hope.
|
||||
|
||||
## 0.25.27
|
||||
|
||||
12th November, 2025
|
||||
|
||||
### Improved
|
||||
|
||||
- Now we can switch the database adapter between IndexedDB and IDB without rebuilding (#747).
|
||||
- Just a local migration will be required, but faster than a full rebuild.
|
||||
- No longer checking for the adapter by `Doctor`.
|
||||
|
||||
### Changes
|
||||
|
||||
- The default adapter is reverted to IDB to avoid memory leaks (#747).
|
||||
|
||||
### Fixed (?)
|
||||
|
||||
- Reverted QR code library to v1.4.4 (To make sure #752).
|
||||
|
||||
|
||||
## 0.25.26
|
||||
|
||||
07th November, 2025
|
||||
|
||||
Reference in New Issue
Block a user