- TypeScript 93.3%
- JavaScript 3.7%
- Shell 1.8%
- Dockerfile 1.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .ci | ||
| .forgejo/workflows | ||
| .github | ||
| .woodpecker | ||
| dat | ||
| hack | ||
| lib@5acae2f988 | ||
| runtime | ||
| script | ||
| scripts | ||
| stubs | ||
| test | ||
| types | ||
| .dockerignore | ||
| .gitignore | ||
| .gitmodules | ||
| .mise.toml | ||
| .prettierignore | ||
| docker-compose.yml | ||
| Dockerfile | ||
| eslint.config.js | ||
| Hub.ts | ||
| main.ts | ||
| package.json | ||
| Peer.ts | ||
| PeerCouchDB.ts | ||
| PeerStorage.ts | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| readme.md | ||
| tsconfig.json | ||
| types.ts | ||
| util.ts | ||
| vitest.config.ts | ||
LiveSync Bridge
m0sh1.cc fork
This Forgejo-first fork is maintained for the m0sh1.cc self-hosted LiveSync
tooling stack. The canonical repository is
https://git.m0sh1.cc/isityael/livesync-bridge; GitHub is maintained as a public
push mirror at https://github.com/isityael/livesync-bridge.
What is this?
This is a custom replicator between Self-hosted LiveSync remote vaults and storage. The Unified Version of filesystem-livesync and livesync-classroom.
A Vault or storage can be synchronised with vaults or storage. You can even combine them. Of course, different passphrases for each vault could be used. And, you can synchronize documents under the specified folder on the vault, to another vault's specified one.
Of course, it is multi-directional!
How to use
Prerequisites
- Node.js 26 and PNPM 11 via Corepack are required.
Simply run
- Clone the GitHub Repository
git clone --recursive https://github.com/isityael/livesync-bridge
- Open the config file dat/config.sample.json, edit and save to dat/config.json. (You do not have to worry, the sample is in the following section).
- Simply run like this.
$ corepack enable
$ pnpm install --frozen-lockfile
$ pnpm run build
$ pnpm start
Note: If you want to scan all storage and databases from the beginning, please run with --reset.
Docker Instructions
- Clone the GitHub Repository
git clone --recursive https://github.com/isityael/livesync-bridge
-
Open the config file dat/config.sample.json, edit and save to dat/config.json. (The storage folder has to start with "data/" to be in the volume)
-
Simply run like this.
docker compose up -d
The sole canonical container image is
ghcr.io/isityael/livesync-bridge. The GitHub publication workflow blocks
critical vulnerabilities on the immutable digest, keylessly signs that digest,
and only then applies canonical tags. The image is built once with BuildKit
provenance and an SBOM.
Health and recovery
GET /healthz listens on port 8080 by default. Set LSB_HEALTH_PORT to
change the port. Kubernetes startup, readiness, and liveness probes may use the
same path: only healthy returns HTTP 200; startup, stale, and unhealthy
return HTTP 503. The response includes phase, checkpoint and remote-activity
times, conflict count, and replay state, but never credentials or note content.
Persist LSB_STATE_DIR across restarts. Malformed state is quarantined and
forces a full remote replay before local tombstones can be sent. Replay and
watch callbacks are processed durably in sequence; a failed destination write
does not advance the checkpoint. Each CouchDB destination has its own confirmed
baseline and per-checkpoint tombstone budget. Additional controls are:
LSB_MAX_CONSECUTIVE_FAILURES(default3)LSB_RETRY_DELAY_MS(default10000)LSB_STALE_AFTER_MS(default300000)LSB_MAX_TOMBSTONES_PER_CHECKPOINT(default10)
Configuration
The configuration file consists of the following structure.
{
"peers": [
{
"type": "couchdb", // Type should be `couchdb or storage`
"name": "test1", // Should be unique
"group": "main", // we can omit this.
"database": "test",
"username": "admin",
"password": "password",
"url": "http://localhost:5984",
"customChunkSize": 100,
"minimumChunkSize": 20,
"passphrase": "passphrase", // E2EE passphrase, if you do not enabled, leave it blank.
"obfuscatePassphrase": "passphrase", // Path obfuscation passphrase, if you do not enabled, leave it blank. if enabled, set the same value of passphrase.
"baseDir": "blog/", // Sharing folder
"useRemoteTweaks": true, // Overwrite customChunkSize or minimumChunkSize, and check configuration matches
},
{
"type": "couchdb",
"name": "test2", // We can even synchronise the same databases as long as they have different names in here.
"group": "main", // we can omit this.
"database": "test2",
"username": "admin",
"passphrase": "passphrase",
"password": "password",
"url": "http://localhost:5984",
"customChunkSize": 100,
"minimumChunkSize": 20,
"obfuscatePassphrase": "passphrase",
"baseDir": "xxxx/",
},
{
"type": "storage",
"name": "storage-test1",
"group": "main", // we can omit this.
"baseDir": "./vault/", // The folder which have been synchronised.
"processor": {
// The processor configuration. You can omit this.
"cmd": "script/test.sh", // The programme which run at file modification or deletion.
"args": ["$filename", "$mode"],
// The modified file is set to $filename. The mode is set to `deleted` or `modified`.
// $filename and $mode have been set also in environment variables.
},
"scanOfflineChanges": true,
"useChokidar": true, // Node runtime uses chokidar for filesystem watching.
},
],
}
Realistic example
| name | database_uri / path | CouchDB username | CouchDB password | vault E2EE passphrase | baseDir |
|---|---|---|---|---|---|
| private vault of Cornbread | http://localhost:5984/classroom_cornbread | cornbread | tackle | glucose | shared/ |
| shared vault | http://localhost:5984/classroom_shared | common_user | resu_nommoc | cocoa | |
| private vault of Vanilla | http://localhost:5984/classroom_vanilla | vanilla | liberty | smock | kyouyuu/ |
| storage | ./vault/ |
Cornbread's every document under "shared" is synchronized with the top of the shared vault:
| Cornbread | shared |
|---|---|
| document1 | Not transferred |
| document2 | Not transferred |
| shared/shared_doc1 | shared_doc1 |
| shared/sub/sub_doc | sub/sub_doc |
Vanilla's every document under "kyouyuu" is synchronized with the top of the shared vault:
| Vanilla | shared |
|---|---|
| documentA | Not transferred |
| documentB | Not transferred |
| kyouyuu/some_doc | some_doc |
| kyouyuu/sub/some_sub_doc | sub/some_sub_doc |
Totally, all files are synchronized like this:
| Cornbread | shared | Vanilla |
|---|---|---|
| document1 | Not transferred | |
| document2 | Not transferred | |
| Not transferred | documentA | |
| Not transferred | documentB | |
| shared/shared_doc1 | shared_doc1 | kyouyuu/shared_doc1 |
| shared/some_doc | some_doc | kyouyuu/some_doc |
| shared/sub/some_sub_doc | sub/some_sub_doc | kyouyuu/sub/some_sub_doc |
| shared/sub/sub_doc | sub/sub_doc | kyouyuu/sub/sub_doc |
... with the configuration below:
{
"peers": [
{
"type": "couchdb", // Type should be `couchdb or storage`
"name": "cornbread", // Should be unique
"url": "http://localhost:5984",
"database": "classroom_cornbread",
"username": "cornbread",
"password": "tackle",
"passphrase": "glucose", // E2EE passphrase, if you do not enabled, leave it blank.
"obfuscatePassphrase": "glucose", // Path obfuscation passphrase, if you do not enabled, leave it blank. if enabled, set the same value of passphrase.
"customChunkSize": 100,
"minimumChunkSize": 20,
"baseDir": "shared/", // Sharing folder
},
{
"type": "couchdb", // Type should be `couchdb or storage`
"name": "shared", // Should be unique
"url": "http://localhost:5984",
"database": "classroom_shared",
"username": "common_user",
"password": "resu_nommoc",
"passphrase": "cocoa", // E2EE passphrase, if you do not enabled, leave it blank.
"obfuscatePassphrase": "cocoa", // Path obfuscation passphrase, if you do not enabled, leave it blank. if enabled, set the same value of passphrase.
"customChunkSize": 100,
"minimumChunkSize": 20,
"baseDir": "", // Sharing folder
},
{
"type": "couchdb",
"name": "vanilla", // We can even synchronise the same databases as long as they have different names in here.
"url": "http://localhost:5984",
"database": "classroom_vanilla",
"username": "vanilla",
"password": "liberty",
"passphrase": "smock",
"obfuscatePassphrase": "smock",
"customChunkSize": 100,
"minimumChunkSize": 20,
"baseDir": "kyouyuu/",
},
{
"type": "storage",
"name": "storage-test1",
"baseDir": "./vault/", // The folder which have been synchronised.
},
],
}