mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-07-23 04:52:58 +00:00
Complete Commonlib rc.6 integration and setup workflows
This commit is contained in:
+29
-25
@@ -1,34 +1,38 @@
|
||||
# How to add translations
|
||||
|
||||
Self-hosted LiveSync owns its multilingual catalogue. Commonlib supplies only the typed English messages which its services request; the plug-in combines those keys with its application messages and injects the selected translator at each service composition root.
|
||||
|
||||
## Getting ready
|
||||
|
||||
1. Clone the Commonlib repository, which owns the translation catalogue.
|
||||
```sh
|
||||
git clone https://github.com/vrtmrz/livesync-commonlib
|
||||
```
|
||||
2. Make `ls-debug` folder under your vault's `.obsidian` folder (as like `.../dev/.obsidian/ls-debug`).
|
||||
1. Clone this repository.
|
||||
|
||||
## Add translations for already defined terms
|
||||
```sh
|
||||
git clone https://github.com/vrtmrz/obsidian-livesync
|
||||
cd obsidian-livesync
|
||||
npm ci
|
||||
```
|
||||
|
||||
1. Install dependencies, and build the plug-in as dev. build.
|
||||
```sh
|
||||
cd livesync-commonlib
|
||||
npm ci
|
||||
npm run i18n:bake
|
||||
```
|
||||
2. Create an `ls-debug` directory below the test Vault's `.obsidian` directory, for example `.obsidian/ls-debug`.
|
||||
|
||||
2. Install the resulting packed Commonlib artefact in a Self-hosted LiveSync development checkout, build the plug-in, copy `main.js` to `.obsidian/plugins/obsidian-livesync` in your test Vault, and run Self-hosted LiveSync.
|
||||
3. You will get the `missing-translation-yyyy-mm-dd.jsonl`, please fill in new translations.
|
||||
4. Build the plug-in again, and confirm that displayed things were expected.
|
||||
5. Add the translations to the Commonlib catalogue, run `npm run i18n:bake`, and make the pull request to `https://github.com/vrtmrz/livesync-commonlib`.
|
||||
## Add translations for existing messages
|
||||
|
||||
## Make messages to be translated
|
||||
1. Edit the human-readable YAML files under `src/common/messagesYAML/`.
|
||||
2. Regenerate the JSON and TypeScript resources.
|
||||
|
||||
1. Find the message that you want to be translated.
|
||||
2. Change the literal to use `$tf`, like below.
|
||||
```diff
|
||||
- Logger("Could not determine passphrase to save data.json! You probably make the configuration sure again!", LOG_LEVEL_URGENT);
|
||||
+ Logger($tf('someKeyForPassphraseError'), LOG_LEVEL_URGENT);
|
||||
```
|
||||
3. Make the PR to `https://github.com/vrtmrz/obsidian-livesync`.
|
||||
4. Follow the steps of "Add translations for already defined terms" to add the translations.
|
||||
```sh
|
||||
npm run i18n:bake
|
||||
```
|
||||
|
||||
3. Build the plug-in in development mode, install it in the test Vault, and run Self-hosted LiveSync.
|
||||
4. Review any `missing-translation-yyyy-mm-dd.jsonl` file written below `.obsidian/ls-debug`, and add the required translations to the YAML catalogue.
|
||||
5. Bake and build again, then confirm the displayed text and placeholder substitution in the relevant workflow.
|
||||
|
||||
Commit the edited YAML and all regenerated JSON and TypeScript resources together.
|
||||
|
||||
## Make a message translatable
|
||||
|
||||
1. Add its canonical English entry and translations to `src/common/messagesYAML/`.
|
||||
2. Replace the source literal with `$msg()` or another existing translation helper, using the English catalogue key as the typed contract.
|
||||
3. Run `npm run i18n:bake`, build the plug-in, and verify the affected workflow.
|
||||
|
||||
When a new message belongs to Commonlib rather than the application, add its canonical English definition and key type in Commonlib first. Add any available translations to LiveSync when consuming that package; untranslated languages use Commonlib's canonical English fallback.
|
||||
|
||||
@@ -6,7 +6,7 @@ Accepted / Implemented
|
||||
|
||||
## Release
|
||||
|
||||
Not yet. Included in the 1.0.0 release preparation.
|
||||
Accepted — implemented as the maintained local E2E layer for the 1.0 release preparation.
|
||||
|
||||
## Context
|
||||
|
||||
@@ -148,9 +148,9 @@ Current verification:
|
||||
- `npm run test:e2e:obsidian:customisation-sync` verifies a two-vault Customisation Sync workflow: scan a real snippet CSS file, config JSON file, and sample plug-in fixture into per-file Customisation Sync data, synchronise them through CouchDB, apply them on the second vault, assert the resulting `.obsidian` files, propagate a snippet update, and verify deletion of the source-vault snippet sync data without confusing it with the target vault's own applied copy.
|
||||
- `npm run test:e2e:obsidian:setting-markdown-export` verifies that setting Markdown export creates a vault file and omits credentials when credential export is disabled.
|
||||
- `npm run test:e2e:obsidian:install-appimage` reuses the existing AppImage and extracted binary when they are already present.
|
||||
- `npm run test:e2e:obsidian:local-suite` runs the local verification sequence for the real Obsidian runner after CouchDB and MinIO have been started.
|
||||
- `npm run test:e2e:obsidian:local-suite:services` stops leftover CouchDB and MinIO fixtures, starts fresh fixtures, runs the local suite, and stops the fixtures again.
|
||||
- `npm run test:e2e:obsidian:local-suite:services` has been verified locally with real Obsidian, CouchDB, and MinIO. The run completed discovery, smoke, vault reflection, CouchDB upload, Object Storage upload, startup scan, two-vault synchronisation, Hidden File Sync, Customisation Sync, and setting Markdown export. The build step still emits existing Svelte warnings.
|
||||
- `npm run test:e2e:obsidian:local-suite` runs the local verification sequence for the real Obsidian runner after CouchDB, MinIO, and the P2P relay have been started.
|
||||
- `npm run test:e2e:obsidian:local-suite:services` stops leftover CouchDB, MinIO, and P2P relay fixtures, starts fresh fixtures, runs the local suite, and stops the fixtures again.
|
||||
- `npm run test:e2e:obsidian:local-suite:services` has been verified locally with real Obsidian and all three fixtures. In addition to the core launch and synchronisation scenarios, the maintained suite covers CouchDB, Object Storage, and P2P Setup URI workflows in which the working first device generates the URI imported by the second device.
|
||||
|
||||
Known limits:
|
||||
|
||||
@@ -200,7 +200,7 @@ Current implementation status:
|
||||
Current implementation status:
|
||||
|
||||
- The mocked Vitest browser suites, their P2P runner, their root-level relay helpers, and the manual `harness-ci` workflow have been removed after maintained suites covered the critical flows.
|
||||
- CouchDB and Object Storage combinations, with and without encryption, are owned by the CLI two-Vault matrix. P2P validation is owned by the CLI Compose E2E suite. Plug-in lifecycle and vault integration are owned by real Obsidian E2E.
|
||||
- Headless CouchDB and Object Storage combinations, with and without encryption, remain owned by the CLI two-Vault matrix. P2P transport replacement and relay lifecycle remain owned by the CLI Compose E2E suite. Real Obsidian owns the visible CouchDB, Object Storage, and P2P Setup URI workflows, including first-device URI generation, second-device import, and two-way Vault synchronisation.
|
||||
- The Obsidian compatibility implementation still needed by the Webapp has moved to `src/apps/webapp/obsidianMock.ts`; it is not a retained browser E2E Harness.
|
||||
- Remaining high-value scenarios, including RedFlag and Fast Setup (Simple Fetch) variants, should be added according to their owning integration boundary rather than copied line by line from the retired suite.
|
||||
|
||||
@@ -209,8 +209,8 @@ Current implementation status:
|
||||
Real Obsidian E2E is a local verification layer. It should not be wired into the default CI gate.
|
||||
|
||||
- Keep the scripts individually runnable for focused local debugging.
|
||||
- Provide `test:e2e:obsidian:local-suite` for a broader local pass after the CouchDB and MinIO fixtures have been started.
|
||||
- Provide `test:e2e:obsidian:local-suite:services` for a broader local pass that manages the CouchDB and MinIO fixtures itself.
|
||||
- Provide `test:e2e:obsidian:local-suite` for a broader local pass after the CouchDB, MinIO, and P2P relay fixtures have been started.
|
||||
- Provide `test:e2e:obsidian:local-suite:services` for a broader local pass that manages all three fixtures itself.
|
||||
- Use `OBSIDIAN_BINARY` when testing against an installed desktop application.
|
||||
- Use `test:e2e:obsidian:install-appimage` on Linux when a local AppImage copy is needed, and reuse the extracted `_testdata/obsidian/squashfs-root` directory between local runs.
|
||||
- Capture Obsidian logs, plug-in logs, vault snapshots, and service logs manually when investigating failures.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Status
|
||||
|
||||
Proposed — the implementation proof is complete, `@vrtmrz/livesync-commonlib@0.1.0-rc.2` has been published and verified as the exact downstream dependency, and the Community directory scanner preview confirms the intended package boundary.
|
||||
Accepted — the package boundary is implemented, published pre-release artefacts have been verified as exact downstream dependencies, and the Community directory scanner preview confirms the intended source boundary. Each later release candidate still requires immutable artefact and downstream validation.
|
||||
|
||||
## Context
|
||||
|
||||
@@ -107,11 +107,11 @@ In particular, event subscriptions, translation selection, offline-scan maps and
|
||||
|
||||
### Translation resources
|
||||
|
||||
Translation lookup is separated from the generated catalogue. Core services receive a narrow translator capability, or a service-context equivalent, instead of importing a process-global `$msg` implementation which statically owns every language.
|
||||
Translation lookup is separated from the application catalogue. Commonlib owns a typed canonical English definition for the messages requested by its services and uses it when a host omits the optional translator capability. This ensures that another consumer receives meaningful English rather than symbolic keys.
|
||||
|
||||
The first migration keeps language resources in the common-library repository and exposes them temporarily through the focused compatibility subpath `@vrtmrz/livesync-commonlib/compat/common/i18n`. Importing the root or `context` entry does not load the catalogue. Self-hosted LiveSync imports the catalogue and installs the translator at its composition root. A dedicated language subpath remains the preferred stable replacement once its contract has been narrowed.
|
||||
Self-hosted LiveSync owns the complete multilingual catalogue, generation tools, selected-language state, and translator implementation. It injects that translator into the Obsidian, CLI, and browser composition roots. Commonlib does not publish `compat/common/i18n`, `compat/common/rosetta`, generated language modules, or JSON catalogues.
|
||||
|
||||
This is initially one versioned npm package rather than two independently versioned packages. Message identifiers and their generated catalogue change together, so an immediate package split would add version coordination before the dependency direction is proven. A later `@vrtmrz/livesync-language` package is permitted when independent use or release cadence justifies it. Its dependency must point towards message contracts or core, never from core towards the catalogue.
|
||||
The canonical Commonlib key type and English fallback change with Commonlib. LiveSync may add translations for those keys without duplicating every English definition; its translator delegates absent keys to Commonlib's canonical English fallback. A separate language package remains possible only if independent consumers and release cadence later justify it; core must never depend on an application catalogue.
|
||||
|
||||
### Svelte dialogue hosting
|
||||
|
||||
@@ -232,7 +232,7 @@ Every retained barrel must correspond to an explicit `exports` entry, list named
|
||||
|
||||
- Replace `@lib/*` source aliases with package imports.
|
||||
- Remove the `src/lib` submodule, `_types`, `tsconfig.types.json`, `generate-types.mjs`, and release-workflow steps which regenerate fallback declarations.
|
||||
- Move common-library i18n tooling out of Self-hosted LiveSync release preparation.
|
||||
- Move the multilingual catalogue and its generation tooling into Self-hosted LiveSync, while retaining only Commonlib's typed English fallback in the package.
|
||||
- Keep application-owned source under `src/apps` until a separate decision moves an application.
|
||||
- Run the community scanner's branch or commit preview before releasing the converted plug-in.
|
||||
|
||||
@@ -245,15 +245,15 @@ Every retained barrel must correspond to an explicit `exports` entry, list named
|
||||
|
||||
## Implementation Proof
|
||||
|
||||
The package proof builds Commonlib as one compiled ESM package with a small root, `context`, `settings`, `remote-configurations`, `browser`, `node`, and `rpc` entries, plus the explicit compatibility exports required by the reviewed downstream revision from which it was built. It publishes neither raw TypeScript nor Svelte source. The immutable `@vrtmrz/livesync-commonlib@0.1.0-rc.2` registry artefact can be installed into a clean consumer, imported in Node, type-checked from declarations, and bundled independently for browser context, browser storage, browser services, and workers. Its registry version and checksum are recorded by release validation.
|
||||
The package proof builds Commonlib as one compiled ESM package with a small root, `context`, `settings`, `remote-configurations`, `browser`, `node`, and `rpc` entries, plus only the explicit compatibility exports required by the reviewed downstream inventory. It publishes neither raw TypeScript nor Svelte source, uses no unrestricted export wildcard, and can be installed into a clean consumer, imported in Node, type-checked from declarations, and bundled independently for browser context, browser storage, browser services, and workers. Release validation records and compares the immutable registry version and checksum.
|
||||
|
||||
The published export map contains 126 explicitly named entries, including 118 `compat/*` entries and no unrestricted wildcard. Every compatibility entry was referenced by the reviewed Self-hosted LiveSync source used to prepare the artefact. A final consumer audit then moved imports already covered by the focused `context`, `settings`, and `remote-configurations` entries. The current branch consequently uses 115 compatibility paths; `compat/common/models/setting.const.defaults`, `compat/common/models/setting.const.preferred`, and `compat/hub/hub` remain only as an immutable surplus in `rc.2`. They are candidates for removal from the next reviewed compatibility inventory rather than grounds for changing the published artefact. Remaining compatibility imports still expose migration-only service composition, broader model types, replication implementations, or another contract which the focused entries do not yet replace.
|
||||
The compatibility inventory is regenerated from the maintained Self-hosted LiveSync consumer. Focused entries replace compatibility imports when their contracts are proven; obsolete paths are removed from the next candidate rather than retained merely because an earlier immutable release contained them. The multilingual `common/i18n` and `common/rosetta` paths have been removed in this way after ownership moved to the host.
|
||||
|
||||
The proof found and fixed three boundary defects which source-alias consumption had hidden: compiled JSON imports required explicit output extensions, precompiled Svelte output could not safely be treated as source by the downstream Svelte pipeline, and Vite's default client conditions selected Commonlib's browser worker while building the Node CLI. Packed-consumer regressions cover the first two. The CLI now uses Vite's server conditions and treats every Node built-in reported by Commonlib's Node entry as external; the built CLI is exercised through Deno E2E. Importing root or context also no longer patches DOM prototypes, translator injection prevents the context entry from loading the complete language catalogue, and standard input and protocol output are supplied by the package-owned host contract rather than direct stream access in command handlers.
|
||||
|
||||
Self-hosted LiveSync, its CLI, Webapp, WebPeer, plug-in source, and tests compile against that exact registry artefact without `@lib/*`. Focused downstream storage tests pass against the package-owned Node and File System Access API implementations. Commonlib also owns the Trystero implementation and version; the host retains no direct Trystero dependency, preventing two transport generations from entering one application graph. The old `src/lib` Git submodule, generated `_types` fallback, type-generation scripts, and source aliases are removed by the proof branch.
|
||||
|
||||
The Commonlib contract suite passes 21 tests covering Context results, both platform storage implementations, and standard I/O; its complete suite passes 1,123 tests across 62 files. Self-hosted LiveSync's three host-composition contract tests and complete 342-test unit suite across 38 files pass against the registry artefact. The plug-in, CLI, Webapp, and WebPeer production builds also pass. The CLI contract command completes its nine-step Deno workflow against the built Node artefact.
|
||||
Commonlib's contract and complete suites cover Context results, both platform storage implementations, standard I/O, replication, settings, and package consumption. Self-hosted LiveSync runs the same host-composition result contract for Obsidian, CLI, and browser compositions against the exact packed artefact, followed by its unit, integration, application-build, CLI E2E, and focused real-Obsidian gates.
|
||||
|
||||
The package-owned Trystero transport also completes the canonical Compose P2P synchronisation workflow with a local relay and two isolated CLI peers. In real Obsidian, the plug-in starts with one consistent `ObsidianServiceContext`, the representative server-selection and Setup URI Svelte dialogues mount and close through their normal controls, their mobile variants satisfy viewport, safe-area, and touch-target assertions, and the settings pane exposes only the effective deletion controls. These runtime checks complement the package tests without making Webapp maintenance the primary release gate.
|
||||
|
||||
@@ -271,9 +271,9 @@ The 1.0 dependency review found two newly disclosed denial-of-service advisories
|
||||
|
||||
The remaining audit report is the existing `werift` and `werift-ice` dependency on `ip`, for which npm offers no patched version. The advisory concerns `ip.isPublic()` misclassifying unusual loopback representations. The locked werift implementation uses `ip` for address encoding, decoding, format detection, and loopback filtering, but does not call `isPublic()` or `isPrivate()`. LiveSync reaches werift only through the Node CLI's injected `RTCPeerConnection`; the Obsidian plug-in and browser applications use their platform WebRTC implementation, and the plug-in artefact does not contain werift. The package-level finding is therefore accepted for the 1.0 integration preview as a non-reachable advisory in the reviewed call path, not as a general waiver. Revisit it when werift or `ip` publishes a replacement, or before any change which delegates address trust, routing, or URL access decisions to that dependency.
|
||||
|
||||
The local real-Obsidian suite verifies the actual loaded `ObsidianServiceContext`, all 18 services, Vault reflection, CouchDB and Object Storage transfer, remote-activity accounting, CLI-to-Obsidian encrypted synchronisation, startup scanning, two-Vault create, update, delete, ordinary rename, case-only rename, target mismatch, Hidden File Sync, Customisation Sync, and setting Markdown export. These checks establish observable results and host composition rather than relying on declaration compatibility alone.
|
||||
The local real-Obsidian suite verifies the actual loaded `ObsidianServiceContext`, all 18 services, Vault reflection, CouchDB and Object Storage transfer, remote-activity accounting, CLI-to-Obsidian encrypted synchronisation, startup scanning, two-Vault create, update, delete, ordinary rename, case-only rename, target mismatch, Hidden File Sync, Customisation Sync, setting Markdown export, and two-device CouchDB, Object Storage, and P2P Setup URI workflows. These checks establish observable results and host composition rather than relying on declaration compatibility alone.
|
||||
|
||||
The current browser Harness has a pre-existing settings-migration initialisation timeout which reproduces on the untouched baseline. The Webapp Playwright workflow also currently reuses an unrelated process on its configured port and reaches a `Not Found` page. Neither failure is evidence for or against the package boundary. The Webapp production build and direct composition contract pass, while Webapp browser E2E remains supplementary until its runner is repaired. Current acceptance therefore relies primarily on Commonlib owner and packed-consumer tests, LiveSync unit and integration tests, Deno CLI E2E, application production builds, and the focused local real-Obsidian suite. The unrelated Harness and Playwright defects should be tracked independently.
|
||||
The obsolete mocked browser Harness and its `harness-ci` workflow have been removed. Webapp production builds and the direct browser composition contract remain part of the package-boundary proof; future Webapp browser automation is a Webapp-owned workflow rather than a substitute for real Obsidian E2E.
|
||||
|
||||
## Scanner and Repository Consequences
|
||||
|
||||
@@ -331,12 +331,11 @@ The following are later SDK-stabilisation gates, not blockers for accepting the
|
||||
- Community directory scanning distinguishes plug-in source from the reviewed dependency.
|
||||
- Changes which span the package and plug-in require coordinated package and downstream validation rather than one atomic source commit.
|
||||
- Temporary compatibility exports increase the first package surface, but their pre-1.0 status and explicit classification prevent them from becoming silent permanent contracts.
|
||||
- Translation, Svelte, and platform dependencies become optional composition concerns rather than root-package side effects.
|
||||
- Application translation, Svelte, and platform dependencies become optional composition concerns rather than root-package side effects; Commonlib's small English fallback remains safe by default.
|
||||
- Fancy Kit may gain a generally useful typed Obsidian Modal host without acquiring LiveSync policy or a mandatory Svelte dependency.
|
||||
|
||||
## Open Questions Before Acceptance
|
||||
## Later Open Questions
|
||||
|
||||
- Define the focused stable language entry point which will replace the temporary compatibility subpath.
|
||||
- Define the minimum conflict and conditional-write guarantees required by the first public high-level client.
|
||||
- Continue narrowing the broad model, service-composition, and replication compatibility paths as focused result contracts become available.
|
||||
- Confirm whether another Fancy Kit consumer needs the framework-neutral Modal host before it is added to the Kit, or whether LiveSync should pilot the contract first.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Status
|
||||
|
||||
Accepted — implemented and verified against the locked Commonlib package.
|
||||
Accepted — implemented and verified through Commonlib owner tests, the Compose transport suite, and the real-Obsidian setup workflow.
|
||||
|
||||
## Context
|
||||
|
||||
@@ -31,12 +31,12 @@ LiveSync does not call `close()` on the `RTCPeerConnection` values returned by `
|
||||
|
||||
The explicit disconnect operation therefore has the following contract:
|
||||
|
||||
| Resource | State after the operation |
|
||||
| --- | --- |
|
||||
| LiveSync P2P service and RPC room | Closed immediately. |
|
||||
| Trystero room membership | Left; room actions and advertisements are no longer available. |
|
||||
| Nostr relay WebSockets | Closed, with automatic reconnection paused. |
|
||||
| Underlying WebRTC peer | May remain idle under Trystero ownership for reuse, but cannot carry the departed room's traffic. |
|
||||
| Resource | State after the operation |
|
||||
| --------------------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| LiveSync P2P service and RPC room | Closed immediately. |
|
||||
| Trystero room membership | Left; room actions and advertisements are no longer available. |
|
||||
| Nostr relay WebSockets | Closed, with automatic reconnection paused. |
|
||||
| Underlying WebRTC peer | May remain idle under Trystero ownership for reuse, but cannot carry the departed room's traffic. |
|
||||
|
||||
This operation is a logical LiveSync disconnection and a physical signalling-server disconnection. It does not promise that every browser-owned WebRTC object has been destroyed synchronously.
|
||||
|
||||
@@ -46,6 +46,8 @@ Lifecycle operations on one `LiveSyncTrysteroReplicator` are serialised. A close
|
||||
|
||||
Relay sockets retain their Trystero-provided close handlers. LiveSync pauses relay reconnection, closes the sockets, and later resumes reconnection through Trystero's public functions. It does not replace `socket.onclose`, because Trystero uses that handler to retire and recreate shared relay clients correctly.
|
||||
|
||||
P2P setup follows the transport's actual ownership model. First-device initialisation resets and scans the local database, but does not attempt to lock, reset, or upload to a non-existent central remote database. Its confirmation dialogues therefore describe preparing this device and do not present the central-server overwrite warnings or remote-configuration option. An additional device performs one explicit peer-selection and finite Fetch pass, then resumes database and Vault reflection. The generic second convergence pass remains reserved for central remote types because repeating it for P2P would ask the user to select the same peer twice.
|
||||
|
||||
## Ownership
|
||||
|
||||
Commonlib owns the LiveSync-specific P2P service, RPC, command, and lifecycle composition. Trystero owns WebRTC peer creation, sharing, reuse, stale detection, and destruction, as well as relay-client reconstruction. The Self-hosted LiveSync host owns the current Commonlib service-feature result and supplies the platform services used by its current replicator.
|
||||
@@ -72,13 +74,13 @@ This interferes with Trystero's shared relay clients. The public pause and resum
|
||||
|
||||
## Verification
|
||||
|
||||
Commonlib unit tests prove that normal P2P host closure calls `room.leave()` without directly closing Trystero-owned peer connections. Additional package tests cover the action API, replaceable peer-event subscriptions, multiple RPC transport disposers, and serialised open and close operations.
|
||||
Commonlib unit tests prove that normal P2P host closure calls `room.leave()` without directly closing Trystero-owned peer connections. Additional package tests cover the action API, replaceable peer-event subscriptions, multiple RPC transport disposers, serialised open and close operations, local-only first-device initialisation, and one-pass additional-device Fetch.
|
||||
|
||||
Self-hosted LiveSync unit tests prove that settings and database replacement leave panes on the current replicator, and that an explicit P2P rebuild bypasses the policy intended for ordinary replication.
|
||||
|
||||
The canonical Compose P2P suite uses a real local Nostr relay and WebRTC implementation. It covers ordinary two-peer synchronisation, replacement of the active LiveSync replicator followed by discovery and transfer with the same peer, and explicit relay disconnection followed by paused and resumed reconnection. The lifecycle scenario is exposed only through a Docker test build and an injected CLI command runner; it is not part of the public CLI command surface.
|
||||
|
||||
A focused real-Obsidian test mounts the P2P status pane without a relay or remote peer, verifies its principal connection control and horizontal layout, and confirms normal process and fixture teardown. Transport replacement and relay lifecycle remain owned by the package and Compose tests rather than being duplicated in Obsidian.
|
||||
The real-Obsidian P2P Setup URI workflow creates the first device, generates the second-device URI from it, accepts each peer visibly, and verifies a two-way note round-trip through a local relay. A separate focused pane test covers the principal connection control and teardown without requiring a remote peer. Transport replacement and relay-socket lifecycle remain owned by the package and Compose tests rather than being duplicated in Obsidian.
|
||||
|
||||
## Consequences
|
||||
|
||||
|
||||
+17
-1
@@ -48,6 +48,22 @@ Use this path only when the remote database is new, or when this device is inten
|
||||
|
||||
Create an ordinary test note and allow it to upload before adding another device.
|
||||
|
||||
## Create a Setup URI for another device
|
||||
|
||||
Generate the additional-device Setup URI from the working first device. This captures the settings which that device is actually using, rather than asking another device to reuse the bootstrap URI produced during server provisioning.
|
||||
|
||||
1. Open the Obsidian command palette on the first device.
|
||||
2. Run `Self-hosted LiveSync: Copy settings as a new Setup URI`.
|
||||
3. Enter a new passphrase which will protect this Setup URI, then select `OK`.
|
||||
|
||||

|
||||
|
||||
4. Copy the resulting Setup URI, then select `OK`.
|
||||
|
||||

|
||||
|
||||
Store the new Setup URI and its passphrase separately. The URI is encrypted, but it contains credentials and Vault settings, so continue to protect it.
|
||||
|
||||
## Add another device
|
||||
|
||||
Start with a new or separately backed-up Vault. Do not use a production Vault containing unsynchronised notes unless you have reviewed the [Fast Setup choices](./tips/fast-setup.md).
|
||||
@@ -56,7 +72,7 @@ Start with a new or separately backed-up Vault. Do not use a production Vault co
|
||||
2. Open onboarding from the `Welcome to Self-hosted LiveSync` Notice.
|
||||
3. Select `I am adding a device to an existing synchronisation setup`, then confirm that you want to add the device.
|
||||
4. On `Device Setup Method`, select `Use a Setup URI (Recommended)`.
|
||||
5. Paste the same Setup URI, enter its Setup URI passphrase, and select `Test Settings and Continue`.
|
||||
5. Paste the new Setup URI generated by the first device, enter its Setup URI passphrase, and select `Test Settings and Continue`.
|
||||
6. Review `Setup Complete: Preparing to Fetch Synchronisation Data`, then select `Restart and Fetch Data`.
|
||||
|
||||

|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
# Set up Object Storage
|
||||
|
||||
This guide establishes Object Storage synchronisation on a first device, generates an additional-device Setup URI from that working device, and verifies synchronisation in both directions.
|
||||
|
||||
Object Storage uses the S3-compatible API. Prepare the following before starting:
|
||||
|
||||
- an HTTPS endpoint reachable by every device;
|
||||
- an access key and secret key with access to the selected bucket;
|
||||
- a bucket name and region;
|
||||
- a unique bucket prefix when the bucket is shared; and
|
||||
- separate passphrases for Vault encryption and Setup URI encryption.
|
||||
|
||||
Back up every Vault involved, and do not use Obsidian Sync, iCloud synchronisation, or another synchronisation service on the same Vault.
|
||||
|
||||
## Generate the bootstrap Setup URI
|
||||
|
||||
The public generator applies the Object Storage preset and records the connection as the selected remote profile. Run it from a trusted terminal:
|
||||
|
||||
```sh
|
||||
export remote_type=s3
|
||||
export endpoint=https://objects.example.com
|
||||
export access_key=<ACCESS KEY>
|
||||
export secret_key=<SECRET KEY>
|
||||
export bucket=vault-data
|
||||
export region=auto
|
||||
export bucket_prefix=my-vault
|
||||
export passphrase=<A STRONG VAULT ENCRYPTION PASSPHRASE>
|
||||
export uri_passphrase=<A SEPARATE SETUP URI PASSPHRASE>
|
||||
deno run --minimum-dependency-age=0 --allow-env https://raw.githubusercontent.com/vrtmrz/obsidian-livesync/main/utils/setup/generate_setup_uri.ts
|
||||
```
|
||||
|
||||
For providers which require them, set `force_path_style`, `use_custom_request_handler`, or `bucket_custom_headers` as described in the [setup utility reference](../utils/readme.md#object-storage).
|
||||
|
||||
Store the generated Setup URI and Setup URI passphrase separately. The URI is encrypted, but it contains the Object Storage credentials.
|
||||
|
||||
## Set up the first device
|
||||
|
||||
Use a new bucket prefix, or a prefix whose contents you deliberately intend to replace.
|
||||
|
||||
1. Install and enable Self-hosted LiveSync in the intended Vault.
|
||||
2. Open onboarding from the `Welcome to Self-hosted LiveSync` Notice.
|
||||
3. Select `I am setting this up for the first time`, then choose the recommended Setup URI method.
|
||||
4. Paste the bootstrap Setup URI, enter its passphrase, and select `Test Settings and Continue`.
|
||||
|
||||

|
||||
|
||||
5. Select `Restart and Initialise Server`, then read and accept the final overwrite confirmation only when this Vault is the intended source of truth.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
6. A new prefix may show `Fetch Remote Configuration Failed` because it has no saved configuration. Select `Skip and proceed` only for a genuinely new prefix. Otherwise, stop and check the endpoint, credentials, bucket, and prefix.
|
||||
|
||||

|
||||
|
||||
7. Keep optional features disabled until ordinary note synchronisation works.
|
||||
8. Create an ordinary test note, and keep Obsidian open until the LiveSync progress indicators have cleared.
|
||||
|
||||
## Generate the second-device Setup URI
|
||||
|
||||
Generate a fresh Setup URI from the working first device:
|
||||
|
||||
1. Run `Self-hosted LiveSync: Copy settings as a new Setup URI` from the command palette.
|
||||
2. Enter a new Setup URI passphrase.
|
||||
|
||||

|
||||
|
||||
3. Copy the resulting URI.
|
||||
|
||||

|
||||
|
||||
Store this URI and its passphrase separately.
|
||||
|
||||
## Add another device
|
||||
|
||||
Start with a new or separately backed-up Vault.
|
||||
|
||||
1. Install and enable Self-hosted LiveSync.
|
||||
2. Open onboarding, select `I am adding a device to an existing synchronisation setup`, and choose the recommended Setup URI method.
|
||||
3. Enter the URI generated by the first device and its passphrase.
|
||||
|
||||

|
||||
|
||||
4. Select `Restart and Fetch Data`.
|
||||
|
||||

|
||||
|
||||
5. For a new or empty Vault, choose `Overwrite all with remote files`, then `Keep local files even if not on remote`. Review the [Fast Setup guide](./tips/fast-setup.md) before choosing a different policy for a Vault containing local work.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
6. Keep Obsidian open until retrieval and file reflection finish.
|
||||
|
||||
Confirm that the first device's test note appears unchanged. Create a second ordinary note on the new device, wait for its journal synchronisation to finish, and confirm that it reaches the first device. Configure optional features only after this two-way check passes.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Safety notes
|
||||
|
||||
- Treat the endpoint, bucket, prefix, access key, secret key, Vault passphrase, Setup URI, and Setup URI passphrase as sensitive.
|
||||
- Use a distinct prefix per synchronisation set unless shared data is explicitly intended.
|
||||
- Do not select first-device initialisation against an existing prefix unless replacing its contents is deliberate.
|
||||
- Object Storage is not a Vault backup. Keep independent backups and test restoration separately.
|
||||
@@ -202,7 +202,7 @@ Store the Setup URI and its passphrase separately.
|
||||
|
||||
Follow [Quick setup](./quick_setup.md#set-up-the-first-device) for the first device. It covers the current onboarding Notice, Setup URI import, server initialisation, and the safety prompts shown for a newly provisioned database.
|
||||
|
||||
After ordinary note synchronisation works, follow [Add another device](./quick_setup.md#add-another-device). Configure optional features only after the normal path is verified; [Hidden File Sync has its own guide](./tips/hidden-file-sync.md).
|
||||
After ordinary note synchronisation works, [generate a new Setup URI on that first device](./quick_setup.md#create-a-setup-uri-for-another-device), then follow [Add another device](./quick_setup.md#add-another-device). Do not make the second device depend on retaining the provisioning-time bootstrap URI. Configure optional features only after the normal path is verified; [Hidden File Sync has its own guide](./tips/hidden-file-sync.md).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
# Set up peer-to-peer synchronisation
|
||||
|
||||
This guide establishes a peer-to-peer synchronisation set, generates the second-device Setup URI on the working first device, and verifies synchronisation in both directions with explicit peer approval.
|
||||
|
||||
Peer-to-peer synchronisation has no central copy of the Vault. At least one device containing the required data must be online when another device fetches it. A Nostr-compatible signalling relay helps devices discover each other, while the Vault data travels through the peer connection.
|
||||
|
||||
Before starting:
|
||||
|
||||
- back up both Vaults;
|
||||
- prepare a signalling relay reachable by both devices;
|
||||
- ensure the networks permit a WebRTC connection, or review the [P2P troubleshooting guidance](./tips/p2p-sync-tips.md);
|
||||
- disable every other synchronisation service for these Vaults; and
|
||||
- keep both devices awake and Obsidian open during the initial transfer.
|
||||
|
||||
## Generate the bootstrap Setup URI
|
||||
|
||||
Run the public generator from a trusted terminal. Supply your own relay for a controlled self-hosted setup:
|
||||
|
||||
```sh
|
||||
export remote_type=p2p
|
||||
export p2p_relays=wss://relay.example.com
|
||||
export p2p_room_id=<A PRIVATE ROOM ID> # Optional; generated when omitted
|
||||
export p2p_passphrase=<A PRIVATE P2P PASSPHRASE> # Optional; generated when omitted
|
||||
export passphrase=<A STRONG VAULT ENCRYPTION PASSPHRASE>
|
||||
export uri_passphrase=<A SEPARATE SETUP URI PASSPHRASE>
|
||||
deno run --minimum-dependency-age=0 --allow-env https://raw.githubusercontent.com/vrtmrz/obsidian-livesync/main/utils/setup/generate_setup_uri.ts
|
||||
```
|
||||
|
||||
The generated Setup URI contains the encrypted room, relay, and Vault settings. It deliberately omits the device-specific peer name. Store the URI and its passphrase separately.
|
||||
|
||||
## Set up the first device
|
||||
|
||||
1. Install and enable Self-hosted LiveSync in the intended Vault.
|
||||
2. Open onboarding from the `Welcome to Self-hosted LiveSync` Notice.
|
||||
3. Select `I am setting this up for the first time`, then choose the recommended Setup URI method.
|
||||
4. Paste the bootstrap Setup URI, enter its passphrase, and select `Test Settings and Continue`.
|
||||
|
||||

|
||||
|
||||
5. Complete the first-device initialisation and final confirmation. This initialises the local LiveSync database; P2P has no central remote database to erase.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
6. Keep optional features disabled until ordinary note synchronisation works.
|
||||
7. Open `Self-hosted LiveSync: Open P2P Replicator` from the command palette. Select `Open connection` if signalling is disconnected.
|
||||
|
||||

|
||||
|
||||
8. Create an ordinary test note and wait for the local LiveSync progress indicators to clear.
|
||||
|
||||
## Generate the second-device Setup URI
|
||||
|
||||
On the working first device:
|
||||
|
||||
1. Run `Self-hosted LiveSync: Copy settings as a new Setup URI` from the command palette.
|
||||
2. Enter a new Setup URI passphrase.
|
||||
|
||||

|
||||
|
||||
3. Copy the resulting URI.
|
||||
|
||||

|
||||
|
||||
Keep the first device online. Store the new URI and its passphrase separately.
|
||||
|
||||
## Add the second device
|
||||
|
||||
1. Install and enable Self-hosted LiveSync in a new or separately backed-up Vault.
|
||||
2. Open onboarding, select `I am adding a device to an existing synchronisation setup`, and choose the recommended Setup URI method.
|
||||
3. Enter the Setup URI generated by the first device and its passphrase.
|
||||
|
||||

|
||||
|
||||
4. Select `Restart and Fetch Data`.
|
||||
|
||||

|
||||
|
||||
5. For a new or empty Vault, choose `Overwrite all with remote files`, then `Keep local files even if not on remote`. Review the [Fast Setup guide](./tips/fast-setup.md) before using a Vault which contains local work.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
6. In `P2P Rebuild`, confirm that the expected first-device name is shown, then select `Sync`.
|
||||
|
||||

|
||||
|
||||
7. On the first device, verify the requesting device name and select `Accept`. Use `Accept Temporarily` instead when approval should last only for this Obsidian session.
|
||||
|
||||

|
||||
|
||||
8. Keep both devices open until the test note appears on the second device.
|
||||
|
||||

|
||||
|
||||
## Verify the return journey
|
||||
|
||||
Create a second ordinary note on the second device. With automatic broadcast disabled, start the next finite synchronisation explicitly:
|
||||
|
||||
1. Open the P2P Replicator pane on both devices.
|
||||
2. If the previous finite peer connection no longer appears, select `Disconnect` and then `Open connection` on the first device, followed by the second device. The device which joins last is advertised to devices already in the room.
|
||||
3. On the first device, select `Refresh`, verify the second-device name, then select `Replicate now`.
|
||||
4. On the second device, verify the requesting first-device name and select `Accept` or `Accept Temporarily`.
|
||||
|
||||

|
||||
|
||||
5. Confirm that the second-device note appears unchanged on the first device.
|
||||
|
||||

|
||||
|
||||
The two devices are now proven to share the same room, encryption settings, and data format in both directions. Configure automatic start, automatic broadcast, or optional features separately after this manual path works.
|
||||
|
||||
## If a peer does not appear
|
||||
|
||||
- Confirm that both panes show `Connected` and the same Room ID suffix.
|
||||
- Select `Refresh` after the other device joins.
|
||||
- Reconnect the device which should be discovered last.
|
||||
- Check that the Setup URI came from the working first device and that neither device copied a peer name manually.
|
||||
- Check relay reachability, WebRTC restrictions, VPNs, and TURN considerations in [Peer-to-Peer Synchronisation Tips](./tips/p2p-sync-tips.md).
|
||||
@@ -10,6 +10,8 @@ authors:
|
||||
|
||||
# Peer-to-Peer Synchronisation Tips
|
||||
|
||||
For the complete first-device, Setup URI, second-device, and two-way verification procedure, see [Set up peer-to-peer synchronisation](../setup_p2p.md).
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Peer-to-peer synchronisation is a supported opt-in feature. WebRTC connectivity still depends on the networks, relays, and optional TURN servers available to every device, so a working connection cannot be guaranteed in every environment.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user