Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09146591eb | ||
|
|
69c6e57df3 | ||
|
|
5e181a8ec4 | ||
|
|
4354cc3054 | ||
|
|
0664427c63 | ||
|
|
49c4736d69 | ||
|
|
f0ce8f0e05 | ||
|
|
0a70afc5a3 | ||
|
|
431239a736 | ||
|
|
1ceb671683 | ||
|
|
ea40e5918c | ||
|
|
64681729ff | ||
|
|
830f2f25d1 | ||
|
|
05f0abebf0 | ||
|
|
842da980d7 | ||
|
|
d8ecbb593b | ||
|
|
8d66c372e1 |
78
.github/ISSUE_TEMPLATE/issue-report.md
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
---
|
||||||
|
name: Issue report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Thank you for taking the time to report this issue!
|
||||||
|
To improve the process, I would like to ask you to let me know the information in advance.
|
||||||
|
|
||||||
|
All instructions and examples, and empty entries can be deleted.
|
||||||
|
Just for your information, a [filled example](https://docs.vrtmrz.net/LiveSync/hintandtrivia/Issue+example) is also written.
|
||||||
|
|
||||||
|
## Abstract
|
||||||
|
The synchronisation hung up immediately after connecting.
|
||||||
|
|
||||||
|
## Expected behaviour
|
||||||
|
- Synchronisation ends with the message `Replication completed`
|
||||||
|
- Everything synchronised
|
||||||
|
|
||||||
|
## Actually happened
|
||||||
|
- Synchronisation has been cancelled with the message `TypeError ... ` (captured in the attached log, around LL.10-LL.12)
|
||||||
|
- No files synchronised
|
||||||
|
|
||||||
|
## Reproducing procedure
|
||||||
|
|
||||||
|
1. Configure LiveSync as in the attached material.
|
||||||
|
2. Click the replication button on the ribbon.
|
||||||
|
3. Synchronising has begun.
|
||||||
|
4. About two or three seconds later, we got the error `TypeError ... `.
|
||||||
|
5. Replication has been stopped. No files synchronised.
|
||||||
|
|
||||||
|
Note: If you do not catch the reproducing procedure, please let me know the frequency and signs.
|
||||||
|
|
||||||
|
## Report materials
|
||||||
|
If the information is not available, do not hesitate to report it as it is. You can also of course omit it if you think this is indeed unnecessary. If it is necessary, I will ask you.
|
||||||
|
|
||||||
|
### Report from the LiveSync
|
||||||
|
For more information, please refer to [Making the report](https://docs.vrtmrz.net/LiveSync/hintandtrivia/Making+the+report).
|
||||||
|
<details>
|
||||||
|
<summary>Report from hatch</summary>
|
||||||
|
|
||||||
|
```
|
||||||
|
<!-- paste here -->
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### Obsidian debug info
|
||||||
|
<details>
|
||||||
|
<summary>Debug info</summary>
|
||||||
|
|
||||||
|
```
|
||||||
|
<!-- paste here -->
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### Plug-in log
|
||||||
|
We can see the log by tapping the Document box icon. If you noticed something suspicious, please let me know.
|
||||||
|
Note: **Please enable `Verbose Log`**. For detail, refer to [Logging](https://docs.vrtmrz.net/LiveSync/hintandtrivia/Logging), please.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Plug-in log</summary>
|
||||||
|
|
||||||
|
```
|
||||||
|
<!-- paste here -->
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### Network log
|
||||||
|
Network logs displayed in DevTools will possibly help with connection-related issues. To capture that, please refer to [DevTools](https://docs.vrtmrz.net/LiveSync/hintandtrivia/DevTools).
|
||||||
|
|
||||||
|
### Screenshots
|
||||||
|
If applicable, please add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
### Other information, insights and intuition.
|
||||||
|
Please provide any additional context or information about the problem.
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
# Quick setup
|
# Quick setup
|
||||||
The Setup wizard has been implemented since v0.15.0 simplifying the initial setup.
|
The plugin has so many configuration options to deal with different circumstances. However, there are not so many settings that are actually used. Therefore, `The Setup wizard` has been implemented to simplify the initial setup.
|
||||||
|
|
||||||
Note: Subsequent devices should be set up using the `Copy setup URI` and `Open setup URI` functionality.
|
Note: Subsequent devices are recommended to be set up using the `Copy setup URI` and `Open setup URI`.
|
||||||
|
|
||||||
## How to open and use the wizard
|
## The Setup wizard
|
||||||
Open the `🪄 Setup wizard` in the settings dialogue. If the plugin has not been configured before, it should already be open.
|
Open the `🧙♂️ Setup wizard` in the settings dialogue. If the plugin has not been configured before, it should already be open.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
### Discard the existing configuration and set up
|
- Discard the existing configuration and set up
|
||||||
If you have changed any settings, this button allows you to discard all changes before setting up.
|
If you have changed any settings, this button allows you to discard all changes before setting up.
|
||||||
|
|
||||||
### Do not discard the existing configuration and set up
|
- Do not discard the existing configuration and set up
|
||||||
Simply reconfigure. Be careful. In wizard mode, you cannot see all configuration items, even if they have been configured.
|
Simply reconfigure. Be careful. In wizard mode, you cannot see all configuration items, even if they have been configured.
|
||||||
|
|
||||||
Pressing `Next` on one of the above options will put the configuration dialog into wizard mode.
|
Pressing `Next` on one of the above options will put the configuration dialog into wizard mode.
|
||||||
@@ -30,17 +30,10 @@ Enter the information for the database we have set up.
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
### End to End Encryption
|
|
||||||
|
|
||||||

|
#### Test database connection and Check database configuration
|
||||||
|
|
||||||
When End to End encryption is enabled, a third party will be less likely to be able to read your Remote database in the event of a data breach/leak (assuming they do not know the Passphrase). We strongly recommend enabling it.
|
We can check the connectivity to the database, and the database settings.
|
||||||
Encryption is based on 256-bit AES-GCM.
|
|
||||||
This setting can be disabled if you are inside a closed network and it is clear that you will not be accessed by third parties.
|
|
||||||
|
|
||||||
### Test database connection and Check database configuration
|
|
||||||
|
|
||||||
Here we can check the status of the connection to the database and the database settings.
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -49,38 +42,36 @@ Check whether we can connect to the database. If it fails, there are several pos
|
|||||||
|
|
||||||
#### Check database configuration
|
#### Check database configuration
|
||||||
|
|
||||||
Check the database settings and fix any deficiencies on the spot.
|
Check the database settings and fix any problems on the spot.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
This item may vary depending on the connection. In the above case, press all three Fix buttons.
|
This item may vary depending on the connection. In the above case, press all three Fix buttons.
|
||||||
If the Fix buttons disappear and all become check marks, we are done.
|
If the Fix buttons disappear and all become check marks, we are done.
|
||||||
|
|
||||||
|
|
||||||
|
### Confidentiality configuration
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Encrypt your database in case of unintended database exposure; enable End to End encryption and the contents of your notes will be encrypted at the moment it leaves the device. We strongly recommend enabling it. And `Path Obfuscation` also obfuscates filenames. Now stable and recommended.
|
||||||
|
Encryption is based on 256-bit AES-GCM.
|
||||||
|
These setting can be disabled if you are inside a closed network and it is clear that you will not be accessed by third parties.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
### Next
|
#### Next
|
||||||
Go to the Local Database configuration.
|
Go to the Sync Settings.
|
||||||
|
|
||||||
### Discard existing database and proceed
|
#### Discard existing database and proceed
|
||||||
Discard the contents of the Remote database and go to the Local Database configuration.
|
Discard the contents of the Remote database and go to the Sync Settings.
|
||||||
|
|
||||||
## Local Database configuration
|
### Sync Settings
|
||||||
|
Finally, finish the wizard by selecting a preset for synchronisation.
|
||||||

|
|
||||||
|
|
||||||
Configure the local database. If we already have a Vault with Self-hosted LiveSync installed which has the same directory name as the one we are currently setting up, please specify a different suffix than the Vault you have already set up here.
|
|
||||||
|
|
||||||
## Miscellaneous
|
|
||||||
Finally, finish the miscellaneous configurations and select a preset for synchronisation.
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
The `Show status inside editor` can be enabled to your liking. If enabled, the status is displayed in the top right-hand corner of the editor. Learn how to read the status bar [here](/README.md#information-in-statusbar).
|
Select any synchronisation methods we want to use and `Apply` to initialise and build the local and remote databases as required. If `All done!` is displayed, we are done. Automatically, `Copy setup URI` will open and we will be asked for a passphrase to encrypt the `Setup URI`.
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
From Presets, select the synchronisation method we want to use and `Apply` to initialise and build the local and remote databases as required.
|
|
||||||
If `All done!' is displayed, we are done. Automatically, `Copy setup URI` will open and we will be asked for a passphrase to encrypt the `Setup URI`.
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# Quick setup
|
# Quick setup
|
||||||
v0.15.0からSetup wizardが実装されました。これで、初回セットアップがシンプルになります。
|
このプラグインには、いろいろな状況に対応するための非常に多くの設定オプションがあります。しかし、実際に使用する設定項目はそれほど多くはありません。そこで、初期設定を簡略化するために、「セットアップウィザード」を実装しています。
|
||||||
※なお、次のデバイスからは、`Copy setup URI`と`Open setup URI`を使ってセットアップしてください。
|
※なお、次のデバイスからは、`Copy setup URI`と`Open setup URI`を使ってセットアップしてください。
|
||||||
|
|
||||||
|
|
||||||
## Wizardの使い方
|
## Wizardの使い方
|
||||||
`🪄 Setup wizard` から開きます。もしセットアップされていなかったり、同期設定が何も有効になっていない場合はデフォルトで開いています。
|
`🧙♂️ Setup wizard` から開きます。もしセットアップされていなかったり、同期設定が何も有効になっていない場合はデフォルトで開いています。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -32,20 +32,12 @@ v0.15.0からSetup wizardが実装されました。これで、初回セット
|
|||||||
|
|
||||||
これらはデータベースをセットアップした際に決めた情報です。
|
これらはデータベースをセットアップした際に決めた情報です。
|
||||||
|
|
||||||
### End to End暗号化の設定
|
### Test database connectionとCheck database configuration
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
End to End暗号化を有効にした場合、万が一Remote databaseの内容が流出してもPassphraseを知らない第三者にそれを読まれる可能性が低くなります。そのため、有効化を強く推奨します。
|
|
||||||
暗号化は256bitのAES-GCMを採用しています。
|
|
||||||
この設定は、あなたが閉じたネットワークの内側にいて、かつ第三者からアクセスされない事が明確な場合には無効にできます。
|
|
||||||
|
|
||||||
### Test database connectionとCheck database configuraion
|
|
||||||
ここで、データベースへの接続状況と、データベース設定を確認します。
|
ここで、データベースへの接続状況と、データベース設定を確認します。
|
||||||

|

|
||||||
|
|
||||||
#### Test Database Connection
|
#### Test Database Connection
|
||||||
データベースに接続出来るか自体を確認します。失敗する場合はいくつか理由がありますが、一度Check database configurationを行ってそちらでも失敗するか確認してください。
|
データベースに接続できるか自体を確認します。失敗する場合はいくつか理由がありますが、一度Check database configurationを行ってそちらでも失敗するか確認してください。
|
||||||
|
|
||||||
#### Check database configuration
|
#### Check database configuration
|
||||||
データベースの設定を確認し、不備がある場合はその場で修正します。
|
データベースの設定を確認し、不備がある場合はその場で修正します。
|
||||||
@@ -55,6 +47,15 @@ End to End暗号化を有効にした場合、万が一Remote databaseの内容
|
|||||||
この項目は接続先によって異なる場合があります。上記の場合、みっつのFixボタンを順にすべて押してください。
|
この項目は接続先によって異なる場合があります。上記の場合、みっつのFixボタンを順にすべて押してください。
|
||||||
Fixボタンがなくなり、すべてチェックマークになれば完了です。
|
Fixボタンがなくなり、すべてチェックマークになれば完了です。
|
||||||
|
|
||||||
|
### 機密性設定
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
意図しないデータベースの暴露に備えて、End to End Encryptionを有効にします。この項目を有効にした場合、デバイスを出る瞬間にノートの内容が暗号化されます。`Path Obfuscation`を有効にすると、ファイル名も難読化されます。現在は安定しているため、こちらも推奨されます。
|
||||||
|
暗号化には256bitのAES-GCMを採用しています。
|
||||||
|
これらの設定は、あなたが閉じたネットワークの内側にいて、かつ第三者からアクセスされない事が明確な場合には無効にできます。
|
||||||
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
### Next
|
### Next
|
||||||
@@ -63,20 +64,13 @@ Fixボタンがなくなり、すべてチェックマークになれば完了
|
|||||||
### Discard exist database and proceed
|
### Discard exist database and proceed
|
||||||
すでにRemote databaseがある場合、Remote databaseの内容を破棄してから次へ進みます
|
すでにRemote databaseがある場合、Remote databaseの内容を破棄してから次へ進みます
|
||||||
|
|
||||||
## Local Database confiuration
|
|
||||||

|
|
||||||
ローカルのデータベースを設定します。もし、すでにSelf-hosted LiveSyncをインストールしたVaultがあり、そのVaultと同じデータベース名を使用している場合は、ここですでに設定したVaultとは異なるsuffixを指定してください。
|
|
||||||
|
|
||||||
## Miscellaneous
|
## Sync Settings
|
||||||
最後にその他の設定を行います。
|
最後に同期方法の設定を行います。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
`Show status inside editor`はお好みで有効化してください。有効にするとエディターの右上にステータスが表示されます。
|
Presetsから、いずれかの同期方法を選び`Apply`を行うと、必要に応じてローカル・リモートのデータベースを初期化・構築します。
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
Presetsから、使用する同期方法を選び`Apply`を行うと、必要に応じてローカル・リモートのデータベースを初期化・構築します。
|
|
||||||
All done! と表示されれば完了です。自動的に、`Copy setup URI`が開き、`Setup URI`を暗号化するパスフレーズを聞かれます。
|
All done! と表示されれば完了です。自動的に、`Copy setup URI`が開き、`Setup URI`を暗号化するパスフレーズを聞かれます。
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
# Setup CouchDB to your server
|
# Setup a CouchDB server
|
||||||
|
|
||||||
|
## Configure
|
||||||
|
|
||||||
## Install CouchDB and access from a PC or Mac
|
The easiest way to set up a CouchDB instance is using the official [docker image](https://hub.docker.com/_/couchdb).
|
||||||
|
|
||||||
The easiest way to set up the CouchDB is using the [docker image]((https://hub.docker.com/_/couchdb)).
|
Some initial configuration is required. Create a `local.ini` to use Self-hosted LiveSync as follows:
|
||||||
|
|
||||||
But some additional configurations are required in `local.ini` to use from Self-hosted LiveSync, like below:
|
```ini
|
||||||
|
|
||||||
```
|
|
||||||
[couchdb]
|
[couchdb]
|
||||||
single_node=true
|
single_node=true
|
||||||
max_document_size = 50000000
|
max_document_size = 50000000
|
||||||
@@ -32,28 +31,62 @@ methods = GET, PUT, POST, HEAD, DELETE
|
|||||||
max_age = 3600
|
max_age = 3600
|
||||||
```
|
```
|
||||||
|
|
||||||
Make `local.ini` and run with docker run like this, you can launch the CouchDB.
|
## Run
|
||||||
|
|
||||||
|
### Docker CLI
|
||||||
|
|
||||||
|
You can launch CouchDB using your `local.ini` like this:
|
||||||
```
|
```
|
||||||
$ docker run --rm -it -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password -v /path/to/local.ini:/opt/couchdb/etc/local.ini -p 5984:5984 couchdb
|
$ docker run --rm -it -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password -v /path/to/local.ini:/opt/couchdb/etc/local.ini -p 5984:5984 couchdb
|
||||||
```
|
```
|
||||||
*Remember to replace the path with the path to your local.ini*
|
*Remember to replace the path with the path to your local.ini*
|
||||||
Note: At this time, the file owner of local.ini became 5984:5984. It's the limitation docker image. please change the owner before editing local.ini again.
|
|
||||||
|
|
||||||
If you could confirm that Self-hosted LiveSync can sync with the server, launch the docker image as a background as you like.
|
Run in detached mode:
|
||||||
|
|
||||||
Example to run docker in detached mode:
|
|
||||||
```
|
```
|
||||||
$ docker run -d --restart always -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password -v /path/to/local.ini:/opt/couchdb/etc/local.ini -p 5984:5984 couchdb
|
$ docker run -d --restart always -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password -v /path/to/local.ini:/opt/couchdb/etc/local.ini -p 5984:5984 couchdb
|
||||||
```
|
```
|
||||||
*Remember to replace the path with the path to your local.ini*
|
*Remember to replace the path with the path to your local.ini*
|
||||||
|
|
||||||
|
### Docker Compose
|
||||||
|
Create a directory, place your `local.ini` within it, and create a `docker-compose.yml` alongside it. The directory structure should look similar to this:
|
||||||
|
```
|
||||||
|
obsidian-livesync
|
||||||
|
├── docker-compose.yml
|
||||||
|
└── local.ini
|
||||||
|
```
|
||||||
|
|
||||||
|
A good place to start for `docker-compose.yml`:
|
||||||
|
```yaml
|
||||||
|
version: "2.1"
|
||||||
|
services:
|
||||||
|
couchdb:
|
||||||
|
image: couchdb
|
||||||
|
container_name: obsidian-livesync
|
||||||
|
user: 1000:1000
|
||||||
|
environment:
|
||||||
|
- COUCHDB_USER=admin
|
||||||
|
- COUCHDB_PASSWORD=password
|
||||||
|
volumes:
|
||||||
|
- ./data:/opt/couchdb/data
|
||||||
|
- ./local.ini:/opt/couchdb/etc/local.ini
|
||||||
|
ports:
|
||||||
|
- 5984:5984
|
||||||
|
restart: unless-stopped
|
||||||
|
```
|
||||||
|
|
||||||
|
And finally launch the container
|
||||||
|
```
|
||||||
|
# -d will launch detached so the container runs in background
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
## Access from a mobile device
|
## Access from a mobile device
|
||||||
If you want to access Self-hosted LiveSync from mobile devices, you need a valid SSL certificate.
|
If you want to access Self-hosted LiveSync from mobile devices, you need a valid SSL certificate.
|
||||||
|
|
||||||
### Testing from a mobile
|
### Testing from a mobile
|
||||||
In the testing phase, [localhost.run](http://localhost.run/) or something like services is very useful.
|
In the testing phase, [localhost.run](https://localhost.run/) or something like services is very useful.
|
||||||
|
|
||||||
example on using localhost.run)
|
example using localhost.run:
|
||||||
```
|
```
|
||||||
$ ssh -R 80:localhost:5984 nokey@localhost.run
|
$ ssh -R 80:localhost:5984 nokey@localhost.run
|
||||||
Warning: Permanently added the RSA host key for IP address '35.171.254.69' to the list of known hosts.
|
Warning: Permanently added the RSA host key for IP address '35.171.254.69' to the list of known hosts.
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 6.4 KiB |
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"id": "obsidian-livesync",
|
"id": "obsidian-livesync",
|
||||||
"name": "Self-hosted LiveSync",
|
"name": "Self-hosted LiveSync",
|
||||||
"version": "0.19.2",
|
"version": "0.19.7",
|
||||||
"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",
|
||||||
|
|||||||
112
package-lock.json
generated
@@ -1,22 +1,22 @@
|
|||||||
{
|
{
|
||||||
"name": "obsidian-livesync",
|
"name": "obsidian-livesync",
|
||||||
"version": "0.19.2",
|
"version": "0.19.7",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "obsidian-livesync",
|
"name": "obsidian-livesync",
|
||||||
"version": "0.19.2",
|
"version": "0.19.7",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"diff-match-patch": "^1.0.5",
|
"diff-match-patch": "^1.0.5",
|
||||||
"esbuild": "0.15.15",
|
|
||||||
"esbuild-svelte": "^0.7.3",
|
|
||||||
"idb": "^7.1.1",
|
"idb": "^7.1.1",
|
||||||
"xxhash-wasm": "^0.4.2"
|
"xxhash-wasm": "^0.4.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@tsconfig/svelte": "^4.0.1",
|
||||||
"@types/diff-match-patch": "^1.0.32",
|
"@types/diff-match-patch": "^1.0.32",
|
||||||
|
"@types/node": "^20.2.5",
|
||||||
"@types/pouchdb": "^6.4.0",
|
"@types/pouchdb": "^6.4.0",
|
||||||
"@types/pouchdb-browser": "^6.1.3",
|
"@types/pouchdb-browser": "^6.1.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||||
@@ -39,11 +39,11 @@
|
|||||||
"pouchdb-mapreduce": "^8.0.1",
|
"pouchdb-mapreduce": "^8.0.1",
|
||||||
"pouchdb-replication": "^8.0.1",
|
"pouchdb-replication": "^8.0.1",
|
||||||
"pouchdb-utils": "^8.0.1",
|
"pouchdb-utils": "^8.0.1",
|
||||||
"svelte": "^3.55.1",
|
"svelte": "^3.59.1",
|
||||||
"svelte-preprocess": "^5.0.1",
|
"svelte-preprocess": "^5.0.3",
|
||||||
"transform-pouch": "^2.0.0",
|
"transform-pouch": "^2.0.0",
|
||||||
"tslib": "^2.5.0",
|
"tslib": "^2.5.0",
|
||||||
"typescript": "^4.9.5"
|
"typescript": "^5.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/state": {
|
"node_modules/@codemirror/state": {
|
||||||
@@ -203,6 +203,12 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tsconfig/svelte": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-B+XlGpmuAQzJqDoBATNCvEPqQg0HkO7S8pM14QDI5NsmtymzRexQ1N+nX2H6RTtFbuFgaZD4I8AAi8voGg0GLg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/codemirror": {
|
"node_modules/@types/codemirror": {
|
||||||
"version": "0.0.108",
|
"version": "0.0.108",
|
||||||
"resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.108.tgz",
|
"resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.108.tgz",
|
||||||
@@ -252,9 +258,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "14.17.21",
|
"version": "20.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz",
|
||||||
"integrity": "sha512-zv8ukKci1mrILYiQOwGSV4FpkZhyxQtuFWGya2GujWg+zVAeRQ4qbaMmWp9vb9889CFA8JECH7lkwCL6Ygg8kA==",
|
"integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/pouchdb": {
|
"node_modules/@types/pouchdb": {
|
||||||
@@ -443,15 +449,6 @@
|
|||||||
"integrity": "sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==",
|
"integrity": "sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/sass": {
|
|
||||||
"version": "1.43.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/sass/-/sass-1.43.1.tgz",
|
|
||||||
"integrity": "sha512-BPdoIt1lfJ6B7rw35ncdwBZrAssjcwzI5LByIrYs+tpXlj/CAkuVdRsgZDdP4lq5EjyWzwxZCqAoFyHKFwp32g==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@types/node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/semver": {
|
"node_modules/@types/semver": {
|
||||||
"version": "7.3.13",
|
"version": "7.3.13",
|
||||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
|
||||||
@@ -3719,23 +3716,22 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/svelte": {
|
"node_modules/svelte": {
|
||||||
"version": "3.55.1",
|
"version": "3.59.1",
|
||||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.55.1.tgz",
|
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.59.1.tgz",
|
||||||
"integrity": "sha512-S+87/P0Ve67HxKkEV23iCdAh/SX1xiSfjF1HOglno/YTbSTW7RniICMCofWGdJJbdjw3S+0PfFb1JtGfTXE0oQ==",
|
"integrity": "sha512-pKj8fEBmqf6mq3/NfrB9SLtcJcUvjYSWyePlfCqN9gujLB25RitWK8PvFzlwim6hD/We35KbPlRteuA6rnPGcQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/svelte-preprocess": {
|
"node_modules/svelte-preprocess": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.0.4.tgz",
|
||||||
"integrity": "sha512-0HXyhCoc9rsW4zGOgtInylC6qj259E1hpFnJMJWTf+aIfeqh4O/QHT31KT2hvPEqQfdjmqBR/kO2JDkkciBLrQ==",
|
"integrity": "sha512-ABia2QegosxOGsVlsSBJvoWeXy1wUKSfF7SWJdTjLAbx/Y3SrVevvvbFNQqrSJw89+lNSsM58SipmZJ5SRi5iw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/pug": "^2.0.6",
|
"@types/pug": "^2.0.6",
|
||||||
"@types/sass": "^1.43.1",
|
|
||||||
"detect-indent": "^6.1.0",
|
"detect-indent": "^6.1.0",
|
||||||
"magic-string": "^0.27.0",
|
"magic-string": "^0.27.0",
|
||||||
"sorcery": "^0.11.0",
|
"sorcery": "^0.11.0",
|
||||||
@@ -3754,8 +3750,8 @@
|
|||||||
"sass": "^1.26.8",
|
"sass": "^1.26.8",
|
||||||
"stylus": "^0.55.0",
|
"stylus": "^0.55.0",
|
||||||
"sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0",
|
"sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0",
|
||||||
"svelte": "^3.23.0",
|
"svelte": "^3.23.0 || ^4.0.0-next.0 || ^4.0.0",
|
||||||
"typescript": "^3.9.5 || ^4.0.0"
|
"typescript": ">=3.9.5 || ^4.0.0 || ^5.0.0"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"@babel/core": {
|
"@babel/core": {
|
||||||
@@ -3916,16 +3912,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "4.9.5",
|
"version": "5.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz",
|
||||||
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
"integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4.2.0"
|
"node": ">=12.20"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/unbox-primitive": {
|
"node_modules/unbox-primitive": {
|
||||||
@@ -4087,9 +4083,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/yaml": {
|
"node_modules/yaml": {
|
||||||
"version": "2.1.3",
|
"version": "2.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz",
|
||||||
"integrity": "sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg==",
|
"integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 14"
|
"node": ">= 14"
|
||||||
@@ -4233,6 +4229,12 @@
|
|||||||
"fastq": "^1.6.0"
|
"fastq": "^1.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@tsconfig/svelte": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-B+XlGpmuAQzJqDoBATNCvEPqQg0HkO7S8pM14QDI5NsmtymzRexQ1N+nX2H6RTtFbuFgaZD4I8AAi8voGg0GLg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/codemirror": {
|
"@types/codemirror": {
|
||||||
"version": "0.0.108",
|
"version": "0.0.108",
|
||||||
"resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.108.tgz",
|
"resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.108.tgz",
|
||||||
@@ -4282,9 +4284,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "14.17.21",
|
"version": "20.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz",
|
||||||
"integrity": "sha512-zv8ukKci1mrILYiQOwGSV4FpkZhyxQtuFWGya2GujWg+zVAeRQ4qbaMmWp9vb9889CFA8JECH7lkwCL6Ygg8kA==",
|
"integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/pouchdb": {
|
"@types/pouchdb": {
|
||||||
@@ -4473,15 +4475,6 @@
|
|||||||
"integrity": "sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==",
|
"integrity": "sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/sass": {
|
|
||||||
"version": "1.43.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/sass/-/sass-1.43.1.tgz",
|
|
||||||
"integrity": "sha512-BPdoIt1lfJ6B7rw35ncdwBZrAssjcwzI5LByIrYs+tpXlj/CAkuVdRsgZDdP4lq5EjyWzwxZCqAoFyHKFwp32g==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"@types/node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@types/semver": {
|
"@types/semver": {
|
||||||
"version": "7.3.13",
|
"version": "7.3.13",
|
||||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
|
||||||
@@ -6787,19 +6780,18 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"svelte": {
|
"svelte": {
|
||||||
"version": "3.55.1",
|
"version": "3.59.1",
|
||||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.55.1.tgz",
|
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.59.1.tgz",
|
||||||
"integrity": "sha512-S+87/P0Ve67HxKkEV23iCdAh/SX1xiSfjF1HOglno/YTbSTW7RniICMCofWGdJJbdjw3S+0PfFb1JtGfTXE0oQ==",
|
"integrity": "sha512-pKj8fEBmqf6mq3/NfrB9SLtcJcUvjYSWyePlfCqN9gujLB25RitWK8PvFzlwim6hD/We35KbPlRteuA6rnPGcQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"svelte-preprocess": {
|
"svelte-preprocess": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.0.4.tgz",
|
||||||
"integrity": "sha512-0HXyhCoc9rsW4zGOgtInylC6qj259E1hpFnJMJWTf+aIfeqh4O/QHT31KT2hvPEqQfdjmqBR/kO2JDkkciBLrQ==",
|
"integrity": "sha512-ABia2QegosxOGsVlsSBJvoWeXy1wUKSfF7SWJdTjLAbx/Y3SrVevvvbFNQqrSJw89+lNSsM58SipmZJ5SRi5iw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/pug": "^2.0.6",
|
"@types/pug": "^2.0.6",
|
||||||
"@types/sass": "^1.43.1",
|
|
||||||
"detect-indent": "^6.1.0",
|
"detect-indent": "^6.1.0",
|
||||||
"magic-string": "^0.27.0",
|
"magic-string": "^0.27.0",
|
||||||
"sorcery": "^0.11.0",
|
"sorcery": "^0.11.0",
|
||||||
@@ -6910,9 +6902,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "4.9.5",
|
"version": "5.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz",
|
||||||
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
"integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"unbox-primitive": {
|
"unbox-primitive": {
|
||||||
@@ -7047,9 +7039,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"yaml": {
|
"yaml": {
|
||||||
"version": "2.1.3",
|
"version": "2.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz",
|
||||||
"integrity": "sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg==",
|
"integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"yocto-queue": {
|
"yocto-queue": {
|
||||||
|
|||||||
14
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "obsidian-livesync",
|
"name": "obsidian-livesync",
|
||||||
"version": "0.19.2",
|
"version": "0.19.7",
|
||||||
"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",
|
||||||
@@ -13,7 +13,9 @@
|
|||||||
"author": "vorotamoroz",
|
"author": "vorotamoroz",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@tsconfig/svelte": "^4.0.1",
|
||||||
"@types/diff-match-patch": "^1.0.32",
|
"@types/diff-match-patch": "^1.0.32",
|
||||||
|
"@types/node": "^20.2.5",
|
||||||
"@types/pouchdb": "^6.4.0",
|
"@types/pouchdb": "^6.4.0",
|
||||||
"@types/pouchdb-browser": "^6.1.3",
|
"@types/pouchdb-browser": "^6.1.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||||
@@ -36,17 +38,15 @@
|
|||||||
"pouchdb-mapreduce": "^8.0.1",
|
"pouchdb-mapreduce": "^8.0.1",
|
||||||
"pouchdb-replication": "^8.0.1",
|
"pouchdb-replication": "^8.0.1",
|
||||||
"pouchdb-utils": "^8.0.1",
|
"pouchdb-utils": "^8.0.1",
|
||||||
"svelte": "^3.55.1",
|
"svelte": "^3.59.1",
|
||||||
"svelte-preprocess": "^5.0.1",
|
"svelte-preprocess": "^5.0.3",
|
||||||
"transform-pouch": "^2.0.0",
|
"transform-pouch": "^2.0.0",
|
||||||
"tslib": "^2.5.0",
|
"tslib": "^2.5.0",
|
||||||
"typescript": "^4.9.5"
|
"typescript": "^5.0.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"diff-match-patch": "^1.0.5",
|
"diff-match-patch": "^1.0.5",
|
||||||
"esbuild": "0.15.15",
|
|
||||||
"esbuild-svelte": "^0.7.3",
|
|
||||||
"idb": "^7.1.1",
|
"idb": "^7.1.1",
|
||||||
"xxhash-wasm": "^0.4.2"
|
"xxhash-wasm": "^0.4.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { writable } from 'svelte/store';
|
import { writable } from 'svelte/store';
|
||||||
import { Notice, PluginManifest, stringifyYaml, parseYaml } from "./deps";
|
import { Notice, type PluginManifest, parseYaml } from "./deps";
|
||||||
|
|
||||||
import { EntryDoc, LoadedEntry, LOG_LEVEL, InternalFileEntry, FilePathWithPrefix, FilePath, DocumentID } from "./lib/src/types";
|
import type { EntryDoc, LoadedEntry, InternalFileEntry, FilePathWithPrefix, FilePath, DocumentID, AnyEntry } from "./lib/src/types";
|
||||||
|
import { LOG_LEVEL } from "./lib/src/types";
|
||||||
import { ICXHeader, PERIODIC_PLUGIN_SWEEP, } from "./types";
|
import { ICXHeader, PERIODIC_PLUGIN_SWEEP, } from "./types";
|
||||||
import { delay, getDocData } from "./lib/src/utils";
|
import { Parallels, delay, getDocData } from "./lib/src/utils";
|
||||||
import { Logger } from "./lib/src/logger";
|
import { Logger } from "./lib/src/logger";
|
||||||
import { PouchDB } from "./lib/src/pouchdb-browser.js";
|
|
||||||
import { WrappedNotice } from "./lib/src/wrapper";
|
import { WrappedNotice } from "./lib/src/wrapper";
|
||||||
import { base64ToArrayBuffer, arrayBufferToBase64, readString, writeString, uint8ArrayToHexString } from "./lib/src/strbin";
|
import { base64ToArrayBuffer, arrayBufferToBase64, readString, uint8ArrayToHexString } from "./lib/src/strbin";
|
||||||
import { runWithLock } from "./lib/src/lock";
|
import { runWithLock } from "./lib/src/lock";
|
||||||
import { LiveSyncCommands } from "./LiveSyncCommands";
|
import { LiveSyncCommands } from "./LiveSyncCommands";
|
||||||
import { stripAllPrefixes } from "./lib/src/path";
|
import { stripAllPrefixes } from "./lib/src/path";
|
||||||
@@ -17,13 +17,29 @@ import { PluginDialogModal } from "./dialogs";
|
|||||||
import { JsonResolveModal } from "./JsonResolveModal";
|
import { JsonResolveModal } from "./JsonResolveModal";
|
||||||
|
|
||||||
|
|
||||||
|
function serialize<T>(obj: T): string {
|
||||||
|
return JSON.stringify(obj, null, 1);
|
||||||
|
}
|
||||||
|
function deserialize<T>(str: string, def: T) {
|
||||||
|
try {
|
||||||
|
return JSON.parse(str) as T;
|
||||||
|
} catch (ex) {
|
||||||
|
try {
|
||||||
|
return parseYaml(str);
|
||||||
|
} catch (ex) {
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export const pluginList = writable([] as PluginDataExDisplay[]);
|
export const pluginList = writable([] as PluginDataExDisplay[]);
|
||||||
export const pluginIsEnumerating = writable(false);
|
export const pluginIsEnumerating = writable(false);
|
||||||
|
|
||||||
|
const encoder = new TextEncoder();
|
||||||
const hashString = (async (key: string) => {
|
const hashString = (async (key: string) => {
|
||||||
const buff = writeString(key);
|
// const buff = writeString(key);
|
||||||
|
const buff = encoder.encode(key);
|
||||||
const digest = await crypto.subtle.digest('SHA-256', buff);
|
const digest = await crypto.subtle.digest('SHA-256', buff);
|
||||||
return uint8ArrayToHexString(new Uint8Array(digest));
|
return uint8ArrayToHexString(new Uint8Array(digest));
|
||||||
})
|
})
|
||||||
@@ -145,7 +161,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
if (this.plugin.suspended) {
|
if (this.plugin.suspended) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.settings.autoSweepPlugins) {
|
if (this.settings.autoSweepPlugins && this.settings.usePluginSync) {
|
||||||
await this.scanAllConfigFiles(false);
|
await this.scanAllConfigFiles(false);
|
||||||
}
|
}
|
||||||
this.periodicPluginSweepProcessor.enable(this.settings.autoSweepPluginsPeriodic && !this.settings.watchInternalFileChanges ? (PERIODIC_PLUGIN_SWEEP * 1000) : 0);
|
this.periodicPluginSweepProcessor.enable(this.settings.autoSweepPluginsPeriodic && !this.settings.watchInternalFileChanges ? (PERIODIC_PLUGIN_SWEEP * 1000) : 0);
|
||||||
@@ -171,7 +187,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
const entries = [] as PluginDataExDisplay[]
|
const entries = [] as PluginDataExDisplay[]
|
||||||
const plugins = this.localDatabase.findEntries(ICXHeader + "", `${ICXHeader}\u{10ffff}`, { include_docs: true });
|
const plugins = this.localDatabase.findEntries(ICXHeader + "", `${ICXHeader}\u{10ffff}`, { include_docs: true });
|
||||||
const semaphore = Semaphore(4);
|
const semaphore = Semaphore(4);
|
||||||
const processes = [] as Promise<void>[];
|
const para = Parallels();
|
||||||
let count = 0;
|
let count = 0;
|
||||||
pluginIsEnumerating.set(true);
|
pluginIsEnumerating.set(true);
|
||||||
let processed = false;
|
let processed = false;
|
||||||
@@ -184,16 +200,18 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
processed = true;
|
processed = true;
|
||||||
const oldEntry = (this.pluginList.find(e => e.documentPath == path));
|
const oldEntry = (this.pluginList.find(e => e.documentPath == path));
|
||||||
if (oldEntry && oldEntry.mtime == plugin.mtime) continue;
|
if (oldEntry && oldEntry.mtime == plugin.mtime) continue;
|
||||||
processes.push((async (v) => {
|
await para.wait(5);
|
||||||
|
para.add((async (v) => {
|
||||||
|
|
||||||
const release = await semaphore.acquire(1);
|
const release = await semaphore.acquire(1);
|
||||||
try {
|
try {
|
||||||
Logger(`Enumerating files... ${count++}`, logLevel, "get-plugins");
|
count++;
|
||||||
|
if (count % 10 == 0) Logger(`Enumerating files... ${count}`, logLevel, "get-plugins");
|
||||||
|
|
||||||
Logger(`plugin-${path}`, LOG_LEVEL.VERBOSE);
|
Logger(`plugin-${path}`, LOG_LEVEL.VERBOSE);
|
||||||
const wx = await this.localDatabase.getDBEntry(path, null, false, false);
|
const wx = await this.localDatabase.getDBEntry(path, null, false, false);
|
||||||
if (wx) {
|
if (wx) {
|
||||||
const data = parseYaml(getDocData(wx.data)) as PluginDataEx;
|
const data = deserialize(getDocData(wx.data), {}) as PluginDataEx;
|
||||||
const xFiles = [] as PluginDataExFile[];
|
const xFiles = [] as PluginDataExFile[];
|
||||||
for (const file of data.files) {
|
for (const file of data.files) {
|
||||||
const work = { ...file };
|
const work = { ...file };
|
||||||
@@ -217,7 +235,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
}
|
}
|
||||||
)(plugin));
|
)(plugin));
|
||||||
}
|
}
|
||||||
await Promise.all(processes);
|
await para.all();
|
||||||
let newList = [...this.pluginList];
|
let newList = [...this.pluginList];
|
||||||
for (const item of entries) {
|
for (const item of entries) {
|
||||||
newList = newList.filter(x => x.documentPath != item.documentPath);
|
newList = newList.filter(x => x.documentPath != item.documentPath);
|
||||||
@@ -241,9 +259,9 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
const docB = await this.localDatabase.getDBEntry(dataB.documentPath);
|
const docB = await this.localDatabase.getDBEntry(dataB.documentPath);
|
||||||
|
|
||||||
if (docA && docB) {
|
if (docA && docB) {
|
||||||
const pluginDataA = parseYaml(getDocData(docA.data)) as PluginDataEx;
|
const pluginDataA = deserialize(getDocData(docA.data), {}) as PluginDataEx;
|
||||||
pluginDataA.documentPath = dataA.documentPath;
|
pluginDataA.documentPath = dataA.documentPath;
|
||||||
const pluginDataB = parseYaml(getDocData(docB.data)) as PluginDataEx;
|
const pluginDataB = deserialize(getDocData(docB.data), {}) as PluginDataEx;
|
||||||
pluginDataB.documentPath = dataB.documentPath;
|
pluginDataB.documentPath = dataB.documentPath;
|
||||||
|
|
||||||
// Use outer structure to wrap each data.
|
// Use outer structure to wrap each data.
|
||||||
@@ -282,7 +300,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
if (dx == false) {
|
if (dx == false) {
|
||||||
throw "Not found on database"
|
throw "Not found on database"
|
||||||
}
|
}
|
||||||
const loadedData = parseYaml(getDocData(dx.data)) as PluginDataEx;
|
const loadedData = deserialize(getDocData(dx.data), {}) as PluginDataEx;
|
||||||
for (const f of loadedData.files) {
|
for (const f of loadedData.files) {
|
||||||
Logger(`Applying ${f.filename} of ${data.displayName || data.name}..`);
|
Logger(`Applying ${f.filename} of ${data.displayName || data.name}..`);
|
||||||
try {
|
try {
|
||||||
@@ -354,7 +372,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
async parseReplicationResultItem(docs: PouchDB.Core.ExistingDocument<EntryDoc>) {
|
async parseReplicationResultItem(docs: PouchDB.Core.ExistingDocument<EntryDoc>) {
|
||||||
if (docs._id.startsWith(ICXHeader)) {
|
if (docs._id.startsWith(ICXHeader)) {
|
||||||
if (this.plugin.settings.usePluginSync) {
|
if (this.plugin.settings.usePluginSync) {
|
||||||
await this.updatePluginList(false, docs.path ? docs.path : this.getPath(docs));
|
await this.updatePluginList(false, (docs as AnyEntry).path ? (docs as AnyEntry).path : this.getPath((docs as AnyEntry)));
|
||||||
}
|
}
|
||||||
if (this.plugin.settings.usePluginSync && this.plugin.settings.notifyPluginOrSettingUpdated) {
|
if (this.plugin.settings.usePluginSync && this.plugin.settings.notifyPluginOrSettingUpdated) {
|
||||||
if (!this.pluginDialog || (this.pluginDialog && !this.pluginDialog.isOpened())) {
|
if (!this.pluginDialog || (this.pluginDialog && !this.pluginDialog.isOpened())) {
|
||||||
@@ -497,7 +515,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
for (const target of fileTargets) {
|
for (const target of fileTargets) {
|
||||||
const data = await this.makeEntryFromFile(target);
|
const data = await this.makeEntryFromFile(target);
|
||||||
if (data == false) {
|
if (data == false) {
|
||||||
Logger(`Config: skipped: ${target} `, LOG_LEVEL.VERBOSE);
|
// Logger(`Config: skipped: ${target} `, LOG_LEVEL.VERBOSE);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (data.version) {
|
if (data.version) {
|
||||||
@@ -520,7 +538,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = stringifyYaml(dt);
|
const content = serialize(dt);
|
||||||
try {
|
try {
|
||||||
const old = await this.localDatabase.getDBEntryMeta(prefixedFileName, null, false);
|
const old = await this.localDatabase.getDBEntryMeta(prefixedFileName, null, false);
|
||||||
let saveData: LoadedEntry;
|
let saveData: LoadedEntry;
|
||||||
@@ -567,6 +585,7 @@ export class ConfigSync extends LiveSyncCommands {
|
|||||||
|
|
||||||
}
|
}
|
||||||
async watchVaultRawEventsAsync(path: FilePath) {
|
async watchVaultRawEventsAsync(path: FilePath) {
|
||||||
|
if (!this.settings.usePluginSync) return false;
|
||||||
if (!this.isTargetPath(path)) return false;
|
if (!this.isTargetPath(path)) return false;
|
||||||
const stat = await this.app.vault.adapter.stat(path);
|
const stat = await this.app.vault.adapter.stat(path);
|
||||||
// Make sure that target is a file.
|
// Make sure that target is a file.
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import { Notice, normalizePath, PluginManifest } from "./deps";
|
import { Notice, normalizePath, PluginManifest } from "./deps";
|
||||||
import { EntryDoc, LoadedEntry, LOG_LEVEL, InternalFileEntry, FilePathWithPrefix, FilePath } from "./lib/src/types";
|
import { EntryDoc, LoadedEntry, LOG_LEVEL, InternalFileEntry, FilePathWithPrefix, FilePath } from "./lib/src/types";
|
||||||
import { InternalFileInfo, ICHeader, ICHeaderEnd } from "./types";
|
import { InternalFileInfo, ICHeader, ICHeaderEnd } from "./types";
|
||||||
import { delay, isDocContentSame } from "./lib/src/utils";
|
import { Parallels, delay, isDocContentSame } from "./lib/src/utils";
|
||||||
import { Logger } from "./lib/src/logger";
|
import { Logger } from "./lib/src/logger";
|
||||||
import { PouchDB } from "./lib/src/pouchdb-browser.js";
|
import { PouchDB } from "./lib/src/pouchdb-browser.js";
|
||||||
import { disposeMemoObject, memoIfNotExist, memoObject, retrieveMemoObject, scheduleTask, isInternalMetadata, PeriodicProcessor } from "./utils";
|
import { disposeMemoObject, memoIfNotExist, memoObject, retrieveMemoObject, scheduleTask, isInternalMetadata, PeriodicProcessor } from "./utils";
|
||||||
import { WrappedNotice } from "./lib/src/wrapper";
|
import { WrappedNotice } from "./lib/src/wrapper";
|
||||||
import { base64ToArrayBuffer, arrayBufferToBase64 } from "./lib/src/strbin";
|
import { base64ToArrayBuffer, arrayBufferToBase64 } from "./lib/src/strbin";
|
||||||
import { runWithLock } from "./lib/src/lock";
|
import { runWithLock } from "./lib/src/lock";
|
||||||
import { Semaphore } from "./lib/src/semaphore";
|
|
||||||
import { JsonResolveModal } from "./JsonResolveModal";
|
import { JsonResolveModal } from "./JsonResolveModal";
|
||||||
import { LiveSyncCommands } from "./LiveSyncCommands";
|
import { LiveSyncCommands } from "./LiveSyncCommands";
|
||||||
import { addPrefix, stripAllPrefixes } from "./lib/src/path";
|
import { addPrefix, stripAllPrefixes } from "./lib/src/path";
|
||||||
@@ -254,37 +253,35 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
c = pieces.shift();
|
c = pieces.shift();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const p = [] as Promise<void>[];
|
|
||||||
const semaphore = Semaphore(10);
|
|
||||||
// Cache update time information for files which have already been processed (mainly for files that were skipped due to the same content)
|
// Cache update time information for files which have already been processed (mainly for files that were skipped due to the same content)
|
||||||
let caches: { [key: string]: { storageMtime: number; docMtime: number; }; } = {};
|
let caches: { [key: string]: { storageMtime: number; docMtime: number; }; } = {};
|
||||||
caches = await this.kvDB.get<{ [key: string]: { storageMtime: number; docMtime: number; }; }>("diff-caches-internal") || {};
|
caches = await this.kvDB.get<{ [key: string]: { storageMtime: number; docMtime: number; }; }>("diff-caches-internal") || {};
|
||||||
|
const filesMap = files.reduce((acc, cur) => {
|
||||||
|
acc[cur.path] = cur;
|
||||||
|
return acc;
|
||||||
|
}, {} as { [key: string]: InternalFileInfo; });
|
||||||
|
const filesOnDBMap = filesOnDB.reduce((acc, cur) => {
|
||||||
|
acc[stripAllPrefixes(this.getPath(cur))] = cur;
|
||||||
|
return acc;
|
||||||
|
}, {} as { [key: string]: InternalFileEntry; });
|
||||||
|
const para = Parallels();
|
||||||
for (const filename of allFileNames) {
|
for (const filename of allFileNames) {
|
||||||
if (!filename) continue;
|
|
||||||
processed++;
|
processed++;
|
||||||
if (processed % 100 == 0)
|
if (processed % 100 == 0) {
|
||||||
Logger(`Hidden file: ${processed}/${fileCount}`, logLevel, "sync_internal");
|
Logger(`Hidden file: ${processed}/${fileCount}`, logLevel, "sync_internal");
|
||||||
|
}
|
||||||
|
if (!filename) continue;
|
||||||
if (ignorePatterns.some(e => filename.match(e)))
|
if (ignorePatterns.some(e => filename.match(e)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const fileOnStorage = files.find(e => e.path == filename);
|
const fileOnStorage = filename in filesMap ? filesMap[filename] : undefined;
|
||||||
const fileOnDatabase = filesOnDB.find(e => stripAllPrefixes(this.getPath(e)) == filename);
|
const fileOnDatabase = filename in filesOnDBMap ? filesOnDBMap[filename] : undefined;
|
||||||
const addProc = async (p: () => Promise<void>): Promise<void> => {
|
|
||||||
const releaser = await semaphore.acquire(1);
|
|
||||||
try {
|
|
||||||
return p();
|
|
||||||
} catch (ex) {
|
|
||||||
Logger("Some process failed", logLevel);
|
|
||||||
Logger(ex);
|
|
||||||
} finally {
|
|
||||||
releaser();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const cache = filename in caches ? caches[filename] : { storageMtime: 0, docMtime: 0 };
|
const cache = filename in caches ? caches[filename] : { storageMtime: 0, docMtime: 0 };
|
||||||
|
|
||||||
p.push(addProc(async () => {
|
await para.wait(5);
|
||||||
const xFileOnStorage = fileOnStorage;
|
const proc = (async (xFileOnStorage: InternalFileInfo, xFileOnDatabase: InternalFileEntry) => {
|
||||||
const xFileOnDatabase = fileOnDatabase;
|
|
||||||
if (xFileOnStorage && xFileOnDatabase) {
|
if (xFileOnStorage && xFileOnDatabase) {
|
||||||
// Both => Synchronize
|
// Both => Synchronize
|
||||||
if ((direction != "pullForce" && direction != "pushForce") && xFileOnDatabase.mtime == cache.docMtime && xFileOnStorage.mtime == cache.storageMtime) {
|
if ((direction != "pullForce" && direction != "pushForce") && xFileOnDatabase.mtime == cache.docMtime && xFileOnStorage.mtime == cache.storageMtime) {
|
||||||
@@ -326,9 +323,11 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
throw new Error("Invalid state on hidden file sync");
|
throw new Error("Invalid state on hidden file sync");
|
||||||
// Something corrupted?
|
// Something corrupted?
|
||||||
}
|
}
|
||||||
}));
|
|
||||||
|
});
|
||||||
|
para.add(proc(fileOnStorage, fileOnDatabase))
|
||||||
}
|
}
|
||||||
await Promise.all(p);
|
await para.all();
|
||||||
await this.kvDB.set("diff-caches-internal", caches);
|
await this.kvDB.set("diff-caches-internal", caches);
|
||||||
|
|
||||||
// When files has been retrieved from the database. they must be reloaded.
|
// When files has been retrieved from the database. they must be reloaded.
|
||||||
@@ -495,7 +494,7 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
const mtime = new Date().getTime();
|
const mtime = new Date().getTime();
|
||||||
await runWithLock("file-" + prefixedFileName, false, async () => {
|
await runWithLock("file-" + prefixedFileName, false, async () => {
|
||||||
try {
|
try {
|
||||||
const old = await this.localDatabase.getDBEntry(prefixedFileName, null, false, false) as InternalFileEntry | false;
|
const old = await this.localDatabase.getDBEntryMeta(prefixedFileName, null, true) as InternalFileEntry | false;
|
||||||
let saveData: InternalFileEntry;
|
let saveData: InternalFileEntry;
|
||||||
if (old === false) {
|
if (old === false) {
|
||||||
saveData = {
|
saveData = {
|
||||||
@@ -541,7 +540,7 @@ export class HiddenFileSync extends LiveSyncCommands {
|
|||||||
try {
|
try {
|
||||||
// Check conflicted status
|
// Check conflicted status
|
||||||
//TODO option
|
//TODO option
|
||||||
const fileOnDB = await this.localDatabase.getDBEntry(prefixedFileName, { conflicts: true }, false, false);
|
const fileOnDB = await this.localDatabase.getDBEntry(prefixedFileName, { conflicts: true }, false, true);
|
||||||
if (fileOnDB === false)
|
if (fileOnDB === false)
|
||||||
throw new Error(`File not found on database.:${filename}`);
|
throw new Error(`File not found on database.:${filename}`);
|
||||||
// Prevent overwrite for Prevent overwriting while some conflicted revision exists.
|
// Prevent overwrite for Prevent overwriting while some conflicted revision exists.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { normalizePath, PluginManifest } from "./deps";
|
import { normalizePath, type PluginManifest } from "./deps";
|
||||||
import { DocumentID, EntryDoc, FilePathWithPrefix, LoadedEntry, LOG_LEVEL } from "./lib/src/types";
|
import type { DocumentID, EntryDoc, FilePathWithPrefix, LoadedEntry } from "./lib/src/types";
|
||||||
import { PluginDataEntry, PERIODIC_PLUGIN_SWEEP, PluginList, DevicePluginList, PSCHeader, PSCHeaderEnd } from "./types";
|
import { LOG_LEVEL } from "./lib/src/types";
|
||||||
|
import { type PluginDataEntry, PERIODIC_PLUGIN_SWEEP, type PluginList, type DevicePluginList, PSCHeader, PSCHeaderEnd } from "./types";
|
||||||
import { getDocData, isDocContentSame } from "./lib/src/utils";
|
import { getDocData, isDocContentSame } from "./lib/src/utils";
|
||||||
import { Logger } from "./lib/src/logger";
|
import { Logger } from "./lib/src/logger";
|
||||||
import { PouchDB } from "./lib/src/pouchdb-browser.js";
|
import { PouchDB } from "./lib/src/pouchdb-browser.js";
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { EntryDoc, ObsidianLiveSyncSettings, LOG_LEVEL, DEFAULT_SETTINGS } from "./lib/src/types";
|
import { type EntryDoc, type ObsidianLiveSyncSettings, LOG_LEVEL, DEFAULT_SETTINGS } from "./lib/src/types";
|
||||||
import { configURIBase } from "./types";
|
import { configURIBase } from "./types";
|
||||||
import { Logger } from "./lib/src/logger";
|
import { Logger } from "./lib/src/logger";
|
||||||
import { PouchDB } from "./lib/src/pouchdb-browser.js";
|
import { PouchDB } from "./lib/src/pouchdb-browser.js";
|
||||||
@@ -284,8 +284,22 @@ Of course, we are able to disable these features.`
|
|||||||
this.plugin.settings.syncAfterMerge = false;
|
this.plugin.settings.syncAfterMerge = false;
|
||||||
//this.suspendExtraSync();
|
//this.suspendExtraSync();
|
||||||
}
|
}
|
||||||
|
async askUseNewAdapter() {
|
||||||
|
if (!this.plugin.settings.useIndexedDBAdapter) {
|
||||||
|
const message = `Now this plugin has been configured to use the old database adapter for keeping compatibility. Do you want to deactivate it?`;
|
||||||
|
const CHOICE_YES = "Yes, disable and use latest";
|
||||||
|
const CHOICE_NO = "No, keep compatibility";
|
||||||
|
const choices = [CHOICE_YES, CHOICE_NO];
|
||||||
|
|
||||||
|
const ret = await confirmWithMessage(this.plugin, "Database adapter", message, choices, CHOICE_YES, 10);
|
||||||
|
if (ret == CHOICE_YES) {
|
||||||
|
this.plugin.settings.useIndexedDBAdapter = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
async fetchLocal() {
|
async fetchLocal() {
|
||||||
this.suspendExtraSync();
|
this.suspendExtraSync();
|
||||||
|
this.askUseNewAdapter();
|
||||||
await this.plugin.realizeSettingSyncMode();
|
await this.plugin.realizeSettingSyncMode();
|
||||||
await this.plugin.resetLocalDatabase();
|
await this.plugin.resetLocalDatabase();
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
@@ -313,6 +327,7 @@ Of course, we are able to disable these features.`
|
|||||||
}
|
}
|
||||||
async rebuildEverything() {
|
async rebuildEverything() {
|
||||||
this.suspendExtraSync();
|
this.suspendExtraSync();
|
||||||
|
this.askUseNewAdapter();
|
||||||
await this.plugin.realizeSettingSyncMode();
|
await this.plugin.realizeSettingSyncMode();
|
||||||
await this.plugin.resetLocalDatabase();
|
await this.plugin.resetLocalDatabase();
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Diff, DIFF_DELETE, DIFF_INSERT, diff_match_patch } from "diff-match-patch";
|
import { type Diff, DIFF_DELETE, DIFF_INSERT, diff_match_patch } from "diff-match-patch";
|
||||||
import type { FilePath, LoadedEntry } from "./lib/src/types";
|
import type { FilePath, LoadedEntry } from "./lib/src/types";
|
||||||
import { base64ToString } from "./lib/src/strbin";
|
import { base64ToString } from "./lib/src/strbin";
|
||||||
import { getDocData } from "./lib/src/utils";
|
import { getDocData } from "./lib/src/utils";
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import type { PluginDataExDisplay } from "./CmdConfigSync";
|
import type { PluginDataExDisplay } from "./CmdConfigSync";
|
||||||
import { Logger } from "./lib/src/logger";
|
import { Logger } from "./lib/src/logger";
|
||||||
import { versionNumberString2Number } from "./lib/src/strbin";
|
import { versionNumberString2Number } from "./lib/src/strbin";
|
||||||
import { FilePath, LOG_LEVEL } from "./lib/src/types";
|
import { type FilePath, LOG_LEVEL } from "./lib/src/types";
|
||||||
import { getDocData } from "./lib/src/utils";
|
import { getDocData } from "./lib/src/utils";
|
||||||
import type ObsidianLiveSyncPlugin from "./main";
|
import type ObsidianLiveSyncPlugin from "./main";
|
||||||
import { askString, scheduleTask } from "./utils";
|
import { askString, scheduleTask } from "./utils";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import ObsidianLiveSyncPlugin from "./main";
|
import ObsidianLiveSyncPlugin from "./main";
|
||||||
import { PluginDataExDisplay, pluginIsEnumerating, pluginList } from "./CmdConfigSync";
|
import { type PluginDataExDisplay, pluginIsEnumerating, pluginList } from "./CmdConfigSync";
|
||||||
import PluginCombo from "./PluginCombo.svelte";
|
import PluginCombo from "./PluginCombo.svelte";
|
||||||
export let plugin: ObsidianLiveSyncPlugin;
|
export let plugin: ObsidianLiveSyncPlugin;
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ export class StorageEventManagerObsidian extends StorageEventManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (this.plugin.settings.batchSave) {
|
if (this.plugin.settings.batchSave && !this.plugin.settings.liveSync) {
|
||||||
// if the latest event is the same type, omit that
|
// if the latest event is the same type, omit that
|
||||||
// a.md MODIFY <- this should be cancelled when a.md MODIFIED
|
// a.md MODIFY <- this should be cancelled when a.md MODIFIED
|
||||||
// b.md MODIFY <- this should be cancelled when b.md MODIFIED
|
// b.md MODIFY <- this should be cancelled when b.md MODIFIED
|
||||||
|
|||||||
2
src/lib
101
src/main.ts
@@ -1,10 +1,10 @@
|
|||||||
const isDebug = false;
|
const isDebug = false;
|
||||||
|
|
||||||
import { Diff, DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch } from "diff-match-patch";
|
import { type Diff, DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch } from "diff-match-patch";
|
||||||
import { debounce, Notice, Plugin, TFile, addIcon, TFolder, normalizePath, TAbstractFile, Editor, MarkdownView, RequestUrlParam, RequestUrlResponse, requestUrl } from "./deps";
|
import { debounce, Notice, Plugin, TFile, addIcon, TFolder, normalizePath, TAbstractFile, Editor, MarkdownView, type RequestUrlParam, type RequestUrlResponse, requestUrl } from "./deps";
|
||||||
import { EntryDoc, LoadedEntry, ObsidianLiveSyncSettings, diff_check_result, diff_result_leaf, EntryBody, LOG_LEVEL, VER, DEFAULT_SETTINGS, diff_result, FLAGMD_REDFLAG, SYNCINFO_ID, SALT_OF_PASSPHRASE, ConfigPassphraseStore, CouchDBConnection, FLAGMD_REDFLAG2, FLAGMD_REDFLAG3, PREFIXMD_LOGFILE, DatabaseConnectingStatus, EntryHasPath, DocumentID, FilePathWithPrefix, FilePath, AnyEntry } from "./lib/src/types";
|
import { type EntryDoc, type LoadedEntry, type ObsidianLiveSyncSettings, type diff_check_result, type diff_result_leaf, type EntryBody, LOG_LEVEL, VER, DEFAULT_SETTINGS, type diff_result, FLAGMD_REDFLAG, SYNCINFO_ID, SALT_OF_PASSPHRASE, type ConfigPassphraseStore, type CouchDBConnection, FLAGMD_REDFLAG2, FLAGMD_REDFLAG3, PREFIXMD_LOGFILE, type DatabaseConnectingStatus, type EntryHasPath, type DocumentID, type FilePathWithPrefix, type FilePath, type AnyEntry } from "./lib/src/types";
|
||||||
import { InternalFileInfo, queueItem, CacheData, FileEventItem, FileWatchEventQueueMax } from "./types";
|
import { type InternalFileInfo, type queueItem, type CacheData, type FileEventItem, FileWatchEventQueueMax } from "./types";
|
||||||
import { getDocData, isDocContentSame } from "./lib/src/utils";
|
import { getDocData, isDocContentSame, Parallels } from "./lib/src/utils";
|
||||||
import { Logger } from "./lib/src/logger";
|
import { Logger } from "./lib/src/logger";
|
||||||
import { PouchDB } from "./lib/src/pouchdb-browser.js";
|
import { PouchDB } from "./lib/src/pouchdb-browser.js";
|
||||||
import { LogDisplayModal } from "./LogDisplayModal";
|
import { LogDisplayModal } from "./LogDisplayModal";
|
||||||
@@ -22,9 +22,9 @@ import { addPrefix, isPlainText, shouldBeIgnored, stripAllPrefixes } from "./lib
|
|||||||
import { runWithLock } from "./lib/src/lock";
|
import { runWithLock } from "./lib/src/lock";
|
||||||
import { Semaphore } from "./lib/src/semaphore";
|
import { Semaphore } from "./lib/src/semaphore";
|
||||||
import { StorageEventManager, StorageEventManagerObsidian } from "./StorageEventManager";
|
import { StorageEventManager, StorageEventManagerObsidian } from "./StorageEventManager";
|
||||||
import { LiveSyncLocalDB, LiveSyncLocalDBEnv } from "./lib/src/LiveSyncLocalDB";
|
import { LiveSyncLocalDB, type LiveSyncLocalDBEnv } from "./lib/src/LiveSyncLocalDB";
|
||||||
import { LiveSyncDBReplicator, LiveSyncReplicatorEnv } from "./lib/src/LiveSyncReplicator";
|
import { LiveSyncDBReplicator, type LiveSyncReplicatorEnv } from "./lib/src/LiveSyncReplicator";
|
||||||
import { KeyValueDatabase, OpenKeyValueDatabase } from "./KeyValueDB";
|
import { type KeyValueDatabase, OpenKeyValueDatabase } from "./KeyValueDB";
|
||||||
import { LiveSyncCommands } from "./LiveSyncCommands";
|
import { LiveSyncCommands } from "./LiveSyncCommands";
|
||||||
import { HiddenFileSync } from "./CmdHiddenFileSync";
|
import { HiddenFileSync } from "./CmdHiddenFileSync";
|
||||||
import { SetupLiveSync } from "./CmdSetupLiveSync";
|
import { SetupLiveSync } from "./CmdSetupLiveSync";
|
||||||
@@ -87,7 +87,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
processReplication = (e: PouchDB.Core.ExistingDocument<EntryDoc>[]) => this.parseReplicationResult(e);
|
processReplication = (e: PouchDB.Core.ExistingDocument<EntryDoc>[]) => this.parseReplicationResult(e);
|
||||||
async connectRemoteCouchDB(uri: string, auth: { username: string; password: string }, disableRequestURI: boolean, passphrase: string | false, useDynamicIterationCount: boolean): Promise<string | { db: PouchDB.Database<EntryDoc>; info: PouchDB.Core.DatabaseInfo }> {
|
async connectRemoteCouchDB(uri: string, auth: { username: string; password: string }, disableRequestURI: boolean, passphrase: string | false, useDynamicIterationCount: boolean, performSetup: boolean, skipInfo: boolean): Promise<string | { db: PouchDB.Database<EntryDoc>; info: PouchDB.Core.DatabaseInfo }> {
|
||||||
if (!isValidRemoteCouchDBURI(uri)) return "Remote URI is not valid";
|
if (!isValidRemoteCouchDBURI(uri)) return "Remote URI is not valid";
|
||||||
if (uri.toLowerCase() != uri) return "Remote URI and database name could not contain capital letters.";
|
if (uri.toLowerCase() != uri) return "Remote URI and database name could not contain capital letters.";
|
||||||
if (uri.indexOf(" ") !== -1) return "Remote URI and database name could not contain spaces.";
|
if (uri.indexOf(" ") !== -1) return "Remote URI and database name could not contain spaces.";
|
||||||
@@ -104,6 +104,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
const conf: PouchDB.HttpAdapter.HttpAdapterConfiguration = {
|
const conf: PouchDB.HttpAdapter.HttpAdapterConfiguration = {
|
||||||
adapter: "http",
|
adapter: "http",
|
||||||
auth,
|
auth,
|
||||||
|
skip_setup: !performSetup,
|
||||||
fetch: async (url: string | Request, opts: RequestInit) => {
|
fetch: async (url: string | Request, opts: RequestInit) => {
|
||||||
let size = "";
|
let size = "";
|
||||||
const localURL = url.toString().substring(uri.length);
|
const localURL = url.toString().substring(uri.length);
|
||||||
@@ -192,6 +193,9 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
if (passphrase !== "false" && typeof passphrase === "string") {
|
if (passphrase !== "false" && typeof passphrase === "string") {
|
||||||
enableEncryption(db, passphrase, useDynamicIterationCount);
|
enableEncryption(db, passphrase, useDynamicIterationCount);
|
||||||
}
|
}
|
||||||
|
if (skipInfo) {
|
||||||
|
return { db: db, info: { db_name: "", doc_count: 0, update_seq: "" } };
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const info = await db.info();
|
const info = await db.info();
|
||||||
return { db: db, info: info };
|
return { db: db, info: info };
|
||||||
@@ -878,7 +882,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
|
|
||||||
async procFileEvent(applyBatch?: boolean) {
|
async procFileEvent(applyBatch?: boolean) {
|
||||||
if (!this.isReady) return;
|
if (!this.isReady) return;
|
||||||
if (this.settings.batchSave) {
|
if (this.settings.batchSave && !this.settings.liveSync) {
|
||||||
if (!applyBatch && this.vaultManager.getQueueLength() < FileWatchEventQueueMax) {
|
if (!applyBatch && this.vaultManager.getQueueLength() < FileWatchEventQueueMax) {
|
||||||
// Defer till applying batch save or queue has been grown enough.
|
// Defer till applying batch save or queue has been grown enough.
|
||||||
// or 30 seconds after.
|
// or 30 seconds after.
|
||||||
@@ -964,7 +968,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
async applyBatchChange() {
|
async applyBatchChange() {
|
||||||
if (this.settings.batchSave) {
|
if (this.settings.batchSave && !this.settings.liveSync) {
|
||||||
return await this.procFileEvent(true);
|
return await this.procFileEvent(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1364,8 +1368,8 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
// If `Read chunks online` is disabled, chunks should be transferred before here.
|
// If `Read chunks online` is disabled, chunks should be transferred before here.
|
||||||
// However, in some cases, chunks are after that. So, if missing chunks exist, we have to wait for them.
|
// However, in some cases, chunks are after that. So, if missing chunks exist, we have to wait for them.
|
||||||
if ((!this.settings.readChunksOnline) && "children" in doc) {
|
if ((!this.settings.readChunksOnline) && "children" in doc) {
|
||||||
const c = await this.localDatabase.collectChunksWithCache(doc.children)
|
const c = await this.localDatabase.collectChunksWithCache(doc.children as DocumentID[]);
|
||||||
const missing = c.filter((e) => !e.chunk).map((e) => e.id);
|
const missing = c.filter((e) => e.chunk === false).map((e) => e.id);
|
||||||
if (missing.length > 0) Logger(`${path} (${doc._id}, ${doc._rev}) Queued (waiting ${missing.length} items)`, LOG_LEVEL.VERBOSE);
|
if (missing.length > 0) Logger(`${path} (${doc._id}, ${doc._rev}) Queued (waiting ${missing.length} items)`, LOG_LEVEL.VERBOSE);
|
||||||
newQueue.missingChildren = missing;
|
newQueue.missingChildren = missing;
|
||||||
this.queuedFiles.push(newQueue);
|
this.queuedFiles.push(newQueue);
|
||||||
@@ -1381,15 +1385,15 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
const docsSorted = docs.sort((a, b) => b.mtime - a.mtime);
|
const docsSorted = docs.sort((a, b) => b.mtime - a.mtime);
|
||||||
L1:
|
L1:
|
||||||
for (const change of docsSorted) {
|
for (const change of docsSorted) {
|
||||||
|
if (isChunk(change._id)) {
|
||||||
|
await this.parseIncomingChunk(change);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
for (const proc of this.addOns) {
|
for (const proc of this.addOns) {
|
||||||
if (await proc.parseReplicationResultItem(change)) {
|
if (await proc.parseReplicationResultItem(change)) {
|
||||||
continue L1;
|
continue L1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isChunk(change._id)) {
|
|
||||||
await this.parseIncomingChunk(change);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (change._id == SYNCINFO_ID) {
|
if (change._id == SYNCINFO_ID) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1466,9 +1470,11 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
this.statusBar.title = e.syncStatus;
|
this.statusBar.title = e.syncStatus;
|
||||||
let waiting = "";
|
let waiting = "";
|
||||||
if (this.settings.batchSave) {
|
if (this.settings.batchSave && !this.settings.liveSync) {
|
||||||
waiting = " " + "🛫".repeat(this.vaultManager.getQueueLength());
|
const len = this.vaultManager.getQueueLength();
|
||||||
waiting = waiting.replace(/(🛫){10}/g, "🚀");
|
if (len != 0) {
|
||||||
|
waiting = ` 🛫${len}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let queued = "";
|
let queued = "";
|
||||||
const queue = Object.entries(e.queuedItems).filter((e) => !e[1].warned);
|
const queue = Object.entries(e.queuedItems).filter((e) => !e[1].warned);
|
||||||
@@ -1476,7 +1482,7 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
|
|
||||||
if (queuedCount) {
|
if (queuedCount) {
|
||||||
const pieces = queue.map((e) => e[1].missingChildren).reduce((prev, cur) => prev + cur.length, 0);
|
const pieces = queue.map((e) => e[1].missingChildren).reduce((prev, cur) => prev + cur.length, 0);
|
||||||
queued = ` 🧩 ${queuedCount} (${pieces})`;
|
queued = ` 🧩${queuedCount} (${pieces})`;
|
||||||
}
|
}
|
||||||
const processes = e.count;
|
const processes = e.count;
|
||||||
const processesDisp = processes == 0 ? "" : ` ⏳${processes}`;
|
const processesDisp = processes == 0 ? "" : ` ⏳${processes}`;
|
||||||
@@ -1488,19 +1494,20 @@ export default class ObsidianLiveSyncPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
return proc.substring(0, p);
|
return proc.substring(0, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
const pendingTask = e.pending.length
|
const pendingTask = e.pending.length
|
||||||
? "\nPending: " +
|
? e.pending.length < 10 ? ("\nPending: " +
|
||||||
Object.entries(e.pending.reduce((p, c) => ({ ...p, [getProcKind(c)]: (p[getProcKind(c)] ?? 0) + 1 }), {} as { [key: string]: number }))
|
Object.entries(e.pending.reduce((p, c) => ({ ...p, [getProcKind(c)]: (p[getProcKind(c)] ?? 0) + 1 }), {} as { [key: string]: number }))
|
||||||
.map((e) => `${e[0]}${e[1] == 1 ? "" : `(${e[1]})`}`)
|
.map((e) => `${e[0]}${e[1] == 1 ? "" : `(${e[1]})`}`)
|
||||||
.join(", ")
|
.join(", ")
|
||||||
: "";
|
) : `\n Pending: ${e.pending.length}` : "";
|
||||||
|
|
||||||
const runningTask = e.running.length
|
const runningTask = e.running.length
|
||||||
? "\nRunning: " +
|
? e.running.length < 10 ? ("\nRunning: " +
|
||||||
Object.entries(e.running.reduce((p, c) => ({ ...p, [getProcKind(c)]: (p[getProcKind(c)] ?? 0) + 1 }), {} as { [key: string]: number }))
|
Object.entries(e.running.reduce((p, c) => ({ ...p, [getProcKind(c)]: (p[getProcKind(c)] ?? 0) + 1 }), {} as { [key: string]: number }))
|
||||||
.map((e) => `${e[0]}${e[1] == 1 ? "" : `(${e[1]})`}`)
|
.map((e) => `${e[0]}${e[1] == 1 ? "" : `(${e[1]})`}`)
|
||||||
.join(", ")
|
.join(", ")
|
||||||
: "";
|
) : `\n Running: ${e.running.length}` : "";
|
||||||
this.setStatusBarText(message + pendingTask + runningTask);
|
this.setStatusBarText(message + pendingTask + runningTask);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1638,13 +1645,15 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
const filesStorageName = filesStorage.map((e) => e.path);
|
const filesStorageName = filesStorage.map((e) => e.path);
|
||||||
Logger("Collecting local files on the DB", LOG_LEVEL.VERBOSE);
|
Logger("Collecting local files on the DB", LOG_LEVEL.VERBOSE);
|
||||||
const filesDatabase = [] as FilePathWithPrefix[]
|
const filesDatabase = [] as FilePathWithPrefix[]
|
||||||
|
let count = 0;
|
||||||
for await (const doc of this.localDatabase.findAllNormalDocs()) {
|
for await (const doc of this.localDatabase.findAllNormalDocs()) {
|
||||||
|
count++;
|
||||||
|
if (count % 25 == 0) Logger(`Collecting local files on the DB: ${count}`, showingNotice ? LOG_LEVEL.NOTICE : LOG_LEVEL.INFO, "syncAll");
|
||||||
const path = getPath(doc);
|
const path = getPath(doc);
|
||||||
if (isValidPath(path) && this.isTargetFile(path)) {
|
if (isValidPath(path) && this.isTargetFile(path)) {
|
||||||
filesDatabase.push(path);
|
filesDatabase.push(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger("Opening the key-value database", LOG_LEVEL.VERBOSE);
|
Logger("Opening the key-value database", LOG_LEVEL.VERBOSE);
|
||||||
const isInitialized = await (this.kvDB.get<boolean>("initialized")) || false;
|
const isInitialized = await (this.kvDB.get<boolean>("initialized")) || false;
|
||||||
// Make chunk bigger if it is the initial scan. There must be non-active docs.
|
// Make chunk bigger if it is the initial scan. There must be non-active docs.
|
||||||
@@ -1663,25 +1672,23 @@ Or if you are sure know what had been happened, we can unlock the database from
|
|||||||
|
|
||||||
const runAll = async<T>(procedureName: string, objects: T[], callback: (arg: T) => Promise<void>) => {
|
const runAll = async<T>(procedureName: string, objects: T[], callback: (arg: T) => Promise<void>) => {
|
||||||
Logger(procedureName);
|
Logger(procedureName);
|
||||||
const semaphore = Semaphore(25);
|
|
||||||
if (!this.localDatabase.isReady) throw Error("Database is not ready!");
|
if (!this.localDatabase.isReady) throw Error("Database is not ready!");
|
||||||
const processes = objects.map(e => (async (v) => {
|
const para = Parallels();
|
||||||
const releaser = await semaphore.acquire(1, procedureName);
|
for (const v of objects) {
|
||||||
|
await para.wait(10);
|
||||||
|
para.add((async (v) => {
|
||||||
|
try {
|
||||||
|
await callback(v);
|
||||||
|
} catch (ex) {
|
||||||
|
Logger(`Error while ${procedureName}`, LOG_LEVEL.NOTICE);
|
||||||
|
Logger(ex);
|
||||||
|
}
|
||||||
|
})(v));
|
||||||
|
|
||||||
try {
|
|
||||||
await callback(v);
|
|
||||||
} catch (ex) {
|
|
||||||
Logger(`Error while ${procedureName}`, LOG_LEVEL.NOTICE);
|
|
||||||
Logger(ex);
|
|
||||||
} finally {
|
|
||||||
releaser();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)(e));
|
await para.all();
|
||||||
await Promise.all(processes);
|
|
||||||
|
|
||||||
Logger(`${procedureName} done.`);
|
Logger(`${procedureName} done.`);
|
||||||
};
|
}
|
||||||
|
|
||||||
await runAll("UPDATE DATABASE", onlyInStorage, async (e) => {
|
await runAll("UPDATE DATABASE", onlyInStorage, async (e) => {
|
||||||
Logger(`UPDATE DATABASE ${e.path}`);
|
Logger(`UPDATE DATABASE ${e.path}`);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { DataWriteOptions, normalizePath, TFile, Platform, TAbstractFile, App, Plugin_2, RequestUrlParam, requestUrl } from "./deps";
|
import { type DataWriteOptions, normalizePath, TFile, Platform, TAbstractFile, App, Plugin_2, type RequestUrlParam, requestUrl } from "./deps";
|
||||||
import { path2id_base, id2path_base, isValidFilenameInLinux, isValidFilenameInDarwin, isValidFilenameInWidows, isValidFilenameInAndroid, stripAllPrefixes } from "./lib/src/path";
|
import { path2id_base, id2path_base, isValidFilenameInLinux, isValidFilenameInDarwin, isValidFilenameInWidows, isValidFilenameInAndroid, stripAllPrefixes } from "./lib/src/path";
|
||||||
|
|
||||||
import { Logger } from "./lib/src/logger";
|
import { Logger } from "./lib/src/logger";
|
||||||
import { AnyEntry, DocumentID, EntryDoc, EntryHasPath, FilePath, FilePathWithPrefix, LOG_LEVEL, NewEntry } from "./lib/src/types";
|
import { type AnyEntry, type DocumentID, type EntryDoc, type EntryHasPath, type FilePath, type FilePathWithPrefix, LOG_LEVEL, type NewEntry } from "./lib/src/types";
|
||||||
import { CHeader, ICHeader, ICHeaderLength, PSCHeader } from "./types";
|
import { CHeader, ICHeader, ICHeaderLength, PSCHeader } from "./types";
|
||||||
import { InputStringDialog, PopoverSelectString } from "./dialogs";
|
import { InputStringDialog, PopoverSelectString } from "./dialogs";
|
||||||
import ObsidianLiveSyncPlugin from "./main";
|
import ObsidianLiveSyncPlugin from "./main";
|
||||||
@@ -535,7 +535,7 @@ export const localDatabaseCleanUp = async (plugin: ObsidianLiveSyncPlugin, force
|
|||||||
await performRebuildDB(plugin, "localOnly");
|
await performRebuildDB(plugin, "localOnly");
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
Logger("This feature requires enabling `Use new adapter`. Please enable it", LOG_LEVEL.NOTICE, "clean-up-db");
|
Logger("This feature requires disabling `Use an old adapter for compatibility`.", LOG_LEVEL.NOTICE, "clean-up-db");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -251,4 +251,8 @@ div.sls-setting-menu-btn {
|
|||||||
|
|
||||||
.sls-item-dirty::before {
|
.sls-item-dirty::before {
|
||||||
content: "✏";
|
content: "✏";
|
||||||
|
}
|
||||||
|
|
||||||
|
.sls-setting-hidden {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
{
|
{
|
||||||
|
"extends": "@tsconfig/svelte/tsconfig.json",
|
||||||
|
"inlineSourceMap": true,
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
@@ -6,6 +8,10 @@
|
|||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
|
"types": [
|
||||||
|
"svelte",
|
||||||
|
"node"
|
||||||
|
],
|
||||||
// "importsNotUsedAsValues": "error",
|
// "importsNotUsedAsValues": "error",
|
||||||
"importHelpers": false,
|
"importHelpers": false,
|
||||||
"alwaysStrict": true,
|
"alwaysStrict": true,
|
||||||
|
|||||||
38
updates.md
@@ -24,5 +24,43 @@ I hope you will give it a try.
|
|||||||
- Improved:
|
- Improved:
|
||||||
- Showing status is now thinned for performance.
|
- Showing status is now thinned for performance.
|
||||||
- Enhance caching while collecting chunks.
|
- Enhance caching while collecting chunks.
|
||||||
|
- 0.19.3
|
||||||
|
- Improved:
|
||||||
|
- Now replication will be paced by collecting chunks. If synchronisation has been deadlocked, please enable `Do not pace synchronization` once.
|
||||||
|
- 0.19.4
|
||||||
|
- Improved:
|
||||||
|
- Reduced remote database checking to improve speed and reduce bandwidth.
|
||||||
|
- Fixed:
|
||||||
|
- Chunks which previously misinterpreted are now interpreted correctly.
|
||||||
|
- No more missing chunks which not be found forever, except if it has been actually missing.
|
||||||
|
- Deleted file detection on hidden file synchronising now works fine.
|
||||||
|
- Now the Customisation sync is surely quiet while it has been disabled.
|
||||||
|
- 0.19.5
|
||||||
|
- Fixed:
|
||||||
|
- Now hidden file synchronisation would not be hanged, even if so many files exist.
|
||||||
|
- Improved:
|
||||||
|
- Customisation sync works more smoothly.
|
||||||
|
- Note: Concurrent processing has been rollbacked into the original implementation. As a result, the total number of processes is no longer shown next to the hourglass icon. However, only the processes that are running concurrently are shown.
|
||||||
|
- 0.19.6
|
||||||
|
- Fixed:
|
||||||
|
- Logging has been tweaked.
|
||||||
|
- No more too many planes and rockets.
|
||||||
|
- The batch database update now surely only works in non-live mode.
|
||||||
|
- Internal things:
|
||||||
|
- Some frameworks has been upgraded.
|
||||||
|
- Import declaration has been fixed.
|
||||||
|
- Improved:
|
||||||
|
- The plug-in now asks to enable a new adaptor, when rebuilding, if it is not enabled yet.
|
||||||
|
- The setting dialogue refined.
|
||||||
|
- Configurations for compatibilities have been moved under the hatch.
|
||||||
|
- Made it clear that disabled is the default.
|
||||||
|
- Ambiguous names configuration have been renamed.
|
||||||
|
- Items that have no meaning in the settings are no longer displayed.
|
||||||
|
- Some items have been reordered for clarity.
|
||||||
|
- Each configuration has been grouped.
|
||||||
|
- 0.19.7
|
||||||
|
- Fixed:
|
||||||
|
- The initial pane of Setting dialogue is now changed to General Settings.
|
||||||
|
- The Setup Wizard is now able to flush existing settings and get into the mode again.
|
||||||
|
|
||||||
... To continue on to `updates_old.md`.
|
... To continue on to `updates_old.md`.
|
||||||
|
|||||||