1import type { LiveLoader } from "astro/loaders"; 2import { Agent } from "@atproto/api"; 3import { isDid } from "@atproto/did"; 4import { isValidHandle } from "@atproto/syntax"; 5import { 6 getLeafletDocuments, 7 getSingleLeafletDocument, 8 resolveMiniDoc, 9 uriToRkey, 10} from "./utils.js"; 11import type { 12 CollectionFilter, 13 EntryFilter, 14 LeafletRecord, 15 LiveLoaderOptions, 16} from "./types.js"; 17 18export class LiveLoaderError extends Error { 19 constructor( 20 message: string, 21 public code?: string, 22 ) { 23 super(message); 24 this.name = "LiveLoaderError"; 25 } 26} 27 28/** 29 * Flow: 30 * - Check for valid handle or did [done] 31 * - Resolve PDS url from handle or did [done, thanks Phil!] 32 * - Fetch leaflet documents [done] 33 * - Find out how to use leaflet types here 34 */ 35 36export function leafletLiveLoader( 37 options: LiveLoaderOptions, 38): LiveLoader<LeafletRecord, EntryFilter, CollectionFilter, LiveLoaderError> { 39 const { repo } = options; 40 41 if (!repo || typeof repo !== "string") { 42 throw new LiveLoaderError( 43 "missing or invalid handle or did", 44 "MISSING_OR_INVALID_HANDLE_OR_DID", 45 ); 46 } 47 48 if (!isValidHandle(repo)) { 49 // not a valid handle, let's check if it's a valid did 50 if (!isDid(repo)) { 51 throw new LiveLoaderError( 52 "invalid handle or did", 53 "INVALID_HANDLE_OR_DID", 54 ); 55 } 56 } 57 58 return { 59 name: "leaflet-live-loader", 60 loadCollection: async ({ filter }) => { 61 try { 62 const pds_url = await resolveMiniDoc(repo); 63 const agent = new Agent({ service: pds_url }); 64 65 const documents = await getLeafletDocuments({ 66 repo, 67 agent, 68 cursor: filter?.cursor, 69 limit: filter?.limit, 70 reverse: filter?.reverse, 71 }); 72 73 return { 74 entries: documents.map((document) => ({ 75 id: uriToRkey(document.uri), 76 data: document, 77 })), 78 }; 79 } catch (error) { 80 return { 81 error: new LiveLoaderError( 82 "could not recover from error, please report on github", 83 "UNRECOVERABLE_ERROR", 84 ), 85 }; 86 } 87 }, 88 loadEntry: async ({ filter }) => { 89 try { 90 if (!filter.id) { 91 return { 92 error: new LiveLoaderError( 93 "must provide an id for specific document", 94 "MISSING_DOCUMENT_ID", 95 ), 96 }; 97 } 98 const pds_url = await resolveMiniDoc(repo); 99 const agent = new Agent({ service: pds_url }); 100 const document = await getSingleLeafletDocument({ 101 agent, 102 id: filter.id, 103 repo, 104 }); 105 106 return { 107 id: uriToRkey(document.data.uri), 108 data: document.data.value, 109 }; 110 } catch { 111 return { 112 error: new LiveLoaderError( 113 "could not recover from error, please report on github", 114 "UNRECOVERABLE_ERROR", 115 ), 116 }; 117 } 118 }, 119 }; 120}