# Affinidi WebVH Watcher
The WebVH Watcher is a read-only DID mirror that receives pushed
DID updates from [did-hosting-server](../did-hosting-server/) instances and
serves them publicly. It provides redundancy, geographic
distribution, and load balancing for DID resolution without
managing DIDs directly.
The watcher has no authentication, no ACL, and no DID lifecycle
management — it simply stores and serves replicated DID content.
> **IMPORTANT:**
> did-hosting-service crates are provided "as is" without any
> warranties or guarantees, and by using this framework, users
> agree to assume all risks associated with its deployment and
> use including implementing security, and privacy measures in
> their applications. Affinidi assumes no liability for any
> issues arising from the use or modification of the project.
## Getting Started
### Prerequisites
- Rust 1.94.0+ (2024 Edition)
### 1. Build
```bash
cargo build -p webvh-watcher --release
```
The binary is produced at `target/release/webvh-watcher`.
### 2. Configure
Create a `config.toml`:
```toml
[server]
host = "0.0.0.0"
port = 8533
[log]
level = "info"
[store]
data_dir = "data/webvh-watcher"
[sync]
# Shared secret tokens that source servers must present when pushing
push_tokens = ["my-shared-secret-token"]
# Optional: source servers to pull from for reconciliation
# [[sync.sources]]
# url = "http://server1:8530"
# token = "pull-token"
```
### 3. Configure the source server
On the did-hosting-server that will push DID updates, add the watcher
to its `config.toml`:
```toml
[[watchers]]
url = "http://watcher1.example.com:8533"
token = "my-shared-secret-token"
```
The token must match one of the watcher's `sync.push_tokens`.
### 4. Start the watcher
```bash
webvh-watcher --config config.toml
```
## How It Works
```
did-hosting-server ──(POST /api/sync/did)──► webvh-watcher
──(POST /api/sync/delete)──►
Clients ──(GET /{mnemonic}/did.jsonl)──► webvh-watcher
```
1. A DID is published on a did-hosting-server
2. The server pushes the DID content to all registered watchers
3. The watcher stores the content and serves it at the same
public paths as the original server
4. Clients can resolve DIDs from any watcher instance
Push failures on the server side are logged but do not block the
primary publish operation.
## Configuration
The watcher is configured via a TOML file. By default it looks
for `config.toml` in the current directory. You can specify a
different path with the `--config` flag or the
`WATCHER_CONFIG_PATH` environment variable.
### Environment Variable Overrides
| `WATCHER_CONFIG_PATH` | Path to config file |
| `WATCHER_SERVER_HOST` | Bind host |
| `WATCHER_SERVER_PORT` | Bind port |
| `WATCHER_LOG_LEVEL` | Log level |
## CLI Commands
```
webvh-watcher # Run watcher (default)
webvh-watcher setup # Interactive config wizard
webvh-watcher setup --from <recipe.toml> # Non-interactive (see examples/)
webvh-watcher setup --from <recipe.toml> --force-reprovision # overwrite existing
```
The watcher has no VTA / no secret store, so the recipe is just
`[deployment]`, `[output]`, `[server]`, and `[watcher]` — see
`examples/webvh-watcher-build.toml`.
## API Endpoints
### Public (unauthenticated)
| `GET` | `/api/health` | Health check |
| `GET` | `/{mnemonic}/did.jsonl` | Resolve DID log |
| `GET` | `/{mnemonic}/did-witness.json` | Resolve witness |
| `GET` | `/.well-known/did.jsonl` | Root DID log |
| `GET` | `/.well-known/did-witness.json` | Root witness |
### Sync (token-authenticated)
| `POST` | `/api/sync/did` | Receive pushed DID |
| `POST` | `/api/sync/delete` | Receive DID deletion |
Sync endpoints require a `Bearer` token matching one of the
configured `sync.push_tokens`.
## Library Usage
The webvh-watcher crate can be used as a library (e.g., by the
[did-hosting-daemon](../did-hosting-daemon/)). It exposes:
- `webvh_watcher::config::AppConfig` — configuration
- `webvh_watcher::server::AppState` — application state
- `webvh_watcher::routes::router()` — Axum router
- `webvh_watcher::server::run()` — standalone entry point
## Support & feedback
If you face any issues or have suggestions, please don't
hesitate to contact us using
[this link](https://share.hsforms.com/1i-4HKZRXSsmENzXtPdIG4g8oa2v).
### Reporting technical issues
If you have a technical issue with the Affinidi DID Hosting Service
codebase, you can also create an issue directly in GitHub.
1. Ensure the bug was not already reported by searching on
GitHub under
[Issues](https://github.com/affinidi/did-hosting-service/issues).
2. If you're unable to find an open issue addressing the
problem,
[open a new one](https://github.com/affinidi/did-hosting-service/issues/new).
Be sure to include a **title and clear description**, as
much relevant information as possible, and a **code sample**
or an **executable test case** demonstrating the expected
behaviour that is not occurring.
## Contributing
Want to contribute? Head over to our
[CONTRIBUTING](https://github.com/affinidi/did-hosting-service/blob/main/CONTRIBUTING.md)
guidelines.