From b21c3114e5242158c74169d30d3358f72ea09de1 Mon Sep 17 00:00:00 2001 From: vorotamoroz Date: Thu, 30 Jul 2026 05:53:42 +0000 Subject: [PATCH] fix: clarify browser application guidance --- src/apps/webapp/README.md | 72 +++++++++++++++++- .../FSAPIStorageEventManagerAdapter.ts | 10 ++- src/apps/webpeer/README.md | 74 +++++++++++++++++-- ...APIStorageEventManagerAdapter.unit.spec.ts | 34 +++++++++ updates.md | 3 +- 5 files changed, 180 insertions(+), 13 deletions(-) create mode 100644 test/apps/webapp/FSAPIStorageEventManagerAdapter.unit.spec.ts diff --git a/src/apps/webapp/README.md b/src/apps/webapp/README.md index beead82a..46143129 100644 --- a/src/apps/webapp/README.md +++ b/src/apps/webapp/README.md @@ -2,15 +2,39 @@ WebApp is an experimental proof of concept for running Self-hosted LiveSync against a browser-authorised local Vault. It is not a replacement for the Obsidian plug-in, and it does not provide the plug-in's settings screen, command palette, or setup wizard. +## Capabilities + +- Runs as a static application in the browser. +- Reads and writes a user-selected Vault through the File System Access API. +- Keeps previously selected directory handles in origin-scoped IndexedDB. +- Loads and saves LiveSync settings in `.livesync/settings.json` inside the selected Vault. +- Uses CouchDB as its primary continuous remote. +- Provides optional P2P controls as a secondary connection. +- Scans the Vault on start-up and when **Scan local files** is selected. +- Watches external file changes automatically when `FileSystemObserver` is available. + +The WebApp itself does not require an application server, but synchronisation still requires a compatible remote or P2P peer. + +## Requirements + +WebApp requires: + +- a secure context, such as HTTPS or `localhost`; +- `showDirectoryPicker()` and read-write access to the selected directory; +- IndexedDB for saved directory handles and the local database; and +- a CouchDB server which permits requests from the WebApp origin when CouchDB is used. + +Automated browser coverage uses Chromium. Other browsers, background execution, and remote types other than CouchDB remain experimental. Use feature detection rather than relying on a fixed browser-version list. + ## Use -WebApp requires a browser which provides the File System Access API and IndexedDB. Serve the built files over HTTPS, or from `localhost`, then open `webapp.html`. +Serve the built files over HTTPS, or from `localhost`, then open `webapp.html`. 1. Select the local Vault root. 2. Create or edit `.livesync/settings.json` in that Vault. 3. Reload WebApp to apply the settings. -For example, a manually configured CouchDB connection includes: +For example, a minimal manually configured CouchDB connection includes: ```json { @@ -24,9 +48,47 @@ For example, a manually configured CouchDB connection includes: } ``` -The visible P2P controls are optional. Saving them does not select P2P as the main remote or mark an otherwise unconfigured Vault as configured. +The settings must match the remote database, including any encryption and compatibility settings which are already in use. The file may contain credentials and passphrases, so protect it accordingly. Review individual values instead of copying an Obsidian `data.json` file wholesale. -CouchDB must permit access from the WebApp origin. Other remote types, browser background behaviour, and browsers without the required file-system APIs remain experimental. +### Optional P2P + +The visible P2P controls are optional. Saving them does not select P2P as the main remote or mark an otherwise unconfigured Vault as configured. Use **Scan local files** before offering existing Vault content to a peer when automatic file observation is unavailable. + +## Limitations + +- There is no general settings screen, setup wizard, or command palette. +- Object Storage and other main-remote configurations remain experimental and are not covered by the current WebApp browser tests. +- Without `FileSystemObserver`, external changes are detected only by a start-up or manual scan. +- A browser may suspend the page, discard permissions, or evict origin-scoped storage. +- The File System Access API is not available in every browser. +- Customisation Sync and Obsidian-specific Vault features are unavailable. + +## Troubleshooting + +### A Vault cannot be opened + +- Confirm that WebApp is served over HTTPS or from `localhost`. +- Grant read-write access when the browser prompts. +- If a saved handle no longer has permission, select **Choose new vault folder** and choose the same directory again. + +### Settings are not loaded + +- Confirm that `.livesync/settings.json` exists under the selected Vault root. +- Confirm that the file contains one valid JSON object. +- Reload WebApp after editing the file. +- Check the status line and browser console for the first reported error. + +### External file changes are not detected + +- Select **Scan local files** after making changes outside WebApp. +- Check whether the browser provides `FileSystemObserver`. +- Keep the page open while automatic watching or synchronisation is expected. + +### CouchDB does not synchronise + +- Confirm the URL, credentials, database name, encryption settings, and compatibility settings. +- Confirm that CouchDB permits requests from the WebApp origin. +- Check the browser network inspector and console for the rejected request. ## Development @@ -41,6 +103,8 @@ npm run test:browser --workspace livesync-webapp The production files are written to `src/apps/webapp/dist/`. App-owned unit tests are stored in `test/apps/webapp/`, outside the Community Review source boundary. The browser test builds the production artefact, selects an OPFS-backed test Vault in Chromium, and verifies start-up and P2P setting isolation. +## Composition + `WebAppRuntime.ts` owns the LiveSync service composition and lifecycle. `main.ts` owns Vault selection and the small browser shell, while `adapters/`, `managers/`, and `serviceModules/` provide the File System Access API boundary. ## Licence diff --git a/src/apps/webapp/managers/FSAPIStorageEventManagerAdapter.ts b/src/apps/webapp/managers/FSAPIStorageEventManagerAdapter.ts index bd23ea0d..6594b61d 100644 --- a/src/apps/webapp/managers/FSAPIStorageEventManagerAdapter.ts +++ b/src/apps/webapp/managers/FSAPIStorageEventManagerAdapter.ts @@ -194,11 +194,15 @@ class FSAPIWatchAdapter implements IStorageEventWatchAdapter { ) {} async beginWatch(handlers: IStorageEventWatchHandlers): Promise { - // Use FileSystemObserver if available (Chrome 124+) + // Use FileSystemObserver when the browser provides it. const FileSystemObserver = (compatGlobal as GlobalWithFileSystemObserver).FileSystemObserver; if (!FileSystemObserver) { - this.addLog("FileSystemObserver is not available; file watching is disabled", LOG_LEVEL_INFO, "fsapi-watch"); - this.addLog("Chrome 124 or later supports real-time file watching", LOG_LEVEL_INFO, "fsapi-watch"); + this.addLog( + "FileSystemObserver is not available; file watching is disabled", + LOG_LEVEL_INFO, + "fsapi-watch" + ); + this.addLog("Use 'Scan local files' after external changes", LOG_LEVEL_INFO, "fsapi-watch"); return Promise.resolve(); } diff --git a/src/apps/webpeer/README.md b/src/apps/webpeer/README.md index 863abff7..4f6d9764 100644 --- a/src/apps/webpeer/README.md +++ b/src/apps/webpeer/README.md @@ -1,6 +1,70 @@ # Self-hosted LiveSync WebPeer -WebPeer is a browser-hosted, P2P-only Self-hosted LiveSync peer. It can receive database changes from one peer and provide them to another without materialising ordinary Vault files. +WebPeer is an experimental, browser-hosted, P2P-only Self-hosted LiveSync peer. It can receive database changes from one peer and provide them to another without materialising ordinary Vault files. + +It stores LiveSync metadata and chunks in an origin-scoped local database, but it does not present them as a Vault. This makes it useful as a temporary browser peer or transfer bridge. It is not a durable replacement for CouchDB, a backup, or an always-on server. + +## Requirements + +WebPeer requires: + +- a secure context, such as HTTPS or `localhost`; +- IndexedDB, WebRTC, WebSocket, and Web Crypto support; +- access to the configured signalling relay; and +- the same Group ID, passphrase, and compatible P2P settings as the other peers. + +TURN is optional and is needed only when a direct WebRTC connection cannot be established. The signalling relay is required for peer discovery, but it does not store or transfer Vault contents. + +## Use + +Serve `src/apps/webpeer/dist/` over HTTPS, or from `localhost`, then open `index.html`. + +1. Enable the P2P replicator. +2. Enter the signalling relay, Group ID, passphrase, and a unique device name. +3. Select **Save and Apply**. +4. Select **Connect** and wait for the intended peers to appear. +5. Use the peer actions to fetch, send, watch, or configure automatic synchronisation as required. + +**Start change-broadcasting on Connect** allows watching peers to notice changes and fetch them. It does not send Vault data through the signalling relay. Optional TURN settings are available separately. + +Keep the page open while WebPeer is expected to announce or transfer changes. + +## Storage and lifecycle + +WebPeer stores its settings, metadata, and chunks in storage belonging to the page origin. Consequently: + +- changing the scheme, host, or port creates a different WebPeer state; +- clearing site data removes the local database and settings; +- browser storage eviction can remove the state; and +- page suspension, tab closure, device sleep, and network policy can interrupt P2P activity. + +Use a separately deployed origin when isolation from the public Pages deployment is required. Do not treat WebPeer browser storage as the only copy of any data. + +## Troubleshooting + +### No peers appear + +- Confirm that every peer uses the same signalling relay, Group ID, and passphrase. +- Confirm that each peer has a distinct device name. +- Confirm that P2P is enabled and that the signalling connection reports **Connected**. +- Check whether the browser or network blocks the relay WebSocket. + +### Peers connect but changes do not transfer + +- Confirm which peer should fetch and which should send. +- Start broadcasting on the source when another peer is watching it. +- Use the explicit fetch or send action to test one direction. +- Confirm that the peers use compatible Self-hosted LiveSync versions and P2P settings. + +### Saved settings or data appear to be missing + +- Confirm that the page is using the same origin as before. +- Check whether site data was cleared or evicted. +- Check the status line and WebPeer log for the first reported error. + +For more detail about relay, TURN, announcing, and following behaviour, see the [P2P guide](../../../docs/p2p.md). + +## Development Build it from the repository root: @@ -8,10 +72,6 @@ Build it from the repository root: npm run build --workspace webpeer ``` -Serve `src/apps/webpeer/dist/` over HTTPS, or from `localhost`, open `index.html`, and configure the same Group ID, passphrase, signalling relay, and optional TURN settings as the other peers. Keep the page open while it is expected to announce or transfer changes. - -WebPeer stores its settings, metadata, and chunks in origin-scoped browser storage. Clearing site data removes this state. Browser suspension, storage eviction, tab lifecycle, and network policy mean that WebPeer is not an always-on server. - The app-owned unit and Chromium tests can be run with: ```bash @@ -21,6 +81,10 @@ npm run test:browser --workspace webpeer The unit tests are stored in `test/apps/webpeer/`, outside the Community Review source boundary. +## Composition + +`WebPeerRuntime.ts` owns the browser service composition, local database lifecycle, P2P replicator, and peer actions. `WebPeerPersistence.ts` owns origin-scoped settings persistence, while the shared P2P pane supplies the connection and peer controls. + ## Licence The same licence as the main Self-hosted LiveSync project applies. diff --git a/test/apps/webapp/FSAPIStorageEventManagerAdapter.unit.spec.ts b/test/apps/webapp/FSAPIStorageEventManagerAdapter.unit.spec.ts new file mode 100644 index 00000000..820b40f0 --- /dev/null +++ b/test/apps/webapp/FSAPIStorageEventManagerAdapter.unit.spec.ts @@ -0,0 +1,34 @@ +import { LOG_LEVEL_INFO } from "@vrtmrz/livesync-commonlib/compat/common/types"; +import type { IStorageEventWatchHandlers } from "@vrtmrz/livesync-commonlib/compat/managers/adapters"; +import { afterEach, describe, expect, it, vi } from "vitest"; + +import { FSAPIStorageEventManagerAdapter } from "@/apps/webapp/managers/FSAPIStorageEventManagerAdapter"; +import type { FSAPIFile } from "@/apps/webapp/adapters/FSAPITypes"; + +afterEach(() => { + vi.unstubAllGlobals(); +}); + +describe("WebApp file watching guidance", () => { + it("offers a capability-based manual fallback when FileSystemObserver is unavailable", async () => { + vi.stubGlobal("FileSystemObserver", undefined); + const addLog = vi.fn(); + const adapter = new FSAPIStorageEventManagerAdapter({} as FileSystemDirectoryHandle, addLog); + const handlers = { + onCreate: vi.fn(), + onChange: vi.fn(), + onDelete: vi.fn(), + onRename: vi.fn(), + onRaw: vi.fn(), + } satisfies IStorageEventWatchHandlers; + + await adapter.watch.beginWatch(handlers); + + expect(addLog).toHaveBeenCalledWith( + "Use 'Scan local files' after external changes", + LOG_LEVEL_INFO, + "fsapi-watch" + ); + expect(addLog.mock.calls.map(([message]) => String(message)).join("\n")).not.toMatch(/Chrome \d+/); + }); +}); diff --git a/updates.md b/updates.md index f0a340bf..f6605723 100644 --- a/updates.md +++ b/updates.md @@ -18,13 +18,14 @@ Earlier releases remain available in the 0.25 release history and the legacy rel I am taking this opportunity to update the experimental features as well. -This is a review-only maintenance release. It improves the robustness and maintainability of the experimental WebApp, WebPeer, and shared dialogue composition, but offers no particular benefit to plug-in users and may be skipped. I have reviewed the changes through CI and a real Obsidian instance, and I will validate the exact published build before merging the release commit. +This maintenance release mainly improves the robustness and maintainability of the experimental WebApp, WebPeer, and shared dialogue composition. Most plug-in users can skip it. I have reviewed the changes through CI and a real Obsidian instance, and I will validate the exact published build before merging the release commit. ### Interface #### Improved - Removed a custom positioning workaround from the onboarding Notice so that it follows Obsidian's standard placement and dismissal behaviour. +- WebApp now points users to **Scan local files** when automatic file observation is unavailable, instead of relying on a fixed browser-version recommendation. ## 1.0.0