| … | … | @@ -1,8 +1,23 @@ |
| 1 | 1 | # favela-community |
| 2 | 2 | |
| 3 | | Co-owned, **plaintext** community rooms for [Favela](../favela-web) — membership + moderation on a |
| 4 | | [hyper-rooms](../hyper-rooms) Autobase. One community protocol, shared across surfaces: **read keylessly** |
| 5 | | by the gateway (`favela-web`), **written** by mods (a full-node / CLI / hpp). |
| 3 | Co-owned, plaintext community rooms for [favela-web](../favela-web) — membership and moderation on a |
| 4 | [hyper-rooms](../hyper-rooms) Autobase. One community protocol, shared across surfaces: read keylessly |
| 5 | by the gateway (`favela-web`), written by mods (a full-node / CLI / hpp). |
| 6 | |
| 7 | ## Which stack this belongs to |
| 8 | |
| 9 | favela has two room concepts and they are not the same object. This one is the **atproto / |
| 10 | lens-export** community: a co-owned `did:plc:` whose roster favela-web reads keylessly, with posts |
| 11 | living in each member's own signed atproto repo. It is live — `loser-club` is in favela-web's shipped |
| 12 | defaults and [favela.7rnx.net](https://favela.7rnx.net) serves it. |
| 13 | |
| 14 | The **markdown-record** stack has its own primitive: `favela-peer`'s rooms, on autobee rather than |
| 15 | autobase, with keet's roles, where membership *is* the audience and a DM is a room with one other |
| 16 | member. That one is not this, does not use this package, and could not — `favela-peer` may not import |
| 17 | anything `atproto-*`, and its boundary test enforces it. |
| 18 | |
| 19 | So this is not superseded and it is not the room primitive for new work. Consumers today are |
| 20 | `favela-web`, `atproto-bridge` and `favela-node`. |
| 6 | 21 | |
| 7 | 22 | ## The model |
| 8 | 23 | |
| … | … | @@ -52,8 +67,42 @@ const view = await CommunityRoom.openReadonly(corestore3, roomKey) |
| 52 | 67 | await view.members() // ['did:plc:…', …] (roster minus banned) |
| 53 | 68 | ``` |
| 54 | 69 | |
| 55 | | `CommunityRooms(corestore, swarm)` is a server-side read-manager: it opens + joins a keyless replica per |
| 56 | | room and answers `members(roomKey)` — the `Communities.resolve` source in `favela-web`. |
| 70 | `CommunityRooms(corestore, swarm)` is a server-side read-manager: it opens and joins a keyless replica |
| 71 | per room and answers `members(roomKey)`, `meta`, `communityDid`, `curation`, and `watch(roomKey, |
| 72 | onChange, { debounceMs })` for roster changes. It is the `Communities.resolve` source in `favela-web`. |
| 73 | |
| 74 | ### The rest of the room |
| 75 | |
| 76 | | | | |
| 77 | |---|---| |
| 78 | | `members()` `addMember(did)` `removeMember(did)` | the roster, minus bans | |
| 79 | | `ban(did)` `unban(did)` `isBanned(did)` | | |
| 80 | | `mods()` `addMod(localKey, { role })` `addIndexer(localKey)` | roles are `owner`, `writer`, `mirror` | |
| 81 | | `meta()` `setMeta(k, v)` | public metadata only | |
| 82 | | `communityDid()` `setDid(did)` | the community's co-owned `did:plc:`, in `meta:did` | |
| 83 | | `curation()` `setCuration(curator, params)` | `{ curator, params }`; built-ins `roster`, `subject`, `rules` | |
| 84 | | `key` `localKey` `discoveryKey` `writable` | `key` is the public bootstrap key; `localKey` is what a mod hands the owner | |
| 85 | |
| 86 | `CommunityRoom.create` takes `{ name, did, curator, params }` so a community can be bound to its DID |
| 87 | and its curation at genesis rather than in three follow-up writes. |
| 88 | |
| 89 | ### `CommunityDiscovery(swarm)` |
| 90 | |
| 91 | Name and topic discovery over the DHT: `announce({ roomKey, name, description, topics })`, |
| 92 | `discover(topic)`, `resolve(name)` (case-insensitive, `null` when unknown), `unannounce(roomKey)`. |
| 93 | This is how a room key is found from a name nobody has shared out of band. |
| 94 | |
| 95 | ### `FeedRegistry` / `FeedRegistries` |
| 96 | |
| 97 | A durable, co-ownable, keyless list of feeds — the same room machinery one layer over, keyed |
| 98 | `feed:<did>/<rkey>`. `create`, `open`, `openReadonly`, `feeds()`, `feed(did, rkey)`, |
| 99 | `addFeed({ did, rkey, name, curator, params, roomKey, handle })`, `removeFeed`, `addMod`, `removeMod`. |
| 100 | `FeedRegistries` is its read-manager, with the same `watch`. |
| 101 | |
| 102 | ### Schemas |
| 103 | |
| 104 | `communitySchema` and `feedRegistrySchema` are the `apply` contracts; `isDid`, `feedKey` and |
| 105 | `FEED_PREFIX` are the key helpers. Import these rather than re-deriving a key format. |
| 57 | 106 | |
| 58 | 107 | ## Deploy |
| 59 | 108 | |
| … | … | @@ -62,5 +111,17 @@ deploy must vendor **both** `favela-community` and `hyper-rooms` (`cp -rL` into |
| 62 | 111 | |
| 63 | 112 | ## Test |
| 64 | 113 | |
| 65 | | `npm test` → `bare test/community-room.test.mjs` — keyless read + mod admission + co-writer ops linearizing |
| 66 | | through the owner. Fully offline (in-process replication). |
| 114 | ```sh |
| 115 | npm test |
| 116 | ``` |
| 117 | |
| 118 | Four files under `bare`: `community-room` (keyless read, mod admission, co-writer ops linearizing |
| 119 | through the owner, fully offline via in-process replication), `feed-registry`, `cli`, and `discovery` |
| 120 | — the last one over a testnet DHT, covering announce, resolve-by-name and discover-by-topic. |
| 121 | |
| 122 | Not `brittle-bare`, unlike the markdown-record repos: these are plain assertion scripts that print |
| 123 | their own summary line. |
| 124 | |
| 125 | ## License |
| 126 | |
| 127 | Not yet declared — `package.json` carries no `license` field and there is no LICENSE file. |