mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-05-19 14:01:21 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3cd9b9e06d | ||
|
|
7c43c61b85 | ||
|
|
465af4f3aa | ||
|
|
0a1e3dcd51 | ||
|
|
b97756d0cf | ||
|
|
acf4bc3737 | ||
|
|
88838872e7 |
33
.github/workflows/unit-ci.yml
vendored
Normal file
33
.github/workflows/unit-ci.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Run Unit test without Harnesses
|
||||||
|
name: unit-ci
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 30
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '24.x'
|
||||||
|
cache: 'npm'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Install test dependencies (Playwright Chromium)
|
||||||
|
run: npm run test:install-dependencies
|
||||||
|
|
||||||
|
- name: Run unit tests suite
|
||||||
|
run: npm run test:unit
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"id": "obsidian-livesync",
|
"id": "obsidian-livesync",
|
||||||
"name": "Self-hosted LiveSync",
|
"name": "Self-hosted LiveSync",
|
||||||
"version": "0.25.38",
|
"version": "0.25.41",
|
||||||
"minAppVersion": "0.9.12",
|
"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.",
|
"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",
|
"author": "vorotamoroz",
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "obsidian-livesync",
|
"name": "obsidian-livesync",
|
||||||
"version": "0.25.38",
|
"version": "0.25.41",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "obsidian-livesync",
|
"name": "obsidian-livesync",
|
||||||
"version": "0.25.38",
|
"version": "0.25.41",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "^3.808.0",
|
"@aws-sdk/client-s3": "^3.808.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "obsidian-livesync",
|
"name": "obsidian-livesync",
|
||||||
"version": "0.25.38",
|
"version": "0.25.41",
|
||||||
"description": "Reflect your vault changes to some other devices immediately. Please make sure to disable other synchronize solutions to avoid content corruption or duplication.",
|
"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",
|
"main": "main.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -26,6 +26,8 @@
|
|||||||
"check": "npm run lint && npm run svelte-check",
|
"check": "npm run lint && npm run svelte-check",
|
||||||
"unittest": "deno test -A --no-check --coverage=cov_profile --v8-flags=--expose-gc --trace-leaks ./src/",
|
"unittest": "deno test -A --no-check --coverage=cov_profile --v8-flags=--expose-gc --trace-leaks ./src/",
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
|
"test:unit": "vitest run --config vitest.config.unit.ts",
|
||||||
|
"test:unit:coverage": "vitest run --config vitest.config.unit.ts --coverage",
|
||||||
"test:install-playwright": "npx playwright install chromium",
|
"test:install-playwright": "npx playwright install chromium",
|
||||||
"test:install-dependencies": "npm run test:install-playwright",
|
"test:install-dependencies": "npm run test:install-playwright",
|
||||||
"test:coverage": "vitest run --coverage",
|
"test:coverage": "vitest run --coverage",
|
||||||
|
|||||||
@@ -1803,16 +1803,16 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
||||||
services.fileProcessing.handleOptionalFileEvent(this._anyProcessOptionalFileEvent.bind(this));
|
services.fileProcessing.processOptionalFileEvent.addHandler(this._anyProcessOptionalFileEvent.bind(this));
|
||||||
services.conflict.handleGetOptionalConflictCheckMethod(this._anyGetOptionalConflictCheckMethod.bind(this));
|
services.conflict.getOptionalConflictCheckMethod.addHandler(this._anyGetOptionalConflictCheckMethod.bind(this));
|
||||||
services.replication.handleProcessVirtualDocuments(this._anyModuleParsedReplicationResultItem.bind(this));
|
services.replication.processVirtualDocument.addHandler(this._anyModuleParsedReplicationResultItem.bind(this));
|
||||||
services.setting.handleOnRealiseSetting(this._everyRealizeSettingSyncMode.bind(this));
|
services.setting.onRealiseSetting.addHandler(this._everyRealizeSettingSyncMode.bind(this));
|
||||||
services.appLifecycle.handleOnResuming(this._everyOnResumeProcess.bind(this));
|
services.appLifecycle.onResuming.addHandler(this._everyOnResumeProcess.bind(this));
|
||||||
services.appLifecycle.handleOnResumed(this._everyAfterResumeProcess.bind(this));
|
services.appLifecycle.onResumed.addHandler(this._everyAfterResumeProcess.bind(this));
|
||||||
services.replication.handleBeforeReplicate(this._everyBeforeReplicate.bind(this));
|
services.replication.onBeforeReplicate.addHandler(this._everyBeforeReplicate.bind(this));
|
||||||
services.databaseEvents.handleDatabaseInitialised(this._everyOnDatabaseInitialized.bind(this));
|
services.databaseEvents.onDatabaseInitialised.addHandler(this._everyOnDatabaseInitialized.bind(this));
|
||||||
services.setting.handleSuspendExtraSync(this._allSuspendExtraSync.bind(this));
|
services.setting.suspendExtraSync.addHandler(this._allSuspendExtraSync.bind(this));
|
||||||
services.setting.handleSuggestOptionalFeatures(this._allAskUsingOptionalSyncFeature.bind(this));
|
services.setting.suggestOptionalFeatures.addHandler(this._allAskUsingOptionalSyncFeature.bind(this));
|
||||||
services.setting.handleEnableOptionalFeature(this._allConfigureOptionalSyncFeature.bind(this));
|
services.setting.enableOptionalFeature.addHandler(this._allConfigureOptionalSyncFeature.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1914,16 +1914,16 @@ ${messageFetch}${messageOverwrite}${messageMerge}
|
|||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services) {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services) {
|
||||||
// No longer needed on initialisation
|
// No longer needed on initialisation
|
||||||
// services.databaseEvents.handleOnDatabaseInitialisation(this._everyOnInitializeDatabase.bind(this));
|
// services.databaseEvents.handleOnDatabaseInitialisation(this._everyOnInitializeDatabase.bind(this));
|
||||||
services.appLifecycle.handleOnSettingLoaded(this._everyOnloadAfterLoadSettings.bind(this));
|
services.appLifecycle.onSettingLoaded.addHandler(this._everyOnloadAfterLoadSettings.bind(this));
|
||||||
services.fileProcessing.handleOptionalFileEvent(this._anyProcessOptionalFileEvent.bind(this));
|
services.fileProcessing.processOptionalFileEvent.addHandler(this._anyProcessOptionalFileEvent.bind(this));
|
||||||
services.conflict.handleGetOptionalConflictCheckMethod(this._anyGetOptionalConflictCheckMethod.bind(this));
|
services.conflict.getOptionalConflictCheckMethod.addHandler(this._anyGetOptionalConflictCheckMethod.bind(this));
|
||||||
services.replication.handleProcessOptionalSynchroniseResult(this._anyProcessOptionalSyncFiles.bind(this));
|
services.replication.processOptionalSynchroniseResult.addHandler(this._anyProcessOptionalSyncFiles.bind(this));
|
||||||
services.setting.handleOnRealiseSetting(this._everyRealizeSettingSyncMode.bind(this));
|
services.setting.onRealiseSetting.addHandler(this._everyRealizeSettingSyncMode.bind(this));
|
||||||
services.appLifecycle.handleOnResuming(this._everyOnResumeProcess.bind(this));
|
services.appLifecycle.onResuming.addHandler(this._everyOnResumeProcess.bind(this));
|
||||||
services.replication.handleBeforeReplicate(this._everyBeforeReplicate.bind(this));
|
services.replication.onBeforeReplicate.addHandler(this._everyBeforeReplicate.bind(this));
|
||||||
services.databaseEvents.handleDatabaseInitialised(this._everyOnDatabaseInitialized.bind(this));
|
services.databaseEvents.onDatabaseInitialised.addHandler(this._everyOnDatabaseInitialized.bind(this));
|
||||||
services.setting.handleSuspendExtraSync(this._allSuspendExtraSync.bind(this));
|
services.setting.suspendExtraSync.addHandler(this._allSuspendExtraSync.bind(this));
|
||||||
services.setting.handleSuggestOptionalFeatures(this._allAskUsingOptionalSyncFeature.bind(this));
|
services.setting.suggestOptionalFeatures.addHandler(this._allAskUsingOptionalSyncFeature.bind(this));
|
||||||
services.setting.handleEnableOptionalFeature(this._allConfigureOptionalSyncFeature.bind(this));
|
services.setting.enableOptionalFeature.addHandler(this._allConfigureOptionalSyncFeature.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -271,11 +271,11 @@ export class P2PReplicator extends LiveSyncCommands implements P2PReplicatorBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
override onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
override onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.replicator.handleGetNewReplicator(this._anyNewReplicator.bind(this));
|
services.replicator.getNewReplicator.addHandler(this._anyNewReplicator.bind(this));
|
||||||
services.databaseEvents.handleOnDatabaseInitialisation(this._everyOnInitializeDatabase.bind(this));
|
services.databaseEvents.onDatabaseInitialisation.addHandler(this._everyOnInitializeDatabase.bind(this));
|
||||||
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
|
||||||
services.appLifecycle.handleOnSuspending(this._everyBeforeSuspendProcess.bind(this));
|
services.appLifecycle.onSuspending.addHandler(this._everyBeforeSuspendProcess.bind(this));
|
||||||
services.appLifecycle.handleOnResumed(this._everyAfterResumeProcess.bind(this));
|
services.appLifecycle.onResumed.addHandler(this._everyAfterResumeProcess.bind(this));
|
||||||
services.setting.handleSuspendExtraSync(this._allSuspendExtraSync.bind(this));
|
services.setting.suspendExtraSync.addHandler(this._allSuspendExtraSync.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
src/lib
2
src/lib
Submodule src/lib updated: 8fbd310e7f...cd32d3d326
@@ -23,7 +23,6 @@ import type { IObsidianModule } from "./modules/AbstractObsidianModule.ts";
|
|||||||
|
|
||||||
import { ModuleDev } from "./modules/extras/ModuleDev.ts";
|
import { ModuleDev } from "./modules/extras/ModuleDev.ts";
|
||||||
import { ModuleFileAccessObsidian } from "./modules/coreObsidian/ModuleFileAccessObsidian.ts";
|
import { ModuleFileAccessObsidian } from "./modules/coreObsidian/ModuleFileAccessObsidian.ts";
|
||||||
import { ModuleInputUIObsidian } from "./modules/coreObsidian/ModuleInputUIObsidian.ts";
|
|
||||||
import { ModuleMigration } from "./modules/essential/ModuleMigration.ts";
|
import { ModuleMigration } from "./modules/essential/ModuleMigration.ts";
|
||||||
|
|
||||||
import { ModuleCheckRemoteSize } from "./modules/essentialObsidian/ModuleCheckRemoteSize.ts";
|
import { ModuleCheckRemoteSize } from "./modules/essentialObsidian/ModuleCheckRemoteSize.ts";
|
||||||
@@ -70,6 +69,7 @@ import { P2PReplicator } from "./features/P2PSync/CmdP2PReplicator.ts";
|
|||||||
import type { LiveSyncManagers } from "./lib/src/managers/LiveSyncManagers.ts";
|
import type { LiveSyncManagers } from "./lib/src/managers/LiveSyncManagers.ts";
|
||||||
import { ObsidianServiceHub } from "./modules/services/ObsidianServices.ts";
|
import { ObsidianServiceHub } from "./modules/services/ObsidianServices.ts";
|
||||||
import type { InjectableServiceHub } from "./lib/src/services/InjectableServices.ts";
|
import type { InjectableServiceHub } from "./lib/src/services/InjectableServices.ts";
|
||||||
|
import type { ServiceContext } from "./lib/src/services/ServiceHub.ts";
|
||||||
|
|
||||||
export default class ObsidianLiveSyncPlugin
|
export default class ObsidianLiveSyncPlugin
|
||||||
extends Plugin
|
extends Plugin
|
||||||
@@ -83,7 +83,7 @@ export default class ObsidianLiveSyncPlugin
|
|||||||
/**
|
/**
|
||||||
* The service hub for managing all services.
|
* The service hub for managing all services.
|
||||||
*/
|
*/
|
||||||
_services: InjectableServiceHub = new ObsidianServiceHub(this);
|
_services: InjectableServiceHub<ServiceContext> = new ObsidianServiceHub(this);
|
||||||
get services() {
|
get services() {
|
||||||
return this._services;
|
return this._services;
|
||||||
}
|
}
|
||||||
@@ -136,7 +136,6 @@ export default class ObsidianLiveSyncPlugin
|
|||||||
new ModuleObsidianSettingsAsMarkdown(this, this),
|
new ModuleObsidianSettingsAsMarkdown(this, this),
|
||||||
new ModuleObsidianSettingDialogue(this, this),
|
new ModuleObsidianSettingDialogue(this, this),
|
||||||
new ModuleLog(this, this),
|
new ModuleLog(this, this),
|
||||||
new ModuleInputUIObsidian(this, this),
|
|
||||||
new ModuleObsidianMenu(this, this),
|
new ModuleObsidianMenu(this, this),
|
||||||
new ModuleRebuilder(this),
|
new ModuleRebuilder(this),
|
||||||
new ModuleSetupObsidian(this, this),
|
new ModuleSetupObsidian(this, this),
|
||||||
@@ -165,7 +164,9 @@ export default class ObsidianLiveSyncPlugin
|
|||||||
managers!: LiveSyncManagers;
|
managers!: LiveSyncManagers;
|
||||||
simpleStore!: SimpleStore<CheckPointInfo>;
|
simpleStore!: SimpleStore<CheckPointInfo>;
|
||||||
replicator!: LiveSyncAbstractReplicator;
|
replicator!: LiveSyncAbstractReplicator;
|
||||||
confirm!: Confirm;
|
get confirm(): Confirm {
|
||||||
|
return this.services.UI.confirm;
|
||||||
|
}
|
||||||
storageAccess!: StorageAccess;
|
storageAccess!: StorageAccess;
|
||||||
databaseFileAccess!: DatabaseFileAccess;
|
databaseFileAccess!: DatabaseFileAccess;
|
||||||
fileHandler!: ModuleFileHandler;
|
fileHandler!: ModuleFileHandler;
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ export class ModuleDatabaseFileAccess extends AbstractModule implements Database
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.appLifecycle.handleOnLoaded(this._everyOnload.bind(this));
|
services.appLifecycle.onLoaded.addHandler(this._everyOnload.bind(this));
|
||||||
services.test.handleTest(this._everyModuleTest.bind(this));
|
services.test.test.addHandler(this._everyModuleTest.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -436,8 +436,8 @@ export class ModuleFileHandler extends AbstractModule {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
|
||||||
services.fileProcessing.handleProcessFileEvent(this._anyHandlerProcessesFileEvent.bind(this));
|
services.fileProcessing.processFileEvent.addHandler(this._anyHandlerProcessesFileEvent.bind(this));
|
||||||
services.replication.handleProcessSynchroniseResult(this._anyProcessReplicatedDoc.bind(this));
|
services.replication.processSynchroniseResult.addHandler(this._anyProcessReplicatedDoc.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ export class ModuleLocalDatabaseObsidian extends AbstractModule {
|
|||||||
return this.localDatabase != null && this.localDatabase.isReady;
|
return this.localDatabase != null && this.localDatabase.isReady;
|
||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.database.handleIsDatabaseReady(this._isDatabaseReady.bind(this));
|
services.database.isDatabaseReady.setHandler(this._isDatabaseReady.bind(this));
|
||||||
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
|
||||||
services.database.handleOpenDatabase(this._openDatabase.bind(this));
|
services.database.openDatabase.setHandler(this._openDatabase.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ export class ModulePeriodicProcess extends AbstractModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.appLifecycle.handleOnUnload(this._allOnUnload.bind(this));
|
services.appLifecycle.onUnload.addHandler(this._allOnUnload.bind(this));
|
||||||
services.setting.handleBeforeRealiseSetting(this._everyBeforeRealizeSetting.bind(this));
|
services.setting.onBeforeRealiseSetting.addHandler(this._everyBeforeRealizeSetting.bind(this));
|
||||||
services.setting.handleSettingRealised(this._everyAfterRealizeSetting.bind(this));
|
services.setting.onSettingRealised.addHandler(this._everyAfterRealizeSetting.bind(this));
|
||||||
services.appLifecycle.handleOnSuspending(this._everyBeforeSuspendProcess.bind(this));
|
services.appLifecycle.onSuspending.addHandler(this._everyBeforeSuspendProcess.bind(this));
|
||||||
services.appLifecycle.handleOnResumed(this._everyAfterResumeProcess.bind(this));
|
services.appLifecycle.onResumed.addHandler(this._everyAfterResumeProcess.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,6 @@ export class ModulePouchDB extends AbstractModule {
|
|||||||
return new PouchDB(name, optionPass);
|
return new PouchDB(name, optionPass);
|
||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.database.handleCreatePouchDBInstance(this._createPouchDBInstance.bind(this));
|
services.database.createPouchDBInstance.setHandler(this._createPouchDBInstance.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,6 +194,32 @@ Please enable them from the settings screen after setup is complete.`,
|
|||||||
// await this.askUseNewAdapter();
|
// await this.askUseNewAdapter();
|
||||||
this.core.settings.isConfigured = true;
|
this.core.settings.isConfigured = true;
|
||||||
this.core.settings.notifyThresholdOfRemoteStorageSize = DEFAULT_SETTINGS.notifyThresholdOfRemoteStorageSize;
|
this.core.settings.notifyThresholdOfRemoteStorageSize = DEFAULT_SETTINGS.notifyThresholdOfRemoteStorageSize;
|
||||||
|
if (this.core.settings.maxMTimeForReflectEvents > 0) {
|
||||||
|
const date = new Date(this.core.settings.maxMTimeForReflectEvents);
|
||||||
|
|
||||||
|
const ask = `Your settings restrict file reflection times to no later than ${date}.
|
||||||
|
|
||||||
|
**This is a recovery configuration.**
|
||||||
|
|
||||||
|
This operation should only be performed on an empty vault.
|
||||||
|
Are you sure you wish to proceed?`;
|
||||||
|
const PROCEED = "I understand, proceed";
|
||||||
|
const CANCEL = "Cancel operation";
|
||||||
|
const CLEARANDPROCEED = "Clear restriction and proceed";
|
||||||
|
const choices = [PROCEED, CLEARANDPROCEED, CANCEL] as const;
|
||||||
|
const ret = await this.core.confirm.askSelectStringDialogue(ask, choices, {
|
||||||
|
title: "Confirm restricted fetch",
|
||||||
|
defaultAction: CANCEL,
|
||||||
|
timeout: 0,
|
||||||
|
});
|
||||||
|
if (ret == CLEARANDPROCEED) {
|
||||||
|
this.core.settings.maxMTimeForReflectEvents = 0;
|
||||||
|
await this.core.saveSettings();
|
||||||
|
}
|
||||||
|
if (ret == CANCEL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
await this.suspendReflectingDatabase();
|
await this.suspendReflectingDatabase();
|
||||||
await this.services.setting.realiseSetting();
|
await this.services.setting.realiseSetting();
|
||||||
await this.resetLocalDatabase();
|
await this.resetLocalDatabase();
|
||||||
@@ -275,10 +301,10 @@ Please enable them from the settings screen after setup is complete.`,
|
|||||||
this._log(`Done!`, LOG_LEVEL_NOTICE, "resolveAllConflictedFilesByNewerOnes");
|
this._log(`Done!`, LOG_LEVEL_NOTICE, "resolveAllConflictedFilesByNewerOnes");
|
||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.appLifecycle.handleOnLoaded(this._everyOnload.bind(this));
|
services.appLifecycle.onLoaded.addHandler(this._everyOnload.bind(this));
|
||||||
services.database.handleResetDatabase(this._resetLocalDatabase.bind(this));
|
services.database.resetDatabase.setHandler(this._resetLocalDatabase.bind(this));
|
||||||
services.remote.handleTryResetDatabase(this._tryResetRemoteDatabase.bind(this));
|
services.remote.tryResetDatabase.setHandler(this._tryResetRemoteDatabase.bind(this));
|
||||||
services.remote.handleTryCreateDatabase(this._tryCreateRemoteDatabase.bind(this));
|
services.remote.tryCreateDatabase.setHandler(this._tryCreateRemoteDatabase.bind(this));
|
||||||
services.setting.handleSuspendAllSync(this._allSuspendAllSync.bind(this));
|
services.setting.suspendAllSync.addHandler(this._allSuspendAllSync.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -329,19 +329,19 @@ Even if you choose to clean up, you will see this option again if you exit Obsid
|
|||||||
}
|
}
|
||||||
|
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.replicator.handleGetActiveReplicator(this._getReplicator.bind(this));
|
services.replicator.getActiveReplicator.setHandler(this._getReplicator.bind(this));
|
||||||
services.databaseEvents.handleOnDatabaseInitialisation(this._everyOnInitializeDatabase.bind(this));
|
services.databaseEvents.onDatabaseInitialisation.addHandler(this._everyOnInitializeDatabase.bind(this));
|
||||||
services.databaseEvents.handleDatabaseInitialised(this._everyOnDatabaseInitialized.bind(this));
|
services.databaseEvents.onDatabaseInitialised.addHandler(this._everyOnDatabaseInitialized.bind(this));
|
||||||
services.databaseEvents.handleOnResetDatabase(this._everyOnResetDatabase.bind(this));
|
services.databaseEvents.onResetDatabase.addHandler(this._everyOnResetDatabase.bind(this));
|
||||||
services.appLifecycle.handleOnSettingLoaded(this._everyOnloadAfterLoadSettings.bind(this));
|
services.appLifecycle.onSettingLoaded.addHandler(this._everyOnloadAfterLoadSettings.bind(this));
|
||||||
services.replication.handleParseSynchroniseResult(this._parseReplicationResult.bind(this));
|
services.replication.parseSynchroniseResult.setHandler(this._parseReplicationResult.bind(this));
|
||||||
services.appLifecycle.handleOnSuspending(this._everyBeforeSuspendProcess.bind(this));
|
services.appLifecycle.onSuspending.addHandler(this._everyBeforeSuspendProcess.bind(this));
|
||||||
services.replication.handleBeforeReplicate(this._everyBeforeReplicate.bind(this));
|
services.replication.onBeforeReplicate.addHandler(this._everyBeforeReplicate.bind(this));
|
||||||
services.replication.handleIsReplicationReady(this._canReplicate.bind(this));
|
services.replication.isReplicationReady.setHandler(this._canReplicate.bind(this));
|
||||||
services.replication.handleReplicate(this._replicate.bind(this));
|
services.replication.replicate.setHandler(this._replicate.bind(this));
|
||||||
services.replication.handleReplicateByEvent(this._replicateByEvent.bind(this));
|
services.replication.replicateByEvent.setHandler(this._replicateByEvent.bind(this));
|
||||||
services.remote.handleReplicateAllToRemote(this._replicateAllToServer.bind(this));
|
services.remote.replicateAllToRemote.setHandler(this._replicateAllToServer.bind(this));
|
||||||
services.remote.handleReplicateAllFromRemote(this._replicateAllFromServer.bind(this));
|
services.remote.replicateAllFromRemote.setHandler(this._replicateAllFromServer.bind(this));
|
||||||
services.appLifecycle.reportUnresolvedMessages(this._reportUnresolvedMessages.bind(this));
|
services.appLifecycle.getUnresolvedMessages.addHandler(this._reportUnresolvedMessages.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export class ModuleReplicatorCouchDB extends AbstractModule {
|
|||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.replicator.handleGetNewReplicator(this._anyNewReplicator.bind(this));
|
services.replicator.getNewReplicator.addHandler(this._anyNewReplicator.bind(this));
|
||||||
services.appLifecycle.handleOnResumed(this._everyAfterResumeProcess.bind(this));
|
services.appLifecycle.onResumed.addHandler(this._everyAfterResumeProcess.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,6 @@ export class ModuleReplicatorMinIO extends AbstractModule {
|
|||||||
return Promise.resolve(false);
|
return Promise.resolve(false);
|
||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.replicator.handleGetNewReplicator(this._anyNewReplicator.bind(this));
|
services.replicator.getNewReplicator.addHandler(this._anyNewReplicator.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export class ModuleReplicatorP2P extends AbstractModule {
|
|||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.replicator.handleGetNewReplicator(this._anyNewReplicator.bind(this));
|
services.replicator.getNewReplicator.addHandler(this._anyNewReplicator.bind(this));
|
||||||
services.appLifecycle.handleOnResumed(this._everyAfterResumeProcess.bind(this));
|
services.appLifecycle.onResumed.addHandler(this._everyAfterResumeProcess.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,12 +174,12 @@ export class ModuleTargetFilter extends AbstractModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.vault.handleMarkFileListPossiblyChanged(this._markFileListPossiblyChanged.bind(this));
|
services.vault.markFileListPossiblyChanged.setHandler(this._markFileListPossiblyChanged.bind(this));
|
||||||
services.path.handleId2Path(this._id2path.bind(this));
|
services.path.id2path.setHandler(this._id2path.bind(this));
|
||||||
services.path.handlePath2Id(this._path2id.bind(this));
|
services.path.path2id.setHandler(this._path2id.bind(this));
|
||||||
services.appLifecycle.handleOnLoaded(this._everyOnload.bind(this));
|
services.appLifecycle.onLoaded.addHandler(this._everyOnload.bind(this));
|
||||||
services.vault.handleIsFileSizeTooLarge(this._isFileSizeExceeded.bind(this));
|
services.vault.isFileSizeTooLarge.setHandler(this._isFileSizeExceeded.bind(this));
|
||||||
services.vault.handleIsIgnoredByIgnoreFile(this._isIgnoredByIgnoreFiles.bind(this));
|
services.vault.isIgnoredByIgnoreFile.setHandler(this._isIgnoredByIgnoreFiles.bind(this));
|
||||||
services.vault.handleIsTargetFile(this._isTargetFile.bind(this));
|
services.vault.isTargetFile.setHandler(this._isTargetFile.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -318,6 +318,20 @@ export class ReplicateResultProcessor {
|
|||||||
*/
|
*/
|
||||||
async parseDocumentChange(change: PouchDB.Core.ExistingDocument<EntryDoc>) {
|
async parseDocumentChange(change: PouchDB.Core.ExistingDocument<EntryDoc>) {
|
||||||
try {
|
try {
|
||||||
|
if (isAnyNote(change)) {
|
||||||
|
const docMtime = change.mtime ?? 0;
|
||||||
|
const maxMTime = this.replicator.settings.maxMTimeForReflectEvents;
|
||||||
|
if (maxMTime > 0 && docMtime > maxMTime) {
|
||||||
|
const docPath = getPath(change);
|
||||||
|
this.log(
|
||||||
|
`Processing ${docPath} has been skipped due to modification time (${new Date(
|
||||||
|
docMtime * 1000
|
||||||
|
).toISOString()}) exceeding the limit`,
|
||||||
|
LOG_LEVEL_INFO
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
// If the document is a virtual document, process it in the virtual document processor.
|
// If the document is a virtual document, process it in the virtual document processor.
|
||||||
if (await this.services.replication.processVirtualDocument(change)) return;
|
if (await this.services.replication.processVirtualDocument(change)) return;
|
||||||
// If the document is version info, check compatibility and return.
|
// If the document is version info, check compatibility and return.
|
||||||
|
|||||||
@@ -75,8 +75,8 @@ export class ModuleConflictChecker extends AbstractModule {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
||||||
services.conflict.handleQueueCheckForIfOpen(this._queueConflictCheckIfOpen.bind(this));
|
services.conflict.queueCheckForIfOpen.setHandler(this._queueConflictCheckIfOpen.bind(this));
|
||||||
services.conflict.handleQueueCheckFor(this._queueConflictCheck.bind(this));
|
services.conflict.queueCheckFor.setHandler(this._queueConflictCheck.bind(this));
|
||||||
services.conflict.handleEnsureAllProcessed(this._waitForAllConflictProcessed.bind(this));
|
services.conflict.ensureAllProcessed.setHandler(this._waitForAllConflictProcessed.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -213,8 +213,8 @@ export class ModuleConflictResolver extends AbstractModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
||||||
services.conflict.handleResolveByDeletingRevision(this._resolveConflictByDeletingRev.bind(this));
|
services.conflict.resolveByDeletingRevision.setHandler(this._resolveConflictByDeletingRev.bind(this));
|
||||||
services.conflict.handleResolve(this._resolveConflict.bind(this));
|
services.conflict.resolve.setHandler(this._resolveConflict.bind(this));
|
||||||
services.conflict.handleResolveByNewest(this._anyResolveConflictByNewest.bind(this));
|
services.conflict.resolveByNewest.setHandler(this._anyResolveConflictByNewest.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -322,6 +322,6 @@ export class ModuleRedFlag extends AbstractModule {
|
|||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
super.onBindFunction(core, services);
|
super.onBindFunction(core, services);
|
||||||
services.appLifecycle.handleLayoutReady(this._everyOnLayoutReady.bind(this));
|
services.appLifecycle.onLayoutReady.addHandler(this._everyOnLayoutReady.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ export class ModuleRemoteGovernor extends AbstractModule {
|
|||||||
return await this.core.replicator.markRemoteResolved(this.settings);
|
return await this.core.replicator.markRemoteResolved(this.settings);
|
||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
||||||
services.remote.handleMarkLocked(this._markRemoteLocked.bind(this));
|
services.remote.markLocked.setHandler(this._markRemoteLocked.bind(this));
|
||||||
services.remote.handleMarkUnlocked(this._markRemoteUnlocked.bind(this));
|
services.remote.markUnlocked.setHandler(this._markRemoteUnlocked.bind(this));
|
||||||
services.remote.handleMarkResolved(this._markRemoteResolved.bind(this));
|
services.remote.markResolved.setHandler(this._markRemoteResolved.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -285,11 +285,15 @@ export class ModuleResolvingMismatchedTweaks extends AbstractModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
||||||
services.tweakValue.handleFetchRemotePreferred(this._fetchRemotePreferredTweakValues.bind(this));
|
services.tweakValue.fetchRemotePreferred.setHandler(this._fetchRemotePreferredTweakValues.bind(this));
|
||||||
services.tweakValue.handleCheckAndAskResolvingMismatched(this._checkAndAskResolvingMismatchedTweaks.bind(this));
|
services.tweakValue.checkAndAskResolvingMismatched.setHandler(
|
||||||
services.tweakValue.handleAskResolvingMismatched(this._askResolvingMismatchedTweaks.bind(this));
|
this._checkAndAskResolvingMismatchedTweaks.bind(this)
|
||||||
services.tweakValue.handleCheckAndAskUseRemoteConfiguration(this._checkAndAskUseRemoteConfiguration.bind(this));
|
);
|
||||||
services.tweakValue.handleAskUseRemoteConfiguration(this._askUseRemoteConfiguration.bind(this));
|
services.tweakValue.askResolvingMismatched.setHandler(this._askResolvingMismatchedTweaks.bind(this));
|
||||||
services.replication.handleCheckConnectionFailure(this._anyAfterConnectCheckFailed.bind(this));
|
services.tweakValue.checkAndAskUseRemoteConfiguration.setHandler(
|
||||||
|
this._checkAndAskUseRemoteConfiguration.bind(this)
|
||||||
|
);
|
||||||
|
services.tweakValue.askUseRemoteConfiguration.setHandler(this._askUseRemoteConfiguration.bind(this));
|
||||||
|
services.replication.checkConnectionFailure.addHandler(this._anyAfterConnectCheckFailed.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -386,11 +386,11 @@ export class ModuleFileAccessObsidian extends AbstractObsidianModule implements
|
|||||||
super(plugin, core);
|
super(plugin, core);
|
||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
||||||
services.vault.handleIsStorageInsensitive(this._isStorageInsensitive.bind(this));
|
services.vault.isStorageInsensitive.setHandler(this._isStorageInsensitive.bind(this));
|
||||||
services.setting.handleShouldCheckCaseInsensitively(this._shouldCheckCaseInsensitive.bind(this));
|
services.setting.shouldCheckCaseInsensitively.setHandler(this._shouldCheckCaseInsensitive.bind(this));
|
||||||
services.appLifecycle.handleFirstInitialise(this._everyOnFirstInitialize.bind(this));
|
services.appLifecycle.onFirstInitialise.addHandler(this._everyOnFirstInitialize.bind(this));
|
||||||
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
|
||||||
services.appLifecycle.handleOnLoaded(this._everyOnload.bind(this));
|
services.appLifecycle.onLoaded.addHandler(this._everyOnload.bind(this));
|
||||||
services.fileProcessing.handleCommitPendingFileEvents(this._everyCommitPendingFileEvent.bind(this));
|
services.fileProcessing.commitPendingFileEvents.addHandler(this._everyCommitPendingFileEvent.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,118 +0,0 @@
|
|||||||
// ModuleInputUIObsidian.ts
|
|
||||||
import { AbstractObsidianModule } from "../AbstractObsidianModule.ts";
|
|
||||||
import { scheduleTask } from "octagonal-wheels/concurrency/task";
|
|
||||||
import { disposeMemoObject, memoIfNotExist, memoObject, retrieveMemoObject } from "../../common/utils.ts";
|
|
||||||
import {
|
|
||||||
askSelectString,
|
|
||||||
askString,
|
|
||||||
askYesNo,
|
|
||||||
confirmWithMessage,
|
|
||||||
confirmWithMessageWithWideButton,
|
|
||||||
} from "./UILib/dialogs.ts";
|
|
||||||
import { Notice } from "../../deps.ts";
|
|
||||||
import type { Confirm } from "../../lib/src/interfaces/Confirm.ts";
|
|
||||||
import { setConfirmInstance } from "../../lib/src/PlatformAPIs/obsidian/Confirm.ts";
|
|
||||||
import { $msg } from "src/lib/src/common/i18n.ts";
|
|
||||||
import type { LiveSyncCore } from "../../main.ts";
|
|
||||||
|
|
||||||
// This module cannot be a common module because it depends on Obsidian's API.
|
|
||||||
// However, we have to make compatible one for other platform.
|
|
||||||
|
|
||||||
export class ModuleInputUIObsidian extends AbstractObsidianModule implements Confirm {
|
|
||||||
private _everyOnload(): Promise<boolean> {
|
|
||||||
this.core.confirm = this;
|
|
||||||
setConfirmInstance(this);
|
|
||||||
return Promise.resolve(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
askYesNo(message: string): Promise<"yes" | "no"> {
|
|
||||||
return askYesNo(this.app, message);
|
|
||||||
}
|
|
||||||
askString(title: string, key: string, placeholder: string, isPassword: boolean = false): Promise<string | false> {
|
|
||||||
return askString(this.app, title, key, placeholder, isPassword);
|
|
||||||
}
|
|
||||||
|
|
||||||
async askYesNoDialog(
|
|
||||||
message: string,
|
|
||||||
opt: { title?: string; defaultOption?: "Yes" | "No"; timeout?: number } = { title: "Confirmation" }
|
|
||||||
): Promise<"yes" | "no"> {
|
|
||||||
const defaultTitle = $msg("moduleInputUIObsidian.defaultTitleConfirmation");
|
|
||||||
const yesLabel = $msg("moduleInputUIObsidian.optionYes");
|
|
||||||
const noLabel = $msg("moduleInputUIObsidian.optionNo");
|
|
||||||
const defaultOption = opt.defaultOption === "Yes" ? yesLabel : noLabel;
|
|
||||||
const ret = await confirmWithMessageWithWideButton(
|
|
||||||
this.plugin,
|
|
||||||
opt.title || defaultTitle,
|
|
||||||
message,
|
|
||||||
[yesLabel, noLabel],
|
|
||||||
defaultOption,
|
|
||||||
opt.timeout
|
|
||||||
);
|
|
||||||
return ret === yesLabel ? "yes" : "no";
|
|
||||||
}
|
|
||||||
|
|
||||||
askSelectString(message: string, items: string[]): Promise<string> {
|
|
||||||
return askSelectString(this.app, message, items);
|
|
||||||
}
|
|
||||||
|
|
||||||
askSelectStringDialogue<T extends readonly string[]>(
|
|
||||||
message: string,
|
|
||||||
buttons: T,
|
|
||||||
opt: { title?: string; defaultAction: T[number]; timeout?: number }
|
|
||||||
): Promise<T[number] | false> {
|
|
||||||
const defaultTitle = $msg("moduleInputUIObsidian.defaultTitleSelect");
|
|
||||||
return confirmWithMessageWithWideButton(
|
|
||||||
this.plugin,
|
|
||||||
opt.title || defaultTitle,
|
|
||||||
message,
|
|
||||||
buttons,
|
|
||||||
opt.defaultAction,
|
|
||||||
opt.timeout
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
askInPopup(key: string, dialogText: string, anchorCallback: (anchor: HTMLAnchorElement) => void) {
|
|
||||||
const fragment = createFragment((doc) => {
|
|
||||||
const [beforeText, afterText] = dialogText.split("{HERE}", 2);
|
|
||||||
doc.createEl("span", undefined, (a) => {
|
|
||||||
a.appendText(beforeText);
|
|
||||||
a.appendChild(
|
|
||||||
a.createEl("a", undefined, (anchor) => {
|
|
||||||
anchorCallback(anchor);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
a.appendText(afterText);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
const popupKey = "popup-" + key;
|
|
||||||
scheduleTask(popupKey, 1000, async () => {
|
|
||||||
const popup = await memoIfNotExist(popupKey, () => new Notice(fragment, 0));
|
|
||||||
const isShown = popup?.noticeEl?.isShown();
|
|
||||||
if (!isShown) {
|
|
||||||
memoObject(popupKey, new Notice(fragment, 0));
|
|
||||||
}
|
|
||||||
scheduleTask(popupKey + "-close", 20000, () => {
|
|
||||||
const popup = retrieveMemoObject<Notice>(popupKey);
|
|
||||||
if (!popup) return;
|
|
||||||
if (popup?.noticeEl?.isShown()) {
|
|
||||||
popup.hide();
|
|
||||||
}
|
|
||||||
disposeMemoObject(popupKey);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
confirmWithMessage(
|
|
||||||
title: string,
|
|
||||||
contentMd: string,
|
|
||||||
buttons: string[],
|
|
||||||
defaultAction: (typeof buttons)[number],
|
|
||||||
timeout?: number
|
|
||||||
): Promise<(typeof buttons)[number] | false> {
|
|
||||||
return confirmWithMessage(this.plugin, title, contentMd, buttons, defaultAction, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
|
||||||
services.appLifecycle.handleOnLoaded(this._everyOnload.bind(this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -243,6 +243,9 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
|||||||
async appendQueue(params: FileEvent[], ctx?: any) {
|
async appendQueue(params: FileEvent[], ctx?: any) {
|
||||||
if (!this.core.settings.isConfigured) return;
|
if (!this.core.settings.isConfigured) return;
|
||||||
if (this.core.settings.suspendFileWatching) return;
|
if (this.core.settings.suspendFileWatching) return;
|
||||||
|
if (this.core.settings.maxMTimeForReflectEvents > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.core.services.vault.markFileListPossiblyChanged();
|
this.core.services.vault.markFileListPossiblyChanged();
|
||||||
// Flag up to be reload
|
// Flag up to be reload
|
||||||
for (const param of params) {
|
for (const param of params) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { unique } from "octagonal-wheels/collection";
|
import { unique } from "octagonal-wheels/collection";
|
||||||
import { throttle } from "octagonal-wheels/function";
|
import { throttle } from "octagonal-wheels/function";
|
||||||
import { eventHub } from "../../common/events.ts";
|
import { EVENT_ON_UNRESOLVED_ERROR, eventHub } from "../../common/events.ts";
|
||||||
import { BASE_IS_NEW, compareFileFreshness, EVEN, getPath, isValidPath, TARGET_IS_NEW } from "../../common/utils.ts";
|
import { BASE_IS_NEW, compareFileFreshness, EVEN, getPath, isValidPath, TARGET_IS_NEW } from "../../common/utils.ts";
|
||||||
import {
|
import {
|
||||||
type FilePathWithPrefixLC,
|
type FilePathWithPrefixLC,
|
||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
LOG_LEVEL_INFO,
|
LOG_LEVEL_INFO,
|
||||||
LOG_LEVEL_DEBUG,
|
LOG_LEVEL_DEBUG,
|
||||||
type UXFileInfoStub,
|
type UXFileInfoStub,
|
||||||
|
type LOG_LEVEL,
|
||||||
} from "../../lib/src/common/types.ts";
|
} from "../../lib/src/common/types.ts";
|
||||||
import { isAnyNote } from "../../lib/src/common/utils.ts";
|
import { isAnyNote } from "../../lib/src/common/utils.ts";
|
||||||
import { stripAllPrefixes } from "../../lib/src/string_and_binary/path.ts";
|
import { stripAllPrefixes } from "../../lib/src/string_and_binary/path.ts";
|
||||||
@@ -21,30 +22,43 @@ import { withConcurrency } from "octagonal-wheels/iterable/map";
|
|||||||
import type { InjectableServiceHub } from "../../lib/src/services/InjectableServices.ts";
|
import type { InjectableServiceHub } from "../../lib/src/services/InjectableServices.ts";
|
||||||
import type { LiveSyncCore } from "../../main.ts";
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
export class ModuleInitializerFile extends AbstractModule {
|
export class ModuleInitializerFile extends AbstractModule {
|
||||||
|
private _detectedErrors = new Set<string>();
|
||||||
|
|
||||||
|
private logDetectedError(message: string, logLevel: LOG_LEVEL = LOG_LEVEL_INFO, key?: string) {
|
||||||
|
this._detectedErrors.add(message);
|
||||||
|
eventHub.emitEvent(EVENT_ON_UNRESOLVED_ERROR);
|
||||||
|
this._log(message, logLevel, key);
|
||||||
|
}
|
||||||
|
private resetDetectedError(message: string) {
|
||||||
|
eventHub.emitEvent(EVENT_ON_UNRESOLVED_ERROR);
|
||||||
|
this._detectedErrors.delete(message);
|
||||||
|
}
|
||||||
private async _performFullScan(showingNotice?: boolean, ignoreSuspending: boolean = false): Promise<boolean> {
|
private async _performFullScan(showingNotice?: boolean, ignoreSuspending: boolean = false): Promise<boolean> {
|
||||||
this._log("Opening the key-value database", LOG_LEVEL_VERBOSE);
|
this._log("Opening the key-value database", LOG_LEVEL_VERBOSE);
|
||||||
const isInitialized = (await this.core.kvDB.get<boolean>("initialized")) || false;
|
const isInitialized = (await this.core.kvDB.get<boolean>("initialized")) || false;
|
||||||
// synchronize all files between database and storage.
|
// synchronize all files between database and storage.
|
||||||
|
|
||||||
|
const ERR_NOT_CONFIGURED =
|
||||||
|
"LiveSync is not configured yet. Synchronising between the storage and the local database is now prevented.";
|
||||||
if (!this.settings.isConfigured) {
|
if (!this.settings.isConfigured) {
|
||||||
if (showingNotice) {
|
this.logDetectedError(ERR_NOT_CONFIGURED, showingNotice ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO, "syncAll");
|
||||||
this._log(
|
|
||||||
"LiveSync is not configured yet. Synchronising between the storage and the local database is now prevented.",
|
|
||||||
LOG_LEVEL_NOTICE,
|
|
||||||
"syncAll"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
this.resetDetectedError(ERR_NOT_CONFIGURED);
|
||||||
|
|
||||||
|
const ERR_SUSPENDING =
|
||||||
|
"Now suspending file watching. Synchronising between the storage and the local database is now prevented.";
|
||||||
if (!ignoreSuspending && this.settings.suspendFileWatching) {
|
if (!ignoreSuspending && this.settings.suspendFileWatching) {
|
||||||
if (showingNotice) {
|
this.logDetectedError(ERR_SUSPENDING, showingNotice ? LOG_LEVEL_NOTICE : LOG_LEVEL_INFO, "syncAll");
|
||||||
this._log(
|
|
||||||
"Now suspending file watching. Synchronising between the storage and the local database is now prevented.",
|
|
||||||
LOG_LEVEL_NOTICE,
|
|
||||||
"syncAll"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const MSG_IN_REMEDIATION = `Started in remediation Mode! (Max mtime for reflect events is set). Synchronising between the storage and the local database is now prevented.`;
|
||||||
|
this.resetDetectedError(ERR_SUSPENDING);
|
||||||
|
if (this.settings.maxMTimeForReflectEvents > 0) {
|
||||||
|
this.logDetectedError(MSG_IN_REMEDIATION, LOG_LEVEL_NOTICE, "syncAll");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.resetDetectedError(MSG_IN_REMEDIATION);
|
||||||
|
|
||||||
if (showingNotice) {
|
if (showingNotice) {
|
||||||
this._log("Initializing", LOG_LEVEL_NOTICE, "syncAll");
|
this._log("Initializing", LOG_LEVEL_NOTICE, "syncAll");
|
||||||
@@ -383,10 +397,12 @@ export class ModuleInitializerFile extends AbstractModule {
|
|||||||
if (this.localDatabase.isReady) {
|
if (this.localDatabase.isReady) {
|
||||||
await this.services.vault.scanVault(showingNotice, ignoreSuspending);
|
await this.services.vault.scanVault(showingNotice, ignoreSuspending);
|
||||||
}
|
}
|
||||||
|
const ERR_INITIALISATION_FAILED = `Initializing database has been failed on some module!`;
|
||||||
if (!(await this.services.databaseEvents.onDatabaseInitialised(showingNotice))) {
|
if (!(await this.services.databaseEvents.onDatabaseInitialised(showingNotice))) {
|
||||||
this._log(`Initializing database has been failed on some module!`, LOG_LEVEL_NOTICE);
|
this.logDetectedError(ERR_INITIALISATION_FAILED, LOG_LEVEL_NOTICE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
this.resetDetectedError(ERR_INITIALISATION_FAILED);
|
||||||
this.services.appLifecycle.markIsReady();
|
this.services.appLifecycle.markIsReady();
|
||||||
// run queued event once.
|
// run queued event once.
|
||||||
await this.services.fileProcessing.commitPendingFileEvents();
|
await this.services.fileProcessing.commitPendingFileEvents();
|
||||||
@@ -396,8 +412,12 @@ export class ModuleInitializerFile extends AbstractModule {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private _reportDetectedErrors(): Promise<string[]> {
|
||||||
|
return Promise.resolve(Array.from(this._detectedErrors));
|
||||||
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
||||||
services.databaseEvents.handleInitialiseDatabase(this._initializeDatabase.bind(this));
|
services.appLifecycle.getUnresolvedMessages.addHandler(this._reportDetectedErrors.bind(this));
|
||||||
services.vault.handleScanVault(this._performFullScan.bind(this));
|
services.databaseEvents.initialiseDatabase.setHandler(this._initializeDatabase.bind(this));
|
||||||
|
services.vault.scanVault.setHandler(this._performFullScan.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import type { LiveSyncLocalDB } from "../../lib/src/pouchdb/LiveSyncLocalDB.ts";
|
|||||||
import { LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
import { LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "octagonal-wheels/common/logger";
|
||||||
import { AbstractModule } from "../AbstractModule.ts";
|
import { AbstractModule } from "../AbstractModule.ts";
|
||||||
import type { LiveSyncCore } from "../../main.ts";
|
import type { LiveSyncCore } from "../../main.ts";
|
||||||
|
import type { SimpleStore } from "octagonal-wheels/databases/SimpleStoreBase";
|
||||||
|
|
||||||
export class ModuleKeyValueDB extends AbstractModule {
|
export class ModuleKeyValueDB extends AbstractModule {
|
||||||
async tryCloseKvDB() {
|
async tryCloseKvDB() {
|
||||||
@@ -76,7 +77,7 @@ export class ModuleKeyValueDB extends AbstractModule {
|
|||||||
.filter((e) => e.startsWith(prefix))
|
.filter((e) => e.startsWith(prefix))
|
||||||
.map((e) => e.substring(prefix.length));
|
.map((e) => e.substring(prefix.length));
|
||||||
},
|
},
|
||||||
};
|
} satisfies SimpleStore<T>;
|
||||||
}
|
}
|
||||||
_everyOnInitializeDatabase(db: LiveSyncLocalDB): Promise<boolean> {
|
_everyOnInitializeDatabase(db: LiveSyncLocalDB): Promise<boolean> {
|
||||||
return this.openKeyValueDB();
|
return this.openKeyValueDB();
|
||||||
@@ -100,11 +101,11 @@ export class ModuleKeyValueDB extends AbstractModule {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.databaseEvents.handleOnUnloadDatabase(this._onDBUnload.bind(this));
|
services.databaseEvents.onUnloadDatabase.addHandler(this._onDBUnload.bind(this));
|
||||||
services.databaseEvents.handleOnCloseDatabase(this._onDBClose.bind(this));
|
services.databaseEvents.onCloseDatabase.addHandler(this._onDBClose.bind(this));
|
||||||
services.databaseEvents.handleOnDatabaseInitialisation(this._everyOnInitializeDatabase.bind(this));
|
services.databaseEvents.onDatabaseInitialisation.addHandler(this._everyOnInitializeDatabase.bind(this));
|
||||||
services.databaseEvents.handleOnResetDatabase(this._everyOnResetDatabase.bind(this));
|
services.databaseEvents.onResetDatabase.addHandler(this._everyOnResetDatabase.bind(this));
|
||||||
services.database.handleOpenSimpleStore(this._getSimpleStore.bind(this));
|
services.database.openSimpleStore.setHandler(this._getSimpleStore.bind(this));
|
||||||
services.appLifecycle.handleOnSettingLoaded(this._everyOnloadAfterLoadSettings.bind(this));
|
services.appLifecycle.onSettingLoaded.addHandler(this._everyOnloadAfterLoadSettings.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -355,7 +355,7 @@ export class ModuleMigration extends AbstractModule {
|
|||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
super.onBindFunction(core, services);
|
super.onBindFunction(core, services);
|
||||||
services.appLifecycle.handleLayoutReady(this._everyOnLayoutReady.bind(this));
|
services.appLifecycle.onLayoutReady.addHandler(this._everyOnLayoutReady.bind(this));
|
||||||
services.appLifecycle.handleFirstInitialise(this._everyOnFirstInitialize.bind(this));
|
services.appLifecycle.onFirstInitialise.addHandler(this._everyOnFirstInitialize.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ export class ModuleCheckRemoteSize extends AbstractObsidianModule {
|
|||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.appLifecycle.handleOnScanningStartupIssues(this._allScanStat.bind(this));
|
services.appLifecycle.onScanningStartupIssues.addHandler(this._allScanStat.bind(this));
|
||||||
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -312,7 +312,7 @@ export class ModuleObsidianAPI extends AbstractObsidianModule {
|
|||||||
return `${"appId" in this.app ? this.app.appId : ""}`;
|
return `${"appId" in this.app ? this.app.appId : ""}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _reportUnresolvedMessages(): Promise<string[]> {
|
private _reportUnresolvedMessages(): Promise<(string | Error)[]> {
|
||||||
return Promise.resolve([...this._previousErrors]);
|
return Promise.resolve([...this._previousErrors]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,16 +330,16 @@ export class ModuleObsidianAPI extends AbstractObsidianModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services) {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services) {
|
||||||
services.API.handleGetCustomFetchHandler(this._customFetchHandler.bind(this));
|
services.API.getCustomFetchHandler.setHandler(this._customFetchHandler.bind(this));
|
||||||
services.API.handleIsLastPostFailedDueToPayloadSize(this._getLastPostFailedBySize.bind(this));
|
services.API.isLastPostFailedDueToPayloadSize.setHandler(this._getLastPostFailedBySize.bind(this));
|
||||||
services.remote.handleConnect(this._connectRemoteCouchDB.bind(this));
|
services.remote.connect.setHandler(this._connectRemoteCouchDB.bind(this));
|
||||||
services.API.handleIsMobile(this._isMobile.bind(this));
|
services.API.isMobile.setHandler(this._isMobile.bind(this));
|
||||||
services.vault.handleGetVaultName(this._getVaultName.bind(this));
|
services.vault.getVaultName.setHandler(this._getVaultName.bind(this));
|
||||||
services.vault.handleVaultName(this._vaultName.bind(this));
|
services.vault.vaultName.setHandler(this._vaultName.bind(this));
|
||||||
services.vault.handleGetActiveFilePath(this._getActiveFilePath.bind(this));
|
services.vault.getActiveFilePath.setHandler(this._getActiveFilePath.bind(this));
|
||||||
services.API.handleGetAppID(this._anyGetAppId.bind(this));
|
services.API.getAppID.setHandler(this._anyGetAppId.bind(this));
|
||||||
services.API.handleGetAppVersion(this._getAppVersion.bind(this));
|
services.API.getAppVersion.setHandler(this._getAppVersion.bind(this));
|
||||||
services.API.handleGetPluginVersion(this._getPluginVersion.bind(this));
|
services.API.getPluginVersion.setHandler(this._getPluginVersion.bind(this));
|
||||||
services.appLifecycle.reportUnresolvedMessages(this._reportUnresolvedMessages.bind(this));
|
services.appLifecycle.getUnresolvedMessages.addHandler(this._reportUnresolvedMessages.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -244,10 +244,10 @@ export class ModuleObsidianEvents extends AbstractObsidianModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.appLifecycle.handleLayoutReady(this._everyOnLayoutReady.bind(this));
|
services.appLifecycle.onLayoutReady.addHandler(this._everyOnLayoutReady.bind(this));
|
||||||
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
|
||||||
services.appLifecycle.handlePerformRestart(this._performRestart.bind(this));
|
services.appLifecycle.performRestart.setHandler(this._performRestart.bind(this));
|
||||||
services.appLifecycle.handleAskRestart(this._askReload.bind(this));
|
services.appLifecycle.askRestart.setHandler(this._askReload.bind(this));
|
||||||
services.appLifecycle.handleScheduleRestart(this._scheduleAppReload.bind(this));
|
services.appLifecycle.scheduleRestart.setHandler(this._scheduleAppReload.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,8 +131,8 @@ export class ModuleObsidianMenu extends AbstractObsidianModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
|
||||||
services.appLifecycle.handleOnLoaded(this._everyOnload.bind(this));
|
services.appLifecycle.onLoaded.addHandler(this._everyOnload.bind(this));
|
||||||
services.API.handleShowWindow(this._showView.bind(this));
|
services.API.showWindow.setHandler(this._showView.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export class ModuleExtraSyncObsidian extends AbstractObsidianModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.setting.handleGetDeviceAndVaultName(this._getDeviceAndVaultName.bind(this));
|
services.setting.getDeviceAndVaultName.setHandler(this._getDeviceAndVaultName.bind(this));
|
||||||
services.setting.handleSetDeviceAndVaultName(this._setDeviceAndVaultName.bind(this));
|
services.setting.setDeviceAndVaultName.setHandler(this._setDeviceAndVaultName.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -157,10 +157,10 @@ export class ModuleDev extends AbstractObsidianModule {
|
|||||||
return this.testDone();
|
return this.testDone();
|
||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.appLifecycle.handleLayoutReady(this._everyOnLayoutReady.bind(this));
|
services.appLifecycle.onLayoutReady.addHandler(this._everyOnLayoutReady.bind(this));
|
||||||
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
|
||||||
services.appLifecycle.handleOnSettingLoaded(this._everyOnloadAfterLoadSettings.bind(this));
|
services.appLifecycle.onSettingLoaded.addHandler(this._everyOnloadAfterLoadSettings.bind(this));
|
||||||
services.test.handleTest(this._everyModuleTest.bind(this));
|
services.test.test.addHandler(this._everyModuleTest.bind(this));
|
||||||
services.test.handleAddTestResult(this._addTestResult.bind(this));
|
services.test.addTestResult.setHandler(this._addTestResult.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -441,6 +441,6 @@ Line4:D`;
|
|||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
onBindFunction(core: typeof this.core, services: typeof core.services): void {
|
onBindFunction(core: typeof this.core, services: typeof core.services): void {
|
||||||
services.test.handleTestMultiDevice(this._everyModuleTestMultiDevice.bind(this));
|
services.test.testMultiDevice.addHandler(this._everyModuleTestMultiDevice.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -581,8 +581,8 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ`;
|
|||||||
return this.testDone();
|
return this.testDone();
|
||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.appLifecycle.handleOnSettingLoaded(this._everyOnloadAfterLoadSettings.bind(this));
|
services.appLifecycle.onSettingLoaded.addHandler(this._everyOnloadAfterLoadSettings.bind(this));
|
||||||
services.replication.handleBeforeReplicate(this._everyBeforeReplicate.bind(this));
|
services.replication.onBeforeReplicate.addHandler(this._everyBeforeReplicate.bind(this));
|
||||||
services.test.handleTestMultiDevice(this._everyModuleTestMultiDevice.bind(this));
|
services.test.testMultiDevice.addHandler(this._everyModuleTestMultiDevice.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,6 @@ export class ModuleObsidianGlobalHistory extends AbstractObsidianModule {
|
|||||||
void this.services.API.showWindow(VIEW_TYPE_GLOBAL_HISTORY);
|
void this.services.API.showWindow(VIEW_TYPE_GLOBAL_HISTORY);
|
||||||
}
|
}
|
||||||
onBindFunction(core: typeof this.core, services: typeof core.services): void {
|
onBindFunction(core: typeof this.core, services: typeof core.services): void {
|
||||||
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,8 +165,8 @@ export class ModuleInteractiveConflictResolver extends AbstractObsidianModule {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.appLifecycle.handleOnScanningStartupIssues(this._allScanStat.bind(this));
|
services.appLifecycle.onScanningStartupIssues.addHandler(this._allScanStat.bind(this));
|
||||||
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
|
||||||
services.conflict.handleResolveByUserInteraction(this._anyResolveConflictByUI.bind(this));
|
services.conflict.resolveByUserInteraction.addHandler(this._anyResolveConflictByUI.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -495,9 +495,9 @@ export class ModuleLog extends AbstractObsidianModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
|
||||||
services.appLifecycle.handleOnSettingLoaded(this._everyOnloadAfterLoadSettings.bind(this));
|
services.appLifecycle.onSettingLoaded.addHandler(this._everyOnloadAfterLoadSettings.bind(this));
|
||||||
services.appLifecycle.handleOnLoaded(this._everyOnload.bind(this));
|
services.appLifecycle.onLoaded.addHandler(this._everyOnload.bind(this));
|
||||||
services.appLifecycle.handleOnBeforeUnload(this._allStartOnUnload.bind(this));
|
services.appLifecycle.onBeforeUnload.addHandler(this._allStartOnUnload.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,6 @@ export class ModuleObsidianDocumentHistory extends AbstractObsidianModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
onBindFunction(core: typeof this.core, services: typeof core.services): void {
|
onBindFunction(core: typeof this.core, services: typeof core.services): void {
|
||||||
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -323,13 +323,13 @@ export class ModuleObsidianSettings extends AbstractObsidianModule {
|
|||||||
|
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
super.onBindFunction(core, services);
|
super.onBindFunction(core, services);
|
||||||
services.appLifecycle.handleLayoutReady(this._everyOnLayoutReady.bind(this));
|
services.appLifecycle.onLayoutReady.addHandler(this._everyOnLayoutReady.bind(this));
|
||||||
services.setting.handleClearUsedPassphrase(this._clearUsedPassphrase.bind(this));
|
services.setting.clearUsedPassphrase.setHandler(this._clearUsedPassphrase.bind(this));
|
||||||
services.setting.handleDecryptSettings(this._decryptSettings.bind(this));
|
services.setting.decryptSettings.setHandler(this._decryptSettings.bind(this));
|
||||||
services.setting.handleAdjustSettings(this._adjustSettings.bind(this));
|
services.setting.adjustSettings.setHandler(this._adjustSettings.bind(this));
|
||||||
services.setting.handleLoadSettings(this._loadSettings.bind(this));
|
services.setting.loadSettings.setHandler(this._loadSettings.bind(this));
|
||||||
services.setting.handleCurrentSettings(this._currentSettings.bind(this));
|
services.setting.currentSettings.setHandler(this._currentSettings.bind(this));
|
||||||
services.setting.handleSaveDeviceAndVaultName(this._saveDeviceAndVaultName.bind(this));
|
services.setting.saveDeviceAndVaultName.setHandler(this._saveDeviceAndVaultName.bind(this));
|
||||||
services.setting.handleSaveSettingData(this._saveSettingData.bind(this));
|
services.setting.saveSettingData.setHandler(this._saveSettingData.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,6 +243,6 @@ We can perform a command in this file.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
onBindFunction(core: typeof this.plugin, services: typeof core.services): void {
|
onBindFunction(core: typeof this.plugin, services: typeof core.services): void {
|
||||||
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,6 @@ export class ModuleObsidianSettingDialogue extends AbstractObsidianModule {
|
|||||||
return `${"appId" in this.app ? this.app.appId : ""}`;
|
return `${"appId" in this.app ? this.app.appId : ""}`;
|
||||||
}
|
}
|
||||||
onBindFunction(core: typeof this.plugin, services: typeof core.services): void {
|
onBindFunction(core: typeof this.plugin, services: typeof core.services): void {
|
||||||
services.appLifecycle.handleOnInitialise(this._everyOnloadStart.bind(this));
|
services.appLifecycle.onInitialise.addHandler(this._everyOnloadStart.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -195,6 +195,6 @@ export class ModuleSetupObsidian extends AbstractObsidianModule {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
onBindFunction(core: LiveSyncCore, services: typeof core.services): void {
|
||||||
services.appLifecycle.handleOnLoaded(this._everyOnload.bind(this));
|
services.appLifecycle.onLoaded.addHandler(this._everyOnload.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,7 +173,62 @@ export function panePatches(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElemen
|
|||||||
void addPanel(paneEl, "Compatibility (Trouble addressed)").then((paneEl) => {
|
void addPanel(paneEl, "Compatibility (Trouble addressed)").then((paneEl) => {
|
||||||
new Setting(paneEl).autoWireToggle("disableCheckingConfigMismatch");
|
new Setting(paneEl).autoWireToggle("disableCheckingConfigMismatch");
|
||||||
});
|
});
|
||||||
|
void addPanel(paneEl, "Remediation").then((paneEl) => {
|
||||||
|
let dateEl: HTMLSpanElement;
|
||||||
|
new Setting(paneEl)
|
||||||
|
.addText((text) => {
|
||||||
|
const updateDateText = () => {
|
||||||
|
if (this.editingSettings.maxMTimeForReflectEvents == 0) {
|
||||||
|
dateEl.textContent = `No limit configured`;
|
||||||
|
} else {
|
||||||
|
const date = new Date(this.editingSettings.maxMTimeForReflectEvents);
|
||||||
|
dateEl.textContent = `Limit: ${date.toLocaleString()} (${this.editingSettings.maxMTimeForReflectEvents})`;
|
||||||
|
}
|
||||||
|
this.requestUpdate();
|
||||||
|
};
|
||||||
|
text.inputEl.before((dateEl = document.createElement("span")));
|
||||||
|
text.inputEl.type = "datetime-local";
|
||||||
|
if (this.editingSettings.maxMTimeForReflectEvents > 0) {
|
||||||
|
const date = new Date(this.editingSettings.maxMTimeForReflectEvents);
|
||||||
|
const isoString = date.toISOString().slice(0, 16);
|
||||||
|
text.setValue(isoString);
|
||||||
|
} else {
|
||||||
|
text.setValue("");
|
||||||
|
}
|
||||||
|
text.onChange((value) => {
|
||||||
|
if (value == "") {
|
||||||
|
this.editingSettings.maxMTimeForReflectEvents = 0;
|
||||||
|
updateDateText();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const date = new Date(value);
|
||||||
|
if (!isNaN(date.getTime())) {
|
||||||
|
this.editingSettings.maxMTimeForReflectEvents = date.getTime();
|
||||||
|
}
|
||||||
|
updateDateText();
|
||||||
|
});
|
||||||
|
updateDateText();
|
||||||
|
return text;
|
||||||
|
})
|
||||||
|
.setAuto("maxMTimeForReflectEvents")
|
||||||
|
.addApplyButton(["maxMTimeForReflectEvents"]);
|
||||||
|
|
||||||
|
this.addOnSaved("maxMTimeForReflectEvents", async (key) => {
|
||||||
|
const buttons = ["Restart Now", "Later"] as const;
|
||||||
|
const reboot = await this.plugin.confirm.askSelectStringDialogue(
|
||||||
|
"Restarting Obsidian is strongly recommended. Until restart, some changes may not take effect, and display may be inconsistent. Are you sure to restart now?",
|
||||||
|
buttons,
|
||||||
|
{
|
||||||
|
title: "Remediation Setting Changed",
|
||||||
|
defaultAction: "Restart Now",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (reboot !== "Later") {
|
||||||
|
Logger("Remediation setting changed. Restarting Obsidian...", LOG_LEVEL_NOTICE);
|
||||||
|
this.services.appLifecycle.performRestart();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
void addPanel(paneEl, "Remote Database Tweak (In sunset)").then((paneEl) => {
|
void addPanel(paneEl, "Remote Database Tweak (In sunset)").then((paneEl) => {
|
||||||
// new Setting(paneEl).autoWireToggle("useEden").setClass("wizardHidden");
|
// new Setting(paneEl).autoWireToggle("useEden").setClass("wizardHidden");
|
||||||
// const onlyUsingEden = visibleOnly(() => this.isConfiguredAs("useEden", true));
|
// const onlyUsingEden = visibleOnly(() => this.isConfiguredAs("useEden", true));
|
||||||
|
|||||||
@@ -93,6 +93,9 @@
|
|||||||
keys: () => {
|
keys: () => {
|
||||||
return Promise.resolve(Array.from(map.keys()));
|
return Promise.resolve(Array.from(map.keys()));
|
||||||
},
|
},
|
||||||
|
get db() {
|
||||||
|
return Promise.resolve(this);
|
||||||
|
},
|
||||||
} as SimpleStore<any>;
|
} as SimpleStore<any>;
|
||||||
|
|
||||||
const dummyPouch = new PouchDB<EntryDoc>("dummy");
|
const dummyPouch = new PouchDB<EntryDoc>("dummy");
|
||||||
|
|||||||
@@ -208,17 +208,17 @@ export class ModuleLiveSyncMain extends AbstractModule {
|
|||||||
|
|
||||||
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
onBindFunction(core: LiveSyncCore, services: InjectableServiceHub): void {
|
||||||
super.onBindFunction(core, services);
|
super.onBindFunction(core, services);
|
||||||
services.appLifecycle.handleIsSuspended(this._isSuspended.bind(this));
|
services.appLifecycle.isSuspended.setHandler(this._isSuspended.bind(this));
|
||||||
services.appLifecycle.handleSetSuspended(this._setSuspended.bind(this));
|
services.appLifecycle.setSuspended.setHandler(this._setSuspended.bind(this));
|
||||||
services.appLifecycle.handleIsReady(this._isReady.bind(this));
|
services.appLifecycle.isReady.setHandler(this._isReady.bind(this));
|
||||||
services.appLifecycle.handleMarkIsReady(this._markIsReady.bind(this));
|
services.appLifecycle.markIsReady.setHandler(this._markIsReady.bind(this));
|
||||||
services.appLifecycle.handleResetIsReady(this._resetIsReady.bind(this));
|
services.appLifecycle.resetIsReady.setHandler(this._resetIsReady.bind(this));
|
||||||
services.appLifecycle.handleHasUnloaded(this._isUnloaded.bind(this));
|
services.appLifecycle.hasUnloaded.setHandler(this._isUnloaded.bind(this));
|
||||||
services.appLifecycle.handleIsReloadingScheduled(this._isReloadingScheduled.bind(this));
|
services.appLifecycle.isReloadingScheduled.setHandler(this._isReloadingScheduled.bind(this));
|
||||||
services.appLifecycle.handleOnReady(this._onLiveSyncReady.bind(this));
|
services.appLifecycle.onReady.addHandler(this._onLiveSyncReady.bind(this));
|
||||||
services.appLifecycle.handleOnWireUpEvents(this._wireUpEvents.bind(this));
|
services.appLifecycle.onWireUpEvents.addHandler(this._wireUpEvents.bind(this));
|
||||||
services.appLifecycle.handleOnLoad(this._onLiveSyncLoad.bind(this));
|
services.appLifecycle.onLoad.addHandler(this._onLiveSyncLoad.bind(this));
|
||||||
services.appLifecycle.handleOnAppUnload(this._onLiveSyncUnload.bind(this));
|
services.appLifecycle.onAppUnload.addHandler(this._onLiveSyncUnload.bind(this));
|
||||||
services.setting.handleRealiseSetting(this._realizeSettingSyncMode.bind(this));
|
services.setting.realiseSetting.setHandler(this._realizeSettingSyncMode.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
import { ServiceContext, type ServiceInstances } from "@/lib/src/services/ServiceHub.ts";
|
||||||
import {
|
import {
|
||||||
InjectableAPIService,
|
InjectableAPIService,
|
||||||
InjectableAppLifecycleService,
|
InjectableAppLifecycleService,
|
||||||
InjectableConflictService,
|
InjectableConflictService,
|
||||||
|
InjectableDatabaseEventService,
|
||||||
InjectableDatabaseService,
|
InjectableDatabaseService,
|
||||||
InjectableFileProcessingService,
|
InjectableFileProcessingService,
|
||||||
InjectablePathService,
|
InjectablePathService,
|
||||||
@@ -17,79 +19,96 @@ import { InjectableServiceHub } from "../../lib/src/services/InjectableServices.
|
|||||||
import { ConfigServiceBrowserCompat } from "../../lib/src/services/Services.ts";
|
import { ConfigServiceBrowserCompat } from "../../lib/src/services/Services.ts";
|
||||||
import type ObsidianLiveSyncPlugin from "../../main.ts";
|
import type ObsidianLiveSyncPlugin from "../../main.ts";
|
||||||
import { ObsidianUIService } from "./ObsidianUIService.ts";
|
import { ObsidianUIService } from "./ObsidianUIService.ts";
|
||||||
|
import type { App, Plugin } from "@/deps";
|
||||||
|
|
||||||
|
export class ObsidianServiceContext extends ServiceContext {
|
||||||
|
app: App;
|
||||||
|
plugin: Plugin;
|
||||||
|
liveSyncPlugin: ObsidianLiveSyncPlugin;
|
||||||
|
constructor(app: App, plugin: Plugin, liveSyncPlugin: ObsidianLiveSyncPlugin) {
|
||||||
|
super();
|
||||||
|
this.app = app;
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.liveSyncPlugin = liveSyncPlugin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// All Services will be migrated to be based on Plain Services, not Injectable Services.
|
// All Services will be migrated to be based on Plain Services, not Injectable Services.
|
||||||
// This is a migration step.
|
// This is a migration step.
|
||||||
|
|
||||||
export class ObsidianAPIService extends InjectableAPIService {
|
export class ObsidianAPIService extends InjectableAPIService<ObsidianServiceContext> {
|
||||||
getPlatform(): string {
|
getPlatform(): string {
|
||||||
return "obsidian";
|
return "obsidian";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class ObsidianPathService extends InjectablePathService {}
|
export class ObsidianPathService extends InjectablePathService<ObsidianServiceContext> {}
|
||||||
export class ObsidianDatabaseService extends InjectableDatabaseService {}
|
export class ObsidianDatabaseService extends InjectableDatabaseService<ObsidianServiceContext> {}
|
||||||
|
export class ObsidianDatabaseEventService extends InjectableDatabaseEventService<ObsidianServiceContext> {}
|
||||||
|
|
||||||
// InjectableReplicatorService
|
// InjectableReplicatorService
|
||||||
export class ObsidianReplicatorService extends InjectableReplicatorService {}
|
export class ObsidianReplicatorService extends InjectableReplicatorService<ObsidianServiceContext> {}
|
||||||
// InjectableFileProcessingService
|
// InjectableFileProcessingService
|
||||||
export class ObsidianFileProcessingService extends InjectableFileProcessingService {}
|
export class ObsidianFileProcessingService extends InjectableFileProcessingService<ObsidianServiceContext> {}
|
||||||
// InjectableReplicationService
|
// InjectableReplicationService
|
||||||
export class ObsidianReplicationService extends InjectableReplicationService {}
|
export class ObsidianReplicationService extends InjectableReplicationService<ObsidianServiceContext> {}
|
||||||
// InjectableRemoteService
|
// InjectableRemoteService
|
||||||
export class ObsidianRemoteService extends InjectableRemoteService {}
|
export class ObsidianRemoteService extends InjectableRemoteService<ObsidianServiceContext> {}
|
||||||
// InjectableConflictService
|
// InjectableConflictService
|
||||||
export class ObsidianConflictService extends InjectableConflictService {}
|
export class ObsidianConflictService extends InjectableConflictService<ObsidianServiceContext> {}
|
||||||
// InjectableAppLifecycleService
|
// InjectableAppLifecycleService
|
||||||
export class ObsidianAppLifecycleService extends InjectableAppLifecycleService {}
|
export class ObsidianAppLifecycleService extends InjectableAppLifecycleService<ObsidianServiceContext> {}
|
||||||
// InjectableSettingService
|
// InjectableSettingService
|
||||||
export class ObsidianSettingService extends InjectableSettingService {}
|
export class ObsidianSettingService extends InjectableSettingService<ObsidianServiceContext> {}
|
||||||
// InjectableTweakValueService
|
// InjectableTweakValueService
|
||||||
export class ObsidianTweakValueService extends InjectableTweakValueService {}
|
export class ObsidianTweakValueService extends InjectableTweakValueService<ObsidianServiceContext> {}
|
||||||
// InjectableVaultService
|
// InjectableVaultService
|
||||||
export class ObsidianVaultService extends InjectableVaultService {}
|
export class ObsidianVaultService extends InjectableVaultService<ObsidianServiceContext> {}
|
||||||
// InjectableTestService
|
// InjectableTestService
|
||||||
export class ObsidianTestService extends InjectableTestService {}
|
export class ObsidianTestService extends InjectableTestService<ObsidianServiceContext> {}
|
||||||
|
export class ObsidianConfigService extends ConfigServiceBrowserCompat<ObsidianServiceContext> {}
|
||||||
export class ObsidianConfigService extends ConfigServiceBrowserCompat {}
|
|
||||||
|
|
||||||
// InjectableServiceHub
|
// InjectableServiceHub
|
||||||
|
|
||||||
export class ObsidianServiceHub extends InjectableServiceHub {
|
export class ObsidianServiceHub extends InjectableServiceHub<ObsidianServiceContext> {
|
||||||
protected _api: ObsidianAPIService = new ObsidianAPIService(this._serviceBackend, this._throughHole);
|
|
||||||
protected _path: ObsidianPathService = new ObsidianPathService(this._serviceBackend, this._throughHole);
|
|
||||||
protected _database: ObsidianDatabaseService = new ObsidianDatabaseService(this._serviceBackend, this._throughHole);
|
|
||||||
protected _replicator: ObsidianReplicatorService = new ObsidianReplicatorService(
|
|
||||||
this._serviceBackend,
|
|
||||||
this._throughHole
|
|
||||||
);
|
|
||||||
protected _fileProcessing: ObsidianFileProcessingService = new ObsidianFileProcessingService(
|
|
||||||
this._serviceBackend,
|
|
||||||
this._throughHole
|
|
||||||
);
|
|
||||||
protected _replication: ObsidianReplicationService = new ObsidianReplicationService(
|
|
||||||
this._serviceBackend,
|
|
||||||
this._throughHole
|
|
||||||
);
|
|
||||||
protected _remote: ObsidianRemoteService = new ObsidianRemoteService(this._serviceBackend, this._throughHole);
|
|
||||||
protected _conflict: ObsidianConflictService = new ObsidianConflictService(this._serviceBackend, this._throughHole);
|
|
||||||
protected _appLifecycle: ObsidianAppLifecycleService = new ObsidianAppLifecycleService(
|
|
||||||
this._serviceBackend,
|
|
||||||
this._throughHole
|
|
||||||
);
|
|
||||||
protected _setting: ObsidianSettingService = new ObsidianSettingService(this._serviceBackend, this._throughHole);
|
|
||||||
protected _tweakValue: ObsidianTweakValueService = new ObsidianTweakValueService(
|
|
||||||
this._serviceBackend,
|
|
||||||
this._throughHole
|
|
||||||
);
|
|
||||||
protected _vault: ObsidianVaultService = new ObsidianVaultService(this._serviceBackend, this._throughHole);
|
|
||||||
protected _test: ObsidianTestService = new ObsidianTestService(this._serviceBackend, this._throughHole);
|
|
||||||
|
|
||||||
private _plugin: ObsidianLiveSyncPlugin;
|
|
||||||
constructor(plugin: ObsidianLiveSyncPlugin) {
|
constructor(plugin: ObsidianLiveSyncPlugin) {
|
||||||
const config = new ObsidianConfigService();
|
const context = new ObsidianServiceContext(plugin.app, plugin, plugin);
|
||||||
super({
|
|
||||||
ui: new ObsidianUIService(plugin),
|
const API = new ObsidianAPIService(context);
|
||||||
|
const appLifecycle = new ObsidianAppLifecycleService(context);
|
||||||
|
const conflict = new ObsidianConflictService(context);
|
||||||
|
const database = new ObsidianDatabaseService(context);
|
||||||
|
const fileProcessing = new ObsidianFileProcessingService(context);
|
||||||
|
const replication = new ObsidianReplicationService(context);
|
||||||
|
const replicator = new ObsidianReplicatorService(context);
|
||||||
|
const remote = new ObsidianRemoteService(context);
|
||||||
|
const setting = new ObsidianSettingService(context);
|
||||||
|
const tweakValue = new ObsidianTweakValueService(context);
|
||||||
|
const vault = new ObsidianVaultService(context);
|
||||||
|
const test = new ObsidianTestService(context);
|
||||||
|
const databaseEvents = new ObsidianDatabaseEventService(context);
|
||||||
|
const path = new ObsidianPathService(context);
|
||||||
|
const ui = new ObsidianUIService(context);
|
||||||
|
const config = new ObsidianConfigService(context, vault);
|
||||||
|
// Using 'satisfies' to ensure all services are provided
|
||||||
|
const serviceInstancesToInit = {
|
||||||
|
appLifecycle: appLifecycle,
|
||||||
|
conflict: conflict,
|
||||||
|
database: database,
|
||||||
|
databaseEvents: databaseEvents,
|
||||||
|
fileProcessing: fileProcessing,
|
||||||
|
replication: replication,
|
||||||
|
replicator: replicator,
|
||||||
|
remote: remote,
|
||||||
|
setting: setting,
|
||||||
|
tweakValue: tweakValue,
|
||||||
|
vault: vault,
|
||||||
|
test: test,
|
||||||
|
ui: ui,
|
||||||
|
path: path,
|
||||||
|
API: API,
|
||||||
config: config,
|
config: config,
|
||||||
});
|
} satisfies Required<ServiceInstances<ObsidianServiceContext>>;
|
||||||
this._plugin = plugin;
|
|
||||||
|
super(context, serviceInstancesToInit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,129 @@
|
|||||||
import { UIService } from "../../lib/src/services/Services";
|
import { UIService } from "../../lib/src/services/Services";
|
||||||
import type ObsidianLiveSyncPlugin from "../../main";
|
import { Notice, type App, type Plugin } from "@/deps";
|
||||||
import { SvelteDialogManager } from "../features/SetupWizard/ObsidianSvelteDialog";
|
import { SvelteDialogManager } from "../features/SetupWizard/ObsidianSvelteDialog";
|
||||||
import DialogueToCopy from "../../lib/src/UI/dialogues/DialogueToCopy.svelte";
|
import DialogueToCopy from "../../lib/src/UI/dialogues/DialogueToCopy.svelte";
|
||||||
|
import type { ObsidianServiceContext } from "./ObsidianServices";
|
||||||
|
import type ObsidianLiveSyncPlugin from "@/main";
|
||||||
|
import type { Confirm } from "@/lib/src/interfaces/Confirm";
|
||||||
|
import {
|
||||||
|
askSelectString,
|
||||||
|
askString,
|
||||||
|
askYesNo,
|
||||||
|
confirmWithMessage,
|
||||||
|
confirmWithMessageWithWideButton,
|
||||||
|
} from "../coreObsidian/UILib/dialogs";
|
||||||
|
import { $msg } from "@/lib/src/common/i18n";
|
||||||
|
import { disposeMemoObject, memoIfNotExist, memoObject, retrieveMemoObject, scheduleTask } from "@/common/utils";
|
||||||
|
export class ObsidianConfirm implements Confirm {
|
||||||
|
private _app: App;
|
||||||
|
private _plugin: Plugin;
|
||||||
|
constructor(app: App, plugin: Plugin) {
|
||||||
|
this._app = app;
|
||||||
|
this._plugin = plugin;
|
||||||
|
}
|
||||||
|
askYesNo(message: string): Promise<"yes" | "no"> {
|
||||||
|
return askYesNo(this._app, message);
|
||||||
|
}
|
||||||
|
askString(title: string, key: string, placeholder: string, isPassword: boolean = false): Promise<string | false> {
|
||||||
|
return askString(this._app, title, key, placeholder, isPassword);
|
||||||
|
}
|
||||||
|
|
||||||
export class ObsidianUIService extends UIService {
|
async askYesNoDialog(
|
||||||
|
message: string,
|
||||||
|
opt: { title?: string; defaultOption?: "Yes" | "No"; timeout?: number } = { title: "Confirmation" }
|
||||||
|
): Promise<"yes" | "no"> {
|
||||||
|
const defaultTitle = $msg("moduleInputUIObsidian.defaultTitleConfirmation");
|
||||||
|
const yesLabel = $msg("moduleInputUIObsidian.optionYes");
|
||||||
|
const noLabel = $msg("moduleInputUIObsidian.optionNo");
|
||||||
|
const defaultOption = opt.defaultOption === "Yes" ? yesLabel : noLabel;
|
||||||
|
const ret = await confirmWithMessageWithWideButton(
|
||||||
|
this._plugin,
|
||||||
|
opt.title || defaultTitle,
|
||||||
|
message,
|
||||||
|
[yesLabel, noLabel],
|
||||||
|
defaultOption,
|
||||||
|
opt.timeout
|
||||||
|
);
|
||||||
|
return ret === yesLabel ? "yes" : "no";
|
||||||
|
}
|
||||||
|
|
||||||
|
askSelectString(message: string, items: string[]): Promise<string> {
|
||||||
|
return askSelectString(this._app, message, items);
|
||||||
|
}
|
||||||
|
|
||||||
|
askSelectStringDialogue<T extends readonly string[]>(
|
||||||
|
message: string,
|
||||||
|
buttons: T,
|
||||||
|
opt: { title?: string; defaultAction: T[number]; timeout?: number }
|
||||||
|
): Promise<T[number] | false> {
|
||||||
|
const defaultTitle = $msg("moduleInputUIObsidian.defaultTitleSelect");
|
||||||
|
return confirmWithMessageWithWideButton(
|
||||||
|
this._plugin,
|
||||||
|
opt.title || defaultTitle,
|
||||||
|
message,
|
||||||
|
buttons,
|
||||||
|
opt.defaultAction,
|
||||||
|
opt.timeout
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
askInPopup(key: string, dialogText: string, anchorCallback: (anchor: HTMLAnchorElement) => void) {
|
||||||
|
const fragment = createFragment((doc) => {
|
||||||
|
const [beforeText, afterText] = dialogText.split("{HERE}", 2);
|
||||||
|
doc.createEl("span", undefined, (a) => {
|
||||||
|
a.appendText(beforeText);
|
||||||
|
a.appendChild(
|
||||||
|
a.createEl("a", undefined, (anchor) => {
|
||||||
|
anchorCallback(anchor);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
a.appendText(afterText);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const popupKey = "popup-" + key;
|
||||||
|
scheduleTask(popupKey, 1000, async () => {
|
||||||
|
const popup = await memoIfNotExist(popupKey, () => new Notice(fragment, 0));
|
||||||
|
const isShown = popup?.noticeEl?.isShown();
|
||||||
|
if (!isShown) {
|
||||||
|
memoObject(popupKey, new Notice(fragment, 0));
|
||||||
|
}
|
||||||
|
scheduleTask(popupKey + "-close", 20000, () => {
|
||||||
|
const popup = retrieveMemoObject<Notice>(popupKey);
|
||||||
|
if (!popup) return;
|
||||||
|
if (popup?.noticeEl?.isShown()) {
|
||||||
|
popup.hide();
|
||||||
|
}
|
||||||
|
disposeMemoObject(popupKey);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmWithMessage(
|
||||||
|
title: string,
|
||||||
|
contentMd: string,
|
||||||
|
buttons: string[],
|
||||||
|
defaultAction: (typeof buttons)[number],
|
||||||
|
timeout?: number
|
||||||
|
): Promise<(typeof buttons)[number] | false> {
|
||||||
|
return confirmWithMessage(this._plugin, title, contentMd, buttons, defaultAction, timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class ObsidianUIService extends UIService<ObsidianServiceContext> {
|
||||||
private _dialogManager: SvelteDialogManager;
|
private _dialogManager: SvelteDialogManager;
|
||||||
private _plugin: ObsidianLiveSyncPlugin;
|
private _plugin: Plugin;
|
||||||
|
private _liveSyncPlugin: ObsidianLiveSyncPlugin;
|
||||||
|
private _confirmInstance: ObsidianConfirm;
|
||||||
get dialogManager() {
|
get dialogManager() {
|
||||||
return this._dialogManager;
|
return this._dialogManager;
|
||||||
}
|
}
|
||||||
constructor(plugin: ObsidianLiveSyncPlugin) {
|
constructor(context: ObsidianServiceContext) {
|
||||||
super();
|
super(context);
|
||||||
this._dialogManager = new SvelteDialogManager(plugin);
|
this._liveSyncPlugin = context.liveSyncPlugin;
|
||||||
this._plugin = plugin;
|
this._dialogManager = new SvelteDialogManager(this._liveSyncPlugin);
|
||||||
|
this._plugin = context.plugin;
|
||||||
|
this._confirmInstance = new ObsidianConfirm(this._plugin.app, this._plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
async promptCopyToClipboard(title: string, value: string): Promise<boolean> {
|
async promptCopyToClipboard(title: string, value: string): Promise<boolean> {
|
||||||
const param = {
|
const param = {
|
||||||
title: title,
|
title: title,
|
||||||
@@ -25,16 +135,22 @@ export class ObsidianUIService extends UIService {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
showMarkdownDialog<T extends string[]>(
|
showMarkdownDialog<T extends string[]>(
|
||||||
title: string,
|
title: string,
|
||||||
contentMD: string,
|
contentMD: string,
|
||||||
buttons: T,
|
buttons: T,
|
||||||
defaultAction?: (typeof buttons)[number]
|
defaultAction?: (typeof buttons)[number]
|
||||||
): Promise<(typeof buttons)[number] | false> {
|
): Promise<(typeof buttons)[number] | false> {
|
||||||
return this._plugin.confirm.askSelectStringDialogue(contentMD, buttons, {
|
// TODO: implement `confirm` to this service
|
||||||
|
return this._liveSyncPlugin.confirm.askSelectStringDialogue(contentMD, buttons, {
|
||||||
title,
|
title,
|
||||||
defaultAction: defaultAction ?? buttons[0],
|
defaultAction: defaultAction ?? buttons[0],
|
||||||
timeout: 0,
|
timeout: 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get confirm(): Confirm {
|
||||||
|
return this._confirmInstance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -992,4 +992,4 @@ export type ListedFiles = {
|
|||||||
folders: string[];
|
folders: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ValueComponent = any;
|
export type ValueComponent = any;
|
||||||
|
|||||||
99
updates.md
99
updates.md
@@ -3,6 +3,58 @@ 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.
|
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.41
|
||||||
|
|
||||||
|
24th January, 2026
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- No longer `No available splitter for settings!!` errors occur after fetching old remote settings while rebuilding local database. (#748)
|
||||||
|
|
||||||
|
### Improved
|
||||||
|
|
||||||
|
- Boot sequence warning is now kept in the in-editor notification area.
|
||||||
|
|
||||||
|
### New feature
|
||||||
|
|
||||||
|
- We can now set the maximum modified time for reflect events in the settings. (for #754)
|
||||||
|
- This setting can be configured from `Patches` -> `Remediation` in the settings dialogue.
|
||||||
|
- Enabling this setting will restrict the propagation from the database to storage to only those changes made before the specified date and time.
|
||||||
|
- This feature is primarily intended for recovery purposes. After placing `redflag.md` in an empty vault and importing the Self-hosted LiveSync configuration, please perform this configuration, and then fetch the local database from the remote.
|
||||||
|
- This feature is useful when we want to prevent recent unwanted changes from being reflected in the local storage.
|
||||||
|
|
||||||
|
### Refactored
|
||||||
|
- Module to service refactoring has been started for better maintainability:
|
||||||
|
- UI module has been moved to UI service.
|
||||||
|
|
||||||
|
### Behaviour change
|
||||||
|
- Default chunk splitter version has been changed to `Rabin-Karp` for new installations.
|
||||||
|
|
||||||
|
## 0.25.40
|
||||||
|
|
||||||
|
23rd January, 2026
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed an issue where some events were not triggered correctly after the refactoring in 0.25.39.
|
||||||
|
|
||||||
|
## 0.25.39
|
||||||
|
|
||||||
|
23rd January, 2026
|
||||||
|
|
||||||
|
Also no behaviour changes or fixes in this release. Just refactoring for better maintainability. Thank you for your patience! I will address some of the reported issues soon.
|
||||||
|
However, this is not a minor refactoring, so please be careful. Let me know if you find any unexpected behaviour after this update.
|
||||||
|
|
||||||
|
### Refactored
|
||||||
|
|
||||||
|
- Rewrite the service's binding/handler assignment systems
|
||||||
|
- Removed loopholes that allowed traversal between services to clarify dependencies.
|
||||||
|
- Consolidated the hidden state-related state, the handler, and the addition of bindings to the handler into a single object.
|
||||||
|
- Currently, functions that can have handlers added implement either addHandler or setHandler directly on the function itself.
|
||||||
|
I understand there are differing opinions on this, but for now, this is how it stands.
|
||||||
|
- Services now possess a Context. Please ensure each platform has a class that inherits from ServiceContext.
|
||||||
|
- To permit services to be dynamically bound, the services themselves are now defined by interfaces.
|
||||||
|
|
||||||
## 0.25.38
|
## 0.25.38
|
||||||
|
|
||||||
17th January, 2026
|
17th January, 2026
|
||||||
@@ -21,6 +73,7 @@ This release contains minor changes discovered and fixed during test implementat
|
|||||||
There are no changes affecting usage.
|
There are no changes affecting usage.
|
||||||
|
|
||||||
### Refactored
|
### Refactored
|
||||||
|
|
||||||
- Logging system has been slightly refactored to improve maintainability.
|
- Logging system has been slightly refactored to improve maintainability.
|
||||||
- Some import statements have been unified.
|
- Some import statements have been unified.
|
||||||
|
|
||||||
@@ -121,51 +174,5 @@ Anyway, I will release the things a bit by bit. I think that we need a rehabilit
|
|||||||
- Now fetching configuration from the server can handle the empty remote correctly (reported on #756).
|
- Now fetching configuration from the server can handle the empty remote correctly (reported on #756).
|
||||||
- No longer asking to switch adapters during rebuilding.
|
- No longer asking to switch adapters during rebuilding.
|
||||||
|
|
||||||
## 0.25.30
|
|
||||||
|
|
||||||
17th November, 2025
|
|
||||||
|
|
||||||
So sorry for the quick follow-up release, due to a humble mistake in a quick causing a matter.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Now we can save settings correctly again (#756).
|
|
||||||
|
|
||||||
## ~~0.25.28~~ 0.25.29
|
|
||||||
|
|
||||||
(0.25.28 was skipped due to a packaging issue.)
|
|
||||||
|
|
||||||
17th November, 2025
|
|
||||||
|
|
||||||
### New feature
|
|
||||||
|
|
||||||
- We can now configure hidden file synchronisation to always overwrite with the latest version (#579).
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Timing dependency issues during initialisation have been mitigated (#714)
|
|
||||||
|
|
||||||
### Improved
|
|
||||||
|
|
||||||
- Error logs now contain stack-traces for better inspection.
|
|
||||||
|
|
||||||
## 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).
|
|
||||||
|
|
||||||
Older notes are in
|
Older notes are in
|
||||||
[updates_old.md](https://github.com/vrtmrz/obsidian-livesync/blob/main/updates_old.md).
|
[updates_old.md](https://github.com/vrtmrz/obsidian-livesync/blob/main/updates_old.md).
|
||||||
|
|||||||
@@ -9,6 +9,52 @@ I have now rewritten the E2EE code to be more robust and easier to understand. I
|
|||||||
As a result, this is the first time in a while that forward compatibility has been broken. We have also taken the opportunity to change all metadata to use encryption rather than obfuscation. Furthermore, the `Dynamic Iteration Count` setting is now redundant and has been moved to the `Patches` pane in the settings. Thanks to Rabin-Karp, the eden setting is also no longer necessary and has been relocated accordingly. Therefore, v0.25.0 represents a legitimate and correct evolution.
|
As a result, this is the first time in a while that forward compatibility has been broken. We have also taken the opportunity to change all metadata to use encryption rather than obfuscation. Furthermore, the `Dynamic Iteration Count` setting is now redundant and has been moved to the `Patches` pane in the settings. Thanks to Rabin-Karp, the eden setting is also no longer necessary and has been relocated accordingly. Therefore, v0.25.0 represents a legitimate and correct evolution.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
## 0.25.30
|
||||||
|
|
||||||
|
17th November, 2025
|
||||||
|
|
||||||
|
So sorry for the quick follow-up release, due to a humble mistake in a quick causing a matter.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Now we can save settings correctly again (#756).
|
||||||
|
|
||||||
|
## ~~0.25.28~~ 0.25.29
|
||||||
|
|
||||||
|
(0.25.28 was skipped due to a packaging issue.)
|
||||||
|
|
||||||
|
17th November, 2025
|
||||||
|
|
||||||
|
### New feature
|
||||||
|
|
||||||
|
- We can now configure hidden file synchronisation to always overwrite with the latest version (#579).
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Timing dependency issues during initialisation have been mitigated (#714)
|
||||||
|
|
||||||
|
### Improved
|
||||||
|
|
||||||
|
- Error logs now contain stack-traces for better inspection.
|
||||||
|
|
||||||
|
## 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
|
## 0.25.26
|
||||||
|
|
||||||
07th November, 2025
|
07th November, 2025
|
||||||
|
|||||||
110
vitest.config.common.ts
Normal file
110
vitest.config.common.ts
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
import { defineConfig } from "vitest/config";
|
||||||
|
import { svelte } from "@sveltejs/vite-plugin-svelte";
|
||||||
|
import { sveltePreprocess } from "svelte-preprocess";
|
||||||
|
import inlineWorkerPlugin from "esbuild-plugin-inline-worker";
|
||||||
|
import path from "path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
import fs from "node:fs";
|
||||||
|
import { platform } from "node:process";
|
||||||
|
|
||||||
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
const manifestJson = JSON.parse(fs.readFileSync("./manifest.json") + "");
|
||||||
|
const packageJson = JSON.parse(fs.readFileSync("./package.json") + "");
|
||||||
|
const updateInfo = JSON.stringify(fs.readFileSync("./updates.md") + "");
|
||||||
|
const prod = false;
|
||||||
|
const moduleAliasPlugin = {
|
||||||
|
name: "module-alias",
|
||||||
|
setup(build: any) {
|
||||||
|
build.onResolve({ filter: /.(dev)(.ts|)$/ }, (args: any) => {
|
||||||
|
// console.log(args.path);
|
||||||
|
if (prod) {
|
||||||
|
const prodTs = args.path.replace(".dev", ".prod");
|
||||||
|
const statFile = prodTs.endsWith(".ts") ? prodTs : prodTs + ".ts";
|
||||||
|
const realPath = path.join(args.resolveDir, statFile);
|
||||||
|
console.log(`Checking ${statFile}`);
|
||||||
|
if (fs.existsSync(realPath)) {
|
||||||
|
console.log(`Replaced ${args.path} with ${prodTs}`);
|
||||||
|
return {
|
||||||
|
path: realPath,
|
||||||
|
namespace: "file",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
build.onResolve({ filter: /.(platform)(.ts|)$/ }, (args: any) => {
|
||||||
|
// console.log(args.path);
|
||||||
|
if (prod) {
|
||||||
|
const prodTs = args.path.replace(".platform", ".obsidian");
|
||||||
|
const statFile = prodTs.endsWith(".ts") ? prodTs : prodTs + ".ts";
|
||||||
|
const realPath = path.join(args.resolveDir, statFile);
|
||||||
|
console.log(`Checking ${statFile}`);
|
||||||
|
if (fs.existsSync(realPath)) {
|
||||||
|
console.log(`Replaced ${args.path} with ${prodTs}`);
|
||||||
|
return {
|
||||||
|
path: realPath,
|
||||||
|
namespace: "file",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const externals = [
|
||||||
|
"obsidian",
|
||||||
|
"electron",
|
||||||
|
"crypto",
|
||||||
|
"@codemirror/autocomplete",
|
||||||
|
"@codemirror/collab",
|
||||||
|
"@codemirror/commands",
|
||||||
|
"@codemirror/language",
|
||||||
|
"@codemirror/lint",
|
||||||
|
"@codemirror/search",
|
||||||
|
"@codemirror/state",
|
||||||
|
"@codemirror/view",
|
||||||
|
"@lezer/common",
|
||||||
|
"@lezer/highlight",
|
||||||
|
"@lezer/lr",
|
||||||
|
];
|
||||||
|
const define = {
|
||||||
|
MANIFEST_VERSION: `"${manifestJson.version}"`,
|
||||||
|
PACKAGE_VERSION: `"${packageJson.version}"`,
|
||||||
|
UPDATE_INFO: `${updateInfo}`,
|
||||||
|
global: "globalThis",
|
||||||
|
hostPlatform: `"${platform}"`,
|
||||||
|
};
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
moduleAliasPlugin,
|
||||||
|
inlineWorkerPlugin({
|
||||||
|
external: externals,
|
||||||
|
treeShaking: true,
|
||||||
|
}),
|
||||||
|
svelte({
|
||||||
|
preprocess: sveltePreprocess(),
|
||||||
|
compilerOptions: { css: "injected", preserveComments: false },
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
obsidian: path.resolve(__dirname, "./test/harness/obsidian-mock.ts"),
|
||||||
|
"@": path.resolve(__dirname, "./src"),
|
||||||
|
"@lib": path.resolve(__dirname, "./src/lib/src"),
|
||||||
|
src: path.resolve(__dirname, "./src"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
esbuild: {
|
||||||
|
define: define,
|
||||||
|
target: "es2018",
|
||||||
|
platform: "browser",
|
||||||
|
},
|
||||||
|
// define,
|
||||||
|
server: {
|
||||||
|
headers: {
|
||||||
|
"Service-Worker-Allowed": "/",
|
||||||
|
},
|
||||||
|
port: 5173,
|
||||||
|
},
|
||||||
|
});
|
||||||
236
vitest.config.ts
236
vitest.config.ts
@@ -1,180 +1,76 @@
|
|||||||
import { defineConfig } from "vitest/config";
|
import { defineConfig, mergeConfig } from "vitest/config";
|
||||||
import { playwright } from "@vitest/browser-playwright";
|
import { playwright } from "@vitest/browser-playwright";
|
||||||
import { svelte } from "@sveltejs/vite-plugin-svelte";
|
import viteConfig from "./vitest.config.common";
|
||||||
import { sveltePreprocess } from "svelte-preprocess";
|
|
||||||
import inlineWorkerPlugin from "esbuild-plugin-inline-worker";
|
|
||||||
import path from "path";
|
|
||||||
import { fileURLToPath } from "node:url";
|
|
||||||
import fs from "node:fs";
|
|
||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
import { platform } from "node:process";
|
import { grantClipboardPermissions, openWebPeer, closeWebPeer, acceptWebPeer } from "./test/lib/commands";
|
||||||
|
|
||||||
import { acceptWebPeer, closeWebPeer, grantClipboardPermissions, openWebPeer } from "./test/lib/commands.ts";
|
|
||||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
||||||
|
|
||||||
const defEnv = dotenv.config({ path: ".env" }).parsed;
|
const defEnv = dotenv.config({ path: ".env" }).parsed;
|
||||||
const testEnv = dotenv.config({ path: ".test.env" }).parsed;
|
const testEnv = dotenv.config({ path: ".test.env" }).parsed;
|
||||||
const env = Object.assign({}, defEnv, testEnv);
|
const env = Object.assign({}, defEnv, testEnv);
|
||||||
const debuggerEnabled = env?.ENABLE_DEBUGGER === "true";
|
const debuggerEnabled = env?.ENABLE_DEBUGGER === "true";
|
||||||
const enableUI = env?.ENABLE_UI === "true";
|
const enableUI = env?.ENABLE_UI === "true";
|
||||||
// const livesyncLogsEnabled = env?.PRINT_LIVESYNC_LOGS === "true";
|
|
||||||
const headless = !debuggerEnabled && !enableUI;
|
const headless = !debuggerEnabled && !enableUI;
|
||||||
const manifestJson = JSON.parse(fs.readFileSync("./manifest.json") + "");
|
export default mergeConfig(
|
||||||
const packageJson = JSON.parse(fs.readFileSync("./package.json") + "");
|
viteConfig,
|
||||||
const updateInfo = JSON.stringify(fs.readFileSync("./updates.md") + "");
|
defineConfig({
|
||||||
const prod = false;
|
test: {
|
||||||
const moduleAliasPlugin = {
|
env: env,
|
||||||
name: "module-alias",
|
testTimeout: 40000,
|
||||||
setup(build: any) {
|
hookTimeout: 50000,
|
||||||
build.onResolve({ filter: /.(dev)(.ts|)$/ }, (args: any) => {
|
|
||||||
// console.log(args.path);
|
|
||||||
if (prod) {
|
|
||||||
const prodTs = args.path.replace(".dev", ".prod");
|
|
||||||
const statFile = prodTs.endsWith(".ts") ? prodTs : prodTs + ".ts";
|
|
||||||
const realPath = path.join(args.resolveDir, statFile);
|
|
||||||
console.log(`Checking ${statFile}`);
|
|
||||||
if (fs.existsSync(realPath)) {
|
|
||||||
console.log(`Replaced ${args.path} with ${prodTs}`);
|
|
||||||
return {
|
|
||||||
path: realPath,
|
|
||||||
namespace: "file",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
build.onResolve({ filter: /.(platform)(.ts|)$/ }, (args: any) => {
|
|
||||||
// console.log(args.path);
|
|
||||||
if (prod) {
|
|
||||||
const prodTs = args.path.replace(".platform", ".obsidian");
|
|
||||||
const statFile = prodTs.endsWith(".ts") ? prodTs : prodTs + ".ts";
|
|
||||||
const realPath = path.join(args.resolveDir, statFile);
|
|
||||||
console.log(`Checking ${statFile}`);
|
|
||||||
if (fs.existsSync(realPath)) {
|
|
||||||
console.log(`Replaced ${args.path} with ${prodTs}`);
|
|
||||||
return {
|
|
||||||
path: realPath,
|
|
||||||
namespace: "file",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const externals = [
|
|
||||||
"obsidian",
|
|
||||||
"electron",
|
|
||||||
"crypto",
|
|
||||||
"@codemirror/autocomplete",
|
|
||||||
"@codemirror/collab",
|
|
||||||
"@codemirror/commands",
|
|
||||||
"@codemirror/language",
|
|
||||||
"@codemirror/lint",
|
|
||||||
"@codemirror/search",
|
|
||||||
"@codemirror/state",
|
|
||||||
"@codemirror/view",
|
|
||||||
"@lezer/common",
|
|
||||||
"@lezer/highlight",
|
|
||||||
"@lezer/lr",
|
|
||||||
];
|
|
||||||
const define = {
|
|
||||||
MANIFEST_VERSION: `"${manifestJson.version}"`,
|
|
||||||
PACKAGE_VERSION: `"${packageJson.version}"`,
|
|
||||||
UPDATE_INFO: `${updateInfo}`,
|
|
||||||
global: "globalThis",
|
|
||||||
hostPlatform: `"${platform}"`,
|
|
||||||
};
|
|
||||||
export default defineConfig({
|
|
||||||
plugins: [
|
|
||||||
moduleAliasPlugin,
|
|
||||||
inlineWorkerPlugin({
|
|
||||||
external: externals,
|
|
||||||
treeShaking: true,
|
|
||||||
}),
|
|
||||||
svelte({
|
|
||||||
preprocess: sveltePreprocess(),
|
|
||||||
compilerOptions: { css: "injected", preserveComments: false },
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
obsidian: path.resolve(__dirname, "./test/harness/obsidian-mock.ts"),
|
|
||||||
"@": path.resolve(__dirname, "./src"),
|
|
||||||
"@lib": path.resolve(__dirname, "./src/lib/src"),
|
|
||||||
src: path.resolve(__dirname, "./src"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
esbuild: {
|
|
||||||
define: define,
|
|
||||||
target: "es2018",
|
|
||||||
platform: "browser",
|
|
||||||
},
|
|
||||||
// define,
|
|
||||||
server: {
|
|
||||||
headers: {
|
|
||||||
"Service-Worker-Allowed": "/",
|
|
||||||
},
|
|
||||||
port: 5173,
|
|
||||||
},
|
|
||||||
test: {
|
|
||||||
env: env,
|
|
||||||
testTimeout: 40000,
|
|
||||||
hookTimeout: 50000,
|
|
||||||
fileParallelism: false,
|
|
||||||
isolate: true,
|
|
||||||
watch: false,
|
|
||||||
|
|
||||||
// environment: "browser",
|
|
||||||
include: ["test/**/*.test.ts"],
|
|
||||||
coverage: {
|
|
||||||
include: ["src/**/*.ts", "src/lib/src/**/*.ts", "src/**/*.svelte"],
|
|
||||||
exclude: ["**/*.test.ts", "src/lib/**"],
|
|
||||||
provider: "v8",
|
|
||||||
reporter: ["text", "json", "html"],
|
|
||||||
// ignoreEmptyLines: true,
|
|
||||||
},
|
|
||||||
browser: {
|
|
||||||
isolate: true,
|
|
||||||
commands: {
|
|
||||||
grantClipboardPermissions,
|
|
||||||
openWebPeer,
|
|
||||||
closeWebPeer,
|
|
||||||
acceptWebPeer,
|
|
||||||
},
|
|
||||||
provider: playwright({
|
|
||||||
launchOptions: {
|
|
||||||
args: ["--js-flags=--expose-gc"],
|
|
||||||
// chromiumSandbox: true,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
enabled: true,
|
|
||||||
screenshotFailures: false,
|
|
||||||
instances: [
|
|
||||||
{
|
|
||||||
execArgv: ["--js-flags=--expose-gc"],
|
|
||||||
browser: "chromium",
|
|
||||||
headless,
|
|
||||||
isolate: true,
|
|
||||||
inspector: debuggerEnabled
|
|
||||||
? {
|
|
||||||
waitForDebugger: true,
|
|
||||||
enabled: true,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
printConsoleTrace: debuggerEnabled,
|
|
||||||
onUnhandledError(error) {
|
|
||||||
// Ignore certain errors
|
|
||||||
const msg = error.message || "";
|
|
||||||
if (msg.includes("Cannot create so many PeerConnections")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
headless,
|
|
||||||
fileParallelism: false,
|
fileParallelism: false,
|
||||||
ui: debuggerEnabled || enableUI ? true : false,
|
isolate: true,
|
||||||
|
watch: false,
|
||||||
|
|
||||||
|
// environment: "browser",
|
||||||
|
include: ["test/**/*.test.ts"],
|
||||||
|
coverage: {
|
||||||
|
include: ["src/**/*.ts", "src/lib/src/**/*.ts", "src/**/*.svelte"],
|
||||||
|
exclude: ["**/*.test.ts", "src/lib/**"],
|
||||||
|
provider: "v8",
|
||||||
|
reporter: ["text", "json", "html"],
|
||||||
|
// ignoreEmptyLines: true,
|
||||||
|
},
|
||||||
|
browser: {
|
||||||
|
isolate: true,
|
||||||
|
commands: {
|
||||||
|
grantClipboardPermissions,
|
||||||
|
openWebPeer,
|
||||||
|
closeWebPeer,
|
||||||
|
acceptWebPeer,
|
||||||
|
},
|
||||||
|
provider: playwright({
|
||||||
|
launchOptions: {
|
||||||
|
args: ["--js-flags=--expose-gc"],
|
||||||
|
// chromiumSandbox: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
enabled: true,
|
||||||
|
screenshotFailures: false,
|
||||||
|
instances: [
|
||||||
|
{
|
||||||
|
execArgv: ["--js-flags=--expose-gc"],
|
||||||
|
browser: "chromium",
|
||||||
|
headless,
|
||||||
|
isolate: true,
|
||||||
|
inspector: debuggerEnabled
|
||||||
|
? {
|
||||||
|
waitForDebugger: true,
|
||||||
|
enabled: true,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
printConsoleTrace: debuggerEnabled,
|
||||||
|
onUnhandledError(error) {
|
||||||
|
// Ignore certain errors
|
||||||
|
const msg = error.message || "";
|
||||||
|
if (msg.includes("Cannot create so many PeerConnections")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
headless,
|
||||||
|
fileParallelism: false,
|
||||||
|
ui: debuggerEnabled || enableUI ? true : false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
})
|
||||||
});
|
);
|
||||||
|
|||||||
19
vitest.config.unit.ts
Normal file
19
vitest.config.unit.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { defineConfig, mergeConfig } from "vitest/config";
|
||||||
|
import viteConfig from "./vitest.config.common";
|
||||||
|
|
||||||
|
export default mergeConfig(
|
||||||
|
viteConfig,
|
||||||
|
defineConfig({
|
||||||
|
test: {
|
||||||
|
name: "unit-tests",
|
||||||
|
include: ["**/*unit.test.ts"],
|
||||||
|
exclude: ["test/**"],
|
||||||
|
coverage: {
|
||||||
|
include: ["src/**/*.ts"],
|
||||||
|
exclude: ["**/*.test.ts", "src/lib/**/*.test.ts", "**/_*", "src/lib/apps", "src/lib/src/cli"],
|
||||||
|
provider: "v8",
|
||||||
|
reporter: ["text", "json", "html"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user