A React component library for rendering common AT Protocol records for applications such as Bluesky and Leaflet.
1/* eslint-disable react-refresh/only-export-components */
2import React, { createContext, useContext, useMemo, useRef } from "react";
3import { ServiceResolver, normalizeBaseUrl } from "../utils/atproto-client";
4import { BlobCache, DidCache } from "../utils/cache";
5
6export interface AtProtoProviderProps {
7 children: React.ReactNode;
8 plcDirectory?: string;
9}
10
11interface AtProtoContextValue {
12 resolver: ServiceResolver;
13 plcDirectory: string;
14 didCache: DidCache;
15 blobCache: BlobCache;
16}
17
18const AtProtoContext = createContext<AtProtoContextValue | undefined>(
19 undefined,
20);
21
22export function AtProtoProvider({
23 children,
24 plcDirectory,
25}: AtProtoProviderProps) {
26 const normalizedPlc = useMemo(
27 () =>
28 normalizeBaseUrl(
29 plcDirectory && plcDirectory.trim()
30 ? plcDirectory
31 : "https://plc.directory",
32 ),
33 [plcDirectory],
34 );
35 const resolver = useMemo(
36 () => new ServiceResolver({ plcDirectory: normalizedPlc }),
37 [normalizedPlc],
38 );
39 const cachesRef = useRef<{
40 didCache: DidCache;
41 blobCache: BlobCache;
42 } | null>(null);
43 if (!cachesRef.current) {
44 cachesRef.current = {
45 didCache: new DidCache(),
46 blobCache: new BlobCache(),
47 };
48 }
49 const value = useMemo<AtProtoContextValue>(
50 () => ({
51 resolver,
52 plcDirectory: normalizedPlc,
53 didCache: cachesRef.current!.didCache,
54 blobCache: cachesRef.current!.blobCache,
55 }),
56 [resolver, normalizedPlc],
57 );
58 return (
59 <AtProtoContext.Provider value={value}>
60 {children}
61 </AtProtoContext.Provider>
62 );
63}
64
65export function useAtProto() {
66 const ctx = useContext(AtProtoContext);
67 if (!ctx) throw new Error("useAtProto must be used within AtProtoProvider");
68 return ctx;
69}