leaflet.pub astro loader
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}