Monorepo for Tangled
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108import { ok } from "@atcute/client";import { mainSchema as createRecordSchema } from "@atcute/atproto/types/repo/createRecord";import { mainSchema as deleteRecordSchema } from "@atcute/atproto/types/repo/deleteRecord";import type { Did, Nsid, RecordKey } from "@atcute/lexicons/syntax";import type { OAuthUserAgent } from "@atcute/oauth-browser-client";import { createClient } from "$lib/auth/agent";import { ClientResponseError, type BobbinContext } from "./client";import { jsonGet } from "./_request";import { httpStatusFor } from "./load";import { rkeyFromUri } from "./uri";import type * as ShTangledFeedGetStar from "./lexicons/types/sh/tangled/feed/getStar";import type * as ShTangledGraphFollow from "./lexicons/types/sh/tangled/graph/follow";import type * as ShTangledGraphGetFollow from "./lexicons/types/sh/tangled/graph/getFollow";import type * as ShTangledGraphVouch from "./lexicons/types/sh/tangled/graph/vouch";
export type FollowRecord = ShTangledGraphFollow.Main;export type VouchRecord = ShTangledGraphVouch.Main;
const FOLLOW_COLLECTION = "sh.tangled.graph.follow" as Nsid;const STAR_COLLECTION = "sh.tangled.feed.star" as Nsid;
// 404 means no follow exists, other errors propagateexport const getFollowRkey = async ( ctx: BobbinContext, actor: string, subject: string): Promise<string | null> => { try { const { uri } = await jsonGet<ShTangledGraphGetFollow.$output>( ctx, "sh.tangled.graph.getFollow", { actor: actor as Did, subject: subject as Did } satisfies ShTangledGraphGetFollow.$params ); return rkeyFromUri(uri); } catch (cause) { if (cause instanceof ClientResponseError && httpStatusFor(cause) === 404) return null; throw cause; }};
// 404 means no star exists, other errors propagateexport const getStarRkey = async ( ctx: BobbinContext, actor: string, subject: string): Promise<string | null> => { try { const { uri } = await jsonGet<ShTangledFeedGetStar.$output>(ctx, "sh.tangled.feed.getStar", { actor: actor as Did, subject } satisfies ShTangledFeedGetStar.$params); return rkeyFromUri(uri); } catch (cause) { if (cause instanceof ClientResponseError && httpStatusFor(cause) === 404) return null; throw cause; }};
const createGenericRecord = async <T extends { $type: string }>( agent: OAuthUserAgent, collection: Nsid, record: T): Promise<string> => { const rpc = createClient(agent); const result = await ok( rpc.call(createRecordSchema, { input: { repo: agent.sub, collection, record } }) ); return rkeyFromUri(result.uri);};
const deleteGenericRecord = async ( agent: OAuthUserAgent, collection: Nsid, rkey: string): Promise<void> => { const rpc = createClient(agent); await ok( rpc.call(deleteRecordSchema, { input: { repo: agent.sub, collection, rkey: rkey as RecordKey } }) );};
export const createFollow = (agent: OAuthUserAgent, subject: string): Promise<string> => createGenericRecord(agent, FOLLOW_COLLECTION, { $type: "sh.tangled.graph.follow", subject: subject as Did, createdAt: new Date().toISOString() });
export const deleteFollow = (agent: OAuthUserAgent, rkey: string): Promise<void> => deleteGenericRecord(agent, FOLLOW_COLLECTION, rkey);
export const createStar = (agent: OAuthUserAgent, repoDid: string): Promise<string> => createGenericRecord(agent, STAR_COLLECTION, { $type: "sh.tangled.feed.star", subject: { $type: "sh.tangled.feed.star#repo", did: repoDid as Did }, createdAt: new Date().toISOString() });
export const deleteStar = (agent: OAuthUserAgent, rkey: string): Promise<void> => deleteGenericRecord(agent, STAR_COLLECTION, rkey);