A small React app that shows how to build a collaborative, access-controlled app with automerge-repo and keyhive, wired together by automerge-repo-keyhive (ARK).
Each TODO list is an end-to-end encrypted Automerge document. The demo demonstrates:
- Creating and editing documents that sync through a subduction sync server.
- Sharing a document with another identity at a chosen access level (relay, read, edit, admin) via its contact card.
- Sharing a document by invite link, which anyone can open to add themselves.
- Making a document public so anyone can read or edit it.
- Revoking access, and access-gated UI (read-only view, hidden share button) driven by keyhive membership.
The demo needs a phonebook document id, which it requires you to supply. Generate
one into a .env file, then start the app:
pnpm install
echo "PHONEBOOK_DOC_ID=$(pnpm -s gen:phonebook-id)" > .env
pnpm dev
The app opens at http://localhost:5557.
Do this once. Keep the same id from then on. A fresh one points the app at a
brand new, empty phonebook, so every name and avatar disappears. .env is
gitignored.
To override the id for a single run without touching .env:
PHONEBOOK_DOC_ID=automerge:... pnpm dev
The phonebook is a shared document holding every peer's display name and avatar.
It is an ordinary Automerge document: unencrypted, and writable by anyone who
knows its id. So rather than shipping one hardcoded id that every copy of the
demo writes to, the demo requires you to supply your own via the
PHONEBOOK_DOC_ID build variable. Generate an id with pnpm gen:phonebook-id
and share it with the people you want in your phonebook.
The document does not need to exist beforehand. The first peer to run with a given id creates it and later peers pick it up from the sync server.
Keep in mind that the id is the only thing protecting the phonebook. Anyone you give it to, and anyone they give it to, can edit its entries. This is fine for a demo but is not an access-control mechanism. The TODO documents themselves are end-to-end encrypted and access-controlled by keyhive.
By default the demo connects to the public keyhive sync server at
wss://keyhive.sync.automerge.org using ARK's built-in keyhive identity.
Three build-time variables override this:
| Variable | Purpose |
|---|---|
SYNC_SERVER |
Websocket endpoint (e.g. ws://localhost:3030). |
SYNC_SERVER_CONTACT_CARD |
The server's signed contact card JSON. |
SYNC_SERVER_PEER_ID |
The server's keyhive peer id. |
SYNC_SERVER_CONTACT_CARD and SYNC_SERVER_PEER_ID must be set together, and
the identity they describe must match the server SYNC_SERVER points at. When
they are unset the demo uses the built-in keyhive identity.
"Create invite link" in the share modal produces a URL that anyone can open to give themselves access to that list, at the access level selected next to it.
In Keyhive, every membership change has to be signed by a principal that already holds at least the access being granted. An invite link carries one. Creating it generates a throwaway keyhive identity, delegates the document to that identity, and puts its key pair and prekey secrets in the URL fragment. Opening the link rebuilds that identity in the visitor's browser, briefly runs it as a second hive against the same sync server, and uses it to delegate the document to the visitor's own identity.
The link is a bearer capability. Anyone who sees the URL has the access it carries, so treat it the way you would treat the document's contents.
Once the join finishes, the fragment is replaced so the key material doesn't stay in the tab's history.
The throwaway identity appears in the member list like any other member. Removing it there turns the link off. Keyhive re-roots the people who joined through it under whoever revokes it, so turning off a link does not remove the people who already used it.
pnpm build
The static site is written to dist/.
For the ARK API this demo is built on, see the automerge-repo-keyhive API guide
at docs/automerge-repo-keyhive-api-guide.md in the
automerge-repo-keyhive
repository.