Something went wrong. Try again.
A Bsky-like frontend using the atprotocol natively.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
import { atprotoClient } from '../api/client';import type { Label, ResolvedLabel } from '../api/types';import { rewriteBlobUrl } from '../api/blobRewrite';
interface CachedLabeler { name: string; avatar?: string; labelNames: Map<string, string>;}
const cache = new Map<string, CachedLabeler>();
let fetchPromise: Promise<void> | null = null;
const pendingDids = new Set<string>();
export async function prefetchLabelerDids(dids: string[]): Promise<void> { if (!dids || dids.length === 0) return; await fetchLabelerServices(dids);}
async function fetchLabelerServices(srcDids: string[]): Promise<void> { const uncached = srcDids.filter((did) => !cache.has(did) && !pendingDids.has(did)); if (uncached.length === 0 && !fetchPromise) return;
for (const did of uncached) { pendingDids.add(did); }
if (fetchPromise) { await fetchPromise; const stillUncached = srcDids.filter((did) => !cache.has(did)); if (stillUncached.length === 0) return; return fetchLabelerServices(stillUncached); }
const didsToFetch = [...pendingDids]; pendingDids.clear();
fetchPromise = (async () => { try { const agent = atprotoClient.api; if (!agent) { console.error('Cannot fetch labeler services: not logged in'); return; }
const CHUNK_SIZE = 25; for (let i = 0; i < didsToFetch.length; i += CHUNK_SIZE) { const chunk = didsToFetch.slice(i, i + CHUNK_SIZE); const resp = await agent.app.bsky.labeler.getServices({ dids: chunk, detailed: true, });
for (const view of resp.data.views) { if (!('creator' in view)) continue;
const creator = view.creator as { did: string; displayName?: string; avatar?: string; };
const policies = 'policies' in view ? view.policies : undefined;
const labelNames = new Map<string, string>(); if (policies?.labelValueDefinitions) { for (const def of policies.labelValueDefinitions) { const enLocale = def.locales.find((l) => l.lang === 'en'); const name = enLocale?.name ?? def.locales[0]?.name ?? def.identifier; labelNames.set(def.identifier, name); } }
cache.set(creator.did, { name: creator.displayName ?? 'Labeler', avatar: rewriteBlobUrl(creator.avatar), labelNames, }); } } } catch (err) { console.error('Error fetching labeler services:', err); } finally { fetchPromise = null; } })();
await fetchPromise;}
export async function resolveLabels(labels: Label[]): Promise<ResolvedLabel[]> { if (!labels || labels.length === 0) return [];
const srcDids = [...new Set(labels.map((l) => l.src))];
await fetchLabelerServices(srcDids);
return labels.map((label) => { const cached = cache.get(label.src); const displayName = cached?.labelNames.get(label.val) ?? label.val; return { val: label.val, displayName, labelerName: cached?.name ?? 'Labeler', labelerAvatar: cached?.avatar, }; });}
export function resolveLabelsSync(labels: Label[]): ResolvedLabel[] { if (!labels || labels.length === 0) return [];
return labels.map((label) => { const cached = cache.get(label.src); const displayName = cached?.labelNames.get(label.val) ?? label.val; return { val: label.val, displayName, labelerName: cached?.name ?? 'Labeler', labelerAvatar: cached?.avatar, }; });}