A community based topic aggregation platform built on atproto

chore: update docs and references for lexicon migration

Updates remaining documentation, code references, and configuration
to reflect the lexicon namespace migration and labels changes.

Changes:
- Update docs (PRDs, CLAUDE.md) with new namespace references
- Update API routes and handlers for community.post
- Update aggregator client references
- Update feed system documentation
- Remove deprecated interaction/comment schemas (moved to feed/comment)

No functional changes - documentation and reference updates only.

+124 -1150
+3 -3
aggregators/kagi-news/src/coves_client.py
··· 17 17 18 18 Handles: 19 19 - Authentication with aggregator credentials 20 - - Creating posts in communities (social.coves.post.create) 20 + - Creating posts in communities (social.coves.community.post.create) 21 21 - External embed formatting 22 22 """ 23 23 ··· 94 94 self.authenticate() 95 95 96 96 try: 97 - # Prepare post data for social.coves.post.create endpoint 97 + # Prepare post data for social.coves.community.post.create endpoint 98 98 post_data = { 99 99 "community": community_handle, 100 100 "content": content, ··· 114 114 logger.info(f"Creating post in community: {community_handle}") 115 115 116 116 # Make direct HTTP request to XRPC endpoint 117 - url = f"{self.api_url}/xrpc/social.coves.post.create" 117 + url = f"{self.api_url}/xrpc/social.coves.community.post.create" 118 118 headers = { 119 119 "Authorization": f"Bearer {self.client._session.access_jwt}", 120 120 "Content-Type": "application/json"
+2 -2
cmd/server/main.go
··· 306 306 postJetstreamURL := os.Getenv("POST_JETSTREAM_URL") 307 307 if postJetstreamURL == "" { 308 308 // Listen to post record creation events 309 - postJetstreamURL = "ws://localhost:6008/subscribe?wantedCollections=social.coves.post.record" 309 + postJetstreamURL = "ws://localhost:6008/subscribe?wantedCollections=social.coves.community.post" 310 310 } 311 311 312 312 postEventConsumer := jetstream.NewPostEventConsumer(postRepo, communityRepo, userService) ··· 319 319 }() 320 320 321 321 log.Printf("Started Jetstream post consumer: %s", postJetstreamURL) 322 - log.Println(" - Indexing: social.coves.post.record CREATE operations") 322 + log.Println(" - Indexing: social.coves.community.post CREATE operations") 323 323 log.Println(" - UPDATE/DELETE indexing deferred until those features are implemented") 324 324 325 325 // Start Jetstream consumer for aggregators
+5 -5
docs/COMMUNITY_FEEDS.md
··· 182 182 183 183 ```go 184 184 type PostView struct { 185 - URI string // at://did:plc:abc/social.coves.post.record/123 185 + URI string // at://did:plc:abc/social.coves.community.post.record/123 186 186 CID string // Content ID 187 187 RKey string // Record key (TID) 188 188 Author *AuthorView // Author with handle, avatar, reputation ··· 247 247 "feed": [ 248 248 { 249 249 "post": { 250 - "uri": "at://did:plc:gaming123/social.coves.post.record/abc", 250 + "uri": "at://did:plc:gaming123/social.coves.community.post.record/abc", 251 251 "cid": "bafyrei...", 252 252 "author": { 253 253 "did": "did:plc:alice", ··· 473 473 GET /xrpc/social.coves.feed.getSkeleton?feed=at://alice/feed/best-memes 474 474 → Returns: [uri1, uri2, uri3, ...] 475 475 476 - GET /xrpc/social.coves.post.get?uris=[...] 476 + GET /xrpc/social.coves.community.post.get?uris=[...] 477 477 → Returns: [full posts] 478 478 ``` 479 479 ··· 556 556 557 557 ## Lexicon Updates 558 558 559 - ### Updated: `social.coves.post.get` 559 + ### Updated: `social.coves.community.post.get` 560 560 561 561 **Changes:** 562 562 1. ✅ Batch URIs: `uri` → `uris[]` (max 25) ··· 638 638 // Custom feed (power users) 639 639 GET /xrpc/social.coves.feed.getSkeleton?feed=at://alice/feed/best-memes 640 640 → Returns URIs 641 - GET /xrpc/social.coves.post.get?uris=[...] 641 + GET /xrpc/social.coves.community.post.get?uris=[...] 642 642 → Hydrates posts 643 643 ``` 644 644
+1 -1
docs/FEED_SYSTEM_IMPLEMENTATION.md
··· 222 222 "feed": [ 223 223 { 224 224 "post": { 225 - "uri": "at://did:plc:community-gaming/social.coves.post.record/3k...", 225 + "uri": "at://did:plc:community-gaming/social.coves.community.post.record/3k...", 226 226 "cid": "bafyrei...", 227 227 "author": { 228 228 "did": "did:plc:alice",
+1 -1
docs/PRD_GOVERNANCE.md
··· 291 291 - [ ] Go structs: `ContentRules` type in community models 292 292 - [ ] Repository: Parse and store `contentRules` from community profiles 293 293 - [ ] Service: `ValidatePostAgainstRules(post, community)` function 294 - - [ ] Handler: Integrate validation into `social.coves.post.create` 294 + - [ ] Handler: Integrate validation into `social.coves.community.post.create` 295 295 - [ ] AppView indexing: Index post characteristics (embed_type, text_length, etc.) 296 296 - [ ] Tests: Comprehensive rule validation tests 297 297 - [ ] Documentation: Content rules guide for community creators
+17 -17
docs/PRD_POSTS.md
··· 45 45 46 46 **Repository Structure:** 47 47 ``` 48 - Repository: at://did:plc:community789/social.coves.post.record/3k2a4b5c6d7e 48 + Repository: at://did:plc:community789/social.coves.community.post.record/3k2a4b5c6d7e 49 49 Owner: did:plc:community789 (community owns the post) 50 50 Author: did:plc:user123 (tracked in record metadata) 51 51 Hosted By: did:web:coves.social (instance manages community credentials) ··· 77 77 78 78 **Implementation checklist:** 79 79 - [x] Lexicon: `contentRules` in `social.coves.community.profile` ✅ 80 - - [x] Lexicon: `postType` removed from `social.coves.post.create` ✅ 80 + - [x] Lexicon: `postType` removed from `social.coves.community.post.create` ✅ 81 81 - [ ] Validation: `ValidatePostAgainstRules()` service function 82 82 - [ ] Handler: Integrate validation in post creation endpoint 83 83 - [ ] AppView: Index derived characteristics (embed_type, text_length, etc.) ··· 90 90 **Priority:** CRITICAL - Posts are the foundation of the platform 91 91 92 92 #### Create Post 93 - - [x] Lexicon: `social.coves.post.record` ✅ 94 - - [x] Lexicon: `social.coves.post.create` ✅ 93 + - [x] Lexicon: `social.coves.community.post.record` ✅ 94 + - [x] Lexicon: `social.coves.community.post.create` ✅ 95 95 - [x] Removed `postType` enum in favor of content rules ✅ (2025-10-18) 96 96 - [x] Removed `postType` from record and get lexicons ✅ (2025-10-18) 97 - - [x] **Handler:** `POST /xrpc/social.coves.post.create` ✅ (Alpha - see IMPLEMENTATION_POST_CREATION.md) 97 + - [x] **Handler:** `POST /xrpc/social.coves.community.post.create` ✅ (Alpha - see IMPLEMENTATION_POST_CREATION.md) 98 98 - ✅ Accept: community (DID/handle), title (optional), content, facets, embed, contentLabels 99 99 - ✅ Validate: User is authenticated, community exists, content within limits 100 100 - ✅ Write: Create record in **community's PDS repository** ··· 124 124 - [x] **E2E Test:** Create text post → Write to **community's PDS** → Index via Jetstream → Verify in AppView ✅ 125 125 126 126 #### Get Post 127 - - [x] Lexicon: `social.coves.post.get` ✅ 128 - - [ ] **Handler:** `GET /xrpc/social.coves.post.get?uri=at://...` 127 + - [x] Lexicon: `social.coves.community.post.get` ✅ 128 + - [ ] **Handler:** `GET /xrpc/social.coves.community.post.get?uri=at://...` 129 129 - Accept: AT-URI of post 130 130 - Return: Full post view with author, community, stats, viewer state 131 131 - [ ] **Service Layer:** `PostService.Get(uri, viewerDID)` ··· 139 139 - [ ] **E2E Test:** Get post by URI → Verify all fields populated 140 140 141 141 #### Update Post 142 - - [x] Lexicon: `social.coves.post.update` ✅ 143 - - [ ] **Handler:** `POST /xrpc/social.coves.post.update` 142 + - [x] Lexicon: `social.coves.community.post.update` ✅ 143 + - [ ] **Handler:** `POST /xrpc/social.coves.community.post.update` 144 144 - Accept: uri, title, content, facets, embed, contentLabels, editNote 145 145 - Validate: User is post author, within 24-hour edit window 146 146 - Write: Update record in **community's PDS** ··· 157 157 - [ ] **E2E Test:** Update post → Verify edit reflected in AppView 158 158 159 159 #### Delete Post 160 - - [x] Lexicon: `social.coves.post.delete` ✅ 161 - - [ ] **Handler:** `POST /xrpc/social.coves.post.delete` 160 + - [x] Lexicon: `social.coves.community.post.delete` ✅ 161 + - [ ] **Handler:** `POST /xrpc/social.coves.community.post.delete` 162 162 - Accept: uri 163 163 - Validate: User is post author OR community moderator 164 164 - Write: Delete record from **community's PDS** ··· 251 251 252 252 #### Post Event Handling 253 253 - [x] **Consumer:** `PostConsumer.HandlePostEvent()` ✅ (2025-10-19) 254 - - ✅ Listen for `social.coves.post.record` CREATE from **community repositories** 254 + - ✅ Listen for `social.coves.community.post.record` CREATE from **community repositories** 255 255 - ✅ Parse post record, extract author DID and community DID (from AT-URI owner) 256 256 - ⚠️ **Derive post characteristics:** DEFERRED (embed_type, text_length, has_title, has_embed for content rules filtering) 257 257 - ✅ Insert in AppView PostgreSQL (CREATE only - UPDATE/DELETE deferred) ··· 447 447 - [ ] **Tag Storage:** Tags live in **user's repository** (users own their tags) 448 448 449 449 #### Crossposting 450 - - [x] Lexicon: `social.coves.post.crosspost` ✅ 450 + - [x] Lexicon: `social.coves.community.post.crosspost` ✅ 451 451 - [ ] **Crosspost Tracking:** Share post to multiple communities 452 452 - [ ] **Implementation:** Create new post record in each community's repository 453 453 - [ ] **Crosspost Chain:** Track all crosspost relationships ··· 461 461 - [ ] **AppView Query:** Endpoint to fetch user's saved posts 462 462 463 463 ### Post Search 464 - - [x] Lexicon: `social.coves.post.search` ✅ 464 + - [x] Lexicon: `social.coves.community.post.search` ✅ 465 465 - [ ] **Search Parameters:** 466 466 - Query string (q) 467 467 - Filter by community ··· 583 583 - **Reuses Token Refresh:** Can leverage existing community credential management 584 584 585 585 **Implementation Details:** 586 - - Post AT-URI: `at://community_did/social.coves.post.record/tid` 586 + - Post AT-URI: `at://community_did/social.coves.community.post.record/tid` 587 587 - Write operations use community's PDS credentials (encrypted, stored in AppView) 588 588 - Author tracked in post record's `author` field (DID) 589 589 - Moderators can delete any post in their community ··· 756 756 757 757 ## Lexicon Summary 758 758 759 - ### `social.coves.post.record` 759 + ### `social.coves.community.post.record` 760 760 **Status:** ✅ Defined, implementation TODO 761 761 **Last Updated:** 2025-10-18 (removed `postType` enum) 762 762 ··· 781 781 - Post "type" is derived from structure (has embed? what embed type? has title? text length?) 782 782 - Community's `contentRules` validate post structure at creation time 783 783 784 - ### `social.coves.post.create` (Procedure) 784 + ### `social.coves.community.post.create` (Procedure) 785 785 **Status:** ✅ Defined, implementation TODO 786 786 **Last Updated:** 2025-10-18 (removed `postType` parameter) 787 787
+4 -4
docs/aggregators/PRD_AGGREGATORS.md
··· 23 23 1. **Aggregators are Actors, Not a Separate System** 24 24 - Each aggregator has its own DID 25 25 - Authenticate as themselves via JWT 26 - - Use existing `social.coves.post.create` endpoint 26 + - Use existing `social.coves.community.post.create` endpoint 27 27 - Post record's `author` field = aggregator DID (server-populated) 28 28 - No separate posting API needed 29 29 ··· 89 89 Aggregator Service (External) 90 90 91 91 │ 1. Authenticates as aggregator DID (JWT) 92 - │ 2. Calls social.coves.post.create 92 + │ 2. Calls social.coves.community.post.create 93 93 94 94 Coves AppView Handler 95 95 ··· 120 120 121 121 ### For Aggregators 122 122 123 - - **`social.coves.post.create`** - Modified to handle aggregator auth 123 + - **`social.coves.community.post.create`** - Modified to handle aggregator auth 124 124 - **`social.coves.aggregator.getAuthorizations`** - Query authorized communities 125 125 126 126 ### For Discovery ··· 312 312 313 313 --- 314 314 315 - ### 2025-10-19: Reuse `social.coves.post.create` Endpoint 315 + ### 2025-10-19: Reuse `social.coves.community.post.create` Endpoint 316 316 **Decision:** Aggregators use existing post creation endpoint. 317 317 318 318 **Rationale:**
+3 -3
docs/aggregators/PRD_KAGI_NEWS_RSS.md
··· 172 172 │ 3. Deduplication: Tracks posted items via JSON state file │ 173 173 │ 4. Feed Mapper: Maps feed URLs to community handles │ 174 174 │ 5. Post Formatter: Converts to Coves post format │ 175 - │ 6. Post Publisher: Calls social.coves.post.create via XRPC │ 175 + │ 6. Post Publisher: Calls social.coves.community.post.create via XRPC │ 176 176 │ 7. Blob Uploader: Handles image upload to ATProto │ 177 177 └─────────────────────────────────────────────────────────────┘ 178 178 179 179 │ Authenticated XRPC calls 180 180 181 181 ┌─────────────────────────────────────────────────────────────┐ 182 - │ Coves AppView (social.coves.post.create) │ 182 + │ Coves AppView (social.coves.community.post.create) │ 183 183 │ - Validates aggregator authorization │ 184 184 │ - Creates post with author = did:plc:[aggregator-did] │ 185 185 │ - Indexes to community feeds │ ··· 271 271 272 272 ```json 273 273 { 274 - "$type": "social.coves.post.record", 274 + "$type": "social.coves.community.post.record", 275 275 "author": "did:plc:[aggregator-did]", 276 276 "community": "world-news.coves.social", 277 277 "title": "{Kagi story title}",
+1 -1
internal/api/handlers/post/create.go
··· 21 21 } 22 22 } 23 23 24 - // HandleCreate handles POST /xrpc/social.coves.post.create 24 + // HandleCreate handles POST /xrpc/social.coves.community.post.create 25 25 // Creates a new post in a community's repository 26 26 func (h *CreateHandler) HandleCreate(w http.ResponseWriter, r *http.Request) { 27 27 // 1. Check HTTP method
+7 -7
internal/api/routes/post.go
··· 9 9 ) 10 10 11 11 // RegisterPostRoutes registers post-related XRPC endpoints on the router 12 - // Implements social.coves.post.* lexicon endpoints 12 + // Implements social.coves.community.post.* lexicon endpoints 13 13 func RegisterPostRoutes(r chi.Router, service posts.Service, authMiddleware *middleware.AtProtoAuthMiddleware) { 14 14 // Initialize handlers 15 15 createHandler := post.NewCreateHandler(service) 16 16 17 17 // Procedure endpoints (POST) - require authentication 18 - // social.coves.post.create - create a new post in a community 19 - r.With(authMiddleware.RequireAuth).Post("/xrpc/social.coves.post.create", createHandler.HandleCreate) 18 + // social.coves.community.post.create - create a new post in a community 19 + r.With(authMiddleware.RequireAuth).Post("/xrpc/social.coves.community.post.create", createHandler.HandleCreate) 20 20 21 21 // Future endpoints (Beta): 22 - // r.Get("/xrpc/social.coves.post.get", getHandler.HandleGet) 23 - // r.With(authMiddleware.RequireAuth).Post("/xrpc/social.coves.post.update", updateHandler.HandleUpdate) 24 - // r.With(authMiddleware.RequireAuth).Post("/xrpc/social.coves.post.delete", deleteHandler.HandleDelete) 25 - // r.Get("/xrpc/social.coves.post.list", listHandler.HandleList) 22 + // r.Get("/xrpc/social.coves.community.post.get", getHandler.HandleGet) 23 + // r.With(authMiddleware.RequireAuth).Post("/xrpc/social.coves.community.post.update", updateHandler.HandleUpdate) 24 + // r.With(authMiddleware.RequireAuth).Post("/xrpc/social.coves.community.post.delete", deleteHandler.HandleDelete) 25 + // r.Get("/xrpc/social.coves.community.post.list", listHandler.HandleList) 26 26 }
+80
internal/atproto/lexicon/social/coves/feed/comment.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "social.coves.feed.comment", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "description": "A comment on a post or another comment. Comments live in user repositories and support nested threading.", 8 + "key": "tid", 9 + "record": { 10 + "type": "object", 11 + "required": ["reply", "content", "createdAt"], 12 + "properties": { 13 + "reply": { 14 + "type": "ref", 15 + "ref": "#replyRef", 16 + "description": "Reference to the post and parent being replied to" 17 + }, 18 + "content": { 19 + "type": "string", 20 + "maxGraphemes": 3000, 21 + "maxLength": 30000, 22 + "description": "Comment text content" 23 + }, 24 + "facets": { 25 + "type": "array", 26 + "description": "Annotations for rich text (mentions, links, etc.)", 27 + "items": { 28 + "type": "ref", 29 + "ref": "social.coves.richtext.facet" 30 + } 31 + }, 32 + "embed": { 33 + "type": "union", 34 + "description": "Embedded media or quoted posts", 35 + "refs": [ 36 + "social.coves.embed.images", 37 + "social.coves.embed.post" 38 + ] 39 + }, 40 + "langs": { 41 + "type": "array", 42 + "description": "Languages used in the comment content (ISO 639-1)", 43 + "maxLength": 3, 44 + "items": { 45 + "type": "string", 46 + "format": "language" 47 + } 48 + }, 49 + "labels": { 50 + "type": "ref", 51 + "ref": "com.atproto.label.defs#selfLabels", 52 + "description": "Self-applied content labels" 53 + }, 54 + "createdAt": { 55 + "type": "string", 56 + "format": "datetime", 57 + "description": "Timestamp of comment creation" 58 + } 59 + } 60 + } 61 + }, 62 + "replyRef": { 63 + "type": "object", 64 + "description": "References for maintaining thread structure. Root always points to the original post, parent points to the immediate parent (post or comment).", 65 + "required": ["root", "parent"], 66 + "properties": { 67 + "root": { 68 + "type": "ref", 69 + "ref": "com.atproto.repo.strongRef", 70 + "description": "Strong reference to the original post that started the thread" 71 + }, 72 + "parent": { 73 + "type": "ref", 74 + "ref": "com.atproto.repo.strongRef", 75 + "description": "Strong reference to the immediate parent (post or comment) being replied to" 76 + } 77 + } 78 + } 79 + } 80 + }
-86
internal/atproto/lexicon/social/coves/interaction/comment.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "social.coves.interaction.comment", 4 - "defs": { 5 - "main": { 6 - "type": "record", 7 - "description": "A comment on a post or another comment", 8 - "key": "tid", 9 - "record": { 10 - "type": "object", 11 - "required": ["subject", "content", "createdAt"], 12 - "properties": { 13 - "subject": { 14 - "type": "string", 15 - "format": "at-uri", 16 - "description": "AT-URI of post or comment being replied to" 17 - }, 18 - "content": { 19 - "type": "union", 20 - "refs": ["#textContent", "#imageContent", "#stickerContent"] 21 - }, 22 - "location": { 23 - "type": "ref", 24 - "ref": "social.coves.actor.profile#geoLocation" 25 - }, 26 - "translatedFrom": { 27 - "type": "string", 28 - "maxLength": 10, 29 - "description": "Language code if auto-translated (ISO 639-1)" 30 - }, 31 - "createdAt": { 32 - "type": "string", 33 - "format": "datetime" 34 - } 35 - } 36 - } 37 - }, 38 - "textContent": { 39 - "type": "object", 40 - "required": ["text"], 41 - "properties": { 42 - "text": { 43 - "type": "string", 44 - "maxLength": 10000, 45 - "description": "Comment text" 46 - }, 47 - "facets": { 48 - "type": "array", 49 - "description": "Rich text annotations", 50 - "items": { 51 - "type": "ref", 52 - "ref": "social.coves.richtext.facet" 53 - } 54 - } 55 - } 56 - }, 57 - "imageContent": { 58 - "type": "object", 59 - "required": ["image"], 60 - "properties": { 61 - "image": { 62 - "type": "ref", 63 - "ref": "social.coves.embed.images#image" 64 - }, 65 - "caption": { 66 - "type": "string", 67 - "maxLength": 1000 68 - } 69 - } 70 - }, 71 - "stickerContent": { 72 - "type": "object", 73 - "required": ["stickerId"], 74 - "properties": { 75 - "stickerId": { 76 - "type": "string", 77 - "description": "Reference to a sticker in a sticker pack" 78 - }, 79 - "stickerPackId": { 80 - "type": "string", 81 - "description": "Reference to the sticker pack" 82 - } 83 - } 84 - } 85 - } 86 - }
-75
internal/atproto/lexicon/social/coves/interaction/createComment.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "social.coves.interaction.createComment", 4 - "defs": { 5 - "main": { 6 - "type": "procedure", 7 - "description": "Create a comment on a post or another comment", 8 - "input": { 9 - "encoding": "application/json", 10 - "schema": { 11 - "type": "object", 12 - "required": ["parent", "text"], 13 - "properties": { 14 - "parent": { 15 - "type": "string", 16 - "format": "at-uri", 17 - "description": "AT-URI of the post or comment being replied to" 18 - }, 19 - "text": { 20 - "type": "string", 21 - "maxGraphemes": 3000, 22 - "maxLength": 30000, 23 - "description": "Comment text" 24 - }, 25 - "textFacets": { 26 - "type": "array", 27 - "description": "Rich text annotations", 28 - "items": { 29 - "type": "ref", 30 - "ref": "social.coves.richtext.facet" 31 - } 32 - } 33 - } 34 - } 35 - }, 36 - "output": { 37 - "encoding": "application/json", 38 - "schema": { 39 - "type": "object", 40 - "required": ["uri", "cid"], 41 - "properties": { 42 - "uri": { 43 - "type": "string", 44 - "format": "at-uri", 45 - "description": "AT-URI of the created comment" 46 - }, 47 - "cid": { 48 - "type": "string", 49 - "format": "cid", 50 - "description": "CID of the created comment" 51 - } 52 - } 53 - } 54 - }, 55 - "errors": [ 56 - { 57 - "name": "ParentNotFound", 58 - "description": "Parent post or comment not found" 59 - }, 60 - { 61 - "name": "NotAuthorized", 62 - "description": "User is not authorized to comment" 63 - }, 64 - { 65 - "name": "ThreadLocked", 66 - "description": "Comment thread is locked" 67 - }, 68 - { 69 - "name": "Banned", 70 - "description": "User is banned from this community" 71 - } 72 - ] 73 - } 74 - } 75 - }
-41
internal/atproto/lexicon/social/coves/interaction/deleteComment.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "social.coves.interaction.deleteComment", 4 - "defs": { 5 - "main": { 6 - "type": "procedure", 7 - "description": "Delete a comment", 8 - "input": { 9 - "encoding": "application/json", 10 - "schema": { 11 - "type": "object", 12 - "required": ["uri"], 13 - "properties": { 14 - "uri": { 15 - "type": "string", 16 - "format": "at-uri", 17 - "description": "AT-URI of the comment to delete" 18 - } 19 - } 20 - } 21 - }, 22 - "output": { 23 - "encoding": "application/json", 24 - "schema": { 25 - "type": "object", 26 - "properties": {} 27 - } 28 - }, 29 - "errors": [ 30 - { 31 - "name": "CommentNotFound", 32 - "description": "Comment not found" 33 - }, 34 - { 35 - "name": "NotAuthorized", 36 - "description": "User is not authorized to delete this comment" 37 - } 38 - ] 39 - } 40 - } 41 - }
-118
internal/atproto/lexicon/social/coves/post/create.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "social.coves.post.create", 4 - "defs": { 5 - "main": { 6 - "type": "procedure", 7 - "description": "Create a new post in a community", 8 - "input": { 9 - "encoding": "application/json", 10 - "schema": { 11 - "type": "object", 12 - "required": ["community"], 13 - "properties": { 14 - "community": { 15 - "type": "string", 16 - "format": "at-identifier", 17 - "description": "DID or handle of the community to post in" 18 - }, 19 - "title": { 20 - "type": "string", 21 - "maxGraphemes": 300, 22 - "maxLength": 3000, 23 - "description": "Post title (optional for microblog, image, and video posts)" 24 - }, 25 - "content": { 26 - "type": "string", 27 - "maxLength": 50000, 28 - "description": "Post content - main text for text posts, description for media, etc." 29 - }, 30 - "facets": { 31 - "type": "array", 32 - "description": "Rich text annotations for content", 33 - "items": { 34 - "type": "ref", 35 - "ref": "social.coves.richtext.facet" 36 - } 37 - }, 38 - "embed": { 39 - "type": "union", 40 - "description": "Embedded content - images, videos, external links, or quoted posts", 41 - "refs": [ 42 - "social.coves.embed.images", 43 - "social.coves.embed.video", 44 - "social.coves.embed.external", 45 - "social.coves.embed.post" 46 - ] 47 - }, 48 - "originalAuthor": { 49 - "type": "ref", 50 - "ref": "social.coves.post.record#originalAuthor", 51 - "description": "For microblog posts - information about the original author" 52 - }, 53 - "federatedFrom": { 54 - "type": "ref", 55 - "ref": "social.coves.federation.post", 56 - "description": "Reference to original federated post (for microblog posts)" 57 - }, 58 - "contentLabels": { 59 - "type": "array", 60 - "description": "Self-applied content labels", 61 - "items": { 62 - "type": "string", 63 - "knownValues": ["nsfw", "spoiler", "violence"], 64 - "maxLength": 32 65 - } 66 - }, 67 - "location": { 68 - "type": "ref", 69 - "ref": "social.coves.actor.profile#geoLocation", 70 - "description": "Geographic location where post was created" 71 - } 72 - } 73 - } 74 - }, 75 - "output": { 76 - "encoding": "application/json", 77 - "schema": { 78 - "type": "object", 79 - "required": ["uri", "cid"], 80 - "properties": { 81 - "uri": { 82 - "type": "string", 83 - "format": "at-uri", 84 - "description": "AT-URI of the created post" 85 - }, 86 - "cid": { 87 - "type": "string", 88 - "format": "cid", 89 - "description": "CID of the created post" 90 - } 91 - } 92 - } 93 - }, 94 - "errors": [ 95 - { 96 - "name": "CommunityNotFound", 97 - "description": "Community not found" 98 - }, 99 - { 100 - "name": "NotAuthorized", 101 - "description": "User is not authorized to post in this community" 102 - }, 103 - { 104 - "name": "Banned", 105 - "description": "User is banned from this community" 106 - }, 107 - { 108 - "name": "InvalidContent", 109 - "description": "Post content violates community rules" 110 - }, 111 - { 112 - "name": "ContentRuleViolation", 113 - "description": "Post violates community content rules (e.g., embeds not allowed, text too short)" 114 - } 115 - ] 116 - } 117 - } 118 - }
-39
internal/atproto/lexicon/social/coves/post/crosspost.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "social.coves.post.crosspost", 4 - "defs": { 5 - "main": { 6 - "type": "record", 7 - "description": "A record tracking crosspost relationships between posts", 8 - "key": "tid", 9 - "record": { 10 - "type": "object", 11 - "required": ["originalPost", "crosspostOf", "createdAt"], 12 - "properties": { 13 - "originalPost": { 14 - "type": "string", 15 - "format": "at-uri", 16 - "description": "AT-URI of the original post in the crosspost chain" 17 - }, 18 - "crosspostOf": { 19 - "type": "string", 20 - "format": "at-uri", 21 - "description": "AT-URI of the immediate parent this is a crosspost of" 22 - }, 23 - "allCrossposts": { 24 - "type": "array", 25 - "description": "Array of AT-URIs of all posts in the crosspost chain", 26 - "items": { 27 - "type": "string", 28 - "format": "at-uri" 29 - } 30 - }, 31 - "createdAt": { 32 - "type": "string", 33 - "format": "datetime" 34 - } 35 - } 36 - } 37 - } 38 - } 39 - }
-41
internal/atproto/lexicon/social/coves/post/delete.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "social.coves.post.delete", 4 - "defs": { 5 - "main": { 6 - "type": "procedure", 7 - "description": "Delete a post", 8 - "input": { 9 - "encoding": "application/json", 10 - "schema": { 11 - "type": "object", 12 - "required": ["uri"], 13 - "properties": { 14 - "uri": { 15 - "type": "string", 16 - "format": "at-uri", 17 - "description": "AT-URI of the post to delete" 18 - } 19 - } 20 - } 21 - }, 22 - "output": { 23 - "encoding": "application/json", 24 - "schema": { 25 - "type": "object", 26 - "properties": {} 27 - } 28 - }, 29 - "errors": [ 30 - { 31 - "name": "PostNotFound", 32 - "description": "Post not found" 33 - }, 34 - { 35 - "name": "NotAuthorized", 36 - "description": "User is not authorized to delete this post" 37 - } 38 - ] 39 - } 40 - } 41 - }
-294
internal/atproto/lexicon/social/coves/post/get.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "social.coves.post.get", 4 - "defs": { 5 - "main": { 6 - "type": "query", 7 - "description": "Get posts by AT-URI. Supports batch fetching for feed hydration. Returns posts in same order as input URIs.", 8 - "parameters": { 9 - "type": "params", 10 - "required": ["uris"], 11 - "properties": { 12 - "uris": { 13 - "type": "array", 14 - "description": "List of post AT-URIs to fetch (max 25)", 15 - "items": { 16 - "type": "string", 17 - "format": "at-uri" 18 - }, 19 - "maxLength": 25, 20 - "minLength": 1 21 - } 22 - } 23 - }, 24 - "output": { 25 - "encoding": "application/json", 26 - "schema": { 27 - "type": "object", 28 - "required": ["posts"], 29 - "properties": { 30 - "posts": { 31 - "type": "array", 32 - "description": "Array of post views. May include notFound/blocked entries for missing posts.", 33 - "items": { 34 - "type": "union", 35 - "refs": ["#postView", "#notFoundPost", "#blockedPost"] 36 - } 37 - } 38 - } 39 - } 40 - }, 41 - "errors": [ 42 - {"name": "InvalidRequest", "description": "Invalid URI format or empty array"} 43 - ] 44 - }, 45 - "postView": { 46 - "type": "object", 47 - "required": ["uri", "cid", "author", "record", "community", "createdAt", "indexedAt"], 48 - "properties": { 49 - "uri": { 50 - "type": "string", 51 - "format": "at-uri" 52 - }, 53 - "cid": { 54 - "type": "string", 55 - "format": "cid" 56 - }, 57 - "author": { 58 - "type": "ref", 59 - "ref": "#authorView" 60 - }, 61 - "record": { 62 - "type": "unknown", 63 - "description": "The actual post record (text, image, video, etc.)" 64 - }, 65 - "community": { 66 - "type": "ref", 67 - "ref": "#communityRef" 68 - }, 69 - "title": { 70 - "type": "string" 71 - }, 72 - "text": { 73 - "type": "string" 74 - }, 75 - "textFacets": { 76 - "type": "array", 77 - "items": { 78 - "type": "ref", 79 - "ref": "social.coves.richtext.facet" 80 - } 81 - }, 82 - "embed": { 83 - "type": "union", 84 - "description": "Embedded content (images, video, link preview, or quoted post)", 85 - "refs": [ 86 - "social.coves.embed.images#view", 87 - "social.coves.embed.video#view", 88 - "social.coves.embed.external#view", 89 - "social.coves.embed.record#view", 90 - "social.coves.embed.recordWithMedia#view" 91 - ] 92 - }, 93 - "language": { 94 - "type": "string", 95 - "format": "language" 96 - }, 97 - "createdAt": { 98 - "type": "string", 99 - "format": "datetime" 100 - }, 101 - "editedAt": { 102 - "type": "string", 103 - "format": "datetime" 104 - }, 105 - "indexedAt": { 106 - "type": "string", 107 - "format": "datetime", 108 - "description": "When this post was indexed by the AppView" 109 - }, 110 - "stats": { 111 - "type": "ref", 112 - "ref": "#postStats" 113 - }, 114 - "viewer": { 115 - "type": "ref", 116 - "ref": "#viewerState" 117 - } 118 - } 119 - }, 120 - "authorView": { 121 - "type": "object", 122 - "required": ["did", "handle"], 123 - "properties": { 124 - "did": { 125 - "type": "string", 126 - "format": "did" 127 - }, 128 - "handle": { 129 - "type": "string", 130 - "format": "handle" 131 - }, 132 - "displayName": { 133 - "type": "string" 134 - }, 135 - "avatar": { 136 - "type": "string", 137 - "format": "uri" 138 - }, 139 - "reputation": { 140 - "type": "integer", 141 - "description": "Author's reputation in the community" 142 - } 143 - } 144 - }, 145 - "communityRef": { 146 - "type": "object", 147 - "required": ["did", "name"], 148 - "properties": { 149 - "did": { 150 - "type": "string", 151 - "format": "did" 152 - }, 153 - "name": { 154 - "type": "string" 155 - }, 156 - "avatar": { 157 - "type": "string", 158 - "format": "uri" 159 - } 160 - } 161 - }, 162 - "notFoundPost": { 163 - "type": "object", 164 - "description": "Post was not found (deleted, never indexed, or invalid URI)", 165 - "required": ["uri", "notFound"], 166 - "properties": { 167 - "uri": { 168 - "type": "string", 169 - "format": "at-uri" 170 - }, 171 - "notFound": { 172 - "type": "boolean", 173 - "const": true 174 - } 175 - } 176 - }, 177 - "blockedPost": { 178 - "type": "object", 179 - "description": "Post is blocked due to viewer blocking author/community, or community moderation", 180 - "required": ["uri", "blocked"], 181 - "properties": { 182 - "uri": { 183 - "type": "string", 184 - "format": "at-uri" 185 - }, 186 - "blocked": { 187 - "type": "boolean", 188 - "const": true 189 - }, 190 - "blockedBy": { 191 - "type": "string", 192 - "enum": ["author", "community", "moderator"], 193 - "description": "What caused the block: viewer blocked author, viewer blocked community, or post was removed by moderators" 194 - }, 195 - "author": { 196 - "type": "ref", 197 - "ref": "#blockedAuthor" 198 - }, 199 - "community": { 200 - "type": "ref", 201 - "ref": "#blockedCommunity" 202 - } 203 - } 204 - }, 205 - "blockedAuthor": { 206 - "type": "object", 207 - "description": "Minimal author info for blocked posts", 208 - "required": ["did"], 209 - "properties": { 210 - "did": { 211 - "type": "string", 212 - "format": "did" 213 - } 214 - } 215 - }, 216 - "blockedCommunity": { 217 - "type": "object", 218 - "description": "Minimal community info for blocked posts", 219 - "required": ["did"], 220 - "properties": { 221 - "did": { 222 - "type": "string", 223 - "format": "did" 224 - }, 225 - "name": { 226 - "type": "string" 227 - } 228 - } 229 - }, 230 - "postStats": { 231 - "type": "object", 232 - "required": ["upvotes", "downvotes", "score", "commentCount"], 233 - "properties": { 234 - "upvotes": { 235 - "type": "integer", 236 - "minimum": 0 237 - }, 238 - "downvotes": { 239 - "type": "integer", 240 - "minimum": 0 241 - }, 242 - "score": { 243 - "type": "integer", 244 - "description": "Calculated score (upvotes - downvotes)" 245 - }, 246 - "commentCount": { 247 - "type": "integer", 248 - "minimum": 0 249 - }, 250 - "shareCount": { 251 - "type": "integer", 252 - "minimum": 0 253 - }, 254 - "tagCounts": { 255 - "type": "object", 256 - "description": "Aggregate counts of tags applied by community members", 257 - "additionalProperties": { 258 - "type": "integer", 259 - "minimum": 0 260 - } 261 - } 262 - } 263 - }, 264 - "viewerState": { 265 - "type": "object", 266 - "properties": { 267 - "vote": { 268 - "type": "string", 269 - "enum": ["up", "down"], 270 - "description": "Viewer's vote on this post" 271 - }, 272 - "voteUri": { 273 - "type": "string", 274 - "format": "at-uri" 275 - }, 276 - "saved": { 277 - "type": "boolean" 278 - }, 279 - "savedUri": { 280 - "type": "string", 281 - "format": "at-uri" 282 - }, 283 - "tags": { 284 - "type": "array", 285 - "description": "Tags applied by the viewer to this post", 286 - "items": { 287 - "type": "string", 288 - "maxLength": 32 289 - } 290 - } 291 - } 292 - } 293 - } 294 - }
-99
internal/atproto/lexicon/social/coves/post/getCrosspostChain.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "social.coves.post.getCrosspostChain", 4 - "defs": { 5 - "main": { 6 - "type": "procedure", 7 - "description": "Get all crossposts in a crosspost chain for a given post", 8 - "input": { 9 - "encoding": "application/json", 10 - "schema": { 11 - "type": "object", 12 - "required": ["uri"], 13 - "properties": { 14 - "uri": { 15 - "type": "string", 16 - "format": "at-uri", 17 - "description": "AT-URI of any post in the crosspost chain" 18 - } 19 - } 20 - } 21 - }, 22 - "output": { 23 - "encoding": "application/json", 24 - "schema": { 25 - "type": "object", 26 - "required": ["crossposts"], 27 - "properties": { 28 - "crossposts": { 29 - "type": "array", 30 - "description": "All posts in the crosspost chain", 31 - "items": { 32 - "type": "ref", 33 - "ref": "#crosspostView" 34 - } 35 - } 36 - } 37 - } 38 - } 39 - }, 40 - "crosspostView": { 41 - "type": "object", 42 - "required": ["uri", "community", "author", "createdAt"], 43 - "properties": { 44 - "uri": { 45 - "type": "string", 46 - "format": "at-uri", 47 - "description": "AT-URI of the post" 48 - }, 49 - "community": { 50 - "type": "object", 51 - "required": ["uri", "name"], 52 - "properties": { 53 - "uri": { 54 - "type": "string", 55 - "format": "at-uri", 56 - "description": "AT-URI of the community" 57 - }, 58 - "name": { 59 - "type": "string", 60 - "description": "Display name of the community" 61 - }, 62 - "handle": { 63 - "type": "string", 64 - "description": "Handle of the community" 65 - } 66 - } 67 - }, 68 - "author": { 69 - "type": "object", 70 - "required": ["did", "handle"], 71 - "properties": { 72 - "did": { 73 - "type": "string", 74 - "format": "did" 75 - }, 76 - "handle": { 77 - "type": "string" 78 - }, 79 - "displayName": { 80 - "type": "string" 81 - }, 82 - "avatar": { 83 - "type": "string", 84 - "format": "uri" 85 - } 86 - } 87 - }, 88 - "isOriginal": { 89 - "type": "boolean", 90 - "description": "Whether this is the original post in the chain" 91 - }, 92 - "createdAt": { 93 - "type": "string", 94 - "format": "datetime" 95 - } 96 - } 97 - } 98 - } 99 - }
-129
internal/atproto/lexicon/social/coves/post/record.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "social.coves.post.record", 4 - "defs": { 5 - "main": { 6 - "type": "record", 7 - "description": "A unified post record supporting multiple content types", 8 - "key": "tid", 9 - "record": { 10 - "type": "object", 11 - "required": ["$type", "community", "author", "createdAt"], 12 - "properties": { 13 - "$type": { 14 - "type": "string", 15 - "const": "social.coves.post.record", 16 - "description": "The record type identifier" 17 - }, 18 - "community": { 19 - "type": "string", 20 - "format": "at-identifier", 21 - "description": "DID or handle of the community this was posted to" 22 - }, 23 - "author": { 24 - "type": "string", 25 - "format": "did", 26 - "description": "DID of the user who created this post. Server-populated from authenticated session; clients MUST NOT provide this field. Required for attribution, moderation, and accountability." 27 - }, 28 - "title": { 29 - "type": "string", 30 - "maxGraphemes": 300, 31 - "maxLength": 3000, 32 - "description": "Post title (optional for microblog, image, and video posts)" 33 - }, 34 - "content": { 35 - "type": "string", 36 - "maxLength": 50000, 37 - "description": "Post content - main text for text posts, description for media, etc." 38 - }, 39 - "facets": { 40 - "type": "array", 41 - "description": "Rich text annotations for content", 42 - "items": { 43 - "type": "ref", 44 - "ref": "social.coves.richtext.facet" 45 - } 46 - }, 47 - "embed": { 48 - "type": "union", 49 - "description": "Embedded content - images, videos, external links, or quoted posts", 50 - "refs": [ 51 - "social.coves.embed.images", 52 - "social.coves.embed.video", 53 - "social.coves.embed.external", 54 - "social.coves.embed.post" 55 - ] 56 - }, 57 - "originalAuthor": { 58 - "type": "ref", 59 - "ref": "#originalAuthor", 60 - "description": "For microblog posts - information about the original author from federated platform" 61 - }, 62 - "contentLabels": { 63 - "type": "array", 64 - "description": "Self-applied content labels", 65 - "items": { 66 - "type": "string", 67 - "knownValues": ["nsfw", "spoiler", "violence"], 68 - "maxLength": 32 69 - } 70 - }, 71 - "federatedFrom": { 72 - "type": "ref", 73 - "ref": "social.coves.federation.post", 74 - "description": "Reference to original federated post (if applicable)" 75 - }, 76 - "location": { 77 - "type": "ref", 78 - "ref": "social.coves.actor.profile#geoLocation", 79 - "description": "Geographic location where post was created" 80 - }, 81 - "crosspostOf": { 82 - "type": "string", 83 - "format": "at-uri", 84 - "description": "If this is a crosspost, AT-URI of the post this is a crosspost of" 85 - }, 86 - "crosspostChain": { 87 - "type": "array", 88 - "description": "Array of AT-URIs of all posts in the crosspost chain (including this one)", 89 - "items": { 90 - "type": "string", 91 - "format": "at-uri" 92 - } 93 - }, 94 - "createdAt": { 95 - "type": "string", 96 - "format": "datetime" 97 - } 98 - } 99 - } 100 - }, 101 - "originalAuthor": { 102 - "type": "object", 103 - "description": "Information about the original author from a federated platform", 104 - "required": ["handle"], 105 - "properties": { 106 - "did": { 107 - "type": "string", 108 - "format": "did", 109 - "description": "Original author's DID (if available)" 110 - }, 111 - "handle": { 112 - "type": "string", 113 - "maxLength": 253, 114 - "description": "Original author's handle" 115 - }, 116 - "displayName": { 117 - "type": "string", 118 - "maxLength": 640, 119 - "description": "Original author's display name" 120 - }, 121 - "avatar": { 122 - "type": "string", 123 - "format": "uri", 124 - "description": "URL to original author's avatar" 125 - } 126 - } 127 - } 128 - } 129 - }
-80
internal/atproto/lexicon/social/coves/post/search.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "social.coves.post.search", 4 - "defs": { 5 - "main": { 6 - "type": "query", 7 - "description": "Search for posts", 8 - "parameters": { 9 - "type": "params", 10 - "required": ["q"], 11 - "properties": { 12 - "q": { 13 - "type": "string", 14 - "description": "Search query" 15 - }, 16 - "community": { 17 - "type": "string", 18 - "format": "at-identifier", 19 - "description": "Filter by specific community" 20 - }, 21 - "author": { 22 - "type": "string", 23 - "format": "at-identifier", 24 - "description": "Filter by author" 25 - }, 26 - "type": { 27 - "type": "string", 28 - "enum": ["text", "image", "video", "article", "microblog"], 29 - "description": "Filter by post type" 30 - }, 31 - "tags": { 32 - "type": "array", 33 - "items": { 34 - "type": "string" 35 - }, 36 - "description": "Filter by tags" 37 - }, 38 - "sort": { 39 - "type": "string", 40 - "enum": ["relevance", "new", "top"], 41 - "default": "relevance" 42 - }, 43 - "timeframe": { 44 - "type": "string", 45 - "enum": ["hour", "day", "week", "month", "year", "all"], 46 - "default": "all" 47 - }, 48 - "limit": { 49 - "type": "integer", 50 - "minimum": 1, 51 - "maximum": 100, 52 - "default": 50 53 - }, 54 - "cursor": { 55 - "type": "string" 56 - } 57 - } 58 - }, 59 - "output": { 60 - "encoding": "application/json", 61 - "schema": { 62 - "type": "object", 63 - "required": ["posts"], 64 - "properties": { 65 - "posts": { 66 - "type": "array", 67 - "items": { 68 - "type": "ref", 69 - "ref": "social.coves.post.getFeed#feedPost" 70 - } 71 - }, 72 - "cursor": { 73 - "type": "string" 74 - } 75 - } 76 - } 77 - } 78 - } 79 - } 80 - }
-104
internal/atproto/lexicon/social/coves/post/update.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "social.coves.post.update", 4 - "defs": { 5 - "main": { 6 - "type": "procedure", 7 - "description": "Update an existing post", 8 - "input": { 9 - "encoding": "application/json", 10 - "schema": { 11 - "type": "object", 12 - "required": ["uri"], 13 - "properties": { 14 - "uri": { 15 - "type": "string", 16 - "format": "at-uri", 17 - "description": "AT-URI of the post to update" 18 - }, 19 - "title": { 20 - "type": "string", 21 - "maxGraphemes": 300, 22 - "maxLength": 3000, 23 - "description": "Updated title" 24 - }, 25 - "content": { 26 - "type": "string", 27 - "maxLength": 50000, 28 - "description": "Updated content - main text for text posts, description for media, etc." 29 - }, 30 - "facets": { 31 - "type": "array", 32 - "description": "Updated rich text annotations for content", 33 - "items": { 34 - "type": "ref", 35 - "ref": "social.coves.richtext.facet" 36 - } 37 - }, 38 - "embed": { 39 - "type": "union", 40 - "description": "Updated embedded content (note: changing embed type may be restricted)", 41 - "refs": [ 42 - "social.coves.embed.images", 43 - "social.coves.embed.video", 44 - "social.coves.embed.external", 45 - "social.coves.embed.post" 46 - ] 47 - }, 48 - "contentLabels": { 49 - "type": "array", 50 - "description": "Updated content labels", 51 - "items": { 52 - "type": "string", 53 - "knownValues": ["nsfw", "spoiler", "violence"], 54 - "maxLength": 32 55 - } 56 - }, 57 - "editNote": { 58 - "type": "string", 59 - "maxLength": 300, 60 - "description": "Optional note explaining the edit" 61 - } 62 - } 63 - } 64 - }, 65 - "output": { 66 - "encoding": "application/json", 67 - "schema": { 68 - "type": "object", 69 - "required": ["uri", "cid"], 70 - "properties": { 71 - "uri": { 72 - "type": "string", 73 - "format": "at-uri", 74 - "description": "AT-URI of the updated post" 75 - }, 76 - "cid": { 77 - "type": "string", 78 - "format": "cid", 79 - "description": "New CID of the updated post" 80 - } 81 - } 82 - } 83 - }, 84 - "errors": [ 85 - { 86 - "name": "PostNotFound", 87 - "description": "Post not found" 88 - }, 89 - { 90 - "name": "NotAuthorized", 91 - "description": "User is not authorized to edit this post" 92 - }, 93 - { 94 - "name": "EditWindowExpired", 95 - "description": "Edit window has expired (posts can only be edited within 24 hours)" 96 - }, 97 - { 98 - "name": "InvalidUpdate", 99 - "description": "Invalid update operation (e.g., changing post type)" 100 - } 101 - ] 102 - } 103 - } 104 - }