an app to share curated trails sidetrail.app
1

Configure Feed

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

at main 1.6 kB View raw
1import { readFileSync } from "node:fs"; 2import { Lexicons, jsonToLex, type LexiconDoc } from "@atproto/lexicon"; 3 4// Validate against the lexicon JSON documents directly (the same source the 5// generated lib/lexicons code is built from). PDSes don't reliably enforce 6// third-party lexicons, so validating is the indexer's responsibility. 7const loadDoc = (path: string): LexiconDoc => 8 JSON.parse(readFileSync(new URL(`../../lexicons/${path}`, import.meta.url), "utf8")); 9 10const lexicons = new Lexicons([ 11 loadDoc("app/sidetrail/trail.json"), 12 loadDoc("app/sidetrail/walk.json"), 13 loadDoc("app/sidetrail/completion.json"), 14 loadDoc("com/atproto/repo/strongRef.json"), 15]); 16 17export const INDEXED_COLLECTIONS = [ 18 "app.sidetrail.trail", 19 "app.sidetrail.walk", 20 "app.sidetrail.completion", 21] as const; 22 23export type IndexedCollection = (typeof INDEXED_COLLECTIONS)[number]; 24 25export function validateRecord( 26 collection: IndexedCollection, 27 record: unknown, 28): { success: true } | { success: false; reason: string } { 29 // Records arrive as JSON (jetstream, listRecords, jsonb storage), where CID 30 // links are {"$link": ...} objects. The validator expects lex values, so 31 // convert first; a record that can't be converted (e.g. malformed CID) is invalid. 32 let lexValue: unknown; 33 try { 34 lexValue = jsonToLex(record); 35 } catch (err) { 36 return { success: false, reason: `unparseable as lex: ${(err as Error).message}` }; 37 } 38 const result = lexicons.validate(collection, lexValue); 39 if (result.success) return { success: true }; 40 return { success: false, reason: result.error.message }; 41}