feat: resolve DID handles via Bluesky API on repo cards

Author: Aaron Steven White
Commit 3fe5211805068d259c2a778a0ef2dd29c608473c
Parent: bd8821b95d
Structural diff unavailable

These commits were pushed via plain git push, so no pre-parsed schemas are available. Install git-remote-cospan and re-push via panproto:// to see scope-level changes, breaking change detection, and semantic diffs.

brew install panproto/tap/git-remote-cospan
2 files changed +40 -1
@@ -0,0 +1,32 @@
1+// DID → handle resolution via public Bluesky API with in-memory cache
2+
3+const cache = new Map<string, string>();
4+const pending = new Map<string, Promise<string>>();
5+
6+export async function resolveHandle(did: string): Promise<string> {
7+	if (cache.has(did)) return cache.get(did)!;
8+	if (pending.has(did)) return pending.get(did)!;
9+
10+	const promise = (async () => {
11+		try {
12+			const resp = await fetch(
13+				`https://public.api.bsky.app/xrpc/app.bsky.actor.getProfile?actor=${encodeURIComponent(did)}`
14+			);
15+			if (resp.ok) {
16+				const data = await resp.json();
17+				const handle = data.handle ?? did;
18+				cache.set(did, handle);
19+				return handle;
20+			}
21+		} catch {}
22+		// Fallback: truncated DID
23+		const fallback = did.startsWith('did:plc:') ? did.slice(8, 18) + '…' : did;
24+		cache.set(did, fallback);
25+		return fallback;
26+	})();
27+
28+	pending.set(did, promise);
29+	const result = await promise;
30+	pending.delete(did);
31+	return result;
32+}
@@ -1,9 +1,16 @@
11 <script lang="ts">
2+	import { onMount } from 'svelte';
23 	import type { Repo } from '$lib/api/repo.js';
4+	import { resolveHandle } from '$lib/api/handle.js';
35 
46 	let { repo }: { repo: Repo } = $props();
57 
68 	let displayName = $derived(repo.name || 'Untitled');
9+	let handle = $state('');
10+
11+	onMount(async () => {
12+		handle = await resolveHandle(repo.did);
13+	});
714 
815 	const hueMap: Record<string, number> = {
916 		typescript: 230, javascript: 50, rust: 25, python: 100,
@@ -19,7 +26,7 @@
1926 
2027 	let hue = $derived(hueMap[repo.protocol] ?? hashHue(repo.protocol));
2128 	let ownerHandle = $derived(
22-		repo.did.startsWith('did:plc:') ? repo.did.slice(8, 18) + '…' : repo.did
29+		handle || (repo.did.startsWith('did:plc:') ? repo.did.slice(8, 18) + '…' : repo.did)
2330 	);
2431 	let isTangled = $derived(repo.source === 'tangled');
2532 </script>
cospan · schematic version control on atproto built on AT Protocol