Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182import { ClientResponseError, ok } from "@atcute/client";import { mainSchema as getRecordSchema } from "@atcute/atproto/types/repo/getRecord";import { mainSchema as uploadBlobSchema } from "@atcute/atproto/types/repo/uploadBlob";import type { OAuthUserAgent } from "@atcute/oauth-browser-client";import { createClient } from "$lib/auth/agent";import { FOLLOW_VIEWER, STAR_VIEWER } from "$lib/api/descriptors";import { enrich, target } from "$lib/api/enrich";import { jsonGet } from "$lib/api/_request";import type { BobbinContext, XrpcRequestInit } from "$lib/api/client";import { putRecord, type WrittenRecord } from "$lib/api/write";import type * as ShTangledActorGetTrending from "$lib/api/lexicons/types/sh/tangled/actor/getTrending";import type { ProfileRecord } from "$lib/api/records";
export const PROFILE_COLLECTION = "sh.tangled.actor.profile";
const AVATAR_TYPES: Record<string, true> = { "image/png": true, "image/jpeg": true };const MAX_AVATAR_BYTES = 1_000_000;
export const getTrending = (ctx: BobbinContext, init?: XrpcRequestInit) => jsonGet<ShTangledActorGetTrending.$output>(ctx, "sh.tangled.actor.getTrending", {}, init);
export const getTrendingWithViewerState = ( ctx: BobbinContext, viewer: string, init?: XrpcRequestInit) => enrich<ShTangledActorGetTrending.$output>( ctx, { xrpc: "sh.tangled.actor.getTrending", viewer, enrich: [target(FOLLOW_VIEWER, ["people[].did"]), target(STAR_VIEWER, ["repos[].did"])] }, init );
export const uploadProfileAvatar = async ( agent: OAuthUserAgent, image: Blob): Promise<NonNullable<ProfileRecord["avatar"]>> => { 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<WrittenRecord> => { return putRecord(agent, PROFILE_COLLECTION, "self", record);};
// asks the account's own pds rather than bobbin: a fresh account is not indexed// yet, and a stale index answer here would overwrite a profile the user editedexport const hasProfile = async (agent: OAuthUserAgent): Promise<boolean> => { try { await ok( createClient(agent).call(getRecordSchema, { params: { repo: agent.sub, collection: PROFILE_COLLECTION, rkey: "self" } }) ); return true; } catch (cause) { if (cause instanceof ClientResponseError && cause.error === "RecordNotFound") return false; throw cause; }};
// the counterpart of the home page's getProfile check that sends new users to// /welcome; accounts nobody logs into as themselves get their profile written hereexport const ensureProfile = async ( agent: OAuthUserAgent, record: ProfileRecord): Promise<void> => { if (await hasProfile(agent)) return; await putProfile(agent, record);};