Skip to content

Instantly share code, notes, and snippets.

@Slokh
Created June 19, 2024 21:40
Show Gist options
  • Save Slokh/18a0a9e97a44c3dfc03758d224c6b965 to your computer and use it in GitHub Desktop.
Save Slokh/18a0a9e97a44c3dfc03758d224c6b965 to your computer and use it in GitHub Desktop.
discover farcaster users based on who you follow
import {
UserDataType,
getSSLHubRpcClient,
utf8StringToBytes,
} from "@farcaster/hub-nodejs";
import { NextRequest } from "next/server";
const client = getSSLHubRpcClient(process.env.HUB_RPC_ENDPOINT as string);
export async function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams;
const query = searchParams.get("fidOrUsername");
if (!query) {
return Response.json({ error: "No query provided" }, { status: 400 });
}
const proof = await client.getUsernameProof({
name: utf8StringToBytes(query)._unsafeUnwrap(),
});
if (!proof && Number.isNaN(Number(query))) {
return Response.json({ error: "Unknown user" }, { status: 400 });
}
const fid = proof.isOk() ? proof.value.fid : Number(query);
const following = await getFollowingFids(fid);
const followingFollowing = await Promise.all(
following.following.slice(0, 300).map(getFollowingFids),
);
const map = followingFollowing.reduce(
(acc, curr) => {
for (const followingFid of curr.following) {
if (
following.following.includes(followingFid) ||
followingFid === fid
) {
continue;
}
if (!acc[followingFid]) {
acc[followingFid] = {
fid: followingFid,
mutuals: [],
};
}
acc[followingFid].mutuals.push(curr.fid);
}
return acc;
},
{} as Record<
number,
{
fid: number;
mutuals: number[];
}
>,
);
const sorted = Object.values(map)
.sort((a, b) => b.mutuals.length - a.mutuals.length)
.slice(0, 25);
const users = await Promise.all(sorted.map((user) => getUser(user.fid)));
return Response.json({
users: sorted.map((data, i) => ({
...data,
...users[i],
})),
});
}
const getFollowingFids = async (fid: number) => {
const following = await client.getLinksByFid({ fid });
if (following.isErr()) {
return {
fid,
following: [],
};
}
return {
fid,
following: following.value.messages.map(
(message) => message.data?.linkBody?.targetFid,
) as number[],
};
};
const getUser = async (fid: number) => {
const user = await client.getUserDataByFid({ fid });
if (user.isErr()) {
throw new Error(`Failed to get user ${fid}`);
}
return {
fid,
username: user.value.messages.find(
(message) => message.data?.userDataBody?.type === UserDataType.USERNAME,
)?.data?.userDataBody?.value,
displayName: user.value.messages.find(
(message) => message.data?.userDataBody?.type === UserDataType.DISPLAY,
)?.data?.userDataBody?.value,
pfp: user.value.messages.find(
(message) => message.data?.userDataBody?.type === UserDataType.PFP,
)?.data?.userDataBody?.value,
bio: user.value.messages.find(
(message) => message.data?.userDataBody?.type === UserDataType.BIO,
)?.data?.userDataBody?.value,
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment