chore: add grain social lexicon schemas

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Changed files
+883
lexicons
app
bsky
actor
richtext
com
atproto
social
+74
lexicons/app/bsky/actor/profile.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "app.bsky.actor.profile", 4 + "defs": { 5 + "main": { 6 + "key": "literal:self", 7 + "type": "record", 8 + "record": { 9 + "type": "object", 10 + "properties": { 11 + "avatar": { 12 + "type": "blob", 13 + "accept": [ 14 + "image/png", 15 + "image/jpeg" 16 + ], 17 + "maxSize": 1000000, 18 + "description": "Small image to be displayed next to posts from account. AKA, 'profile picture'" 19 + }, 20 + "banner": { 21 + "type": "blob", 22 + "accept": [ 23 + "image/png", 24 + "image/jpeg" 25 + ], 26 + "maxSize": 1000000, 27 + "description": "Larger horizontal image to display behind profile view." 28 + }, 29 + "labels": { 30 + "refs": [ 31 + "com.atproto.label.defs#selfLabels" 32 + ], 33 + "type": "union", 34 + "description": "Self-label values, specific to the Bluesky application, on the overall account." 35 + }, 36 + "website": { 37 + "type": "string", 38 + "format": "uri" 39 + }, 40 + "pronouns": { 41 + "type": "string", 42 + "maxLength": 200, 43 + "description": "Free-form pronouns text.", 44 + "maxGraphemes": 20 45 + }, 46 + "createdAt": { 47 + "type": "string", 48 + "format": "datetime" 49 + }, 50 + "pinnedPost": { 51 + "ref": "com.atproto.repo.strongRef", 52 + "type": "ref" 53 + }, 54 + "description": { 55 + "type": "string", 56 + "maxLength": 2560, 57 + "description": "Free-form profile description text.", 58 + "maxGraphemes": 256 59 + }, 60 + "displayName": { 61 + "type": "string", 62 + "maxLength": 640, 63 + "maxGraphemes": 64 64 + }, 65 + "joinedViaStarterPack": { 66 + "ref": "com.atproto.repo.strongRef", 67 + "type": "ref" 68 + } 69 + } 70 + }, 71 + "description": "A declaration of a Bluesky account profile." 72 + } 73 + } 74 + }
+73
lexicons/app/bsky/richtext/factet.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "app.bsky.richtext.facet", 4 + "defs": { 5 + "tag": { 6 + "type": "object", 7 + "required": ["tag"], 8 + "properties": { 9 + "tag": { 10 + "type": "string", 11 + "maxLength": 640, 12 + "maxGraphemes": 64 13 + } 14 + }, 15 + "description": "Facet feature for a hashtag. The text usually includes a '#' prefix, but the facet reference should not (except in the case of 'double hash tags')." 16 + }, 17 + "link": { 18 + "type": "object", 19 + "required": ["uri"], 20 + "properties": { 21 + "uri": { 22 + "type": "string", 23 + "format": "uri" 24 + } 25 + }, 26 + "description": "Facet feature for a URL. The text URL may have been simplified or truncated, but the facet reference should be a complete URL." 27 + }, 28 + "main": { 29 + "type": "object", 30 + "required": ["index", "features"], 31 + "properties": { 32 + "index": { 33 + "ref": "#byteSlice", 34 + "type": "ref" 35 + }, 36 + "features": { 37 + "type": "array", 38 + "items": { 39 + "refs": ["#mention", "#link", "#tag"], 40 + "type": "union" 41 + } 42 + } 43 + }, 44 + "description": "Annotation of a sub-string within rich text." 45 + }, 46 + "mention": { 47 + "type": "object", 48 + "required": ["did"], 49 + "properties": { 50 + "did": { 51 + "type": "string", 52 + "format": "did" 53 + } 54 + }, 55 + "description": "Facet feature for mention of another account. The text is usually a handle, including a '@' prefix, but the facet reference is a DID." 56 + }, 57 + "byteSlice": { 58 + "type": "object", 59 + "required": ["byteStart", "byteEnd"], 60 + "properties": { 61 + "byteEnd": { 62 + "type": "integer", 63 + "minimum": 0 64 + }, 65 + "byteStart": { 66 + "type": "integer", 67 + "minimum": 0 68 + } 69 + }, 70 + "description": "Specifies the sub-string range a facet feature applies to. Start index is inclusive, end index is exclusive. Indices are zero-indexed, counting bytes of the UTF-8 encoded text. NOTE: some languages, like Javascript, use UTF-16 or Unicode codepoints for string slice indexing; in these languages, convert to byte arrays before working with facets." 71 + } 72 + } 73 + }
+192
lexicons/com/atproto/label/defs.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "com.atproto.label.defs", 4 + "defs": { 5 + "label": { 6 + "type": "object", 7 + "required": [ 8 + "src", 9 + "uri", 10 + "val", 11 + "cts" 12 + ], 13 + "properties": { 14 + "cid": { 15 + "type": "string", 16 + "format": "cid", 17 + "description": "Optionally, CID specifying the specific version of 'uri' resource this label applies to." 18 + }, 19 + "cts": { 20 + "type": "string", 21 + "format": "datetime", 22 + "description": "Timestamp when this label was created." 23 + }, 24 + "exp": { 25 + "type": "string", 26 + "format": "datetime", 27 + "description": "Timestamp at which this label expires (no longer applies)." 28 + }, 29 + "neg": { 30 + "type": "boolean", 31 + "description": "If true, this is a negation label, overwriting a previous label." 32 + }, 33 + "sig": { 34 + "type": "bytes", 35 + "description": "Signature of dag-cbor encoded label." 36 + }, 37 + "src": { 38 + "type": "string", 39 + "format": "did", 40 + "description": "DID of the actor who created this label." 41 + }, 42 + "uri": { 43 + "type": "string", 44 + "format": "uri", 45 + "description": "AT URI of the record, repository (account), or other resource that this label applies to." 46 + }, 47 + "val": { 48 + "type": "string", 49 + "maxLength": 128, 50 + "description": "The short string name of the value or type of this label." 51 + }, 52 + "ver": { 53 + "type": "integer", 54 + "description": "The AT Protocol version of the label object." 55 + } 56 + }, 57 + "description": "Metadata tag on an atproto resource (eg, repo or record)." 58 + }, 59 + "selfLabel": { 60 + "type": "object", 61 + "required": [ 62 + "val" 63 + ], 64 + "properties": { 65 + "val": { 66 + "type": "string", 67 + "maxLength": 128, 68 + "description": "The short string name of the value or type of this label." 69 + } 70 + }, 71 + "description": "Metadata tag on an atproto record, published by the author within the record. Note that schemas should use #selfLabels, not #selfLabel." 72 + }, 73 + "labelValue": { 74 + "type": "string", 75 + "knownValues": [ 76 + "!hide", 77 + "!no-promote", 78 + "!warn", 79 + "!no-unauthenticated", 80 + "dmca-violation", 81 + "doxxing", 82 + "porn", 83 + "sexual", 84 + "nudity", 85 + "nsfl", 86 + "gore" 87 + ] 88 + }, 89 + "selfLabels": { 90 + "type": "object", 91 + "required": [ 92 + "values" 93 + ], 94 + "properties": { 95 + "values": { 96 + "type": "array", 97 + "items": { 98 + "ref": "#selfLabel", 99 + "type": "ref" 100 + }, 101 + "maxLength": 10 102 + } 103 + }, 104 + "description": "Metadata tags on an atproto record, published by the author within the record." 105 + }, 106 + "labelValueDefinition": { 107 + "type": "object", 108 + "required": [ 109 + "identifier", 110 + "severity", 111 + "blurs", 112 + "locales" 113 + ], 114 + "properties": { 115 + "blurs": { 116 + "type": "string", 117 + "description": "What should this label hide in the UI, if applied? 'content' hides all of the target; 'media' hides the images/video/audio; 'none' hides nothing.", 118 + "knownValues": [ 119 + "content", 120 + "media", 121 + "none" 122 + ] 123 + }, 124 + "locales": { 125 + "type": "array", 126 + "items": { 127 + "ref": "#labelValueDefinitionStrings", 128 + "type": "ref" 129 + } 130 + }, 131 + "severity": { 132 + "type": "string", 133 + "description": "How should a client visually convey this label? 'inform' means neutral and informational; 'alert' means negative and warning; 'none' means show nothing.", 134 + "knownValues": [ 135 + "inform", 136 + "alert", 137 + "none" 138 + ] 139 + }, 140 + "adultOnly": { 141 + "type": "boolean", 142 + "description": "Does the user need to have adult content enabled in order to configure this label?" 143 + }, 144 + "identifier": { 145 + "type": "string", 146 + "maxLength": 100, 147 + "description": "The value of the label being defined. Must only include lowercase ascii and the '-' character ([a-z-]+).", 148 + "maxGraphemes": 100 149 + }, 150 + "defaultSetting": { 151 + "type": "string", 152 + "default": "warn", 153 + "description": "The default setting for this label.", 154 + "knownValues": [ 155 + "ignore", 156 + "warn", 157 + "hide" 158 + ] 159 + } 160 + }, 161 + "description": "Declares a label value and its expected interpretations and behaviors." 162 + }, 163 + "labelValueDefinitionStrings": { 164 + "type": "object", 165 + "required": [ 166 + "lang", 167 + "name", 168 + "description" 169 + ], 170 + "properties": { 171 + "lang": { 172 + "type": "string", 173 + "format": "language", 174 + "description": "The code of the language these strings are written in." 175 + }, 176 + "name": { 177 + "type": "string", 178 + "maxLength": 640, 179 + "description": "A short human-readable name for the label.", 180 + "maxGraphemes": 64 181 + }, 182 + "description": { 183 + "type": "string", 184 + "maxLength": 100000, 185 + "description": "A longer description of what the label means and why it might be applied.", 186 + "maxGraphemes": 10000 187 + } 188 + }, 189 + "description": "Strings which describe the label in the UI, localized into a specific language." 190 + } 191 + } 192 + }
+24
lexicons/com/atproto/repo/strongRef.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "com.atproto.repo.strongRef", 4 + "description": "A URI with a content-hash fingerprint.", 5 + "defs": { 6 + "main": { 7 + "type": "object", 8 + "required": [ 9 + "uri", 10 + "cid" 11 + ], 12 + "properties": { 13 + "cid": { 14 + "type": "string", 15 + "format": "cid" 16 + }, 17 + "uri": { 18 + "type": "string", 19 + "format": "at-uri" 20 + } 21 + } 22 + } 23 + } 24 + }
+77
lexicons/social/grain/actor/defs.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "social.grain.actor.defs", 4 + "defs": { 5 + "profileView": { 6 + "type": "object", 7 + "required": ["cid", "did", "handle"], 8 + "properties": { 9 + "cid": { "type": "string", "format": "cid" }, 10 + "did": { "type": "string", "format": "did" }, 11 + "handle": { "type": "string", "format": "handle" }, 12 + "displayName": { 13 + "type": "string", 14 + "maxGraphemes": 64, 15 + "maxLength": 640 16 + }, 17 + "description": { 18 + "type": "string", 19 + "maxLength": 2560, 20 + "maxGraphemes": 256 21 + }, 22 + "labels": { 23 + "type": "array", 24 + "items": { 25 + "ref": "com.atproto.label.defs#label", 26 + "type": "ref" 27 + } 28 + }, 29 + "avatar": { "type": "string", "format": "uri" }, 30 + "createdAt": { "type": "string", "format": "datetime" } 31 + } 32 + }, 33 + "profileViewDetailed": { 34 + "type": "object", 35 + "required": ["cid", "did", "handle"], 36 + "properties": { 37 + "cid": { "type": "string", "format": "cid" }, 38 + "did": { "type": "string", "format": "did" }, 39 + "handle": { "type": "string", "format": "handle" }, 40 + "displayName": { 41 + "type": "string", 42 + "maxGraphemes": 64, 43 + "maxLength": 640 44 + }, 45 + "description": { 46 + "type": "string", 47 + "maxGraphemes": 256, 48 + "maxLength": 2560 49 + }, 50 + "avatar": { "type": "string", "format": "uri" }, 51 + "cameras": { 52 + "type": "array", 53 + "items": { "type": "string" }, 54 + "description": "List of camera make and models used by this actor derived from EXIF data of photos linked to galleries." 55 + }, 56 + "followersCount": { "type": "integer" }, 57 + "followsCount": { "type": "integer" }, 58 + "galleryCount": { "type": "integer" }, 59 + "indexedAt": { "type": "string", "format": "datetime" }, 60 + "createdAt": { "type": "string", "format": "datetime" }, 61 + "viewer": { "type": "ref", "ref": "#viewerState" }, 62 + "labels": { 63 + "type": "array", 64 + "items": { "type": "ref", "ref": "com.atproto.label.defs#label" } 65 + } 66 + } 67 + }, 68 + "viewerState": { 69 + "type": "object", 70 + "description": "Metadata about the requesting account's relationship with the subject account. Only has meaningful content for authed requests.", 71 + "properties": { 72 + "following": { "type": "string", "format": "at-uri" }, 73 + "followedBy": { "type": "string", "format": "at-uri" } 74 + } 75 + } 76 + } 77 + }
+34
lexicons/social/grain/actor/profile.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "social.grain.actor.profile", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "description": "A declaration of a basic account profile.", 8 + "key": "literal:self", 9 + "record": { 10 + "type": "object", 11 + "properties": { 12 + "displayName": { 13 + "type": "string", 14 + "maxGraphemes": 64, 15 + "maxLength": 640 16 + }, 17 + "description": { 18 + "type": "string", 19 + "description": "Free-form profile description text.", 20 + "maxGraphemes": 256, 21 + "maxLength": 2560 22 + }, 23 + "avatar": { 24 + "type": "blob", 25 + "description": "Small image to be displayed next to posts from account. AKA, 'profile picture'", 26 + "accept": ["image/png", "image/jpeg"], 27 + "maxSize": 1000000 28 + }, 29 + "createdAt": { "type": "string", "format": "datetime" } 30 + } 31 + } 32 + } 33 + } 34 + }
+42
lexicons/social/grain/comment/comment.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "social.grain.comment", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "key": "tid", 8 + "record": { 9 + "type": "object", 10 + "required": ["text", "subject", "createdAt"], 11 + "properties": { 12 + "text": { 13 + "type": "string", 14 + "maxLength": 3000, 15 + "maxGraphemes": 300 16 + }, 17 + "facets": { 18 + "type": "array", 19 + "description": "Annotations of description text (mentions and URLs, hashtags, etc)", 20 + "items": { "type": "ref", "ref": "app.bsky.richtext.facet" } 21 + }, 22 + "subject": { 23 + "type": "string", 24 + "format": "at-uri" 25 + }, 26 + "focus": { 27 + "type": "string", 28 + "format": "at-uri" 29 + }, 30 + "replyTo": { 31 + "type": "string", 32 + "format": "at-uri" 33 + }, 34 + "createdAt": { 35 + "type": "string", 36 + "format": "datetime" 37 + } 38 + } 39 + } 40 + } 41 + } 42 + }
+52
lexicons/social/grain/comment/defs.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "social.grain.comment.defs", 4 + "defs": { 5 + "commentView": { 6 + "type": "object", 7 + "required": ["uri", "cid", "author", "text", "createdAt"], 8 + "properties": { 9 + "uri": { "type": "string", "format": "at-uri" }, 10 + "cid": { "type": "string", "format": "cid" }, 11 + "author": { 12 + "type": "ref", 13 + "ref": "social.grain.actor.defs#profileView" 14 + }, 15 + "record": { "type": "unknown" }, 16 + "text": { 17 + "type": "string", 18 + "maxLength": 3000, 19 + "maxGraphemes": 300 20 + }, 21 + "facets": { 22 + "type": "array", 23 + "description": "Annotations of description text (mentions and URLs, hashtags, etc)", 24 + "items": { "type": "ref", "ref": "app.bsky.richtext.facet" } 25 + }, 26 + "subject": { 27 + "type": "union", 28 + "refs": [ 29 + "social.grain.gallery.defs#galleryView" 30 + ], 31 + "description": "The subject of the comment, which can be a gallery or a photo." 32 + }, 33 + "focus": { 34 + "type": "union", 35 + "refs": [ 36 + "social.grain.photo.defs#photoView" 37 + ], 38 + "description": "The photo that the comment is focused on, if applicable." 39 + }, 40 + "replyTo": { 41 + "type": "string", 42 + "format": "at-uri", 43 + "description": "The URI of the comment this comment is replying to, if applicable." 44 + }, 45 + "createdAt": { 46 + "type": "string", 47 + "format": "datetime" 48 + } 49 + } 50 + } 51 + } 52 + }
+15
lexicons/social/grain/defs.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "social.grain.defs", 4 + "defs": { 5 + "aspectRatio": { 6 + "type": "object", 7 + "description": "width:height represents an aspect ratio. It may be approximate, and may not correspond to absolute dimensions in any given unit.", 8 + "required": ["width", "height"], 9 + "properties": { 10 + "width": { "type": "integer", "minimum": 1 }, 11 + "height": { "type": "integer", "minimum": 1 } 12 + } 13 + } 14 + } 15 + }
+24
lexicons/social/grain/favorite/favorite.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "social.grain.favorite", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "key": "tid", 8 + "record": { 9 + "type": "object", 10 + "required": ["createdAt", "subject"], 11 + "properties": { 12 + "createdAt": { 13 + "type": "string", 14 + "format": "datetime" 15 + }, 16 + "subject": { 17 + "type": "string", 18 + "format": "at-uri" 19 + } 20 + } 21 + } 22 + } 23 + } 24 + }
+56
lexicons/social/grain/gallery/defs.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "social.grain.gallery.defs", 4 + "defs": { 5 + "galleryView": { 6 + "type": "object", 7 + "required": ["uri", "cid", "creator", "record", "indexedAt"], 8 + "properties": { 9 + "uri": { "type": "string", "format": "at-uri" }, 10 + "cid": { "type": "string", "format": "cid" }, 11 + "title": { "type": "string" }, 12 + "description": { "type": "string" }, 13 + "cameras": { 14 + "type": "array", 15 + "description": "List of camera make and models used in this gallery derived from EXIF data.", 16 + "items": { "type": "string" } 17 + }, 18 + "facets": { 19 + "type": "array", 20 + "description": "Annotations of description text (mentions, URLs, hashtags, etc)", 21 + "items": { "type": "ref", "ref": "app.bsky.richtext.facet" } 22 + }, 23 + "creator": { 24 + "type": "ref", 25 + "ref": "social.grain.actor.defs#profileView" 26 + }, 27 + "record": { "type": "unknown" }, 28 + "items": { 29 + "type": "array", 30 + "items": { 31 + "type": "union", 32 + "refs": [ 33 + "social.grain.photo.defs#photoView" 34 + ] 35 + } 36 + }, 37 + "favCount": { "type": "integer" }, 38 + "commentCount": { "type": "integer" }, 39 + "labels": { 40 + "type": "array", 41 + "items": { "type": "ref", "ref": "com.atproto.label.defs#label" } 42 + }, 43 + "createdAt": { "type": "string", "format": "datetime" }, 44 + "indexedAt": { "type": "string", "format": "datetime" }, 45 + "viewer": { "type": "ref", "ref": "#viewerState" } 46 + } 47 + }, 48 + "viewerState": { 49 + "type": "object", 50 + "description": "Metadata about the requesting account's relationship with the subject content. Only has meaningful content for authed requests.", 51 + "properties": { 52 + "fav": { "type": "string", "format": "at-uri" } 53 + } 54 + } 55 + } 56 + }
+30
lexicons/social/grain/gallery/gallery.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "social.grain.gallery", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "key": "tid", 8 + "record": { 9 + "type": "object", 10 + "required": ["title", "createdAt"], 11 + "properties": { 12 + "title": { "type": "string", "maxLength": 100 }, 13 + "description": { "type": "string", "maxLength": 1000 }, 14 + "facets": { 15 + "type": "array", 16 + "description": "Annotations of description text (mentions, URLs, hashtags, etc)", 17 + "items": { "type": "ref", "ref": "app.bsky.richtext.facet" } 18 + }, 19 + "labels": { 20 + "type": "union", 21 + "description": "Self-label values for this post. Effectively content warnings.", 22 + "refs": ["com.atproto.label.defs#selfLabels"] 23 + }, 24 + "updatedAt": { "type": "string", "format": "datetime" }, 25 + "createdAt": { "type": "string", "format": "datetime" } 26 + } 27 + } 28 + } 29 + } 30 + }
+32
lexicons/social/grain/gallery/item.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "social.grain.gallery.item", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "key": "tid", 8 + "record": { 9 + "type": "object", 10 + "required": ["createdAt", "gallery", "item"], 11 + "properties": { 12 + "createdAt": { 13 + "type": "string", 14 + "format": "datetime" 15 + }, 16 + "gallery": { 17 + "type": "string", 18 + "format": "at-uri" 19 + }, 20 + "item": { 21 + "type": "string", 22 + "format": "at-uri" 23 + }, 24 + "position": { 25 + "type": "integer", 26 + "default": 0 27 + } 28 + } 29 + } 30 + } 31 + } 32 + }
+27
lexicons/social/grain/graph/follow.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "social.grain.graph.follow", 4 + "defs": { 5 + "main": { 6 + "key": "tid", 7 + "type": "record", 8 + "record": { 9 + "type": "object", 10 + "required": [ 11 + "subject", 12 + "createdAt" 13 + ], 14 + "properties": { 15 + "subject": { 16 + "type": "string", 17 + "format": "did" 18 + }, 19 + "createdAt": { 20 + "type": "string", 21 + "format": "datetime" 22 + } 23 + } 24 + } 25 + } 26 + } 27 + }
+69
lexicons/social/grain/photo/defs.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "social.grain.photo.defs", 4 + "defs": { 5 + "photoView": { 6 + "type": "object", 7 + "required": ["uri", "cid", "thumb", "fullsize", "aspectRatio"], 8 + "properties": { 9 + "uri": { "type": "string", "format": "at-uri" }, 10 + "cid": { "type": "string", "format": "cid" }, 11 + "thumb": { 12 + "type": "string", 13 + "format": "uri", 14 + "description": "Fully-qualified URL where a thumbnail of the image can be fetched. For example, CDN location provided by the App View." 15 + }, 16 + "fullsize": { 17 + "type": "string", 18 + "format": "uri", 19 + "description": "Fully-qualified URL where a large version of the image can be fetched. May or may not be the exact original blob. For example, CDN location provided by the App View." 20 + }, 21 + "alt": { 22 + "type": "string", 23 + "description": "Alt text description of the image, for accessibility." 24 + }, 25 + "aspectRatio": { 26 + "type": "ref", 27 + "ref": "social.grain.defs#aspectRatio" 28 + }, 29 + "exif": { 30 + "type": "ref", 31 + "ref": "social.grain.photo.defs#exifView", 32 + "description": "EXIF metadata for the photo, if available." 33 + }, 34 + "gallery": { "type": "ref", "ref": "#galleryState" } 35 + } 36 + }, 37 + "exifView": { 38 + "type": "object", 39 + "required": ["uri", "cid", "photo", "record", "createdAt"], 40 + "properties": { 41 + "uri": { "type": "string", "format": "at-uri" }, 42 + "cid": { "type": "string", "format": "cid" }, 43 + "photo": { "type": "string", "format": "at-uri" }, 44 + "record": { "type": "unknown" }, 45 + "createdAt": { "type": "string", "format": "datetime" }, 46 + "dateTimeOriginal": { "type": "string" }, 47 + "exposureTime": { "type": "string" }, 48 + "fNumber": { "type": "string" }, 49 + "flash": { "type": "string" }, 50 + "focalLengthIn35mmFormat": { "type": "string" }, 51 + "iSO": { "type": "integer" }, 52 + "lensMake": { "type": "string" }, 53 + "lensModel": { "type": "string" }, 54 + "make": { "type": "string" }, 55 + "model": { "type": "string" } 56 + } 57 + }, 58 + "galleryState": { 59 + "type": "object", 60 + "required": ["item", "itemCreatedAt", "itemPosition"], 61 + "description": "Metadata about the photo's relationship with the subject content. Only has meaningful content when photo is attached to a gallery.", 62 + "properties": { 63 + "item": { "type": "string", "format": "at-uri" }, 64 + "itemCreatedAt": { "type": "string", "format": "datetime" }, 65 + "itemPosition": { "type": "integer" } 66 + } 67 + } 68 + } 69 + }
+32
lexicons/social/grain/photo/exif.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "social.grain.photo.exif", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "description": "Basic EXIF metadata for a photo. Integers are scaled by 1000000 to accommodate decimal values and potentially other tags in the future.", 8 + "key": "tid", 9 + "record": { 10 + "type": "object", 11 + "required": [ 12 + "photo", 13 + "createdAt" 14 + ], 15 + "properties": { 16 + "photo": { "type": "string", "format": "at-uri" }, 17 + "createdAt": { "type": "string", "format": "datetime" }, 18 + "dateTimeOriginal": { "type": "string", "format": "datetime" }, 19 + "exposureTime": { "type": "integer" }, 20 + "fNumber": { "type": "integer" }, 21 + "flash": { "type": "string" }, 22 + "focalLengthIn35mmFormat": { "type": "integer" }, 23 + "iSO": { "type": "integer" }, 24 + "lensMake": { "type": "string" }, 25 + "lensModel": { "type": "string" }, 26 + "make": { "type": "string" }, 27 + "model": { "type": "string" } 28 + } 29 + } 30 + } 31 + } 32 + }
+30
lexicons/social/grain/photo/photo.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "social.grain.photo", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "key": "tid", 8 + "record": { 9 + "type": "object", 10 + "required": ["photo", "aspectRatio", "createdAt"], 11 + "properties": { 12 + "photo": { 13 + "type": "blob", 14 + "accept": ["image/*"], 15 + "maxSize": 1000000 16 + }, 17 + "alt": { 18 + "type": "string", 19 + "description": "Alt text description of the image, for accessibility." 20 + }, 21 + "aspectRatio": { 22 + "type": "ref", 23 + "ref": "social.grain.defs#aspectRatio" 24 + }, 25 + "createdAt": { "type": "string", "format": "datetime" } 26 + } 27 + } 28 + } 29 + } 30 + }