A community based topic aggregation platform built on atproto

Revert "feat: Unify post lexicon architecture and improve tag handling"

This reverts commit 32f6836b6ebb8af1a475b06c4045a545f06cdcff.

+705 -333
+1 -24
internal/atproto/lexicon/social/coves/embed/external.json
··· 4 4 "defs": { 5 5 "main": { 6 6 "type": "object", 7 - "description": "External link embed with preview metadata and provider support", 7 + "description": "External link embed with preview metadata", 8 8 "required": ["uri"], 9 9 "properties": { 10 10 "uri": { ··· 31 31 "domain": { 32 32 "type": "string", 33 33 "description": "Domain of the linked content" 34 - }, 35 - "embedType": { 36 - "type": "string", 37 - "enum": ["article", "image", "video-stream"], 38 - "description": "Type hint for special handling of known providers" 39 - }, 40 - "provider": { 41 - "type": "string", 42 - "description": "Service provider name (e.g., imgur, streamable)" 43 - }, 44 - "images": { 45 - "type": "array", 46 - "maxLength": 8, 47 - "description": "Preview images for image gallery providers", 48 - "items": { 49 - "type": "ref", 50 - "ref": "social.coves.embed.images#image" 51 - } 52 - }, 53 - "totalCount": { 54 - "type": "integer", 55 - "minimum": 0, 56 - "description": "Total number of items if more than displayed (for galleries)" 57 34 } 58 35 } 59 36 }
+43
internal/atproto/lexicon/social/coves/embed/image.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "social.coves.embed.image", 4 + "defs": { 5 + "main": { 6 + "type": "object", 7 + "description": "Image embed with metadata", 8 + "required": ["image"], 9 + "properties": { 10 + "image": { 11 + "type": "blob", 12 + "accept": ["image/png", "image/jpeg", "image/webp", "image/gif"], 13 + "maxSize": 10000000, 14 + "description": "Image blob reference" 15 + }, 16 + "alt": { 17 + "type": "string", 18 + "maxLength": 1000, 19 + "description": "Alt text for accessibility" 20 + }, 21 + "aspectRatio": { 22 + "type": "ref", 23 + "ref": "#aspectRatio" 24 + } 25 + } 26 + }, 27 + "aspectRatio": { 28 + "type": "object", 29 + "description": "Image aspect ratio for client display", 30 + "required": ["width", "height"], 31 + "properties": { 32 + "width": { 33 + "type": "integer", 34 + "minimum": 1 35 + }, 36 + "height": { 37 + "type": "integer", 38 + "minimum": 1 39 + } 40 + } 41 + } 42 + } 43 + }
-63
internal/atproto/lexicon/social/coves/embed/images.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "social.coves.embed.images", 4 - "defs": { 5 - "main": { 6 - "type": "object", 7 - "description": "Image set embed supporting multiple images (max 8)", 8 - "required": ["images"], 9 - "properties": { 10 - "images": { 11 - "type": "array", 12 - "minLength": 1, 13 - "maxLength": 8, 14 - "description": "Set of images in the post", 15 - "items": { 16 - "type": "ref", 17 - "ref": "#image" 18 - } 19 - } 20 - } 21 - }, 22 - "image": { 23 - "type": "object", 24 - "description": "Individual image with metadata", 25 - "required": ["image"], 26 - "properties": { 27 - "image": { 28 - "type": "blob", 29 - "accept": ["image/png", "image/jpeg", "image/webp", "image/gif"], 30 - "maxSize": 10000000, 31 - "description": "Image blob reference" 32 - }, 33 - "alt": { 34 - "type": "string", 35 - "maxLength": 1000, 36 - "description": "Alt text for accessibility" 37 - }, 38 - "aspectRatio": { 39 - "type": "ref", 40 - "ref": "#aspectRatio", 41 - "description": "Aspect ratio for client-side rendering optimization" 42 - } 43 - } 44 - }, 45 - "aspectRatio": { 46 - "type": "object", 47 - "description": "Image aspect ratio for client display", 48 - "required": ["width", "height"], 49 - "properties": { 50 - "width": { 51 - "type": "integer", 52 - "minimum": 1, 53 - "description": "Width component of aspect ratio" 54 - }, 55 - "height": { 56 - "type": "integer", 57 - "minimum": 1, 58 - "description": "Height component of aspect ratio" 59 - } 60 - } 61 - } 62 - } 63 - }
+3 -8
internal/atproto/lexicon/social/coves/federation/post.json
··· 5 5 "main": { 6 6 "type": "object", 7 7 "description": "Reference to original federated post", 8 - "required": ["platform", "uri"], 8 + "required": ["platform"], 9 9 "properties": { 10 10 "platform": { 11 11 "type": "string", 12 - "knownValues": ["bluesky", "lemmy", "atproto"], 12 + "knownValues": ["bluesky", "lemmy", "mastodon"], 13 13 "description": "Platform the post originated from" 14 14 }, 15 15 "uri": { 16 16 "type": "string", 17 17 "format": "uri", 18 - "description": "Original URI of the post (at:// URI for atproto platforms)" 18 + "description": "Original URI of the post" 19 19 }, 20 20 "id": { 21 21 "type": "string", 22 22 "description": "Platform-specific post ID" 23 - }, 24 - "originalCreatedAt": { 25 - "type": "string", 26 - "format": "datetime", 27 - "description": "Timestamp when originally posted on source platform" 28 23 } 29 24 } 30 25 }
+106
internal/atproto/lexicon/social/coves/post/article.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "social.coves.post.article", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "description": "An article/link post", 8 + "key": "tid", 9 + "record": { 10 + "type": "object", 11 + "required": ["community", "title", "url", "createdAt"], 12 + "properties": { 13 + "community": { 14 + "type": "string", 15 + "format": "at-identifier", 16 + "description": "DID or handle of the community this was posted to" 17 + }, 18 + "title": { 19 + "type": "string", 20 + "maxGraphemes": 300, 21 + "maxLength": 3000, 22 + "description": "Post title" 23 + }, 24 + "url": { 25 + "type": "string", 26 + "format": "uri", 27 + "description": "URL of the linked article" 28 + }, 29 + "domain": { 30 + "type": "string", 31 + "description": "Domain of the linked article (cached)" 32 + }, 33 + "embed": { 34 + "type": "ref", 35 + "ref": "social.coves.embed.external", 36 + "description": "Preview metadata for the link" 37 + }, 38 + "autoGeneratedDescription": { 39 + "type": "string", 40 + "maxLength": 50000, 41 + "description": "Optional Auto-generated text breakdown of article" 42 + }, 43 + "content": { 44 + "type": "string", 45 + "maxLength": 50000, 46 + "description": "Optional text content to accompany link" 47 + }, 48 + "facets": { 49 + "type": "array", 50 + "description": "Rich text annotations", 51 + "items": { 52 + "type": "ref", 53 + "ref": "social.coves.richtext.facet" 54 + } 55 + }, 56 + "tags": { 57 + "type": "array", 58 + "maxLength": 10, 59 + "items": { 60 + "type": "string", 61 + "maxLength": 32 62 + } 63 + }, 64 + "nsfw": { 65 + "type": "boolean", 66 + "default": false 67 + }, 68 + "contentLabels": { 69 + "type": "array", 70 + "description": "Self-applied content labels", 71 + "items": { 72 + "type": "string", 73 + "knownValues": ["nsfw", "spoiler", "violence"], 74 + "maxLength": 32 75 + } 76 + }, 77 + "federatedFrom": { 78 + "type": "ref", 79 + "ref": "social.coves.federation.post" 80 + }, 81 + "location": { 82 + "type": "ref", 83 + "ref": "social.coves.actor.profile#geoLocation" 84 + }, 85 + "crosspostOf": { 86 + "type": "string", 87 + "format": "at-uri", 88 + "description": "If this is a crosspost, AT-URI of the post this is a crosspost of" 89 + }, 90 + "crosspostChain": { 91 + "type": "array", 92 + "description": "Array of AT-URIs of all posts in the crosspost chain (including this one)", 93 + "items": { 94 + "type": "string", 95 + "format": "at-uri" 96 + } 97 + }, 98 + "createdAt": { 99 + "type": "string", 100 + "format": "datetime" 101 + } 102 + } 103 + } 104 + } 105 + } 106 + }
+87 -39
internal/atproto/lexicon/social/coves/post/create.json
··· 9 9 "encoding": "application/json", 10 10 "schema": { 11 11 "type": "object", 12 - "required": ["community", "postType"], 12 + "required": ["community", "type", "title"], 13 13 "properties": { 14 14 "community": { 15 15 "type": "string", 16 16 "format": "at-identifier", 17 17 "description": "DID or handle of the community to post in" 18 18 }, 19 - "postType": { 19 + "type": { 20 20 "type": "string", 21 - "enum": ["text", "article", "image", "video", "microblog"], 21 + "enum": ["text", "image", "video", "article", "microblog"], 22 22 "description": "Type of post to create" 23 23 }, 24 24 "title": { 25 25 "type": "string", 26 26 "maxGraphemes": 300, 27 27 "maxLength": 3000, 28 - "description": "Post title (optional for microblog, image, and video posts)" 28 + "description": "Post title (required for text, article, image, video posts)" 29 29 }, 30 - "content": { 30 + "text": { 31 31 "type": "string", 32 - "maxLength": 50000, 33 - "description": "Post content - main text for text posts, description for media, etc." 32 + "maxGraphemes": 10000, 33 + "maxLength": 40000, 34 + "description": "Post body text" 34 35 }, 35 - "facets": { 36 + "textFacets": { 36 37 "type": "array", 37 - "description": "Rich text annotations for content", 38 + "description": "Rich text annotations for body", 38 39 "items": { 39 40 "type": "ref", 40 41 "ref": "social.coves.richtext.facet" 41 42 } 42 43 }, 43 - "embed": { 44 - "type": "union", 45 - "description": "Embedded content - images, videos, external links, or quoted posts", 46 - "refs": [ 47 - "social.coves.embed.images", 48 - "social.coves.embed.video", 49 - "social.coves.embed.external", 50 - "social.coves.embed.post" 51 - ] 44 + "images": { 45 + "type": "array", 46 + "maxLength": 10, 47 + "description": "Images for image posts", 48 + "items": { 49 + "type": "object", 50 + "required": ["image"], 51 + "properties": { 52 + "image": { 53 + "type": "blob", 54 + "accept": ["image/png", "image/jpeg", "image/webp"], 55 + "maxSize": 5000000 56 + }, 57 + "alt": { 58 + "type": "string", 59 + "maxLength": 1000, 60 + "description": "Alt text for accessibility" 61 + } 62 + } 63 + } 52 64 }, 53 - "originalAuthor": { 54 - "type": "ref", 55 - "ref": "social.coves.post.record#originalAuthor", 56 - "description": "For microblog posts - information about the original author" 65 + "video": { 66 + "type": "object", 67 + "description": "Video for video posts", 68 + "required": ["video"], 69 + "properties": { 70 + "video": { 71 + "type": "blob", 72 + "accept": ["video/mp4", "video/webm"], 73 + "maxSize": 100000000 74 + }, 75 + "thumbnail": { 76 + "type": "blob", 77 + "accept": ["image/png", "image/jpeg", "image/webp"], 78 + "maxSize": 1000000 79 + }, 80 + "alt": { 81 + "type": "string", 82 + "maxLength": 1000 83 + } 84 + } 57 85 }, 58 - "federatedFrom": { 59 - "type": "ref", 60 - "ref": "social.coves.federation.post", 61 - "description": "Reference to original federated post (for microblog posts)" 86 + "external": { 87 + "type": "object", 88 + "description": "External link embed", 89 + "required": ["uri"], 90 + "properties": { 91 + "uri": { 92 + "type": "string", 93 + "format": "uri" 94 + }, 95 + "title": { 96 + "type": "string", 97 + "maxLength": 300 98 + }, 99 + "description": { 100 + "type": "string", 101 + "maxLength": 1000 102 + }, 103 + "thumb": { 104 + "type": "blob", 105 + "accept": ["image/png", "image/jpeg", "image/webp"], 106 + "maxSize": 1000000 107 + } 108 + } 62 109 }, 63 - "contentLabels": { 110 + "tags": { 64 111 "type": "array", 65 - "description": "Self-applied content labels", 112 + "maxLength": 10, 66 113 "items": { 67 114 "type": "string", 68 - "knownValues": ["nsfw", "spoiler", "violence"], 69 - "maxLength": 32 70 - } 115 + "maxLength": 50 116 + }, 117 + "description": "Tags for categorization" 118 + }, 119 + "nsfw": { 120 + "type": "boolean", 121 + "default": false, 122 + "description": "Whether the post contains NSFW content" 71 123 }, 72 - "location": { 73 - "type": "ref", 74 - "ref": "social.coves.actor.profile#geoLocation", 75 - "description": "Geographic location where post was created" 124 + "language": { 125 + "type": "string", 126 + "format": "language", 127 + "description": "Language of the post" 76 128 } 77 129 } 78 130 } ··· 112 164 { 113 165 "name": "InvalidContent", 114 166 "description": "Post content violates community rules" 115 - }, 116 - { 117 - "name": "InvalidPostType", 118 - "description": "Community does not allow this post type" 119 167 } 120 168 ] 121 169 }
+11 -18
internal/atproto/lexicon/social/coves/post/get.json
··· 32 32 }, 33 33 "postView": { 34 34 "type": "object", 35 - "required": ["uri", "cid", "author", "record", "community", "postType", "createdAt"], 35 + "required": ["uri", "cid", "author", "record", "community", "type", "createdAt"], 36 36 "properties": { 37 37 "uri": { 38 38 "type": "string", ··· 54 54 "type": "ref", 55 55 "ref": "#communityRef" 56 56 }, 57 - "postType": { 57 + "type": { 58 58 "type": "string", 59 59 "enum": ["text", "image", "video", "article", "microblog"] 60 60 }, ··· 85 85 "external": { 86 86 "type": "ref", 87 87 "ref": "#externalView" 88 + }, 89 + "tags": { 90 + "type": "array", 91 + "items": { 92 + "type": "string" 93 + } 94 + }, 95 + "nsfw": { 96 + "type": "boolean" 88 97 }, 89 98 "language": { 90 99 "type": "string", ··· 227 236 "shareCount": { 228 237 "type": "integer", 229 238 "minimum": 0 230 - }, 231 - "tagCounts": { 232 - "type": "object", 233 - "description": "Aggregate counts of tags applied by community members", 234 - "additionalProperties": { 235 - "type": "integer", 236 - "minimum": 0 237 - } 238 239 } 239 240 } 240 241 }, ··· 256 257 "savedUri": { 257 258 "type": "string", 258 259 "format": "at-uri" 259 - }, 260 - "tags": { 261 - "type": "array", 262 - "description": "Tags applied by the viewer to this post", 263 - "items": { 264 - "type": "string", 265 - "maxLength": 32 266 - } 267 260 } 268 261 } 269 262 }
+24 -33
internal/atproto/lexicon/social/coves/post/getFeed.json
··· 4 4 "defs": { 5 5 "main": { 6 6 "type": "query", 7 - "description": "Get a feed of posts with optional filtering by post type", 7 + "description": "Get a feed of posts", 8 8 "parameters": { 9 9 "type": "params", 10 10 "properties": { ··· 18 18 "type": "string", 19 19 "format": "at-identifier", 20 20 "description": "Filter by specific community (DID or handle)" 21 - }, 22 - "postType": { 23 - "type": "string", 24 - "enum": ["text", "article", "image", "video", "microblog"], 25 - "description": "Filter by a single post type" 26 - }, 27 - "postTypes": { 28 - "type": "array", 29 - "items": { 30 - "type": "string", 31 - "enum": ["text", "article", "image", "video", "microblog"] 32 - }, 33 - "description": "Filter by multiple post types" 34 21 }, 35 22 "timeframe": { 36 23 "type": "string", ··· 71 58 }, 72 59 "feedPost": { 73 60 "type": "object", 74 - "required": ["uri", "author", "community", "postType", "createdAt"], 61 + "required": ["uri", "author", "community", "type", "createdAt"], 75 62 "properties": { 76 63 "uri": { 77 64 "type": "string", ··· 85 72 "type": "ref", 86 73 "ref": "social.coves.post.get#communityRef" 87 74 }, 88 - "postType": { 75 + "type": { 89 76 "type": "string", 90 - "enum": ["text", "article", "image", "video", "microblog"], 91 - "description": "Type of the post for UI rendering" 77 + "enum": ["text", "image", "video", "article", "microblog"] 92 78 }, 93 79 "title": { 94 80 "type": "string" 95 81 }, 96 - "content": { 82 + "text": { 97 83 "type": "string", 98 84 "maxLength": 500, 99 - "description": "Truncated preview of the post content" 85 + "description": "Truncated preview of the post text" 86 + }, 87 + "images": { 88 + "type": "array", 89 + "maxLength": 4, 90 + "description": "Preview of images (max 4)", 91 + "items": { 92 + "type": "ref", 93 + "ref": "social.coves.post.get#imageView" 94 + } 100 95 }, 101 - "embed": { 102 - "type": "union", 103 - "description": "Embedded content preview", 104 - "refs": [ 105 - "social.coves.post.get#imagesView", 106 - "social.coves.post.get#videoView", 107 - "social.coves.post.get#externalView", 108 - "social.coves.post.get#postView" 109 - ] 96 + "video": { 97 + "type": "ref", 98 + "ref": "social.coves.post.get#videoView" 110 99 }, 111 - "originalAuthor": { 100 + "external": { 112 101 "type": "ref", 113 - "ref": "social.coves.post.record#originalAuthor", 114 - "description": "For microblog posts - original author info" 102 + "ref": "social.coves.post.get#externalView" 115 103 }, 116 - "contentLabels": { 104 + "tags": { 117 105 "type": "array", 118 106 "items": { 119 107 "type": "string" 120 108 } 109 + }, 110 + "nsfw": { 111 + "type": "boolean" 121 112 }, 122 113 "createdAt": { 123 114 "type": "string",
+93
internal/atproto/lexicon/social/coves/post/image.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "social.coves.post.image", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "description": "An image post", 8 + "key": "tid", 9 + "record": { 10 + "type": "object", 11 + "required": ["community", "title", "images", "createdAt"], 12 + "properties": { 13 + "community": { 14 + "type": "string", 15 + "format": "at-identifier", 16 + "description": "DID or handle of the community this was posted to" 17 + }, 18 + "title": { 19 + "type": "string", 20 + "maxGraphemes": 300, 21 + "maxLength": 3000, 22 + "description": "Post title" 23 + }, 24 + "images": { 25 + "type": "array", 26 + "minLength": 1, 27 + "maxLength": 10, 28 + "description": "Images in the post", 29 + "items": { 30 + "type": "ref", 31 + "ref": "social.coves.embed.image" 32 + } 33 + }, 34 + "caption": { 35 + "type": "string", 36 + "maxLength": 10000, 37 + "description": "Optional caption or description" 38 + }, 39 + "captionFacets": { 40 + "type": "array", 41 + "description": "Rich text annotations for caption", 42 + "items": { 43 + "type": "ref", 44 + "ref": "social.coves.richtext.facet" 45 + } 46 + }, 47 + "tags": { 48 + "type": "array", 49 + "maxLength": 10, 50 + "items": { 51 + "type": "string", 52 + "maxLength": 32 53 + } 54 + }, 55 + "contentLabels": { 56 + "type": "array", 57 + "description": "Self-applied content labels", 58 + "items": { 59 + "type": "string", 60 + "knownValues": ["nsfw", "spoiler", "violence"], 61 + "maxLength": 32 62 + } 63 + }, 64 + "federatedFrom": { 65 + "type": "ref", 66 + "ref": "social.coves.federation.post" 67 + }, 68 + "location": { 69 + "type": "ref", 70 + "ref": "social.coves.actor.profile#geoLocation" 71 + }, 72 + "crosspostOf": { 73 + "type": "string", 74 + "format": "at-uri", 75 + "description": "If this is a crosspost, AT-URI of the post this is a crosspost of" 76 + }, 77 + "crosspostChain": { 78 + "type": "array", 79 + "description": "Array of AT-URIs of all posts in the crosspost chain (including this one)", 80 + "items": { 81 + "type": "string", 82 + "format": "at-uri" 83 + } 84 + }, 85 + "createdAt": { 86 + "type": "string", 87 + "format": "datetime" 88 + } 89 + } 90 + } 91 + } 92 + } 93 + }
+136
internal/atproto/lexicon/social/coves/post/microblog.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "social.coves.post.microblog", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "description": "A microblog post (typically from federated platforms like Bluesky/Mastodon)", 8 + "key": "tid", 9 + "record": { 10 + "type": "object", 11 + "required": ["community", "content", "createdAt"], 12 + "properties": { 13 + "community": { 14 + "type": "string", 15 + "format": "at-identifier", 16 + "description": "DID or handle of the community this was posted to" 17 + }, 18 + "content": { 19 + "type": "string", 20 + "maxLength": 5000, 21 + "description": "Microblog post content (plain text or markdown)" 22 + }, 23 + "facets": { 24 + "type": "array", 25 + "description": "Rich text annotations", 26 + "items": { 27 + "type": "ref", 28 + "ref": "social.coves.richtext.facet" 29 + } 30 + }, 31 + "title": { 32 + "type": "string", 33 + "maxLength": 300, 34 + "description": "Optional title" 35 + }, 36 + "hashtags": { 37 + "type": "array", 38 + "maxLength": 20, 39 + "description": "Hashtags from the original post", 40 + "items": { 41 + "type": "string", 42 + "maxLength": 100 43 + } 44 + }, 45 + "embed": { 46 + "type": "union", 47 + "description": "Embedded content (images, videos, links, quoted posts)", 48 + "refs": [ 49 + "social.coves.embed.image", 50 + "social.coves.embed.video", 51 + "social.coves.embed.external", 52 + "social.coves.embed.post" 53 + ] 54 + }, 55 + "contentLabels": { 56 + "type": "array", 57 + "description": "Content warnings and labels", 58 + "items": { 59 + "type": "string", 60 + "knownValues": ["nsfw", "spoiler", "violence"], 61 + "maxLength": 32 62 + } 63 + }, 64 + "federatedFrom": { 65 + "type": "ref", 66 + "ref": "social.coves.federation.post", 67 + "description": "Required - reference to original federated post" 68 + }, 69 + "originalAuthor": { 70 + "type": "object", 71 + "description": "Information about the original author from federated platform", 72 + "required": ["handle"], 73 + "properties": { 74 + "handle": { 75 + "type": "string", 76 + "maxLength": 253, 77 + "description": "Original author's handle" 78 + }, 79 + "displayName": { 80 + "type": "string", 81 + "maxLength": 640, 82 + "description": "Original author's display name" 83 + }, 84 + "did": { 85 + "type": "string", 86 + "format": "did", 87 + "description": "Original author's DID (if available)" 88 + }, 89 + "avatar": { 90 + "type": "string", 91 + "format": "uri", 92 + "description": "URL to original author's avatar" 93 + } 94 + } 95 + }, 96 + "replyTo": { 97 + "type": "string", 98 + "format": "at-uri", 99 + "description": "If this is a reply, reference to the parent post" 100 + }, 101 + "location": { 102 + "type": "ref", 103 + "ref": "social.coves.actor.profile#geoLocation" 104 + }, 105 + "language": { 106 + "type": "string", 107 + "maxLength": 10, 108 + "description": "Language code (e.g., 'en', 'es', 'fr')" 109 + }, 110 + "crosspostOf": { 111 + "type": "string", 112 + "format": "at-uri", 113 + "description": "If this is a crosspost, AT-URI of the post this is a crosspost of" 114 + }, 115 + "crosspostChain": { 116 + "type": "array", 117 + "description": "Array of AT-URIs of all posts in the crosspost chain (including this one)", 118 + "items": { 119 + "type": "string", 120 + "format": "at-uri" 121 + } 122 + }, 123 + "createdAt": { 124 + "type": "string", 125 + "format": "datetime" 126 + }, 127 + "originalCreatedAt": { 128 + "type": "string", 129 + "format": "datetime", 130 + "description": "Original creation time on the federated platform" 131 + } 132 + } 133 + } 134 + } 135 + } 136 + }
-124
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": ["community", "postType", "createdAt"], 12 - "properties": { 13 - "community": { 14 - "type": "string", 15 - "format": "at-identifier", 16 - "description": "DID or handle of the community this was posted to" 17 - }, 18 - "postType": { 19 - "type": "string", 20 - "enum": ["text", "article", "image", "video", "microblog"], 21 - "description": "Discriminator for post type to enable filtering and specialized rendering" 22 - }, 23 - "title": { 24 - "type": "string", 25 - "maxGraphemes": 300, 26 - "maxLength": 3000, 27 - "description": "Post title (optional for microblog, image, and video posts)" 28 - }, 29 - "content": { 30 - "type": "string", 31 - "maxLength": 50000, 32 - "description": "Post content - main text for text posts, description for media, etc." 33 - }, 34 - "facets": { 35 - "type": "array", 36 - "description": "Rich text annotations for content", 37 - "items": { 38 - "type": "ref", 39 - "ref": "social.coves.richtext.facet" 40 - } 41 - }, 42 - "embed": { 43 - "type": "union", 44 - "description": "Embedded content - images, videos, external links, or quoted posts", 45 - "refs": [ 46 - "social.coves.embed.images", 47 - "social.coves.embed.video", 48 - "social.coves.embed.external", 49 - "social.coves.embed.post" 50 - ] 51 - }, 52 - "originalAuthor": { 53 - "type": "ref", 54 - "ref": "#originalAuthor", 55 - "description": "For microblog posts - information about the original author from federated platform" 56 - }, 57 - "contentLabels": { 58 - "type": "array", 59 - "description": "Self-applied content labels", 60 - "items": { 61 - "type": "string", 62 - "knownValues": ["nsfw", "spoiler", "violence"], 63 - "maxLength": 32 64 - } 65 - }, 66 - "federatedFrom": { 67 - "type": "ref", 68 - "ref": "social.coves.federation.post", 69 - "description": "Reference to original federated post (if applicable)" 70 - }, 71 - "location": { 72 - "type": "ref", 73 - "ref": "social.coves.actor.profile#geoLocation", 74 - "description": "Geographic location where post was created" 75 - }, 76 - "crosspostOf": { 77 - "type": "string", 78 - "format": "at-uri", 79 - "description": "If this is a crosspost, AT-URI of the post this is a crosspost of" 80 - }, 81 - "crosspostChain": { 82 - "type": "array", 83 - "description": "Array of AT-URIs of all posts in the crosspost chain (including this one)", 84 - "items": { 85 - "type": "string", 86 - "format": "at-uri" 87 - } 88 - }, 89 - "createdAt": { 90 - "type": "string", 91 - "format": "datetime" 92 - } 93 - } 94 - } 95 - }, 96 - "originalAuthor": { 97 - "type": "object", 98 - "description": "Information about the original author from a federated platform", 99 - "required": ["handle"], 100 - "properties": { 101 - "did": { 102 - "type": "string", 103 - "format": "did", 104 - "description": "Original author's DID (if available)" 105 - }, 106 - "handle": { 107 - "type": "string", 108 - "maxLength": 253, 109 - "description": "Original author's handle" 110 - }, 111 - "displayName": { 112 - "type": "string", 113 - "maxLength": 640, 114 - "description": "Original author's display name" 115 - }, 116 - "avatar": { 117 - "type": "string", 118 - "format": "uri", 119 - "description": "URL to original author's avatar" 120 - } 121 - } 122 - } 123 - } 124 - }
+94
internal/atproto/lexicon/social/coves/post/text.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "social.coves.post.text", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "description": "A text post", 8 + "key": "tid", 9 + "record": { 10 + "type": "object", 11 + "required": ["community", "title", "createdAt"], 12 + "properties": { 13 + "community": { 14 + "type": "string", 15 + "format": "at-identifier", 16 + "description": "DID or handle of the community this was posted to" 17 + }, 18 + "title": { 19 + "type": "string", 20 + "maxGraphemes": 300, 21 + "maxLength": 3000, 22 + "description": "Post title" 23 + }, 24 + "content": { 25 + "type": "string", 26 + "maxLength": 50000, 27 + "description": "Markdown-formatted post content" 28 + }, 29 + "facets": { 30 + "type": "array", 31 + "description": "Rich text annotations", 32 + "items": { 33 + "type": "ref", 34 + "ref": "social.coves.richtext.facet" 35 + } 36 + }, 37 + "tags": { 38 + "type": "array", 39 + "maxLength": 10, 40 + "description": "Post tags/categories", 41 + "items": { 42 + "type": "string", 43 + "maxLength": 32 44 + } 45 + }, 46 + "contentLabels": { 47 + "type": "array", 48 + "description": "Self-applied content labels", 49 + "items": { 50 + "type": "string", 51 + "knownValues": ["nsfw", "spoiler", "violence"], 52 + "maxLength": 32 53 + } 54 + }, 55 + "federatedFrom": { 56 + "type": "ref", 57 + "ref": "social.coves.federation.post" 58 + }, 59 + "location": { 60 + "type": "ref", 61 + "ref": "social.coves.actor.profile#geoLocation" 62 + }, 63 + "embed": { 64 + "type": "union", 65 + "description": "Optional embedded content", 66 + "refs": [ 67 + "social.coves.embed.image", 68 + "social.coves.embed.video", 69 + "social.coves.embed.external", 70 + "social.coves.embed.post" 71 + ] 72 + }, 73 + "crosspostOf": { 74 + "type": "string", 75 + "format": "at-uri", 76 + "description": "If this is a crosspost, AT-URI of the post this is a crosspost of" 77 + }, 78 + "crosspostChain": { 79 + "type": "array", 80 + "description": "Array of AT-URIs of all posts in the crosspost chain (including this one)", 81 + "items": { 82 + "type": "string", 83 + "format": "at-uri" 84 + } 85 + }, 86 + "createdAt": { 87 + "type": "string", 88 + "format": "datetime" 89 + } 90 + } 91 + } 92 + } 93 + } 94 + }
+15 -24
internal/atproto/lexicon/social/coves/post/update.json
··· 22 22 "maxLength": 3000, 23 23 "description": "Updated title" 24 24 }, 25 - "content": { 25 + "text": { 26 26 "type": "string", 27 - "maxLength": 50000, 28 - "description": "Updated content - main text for text posts, description for media, etc." 27 + "maxGraphemes": 10000, 28 + "maxLength": 100000, 29 + "description": "Updated body text" 29 30 }, 30 - "facets": { 31 + "textFacets": { 31 32 "type": "array", 32 - "description": "Updated rich text annotations for content", 33 + "description": "Updated rich text annotations", 33 34 "items": { 34 35 "type": "ref", 35 36 "ref": "social.coves.richtext.facet" 36 37 } 37 38 }, 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": { 39 + "tags": { 49 40 "type": "array", 50 - "description": "Updated content labels", 41 + "maxLength": 10, 51 42 "items": { 52 43 "type": "string", 53 - "knownValues": ["nsfw", "spoiler", "violence"], 54 - "maxLength": 32 55 - } 44 + "maxLength": 50 45 + }, 46 + "description": "Updated tags" 47 + }, 48 + "nsfw": { 49 + "type": "boolean", 50 + "description": "Updated NSFW status" 56 51 }, 57 52 "editNote": { 58 53 "type": "string", ··· 93 88 { 94 89 "name": "EditWindowExpired", 95 90 "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 91 } 101 92 ] 102 93 }
+92
internal/atproto/lexicon/social/coves/post/video.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "social.coves.post.video", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "description": "A video post", 8 + "key": "tid", 9 + "record": { 10 + "type": "object", 11 + "required": ["community", "title", "video", "createdAt"], 12 + "properties": { 13 + "community": { 14 + "type": "string", 15 + "format": "at-identifier", 16 + "description": "DID or handle of the community this was posted to" 17 + }, 18 + "title": { 19 + "type": "string", 20 + "maxGraphemes": 300, 21 + "maxLength": 3000, 22 + "description": "Post title" 23 + }, 24 + "video": { 25 + "type": "ref", 26 + "ref": "social.coves.embed.video", 27 + "description": "Video content" 28 + }, 29 + "caption": { 30 + "type": "string", 31 + "maxLength": 10000, 32 + "description": "Optional caption or description" 33 + }, 34 + "captionFacets": { 35 + "type": "array", 36 + "description": "Rich text annotations for caption", 37 + "items": { 38 + "type": "ref", 39 + "ref": "social.coves.richtext.facet" 40 + } 41 + }, 42 + "tags": { 43 + "type": "array", 44 + "maxLength": 10, 45 + "items": { 46 + "type": "string", 47 + "maxLength": 32 48 + } 49 + }, 50 + "nsfw": { 51 + "type": "boolean", 52 + "default": false 53 + }, 54 + "contentLabels": { 55 + "type": "array", 56 + "description": "Self-applied content labels", 57 + "items": { 58 + "type": "string", 59 + "knownValues": ["nsfw", "spoiler", "violence"], 60 + "maxLength": 32 61 + } 62 + }, 63 + "federatedFrom": { 64 + "type": "ref", 65 + "ref": "social.coves.federation.post" 66 + }, 67 + "location": { 68 + "type": "ref", 69 + "ref": "social.coves.actor.profile#geoLocation" 70 + }, 71 + "crosspostOf": { 72 + "type": "string", 73 + "format": "at-uri", 74 + "description": "If this is a crosspost, AT-URI of the post this is a crosspost of" 75 + }, 76 + "crosspostChain": { 77 + "type": "array", 78 + "description": "Array of AT-URIs of all posts in the crosspost chain (including this one)", 79 + "items": { 80 + "type": "string", 81 + "format": "at-uri" 82 + } 83 + }, 84 + "createdAt": { 85 + "type": "string", 86 + "format": "datetime" 87 + } 88 + } 89 + } 90 + } 91 + } 92 + }