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 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}