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