···11-{
22- "lexicon": 1,
33- "id": "world.geocache.attribute",
44- "defs": {
55- "fee": {
66- "type": "token",
77- "description": "This cache requires an entry fee, like a park admission fee."
88- },
99- "allAges": {
1010- "type": "token",
1111- "description": "This cache is suitable for all ages. It is easy and safe to find, and does not contain NSFW materials."
1212- },
1313- "winterFriendly": {
1414- "type": "token",
1515- "description": "This cache is accessible during winter."
1616- },
1717- "poisonousPlants": {
1818- "type": "token",
1919- "description": "This cache is in an area known to have poisonous plants."
2020- },
2121- "snakes": {
2222- "type": "token",
2323- "description": "This cache is in an area known to have snakes."
2424- },
2525- "ticks": {
2626- "type": "token",
2727- "description": "This cache is in an area known to have ticks."
2828- },
2929- "dangerous": {
3030- "type": "token",
3131- "description": "This cache is in an area which poses significant risk of injury or other dangers."
3232- },
3333- "accessible": {
3434- "type": "token",
3535- "description": "This cache is accessible to people of all abilities."
3636- },
3737- "thorns": {
3838- "type": "token",
3939- "description": "This cache is in an area known to have thorny plants."
4040- },
4141- "flashlight": {
4242- "type": "token",
4343- "description": "This cache requires a flashlight to find."
4444- },
4545- "bigrig": {
4646- "type": "token",
4747- "description": "This cache is in an area accessible to large vehicles, like RVs and trucks."
4848- },
4949- "trail": {
5050- "type": "token",
5151- "description": "This cache is only accessible through non-paved trails."
5252- },
5353- "specialEquipment": {
5454- "type": "token",
5555- "description": "This cache needs special equipment to access -- see description of cache."
5656- },
5757- "night": {
5858- "type": "token",
5959- "description": "This cache is able to be found at night with use of a flashlight, such as with reflective markers."
6060- },
6161- "garminChirp": {
6262- "type": "token",
6363- "description": "This cache contains a Garmin Chirp device."
6464- },
6565- "letterbox": {
6666- "type": "token",
6767- "description": "This cache is a letterbox, and contains a stamp the cacher can use to mark their own logbook."
6868- },
6969- "compass": {
7070- "type": "token",
7171- "description": "This cache requires use of a compass to find."
7272- },
7373- "quick": {
7474- "type": "token",
7575- "description": "This cache can be found within 15 minutes, including access time from the nearest parking space, transit stop, or trailhead."
7676- },
7777- "traveller": {
7878- "type": "token",
7979- "description": "This cache is suitable for travellers."
8080- },
8181- "byop": {
8282- "type": "token",
8383- "description": "This cache does not have a pen for you to use, so the cacher must bring their own."
8484- },
8585- "magnetic": {
8686- "type": "token",
8787- "description": "This cache is magnetically attached to its resting place."
8888- },
8989- "audio": {
9090- "type": "token",
9191- "description": "This cache has audio cues available."
9292- },
9393- "offset": {
9494- "type": "token",
9595- "description": "This cache requires multiple steps in order to find it."
9696- },
9797- "usb": {
9898- "type": "token",
9999- "description": "This cache contains, or is in its entirety, a USB flashdrive."
100100- },
101101- "surveyBenchmark": {
102102- "type": "token",
103103- "description": "This cache is, or is near, a survey benchmark."
104104- },
105105- "woods": {
106106- "type": "token",
107107- "description": "This cache is located in a forested area."
108108- },
109109- "historic": {
110110- "type": "token",
111111- "description": "This cache is located in or near a site of historic significance."
112112- },
113113- "advertisement": {
114114- "type": "token",
115115- "description": "This cache contains, or is in of itself, an advertisement for some commercial entity."
116116- },
117117- "limitedaccess": {
118118- "type": "token",
119119- "description": "This cache has limited access opportunities, including but not limited to: time-of-day limited, seasonally limited."
120120- },
121121- "guestBook": {
122122- "type": "token",
123123- "description": "This cache is an existing, permanent guestbook open to the public, such as ones located in a visitor center or hotel."
124124- },
125125- "challenge": {
126126- "type": "token",
127127- "description": "This cache is not suitable for beginner cachers, and may require advanced techniques to find."
128128- },
129129- "urban": {
130130- "type": "token",
131131- "description": "This cache is located in an urban environment."
132132- },
133133- "bikeFriendly": {
134134- "type": "token",
135135- "description": "This cache is located in an area accessible by bicycle."
136136- },
137137- "keypair": {
138138- "type": "token",
139139- "description": "This cache has a public/private keypair that can be used to create a visit signature."
140140- },
141141- "noInternet": {
142142- "type": "token",
143143- "description": "This cache is located somewhere without reliable, commonly available internet access, such as a public wifi hotspot, or a mobile network."
144144- },
145145- "bushwhacking": {
146146- "type": "token",
147147- "description": "This cache is located somewhere that does not have an established path or trail of any sort."
148148- },
149149- "underwater": {
150150- "type": "token",
151151- "description": "This cache is located inside a body of water."
152152- },
153153- "cave": {
154154- "type": "token",
155155- "description": "This cache is located inside a cave."
156156- },
157157- }
158158-}
+44
lexicon/world.geocache.cache.attestor.json
···11+{
22+ "lexicon": 1,
33+ "id": "world.geocache.cache.attestor",
44+ "defs": {
55+ "main": {
66+ "type": "record",
77+ "description": "The methodology for verifying a visit to the associated geocache.",
88+ "key": "tid",
99+ "record": {
1010+ "type": "object",
1111+ "required": ["method"],
1212+ "properties": {
1313+ "method": {
1414+ "type": "ref",
1515+ "description": "The methodology for verifying a visit to the associated geocache.",
1616+ "ref": "world.geocache.attestor.method"
1717+ }
1818+ }
1919+ }
2020+ },
2121+ "method": {
2222+ "type": "object",
2323+ "description": "The methodology for verifying a visit to the associated geocache.",
2424+ "required": ["by"],
2525+ "properties": {
2626+ "by": {
2727+ "type": "string",
2828+ "description": "The methodology used.",
2929+ "knownValues": ["world.geocache.attestor.tokenDecryption"]
3030+ },
3131+ "publicKey": {
3232+ "type": "string",
3333+ "description": "The public key associated with the attestor.",
3434+ "maxLength": 10000,
3535+ "maxGraphemes": 1000
3636+ }
3737+ }
3838+ },
3939+ "tokenDecryption": {
4040+ "type": "token",
4141+ "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."
4242+ }
4343+ }
4444+}
-45
lexicon/world.geocache.cache.get.json
···11-{
22- "lexicon": 1,
33- "id": "world.geocache.cache.get",
44- "defs": {
55- "main": {
66- "type": "query",
77- "description": "Gets hydrated data for a geocache.",
88- "parameters": {
99- "type": "params",
1010- "required": ["did", "rkey"],
1111- "properties": {
1212- "did": {
1313- "type": "string",
1414- "format": "at-identifier",
1515- "description": "The DID of the cache maintainer."
1616- },
1717- "rkey": {
1818- "type": "string",
1919- "description": "The record key."
2020- }
2121- }
2222- },
2323- "output": {
2424- "encoding": "application/json",
2525- "schema": {
2626- "type": "object",
2727- "required": ["cache"],
2828- "properties": {
2929- /* the geocache lexicon is a bit complex -- it points to at least one extra other record,
3030- potentially many. it would be simpler for the client if we provided a "hydrated" cache,
3131- with all the data belonging to the geocache record being displayed in a "flat" manner.
3232-3333- this would also allow visits for a cache to be given with the cache, though we may need
3434- in the future a cursor type system for very long running geocaches...
3535- */
3636- "cache": {
3737- "type": "ref",
3838- "refs": "world.geocache.hydratedCache"
3939- },
4040- }
4141- }
4242- }
4343- }
4444- }
4545-}
+104-242
lexicon/world.geocache.cache.json
···11{
22 "lexicon": 1,
33 "id": "world.geocache.cache",
44- "defs": {
55- "main": {
66- "type": "record",
77- "description": "A geocache out there in the world",
88- "key": "tid",
99- "record": {
1010- "type": "object",
1111- "required": ["name", "location", "cacheType", "status", "attributes", "description", "createdAt"],
1212- "properties": {
1313- "name": {
1414- "type": "string",
1515- "maxLength": 1000,
1616- "maxGraphemes": 100,
1717- "description": "The name for the geocache"
1818- },
1919- "location": {
2020- /* because we want to support many types of geocaches, we don't want
2121- to force any location type on the cache. generally, most non-digital
2222- geocaches will have an address and a geo coordinate, whereas
2323- digital ones will only have a URI
2424-2525- this property can be extended with additional location data for
2626- whatever niche caches users may wish to create
2727- */
2828- "type": "object",
2929- "properties": {
3030- "geo": { "type": "ref", "ref": "community.lexicon.location.geo" },
3131- "address": { "type": "ref", "ref": "community.lexicon.location.address" },
3232- "hthree": { "type": "ref", "ref": "community.lexicon.location.hthree" },
3333- "uri": { "type": "string", "format": "uri"}
3434- }
3535- },
3636- "cacheType": {
3737- "type": "ref",
3838- "ref": "world.geocache.cache#cacheType"
3939- },
4040- "status": {
4141- "type": "ref",
4242- "description": "The status of the geocache",
4343- "ref": "world.geocache.cache#status"
4444- },
4545- "attributes": {
4646- "type": "array",
4747- "description": "Information about the geocache.",
4848- "items": {
4949- "type": "union",
5050- "refs": [
5151- "world.geocache.cache.attribute#fee",
5252- "world.geocache.cache.attribute#allAges",
5353- "world.geocache.cache.attribute#winterFriendly",
5454- "world.geocache.cache.attribute#poisonousPlants",
5555- "world.geocache.cache.attribute#snakes",
5656- "world.geocache.cache.attribute#ticks",
5757- "world.geocache.cache.attribute#dangerous",
5858- "world.geocache.cache.attribute#accessible",
5959- "world.geocache.cache.attribute#thorns",
6060- "world.geocache.cache.attribute#flashlight",
6161- "world.geocache.cache.attribute#bigrig",
6262- "world.geocache.cache.attribute#trail",
6363- "world.geocache.cache.attribute#specialEquipment",
6464- "world.geocache.cache.attribute#night",
6565- "world.geocache.cache.attribute#garminChirp",
6666- "world.geocache.cache.attribute#letterbox",
6767- "world.geocache.cache.attribute#compass",
6868- "world.geocache.cache.attribute#quick",
6969- "world.geocache.cache.attribute#traveller",
7070- "world.geocache.cache.attribute#byop",
7171- "world.geocache.cache.attribute#magnetic",
7272- "world.geocache.cache.attribute#audio",
7373- "world.geocache.cache.attribute#offset",
7474- "world.geocache.cache.attribute#usb",
7575- "world.geocache.cache.attribute#surveyBenchmark",
7676- "world.geocache.cache.attribute#woods",
7777- "world.geocache.cache.attribute#historic",
7878- "world.geocache.cache.attribute#advertisement",
7979- "world.geocache.cache.attribute#limitedaccess",
8080- "world.geocache.cache.attribute#guestBook",
8181- "world.geocache.cache.attribute#challenge",
8282- "world.geocache.cache.attribute#urban",
8383- "world.geocache.cache.attribute#bikeFriendly",
8484- "world.geocache.cache.attribute#keypair",
8585- "world.geocache.cache.attribute#noInternet",
8686- "world.geocache.cache.attribute#bushwhacking",
8787- "world.geocache.cache.attribute#underwater",
8888- "world.geocache.cache.attribute#cave",
8989- ]
9090- }
9191- },
9292- "description": {
9393- "type": "string",
9494- "maxLength": 10000,
9595- "maxGraphemes": 1000,
9696- "description": "A description for the geocache. "
9797- },
9898- "pubkey": {
9999- /*
100100- the idea here is basically a fancier method of doing password verification
101101- for visits to a geocache:
102102- - the creator generates an ed25519 keypair (chosen for its small key sizes)
103103- - the pubkey gets logged with the record
104104- - the privkey gets deployed with the geocache
105105- - visitors to the cache save the privkey
106106- - visitors can sign a message with the discovered private key
107107- - this message gets logged with their visit record
108108- - the appview can "verify" the cache using the pubkey to decrypt the message
109109-110110- the exact protocol for this remains to be explored, but i think it's a fun idea.
111111-112112- there's also a riff on this idea that might work well with the "moving" cache type:
113113- - each geocacher has a keypair
114114- - the original owner plants the geocache, and signs off their visit with their key
115115- - the next finder takes the geocache home, and logs their ownership signing with their key, referring to the last owner
116116- - this then creates a cryptographically signed history of the cache's location history
117117-118118- yes, that's basically a stupid blockchain. but it's kinda silly in the good way.
119119-120120- i mean, every record on a user's PDS is able to be proven to originate from the owner,
121121- so maybe you could still share a single private key that moves with the geocache?
122122- much to be thought about...
123123- */
124124- "type": "bytes",
125125- "maxLength": 57,
126126- "createdAt": {
44+ "defs": {
55+ "main": {
66+ "type": "record",
77+ "description": "A geocache out there in the world",
88+ "key": "tid",
99+ "record": {
1010+ "type": "object",
1111+ "required": [
1212+ "name",
1313+ "location",
1414+ "status",
1515+ "tags",
1616+ "description",
1717+ "createdAt"
1818+ ],
1919+ "properties": {
2020+ "name": {
2121+ "type": "string",
2222+ "maxLength": 1000,
2323+ "maxGraphemes": 100,
2424+ "description": "The name for the geocache"
2525+ },
2626+ "attestor": {
2727+ "type": "ref",
2828+ "ref": "#attestorRef"
2929+ },
3030+ "location": {
3131+ "type": "object",
3232+ "properties": {
3333+ "geo": { "type": "ref", "ref": "community.lexicon.location.geo" },
3434+ "address": {
3535+ "type": "ref",
3636+ "ref": "community.lexicon.location.address"
3737+ },
3838+ "hthree": {
3939+ "type": "ref",
4040+ "ref": "community.lexicon.location.hthree"
4141+ },
4242+ "uri": { "type": "string", "format": "uri" }
4343+ }
4444+ },
4545+ "status": {
4646+ "type": "ref",
4747+ "description": "The status of the geocache",
4848+ "ref": "world.geocache.cache#status"
4949+ },
5050+ "tags": {
5151+ "type": "array",
5252+ "description": "Tags which describe the geocache.",
5353+ "minLength": 1,
5454+ "items": {
12755 "type": "string",
128128- "format": "datetime",
129129- "description": "When the geocache was first created"
5656+ "maxLength": 640,
5757+ "maxGraphemes": 64
13058 }
5959+ },
6060+ "description": {
6161+ "type": "string",
6262+ "maxLength": 20000,
6363+ "maxGraphemes": 2000,
6464+ "description": "A description for the geocache. "
6565+ },
6666+ "createdAt": {
6767+ "type": "string",
6868+ "format": "datetime",
6969+ "description": "When the geocache was first created"
13170 }
13271 }
13372 }
134134- },
135135- "status": {
136136- "type": "string",
137137- "description": "The status of the geocache",
138138- "default": "world.geocache.cache#staging",
139139- "knownValues": [
140140- "world.geocache.cache.status#active",
141141- "world.geocache.cache.status#dead",
142142- "world.geocache.cache.status#done",
143143- "world.geocache.cache.status#moved",
144144- "world.geocache.cache.status#unknown",
145145- "world.geocache.cache.status#staging",
146146- "world.geocache.cache.status#asleep",
147147- ]
148148- },
149149- "active": {
150150- "type": "token",
151151- "description": "This geocache is accessible."
152152- },
153153- "dead": {
154154- "type": "token",
155155- "description": "This geocache is inaccessible, and not expected to become accessible again."
156156- },
157157- "done": {
158158- "type": "token",
159159- "description": "This geocache was a time limited experience, and is now over."
160160- },
161161- "moved": {
162162- "type": "token",
163163- "description": "This geocache has been moved."
164164- },
165165- "unknown": {
166166- "type": "token",
167167- "description": "This geocache's status is not known."
168168- },
169169- "staging": {
170170- "type": "token",
171171- "description": "This geocache has yet to be deployed."
172172- },
173173- "asleep": {
174174- "type": "token",
175175- "description": "This geocache is temporarily inaccessible, but will become accessible again at some known time."
176176- },
177177- "cacheType": {
178178- "type": "string",
179179- "default": "world.geocache.cache#traditional",
180180- /*
181181- there's a few cache types that opencaching has which i'm not sure about
182182- - moving
183183- this is the most interesting one -- this represents a geocache that is moving
184184- between each find (typically the finder moves the cache, updates the coordinates
185185- after finding it). atproto does not currently have shared records, so you can't
186186- do it that way.
187187-188188- my immediate thought would be: a special subset of the geocache lexicon which
189189- has a parameter for "nextLocation" -- the finder of the cache logs their visit,
190190- not as a traditional "visit" lexicon, but instead as a "movedCache". while this would
191191- introduce friction in that you would need the owner to update the cache, it would
192192- be a pretty simple implementation from then on. the appview would just need to
193193- keep track of successive moves and display them to the user. you'd also get a mostly free
194194- history view, which could be super fun!
195195-196196- if combined with the idea of pubkey verification, you could even automate the transfer
197197- of a geocache -- the appview listens for a visit that has a linkback, verifies that
198198- the signature is properly decrypted, and then would update the record on the original
199199- owner's PDS to point to the first finder...
200200- - event
201201- the way this is described on opencaching seems to just represent like,
202202- an in person meetup or something like that. not sure we need this one.
203203- it would provide some feature pairity to opencaching, at least?
204204- - webcam
205205- these represent geocaches which use a webcam to log visits.
206206- i don't see why this can't just be an attribute of a cache.
207207- */
208208- "knownValues": [
209209- "world.geocache.cache#traditional",
210210- "world.geocache.cache#multi",
211211- "world.geocache.cache#moving",
212212- "world.geocache.cache#puzzle",
213213- "world.geocache.cache#digital",
214214- "world.geocache.cache#virtual",
215215- "world.geocache.cache#roaming",
216216- "world.geogache.cache#other"
217217- ]
218218- },
219219- "traditional": {
220220- "type": "token",
221221- "description": "This is a traditional geocache, containing at minimum a container and a logbook."
222222- },
223223- "multi": {
224224- "type": "token",
225225- "description": "This geocache involves at least two locations, usually found by hints left in the first geocache."
226226- },
227227- "moving": {
228228- "type": "token",
229229- "description": "This geocache changes its location after each find."
230230- },
231231- "puzzle": {
232232- "type": "token",
233233- "description": "This geocache involves a puzzle to determine the location of the actual cache. Location data refers to a related reference point."
234234- },
235235- "digital": {
236236- "type": "token",
237237- "description": "This geocache exists in cyberspace."
238238- },
239239- "virtual": {
240240- "type": "token",
241241- "description": "This geocache exists in the form of a location only."
242242- },
243243- "roaming": {
244244- "type": "token",
245245- "description": "This geocache roams around the world, typically with the owner of the cache."
246246- },
247247- "other": {
248248- "type": "token",
249249- "description": "This geocache is not well defined by any current type token."
250250- },
7373+ }
7474+ },
7575+ "attestorRef": {
7676+ "type": "object",
7777+ "required": ["record"],
7878+ "properties": {
7979+ "record": { "type": "ref", "ref": "com.atproto.ref.strongRef" }
8080+ }
8181+ },
8282+ "status": {
8383+ "type": "string",
8484+ "description": "The status of the geocache",
8585+ "default": "world.geocache.cache#staging",
8686+ "knownValues": [
8787+ "world.geocache.cache.status#active",
8888+ "world.geocache.cache.status#dead",
8989+ "world.geocache.cache.status#done",
9090+ "world.geocache.cache.status#staging",
9191+ "world.geocache.cache.status#asleep"
9292+ ]
9393+ },
9494+ "active": {
9595+ "type": "token",
9696+ "description": "This geocache is accessible."
9797+ },
9898+ "dead": {
9999+ "type": "token",
100100+ "description": "This geocache is inaccessible, and not expected to become accessible again."
101101+ },
102102+ "done": {
103103+ "type": "token",
104104+ "description": "This geocache was a time limited experience, and has since been put to rest."
105105+ },
106106+ "staging": {
107107+ "type": "token",
108108+ "description": "This geocache has yet to be deployed."
109109+ },
110110+ "asleep": {
111111+ "type": "token",
112112+ "description": "This geocache is temporarily inaccessible, but may become accessible again at some known time."
251113 }
252114}