| … | … | @@ -21,29 +21,85 @@ JSON APIs — the "P2P-less window" into the P2P world. |
| 21 | 21 | - a **labeler** (`lib/labeler-export.js` + `lib/label-firehose.js`) — `com.atproto.label` `queryLabels` |
| 22 | 22 | (pull) + `subscribeLabels` (WS firehose). |
| 23 | 23 | |
| 24 | | ## Run |
| 24 | ## Install |
| 25 | 25 | |
| 26 | 26 | ```sh |
| 27 | | bare bin/favela-web.js # FAVELA_PORT=4041 by default |
| 28 | | npm test # node suite; npm run test:ws for the bare-ws firehose test |
| 27 | pgh app install pgh://1dd36bdfa9cb7f7d84adbd07f017e7200f7f90a3a546cd0761fac2a1f8a13e86/favela-web --name favela-web |
| 29 | 28 | ``` |
| 30 | 29 | |
| 31 | | Deployed as a pgh app (`pgh.type: daemon`, `runtime: bare`); the [atproto-bridge](../atproto-bridge) |
| 32 | | membrane proxies the lens-export XRPC to it (`FAVELA_WEB_UPSTREAM`). |
| 30 | Then set the two things that have **no default** (see Config), and start it: |
| 31 | |
| 32 | ```sh |
| 33 | pgh app start favela-web # http://localhost:4041 |
| 34 | ``` |
| 35 | |
| 36 | ⚠ **Unconfigured means inert, on purpose.** With no `FAVELA_ROSTER` this node indexes nothing, and with |
| 37 | no write transport it refuses every write. Earlier versions defaulted both to the author's own fleet, |
| 38 | so a fresh install silently indexed someone else's timeline and aimed its writes at their production |
| 39 | node. Empty is the correct unconfigured state; the errors tell you what to set. |
| 33 | 40 | |
| 34 | 41 | ## Config (env) |
| 35 | 42 | |
| 43 | Overrides go in `~/.config/pgh/apps.json` under `favela-web.env` (there is no CLI for this yet). |
| 44 | |
| 45 | **Must be set — no safe default exists:** |
| 46 | |
| 36 | 47 | | Var | Meaning | |
| 37 | 48 | |---|---| |
| 38 | | | `FAVELA_PORT` | HTTP port (default 4041) | |
| 39 | | | `FAVELA_COMMUNITY_ROOMS` | `id=roomKeyHex,…` — community rooms to serve (roster source) | |
| 40 | | | `FAVELA_COMMUNITY_NAMES` | `name,…` — communities resolved to roomKeys over the DHT | |
| 41 | | | `FAVELA_LABELER_SEED` | enable favela's own atproto labeler (interim; community-DID labeler supersedes) | |
| 49 | | `FAVELA_ROSTER` | `did:plc:…,…` — whose repos this node reads. Empty = index nothing. | |
| 50 | | `FAVELA_HPP_SOCK` | Path to a **co-located** hpp control socket. The write transport. | |
| 51 | | `FAVELA_CONTROL_KEY` | Alternative to the above: a **remote** hpp's control key, reached over the swarm. Set exactly one; setting neither makes the node read-only. | |
| 52 | |
| 53 | **Usually right, override per host:** |
| 54 | |
| 55 | | Var | Default | Meaning | |
| 56 | |---|---|---| |
| 57 | | `FAVELA_PORT` | `4041` | HTTP port | |
| 58 | | `FAVELA_HOST` | `0.0.0.0` (manifest) / `127.0.0.1` (code) | ⚠ a hand-run `bare bin/favela-web.js` binds loopback | |
| 59 | | `ATPROTO_OVERLAY_ROOT` | hpp's `data/atproto-repo` | shared record byte store; wrong path silently downgrades every DID to firehose backfill | |
| 60 | | `FAVELA_STORE_ROOT` | `~/.config/favela-web/data` | appview corestore — keep it OUTSIDE the install tree or `pgh app update` wipes it | |
| 61 | | `FAVELA_EXTERNAL_URL` | — | public URL published in did:web / feed records | |
| 62 | | `FAVELA_COMMUNITY_ROOMS` | — | `id=roomKeyHex,…` community rooms to serve (roster source) | |
| 63 | | `FAVELA_COMMUNITY_NAMES` | — | `name,…` communities resolved to roomKeys over the DHT | |
| 64 | | `FAVELA_REQUIRE_MEMBERSHIP` | off | `1` = writers must also be on a community roster | |
| 65 | | `FAVELA_LABELER_SEED` | off | enable favela's own atproto labeler (interim) | |
| 66 | |
| 67 | `bin/favela-web.js` reads ~38 env vars in total; the rest are tuning (`FAVELA_SPACEDUST`, |
| 68 | `FAVELA_RETENTION_BUDGET`, `FAVELA_AP_BRIDGE`, …) and are safe to ignore. |
| 69 | |
| 70 | ## Who may read and write |
| 71 | |
| 72 | Authentication is not authorisation. A session proves only that the browser holds a sub-key the DID |
| 73 | delegated — any atproto account can prove that about itself. |
| 74 | |
| 75 | - **Reads** are public by default. A community closes its site with `set-meta visibility members`; the |
| 76 | sign-in path, static assets and `/xrpc/*` stay reachable regardless (`lib/gate-policy.js`). |
| 77 | ⚠ `/xrpc/*` must stay open: bsky's AppView reads the lens anonymously. |
| 78 | - **Writes** pass one default-deny gate (`lib/check.js`). A new POST route is treated as a repo write |
| 79 | until it is deliberately classified otherwise. |
| 80 | - repo writes require **owning the repo** — `viewer.did` must equal the DID this node's hpp signs for; |
| 81 | - self-scoped routes (devices, bookmarks, mutes) require only a live, non-revoked session; |
| 82 | - membership is an additional opt-in gate (`FAVELA_REQUIRE_MEMBERSHIP=1`). |
| 83 | |
| 84 | **Read-only lens mode** — configure no write transport and the node serves feeds and refuses every write |
| 85 | with `this instance is read-only`. This is a first-class deployment posture: it is how a publicly |
| 86 | reachable instance can front the lens without exposing an authoring path. |
| 87 | |
| 88 | ## Run (development) |
| 89 | |
| 90 | ```sh |
| 91 | bare bin/favela-web.js # FAVELA_PORT=4041 by default |
| 92 | npm test # node suite; npm run test:ws for the bare-ws firehose test |
| 93 | ``` |
| 94 | |
| 95 | Deployed as a pgh app (`pgh.type: daemon`, `runtime: bare`); the [atproto-bridge](../atproto-bridge) |
| 96 | membrane proxies the lens-export XRPC to it (`FAVELA_WEB_UPSTREAM`). |
| 42 | 97 | |
| 43 | 98 | ## Read |
| 44 | 99 | |
| 45 | 100 | - `DESIGN.md` — the full design (per-peer view, POSSE-inverted, node topology, §3.6 "favela is its own lens"). |
| 46 | 101 | - `spec/lens-export.md` — communities as bsky feeds + labelers, the co-owned-DID pipeline. |
| 102 | - `spec/mobile-node.md` — the phone as a full node (measured APK/runtime costs, Android floors). |
| 47 | 103 | |
| 48 | 104 | See also: [favela-community](../favela-community) (the keyless community rooms) and |
| 49 | 105 | [favela-node](../favela-node) (the co-owned-DID full-node). |