Handle resolution

This commit is contained in:
Ariadna 2025-04-20 04:03:50 -04:00
parent 6628b3d0df
commit e9507880c1
Signed by: ari
SSH key fingerprint: SHA256:j4xpQafvRcIH4rwZqM5aREIogWsCjyYohia7vH0+uZY
4 changed files with 92 additions and 16 deletions

25
deno.lock generated
View file

@ -3,6 +3,7 @@
"specifiers": { "specifiers": {
"npm:@atcute/bluesky@^2.0.2": "2.0.2_@atcute+client@3.0.1", "npm:@atcute/bluesky@^2.0.2": "2.0.2_@atcute+client@3.0.1",
"npm:@atcute/client@^3.0.1": "3.0.1", "npm:@atcute/client@^3.0.1": "3.0.1",
"npm:@atcute/identity-resolver@~0.1.2": "0.1.2_@atcute+identity@0.1.3",
"npm:@sveltejs/vite-plugin-svelte@^5.0.3": "5.0.3_svelte@5.28.1__acorn@8.14.1_vite@6.3.2__picomatch@4.0.2", "npm:@sveltejs/vite-plugin-svelte@^5.0.3": "5.0.3_svelte@5.28.1__acorn@8.14.1_vite@6.3.2__picomatch@4.0.2",
"npm:@tsconfig/svelte@^5.0.4": "5.0.4", "npm:@tsconfig/svelte@^5.0.4": "5.0.4",
"npm:svelte-check@^4.1.5": "4.1.6_svelte@5.28.1__acorn@8.14.1_typescript@5.7.3", "npm:svelte-check@^4.1.5": "4.1.6_svelte@5.28.1__acorn@8.14.1_typescript@5.7.3",
@ -27,6 +28,29 @@
"@atcute/client@3.0.1": { "@atcute/client@3.0.1": {
"integrity": "sha512-j51SuQYQj5jeKrx1DCXx+Q3fpVvO0JYGnKnJAdDSlesSLjPXjvnx1abC+hkuro58KRHHJvRA6P1MC0pmJsWfcg==" "integrity": "sha512-j51SuQYQj5jeKrx1DCXx+Q3fpVvO0JYGnKnJAdDSlesSLjPXjvnx1abC+hkuro58KRHHJvRA6P1MC0pmJsWfcg=="
}, },
"@atcute/identity-resolver@0.1.2_@atcute+identity@0.1.3": {
"integrity": "sha512-fP2VbHD04kVcCdNi/Kszo6jFzqM7Pg3p33oGhfp2zVkwFKaVBlwCaFRWEga/Xvu/IDLwNdASGWnLqoA34SFeSg==",
"dependencies": [
"@atcute/identity",
"@atcute/util-fetch",
"@badrap/valita"
]
},
"@atcute/identity@0.1.3": {
"integrity": "sha512-ndlD8nypHt8G00wixbozKdSNL0O8HTzBjFGEXeAcBUCXSZPBjRWbqtgyJxhgUWnr7swgxgw1mSbZwRB5b7xCiQ==",
"dependencies": [
"@badrap/valita"
]
},
"@atcute/util-fetch@1.0.1": {
"integrity": "sha512-Clc0E/5ufyGBVfYBUwWNlHONlZCoblSr4Ho50l1LhmRPGB1Wu/AQ9Sz+rsBg7fdaW/auve8ulmwhRhnX2cGRow==",
"dependencies": [
"@badrap/valita"
]
},
"@badrap/valita@0.4.4": {
"integrity": "sha512-GEhUCk9c4XbNxi+0YZHZsV4fYNd6HejfWuN4Ti4c02DauX+LyX5WY1Y3WfyZ8Pxxl0zqhs+MLtW98cMh86vv6g=="
},
"@esbuild/aix-ppc64@0.25.2": { "@esbuild/aix-ppc64@0.25.2": {
"integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==" "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag=="
}, },
@ -443,6 +467,7 @@
"dependencies": [ "dependencies": [
"npm:@atcute/bluesky@^2.0.2", "npm:@atcute/bluesky@^2.0.2",
"npm:@atcute/client@^3.0.1", "npm:@atcute/client@^3.0.1",
"npm:@atcute/identity-resolver@~0.1.2",
"npm:@sveltejs/vite-plugin-svelte@^5.0.3", "npm:@sveltejs/vite-plugin-svelte@^5.0.3",
"npm:@tsconfig/svelte@^5.0.4", "npm:@tsconfig/svelte@^5.0.4",
"npm:svelte-check@^4.1.5", "npm:svelte-check@^4.1.5",

View file

@ -11,7 +11,8 @@
}, },
"dependencies": { "dependencies": {
"@atcute/bluesky": "^2.0.2", "@atcute/bluesky": "^2.0.2",
"@atcute/client": "^3.0.1" "@atcute/client": "^3.0.1",
"@atcute/identity-resolver": "^0.1.2"
}, },
"devDependencies": { "devDependencies": {
"@sveltejs/vite-plugin-svelte": "^5.0.3", "@sveltejs/vite-plugin-svelte": "^5.0.3",

View file

@ -12,12 +12,12 @@
src="https://pds.witchcraft.systems/xrpc/com.atproto.sync.getBlob?did={post.authorDid}&cid={post.authorAvatarCid}" src="https://pds.witchcraft.systems/xrpc/com.atproto.sync.getBlob?did={post.authorDid}&cid={post.authorAvatarCid}"
/> />
{/if} {/if}
<p>{post.displayName} | {post.timenotstamp}</p> <p>{post.displayName} | {post.authorHandle} | {post.timenotstamp}</p>
</div> </div>
<div id="postContent"> <div id="postContent">
<p>{post.text}</p> <p>{post.text}</p>
{#if post.replyingDid} {#if post.replyingUri}
<p>Replying to: {post.replyingDid}</p> <p>Replying to: {post.replyingUri.repo}</p>
{/if} {/if}
{#if post.imagesCid} {#if post.imagesCid}
<div id="imagesContainer"> <div id="imagesContainer">

View file

@ -7,25 +7,33 @@ import type {
At, At,
ComAtprotoRepoListRecords, ComAtprotoRepoListRecords,
} from "@atcute/client/lexicons"; } from "@atcute/client/lexicons";
import type App from "../App.svelte"; import {
// import { ComAtprotoRepoListRecords.Record } from "@atcute/client/lexicons"; CompositeDidDocumentResolver,
// import { AppBskyFeedPost } from "@atcute/client/lexicons"; PlcDidDocumentResolver,
// import { AppBskyActorDefs } from "@atcute/client/lexicons"; WebDidDocumentResolver,
} from "@atcute/identity-resolver";
interface AccountMetadata { interface AccountMetadata {
did: string; did: string;
displayName: string; displayName: string;
handle: string;
avatarCid: string | null; avatarCid: string | null;
} }
interface atUriObject {
repo: string;
collection: string;
rkey: string;
}
class Post { class Post {
authorDid: string; authorDid: string;
authorAvatarCid: string | null; authorAvatarCid: string | null;
authorHandle: string;
displayName: string; displayName: string;
text: string; text: string;
timestamp: number; timestamp: number;
timenotstamp: string; timenotstamp: string;
quotingDid: string | null; quotingUri: atUriObject | null;
replyingDid: string | null; replyingUri: atUriObject | null;
imagesCid: string[] | null; imagesCid: string[] | null;
videosLinkCid: string | null; videosLinkCid: string | null;
@ -35,17 +43,18 @@ class Post {
) { ) {
this.authorDid = account.did; this.authorDid = account.did;
this.authorAvatarCid = account.avatarCid; this.authorAvatarCid = account.avatarCid;
this.authorHandle = account.handle;
this.displayName = account.displayName; this.displayName = account.displayName;
const post = record.value as AppBskyFeedPost.Record; const post = record.value as AppBskyFeedPost.Record;
this.timenotstamp = post.createdAt; this.timenotstamp = post.createdAt;
this.text = post.text; this.text = post.text;
this.timestamp = Date.parse(post.createdAt); this.timestamp = Date.parse(post.createdAt);
if (post.reply) { if (post.reply) {
this.replyingDid = didFromATuri(post.reply.parent.uri).repo; this.replyingUri = processAtUri(post.reply.parent.uri);
} else { } else {
this.replyingDid = null; this.replyingUri = null;
} }
this.quotingDid = null; this.quotingUri = null;
this.imagesCid = null; this.imagesCid = null;
this.videosLinkCid = null; this.videosLinkCid = null;
switch (post.embed?.$type) { switch (post.embed?.$type) {
@ -58,10 +67,10 @@ class Post {
this.videosLinkCid = post.embed.video.ref.$link; this.videosLinkCid = post.embed.video.ref.$link;
break; break;
case "app.bsky.embed.record": case "app.bsky.embed.record":
this.quotingDid = didFromATuri(post.embed.record.uri).repo; this.quotingUri = processAtUri(post.embed.record.uri);
break; break;
case "app.bsky.embed.recordWithMedia": case "app.bsky.embed.recordWithMedia":
this.quotingDid = didFromATuri(post.embed.record.record.uri).repo; this.quotingUri = processAtUri(post.embed.record.record.uri);
switch (post.embed.media.$type) { switch (post.embed.media.$type) {
case "app.bsky.embed.images": case "app.bsky.embed.images":
this.imagesCid = post.embed.media.images.map((imageRecord) => this.imagesCid = post.embed.media.images.map((imageRecord) =>
@ -79,7 +88,7 @@ class Post {
} }
} }
const didFromATuri = (aturi: string) => { const processAtUri = (aturi: string): atUriObject => {
const parts = aturi.split("/"); const parts = aturi.split("/");
return { return {
repo: parts[2], repo: parts[2],
@ -110,8 +119,10 @@ const getAccountMetadata = async (did: `did:${string}:${string}`) => {
}, },
}); });
const value = data.value as AppBskyActorProfile.Record; const value = data.value as AppBskyActorProfile.Record;
const handle = await blueskyHandleFromDid(did);
const account: AccountMetadata = { const account: AccountMetadata = {
did: did, did: did,
handle: handle,
displayName: value.displayName || "", displayName: value.displayName || "",
avatarCid: null, avatarCid: null,
}; };
@ -145,6 +156,39 @@ const fetchPosts = async (did: string) => {
}; };
}; };
const identityResolve = async (did: At.Did) => {
const resolver = new CompositeDidDocumentResolver({
methods: {
plc: new PlcDidDocumentResolver(),
web: new WebDidDocumentResolver(),
},
});
if (did.startsWith("did:plc:") || did.startsWith("did:web:")) {
const doc = await resolver.resolve(
did as `did:plc:${string}` | `did:web:${string}`,
);
return doc;
} else {
throw new Error(`Unsupported DID type: ${did}`);
}
};
const blueskyHandleFromDid = async (did: At.Did) => {
const doc = await identityResolve(did);
if (doc.alsoKnownAs) {
const handleAtUri = doc.alsoKnownAs.find((url) => url.startsWith("at://"));
const handle = handleAtUri?.split("/")[2];
if (!handle) {
return "Handle not found";
} else {
return handle;
}
} else {
return "Handle not found";
}
};
const fetchAllPosts = async () => { const fetchAllPosts = async () => {
const users: AccountMetadata[] = await getAllMetadataFromPds(); const users: AccountMetadata[] = await getAllMetadataFromPds();
const postRecords = await Promise.all( const postRecords = await Promise.all(
@ -167,5 +211,11 @@ const fetchAllPosts = async () => {
return posts; return posts;
}; };
const testApiCall = async () => {
const { data } = await rpc.get("com.atproto.sync.listRepos", {
params: {},
});
console.log(data);
};
export { fetchAllPosts, getAllMetadataFromPds, Post }; export { fetchAllPosts, getAllMetadataFromPds, Post };
export type { AccountMetadata }; export type { AccountMetadata };