This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / web / src / lib / api / graph.ts
3.0 kB 88 lines
1import { ok } from "@atcute/client"; 2import { mainSchema as createRecordSchema } from "@atcute/atproto/types/repo/createRecord"; 3import { mainSchema as deleteRecordSchema } from "@atcute/atproto/types/repo/deleteRecord"; 4import type { Did, Nsid, RecordKey } from "@atcute/lexicons/syntax"; 5import type { OAuthUserAgent } from "@atcute/oauth-browser-client"; 6import { createClient } from "$lib/auth/agent"; 7import { ClientResponseError, type BobbinContext } from "./client"; 8import { jsonGet } from "./_request"; 9import { httpStatusFor } from "./load"; 10import { rkeyFromUri } from "./uri"; 11import type * as ShTangledGraphFollow from "./lexicons/types/sh/tangled/graph/follow"; 12import type * as ShTangledGraphGetFollow from "./lexicons/types/sh/tangled/graph/getFollow"; 13import type * as ShTangledGraphVouch from "./lexicons/types/sh/tangled/graph/vouch"; 14 15export type FollowRecord = ShTangledGraphFollow.Main; 16export type VouchRecord = ShTangledGraphVouch.Main; 17 18const FOLLOW_COLLECTION = "sh.tangled.graph.follow" as Nsid; 19const STAR_COLLECTION = "sh.tangled.feed.star" as Nsid; 20 21// 404 means no follow exists, other errors propagate 22export const getFollowRkey = async ( 23 ctx: BobbinContext, 24 actor: string, 25 subject: string 26): Promise<string | null> => { 27 try { 28 const { uri } = await jsonGet<ShTangledGraphGetFollow.$output>( 29 ctx, 30 "sh.tangled.graph.getFollow", 31 { actor: actor as Did, subject: subject as Did } satisfies ShTangledGraphGetFollow.$params 32 ); 33 return rkeyFromUri(uri); 34 } catch (cause) { 35 if (cause instanceof ClientResponseError && httpStatusFor(cause) === 404) return null; 36 throw cause; 37 } 38}; 39 40const createGenericRecord = async <T extends { $type: string }>( 41 agent: OAuthUserAgent, 42 collection: Nsid, 43 record: T 44): Promise<string> => { 45 const rpc = createClient(agent); 46 const result = await ok( 47 rpc.call(createRecordSchema, { 48 input: { repo: agent.sub, collection, record } 49 }) 50 ); 51 return rkeyFromUri(result.uri); 52}; 53 54const deleteGenericRecord = async ( 55 agent: OAuthUserAgent, 56 collection: Nsid, 57 rkey: string 58): Promise<void> => { 59 const rpc = createClient(agent); 60 await ok( 61 rpc.call(deleteRecordSchema, { 62 input: { repo: agent.sub, collection, rkey: rkey as RecordKey } 63 }) 64 ); 65}; 66 67export const createFollow = (agent: OAuthUserAgent, subject: string): Promise<string> => 68 createGenericRecord(agent, FOLLOW_COLLECTION, { 69 $type: "sh.tangled.graph.follow", 70 subject: subject as Did, 71 createdAt: new Date().toISOString() 72 }); 73 74export const deleteFollow = (agent: OAuthUserAgent, rkey: string): Promise<void> => 75 deleteGenericRecord(agent, FOLLOW_COLLECTION, rkey); 76 77export const createStar = (agent: OAuthUserAgent, repoDid: string): Promise<string> => 78 createGenericRecord(agent, STAR_COLLECTION, { 79 $type: "sh.tangled.feed.star", 80 subject: { 81 $type: "sh.tangled.feed.star#repo", 82 did: repoDid as Did 83 }, 84 createdAt: new Date().toISOString() 85 }); 86 87export const deleteStar = (agent: OAuthUserAgent, rkey: string): Promise<void> => 88 deleteGenericRecord(agent, STAR_COLLECTION, rkey);