import { ok } from "@atcute/client"; import { mainSchema as uploadBlobSchema } from "@atcute/atproto/types/repo/uploadBlob"; import { mainSchema as putRecordSchema } from "@atcute/atproto/types/repo/putRecord"; import type { Nsid, RecordKey } from "@atcute/lexicons/syntax"; import type { OAuthUserAgent } from "@atcute/oauth-browser-client"; import { createClient } from "$lib/auth/agent"; import { enrich, TYPE_VIEWER } from "./enrich"; import type { BobbinContext, XrpcRequestInit } from "./client"; import type * as ShTangledActorGetTrending from "./lexicons/types/sh/tangled/actor/getTrending"; import type { ProfileRecord } from "./records"; const PROFILE_COLLECTION = "sh.tangled.actor.profile" as Nsid; export const TRENDING_FOLLOW_SOURCE = "sh.tangled.graph.follow:subject"; export const TRENDING_STAR_SOURCE = "sh.tangled.feed.star:subject"; const AVATAR_TYPES: Record = { "image/png": true, "image/jpeg": true }; const MAX_AVATAR_BYTES = 1_000_000; export const getTrendingWithViewerState = ( ctx: BobbinContext, viewer: string, init?: XrpcRequestInit ) => enrich( ctx, { xrpc: "sh.tangled.actor.getTrending", viewer, enrich: [ { source: TRENDING_FOLLOW_SOURCE, type: TYPE_VIEWER, targets: ["people[].did"] }, { source: TRENDING_STAR_SOURCE, type: TYPE_VIEWER, targets: ["repos[].did"] } ] }, init ); export const uploadProfileAvatar = async ( agent: OAuthUserAgent, image: Blob ): Promise> => { if (!AVATAR_TYPES[image.type]) throw new Error("Choose a PNG or JPEG image."); if (image.size > MAX_AVATAR_BYTES) throw new Error("Profile pictures must be 1 MB or smaller."); const rpc = createClient(agent); const { blob } = await ok(rpc.call(uploadBlobSchema, { input: image })); return blob; }; // the profile record lives at the fixed rkey `self`; put upserts it. export const putProfile = async (agent: OAuthUserAgent, record: ProfileRecord): Promise => { const rpc = createClient(agent); await ok( rpc.call(putRecordSchema, { input: { repo: agent.sub, collection: PROFILE_COLLECTION, rkey: "self" as RecordKey, record } }) ); };