Fixed federation search

This commit is contained in:
Christopher
2026-01-22 15:26:39 -08:00
parent 1ed8e2c4db
commit b2d594d212
6 changed files with 169 additions and 18 deletions
+75
View File
@@ -0,0 +1,75 @@
import { fetchWebFinger, getActorUrlFromWebFinger } from './webfinger';
export interface ActivityPubProfile {
id: string;
type: string;
preferredUsername: string;
name?: string;
summary?: string;
url?: string;
icon?: {
url: string;
} | string;
image?: {
url: string;
} | string;
publicKey?: {
id: string;
owner: string;
publicKeyPem: string;
};
}
/**
* Fetch a remote ActivityPub actor
*/
export async function fetchRemoteActor(url: string): Promise<ActivityPubProfile | null> {
try {
const res = await fetch(url, {
headers: {
'Accept': 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
'User-Agent': 'Synapsis/1.0 (+https://synapsis.social)',
},
});
if (!res.ok) {
console.error(`Failed to fetch actor: ${res.status} ${res.statusText}`);
return null;
}
const data = await res.json();
// Basic validation
if (!data.id || !data.type) {
return null;
}
return data as ActivityPubProfile;
} catch (error) {
console.error('Error fetching remote actor:', error);
return null;
}
}
/**
* Resolve a remote user via WebFinger and fetch their profile
* @param handle The username (without domain)
* @param domain The domain name
*/
export async function resolveRemoteUser(handle: string, domain: string): Promise<ActivityPubProfile | null> {
// 1. WebFinger lookup
const webfinger = await fetchWebFinger(handle, domain);
if (!webfinger) {
return null;
}
// 2. Get Actor URL
const actorUrl = getActorUrlFromWebFinger(webfinger);
if (!actorUrl) {
return null;
}
// 3. Fetch Actor Profile
return await fetchRemoteActor(actorUrl);
}
+6 -3
View File
@@ -106,8 +106,11 @@ export async function fetchWebFinger(
* Get the ActivityPub actor URL from a WebFinger response
*/
export function getActorUrlFromWebFinger(webfinger: WebFingerResponse): string | null {
const selfLink = webfinger.links.find(
(link) => link.rel === 'self' && link.type === 'application/activity+json'
);
const selfLink = webfinger.links.find((link) => {
if (link.rel !== 'self' || !link.href) return false;
if (!link.type) return true;
const type = link.type.toLowerCase();
return type.includes('activity+json') || type.includes('activitystreams') || type.includes('application/ld+json');
});
return selfLink?.href ?? null;
}