geocaches for the atmosphere
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Major lexicon refactor. Focusing on basic caches and fleshing out the attestations

+218 -518
-158
lexicon/world.geocache.attribute.defs.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "world.geocache.attribute", 4 - "defs": { 5 - "fee": { 6 - "type": "token", 7 - "description": "This cache requires an entry fee, like a park admission fee." 8 - }, 9 - "allAges": { 10 - "type": "token", 11 - "description": "This cache is suitable for all ages. It is easy and safe to find, and does not contain NSFW materials." 12 - }, 13 - "winterFriendly": { 14 - "type": "token", 15 - "description": "This cache is accessible during winter." 16 - }, 17 - "poisonousPlants": { 18 - "type": "token", 19 - "description": "This cache is in an area known to have poisonous plants." 20 - }, 21 - "snakes": { 22 - "type": "token", 23 - "description": "This cache is in an area known to have snakes." 24 - }, 25 - "ticks": { 26 - "type": "token", 27 - "description": "This cache is in an area known to have ticks." 28 - }, 29 - "dangerous": { 30 - "type": "token", 31 - "description": "This cache is in an area which poses significant risk of injury or other dangers." 32 - }, 33 - "accessible": { 34 - "type": "token", 35 - "description": "This cache is accessible to people of all abilities." 36 - }, 37 - "thorns": { 38 - "type": "token", 39 - "description": "This cache is in an area known to have thorny plants." 40 - }, 41 - "flashlight": { 42 - "type": "token", 43 - "description": "This cache requires a flashlight to find." 44 - }, 45 - "bigrig": { 46 - "type": "token", 47 - "description": "This cache is in an area accessible to large vehicles, like RVs and trucks." 48 - }, 49 - "trail": { 50 - "type": "token", 51 - "description": "This cache is only accessible through non-paved trails." 52 - }, 53 - "specialEquipment": { 54 - "type": "token", 55 - "description": "This cache needs special equipment to access -- see description of cache." 56 - }, 57 - "night": { 58 - "type": "token", 59 - "description": "This cache is able to be found at night with use of a flashlight, such as with reflective markers." 60 - }, 61 - "garminChirp": { 62 - "type": "token", 63 - "description": "This cache contains a Garmin Chirp device." 64 - }, 65 - "letterbox": { 66 - "type": "token", 67 - "description": "This cache is a letterbox, and contains a stamp the cacher can use to mark their own logbook." 68 - }, 69 - "compass": { 70 - "type": "token", 71 - "description": "This cache requires use of a compass to find." 72 - }, 73 - "quick": { 74 - "type": "token", 75 - "description": "This cache can be found within 15 minutes, including access time from the nearest parking space, transit stop, or trailhead." 76 - }, 77 - "traveller": { 78 - "type": "token", 79 - "description": "This cache is suitable for travellers." 80 - }, 81 - "byop": { 82 - "type": "token", 83 - "description": "This cache does not have a pen for you to use, so the cacher must bring their own." 84 - }, 85 - "magnetic": { 86 - "type": "token", 87 - "description": "This cache is magnetically attached to its resting place." 88 - }, 89 - "audio": { 90 - "type": "token", 91 - "description": "This cache has audio cues available." 92 - }, 93 - "offset": { 94 - "type": "token", 95 - "description": "This cache requires multiple steps in order to find it." 96 - }, 97 - "usb": { 98 - "type": "token", 99 - "description": "This cache contains, or is in its entirety, a USB flashdrive." 100 - }, 101 - "surveyBenchmark": { 102 - "type": "token", 103 - "description": "This cache is, or is near, a survey benchmark." 104 - }, 105 - "woods": { 106 - "type": "token", 107 - "description": "This cache is located in a forested area." 108 - }, 109 - "historic": { 110 - "type": "token", 111 - "description": "This cache is located in or near a site of historic significance." 112 - }, 113 - "advertisement": { 114 - "type": "token", 115 - "description": "This cache contains, or is in of itself, an advertisement for some commercial entity." 116 - }, 117 - "limitedaccess": { 118 - "type": "token", 119 - "description": "This cache has limited access opportunities, including but not limited to: time-of-day limited, seasonally limited." 120 - }, 121 - "guestBook": { 122 - "type": "token", 123 - "description": "This cache is an existing, permanent guestbook open to the public, such as ones located in a visitor center or hotel." 124 - }, 125 - "challenge": { 126 - "type": "token", 127 - "description": "This cache is not suitable for beginner cachers, and may require advanced techniques to find." 128 - }, 129 - "urban": { 130 - "type": "token", 131 - "description": "This cache is located in an urban environment." 132 - }, 133 - "bikeFriendly": { 134 - "type": "token", 135 - "description": "This cache is located in an area accessible by bicycle." 136 - }, 137 - "keypair": { 138 - "type": "token", 139 - "description": "This cache has a public/private keypair that can be used to create a visit signature." 140 - }, 141 - "noInternet": { 142 - "type": "token", 143 - "description": "This cache is located somewhere without reliable, commonly available internet access, such as a public wifi hotspot, or a mobile network." 144 - }, 145 - "bushwhacking": { 146 - "type": "token", 147 - "description": "This cache is located somewhere that does not have an established path or trail of any sort." 148 - }, 149 - "underwater": { 150 - "type": "token", 151 - "description": "This cache is located inside a body of water." 152 - }, 153 - "cave": { 154 - "type": "token", 155 - "description": "This cache is located inside a cave." 156 - }, 157 - } 158 - }
+44
lexicon/world.geocache.cache.attestor.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "world.geocache.cache.attestor", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "description": "The methodology for verifying a visit to the associated geocache.", 8 + "key": "tid", 9 + "record": { 10 + "type": "object", 11 + "required": ["method"], 12 + "properties": { 13 + "method": { 14 + "type": "ref", 15 + "description": "The methodology for verifying a visit to the associated geocache.", 16 + "ref": "world.geocache.attestor.method" 17 + } 18 + } 19 + } 20 + }, 21 + "method": { 22 + "type": "object", 23 + "description": "The methodology for verifying a visit to the associated geocache.", 24 + "required": ["by"], 25 + "properties": { 26 + "by": { 27 + "type": "string", 28 + "description": "The methodology used.", 29 + "knownValues": ["world.geocache.attestor.tokenDecryption"] 30 + }, 31 + "publicKey": { 32 + "type": "string", 33 + "description": "The public key associated with the attestor.", 34 + "maxLength": 10000, 35 + "maxGraphemes": 1000 36 + } 37 + } 38 + }, 39 + "tokenDecryption": { 40 + "type": "token", 41 + "description": "The geocache will have tokens, physical or otherwise, that are signed with a private key, which are included with a visit record and then decrypted as proof of the visit occuring." 42 + } 43 + } 44 + }
-45
lexicon/world.geocache.cache.get.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "world.geocache.cache.get", 4 - "defs": { 5 - "main": { 6 - "type": "query", 7 - "description": "Gets hydrated data for a geocache.", 8 - "parameters": { 9 - "type": "params", 10 - "required": ["did", "rkey"], 11 - "properties": { 12 - "did": { 13 - "type": "string", 14 - "format": "at-identifier", 15 - "description": "The DID of the cache maintainer." 16 - }, 17 - "rkey": { 18 - "type": "string", 19 - "description": "The record key." 20 - } 21 - } 22 - }, 23 - "output": { 24 - "encoding": "application/json", 25 - "schema": { 26 - "type": "object", 27 - "required": ["cache"], 28 - "properties": { 29 - /* the geocache lexicon is a bit complex -- it points to at least one extra other record, 30 - potentially many. it would be simpler for the client if we provided a "hydrated" cache, 31 - with all the data belonging to the geocache record being displayed in a "flat" manner. 32 - 33 - this would also allow visits for a cache to be given with the cache, though we may need 34 - in the future a cursor type system for very long running geocaches... 35 - */ 36 - "cache": { 37 - "type": "ref", 38 - "refs": "world.geocache.hydratedCache" 39 - }, 40 - } 41 - } 42 - } 43 - } 44 - } 45 - }
+104 -242
lexicon/world.geocache.cache.json
··· 1 1 { 2 2 "lexicon": 1, 3 3 "id": "world.geocache.cache", 4 - "defs": { 5 - "main": { 6 - "type": "record", 7 - "description": "A geocache out there in the world", 8 - "key": "tid", 9 - "record": { 10 - "type": "object", 11 - "required": ["name", "location", "cacheType", "status", "attributes", "description", "createdAt"], 12 - "properties": { 13 - "name": { 14 - "type": "string", 15 - "maxLength": 1000, 16 - "maxGraphemes": 100, 17 - "description": "The name for the geocache" 18 - }, 19 - "location": { 20 - /* because we want to support many types of geocaches, we don't want 21 - to force any location type on the cache. generally, most non-digital 22 - geocaches will have an address and a geo coordinate, whereas 23 - digital ones will only have a URI 24 - 25 - this property can be extended with additional location data for 26 - whatever niche caches users may wish to create 27 - */ 28 - "type": "object", 29 - "properties": { 30 - "geo": { "type": "ref", "ref": "community.lexicon.location.geo" }, 31 - "address": { "type": "ref", "ref": "community.lexicon.location.address" }, 32 - "hthree": { "type": "ref", "ref": "community.lexicon.location.hthree" }, 33 - "uri": { "type": "string", "format": "uri"} 34 - } 35 - }, 36 - "cacheType": { 37 - "type": "ref", 38 - "ref": "world.geocache.cache#cacheType" 39 - }, 40 - "status": { 41 - "type": "ref", 42 - "description": "The status of the geocache", 43 - "ref": "world.geocache.cache#status" 44 - }, 45 - "attributes": { 46 - "type": "array", 47 - "description": "Information about the geocache.", 48 - "items": { 49 - "type": "union", 50 - "refs": [ 51 - "world.geocache.cache.attribute#fee", 52 - "world.geocache.cache.attribute#allAges", 53 - "world.geocache.cache.attribute#winterFriendly", 54 - "world.geocache.cache.attribute#poisonousPlants", 55 - "world.geocache.cache.attribute#snakes", 56 - "world.geocache.cache.attribute#ticks", 57 - "world.geocache.cache.attribute#dangerous", 58 - "world.geocache.cache.attribute#accessible", 59 - "world.geocache.cache.attribute#thorns", 60 - "world.geocache.cache.attribute#flashlight", 61 - "world.geocache.cache.attribute#bigrig", 62 - "world.geocache.cache.attribute#trail", 63 - "world.geocache.cache.attribute#specialEquipment", 64 - "world.geocache.cache.attribute#night", 65 - "world.geocache.cache.attribute#garminChirp", 66 - "world.geocache.cache.attribute#letterbox", 67 - "world.geocache.cache.attribute#compass", 68 - "world.geocache.cache.attribute#quick", 69 - "world.geocache.cache.attribute#traveller", 70 - "world.geocache.cache.attribute#byop", 71 - "world.geocache.cache.attribute#magnetic", 72 - "world.geocache.cache.attribute#audio", 73 - "world.geocache.cache.attribute#offset", 74 - "world.geocache.cache.attribute#usb", 75 - "world.geocache.cache.attribute#surveyBenchmark", 76 - "world.geocache.cache.attribute#woods", 77 - "world.geocache.cache.attribute#historic", 78 - "world.geocache.cache.attribute#advertisement", 79 - "world.geocache.cache.attribute#limitedaccess", 80 - "world.geocache.cache.attribute#guestBook", 81 - "world.geocache.cache.attribute#challenge", 82 - "world.geocache.cache.attribute#urban", 83 - "world.geocache.cache.attribute#bikeFriendly", 84 - "world.geocache.cache.attribute#keypair", 85 - "world.geocache.cache.attribute#noInternet", 86 - "world.geocache.cache.attribute#bushwhacking", 87 - "world.geocache.cache.attribute#underwater", 88 - "world.geocache.cache.attribute#cave", 89 - ] 90 - } 91 - }, 92 - "description": { 93 - "type": "string", 94 - "maxLength": 10000, 95 - "maxGraphemes": 1000, 96 - "description": "A description for the geocache. " 97 - }, 98 - "pubkey": { 99 - /* 100 - the idea here is basically a fancier method of doing password verification 101 - for visits to a geocache: 102 - - the creator generates an ed25519 keypair (chosen for its small key sizes) 103 - - the pubkey gets logged with the record 104 - - the privkey gets deployed with the geocache 105 - - visitors to the cache save the privkey 106 - - visitors can sign a message with the discovered private key 107 - - this message gets logged with their visit record 108 - - the appview can "verify" the cache using the pubkey to decrypt the message 109 - 110 - the exact protocol for this remains to be explored, but i think it's a fun idea. 111 - 112 - there's also a riff on this idea that might work well with the "moving" cache type: 113 - - each geocacher has a keypair 114 - - the original owner plants the geocache, and signs off their visit with their key 115 - - the next finder takes the geocache home, and logs their ownership signing with their key, referring to the last owner 116 - - this then creates a cryptographically signed history of the cache's location history 117 - 118 - yes, that's basically a stupid blockchain. but it's kinda silly in the good way. 119 - 120 - i mean, every record on a user's PDS is able to be proven to originate from the owner, 121 - so maybe you could still share a single private key that moves with the geocache? 122 - much to be thought about... 123 - */ 124 - "type": "bytes", 125 - "maxLength": 57, 126 - "createdAt": { 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "description": "A geocache out there in the world", 8 + "key": "tid", 9 + "record": { 10 + "type": "object", 11 + "required": [ 12 + "name", 13 + "location", 14 + "status", 15 + "tags", 16 + "description", 17 + "createdAt" 18 + ], 19 + "properties": { 20 + "name": { 21 + "type": "string", 22 + "maxLength": 1000, 23 + "maxGraphemes": 100, 24 + "description": "The name for the geocache" 25 + }, 26 + "attestor": { 27 + "type": "ref", 28 + "ref": "#attestorRef" 29 + }, 30 + "location": { 31 + "type": "object", 32 + "properties": { 33 + "geo": { "type": "ref", "ref": "community.lexicon.location.geo" }, 34 + "address": { 35 + "type": "ref", 36 + "ref": "community.lexicon.location.address" 37 + }, 38 + "hthree": { 39 + "type": "ref", 40 + "ref": "community.lexicon.location.hthree" 41 + }, 42 + "uri": { "type": "string", "format": "uri" } 43 + } 44 + }, 45 + "status": { 46 + "type": "ref", 47 + "description": "The status of the geocache", 48 + "ref": "world.geocache.cache#status" 49 + }, 50 + "tags": { 51 + "type": "array", 52 + "description": "Tags which describe the geocache.", 53 + "minLength": 1, 54 + "items": { 127 55 "type": "string", 128 - "format": "datetime", 129 - "description": "When the geocache was first created" 56 + "maxLength": 640, 57 + "maxGraphemes": 64 130 58 } 59 + }, 60 + "description": { 61 + "type": "string", 62 + "maxLength": 20000, 63 + "maxGraphemes": 2000, 64 + "description": "A description for the geocache. " 65 + }, 66 + "createdAt": { 67 + "type": "string", 68 + "format": "datetime", 69 + "description": "When the geocache was first created" 131 70 } 132 71 } 133 72 } 134 - }, 135 - "status": { 136 - "type": "string", 137 - "description": "The status of the geocache", 138 - "default": "world.geocache.cache#staging", 139 - "knownValues": [ 140 - "world.geocache.cache.status#active", 141 - "world.geocache.cache.status#dead", 142 - "world.geocache.cache.status#done", 143 - "world.geocache.cache.status#moved", 144 - "world.geocache.cache.status#unknown", 145 - "world.geocache.cache.status#staging", 146 - "world.geocache.cache.status#asleep", 147 - ] 148 - }, 149 - "active": { 150 - "type": "token", 151 - "description": "This geocache is accessible." 152 - }, 153 - "dead": { 154 - "type": "token", 155 - "description": "This geocache is inaccessible, and not expected to become accessible again." 156 - }, 157 - "done": { 158 - "type": "token", 159 - "description": "This geocache was a time limited experience, and is now over." 160 - }, 161 - "moved": { 162 - "type": "token", 163 - "description": "This geocache has been moved." 164 - }, 165 - "unknown": { 166 - "type": "token", 167 - "description": "This geocache's status is not known." 168 - }, 169 - "staging": { 170 - "type": "token", 171 - "description": "This geocache has yet to be deployed." 172 - }, 173 - "asleep": { 174 - "type": "token", 175 - "description": "This geocache is temporarily inaccessible, but will become accessible again at some known time." 176 - }, 177 - "cacheType": { 178 - "type": "string", 179 - "default": "world.geocache.cache#traditional", 180 - /* 181 - there's a few cache types that opencaching has which i'm not sure about 182 - - moving 183 - this is the most interesting one -- this represents a geocache that is moving 184 - between each find (typically the finder moves the cache, updates the coordinates 185 - after finding it). atproto does not currently have shared records, so you can't 186 - do it that way. 187 - 188 - my immediate thought would be: a special subset of the geocache lexicon which 189 - has a parameter for "nextLocation" -- the finder of the cache logs their visit, 190 - not as a traditional "visit" lexicon, but instead as a "movedCache". while this would 191 - introduce friction in that you would need the owner to update the cache, it would 192 - be a pretty simple implementation from then on. the appview would just need to 193 - keep track of successive moves and display them to the user. you'd also get a mostly free 194 - history view, which could be super fun! 195 - 196 - if combined with the idea of pubkey verification, you could even automate the transfer 197 - of a geocache -- the appview listens for a visit that has a linkback, verifies that 198 - the signature is properly decrypted, and then would update the record on the original 199 - owner's PDS to point to the first finder... 200 - - event 201 - the way this is described on opencaching seems to just represent like, 202 - an in person meetup or something like that. not sure we need this one. 203 - it would provide some feature pairity to opencaching, at least? 204 - - webcam 205 - these represent geocaches which use a webcam to log visits. 206 - i don't see why this can't just be an attribute of a cache. 207 - */ 208 - "knownValues": [ 209 - "world.geocache.cache#traditional", 210 - "world.geocache.cache#multi", 211 - "world.geocache.cache#moving", 212 - "world.geocache.cache#puzzle", 213 - "world.geocache.cache#digital", 214 - "world.geocache.cache#virtual", 215 - "world.geocache.cache#roaming", 216 - "world.geogache.cache#other" 217 - ] 218 - }, 219 - "traditional": { 220 - "type": "token", 221 - "description": "This is a traditional geocache, containing at minimum a container and a logbook." 222 - }, 223 - "multi": { 224 - "type": "token", 225 - "description": "This geocache involves at least two locations, usually found by hints left in the first geocache." 226 - }, 227 - "moving": { 228 - "type": "token", 229 - "description": "This geocache changes its location after each find." 230 - }, 231 - "puzzle": { 232 - "type": "token", 233 - "description": "This geocache involves a puzzle to determine the location of the actual cache. Location data refers to a related reference point." 234 - }, 235 - "digital": { 236 - "type": "token", 237 - "description": "This geocache exists in cyberspace." 238 - }, 239 - "virtual": { 240 - "type": "token", 241 - "description": "This geocache exists in the form of a location only." 242 - }, 243 - "roaming": { 244 - "type": "token", 245 - "description": "This geocache roams around the world, typically with the owner of the cache." 246 - }, 247 - "other": { 248 - "type": "token", 249 - "description": "This geocache is not well defined by any current type token." 250 - }, 73 + } 74 + }, 75 + "attestorRef": { 76 + "type": "object", 77 + "required": ["record"], 78 + "properties": { 79 + "record": { "type": "ref", "ref": "com.atproto.ref.strongRef" } 80 + } 81 + }, 82 + "status": { 83 + "type": "string", 84 + "description": "The status of the geocache", 85 + "default": "world.geocache.cache#staging", 86 + "knownValues": [ 87 + "world.geocache.cache.status#active", 88 + "world.geocache.cache.status#dead", 89 + "world.geocache.cache.status#done", 90 + "world.geocache.cache.status#staging", 91 + "world.geocache.cache.status#asleep" 92 + ] 93 + }, 94 + "active": { 95 + "type": "token", 96 + "description": "This geocache is accessible." 97 + }, 98 + "dead": { 99 + "type": "token", 100 + "description": "This geocache is inaccessible, and not expected to become accessible again." 101 + }, 102 + "done": { 103 + "type": "token", 104 + "description": "This geocache was a time limited experience, and has since been put to rest." 105 + }, 106 + "staging": { 107 + "type": "token", 108 + "description": "This geocache has yet to be deployed." 109 + }, 110 + "asleep": { 111 + "type": "token", 112 + "description": "This geocache is temporarily inaccessible, but may become accessible again at some known time." 251 113 } 252 114 }
+17 -6
lexicon/world.geocache.cache.visit.json lexicon/world.geocache.visit.json
··· 25 25 }, 26 26 "publicComment": { 27 27 "type": "string", 28 - "description": "A comment describing the visit, to be displayed on the geocache's page." 28 + "description": "A comment describing the visit, to be displayed on the geocache's page.", 29 29 "maxGraphemes": 1000, 30 - "maxLength": 10000, 30 + "maxLength": 10000 31 31 }, 32 - "signature": { 32 + "attestation": { 33 33 "type": "ref", 34 - "description": "The cryptographic signature for verifying the user actually visited the cache.", 35 - "ref": "world.geocache.visit.signature" 34 + "description": "The attestation proving the user's visit.", 35 + "ref": "#attestationRef" 36 36 } 37 37 } 38 38 } 39 39 }, 40 + "attestationRef": { 41 + "type": "object", 42 + "required": ["record"], 43 + "properties": { "type": "ref", "ref": "com.atproto.repo.strongRef" } 44 + }, 40 45 "image": { 41 46 "type": "object", 42 47 "required": ["blob", "imageLink"], 43 48 "properties": { 44 49 "blob": { 45 50 "type": "blob", 46 - "accept": ["image/png","image/jpeg","image/jxl","image/heif","image/webp"], 51 + "accept": [ 52 + "image/png", 53 + "image/jpeg", 54 + "image/jxl", 55 + "image/heif", 56 + "image/webp" 57 + ], 47 58 "maxSize": 1048576, 48 59 "description": "The actual atproto image blob." 49 60 },
-44
lexicon/world.geocache.user.profile.get.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "world.geocache.user.profile.get", 4 - "defs": { 5 - "main": { 6 - "type": "query", 7 - "description": "Gets profile for a geocacher.", 8 - "parameters": { 9 - "type": "params", 10 - "required": ["did"], 11 - "properties": { 12 - "did": { 13 - "type": "string", 14 - "format": "at-identifier", 15 - "description": "The DID of the cache maintainer." 16 - }, 17 - }, 18 - "output": { 19 - "encoding": "application/json", 20 - "schema": { 21 - "type": "object", 22 - "required": ["profile","caches"], 23 - "properties": { 24 - "profile": { 25 - "type": "ref", 26 - "ref": "com.atproto.repo.strongRef", 27 - }, 28 - "caches": { 29 - "type": "array", 30 - "items": { 31 - /* it would not be ideal to force the profile view to always show every detail about every cache 32 - so instead we can provide a minified view, with just essential details like the name, status, image, 33 - and the aturi for the cache 34 - */ 35 - "type": "ref", 36 - "ref": "world.geocache.cache.miniView" 37 - } 38 - } 39 - } 40 - } 41 - } 42 - } 43 - } 44 - }
+23 -23
lexicon/world.geocache.user.profile.json
··· 1 1 { 2 - "lexicon": 1, 3 - "id": "world.geocache.user.profile", 4 - "defs": { 5 - "main": { 6 - "type": "record", 7 - "description": "A profile of a Geocache World user.", 8 - "record": { 9 - "type": "object", 10 - "properties": { 11 - "avatar": { 12 - "type": "ref", 13 - "description": "The avatar for the user", 14 - "ref": "com.atproto.repo.strongRef" 15 - }, 16 - "bio": { 17 - "type": "string", 18 - "description": "The bio of the user.", 19 - "maxGraphemes": 240, 20 - "maxLength": 2400 21 - }, 22 - } 23 - } 24 - }, 2 + "lexicon": 1, 3 + "id": "world.geocache.user.profile", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "description": "A profile of a Geocache World user.", 8 + "record": { 9 + "type": "object", 10 + "properties": { 11 + "avatar": { 12 + "type": "ref", 13 + "description": "The avatar for the user", 14 + "ref": "com.atproto.repo.strongRef" 15 + }, 16 + "bio": { 17 + "type": "string", 18 + "description": "The bio of the user.", 19 + "maxGraphemes": 500, 20 + "maxLength": 5000 21 + } 22 + } 23 + } 25 24 } 25 + } 26 26 }
+30
lexicon/world.geocache.visit.attestation.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "world.geocache.visit.attestation", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "description": "The proof of the user's visit to the geocache.", 8 + "key": "tid", 9 + "record": { 10 + "type": "object", 11 + "required": ["attestor", "proof"], 12 + "properties": { 13 + "attestor": { 14 + "type": "object", 15 + "required": ["record"], 16 + "properties": { 17 + "record": { "type": "ref", "ref": "com.atproto.ref.strongRef" } 18 + } 19 + }, 20 + "proof": { 21 + "type": "string", 22 + "description": "The proof of the user's visit to the geocache, such as the encrypted token.", 23 + "maxLength": 100000, 24 + "maxGraphemes": 10000 25 + } 26 + } 27 + } 28 + } 29 + } 30 + }